]> git.sesse.net Git - rdpsrv/blob - Xserver/programs/Xserver/Xext/xtest1dd.c
Import X server from vnc-3.3.7.
[rdpsrv] / Xserver / programs / Xserver / Xext / xtest1dd.c
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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 }