diff options
Diffstat (limited to 'libXext/src/XTestExt1.c')
-rw-r--r-- | libXext/src/XTestExt1.c | 1322 |
1 files changed, 1322 insertions, 0 deletions
diff --git a/libXext/src/XTestExt1.c b/libXext/src/XTestExt1.c new file mode 100644 index 000000000..c9d48d7da --- /dev/null +++ b/libXext/src/XTestExt1.c @@ -0,0 +1,1322 @@ +/* $Xorg: XTestExt1.c,v 1.4 2001/02/09 02:03:49 xorgcvs Exp $ */ +/* + * File: xtestext1lib.c + * + * This file contains the Xlib parts of the input synthesis extension + */ + +/* + + +Copyright 1986, 1987, 1988, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall not be +used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization from The Open Group. + + +Copyright 1986, 1987, 1988 by Hewlett-Packard Corporation + +Permission to use, copy, modify, and distribute this +software and its documentation for any purpose and without +fee is hereby granted, provided that the above copyright +notice appear in all copies and that both that copyright +notice and this permission notice appear in supporting +documentation, and that the name of Hewlett-Packard not be used in +advertising or publicity pertaining to distribution of the +software without specific, written prior permission. + +Hewlett-Packard makes no representations about the +suitability of this software for any purpose. It is provided +"as is" without express or implied warranty. + +This software is not subject to any license of the American +Telephone and Telegraph Company or of the Regents of the +University of California. + +*/ +/* $XFree86: xc/lib/Xext/XTestExt1.c,v 1.3 2001/01/17 19:42:46 dawes Exp $ */ + +/****************************************************************************** + * include files + *****************************************************************************/ + +#define NEED_REPLIES +#define NEED_EVENTS + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif +#include <stdio.h> +#include <X11/Xproto.h> +#include <X11/Xlibint.h> +#include <X11/extensions/xtestext1.h> +#include <X11/extensions/xtestext1proto.h> + +/****************************************************************************** + * variables + *****************************************************************************/ + +/* + * Holds the request type code for this extension. The request type code + * for this extension may vary depending on how many extensions are installed + * already, so the initial value given below will be added to the base request + * code that is acquired when this extension is installed. + */ +static int XTestReqCode = 0; +/* + * Holds the two event type codes for this extension. The event type codes + * for this extension may vary depending on how many extensions are installed + * already, so the initial values given below will be added to the base event + * code that is acquired when this extension is installed. + * + * These two variables must be available to programs that use this extension. + */ +int XTestInputActionType = 0; +int XTestFakeAckType = 1; +/* + * holds the current x and y coordinates for XTestMovePointer + */ +static int current_x = 0; +static int current_y = 0; +/* + * Holds input actions being accumulated until the input action buffer is + * full or until XTestFlush is called. + */ +static CARD8 action_buf[XTestMAX_ACTION_LIST_SIZE]; +/* + * the index into the input action buffer + */ +static int action_index = 0; +/* + * the number of input actions that the server can handle at one time + */ +static unsigned long action_array_size = 0; +/* + * the current number of input actions + */ +static unsigned long action_count = 0; + +/****************************************************************************** + * function declarations + *****************************************************************************/ + +static int XTestWireToEvent(Display *dpy, XEvent *reTemp, xEvent *eventTemp); +static int XTestCheckExtInit(register Display *dpy); +static Bool XTestIdentifyMyEvent(Display *display, XEvent *event_ptr, char *args); +static int XTestInitExtension(register Display *dpy); +static int XTestKeyOrButton(Display *display, int device_id, long unsigned int delay, unsigned int code, unsigned int action); +static int XTestCheckDelay(Display *display, long unsigned int *delay_addr); +static int XTestPackInputAction(Display *display, CARD8 *action_addr, int action_size); +static int XTestWriteInputActions(Display *display, char *action_list_addr, int action_list_size, int ack_flag); + +/****************************************************************************** + * + * XTestFakeInput + * + * Send a a request containing one or more input actions to be sent + * to the server by this extension. + */ +int +XTestFakeInput( +/* + * the connection to the X server + */ +register Display *dpy, +/* + * the address of a list of input actions to be sent to the server + */ +char *action_list_addr, +/* + * the size (in bytes) of the list of input actions + */ +int action_list_size, +/* + * specifies whether the server needs to send an event to indicate that its + * input action buffer is empty + */ +int ack_flag) +{ + /* + * pointer to xTestFakeInputReq structure + */ + xTestFakeInputReq *req; + /* + * loop index + */ + int i; + + LockDisplay(dpy); + if ((XTestCheckExtInit(dpy) == -1) || + (action_list_size > XTestMAX_ACTION_LIST_SIZE)) + { + /* + * if the extension is not installed in the server or the + * action list will not fit in the request, then unlock + * the display and return -1. + */ + UnlockDisplay(dpy); + return(-1); + } + else + { + /* + * Get the next available X request packet in the buffer. + * It sets the `length' field to the size (in 32-bit words) + * of the request. It also sets the `reqType' field in the + * request to X_TestFakeInput, which is not what is needed. + * + * GetReq is a macro defined in Xlibint.h. + */ + GetReq(TestFakeInput, req); + /* + * fix up the request type code to what is needed + */ + req->reqType = XTestReqCode; + /* + * set the minor request type code to X_TestFakeInput + */ + req->XTestReqType = X_TestFakeInput; + /* + * set the ack code + */ + req->ack = ack_flag; + /* + * Set the action_list area to all 0's. An input action header + * value of 0 is interpreted as a flag to the input action + * list handling code in the server part of this extension + * that there are no more input actions in this request. + */ + for (i = 0; i < XTestMAX_ACTION_LIST_SIZE; i++) + { + req->action_list[i] = 0; + } + /* + * copy the input actions into the request + */ + for (i = 0; i < action_list_size; i++) + { + req->action_list[i] = *(action_list_addr++); + } + UnlockDisplay(dpy); + SyncHandle(); + return(0); + } +} + +/****************************************************************************** + * + * XTestGetInput + * + * Request the server to begin putting user input actions into events + * to be sent to the client that called this function. + */ +int +XTestGetInput( +/* + * the connection to the X server + */ +register Display *dpy, +/* + * tells the server what to do with the user input actions + */ +int action_handling) +{ + /* + * pointer to xTestGetInputReq structure + */ + xTestGetInputReq *req; + + LockDisplay(dpy); + if (XTestCheckExtInit(dpy) == -1) + { + /* + * if the extension is not installed in the server + * then unlock the display and return -1. + */ + UnlockDisplay(dpy); + return(-1); + } + else + { + /* + * Get the next available X request packet in the buffer. + * It sets the `length' field to the size (in 32-bit words) + * of the request. It also sets the `reqType' field in the + * request to X_TestGetInput, which is not what is needed. + * + * GetReq is a macro defined in Xlibint.h. + */ + GetReq(TestGetInput, req); + /* + * fix up the request type code to what is needed + */ + req->reqType = XTestReqCode; + /* + * set the minor request type code to X_TestGetInput + */ + req->XTestReqType = X_TestGetInput; + /* + * set the action handling mode + */ + req->mode = action_handling; + UnlockDisplay(dpy); + SyncHandle(); + return(0); + } +} + +/****************************************************************************** + * + * XTestStopInput + * + * Tell the server to stop putting information about user input actions + * into events. + */ +int +XTestStopInput( +/* + * the connection to the X server + */ +register Display *dpy) +{ + /* + * pointer to xTestStopInputReq structure + */ + xTestStopInputReq *req; + + LockDisplay(dpy); + if (XTestCheckExtInit(dpy) == -1) + { + /* + * if the extension is not installed in the server + * then unlock the display and return -1. + */ + UnlockDisplay(dpy); + return(-1); + } + else + { + /* + * Get the next available X request packet in the buffer. + * It sets the `length' field to the size (in 32-bit words) + * of the request. It also sets the `reqType' field in the + * request to X_TestStopInput, which is not what is needed. + * + * GetReq is a macro defined in Xlibint.h. + */ + GetReq(TestStopInput, req); + /* + * fix up the request type code to what is needed + */ + req->reqType = XTestReqCode; + /* + * set the minor request type code to X_TestStopInput + */ + req->XTestReqType = X_TestStopInput; + UnlockDisplay(dpy); + SyncHandle(); + return(0); + } +} + +/****************************************************************************** + * + * XTestReset + * + * Tell the server to set everything having to do with this extension + * back to its initial state. + */ +int +XTestReset( +/* + * the connection to the X server + */ +register Display *dpy) +{ + /* + * pointer to xTestReset structure + */ + xTestResetReq *req; + + LockDisplay(dpy); + if (XTestCheckExtInit(dpy) == -1) + { + /* + * if the extension is not installed in the server + * then unlock the display and return -1. + */ + UnlockDisplay(dpy); + return(-1); + } + else + { + /* + * Get the next available X request packet in the buffer. + * It sets the `length' field to the size (in 32-bit words) + * of the request. It also sets the `reqType' field in the + * request to X_TestReset, which is not what is needed. + * + * GetReq is a macro defined in Xlibint.h. + */ + GetReq(TestReset, req); + /* + * fix up the request type code to what is needed + */ + req->reqType = XTestReqCode; + /* + * set the minor request type code to X_TestReset + */ + req->XTestReqType = X_TestReset; + UnlockDisplay(dpy); + SyncHandle(); + return(0); + } +} + +/****************************************************************************** + * + * XTestQueryInputSize + * + * Returns the number of input actions in the server's input action buffer. + */ +int +XTestQueryInputSize( +/* + * the connection to the X server + */ +register Display *dpy, +/* + * the address of the place to put the number of input actions in the + * server's input action buffer + */ +unsigned long *size_return) +{ + /* + * pointer to xTestQueryInputSize structure + */ + xTestQueryInputSizeReq *req; + /* + * pointer to xTestQueryInputSize structure + */ + xTestQueryInputSizeReply rep; + + LockDisplay(dpy); + if (XTestCheckExtInit(dpy) == -1) + { + /* + * if the extension is not installed in the server + * then unlock the display and return -1. + */ + UnlockDisplay(dpy); + return(-1); + } + else + { + /* + * Get the next available X request packet in the buffer. + * It sets the `length' field to the size (in 32-bit words) + * of the request. It also sets the `reqType' field in the + * request to X_TestQueryInputSize, which is not what is needed. + * + * GetReq is a macro defined in Xlibint.h. + */ + GetReq(TestQueryInputSize, req); + /* + * fix up the request type code to what is needed + */ + req->reqType = XTestReqCode; + /* + * set the minor request type code to X_TestQueryInputSize + */ + req->XTestReqType = X_TestQueryInputSize; + /* + * get a reply from the server + */ + (void) _XReply (dpy, (xReply *) &rep, 0, xTrue); + /* + * put the size in the caller's variable + */ + *size_return = (unsigned long) rep.size_return; + UnlockDisplay(dpy); + SyncHandle(); + return(0); + } +} + +/****************************************************************************** + * + * XTestCheckExtInit + * + * Check to see if the XTest extension is installed in the server. + */ +static int +XTestCheckExtInit( +/* + * the connection to the X server + */ +register Display *dpy) +{ + /* + * if the extension has not been initialized, then do so + */ + if (!XTestReqCode) + { + return(XTestInitExtension(dpy)); + } + return(0); +} + +/****************************************************************************** + * + * XTestInitExtension + * + * Attempt to initialize this extension in the server. Return 0 if it + * succeeds, -1 if it does not succeed. + */ +static int +XTestInitExtension( +/* + * the connection to the X server + */ +register Display *dpy) +{ + /* + * loop index + */ + int i; + /* + * return value from XInitExtension + */ + XExtCodes *ret; + + /* + * attempt to initialize the extension + */ + ret = XInitExtension(dpy, XTestEXTENSION_NAME); + /* + * if the initialize failed, return -1 + */ + if (ret == NULL) + { + return (-1); + } + /* + * the initialize succeeded, remember the major opcode + * for this extension + */ + XTestReqCode = ret->major_opcode; + /* + * set up the event handler for any events from + * this extension + */ + for (i = 0; i < XTestEVENT_COUNT; i++) + { + XESetWireToEvent(dpy, + ret->first_event+i, + XTestWireToEvent); + } + /* + * compute the event type codes for the events + * in this extension + */ + XTestInputActionType += ret->first_event; + XTestFakeAckType += ret->first_event; + /* + * everything worked ok + */ + return(0); +} + +/****************************************************************************** + * + * XTestWireToEvent + * + * Handle XTest extension events. + * Reformat a wire event into an XEvent structure of the right type. + */ +static Bool +XTestWireToEvent( +/* + * the connection to the X server + */ +Display *dpy, +/* + * a pointer to where a host formatted event should be stored + * with the information copied to it + */ +XEvent *reTemp, +/* + * a pointer to the wire event + */ +xEvent *eventTemp) +{ + XTestInputActionEvent *re = (XTestInputActionEvent *) reTemp; + xTestInputActionEvent *event = (xTestInputActionEvent *) eventTemp; + + /* + * loop index + */ + int i; + /* + * pointer to where the input actions go in the host format event + */ + CARD8 *to; + /* + * pointer to the input actions in the wire event + */ + CARD8 *from; + + /* + * Copy the type of the wire event to the new event. + * This will work for either event type because the type, + * display, and window fields in the events have to be the same. + */ + re->type = event->type; + /* + * set the display parameter in case it is needed (by who?) + */ + re->display = dpy; + if (re->type == XTestInputActionType) + { + /* + * point at the first byte of input actions in the wire event + */ + from = &(event->actions[0]); + /* + * point at where the input action bytes go in the new event + */ + to = &(re->actions[0]); + /* + * copy the input action bytes from the wire event to + * the new event + */ + for (i = 0; i < XTestACTIONS_SIZE; i++) + { + *(to++) = *(from++); + } + } + else if (re->type == XTestFakeAckType) + { + /* + * nothing else needs to be done + */ + } + else + { + printf("XTestWireToEvent: UNKNOWN WIRE EVENT! type=%d\n", + (int) event->type); + printf("%s is giving up.\n", XTestEXTENSION_NAME); + exit (1); + } + return 1; +} + +/****************************************************************************** + * + * XTestPressKey + * + * Send input actions to the server to cause the server to think + * that the specified key on the keyboard was moved as specified. + */ +int +XTestPressKey( +Display *display, +int device_id, +unsigned long delay, +unsigned int keycode, +unsigned int key_action) +{ + /* + * bounds check the key code + */ + if (keycode < 8 || keycode > 255) + { + return(-1); + } + /* + * use the commmon key/button handling routine + */ + return(XTestKeyOrButton(display, + device_id, + delay, + keycode, + key_action)); +} + +/****************************************************************************** + * + * XTestPressButton + * + * Send input actions to the server to cause the server to think + * that the specified button on the mouse was moved as specified. + */ +int +XTestPressButton( +Display *display, +int device_id, +unsigned long delay, +unsigned int button_number, +unsigned int button_action) +{ + /* + * bounds check the button number + */ + if (button_number > 7) + { + return(-1); + } + /* + * use the commmon key/button handling routine + */ + return(XTestKeyOrButton(display, + device_id, + delay, + button_number, + button_action)); +} + +/****************************************************************************** + * + * XTestKeyOrButton + * + * Send input actions to the server to cause the server to think + * that the specified key/button was moved as specified. + */ +static int +XTestKeyOrButton( +Display *display, +int device_id, +unsigned long delay, +unsigned int code, +unsigned int action) +{ + /* + * holds a key input action to be filled out and sent to the server + */ + XTestKeyInfo keyinfo; + + /* + * bounds check the device id + */ + if (device_id < 0 || device_id > XTestMAX_DEVICE_ID) + { + return(-1); + } + /* + * fill out the key input action(s) as appropriate + */ + switch(action) + { + case XTestPRESS: + /* + * Check the delay. If it is larger than will fit in the + * key input action, send a delay input action. + */ + if(XTestCheckDelay(display, &delay) == -1) + { + /* + * an error occurred, return -1 + */ + return(-1); + } + /* + * create the header + */ + keyinfo.header = XTestPackDeviceID(device_id) | + XTestKEY_ACTION | + XTestKEY_DOWN; + /* + * set the key/button code + */ + keyinfo.keycode = code; + /* + * set the delay time + */ + keyinfo.delay_time = delay; + /* + * pack the input action into a request to be sent to the + * server when the request is full or XTestFlush is called + */ + return(XTestPackInputAction(display, + (CARD8 *) &keyinfo, + sizeof(XTestKeyInfo))); + case XTestRELEASE: + /* + * Check the delay. If it is larger than will fit in the + * key input action, send a delay input action. + */ + if(XTestCheckDelay(display, &delay) == -1) + { + /* + * an error occurred, return -1 + */ + return(-1); + } + /* + * create the header + */ + keyinfo.header = XTestPackDeviceID(device_id) | + XTestKEY_ACTION | + XTestKEY_UP; + /* + * set the key/button code + */ + keyinfo.keycode = code; + /* + * set the delay time + */ + keyinfo.delay_time = delay; + /* + * pack the input action into a request to be sent to the + * server when the request is full or XTestFlush is called + */ + return(XTestPackInputAction(display, + (CARD8 *) &keyinfo, + sizeof(XTestKeyInfo))); + case XTestSTROKE: + /* + * Check the delay. If it is larger than will fit in the + * key input action, send a delay input action. + */ + if(XTestCheckDelay(display, &delay) == -1) + { + /* + * an error occurred, return -1 + */ + return(-1); + } + /* + * create a key/button-down input action header + */ + keyinfo.header = XTestPackDeviceID(device_id) | + XTestKEY_ACTION | + XTestKEY_DOWN; + /* + * set the key/button code + */ + keyinfo.keycode = code; + /* + * set the delay time + */ + keyinfo.delay_time = delay; + /* + * pack the input action into a request to be sent to the + * server when the request is full or XTestFlush is called + */ + if (XTestPackInputAction(display, + (CARD8 *) &keyinfo, + sizeof(XTestKeyInfo)) == -1) + { + /* + * an error occurred, return -1 + */ + return(-1); + } + /* + * set the delay to XTestSTROKE_DELAY_TIME + */ + delay = XTestSTROKE_DELAY_TIME; + /* + * Check the delay. If it is larger than will fit in the + * key input action, send a delay input action. + */ + if(XTestCheckDelay(display, &delay) == -1) + { + /* + * an error occurred, return -1 + */ + return(-1); + } + /* + * create a key/button-up input action header + */ + keyinfo.header = XTestPackDeviceID(device_id) | + XTestKEY_ACTION | + XTestKEY_UP; + /* + * set the key/button code + */ + keyinfo.keycode = code; + /* + * set the delay time + */ + keyinfo.delay_time = delay; + /* + * pack the input action into a request to be sent to the + * server when the request is full or XTestFlush is called + */ + return(XTestPackInputAction(display, + (CARD8 *) &keyinfo, + sizeof(XTestKeyInfo))); + default: + /* + * invalid action value, return -1 + */ + return(-1); + } +} + +/****************************************************************************** + * + * XTestMovePointer + * + * Send input actions to the server to cause the server to think + * that the mouse was moved as specified. + */ +int +XTestMovePointer( +Display *display, +int device_id, +unsigned long delay[], +int x[], +int y[], +unsigned int count) +{ + /* + * holds a motion input action to be filled out and sent to the server + */ + XTestMotionInfo motioninfo; + /* + * holds a jump input action to be filled out and sent to the server + */ + XTestJumpInfo jumpinfo; + /* + * loop index + */ + unsigned int i; + /* + * holds the change in x and y directions from the current x and y + * coordinates + */ + int dx; + int dy; + + /* + * bounds check the device id + */ + if (device_id < 0 || device_id > XTestMAX_DEVICE_ID) + { + return(-1); + } + /* + * if the count is 0, there is nothing to do. return 0 + */ + if (count == 0) + { + return(0); + } + /* + * loop through the pointer motions, creating the appropriate + * input actions for each motion + */ + for (i = 0; i < count; i++) + { + /* + * Check the delay. If it is larger than will fit in the + * input action, send a delay input action. + */ + if(XTestCheckDelay(display, &(delay[i])) == -1) + { + /* + * an error occurred, return -1 + */ + return(-1); + } + /* + * compute the change from the current x and y coordinates + * to the new x and y coordinates + */ + dx = x[i] - current_x; + dy = y[i] - current_y; + /* + * update the current x and y coordinates + */ + current_x = x[i]; + current_y = y[i]; + /* + * If the pointer motion range is too large to fit into + * a motion input action, then use a jump input action. + * Otherwise, use a motion input action. + */ + if ((dx > XTestMOTION_MAX) || (dx < XTestMOTION_MIN) || + (dy > XTestMOTION_MAX) || (dy < XTestMOTION_MIN)) + { + /* + * create a jump input action header + */ + jumpinfo.header = XTestPackDeviceID(device_id) | + XTestJUMP_ACTION; + /* + * set the x and y coordinates to jump to + */ + jumpinfo.jumpx = x[i]; + jumpinfo.jumpy = y[i]; + /* + * set the delay time + */ + jumpinfo.delay_time = delay[i]; + /* + * pack the jump input action into a request to be + * sent to the server when the request is full + * or XTestFlush is called + */ + if (XTestPackInputAction(display, + (CARD8 *) &jumpinfo, + sizeof(XTestJumpInfo)) == -1) + { + /* + * an error occurred, return -1 + */ + return(-1); + } + } + else + { + /* + * create a motion input action header + */ + motioninfo.header = XTestPackDeviceID(device_id) | + XTestMOTION_ACTION; + /* + * compute the motion data byte + */ + if (dx < 0) + { + motioninfo.header |= XTestX_NEGATIVE; + dx = abs(dx); + } + if (dy < 0) + { + motioninfo.header |= XTestY_NEGATIVE; + dy = abs(dy); + } + motioninfo.motion_data = XTestPackXMotionValue(dx); + motioninfo.motion_data |= XTestPackYMotionValue(dy); + /* + * set the delay time + */ + motioninfo.delay_time = delay[i]; + /* + * pack the motion input action into a request to be + * sent to the server when the request is full + * or XTestFlush is called + */ + if (XTestPackInputAction(display, + (CARD8 *) &motioninfo, + sizeof(XTestMotionInfo)) == -1) + { + /* + * an error occurred, return -1 + */ + return(-1); + } + } + } + /* + * if you get here, everything went ok + */ + return(0); +} + +/****************************************************************************** + * + * XTestCheckDelay + * + * Check the delay value at the passed-in address. If it is larger than + * will fit in a normal input action, then send a delay input action. + */ +static int +XTestCheckDelay( +Display *display, +unsigned long *delay_addr) +{ + /* + * holds a delay input action to be filled out and sent to the server + */ + XTestDelayInfo delayinfo; + + /* + * if the delay value will fit in the input action, + * then there is no need for a delay input action + */ + if (*delay_addr <= XTestSHORT_DELAY_TIME) + { + return(0); + } + /* + * fill out a delay input action + */ + delayinfo.header = XTestPackDeviceID(XTestDELAY_DEVICE_ID); + delayinfo.delay_time = *delay_addr; + /* + * all of the delay time will be accounted for in the + * delay input action, so set the original delay value to 0 + */ + *delay_addr = 0; + /* + * pack the delay input action into a request to be sent to the + * server when the request is full or XTestFlush is called + */ + return(XTestPackInputAction(display, + (CARD8 *) &delayinfo, + sizeof(XTestDelayInfo))); +} + +/****************************************************************************** + * + * XTestPackInputAction + * + * If the input action buffer is full or the number of input actions + * has reached the maximum that the server can handle at one time, + * then send the input actions to the server using XTestFakeInput. + */ +static int +XTestPackInputAction( +Display *display, +CARD8 *action_addr, +int action_size) +{ + /* + * loop index + */ + int i; + /* + * acknowledge flag + */ + int ack_flag; + + /* + * if we don't already know it, find out how many input actions + * the server can handle at one time + */ + if (action_array_size == 0) + { + if(XTestQueryInputSize(display, &action_array_size) == -1) + { + /* + * if an error, return -1 + */ + return(-1); + } + } + /* + * if the specified input action will fit in the the input + * action buffer and won't exceed the server's capacity, then + * put the input action into the input buffer + */ + if(((action_index + action_size) <= XTestMAX_ACTION_LIST_SIZE) && + ((action_count + 1) < action_array_size)) + { + /* + * copy the input action into the buffer + */ + for (i = 0; i < action_size; i++) + { + action_buf[action_index++] = *(action_addr++); + } + /* + * increment the action count + */ + action_count++; + /* + * everything went ok, return 0 + */ + return(0); + } + /* + * We have to write input actions to the server. If the server's + * input action capacity will be reached, then ask for an + * acknowledge event when the server has processed all of the + * input actions. Otherwise, an acknowledge event is not needed. + */ + if (action_count >= action_array_size) + { + ack_flag = XTestFAKE_ACK_REQUEST; + } + else + { + ack_flag = XTestFAKE_ACK_NOT_NEEDED; + } + /* + * write the input actions to the server + */ + if (XTestWriteInputActions(display, + (char *) &(action_buf[0]), + action_index, + ack_flag) == -1) + { + /* + * error, return -1 + */ + return(-1); + } + /* + * copy the input action into the buffer + */ + for (i = 0; i < action_size; i++) + { + action_buf[action_index++] = *(action_addr++); + } + /* + * increment the action count + */ + action_count++; + return(0); +} + +/****************************************************************************** + * + * XTestWriteInputActions + * + * Send input actions to the server. + */ +static int +XTestWriteInputActions( +Display *display, +char *action_list_addr, +int action_list_size, +int ack_flag) +{ + /* + * Holds an event. Used while waiting for an acknowledge event + */ + XEvent event; + /* + * points to XTestIdentifyMyEvent + */ + Bool (*func_ptr)(Display *, XEvent *, XPointer); + + /* + * write the input actions to the server + */ + if (XTestFakeInput(display, + action_list_addr, + action_list_size, + ack_flag) == -1) + { + /* + * if an error, return -1 + */ + return(-1); + } + /* + * flush X's buffers to make sure that the server really gets + * the input actions + */ + XFlush(display); + /* + * mark the input action buffer as empty + */ + action_index = 0; + /* + * if we asked for an acknowledge event, then wait for it + */ + if (ack_flag == XTestFAKE_ACK_REQUEST) + { + /* + * point func_ptr at XTestIdentifyMyEvent + */ + func_ptr = XTestIdentifyMyEvent; + /* + * Wait until the acknowledge event comes. When the + * acknowledge event comes, it is removed from the event + * queue without disturbing any other events that might + * be in the queue. + */ + XIfEvent(display, &event, func_ptr, NULL); + /* + * set the input action count back to 0 + */ + action_count = 0; + } + /* + * if we got here, then everything is ok, return 0 + */ + return(0); +} + +/****************************************************************************** + * + * XTestIdentifyMyEvent + * + * This function is called by XIfEvent to look at an event and see if + * it is of XTestFakeAckType. + */ +static Bool +XTestIdentifyMyEvent( +Display *display, +/* + * Holds the event that this routine is supposed to look at. + */ +XEvent *event_ptr, +/* + * this points to any user-specified arguments (ignored) + */ +char *args) +{ + /* + * if the event if of the correct type, return the Bool True, + * otherwise return the Bool False. + */ + if (event_ptr->type == XTestFakeAckType) + { + return(True); + } + else + { + return(False); + } +} + +/****************************************************************************** + * + * XTestFlush + * + * Send any input actions in the input action buffer to the server. + */ +int +XTestFlush(Display *display) +{ + /* + * acknowledge flag + */ + int ack_flag; + + /* + * if there are no input actions in the input action buffer, + * then return 0 + */ + if (action_index == 0) + { + return(0); + } + /* + * We have input actions to write to the server. We will + * wait until the server has finished processing the input actions. + */ + ack_flag = XTestFAKE_ACK_REQUEST; + /* + * write the input actions to the server + */ + return(XTestWriteInputActions(display, + (char *) &(action_buf[0]), + action_index, + ack_flag)); +} |