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 $ */
6 * This file contains the device dependent parts of the input
13 Copyright (c) 1986, 1987, 1988 X Consortium
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:
22 The above copyright notice and this permission notice shall be included in
23 all copies or substantial portions of the Software.
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.
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.
37 Copyright 1986, 1987, 1988 by Hewlett-Packard Corporation
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.
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.
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.
58 /***************************************************************
60 ***************************************************************/
71 #include "dixstruct.h"
72 #define XTestSERVER_SIDE
73 #include "xtestext1.h"
77 /***************************************************************
79 ***************************************************************/
82 * the size of the fake input action array
84 #define ACTION_ARRAY_SIZE 100
86 /***************************************************************
88 ***************************************************************/
91 * Holds the xTestInputAction event type code.
92 * This is defined in xtestext1di.c.
94 extern int XTestInputActionType;
96 * Holds the xTestFakeAck event type code.
97 * This is defined in xtestext1di.c.
99 extern int XTestFakeAckType;
101 * used in the WriteReplyToClient macro
103 extern int exclusive_steal;
105 /***************************************************************
107 ***************************************************************/
110 * array to hold fake input actions
114 * holds the action type, one of: XTestDELAY_ACTION,
115 * XTestKEY_ACTION, XTestMOTION_ACTION, XTestJUMP_ACTION
119 * holds the device type, in the range 0 to 15
123 * for XTestKEY_ACTION type, holds the keycode
127 * for XTestKEY_ACTION type, holds the key up/down state
131 * for XTestMOTION_ACTION and XTestJUMP_ACTION types,
132 * holds the x and y coordinates to move the mouse to
137 * holds the time to delay (in milliseconds) before performing
141 }action_array[ACTION_ARRAY_SIZE];
144 * write index for input action array
146 static int write_index = 0;
148 * read index for input action array
150 static int read_index = 0;
152 * this is where the input actions are accumulated until they are sent
153 * to a client (in a wire event)
155 static xTestInputActionEvent input_action_packet;
157 * holds the index (in bytes) into the input actions buffer in the
158 * current input action event
160 static int packet_index;
162 * set to 1 when the input action event is full and needs to be sent to the
165 static int input_action_event_full = 0;
167 * logical x position of the mouse during input action gathering
171 * logical y position of the mouse during input action gathering
175 * logical x position of the mouse during input action playback
179 * logical y position of the mouse during input action playback
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
186 static short pmousex;
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
191 static short pmousey;
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
199 * identity of the client using XTestGetInput to get user input actions
201 ClientPtr current_xtest_client;
203 * if 1 send multiple input actions per XTestInputAction event;
204 * if 0 send one input action per XTestInputAction event
206 static char packed_mode;
208 * identity of the client using the XTestFakeInput function to send some
209 * fake input actions to the server
211 ClientPtr playback_client = NULL;
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
217 static int acknowledge = 0;
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.
223 static int saved_sec;
224 static int saved_usec;
226 * Set to 1 when there is a valid time in saved_sec and saved_usec.
228 static int time_saved = 0;
230 * holds the extension's notion of what the current time is while it is
231 * sending input actions to a client
233 static struct timeval current_time;
235 * holds the time when the extension should place the next fake input action
236 * into the server's normal events queue
238 static struct timeval play_time;
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
243 static char play_clock = 0;
245 * holds the amount of time left until the next input action from the
246 * input action array can be sent to the server
248 static struct timeval rtime;
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.
255 static int go_for_next = 1;
257 * needed to restore waitime if playback is to be aborted
259 static struct timeval *restorewait;
261 * tmon special command key
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.
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.
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.
282 * set and also referenced in device layer
283 * XXX there should be a way to set this through the protocol
285 KeyCode xtest_command_key = 0;
287 /***************************************************************
288 * function declarations
289 ***************************************************************/
291 static void parse_key_fake(
292 #if NeedFunctionPrototypes
293 XTestKeyInfo * /* fkey */
296 static void parse_motion_fake(
297 #if NeedFunctionPrototypes
298 XTestMotionInfo * /* fmotion */
301 static void parse_jump_fake(
302 #if NeedFunctionPrototypes
303 XTestJumpInfo * /* fjump */
306 static void parse_delay_fake(
307 #if NeedFunctionPrototypes
308 XTestDelayInfo * /* tevent */
311 static void send_ack(
312 #if NeedFunctionPrototypes
313 ClientPtr /* client */
316 static void start_play_clock(
317 #if NeedFunctionPrototypes
321 static void compute_action_time(
322 #if NeedFunctionPrototypes
323 struct timeval * /* rtime */
326 static int find_residual_time(
327 #if NeedFunctionPrototypes
328 struct timeval * /* rtime */
332 static CARD16 check_time_event(
333 #if NeedFunctionPrototypes
337 static CARD32 current_ms(
338 #if NeedFunctionPrototypes
339 struct timeval * /* otime */
342 static int there_is_room(
343 #if NeedFunctionPrototypes
348 /******************************************************************************
350 * stop_stealing_input
352 * Stop stealing input actions.
355 stop_stealing_input()
358 * put any code that you might need to stop stealing input actions here
360 if (packet_index != 0)
363 * if there is a partially full input action event waiting
364 * when this function is called, send it to the client
366 flush_input_actions();
370 /******************************************************************************
374 * Start stealing input actions and sending them to the passed-in client.
377 steal_input(client, mode)
379 * which client is to receive the input action events
383 * what input action packing mode to use. one of 0, XTestPACKED_MOTION,
384 * or XTestPACKED_ACTIONS; optionally 'or'ed with XTestEXCLUSIVE,
388 if (packet_index != 0)
391 * if there is a partially full input action event waiting
392 * when this function is called, send it to the client
394 flush_input_actions();
399 * otherwise, set up a new input action event
401 input_action_packet.type = XTestInputActionType;
405 * set up the new input action packing mode
407 packed_mode = mode & ~(XTestEXCLUSIVE);
409 * keep track of where the mouse is
411 XTestGetPointerPos(&xtest_mousex, &xtest_mousey);
413 * keep track of which client is getting input actions
415 current_xtest_client = client;
417 * find out what time it is
419 X_GETTIMEOFDAY(¤t_time);
421 * jump to the initial position of the mouse, using a device type of 0.
423 XTestStealJumpData(xtest_mousex, xtest_mousey, 0);
426 /******************************************************************************
428 * flush_input_actions
430 * Write the input actions event to the current requesting client
431 * and re-initialize the input action event.
434 flush_input_actions()
437 * pointer to the input action event
445 if (packet_index == 0)
448 * empty input actions event
452 else if (packet_index < XTestACTIONS_SIZE)
455 * fill to the end of the input actions event with 0's
457 for (i = packet_index; i <XTestACTIONS_SIZE; i++)
459 input_action_packet.actions[i] = 0;
462 rep = (char *) (&input_action_packet);
465 * set the serial number of the input action event
467 input_action_packet.sequenceNumber = current_xtest_client->sequence;
469 * send the input action event to the client
471 WriteEventsToClient(current_xtest_client, 1, (xEvent *) rep);
473 * re-initialize the input action event
475 input_action_event_full = 0;
476 input_action_packet.type = XTestInputActionType;
480 /******************************************************************************
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.
489 XTestStealJumpData(jx, jy, dev_type)
491 * the x and y coordinates to jump to
496 * which device caused the jump
500 XTestJumpInfo *jmp_ptr;
502 * time delta (in ms) from previous event
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.
511 tchar = check_time_event();
512 if (!there_is_room(sizeof(XTestJumpInfo)))
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.
519 flush_input_actions();
522 * update the logical mouse position
527 * point jmp_ptr to the correct place in the input action event
529 jmp_ptr = (XTestJumpInfo *)
530 &(input_action_packet.actions[packet_index]);
532 * compute the input action header
534 jmp_ptr->header = (XTestPackDeviceID(dev_type) | XTestJUMP_ACTION);
536 * set the x and y coordinates to jump to in the input action
541 * set the delay time in the input action
543 jmp_ptr->delay_time = tchar;
545 * increment the packet index by the size of the input action
547 packet_index = packet_index + sizeof(XTestJumpInfo);
548 if (packed_mode == 0)
551 * if input actions are not packed, send the input
552 * action event to the client
554 flush_input_actions();
558 /******************************************************************************
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.
567 struct timeval *otime;
570 unsigned long the_ms;
575 * get the current time
577 X_GETTIMEOFDAY(&tval);
578 if (tval.tv_usec < otime->tv_usec)
581 * borrow a second's worth of microseconds if needed
583 usec = tval.tv_usec - otime->tv_usec + 1000000;
584 sec = tval.tv_sec - 1 - otime->tv_sec;
588 usec = tval.tv_usec - otime->tv_usec;
589 sec = tval.tv_sec - otime->tv_sec;
592 * update the passed-in time to the new time
596 * compute the number of milliseconds contained in
597 * 'sec' seconds and 'usec' microseconds
599 the_ms = (sec * 1000000L + usec) / 1000L;
603 /******************************************************************************
607 * If time delta is > XTestSHORT_DELAY_TIME then insert a time event
608 * and return 0; else return the delay time.
615 XTestDelayInfo *tptr;
618 * get the number of milliseconds between input actions
620 tstamp = current_ms(¤t_time);
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.
625 if (tstamp > XTestSHORT_DELAY_TIME)
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.
632 if (!there_is_room(sizeof(XTestDelayInfo)))
634 flush_input_actions();
637 * point tptr to the correct place in the input action event
639 tptr = (XTestDelayInfo *)
640 (&(input_action_packet.actions[packet_index]));
642 * compute the input action header
644 tptr->header = XTestPackDeviceID(XTestDELAY_DEVICE_ID) |
647 * set the delay time in the input action
649 tptr->delay_time = tstamp;
651 * increment the packet index by the size of the input action
653 packet_index = packet_index + (sizeof(XTestDelayInfo));
654 if (packed_mode != XTestPACKED_ACTIONS)
657 * if input actions are not packed, send the input
658 * action event to the client
660 flush_input_actions();
663 * set the returned delay time to 0
670 * set the returned delay time to the computed delay time
677 /******************************************************************************
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.
686 there_is_room(actsize)
688 * the number of bytes of space needed
692 if ((packet_index + actsize) > XTestACTIONS_SIZE)
694 input_action_event_full = 1;
703 /******************************************************************************
705 * XTestStealMotionData
707 * Put motion information from the locator into an input action.
709 * called from x_hil.c
712 XTestStealMotionData(dx, dy, dev_type, mx, my)
714 * the x and y delta motion of the locator
719 * which locator did the moving
723 * the x and y position of the locator before the delta motion
729 * pointer to a XTestMOTION_ACTION input action
733 * time delta from previous event
738 * if the current position of the locator is not the same as
739 * the logical position, then update the logical position
741 if ((mx != xtest_mousex) || (my != xtest_mousey))
743 XTestStealJumpData(mx, my, dev_type);
746 * if the delta motion is outside the range that can
747 * be held in a motion input action, use a jump input action
749 if ((dx > XTestMOTION_MAX) || (dx < XTestMOTION_MIN) ||
750 (dy > XTestMOTION_MAX) || (dy < XTestMOTION_MIN))
752 XTestStealJumpData((xtest_mousex + dx),
753 (xtest_mousey + dy), dev_type);
758 * compute the new logical position of the mouse
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.
767 tchar = check_time_event();
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.
773 if (!there_is_room(sizeof(XTestMotionInfo)))
775 flush_input_actions();
777 * point fm to the correct place in the input action event
780 fm = (XTestMotionInfo *)
781 &(input_action_packet.actions[packet_index]);
783 * compute the input action header
785 fm->header = XTestMOTION_ACTION;
788 fm->header |= XTestX_NEGATIVE;
793 fm->header |= XTestY_NEGATIVE;
796 fm->header |= XTestPackDeviceID(dev_type);
798 * compute the motion data byte
800 fm->motion_data = XTestPackYMotionValue(dy);
801 fm->motion_data |= XTestPackXMotionValue(dx);
803 * set the delay time in the input action
805 fm->delay_time = tchar;
807 * increment the packet index by the size of the input action
809 packet_index = packet_index + sizeof(XTestMotionInfo);
810 if (packed_mode == 0)
813 * if input actions are not packed, send the input
814 * action event to the client
816 flush_input_actions();
822 /******************************************************************************
826 * Place this key data in the input_action_packet.
830 XTestStealKeyData(keycode, keystate, dev_type, locx, locy)
832 * which key/button moved
836 * whether the key/button was pressed or released
840 * which device caused the input action
844 * the x and y coordinates of the locator when the action happenned
850 * pointer to key/button motion input action
854 * time delta from previous event
860 * update the logical position of the locator if the physical position
861 * of the locator is not the same as the logical position.
863 if ((locx != xtest_mousex) || (locy != xtest_mousey))
865 XTestStealJumpData(locx, locy, dev_type);
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.
872 tchar = check_time_event();
873 if (!there_is_room(sizeof(XTestKeyInfo)))
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.
880 flush_input_actions();
883 * point kp to the correct place in the input action event
885 kp = (XTestKeyInfo *)
886 (&(input_action_packet.actions[packet_index]));
888 * compute the input action header
890 kp->header = XTestPackDeviceID(dev_type);
891 if ((keystate == KeyRelease) || (keystate == ButtonRelease))
893 keytrans = XTestKEY_UP;
895 else if ((keystate == KeyPress) || (keystate == ButtonPress))
897 keytrans = XTestKEY_DOWN;
901 printf("%s: invalid key/button state %d.\n",
905 kp->header = kp->header | keytrans | XTestKEY_ACTION;
907 * set the keycode in the input action
909 kp->keycode = keycode;
911 * set the delay time in the input action
913 kp->delay_time = tchar;
915 * increment the packet index by the size of the input action
917 packet_index = packet_index + sizeof(XTestKeyInfo);
919 * if the command key has been released or input actions are not
920 * packed, send the input action event to the client
922 if(((keycode == xtest_command_key) && (keystate == KeyRelease)) ||
923 (packed_mode != XTestPACKED_ACTIONS))
925 flush_input_actions();
927 /* return TRUE if the event should be passed on to DIX */
929 return ((keystate == KeyRelease) &&
930 (keycode == xtest_command_key));
932 return ((keystate != KeyRelease) ||
933 (keycode != xtest_command_key));
936 /******************************************************************************
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.
946 parse_fake_input(client, req)
948 * which client did the XTestFakeInput request
952 * a pointer to the xTestFakeInputReq structure sent by the client
957 * if set to 1, done processing input actions from the request
961 * type of input action
969 * pointer to an xTestFakeInputReq structure
971 xTestFakeInputReq *request;
973 * holds the index into the action list in the request
978 * get a correct-type pointer to the client-supplied request data
980 request = (xTestFakeInputReq *) req;
982 * save the acknowledge requested state for use in
983 * XTestProcessInputAction
985 acknowledge = request->ack;
987 * set up an index into the action list in the request
990 if (write_index >= ACTION_ARRAY_SIZE)
993 * if the input action array is full, don't add any more
1000 * get the type of input action in the list
1002 action_type = (request->action_list[parse_index])
1003 & XTestACTION_TYPE_MASK;
1005 * get the type of device in the list
1007 dev_type = XTestUnpackDeviceID(request->action_list[parse_index]);
1009 * process the input action appropriately
1011 switch (action_type)
1013 case XTestKEY_ACTION:
1014 parse_key_fake((XTestKeyInfo *)
1015 &(request->action_list[parse_index]));
1016 parse_index = parse_index + sizeof(XTestKeyInfo);
1018 case XTestMOTION_ACTION:
1019 parse_motion_fake((XTestMotionInfo *)
1020 &(request->action_list[parse_index]));
1021 parse_index = parse_index + sizeof(XTestMotionInfo);
1023 case XTestJUMP_ACTION:
1024 parse_jump_fake((XTestJumpInfo *)
1025 &(request->action_list[parse_index]));
1026 parse_index = parse_index + sizeof(XTestJumpInfo);
1028 case XTestDELAY_ACTION:
1029 if (dev_type == XTestDELAY_DEVICE_ID)
1031 parse_delay_fake((XTestDelayInfo *)
1032 &(request->action_list[parse_index]));
1033 parse_index = parse_index +
1034 sizeof(XTestDelayInfo);
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.
1049 if (parse_index >= XTestMAX_ACTION_LIST_SIZE)
1052 * entire XTestFakeInput request has been processed
1056 if (write_index >= ACTION_ARRAY_SIZE)
1059 * no room in the input actions array
1064 if (write_index > read_index)
1067 * there are fake input actions in the input action array
1068 * to be given to the server
1071 playback_client = client;
1075 /******************************************************************************
1079 * Called from parse_fake_input.
1081 * Copy the fake key input action from its packed form into the array of
1082 * pending input events.
1085 parse_key_fake(fkey)
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;
1096 /******************************************************************************
1100 * Called from parse_fake_input.
1102 * Copy the fake motion input action from its packed form into the array of
1103 * pending input events.
1106 parse_motion_fake(fmotion)
1107 XTestMotionInfo *fmotion;
1112 dx = (XTestUnpackXMotionValue(fmotion->motion_data));
1113 dy = (XTestUnpackYMotionValue(fmotion->motion_data));
1114 if (((fmotion->header) & XTestX_SIGN_BIT_MASK) == XTestX_NEGATIVE)
1122 if (((fmotion->header) & XTestY_SIGN_BIT_MASK) == XTestY_NEGATIVE)
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;
1138 /******************************************************************************
1142 * Called from parse_fake_input.
1144 * Copy the fake jump input action from its packed form into the array of
1145 * pending input events.
1148 parse_jump_fake(fjump)
1149 XTestJumpInfo *fjump;
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;
1161 /******************************************************************************
1165 * Called from parse_fake_input.
1167 * Copy the fake delay input action from its packed form into the array of
1168 * pending input events.
1171 parse_delay_fake(tevent)
1172 XTestDelayInfo *tevent;
1174 action_array[write_index].type = XTestDELAY_ACTION;
1175 action_array[write_index].delay_time = tevent->delay_time;
1179 /******************************************************************************
1181 * XTestComputeWaitTime
1183 * Compute the amount of time the server should wait before sending the
1184 * next monitor event in playback mode.
1187 XTestComputeWaitTime(waittime)
1188 struct timeval *waittime;
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
1200 * if the playback clock has never been set,
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.
1212 saved_sec = waittime->tv_sec;
1213 saved_usec = waittime->tv_usec;
1219 * if we just processed an input action, figure out
1220 * how long to wait for the next input action
1222 compute_action_time(&rtime);
1227 * else just find out how much more time to wait
1228 * on the current input action
1230 (void)find_residual_time(&rtime);
1232 waittime->tv_sec = rtime.tv_sec;
1233 waittime->tv_usec = rtime.tv_usec;
1237 /******************************************************************************
1239 * XTestProcessInputAction
1241 * If there are any input actions in the input action array,
1242 * then take one out and process it.
1246 XTestProcessInputAction(readable, waittime)
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.
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.
1260 * this is the timeout value that the select was called with
1262 struct timeval *waittime;
1266 * if playback_on is 0, then the input action array is empty
1270 restorewait = waittime;
1272 * figure out if we need to wait for the next input action
1274 if (find_residual_time(&rtime) > 0)
1277 * still have to wait before processing the current
1285 * don't have to wait any longer before processing
1286 * the current input action
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
1300 * if we don't need to wait, then get an input action from
1301 * the input action array and process it
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.
1314 if (action_array[read_index].type == XTestJUMP_ACTION)
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;
1323 if (action_array[read_index].type == XTestKEY_ACTION)
1325 GetSpritePosition(&mousex, &mousey);
1327 action_array[read_index].device,
1328 action_array[read_index].keycode,
1329 action_array[read_index].keystate,
1335 * if all input actions are processed, then restore
1338 if (read_index >= write_index)
1340 waittime->tv_sec = saved_sec;
1341 waittime->tv_usec = saved_usec;
1347 * if the playback client is waiting
1348 * for an xTestFakeAck event, send
1351 send_ack(playback_client);
1356 playback_client = (ClientPtr) NULL;
1364 /******************************************************************************
1368 * send an xTestFakeAck event to the client
1374 xTestFakeAckEvent rep;
1377 * set the serial number of the xTestFakeAck event
1379 rep.sequenceNumber = client->sequence;
1380 rep.type = XTestFakeAckType;
1381 WriteEventsToClient(client, 1, (xEvent *) &rep);
1384 /******************************************************************************
1388 * start the clock for play back.
1393 X_GETTIMEOFDAY(&play_time);
1395 * flag that play_time is valid
1400 /******************************************************************************
1402 * compute_action_time
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.
1409 compute_action_time(rtime)
1410 struct timeval *rtime;
1413 * holds the delay time in milliseconds
1415 unsigned long dtime;
1417 * holds the number of microseconds in the sum of the dtime value
1418 * and the play_time value
1420 unsigned long tot_usec;
1422 * holds the number of seconds and microseconds in the
1428 * holds the current time
1430 struct timeval btime;
1433 * Put the time from the current input action in dtime
1435 dtime = action_array[read_index].delay_time;
1437 * If the current input action is a delay input action,
1438 * add in the time from the following input action.
1440 if ((action_array[read_index].type == XTestDELAY_ACTION) &&
1441 ((read_index + 1) < write_index))
1444 dtime = dtime + action_array[read_index].delay_time;
1447 * compute the number of seconds and microseconds in the
1451 usec = (dtime % 1000) * 1000;
1453 * get the current time in btime
1455 X_GETTIMEOFDAY(&btime);
1457 * compute the number of microseconds in the sum of the dtime value
1458 * and the current usec value
1460 tot_usec = btime.tv_usec + usec;
1462 * if it is greater than one second's worth, adjust the seconds
1464 if (tot_usec >= 1000000)
1466 tot_usec -= 1000000;
1469 play_time.tv_usec = tot_usec;
1470 play_time.tv_sec = btime.tv_sec + sec;
1472 * put the time until the next input action in rtime
1474 rtime->tv_sec = sec;
1475 rtime->tv_usec = usec;
1478 /******************************************************************************
1480 * find_residual_time
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
1488 find_residual_time(the_residual)
1489 struct timeval *the_residual;
1492 * if > 0, there is time to wait. If < 0, then don't wait
1496 * holds the current time
1498 struct timeval btime;
1500 * holds the current time in seconds and microseconds
1503 unsigned long busec;
1505 * holds the playback time in seconds and microseconds
1508 unsigned long pusec;
1511 * get the current time in btime
1513 X_GETTIMEOFDAY(&btime);
1515 * get the current time in seconds and microseconds
1517 bsec = btime.tv_sec;
1518 busec = btime.tv_usec;
1520 * get the playback time in seconds and microseconds
1522 psec = play_time.tv_sec;
1523 pusec = play_time.tv_usec;
1525 * if the current time is already later than the playback time,
1526 * we don't need to wait
1537 * if the current and playback times have the same
1538 * second value, then compare the microsecond values
1540 if ( busec >= pusec)
1543 * if the current time is already later than
1544 * the playback time, we don't need to wait
1550 the_residual->tv_usec = pusec - busec;
1551 the_residual->tv_sec = 0;
1559 * 'borrow' a second's worth of microseconds
1560 * from the seconds left to wait
1562 the_residual->tv_usec = 1000000 - busec + pusec;
1564 the_residual->tv_sec = psec - bsec;
1568 the_residual->tv_sec = psec - bsec;
1569 the_residual->tv_usec = pusec - busec;
1576 * if don't need to wait, set the playback time
1577 * to the current time
1579 X_GETTIMEOFDAY(&play_time);
1581 * set the time to wait to 0
1583 the_residual->tv_sec = 0;
1584 the_residual->tv_usec = 0;
1589 /******************************************************************************
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
1603 restorewait->tv_sec = saved_sec;
1604 restorewait->tv_usec = saved_usec;
1607 * make the input action array empty
1612 * we are no longer playing back anything
1618 * there is no valid wait time saved any more
1622 * there are no valid clients using this extension
1624 playback_client = (ClientPtr) NULL;
1625 current_xtest_client = (ClientPtr) NULL;
1628 /******************************************************************************
1630 * return_input_array_size
1632 * Return the number of input actions in the input action array.
1635 return_input_array_size(client)
1637 * which client to send the reply to
1641 xTestQueryInputSizeReply rep;
1645 * set the serial number of the reply
1647 rep.sequenceNumber = client->sequence;
1649 rep.size_return = ACTION_ARRAY_SIZE;
1650 WriteReplyToClient(client,
1651 sizeof(xTestQueryInputSizeReply),