1 /* $XConsortium: xtest1dd.c,v 1.14 94/04/17 20:33:00 gildea Exp $ */
2 /* $XFree86: xc/programs/Xserver/Xext/xtest1dd.c,v 3.0 1996/05/06 05:55:42 dawes Exp $ */
3 /*
4  *	File: xtest1dd.c
5  *
6  *	This file contains the device dependent parts of the input
7  *	synthesis extension.
8  */
9 
10 /*
11 
12 
13 Copyright (c) 1986, 1987, 1988   X Consortium
14 
15 Permission is hereby granted, free of charge, to any person obtaining a copy
16 of this software and associated documentation files (the "Software"), to deal
17 in the Software without restriction, including without limitation the rights
18 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
19 copies of the Software, and to permit persons to whom the Software is
20 furnished to do so, subject to the following conditions:
21 
22 The above copyright notice and this permission notice shall be included in
23 all copies or substantial portions of the Software.
24 
25 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
26 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
27 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
28 X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
29 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
30 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
31 
32 Except as contained in this notice, the name of the X Consortium shall not be
33 used in advertising or otherwise to promote the sale, use or other dealings
34 in this Software without prior written authorization from the X Consortium.
35 
36 
37 Copyright 1986, 1987, 1988 by Hewlett-Packard Corporation
38 
39 Permission to use, copy, modify, and distribute this
40 software and its documentation for any purpose and without
41 fee is hereby granted, provided that the above copyright
42 notice appear in all copies and that both that copyright
43 notice and this permission notice appear in supporting
44 documentation, and that the name of Hewlett-Packard not be used in
45 advertising or publicity pertaining to distribution of the
46 software without specific, written prior permission.
47 
48 Hewlett-Packard makes no representations about the
49 suitability of this software for any purpose.  It is provided
50 "as is" without express or implied warranty.
51 
52 This software is not subject to any license of the American
53 Telephone and Telegraph Company or of the Regents of the
54 University of California.
55 
56 */
57 
58 /***************************************************************
59  * include files
60  ***************************************************************/
61 
62 #define	NEED_EVENTS
63 #define	NEED_REPLIES
64 
65 #include <stdio.h>
66 #include "Xos.h"
67 #include "X.h"
68 #include "Xmd.h"
69 #include "Xproto.h"
70 #include "misc.h"
71 #include "dixstruct.h"
72 #define  XTestSERVER_SIDE
73 #include "xtestext1.h"
74 
75 #include "xtest1dd.h"
76 
77 /***************************************************************
78  * defines
79  ***************************************************************/
80 
81 /*
82  * the size of the fake input action array
83  */
84 #define ACTION_ARRAY_SIZE	100
85 
86 /***************************************************************
87  * externals
88  ***************************************************************/
89 
90 /*
91  * Holds the xTestInputAction event type code.
92  * This is defined in xtestext1di.c.
93  */
94 extern int			XTestInputActionType;
95 /*
96  * Holds the xTestFakeAck event type code.
97  * This is defined in xtestext1di.c.
98  */
99 extern int			XTestFakeAckType;
100 /*
101  * used in the WriteReplyToClient macro
102  */
103 extern int			exclusive_steal;
104 
105 /***************************************************************
106  * variables
107  ***************************************************************/
108 
109 /*
110  * array to hold fake input actions
111  */
112 struct {
113 	/*
114 	 * holds the action type, one of: XTestDELAY_ACTION,
115 	 * XTestKEY_ACTION, XTestMOTION_ACTION, XTestJUMP_ACTION
116 	 */
117 	CARD8	type;
118 	/*
119 	 * holds the device type, in the range 0 to 15
120 	 */
121 	CARD8	device;
122 	/*
123 	 * for XTestKEY_ACTION type, holds the keycode
124 	 */
125 	CARD8	keycode;
126 	/*
127 	 * for XTestKEY_ACTION type, holds the key up/down state
128 	 */
129 	CARD8	keystate;
130 	/*
131 	 * for XTestMOTION_ACTION and XTestJUMP_ACTION types,
132 	 * holds the x and y coordinates to move the mouse to
133 	 */
134 	int	x;
135 	int	y;
136 	/*
137 	 * holds the time to delay (in milliseconds) before performing
138 	 * the action
139 	 */
140 	CARD32	delay_time;
141 }action_array[ACTION_ARRAY_SIZE];
142 
143 /*
144  * write index for input action array
145  */
146 static int			write_index = 0;
147 /*
148  * read index for input action array
149  */
150 static int			read_index = 0;
151 /*
152  * this is where the input actions are accumulated until they are sent
153  * to a client (in a wire event)
154  */
155 static xTestInputActionEvent	input_action_packet;
156 /*
157  * holds the index (in bytes) into the input actions buffer in the
158  * current input action event
159  */
160 static int 			packet_index;
161 /*
162  * set to 1 when the input action event is full and needs to be sent to the
163  * client
164  */
165 static int			input_action_event_full = 0;
166 /*
167  * logical x position of the mouse during input action gathering
168  */
169 short				xtest_mousex;
170 /*
171  * logical y position of the mouse during input action gathering
172  */
173 short				xtest_mousey;
174 /*
175  * logical x position of the mouse during input action playback
176  */
177 static short			mx;
178 /*
179  * logical y position of the mouse during input action playback
180  */
181 static short			my;
182 /*
183  * logical x position of the mouse while we are reading fake input actions
184  * from the client and putting them into the fake input action array
185  */
186 static short			pmousex;
187 /*
188  * logical y position of the mouse while we are reading fake input actions
189  * from the client and putting them into the fake input action array
190  */
191 static short			pmousey;
192 /*
193  * The playback_on flag is set to 1 while there are input actions in the
194  * input action array.  It is set to 0 when the server has received all of
195  * the user actions.
196  */
197 int			playback_on = 0;
198 /*
199  * identity of the client using XTestGetInput to get user input actions
200  */
201 ClientPtr 		current_xtest_client;
202 /*
203  * if 1 send multiple input actions per XTestInputAction event;
204  * if 0 send one input action per XTestInputAction event
205  */
206 static char			packed_mode;
207 /*
208  * identity of the client using the XTestFakeInput function to send some
209  * fake input actions to the server
210  */
211 ClientPtr		playback_client = NULL;
212 /*
213  * Set to 1 when the XTestFAKE_ACK_REQUEST flag is set in a XTestFakeInput
214  * request.  Set back to 0 when all of the input actions have been sent
215  * to the server.
216  */
217 static int			acknowledge = 0;
218 /*
219  * The server's idea of the current time is saved in these variables when
220  * a XTestFakeInput request is received.  It is restored when all fake input
221  * actions are sent to the server or when the playback client disconnects.
222  */
223 static int			saved_sec;
224 static int			saved_usec;
225 /*
226  * Set to 1 when there is a valid time in saved_sec and saved_usec.
227  */
228 static int			time_saved = 0;
229 /*
230  * holds the extension's notion of what the current time is while it is
231  * sending input actions to a client
232  */
233 static struct timeval		current_time;
234 /*
235  * holds the time when the extension should place the next fake input action
236  * into the server's normal events queue
237  */
238 static struct timeval		play_time;
239 /*
240  * set to 1 when play_time is first set, cleared to 0 when the
241  * client using the extension disconnects, or when XTestReset is called
242  */
243 static char			play_clock = 0;
244 /*
245  * holds the amount of time left until the next input action from the
246  * input action array can be sent to the server
247  */
248 static struct timeval		rtime;
249 /*
250  * Set to 1 after the extension is done waiting for the correct time delay
251  * for an input action to be sent to the server.  Remains a 1 until the time
252  * delay for the next input action is computed.  Then set to 0 if the
253  * extension has to wait for the correct time delay.
254  */
255 static int			go_for_next = 1;
256 /*
257  * needed to restore waitime if playback is to be aborted
258  */
259 static struct timeval		*restorewait;
260 /*
261  * tmon special command key
262  *
263  * To use the test monitor program (called tmon) efficiently, it is
264  * desirable to have the extension be able to recognize a special "trigger"
265  * key.  If the extension did not do this, tmon would have to have the
266  * extension send all keyboard user input actions exclusively to tmon,
267  * only to have tmon send them right back if they were not the command key.
268  *
269  * If the extension can recognize the command key, then tmon can let the
270  * extension handle keyboard user input actions normally until the command
271  * key is pressed (and released), and only then have the extension start
272  * sending keyboard user input actions exclusively to tmon.
273  *
274  * Any key on the keyboard can be used for this command key.  It is most
275  * convenient if it is a low-frequency key.  If you want to generate a
276  * normal occurrance of this key to a client, just hit it twice.  Tmon
277  * will recognize the first occurrance of the key, take control of the input
278  * actions, and wait for certain keys.  If it sees another occurrance of the
279  * command key, it will send one occurrance of the command key to the
280  * extension, and go back to waiting.
281  *
282  * set and also referenced in device layer
283  * XXX there should be a way to set this through the protocol
284  */
285 KeyCode			xtest_command_key = 0;
286 
287 /***************************************************************
288  * function declarations
289  ***************************************************************/
290 
291 static void	parse_key_fake(
292 #if NeedFunctionPrototypes
293 			XTestKeyInfo	* /* fkey */
294 #endif
295 			);
296 static void	parse_motion_fake(
297 #if NeedFunctionPrototypes
298 			XTestMotionInfo	* /* fmotion */
299 #endif
300 			);
301 static void	parse_jump_fake(
302 #if NeedFunctionPrototypes
303 			XTestJumpInfo	* /* fjump */
304 #endif
305 			);
306 static void	parse_delay_fake(
307 #if NeedFunctionPrototypes
308 			XTestDelayInfo	* /* tevent */
309 #endif
310 			);
311 static void	send_ack(
312 #if NeedFunctionPrototypes
313 			ClientPtr	 /* client */
314 #endif
315 			);
316 static void	start_play_clock(
317 #if NeedFunctionPrototypes
318 			void
319 #endif
320 			);
321 static void	compute_action_time(
322 #if NeedFunctionPrototypes
323 			struct timeval	* /* rtime */
324 #endif
325 			);
326 static int	find_residual_time(
327 #if NeedFunctionPrototypes
328 			struct timeval	* /* rtime */
329 #endif
330 			);
331 
332 static CARD16	check_time_event(
333 #if NeedFunctionPrototypes
334 			void
335 #endif
336 			);
337 static CARD32	current_ms(
338 #if NeedFunctionPrototypes
339 			struct timeval	* /* otime */
340 #endif
341 			);
342 static int	there_is_room(
343 #if NeedFunctionPrototypes
344 			int	/* actsize */
345 #endif
346 			);
347 
348 /******************************************************************************
349  *
350  * 	stop_stealing_input
351  *
352  *	Stop stealing input actions.
353  */
354 void
stop_stealing_input()355 stop_stealing_input()
356 {
357 /*
358  * put any code that you might need to stop stealing input actions here
359  */
360 	if (packet_index != 0)
361 	{
362 		/*
363 		 * if there is a partially full input action event waiting
364 		 * when this function is called, send it to the client
365 		 */
366 		flush_input_actions();
367 	}
368 }
369 
370 /******************************************************************************
371  *
372  * 	steal_input
373  *
374  *	Start stealing input actions and sending them to the passed-in client.
375  */
376 void
steal_input(client,mode)377 steal_input(client, mode)
378 /*
379  * which client is to receive the input action events
380  */
381 ClientPtr	client;
382 /*
383  * what input action packing mode to use.  one of 0, XTestPACKED_MOTION,
384  * or XTestPACKED_ACTIONS; optionally 'or'ed with XTestEXCLUSIVE,
385  */
386 CARD32		mode;
387 {
388 	if (packet_index != 0)
389 	{
390 		/*
391 		 * if there is a partially full input action event waiting
392 		 * when this function is called, send it to the client
393 		 */
394 		flush_input_actions();
395 	}
396 	else
397 	{
398 		/*
399 		 * otherwise, set up a new input action event
400 		 */
401 		input_action_packet.type = XTestInputActionType;
402 		packet_index = 0;
403 	}
404 	/*
405 	 * set up the new input action packing mode
406 	 */
407 	packed_mode = mode & ~(XTestEXCLUSIVE);
408 	/*
409 	 * keep track of where the mouse is
410 	 */
411 	XTestGetPointerPos(&xtest_mousex, &xtest_mousey);
412 	/*
413 	 * keep track of which client is getting input actions
414 	 */
415 	current_xtest_client = client;
416 	/*
417 	 * find out what time it is
418 	 */
419 	X_GETTIMEOFDAY(&current_time);
420 	/*
421 	 * jump to the initial position of the mouse, using a device type of 0.
422 	 */
423 	XTestStealJumpData(xtest_mousex, xtest_mousey, 0);
424 }
425 
426 /******************************************************************************
427  *
428  *	flush_input_actions
429  *
430  *	Write the input actions event to the current requesting client
431  *	and re-initialize the input action event.
432  */
433 void
flush_input_actions()434 flush_input_actions()
435 {
436 	/*
437 	 * pointer to the input action event
438 	 */
439 	char			*rep;
440 	/*
441 	 * loop index
442 	 */
443 	int			i;
444 
445 	if (packet_index == 0)
446 	{
447 		/*
448 		 * empty input actions event
449 		 */
450 		return;
451 	}
452 	else if (packet_index < XTestACTIONS_SIZE)
453 	{
454 		/*
455 		 * fill to the end of the input actions event with 0's
456 		 */
457 		for (i = packet_index; i <XTestACTIONS_SIZE; i++)
458 		{
459 			input_action_packet.actions[i] = 0;
460 		}
461 	}
462 	rep = (char *) (&input_action_packet);
463 
464 	/*
465 	 * set the serial number of the input action event
466 	 */
467 	input_action_packet.sequenceNumber = current_xtest_client->sequence;
468 	/*
469 	 * send the input action event to the client
470 	 */
471 	WriteEventsToClient(current_xtest_client, 1, (xEvent *) rep);
472 	/*
473 	 * re-initialize the input action event
474 	 */
475 	input_action_event_full = 0;
476 	input_action_packet.type = XTestInputActionType;
477  	packet_index = 0;
478 }
479 
480 /******************************************************************************
481  *
482  *	XTestStealJumpData
483  *
484  *	Create one or more input actions and put them in the input action
485  *	event.  The input actions will be an (maybe) XTestDELAY_ACTION
486  *	and an XTestJUMP_ACTION.
487  */
488 void
XTestStealJumpData(jx,jy,dev_type)489 XTestStealJumpData(jx, jy, dev_type)
490 /*
491  * the x and y coordinates to jump to
492  */
493 short	jx;
494 short	jy;
495 /*
496  * which device caused the jump
497  */
498 int	dev_type;
499 {
500 	XTestJumpInfo 	*jmp_ptr;
501 	/*
502 	 * time delta (in ms) from previous event
503 	 */
504 	CARD16			tchar;
505 
506 	/*
507 	 * Get the time delta from the previous event.  If needed,
508 	 * the check_time_event routine will put an XTestDELAY_ACTION
509 	 * type action in the input action event.
510 	 */
511 	tchar = check_time_event();
512 	if (!there_is_room(sizeof(XTestJumpInfo)))
513 	{
514 		/*
515 		 * If there isn't room in the input action event for
516 		 * an XTestJUMP_ACTION, then send that event to the
517 		 * client and start filling an empty one.
518 		 */
519 		flush_input_actions();
520 	}
521 	/*
522 	 * update the logical mouse position
523 	 */
524 	xtest_mousex = jx;
525 	xtest_mousey = jy;
526 	/*
527 	 * point jmp_ptr to the correct place in the input action event
528 	 */
529 	jmp_ptr = (XTestJumpInfo *)
530 		  &(input_action_packet.actions[packet_index]);
531 	/*
532 	 * compute the input action header
533 	 */
534 	jmp_ptr->header = (XTestPackDeviceID(dev_type) | XTestJUMP_ACTION);
535 	/*
536 	 * set the x and y coordinates to jump to in the input action
537 	 */
538 	jmp_ptr->jumpx = jx;
539 	jmp_ptr->jumpy = jy;
540 	/*
541 	 * set the delay time in the input action
542 	 */
543 	jmp_ptr->delay_time = tchar;
544 	/*
545 	 * increment the packet index by the size of the input action
546 	 */
547 	packet_index = packet_index + sizeof(XTestJumpInfo);
548 	if (packed_mode == 0)
549 	{
550 		/*
551 		 * if input actions are not packed, send the input
552 		 * action event to the client
553 		 */
554 		flush_input_actions();
555 	}
556 }
557 
558 /******************************************************************************
559  *
560  *	current_ms
561  *
562  *	Returns the number of milliseconds from the passed-in time to the
563  *	current time, and then updates the passed-in time to the current time.
564  */
565 static CARD32
current_ms(otime)566 current_ms(otime)
567 struct timeval	*otime;
568 {
569 	struct timeval	tval;
570 	unsigned long	the_ms;
571 	unsigned long	sec;
572 	unsigned long	usec;
573 
574 	/*
575 	 * get the current time
576 	 */
577 	X_GETTIMEOFDAY(&tval);
578 	if (tval.tv_usec < otime->tv_usec)
579 	{
580 		/*
581 		 * borrow a second's worth of microseconds if needed
582 		 */
583 		usec = tval.tv_usec - otime->tv_usec + 1000000;
584 		sec = tval.tv_sec - 1 - otime->tv_sec;
585 	}
586 	else
587 	{
588 		usec = tval.tv_usec - otime->tv_usec;
589 		sec = tval.tv_sec - otime->tv_sec;
590 	}
591 	/*
592 	 * update the passed-in time to the new time
593 	 */
594 	*otime = tval;
595 	/*
596 	 * compute the number of milliseconds contained in
597 	 * 'sec' seconds and 'usec' microseconds
598 	 */
599 	the_ms = (sec * 1000000L + usec) / 1000L;
600 	return (the_ms);
601 }
602 
603 /******************************************************************************
604  *
605  *	check_time_event
606  *
607  *	If time delta is > XTestSHORT_DELAY_TIME then insert a time event
608  *	and return 0; else return the delay time.
609  */
610 static CARD16
check_time_event()611 check_time_event()
612 {
613 	CARD32		tstamp;
614 	CARD16		tchar;
615 	XTestDelayInfo	*tptr;
616 
617 	/*
618 	 * get the number of milliseconds between input actions
619 	 */
620 	tstamp = current_ms(&current_time);
621 	/*
622 	 * if the number of milliseconds is too large to fit in a CARD16,
623 	 * then add a XTestDELAY_ACTION to the input action event.
624 	 */
625 	if (tstamp > XTestSHORT_DELAY_TIME)
626 	{
627 		/*
628 		 * If there isn't room in the input action event for
629 		 * an XTestDELAY_ACTION, then send that event to the
630 		 * client and start filling an empty one.
631 		 */
632 		if (!there_is_room(sizeof(XTestDelayInfo)))
633 		{
634 			flush_input_actions();
635 		}
636 		/*
637 		 * point tptr to the correct place in the input action event
638 		 */
639 		tptr = (XTestDelayInfo *)
640 		       (&(input_action_packet.actions[packet_index]));
641 		/*
642 		 * compute the input action header
643 		 */
644 		tptr->header = XTestPackDeviceID(XTestDELAY_DEVICE_ID) |
645 			       XTestDELAY_ACTION;
646 		/*
647 		 * set the delay time in the input action
648 		 */
649 		tptr->delay_time = tstamp;
650 		/*
651 		 * increment the packet index by the size of the input action
652 		 */
653 		packet_index = packet_index + (sizeof(XTestDelayInfo));
654 		if (packed_mode != XTestPACKED_ACTIONS)
655 		{
656 			/*
657 			 * if input actions are not packed, send the input
658 			 * action event to the client
659 			 */
660 			flush_input_actions();
661 		}
662 		/*
663 		 * set the returned delay time to 0
664 		 */
665 		tchar = 0;
666 	}
667 	else
668 	{
669 		/*
670 		 * set the returned delay time to the computed delay time
671 		 */
672 		tchar = tstamp;
673 	}
674 	return(tchar);
675 }
676 
677 /******************************************************************************
678  *
679  *	there_is_room
680  *
681  *	Checks if there is room in the input_action_packet for an input action
682  *	of the size actsize bytes.  Returns 1 if there is space, 0 otherwise.
683  *
684  */
685 static int
there_is_room(actsize)686 there_is_room(actsize)
687 /*
688  * the number of bytes of space needed
689  */
690 int	actsize;
691 {
692 	if ((packet_index + actsize) > XTestACTIONS_SIZE)
693 	{
694 		input_action_event_full = 1;
695 		return(0);
696 	}
697 	else
698 	{
699 		return(1);
700 	}
701 }
702 
703 /******************************************************************************
704  *
705  *	XTestStealMotionData
706  *
707  *	Put motion information from the locator into an input action.
708  *
709  *	called from x_hil.c
710  */
711 void
XTestStealMotionData(dx,dy,dev_type,mx,my)712 XTestStealMotionData(dx, dy, dev_type, mx, my)
713 /*
714  * the x and y delta motion of the locator
715  */
716 short	dx;
717 short	dy;
718 /*
719  * which locator did the moving
720  */
721 int	dev_type;
722 /*
723  * the x and y position of the locator before the delta motion
724  */
725 short	mx;
726 short	my;
727 {
728 	/*
729 	 * pointer to a XTestMOTION_ACTION input action
730 	 */
731 	XTestMotionInfo	*fm;
732 	/*
733 	 * time delta from previous event
734 	 */
735 	CARD16			tchar;
736 
737 	/*
738 	 * if the current position of the locator is not the same as
739 	 * the logical position, then update the logical position
740 	 */
741 	if ((mx != xtest_mousex) || (my != xtest_mousey))
742 	{
743 		XTestStealJumpData(mx, my, dev_type);
744 	}
745 	/*
746 	 * if the delta motion is outside the range that can
747 	 * be held in a motion input action, use a jump input action
748 	 */
749 	if ((dx > XTestMOTION_MAX) || (dx < XTestMOTION_MIN) ||
750 	    (dy > XTestMOTION_MAX) || (dy < XTestMOTION_MIN))
751 	{
752 		XTestStealJumpData((xtest_mousex + dx),
753 				   (xtest_mousey + dy), dev_type);
754 	}
755 	else
756 	{
757 		/*
758 		 * compute the new logical position of the mouse
759 		 */
760 		xtest_mousex += dx;
761 		xtest_mousey += dy;
762 		/*
763 		 * Get the time delta from the previous event.  If needed,
764 		 * the check_time_event routine will put an XTestDELAY_ACTION
765 		 * type action in the input action event.
766 		 */
767 		tchar = check_time_event();
768 		/*
769 		 * If there isn't room in the input action event for
770 		 * an XTestDELAY_ACTION, then send that event to the
771 		 * client and start filling an empty one.
772 		 */
773 		if (!there_is_room(sizeof(XTestMotionInfo)))
774 		{
775 			flush_input_actions();
776 		/*
777 		 * point fm to the correct place in the input action event
778 		 */
779 		}
780 		fm = (XTestMotionInfo *)
781 		     &(input_action_packet.actions[packet_index]);
782 		/*
783 		 * compute the input action header
784 		 */
785 		fm->header = XTestMOTION_ACTION;
786 		if (dx < 0)
787 		{
788 			fm->header |= XTestX_NEGATIVE;
789 			dx = abs(dx);
790 		}
791 		if (dy < 0)
792 		{
793 			fm->header |= XTestY_NEGATIVE;
794 			dy = abs(dy);
795 		}
796 		fm->header |= XTestPackDeviceID(dev_type);
797 		/*
798 		 * compute the motion data byte
799 		 */
800 		fm->motion_data = XTestPackYMotionValue(dy);
801 		fm->motion_data |= XTestPackXMotionValue(dx);
802 		/*
803 		 * set the delay time in the input action
804 		 */
805 		fm->delay_time = tchar;
806 		/*
807 		 * increment the packet index by the size of the input action
808 		 */
809 		packet_index = packet_index + sizeof(XTestMotionInfo);
810 		if (packed_mode == 0)
811 		{
812 			/*
813 			 * if input actions are not packed, send the input
814 			 * action event to the client
815 			 */
816 			flush_input_actions();
817 		}
818 
819 	}
820 }
821 
822 /******************************************************************************
823  *
824  *	XTestStealKeyData
825  *
826  * 	Place this key data in the input_action_packet.
827  *
828  */
829 Bool
XTestStealKeyData(keycode,keystate,dev_type,locx,locy)830 XTestStealKeyData(keycode, keystate, dev_type, locx, locy)
831 /*
832  * which key/button moved
833  */
834 CARD8	keycode;
835 /*
836  * whether the key/button was pressed or released
837  */
838 char	keystate;
839 /*
840  * which device caused the input action
841  */
842 int	dev_type;
843 /*
844  * the x and y coordinates of the locator when the action happenned
845  */
846 short	locx;
847 short	locy;
848 {
849 	/*
850 	 * pointer to key/button motion input action
851 	 */
852 	XTestKeyInfo	*kp;
853 	/*
854 	 * time delta from previous event
855 	 */
856 	CARD16			tchar;
857 	char		keytrans;
858 
859 	/*
860 	 * update the logical position of the locator if the physical position
861 	 * of the locator is not the same as the logical position.
862 	 */
863 	if ((locx != xtest_mousex) || (locy != xtest_mousey))
864 	{
865 		XTestStealJumpData(locx, locy, dev_type);
866 	}
867 	/*
868 	 * Get the time delta from the previous event.  If needed,
869 	 * the check_time_event routine will put an XTestDELAY_ACTION
870 	 * type action in the input action event.
871 	 */
872 	tchar = check_time_event();
873 	if (!there_is_room(sizeof(XTestKeyInfo)))
874 	{
875 		/*
876 		 * If there isn't room in the input action event for
877 		 * an XTestDELAY_ACTION, then send that event to the
878 		 * client and start filling an empty one.
879 		 */
880 		flush_input_actions();
881 	}
882 	/*
883 	 * point kp to the correct place in the input action event
884 	 */
885 	kp = (XTestKeyInfo *)
886 	     (&(input_action_packet.actions[packet_index]));
887 	/*
888 	 * compute the input action header
889 	 */
890 	kp->header = XTestPackDeviceID(dev_type);
891 	if ((keystate == KeyRelease) || (keystate == ButtonRelease))
892 	{
893 		keytrans = XTestKEY_UP;
894 	}
895 	else if ((keystate == KeyPress) || (keystate == ButtonPress))
896 	{
897 		keytrans = XTestKEY_DOWN;
898 	}
899 	else
900 	{
901 		printf("%s: invalid key/button state %d.\n",
902 		       XTestEXTENSION_NAME,
903 		       keystate);
904 	}
905 	kp->header = kp->header | keytrans | XTestKEY_ACTION;
906 	/*
907 	 * set the keycode in the input action
908 	 */
909 	kp->keycode = keycode;
910 	/*
911 	 * set the delay time in the input action
912 	 */
913 	kp->delay_time = tchar;
914 	/*
915 	 * increment the packet index by the size of the input action
916 	 */
917 	packet_index = packet_index + sizeof(XTestKeyInfo);
918 	/*
919 	 * if the command key has been released or input actions are not
920 	 * packed, send the input action event to the client
921 	 */
922  	if(((keycode == xtest_command_key) && (keystate == KeyRelease)) ||
923 	   (packed_mode != XTestPACKED_ACTIONS))
924 	{
925 		flush_input_actions();
926 	}
927 	/* return TRUE if the event should be passed on to DIX */
928 	if (exclusive_steal)
929 		return ((keystate == KeyRelease) &&
930 			(keycode == xtest_command_key));
931 	else
932 		return ((keystate != KeyRelease) ||
933 			(keycode != xtest_command_key));
934 }
935 
936 /******************************************************************************
937  *
938  *	parse_fake_input
939  *
940  *	Parsing routine for a XTestFakeInput request.  It will take a request
941  *	and parse its contents into the input action array.  Eventually the
942  *	XTestProcessInputAction routine will be called to take input actions
943  *	from the input action array and send them to the server to be handled.
944  */
945 void
parse_fake_input(client,req)946 parse_fake_input(client, req)
947 /*
948  * which client did the XTestFakeInput request
949  */
950 ClientPtr	client;
951 /*
952  * a pointer to the xTestFakeInputReq structure sent by the client
953  */
954 char		*req;
955 {
956 	/*
957 	 * if set to 1, done processing input actions from the request
958 	 */
959 	int	        	done = 0;
960 	/*
961 	 * type of input action
962 	 */
963 	CARD8			action_type;
964 	/*
965 	 * device type
966 	 */
967 	CARD8			dev_type;
968 	/*
969 	 * pointer to an xTestFakeInputReq structure
970 	 */
971 	xTestFakeInputReq	*request;
972 	/*
973 	 * holds the index into the action list in the request
974 	 */
975 	int			parse_index;
976 
977 	/*
978 	 * get a correct-type pointer to the client-supplied request data
979 	 */
980 	request = (xTestFakeInputReq *) req;
981 	/*
982 	 * save the acknowledge requested state for use in
983 	 * XTestProcessInputAction
984 	 */
985 	acknowledge = request->ack;
986 	/*
987 	 * set up an index into the action list in the request
988 	 */
989 	parse_index = 0;
990 	if (write_index >= ACTION_ARRAY_SIZE)
991 	{
992 		/*
993 		 * if the input action array is full, don't add any more
994 		 */
995 		done = 1;
996 	}
997 	while (!done)
998 	{
999 		/*
1000 		 * get the type of input action in the list
1001 		 */
1002 		action_type = (request->action_list[parse_index])
1003 			      & XTestACTION_TYPE_MASK;
1004 		/*
1005 		 * get the type of device in the list
1006 		 */
1007 		dev_type = XTestUnpackDeviceID(request->action_list[parse_index]);
1008 		/*
1009 		 * process the input action appropriately
1010 		 */
1011 		switch (action_type)
1012 		{
1013 		case XTestKEY_ACTION:
1014 			parse_key_fake((XTestKeyInfo *)
1015 				       &(request->action_list[parse_index]));
1016 			parse_index = parse_index + sizeof(XTestKeyInfo);
1017 			break;
1018 		case XTestMOTION_ACTION:
1019 			parse_motion_fake((XTestMotionInfo *)
1020 					  &(request->action_list[parse_index]));
1021 			parse_index = parse_index + sizeof(XTestMotionInfo);
1022 			break;
1023 		case XTestJUMP_ACTION:
1024 			parse_jump_fake((XTestJumpInfo *)
1025 					&(request->action_list[parse_index]));
1026 			parse_index = parse_index + sizeof(XTestJumpInfo);
1027 			break;
1028 		case XTestDELAY_ACTION:
1029 			if (dev_type == XTestDELAY_DEVICE_ID)
1030 			{
1031 				parse_delay_fake((XTestDelayInfo *)
1032 						 &(request->action_list[parse_index]));
1033 				parse_index = parse_index +
1034 					      sizeof(XTestDelayInfo);
1035 			}
1036 			else
1037 			{
1038 				/*
1039 				 * An invalid input action header byte has
1040 				 * been detected, so there are no more
1041 				 * input actions in this request.
1042 				 * The intended invalid action header byte
1043 				 * for this case should have a value of 0.
1044 				 */
1045 				done = 1;
1046 			}
1047 			break;
1048 		}
1049 		if (parse_index >= XTestMAX_ACTION_LIST_SIZE)
1050 		{
1051 			/*
1052 			 * entire XTestFakeInput request has been processed
1053 			 */
1054 			done = 1;
1055 		}
1056 		if (write_index >= ACTION_ARRAY_SIZE)
1057 		{
1058 			/*
1059 			 * no room in the input actions array
1060 			 */
1061 			done = 1;
1062 		}
1063 	}
1064 	if (write_index > read_index)
1065 	{
1066 		/*
1067 		 * there are fake input actions in the input action array
1068 		 * to be given to the server
1069 		 */
1070 		playback_on = 1;
1071 		playback_client = client;
1072 	}
1073 }
1074 
1075 /******************************************************************************
1076  *
1077  *	parse_key_fake
1078  *
1079  *	Called from parse_fake_input.
1080  *
1081  *	Copy the fake key input action from its packed form into the array of
1082  *	pending input events.
1083  */
1084 static void
parse_key_fake(fkey)1085 parse_key_fake(fkey)
1086 XTestKeyInfo	*fkey;
1087 {
1088 	action_array[write_index].type = XTestKEY_ACTION;
1089 	action_array[write_index].device = XTestUnpackDeviceID(fkey->header);
1090 	action_array[write_index].keycode = fkey->keycode;
1091 	action_array[write_index].keystate = fkey->header & XTestKEY_STATE_MASK;
1092 	action_array[write_index].delay_time = fkey->delay_time;
1093 	write_index++;
1094 }
1095 
1096 /******************************************************************************
1097  *
1098  *	parse_motion_fake
1099  *
1100  *	Called from parse_fake_input.
1101  *
1102  *	Copy the fake motion input action from its packed form into the array of
1103  *	pending input events.
1104  */
1105 static void
parse_motion_fake(fmotion)1106 parse_motion_fake(fmotion)
1107 XTestMotionInfo	*fmotion;
1108 {
1109 	int	dx;
1110 	int	dy;
1111 
1112 	dx = (XTestUnpackXMotionValue(fmotion->motion_data));
1113 	dy = (XTestUnpackYMotionValue(fmotion->motion_data));
1114 	if (((fmotion->header) & XTestX_SIGN_BIT_MASK) == XTestX_NEGATIVE)
1115 	{
1116 		pmousex -= dx;
1117 	}
1118 	else
1119 	{
1120 		pmousex += dx;
1121 	}
1122 	if (((fmotion->header) & XTestY_SIGN_BIT_MASK) == XTestY_NEGATIVE)
1123 	{
1124 		pmousey -= dy;
1125 	}
1126 	else
1127 	{
1128 		pmousey += dy;
1129 	}
1130 	action_array[write_index].type = XTestJUMP_ACTION;
1131 	action_array[write_index].device = XTestUnpackDeviceID(fmotion->header);
1132 	action_array[write_index].x = pmousex;
1133 	action_array[write_index].y = pmousey;
1134 	action_array[write_index].delay_time = fmotion->delay_time;
1135 	write_index++;
1136 }
1137 
1138 /******************************************************************************
1139  *
1140  *	parse_jump_fake
1141  *
1142  *	Called from parse_fake_input.
1143  *
1144  *	Copy the fake jump input action from its packed form into the array of
1145  *	pending input events.
1146  */
1147 static void
parse_jump_fake(fjump)1148 parse_jump_fake(fjump)
1149 XTestJumpInfo	*fjump;
1150 {
1151 	pmousex = fjump->jumpx;
1152 	pmousey = fjump->jumpy;
1153 	action_array[write_index].type = XTestJUMP_ACTION;
1154 	action_array[write_index].device = XTestUnpackDeviceID(fjump->header);
1155 	action_array[write_index].x = pmousex;
1156 	action_array[write_index].y = pmousey;
1157 	action_array[write_index].delay_time = fjump->delay_time;
1158 	write_index++;
1159 }
1160 
1161 /******************************************************************************
1162  *
1163  *	parse_delay_fake
1164  *
1165  *	Called from parse_fake_input.
1166  *
1167  *	Copy the fake delay input action from its packed form into the array of
1168  *	pending input events.
1169  */
1170 static void
parse_delay_fake(tevent)1171 parse_delay_fake(tevent)
1172 XTestDelayInfo	*tevent;
1173 {
1174 	action_array[write_index].type = XTestDELAY_ACTION;
1175 	action_array[write_index].delay_time = tevent->delay_time;
1176 	write_index++;
1177 }
1178 
1179 /******************************************************************************
1180  *
1181  *	XTestComputeWaitTime
1182  *
1183  *	Compute the amount of time the server should wait before sending the
1184  *	next monitor event in playback mode.
1185  */
1186 void
XTestComputeWaitTime(waittime)1187 XTestComputeWaitTime(waittime)
1188 struct timeval	*waittime;
1189 {
1190 	/*
1191 	 * The playback_on flag is set to 1 in parse_fake_input.  It is set to
1192 	 * 0 in XTestProcessInputAction if the server has replayed all input
1193 	 * actions.
1194 	 */
1195 	if (playback_on)
1196 	{
1197 		if (!play_clock)
1198 		{
1199 			/*
1200 			 * if the playback clock has never been set,
1201 			 * then do it now
1202 			 */
1203 			start_play_clock();
1204 		}
1205 		/*
1206 		 * We need to save the waittime the first time through.  This
1207 		 * is a value the server uses, and we have to restore it when
1208 		 * all of the input actions are processed by the server.
1209 		 */
1210 		if (!time_saved)
1211 		{
1212 			saved_sec = waittime->tv_sec;
1213 			saved_usec = waittime->tv_usec;
1214 			time_saved = 1;
1215 		}
1216 		if (go_for_next)
1217 		{
1218 			/*
1219 			 * if we just processed an input action, figure out
1220 			 * how long to wait for the next input action
1221 			 */
1222 			compute_action_time(&rtime);
1223 		}
1224 		else
1225 		{
1226 			/*
1227 			 * else just find out how much more time to wait
1228 			 * on the current input action
1229 			 */
1230 			(void)find_residual_time(&rtime);
1231 		}
1232 		waittime->tv_sec = rtime.tv_sec;
1233 		waittime->tv_usec = rtime.tv_usec;
1234 	}
1235 }
1236 
1237 /******************************************************************************
1238  *
1239  *	XTestProcessInputAction
1240  *
1241  *	If there are any input actions in the input action array,
1242  *	then take one out and process it.
1243  *
1244  */
1245 int
XTestProcessInputAction(readable,waittime)1246 XTestProcessInputAction(readable, waittime)
1247 /*
1248  * This is the value that a 'select' function returned just before this
1249  * routine was called.  If the select timed out, this value will be 0.
1250  *
1251  * This extension modifies the select call's timeout value to cause the
1252  * select to time out when the next input action is ready to given to
1253  * the server.  This routine is called immediately after the select, to
1254  * give it a chance to process an input action.  If we have an input action
1255  * to process and the only reason that the select returned was because it
1256  * timed out, then we change the select value to 1 and return 1 instead of 0.
1257  */
1258 int		readable;
1259 /*
1260  * this is the timeout value that the select was called with
1261  */
1262 struct timeval	*waittime;
1263 {
1264 int mousex, mousey;
1265 	/*
1266 	 * if playback_on is 0, then the input action array is empty
1267 	 */
1268 	if (playback_on)
1269 	{
1270 		restorewait = waittime;
1271 		/*
1272 		 * figure out if we need to wait for the next input action
1273 		 */
1274 		if (find_residual_time(&rtime) > 0)
1275 		{
1276 			/*
1277 			 * still have to wait before processing the current
1278 			 * input action
1279 			 */
1280 			go_for_next = 0;
1281 		}
1282 		else
1283 		{
1284 			/*
1285 			 * don't have to wait any longer before processing
1286 			 * the current input action
1287 			 */
1288 			go_for_next = 1;
1289 		}
1290 		/*
1291 		 * if we have an input action to process and the only reason
1292 		 * that the select returned was because it timed out, then we
1293 		 * change the select value to 1 and return 1 instead of 0
1294 		 */
1295 		if (readable == 0)
1296 		{
1297 			readable++;
1298 		}
1299 		/*
1300 		 * if we don't need to wait, then get an input action from
1301 		 * the input action array and process it
1302 		 */
1303 		if (go_for_next)
1304 		{
1305 			/*
1306 			 * There are three possible types of input actions in
1307 			 * the input action array (motion input actions are
1308 			 * converted to jump input actions before being put
1309 			 * into the input action array).  Delay input actions
1310 			 * are processed by the compute_action_time function
1311 			 * which is called from XTestComputeWaitTime.  The
1312 			 * other two types of input actions are processed here.
1313 			 */
1314 			if (action_array[read_index].type == XTestJUMP_ACTION)
1315 			{
1316 				XTestJumpPointer(
1317 					action_array[read_index].x,
1318 					action_array[read_index].y,
1319 					action_array[read_index].device);
1320 				mx = action_array[read_index].x;
1321 				my = action_array[read_index].y;
1322 			}
1323 			if (action_array[read_index].type == XTestKEY_ACTION)
1324 			    {
1325 			    GetSpritePosition(&mousex, &mousey);
1326 			    XTestGenerateEvent(
1327 				     action_array[read_index].device,
1328 				     action_array[read_index].keycode,
1329 				     action_array[read_index].keystate,
1330 				     mousex,
1331 				     mousey);
1332 			    }
1333 			read_index++;
1334 			/*
1335 			 * if all input actions are processed, then restore
1336 			 * the server state
1337 			 */
1338 			if (read_index >= write_index)
1339 			{
1340 				waittime->tv_sec = saved_sec;
1341 				waittime->tv_usec = saved_usec;
1342 				time_saved = 0;
1343 				playback_on = 0;
1344 				if (acknowledge)
1345 				{
1346 					/*
1347 					 * if the playback client is waiting
1348 					 * for an xTestFakeAck event, send
1349 					 * it to him
1350 					 */
1351 					send_ack(playback_client);
1352 					acknowledge = 0;
1353 				}
1354 				write_index = 0;
1355 				read_index = 0;
1356 				playback_client = (ClientPtr) NULL;
1357 				play_clock = 0;
1358 			}
1359 		}
1360 	}
1361 	return(readable);
1362 }
1363 
1364 /******************************************************************************
1365  *
1366  *	send_ack
1367  *
1368  *	send an xTestFakeAck event to the client
1369  */
1370 static void
send_ack(client)1371 send_ack(client)
1372 ClientPtr	client;
1373 {
1374 	xTestFakeAckEvent  rep;
1375 
1376 	/*
1377 	 * set the serial number of the xTestFakeAck event
1378 	 */
1379 	rep.sequenceNumber = client->sequence;
1380 	rep.type = XTestFakeAckType;
1381 	WriteEventsToClient(client, 1, (xEvent *) &rep);
1382 }
1383 
1384 /******************************************************************************
1385  *
1386  *	start_play_clock
1387  *
1388  *	start the clock for play back.
1389  */
1390 static void
start_play_clock()1391 start_play_clock()
1392 {
1393 	X_GETTIMEOFDAY(&play_time);
1394 	/*
1395 	 * flag that play_time is valid
1396 	 */
1397 	play_clock = 1;
1398 }
1399 
1400 /******************************************************************************
1401  *
1402  *	compute_action_time
1403  *
1404  *	Set the play clock to the time when the next input action should be put
1405  *	into the server's input queue.  Fill the rtime structure with values
1406  *	for the delta until the time for the next input action.
1407  */
1408 static void
compute_action_time(rtime)1409 compute_action_time(rtime)
1410 struct timeval	*rtime;
1411 {
1412 	/*
1413 	 * holds the delay time in milliseconds
1414 	 */
1415 	unsigned long	dtime;
1416 	/*
1417 	 * holds the number of microseconds in the sum of the dtime value
1418 	 * and the play_time value
1419 	 */
1420 	unsigned long	tot_usec;
1421 	/*
1422 	 * holds the number of seconds and microseconds in the
1423 	 * dtime value
1424 	 */
1425 	unsigned long 	sec;
1426 	unsigned long 	usec;
1427 	/*
1428 	 * holds the current time
1429 	 */
1430 	struct timeval	btime;
1431 
1432 	/*
1433 	 * Put the time from the current input action in dtime
1434 	 */
1435 	dtime = action_array[read_index].delay_time;
1436 	/*
1437 	 * If the current input action is a delay input action,
1438 	 * add in the time from the following input action.
1439 	 */
1440 	if ((action_array[read_index].type == XTestDELAY_ACTION) &&
1441 	    ((read_index + 1) < write_index))
1442 	{
1443 		read_index++;
1444 		dtime = dtime + action_array[read_index].delay_time;
1445 	}
1446 	/*
1447 	 * compute the number of seconds and microseconds in the
1448 	 * dtime value
1449 	 */
1450   	sec = dtime / 1000;
1451   	usec = (dtime % 1000) * 1000;
1452 	/*
1453 	 * get the current time in btime
1454 	 */
1455 	X_GETTIMEOFDAY(&btime);
1456 	/*
1457 	 * compute the number of microseconds in the sum of the dtime value
1458 	 * and the current usec value
1459 	 */
1460 	tot_usec = btime.tv_usec + usec;
1461 	/*
1462 	 * if it is greater than one second's worth, adjust the seconds
1463 	 */
1464 	if (tot_usec >= 1000000)
1465 	{
1466 		tot_usec -= 1000000;
1467 		sec++;
1468 	}
1469 	play_time.tv_usec = tot_usec;
1470 	play_time.tv_sec = btime.tv_sec + sec;
1471 	/*
1472 	 * put the time until the next input action in rtime
1473 	 */
1474 	rtime->tv_sec = sec;
1475 	rtime->tv_usec = usec;
1476 }
1477 
1478 /******************************************************************************
1479  *
1480  *	find_residual_time
1481  *
1482  *	Find the time interval from the current time to the value in play_time.
1483  *	This is the time to wait till putting the next input action into the
1484  *	server's input queue.  If the time is already up, reset play_time to
1485  *	the current time.
1486  */
1487 static int
find_residual_time(the_residual)1488 find_residual_time(the_residual)
1489 struct timeval	*the_residual;
1490 {
1491 	/*
1492 	 * if > 0, there is time to wait.  If < 0, then don't wait
1493 	 */
1494 	int		wait = 1;
1495 	/*
1496 	 * holds the current time
1497 	 */
1498 	struct timeval	btime;
1499 	/*
1500 	 * holds the current time in seconds and microseconds
1501 	 */
1502 	unsigned long	bsec;
1503 	unsigned long	busec;
1504 	/*
1505 	 * holds the playback time in seconds and microseconds
1506 	 */
1507 	unsigned long	psec;
1508 	unsigned long	pusec;
1509 
1510 	/*
1511 	 * get the current time in btime
1512 	 */
1513 	X_GETTIMEOFDAY(&btime);
1514 	/*
1515 	 * get the current time in seconds and microseconds
1516 	 */
1517 	bsec = btime.tv_sec;
1518 	busec = btime.tv_usec;
1519 	/*
1520 	 * get the playback time in seconds and microseconds
1521 	 */
1522 	psec = play_time.tv_sec;
1523 	pusec = play_time.tv_usec;
1524 	/*
1525 	 * if the current time is already later than the playback time,
1526 	 * we don't need to wait
1527 	 */
1528 	if (bsec > psec)
1529 	{
1530 	    wait = -1;
1531 	}
1532 	else
1533 	{
1534 		if (bsec == psec)
1535 		{
1536 			/*
1537 			 * if the current and playback times have the same
1538 			 * second value, then compare the microsecond values
1539 			 */
1540 			if ( busec >= pusec)
1541 			{
1542 				/*
1543 				 * if the current time is already later than
1544 				 * the playback time, we don't need to wait
1545 				 */
1546 				wait = -1;
1547 			}
1548 			else
1549 			{
1550 				the_residual->tv_usec = pusec - busec;
1551 				the_residual->tv_sec = 0;
1552 			}
1553 		}
1554 		else
1555 		{
1556 			if (busec > pusec)
1557 			{
1558 				/*
1559 				 * 'borrow' a second's worth of microseconds
1560 				 * from the seconds left to wait
1561 				 */
1562 				the_residual->tv_usec = 1000000 - busec + pusec;
1563 				psec--;
1564 				the_residual->tv_sec = psec - bsec;
1565 			}
1566 			else
1567 			{
1568 				the_residual->tv_sec = psec - bsec;
1569 				the_residual->tv_usec = pusec - busec;
1570 			}
1571 		}
1572 	}
1573 	if (wait < 0)
1574 	{
1575 		/*
1576 		 * if don't need to wait, set the playback time
1577 		 * to the current time
1578 		 */
1579 		X_GETTIMEOFDAY(&play_time);
1580 		/*
1581 		 * set the time to wait to 0
1582 		 */
1583 		the_residual->tv_sec = 0;
1584 		the_residual->tv_usec = 0;
1585 	}
1586 	return(wait);
1587 }
1588 
1589 /******************************************************************************
1590  *
1591  *	abort_play_back
1592  */
1593 void
abort_play_back()1594 abort_play_back()
1595 {
1596 	/*
1597 	 * If we were playing back input actions at the time of the abort,
1598 	 * restore the original wait time for the select in the main wait
1599 	 * loop of the server
1600 	 */
1601 	if (playback_on)
1602 	{
1603 		restorewait->tv_sec = saved_sec;
1604 		restorewait->tv_usec = saved_usec;
1605 	}
1606 	/*
1607 	 * make the input action array empty
1608 	 */
1609 	read_index = 0;
1610 	write_index = 0;
1611 	/*
1612 	 * we are no longer playing back anything
1613 	 */
1614 	playback_on = 0;
1615 	play_clock = 0;
1616 	go_for_next = 1;
1617 	/*
1618 	 * there is no valid wait time saved any more
1619 	 */
1620 	time_saved = 0;
1621 	/*
1622 	 * there are no valid clients using this extension
1623 	 */
1624 	playback_client = (ClientPtr) NULL;
1625 	current_xtest_client = (ClientPtr) NULL;
1626 }
1627 
1628 /******************************************************************************
1629  *
1630  *	return_input_array_size
1631  *
1632  *	Return the number of input actions in the input action array.
1633  */
1634 void
return_input_array_size(client)1635 return_input_array_size(client)
1636 /*
1637  * which client to send the reply to
1638  */
1639 ClientPtr	client;
1640 {
1641 	xTestQueryInputSizeReply  rep;
1642 
1643 	rep.type = X_Reply;
1644 	/*
1645 	 * set the serial number of the reply
1646 	 */
1647 	rep.sequenceNumber = client->sequence;
1648 	rep.length = 0;
1649 	rep.size_return = ACTION_ARRAY_SIZE;
1650 	WriteReplyToClient(client,
1651 			   sizeof(xTestQueryInputSizeReply),
1652 			   (pointer) &rep);
1653 }
1654