/* $Xorg: xtest1di.c,v 1.4 2001/02/09 02:04:33 xorgcvs Exp $ */ /* * File: xtest1di.c * * This file contains the device independent 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. */ /***************************************************************************** * include files ****************************************************************************/ #define NEED_EVENTS #define NEED_REPLIES #include #include "X.h" #include "Xproto.h" #include "misc.h" #include "os.h" #include "gcstruct.h" #include "extnsionst.h" #include "dixstruct.h" #include "opaque.h" #define XTestSERVER_SIDE #include "xtestext1.h" /***************************************************************************** * defines ****************************************************************************/ /***************************************************************************** * externals ****************************************************************************/ /* * holds the addresses of the routines that handle byte-swapping of replys */ extern void (* ReplySwapVector[256]) (); /* * id of client using XTestGetInput * * defined in xtest1dd.c */ extern ClientPtr current_xtest_client; /* * id of client using XTestFakeInput * * defined in xtest1dd.c */ extern ClientPtr playback_client; /***************************************************************************** * 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 aquired 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 aquired when this extension is installed. */ int XTestInputActionType = 0; int XTestFakeAckType = 1; /* * true => monitor stealing input */ int on_steal_input = FALSE; /* * true => monitor alone getting input */ int exclusive_steal = FALSE; /* * holds the resource type assigned to this extension */ static RESTYPE XTestType; /* * holds the resource ID for the client currently using XTestGetInput */ static XID current_client_id; /***************************************************************************** * function declarations ****************************************************************************/ static int ProcXTestDispatch(); static int SProcXTestDispatch(); static void XTestResetProc(); static int ProcTestFakeInput(); static int SProcTestFakeInput(); static int ProcTestGetInput(); static int SProcTestGetInput(); static int ProcTestStopInput(); static int SProcTestStopInput(); static int ProcTestReset(); static int SProcTestReset(); static int ProcTestQueryInputSize(); static int SProcTestQueryInputSize(); static void SReplyXTestDispatch(); static void SEventXTestDispatch(); void NotImplemented(); void abort_play_back(); void return_input_array_size(); void steal_input(); void stop_stealing_input(); void flush_input_actions(); void parse_fake_input(); static int XTestCurrentClientGone(); /***************************************************************************** * * XTestExtension1Init * * Called from InitExtensions in main() or from QueryExtension() if the * extension is dynamically loaded. * * XTestExtension1Init has no events or errors * (other than the core errors). */ void XTestExtension1Init() { /* * holds the pointer to the extension entry structure */ ExtensionEntry *extEntry; /* * This routine adds the extension to the server extension table. */ ExtensionEntry *AddExtension(); extEntry = AddExtension(XTestEXTENSION_NAME, XTestEVENT_COUNT, 0, ProcXTestDispatch, SProcXTestDispatch, XTestResetProc, StandardMinorOpcode); if (extEntry) { /* * remember the request code assigned to this extension */ XTestReqCode = extEntry->base; /* * make an atom saying that this extension is present */ (void) MakeAtom(XTestEXTENSION_NAME, strlen(XTestEXTENSION_NAME), TRUE); /* * remember the event codes assigned to this extension */ XTestInputActionType += extEntry->eventBase; XTestFakeAckType += extEntry->eventBase; /* * install the routine to handle byte-swapping the replies * for this extension in the ReplySwapVector table */ ReplySwapVector[XTestReqCode] = SReplyXTestDispatch; /* * install the routine to handle byte-swapping the events * for this extension in the EventSwapVector table */ EventSwapVector[XTestInputActionType] = SEventXTestDispatch; EventSwapVector[XTestFakeAckType] = SEventXTestDispatch; /* * get the resource type for this extension */ XTestType = CreateNewResourceType(XTestCurrentClientGone); if (XTestType == 0) { FatalError("XTestExtension1Init: CreateNewResourceType failed\n"); } } else { FatalError("XTestExtension1Init: AddExtensions failed\n"); } } /***************************************************************************** * * ProcXTestDispatch * * */ static int ProcXTestDispatch(client) register ClientPtr client; { REQUEST(xReq); if (stuff->data == X_TestFakeInput) { return(ProcTestFakeInput(client)); } else if (stuff->data == X_TestGetInput) { return(ProcTestGetInput(client)); } else if (stuff->data == X_TestStopInput) { return(ProcTestStopInput(client)); } else if (stuff->data == X_TestReset) { return(ProcTestReset(client)); } else if (stuff->data == X_TestQueryInputSize) { return(ProcTestQueryInputSize(client)); } else { SendErrorToClient(client, XTestReqCode, stuff->data, None, BadRequest); return(BadRequest); } } /***************************************************************************** * * SProcXTestDispatch * * */ static int SProcXTestDispatch(client) register ClientPtr client; { REQUEST(xReq); if (stuff->data == X_TestFakeInput) { return(SProcTestFakeInput(client)); } else if (stuff->data == X_TestGetInput) { return(SProcTestGetInput(client)); } else if (stuff->data == X_TestStopInput) { return(SProcTestStopInput(client)); } else if (stuff->data == X_TestReset) { return(SProcTestReset(client)); } else if (stuff->data == X_TestQueryInputSize) { return(SProcTestQueryInputSize(client)); } else { SendErrorToClient(client, XTestReqCode, stuff->data, None, BadRequest); return(BadRequest); } } /***************************************************************************** * * SProcTestFakeInput * * */ static int SProcTestFakeInput(client) register ClientPtr client; { /* * used in the swaps and swapl macros for temporary storage space */ register char n; /* * index counter */ int i; /* * pointer to the next input action in the request */ CARD8 *input_action_ptr; /* * holds the type of the next input action in the request */ int input_action_type; REQUEST(xTestFakeInputReq); /* * byte-swap the fields in the request */ swaps(&stuff->length, n); swapl(&stuff->ack, n); /* * have to parse and then byte-swap the input action list here */ for (i = 0; i < XTestMAX_ACTION_LIST_SIZE;) { /* * point to the next input action in the request */ input_action_ptr = &(((xTestFakeInputReq *) stuff)->action_list[i]); /* * figure out what type of input action it is */ input_action_type = (*input_action_ptr) & XTestACTION_TYPE_MASK; /* * byte-swap the input action according to it's type */ switch (input_action_type) { case XTestKEY_ACTION: /* * byte-swap the delay_time field */ swaps(&(((XTestKeyInfo *) input_action_ptr)->delay_time), n); /* * advance to the next input action */ i += sizeof(XTestKeyInfo); break; case XTestMOTION_ACTION: /* * byte-swap the delay_time field */ swaps(&(((XTestMotionInfo *) input_action_ptr)->delay_time), n); /* * advance to the next input action */ i += sizeof(XTestMotionInfo); break; case XTestJUMP_ACTION: /* * byte-swap the jumpx field */ swaps(&(((XTestJumpInfo *) input_action_ptr)->jumpx), n); /* * byte-swap the jumpy field */ swaps(&(((XTestJumpInfo *) input_action_ptr)->jumpy), n); /* * byte-swap the delay_time field */ swaps(&(((XTestJumpInfo *) input_action_ptr)->delay_time), n); /* * advance to the next input action */ i += sizeof(XTestJumpInfo); break; default: /* * if this is a delay input action, then byte-swap it, * otherwise we have reached the end of the input * actions in this request */ if (XTestUnpackDeviceID(*input_action_ptr) == XTestDELAY_DEVICE_ID) { /* * byte-swap the delay_time field */ swapl(&(((XTestDelayInfo *) input_action_ptr)->delay_time), n); /* * advance to the next input action */ i += sizeof(XTestDelayInfo); } else { /* * if the input action header byte is 0 or * ill-formed, then there are no more input * actions in this request */ i = XTestMAX_ACTION_LIST_SIZE; } break; } } return(ProcTestFakeInput(client)); } /***************************************************************************** * * SProcTestGetInput * * */ static int SProcTestGetInput(client) register ClientPtr client; { /* * used in the swaps and swapl macros for temporary storage space */ register char n; REQUEST(xTestGetInputReq); /* * byte-swap the fields in the request */ swaps(&stuff->length, n); swapl(&stuff->mode, n); return(ProcTestGetInput(client)); } /***************************************************************************** * * SProcTestStopInput * * */ static int SProcTestStopInput(client) register ClientPtr client; { /* * used in the swaps and swapl macros for temporary storage space */ register char n; REQUEST(xTestStopInputReq); /* * byte-swap the length field in the request */ swaps(&stuff->length, n); return(ProcTestStopInput(client)); } /***************************************************************************** * * SProcTestReset * * */ static int SProcTestReset(client) register ClientPtr client; { /* * used in the swaps and swapl macros for temporary storage space */ register char n; REQUEST(xTestResetReq); /* * byte-swap the length field in the request */ swaps(&stuff->length, n); return(ProcTestReset(client)); } /***************************************************************************** * * SProcTestQueryInputSize * * */ static int SProcTestQueryInputSize(client) register ClientPtr client; { /* * used in the swaps and swapl macros for temporary storage space */ register char n; REQUEST(xTestQueryInputSizeReq); /* * byte-swap the length field in the request */ swaps(&stuff->length, n); return(ProcTestQueryInputSize(client)); } /***************************************************************************** * * ProcTestFakeInput * * */ static int ProcTestFakeInput(client) register ClientPtr client; { REQUEST(xTestFakeInputReq); REQUEST_SIZE_MATCH(xTestFakeInputReq); if (playback_client == NULL) { playback_client = client; current_client_id = FakeClientID(client->index); AddResource(current_client_id, XTestType, 0); MakeClientGrabImpervious(client); } if (playback_client == client) { /* * This extension does not need to clean up any * server state when a client using this function * "goes away". The server will just process any * input actions that have already been sent to it, * and will then reset its association with a client. */ parse_fake_input(client, (char *)stuff); return(Success); } else { /* * this is a request by another client to send fake * input while the server is still being used */ SendErrorToClient(client, XTestReqCode, X_TestFakeInput, None, BadAccess); return(BadAccess); } } /***************************************************************************** * * ProcTestGetInput * * */ static int ProcTestGetInput(client) register ClientPtr client; { REQUEST(xTestGetInputReq); REQUEST_SIZE_MATCH(xTestGetInputReq); if (on_steal_input) { /* * this is a request by another client to get fake input * while the server is still sending input to the first client */ SendErrorToClient(client, XTestReqCode, X_TestGetInput, None, BadAccess); return(BadAccess); } else { /* * Set up a resource associated with the client using this * function so that this extension gets called when the * client "goes away". This allows this extension to * clean up the server state. */ current_client_id = FakeClientID(client->index); AddResource(current_client_id, XTestType, 0); /* * indicate that a client is stealing input */ on_steal_input = TRUE; if ((stuff->mode & XTestEXCLUSIVE) == 0) { exclusive_steal = FALSE; } else { exclusive_steal = TRUE; } steal_input(client, stuff->mode); return(Success); } } /***************************************************************************** * * ProcTestStopInput * * */ static int ProcTestStopInput(client) register ClientPtr client; { REQUEST(xTestStopInputReq); REQUEST_SIZE_MATCH(xTestStopInputReq); if (on_steal_input && (current_xtest_client == client)) { on_steal_input = FALSE; exclusive_steal = FALSE; stop_stealing_input(); /* * remove the resource associated with this client */ FreeResource(current_client_id, RT_NONE); return(Success); } else { /* * this is a request to stop fake input when fake input has * never been started or from a client that hasn't started * fake input */ SendErrorToClient(client, XTestReqCode, X_TestStopInput, None, BadAccess); return(BadAccess); } } /***************************************************************************** * * ProcTestReset * * */ static int ProcTestReset(client) register ClientPtr client; { REQUEST(xTestResetReq); REQUEST_SIZE_MATCH(xTestResetReq); on_steal_input = FALSE; exclusive_steal = FALSE; /* * defined in xtest1dd.c */ stop_stealing_input(); /* * defined in xtest1dd.c */ abort_play_back(); return(Success); } /***************************************************************************** * * ProcTestQueryInputSize * * */ static int ProcTestQueryInputSize(client) register ClientPtr client; { REQUEST(xTestQueryInputSizeReq); REQUEST_SIZE_MATCH(xTestQueryInputSizeReq); /* * defined in xtest1dd.c */ return_input_array_size(client); return(Success); } /***************************************************************************** * * XTestResetProc * * This function is called by the server when the server has no clients * connected to it. It must put eveything back the way it was before * this extension was installed. */ static void XTestResetProc() { /* * remove the routine to handle byte-swapping the replies * for this extension in the ReplySwapVector table */ ReplySwapVector[XTestReqCode] = NotImplemented; /* * remove the routine to handle byte-swapping the events * for this extension in the EventSwapVector table */ EventSwapVector[XTestInputActionType] = NotImplemented; EventSwapVector[XTestFakeAckType] = NotImplemented; /* * reset the variables initialized just once at load time */ XTestReqCode = 0; XTestInputActionType = 0; XTestFakeAckType = 1; on_steal_input = FALSE; exclusive_steal = FALSE; playback_client = 0; /* Don't really need this but it looks nice */ } /***************************************************************************** * * ProcTestQueryInputSize * * This routine is called when a client that has asked for input actions * to be sent to it "goes away". This routine must clean up the * server state. */ /*ARGSUSED*/ static int XTestCurrentClientGone(value, id) pointer value; XID id; { /* * defined in xtest1dd.c */ on_steal_input = FALSE; exclusive_steal = FALSE; /* * defined in xtestdd.c */ playback_client = 0; abort_play_back(); return TRUE; } /***************************************************************************** * * SReplyXTestDispatch * * Swap any replies defined in this extension. */ static void SReplyXTestDispatch(client_ptr, size, reply_ptr) ClientPtr client_ptr; int size; char *reply_ptr; { /* * used in the swaps and swapl macros for temporary storage space */ register char n; /* * pointer to xTestQueryInputSizeReply */ xTestQueryInputSizeReply *rep_ptr; /* * there is only one reply in this extension, so byte-swap it */ rep_ptr = (xTestQueryInputSizeReply *) reply_ptr; swaps(&(rep_ptr->sequenceNumber), n); swapl(&(rep_ptr->length), n); swapl(&(rep_ptr->size_return), n); /* * now write the swapped reply to the client */ WriteToClient(client_ptr, size, reply_ptr); } /***************************************************************************** * * SEventXTestDispatch * * Swap any events defined in this extension. */ static void SEventXTestDispatch(from, to) xEvent *from; xEvent *to; { /* * used in the swaps and swapl macros for temporary storage space */ register char n; /* * index counter */ int i; /* * pointer to the next input action in the event */ CARD8 *input_action_ptr; /* * holds the type of the next input action in the event */ int input_action_type; /* * copy the type information from the "from" event to the "to" event */ ((xTestInputActionEvent *) to)->type = ((xTestInputActionEvent *) from)->type; /* * copy the sequence number information from the "from" event to the * "to" event */ ((xTestInputActionEvent *) to)->sequenceNumber = ((xTestInputActionEvent *) from)->sequenceNumber; /* * byte-swap the sequence number in the "to" event */ swaps(&(((xTestInputActionEvent *) to)->sequenceNumber), n); /* * If the event is an xTestInputActionEvent, then it needs more * processing. Otherwise, it is an xTestFakeAckEvent, which * has no other information in it. */ if ((((xTestInputActionEvent *) to)->type & 0x7f) == XTestInputActionType) { /* * copy the input actions from the "from" event * to the "to" event */ for (i = 0; i < XTestACTIONS_SIZE; i++) { ((xTestInputActionEvent *) to)->actions[i] = ((xTestInputActionEvent *) from)->actions[i]; } /* * byte-swap the input actions in the "to" event */ for (i = 0; i < XTestACTIONS_SIZE; i++) { /* * point to the next input action in the event */ input_action_ptr = &(((xTestInputActionEvent *) to)->actions[i]); /* * figure out what type of input action it is */ input_action_type = (*input_action_ptr) & XTestACTION_TYPE_MASK; /* * byte-swap the input action according to it's type */ switch (input_action_type) { case XTestKEY_ACTION: /* * byte-swap the delay_time field */ swaps(&(((XTestKeyInfo *) input_action_ptr)->delay_time), n); /* * advance to the next input action */ i += sizeof(XTestKeyInfo); break; case XTestMOTION_ACTION: /* * byte-swap the delay_time field */ swaps(&(((XTestMotionInfo *) input_action_ptr)->delay_time), n); /* * advance to the next input action */ i += sizeof(XTestMotionInfo); break; case XTestJUMP_ACTION: /* * byte-swap the jumpx field */ swaps(&(((XTestJumpInfo *) input_action_ptr)->jumpx), n); /* * byte-swap the jumpy field */ swaps(&(((XTestJumpInfo *) input_action_ptr)->jumpy), n); /* * byte-swap the delay_time field */ swaps(&(((XTestJumpInfo *) input_action_ptr)->delay_time), n); /* * advance to the next input action */ i += sizeof(XTestJumpInfo); break; default: /* * if this is a delay input action, then * byte-swap it, otherwise we have reached the * end of the input actions in this event */ if (XTestUnpackDeviceID(*input_action_ptr) == XTestDELAY_DEVICE_ID) { /* * byte-swap the delay_time field */ swapl(&(((XTestDelayInfo *) input_action_ptr)->delay_time), n); /* * advance to the next input action */ i += sizeof(XTestDelayInfo); } else { /* * if the input action header byte is 0 * or ill-formed, then there are no * more input actions in this event */ i = XTestACTIONS_SIZE; } break; } } } }