/* * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice (including the next * paragraph) 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 AUTHORS OR COPYRIGHT HOLDERS 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. * * Authors: * * Paulo Zanoni * Tuan Bui * Colin Cornaby * Timothy Fleck * Colin Hill * Weseung Hwang * Nathaniel Way */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "client.h" #include "nested_input.h" #define SYSCALL(call) while (((call) == -1) && (errno == EINTR)) #define NUM_MOUSE_BUTTONS 6 #define NUM_MOUSE_AXES 2 static pointer NestedInputPlug(pointer module, pointer options, int *errmaj, int *errmin); static void NestedInputUnplug(pointer p); static void NestedInputReadInput(InputInfoPtr pInfo); static int NestedInputControl(DeviceIntPtr device,int what); static int _nested_input_init_keyboard(DeviceIntPtr device); static int _nested_input_init_buttons(DeviceIntPtr device); static int _nested_input_init_axes(DeviceIntPtr device); typedef struct _NestedInputDeviceRec { NestedClientPrivatePtr clientData; int version; } NestedInputDeviceRec, *NestedInputDevicePtr; static XF86ModuleVersionInfo NestedInputVersionRec = { "nestedinput", MODULEVENDORSTRING, MODINFOSTRING1, MODINFOSTRING2, XORG_VERSION_CURRENT, PACKAGE_VERSION_MAJOR, PACKAGE_VERSION_MINOR, PACKAGE_VERSION_PATCHLEVEL, ABI_CLASS_XINPUT, ABI_XINPUT_VERSION, MOD_CLASS_XINPUT, {0, 0, 0, 0} }; _X_EXPORT XF86ModuleData nestedInputModuleData = { &NestedInputVersionRec, &NestedInputPlug, &NestedInputUnplug }; int NestedInputPreInit(InputDriverPtr drv, InputInfoPtr pInfo, int flags) { NestedInputDevicePtr pNestedInput; pNestedInput = calloc(1, sizeof(NestedInputDeviceRec)); if (!pNestedInput) return BadAlloc; pInfo->private = pNestedInput; pInfo->type_name = XI_MOUSE; // This is really both XI_MOUSE and XI_KEYBOARD... but oh well. pInfo->read_input = NestedInputReadInput; // new data available. pInfo->switch_mode = NULL; // Toggle absolute/relative mode. pInfo->device_control = NestedInputControl; // Enable/disable device. return Success; } void NestedInputUnInit(InputDriverPtr drv, InputInfoPtr pInfo, int flags) { } static pointer NestedInputPlug(pointer module, pointer options, int *errmaj, int *errmin) { return NULL; } static void NestedInputUnplug(pointer p) { } static void NestedInputUpdateKeymap(DeviceIntPtr device) { InputInfoPtr pInfo = device->public.devicePrivate; NestedInputDevicePtr pNestedInput = pInfo->private; KeySymsRec keySyms; XkbControlsRec ctrls; CARD8 modmap[MAP_LENGTH]; if(!NestedClientGetKeyboardMappings(pNestedInput->clientData, &keySyms, modmap, &ctrls)) { xf86Msg(X_ERROR, "%s: Failed to get keyboard mappings.\n", pInfo->name); return; } #ifdef _XSERVER64 { unsigned long *keymap64 = (unsigned long *)keySyms.map; size_t len = (keySyms.maxKeyCode - keySyms.minKeyCode + 1) * keySyms.mapWidth; size_t i; keySyms.map = malloc(len * sizeof(KeySym)); if (!keySyms.map) { xf86Msg(X_ERROR, "%s: Failed to get keyboard mappings.\n", pInfo->name); free(keymap64); return; } for(i = 0; i < len; ++i) keySyms.map[i] = keymap64[i]; free(keymap64); } #endif XkbApplyMappingChange(device, &keySyms, keySyms.minKeyCode, keySyms.maxKeyCode - keySyms.minKeyCode + 1, modmap, serverClient); XkbDDXChangeControls(device, &ctrls, &ctrls); free(keySyms.map); if (inputInfo.keyboard != device) XkbCopyDeviceKeymap(inputInfo.keyboard, device); } static int _nested_input_init_keyboard(DeviceIntPtr device) { InputInfoPtr pInfo = device->public.devicePrivate; if (!InitKeyboardDeviceStruct(device, NULL, NULL, NULL)) { xf86Msg(X_ERROR, "%s: Failed to register keyboard.\n", pInfo->name); return BadAlloc; } return Success; } static int _nested_input_init_buttons(DeviceIntPtr device) { InputInfoPtr pInfo = device->public.devicePrivate; CARD8 *map; Atom buttonLabels[NUM_MOUSE_BUTTONS] = {0}; map = calloc(NUM_MOUSE_BUTTONS, sizeof(CARD8)); int i; for (i = 0; i < NUM_MOUSE_BUTTONS; i++) map[i] = i; if (!InitButtonClassDeviceStruct(device, NUM_MOUSE_BUTTONS, buttonLabels, map)) { xf86Msg(X_ERROR, "%s: Failed to register buttons.\n", pInfo->name); free(map); return BadAlloc; } return Success; } static int _nested_input_init_axes(DeviceIntPtr device) { if (!InitValuatorClassDeviceStruct(device, NUM_MOUSE_AXES, (Atom*)GetMotionHistory, // Not sure about this. GetMotionHistorySize(), (Atom)0)) { return BadAlloc; } int i; for (i = 0; i < NUM_MOUSE_AXES; i++) { xf86InitValuatorAxisStruct(device, i, (Atom)0, -1, -1, 1, 1, 1, Absolute); xf86InitValuatorDefaults(device, i); } return Success; } static CARD32 nested_input_on(OsTimerPtr timer, CARD32 time, pointer arg) { DeviceIntPtr device = arg; InputInfoPtr pInfo = device->public.devicePrivate; NestedInputDevicePtr pNestedInput = pInfo->private; if(device->public.on) { pInfo->fd = NestedClientGetFileDescriptor(pNestedInput->clientData); xf86FlushInput(pInfo->fd); xf86AddEnabledDevice(pInfo); } return 0; } static int NestedInputControl(DeviceIntPtr device, int what) { int err; InputInfoPtr pInfo = device->public.devicePrivate; switch (what) { case DEVICE_INIT: err = _nested_input_init_keyboard(device); if (err != Success) return err; err = _nested_input_init_buttons(device); if (err != Success) return err; err = _nested_input_init_axes(device); if (err != Success) return err; break; case DEVICE_ON: xf86Msg(X_INFO, "%s: On.\n", pInfo->name); if (device->public.on) break; device->public.on = TRUE; TimerSet(NULL, 0, 1, nested_input_on, device); break; case DEVICE_OFF: xf86Msg(X_INFO, "%s: Off.\n", pInfo->name); if (!device->public.on) break; xf86RemoveEnabledDevice(pInfo); pInfo->fd = -1; device->public.on = FALSE; break; case DEVICE_CLOSE: break; } return Success; } static CARD32 nested_input_ready(OsTimerPtr timer, CARD32 time, pointer arg) { NestedClientPrivatePtr clientData = arg; NestedClientCheckEvents(clientData); return 0; } static void NestedInputReadInput(InputInfoPtr pInfo) { NestedInputDevicePtr pNestedInput = pInfo->private; TimerSet(NULL, 0, 1, nested_input_ready, pNestedInput->clientData); } #if GET_ABI_MAJOR(ABI_XINPUT_VERSION) < 14 static InputOption* input_option_new(InputOption* list, char *key, char *value) { InputOption *tmp; tmp = calloc(1, sizeof(*tmp)); tmp->key = key; tmp->value = value; tmp->next = list; return tmp; } static void input_option_free_list(InputOption **list) { InputOption *iopts = *list; while(iopts) { InputOption *tmp = iopts->next; free(iopts->key); free(iopts->value); free(iopts); iopts = tmp; } *list = NULL; } #endif void NestedInputLoadDriver(NestedClientPrivatePtr clientData) { DeviceIntPtr dev; InputInfoPtr pInfo; NestedInputDevicePtr pNestedInput; // Create input options for our invocation to NewInputDeviceRequest. InputOption* options = NULL; options = input_option_new(options, strdup("identifier"), strdup("nestedinput")); options = input_option_new(options, strdup("driver"), strdup("nestedinput")); // Invoke NewInputDeviceRequest to call the PreInit function of // the driver. int ret = NewInputDeviceRequest(options, NULL, &dev); input_option_free_list(&options); if (ret != Success) { FatalError("Failed to load input driver.\n"); } pInfo = dev->public.devicePrivate; pNestedInput = pInfo->private; pNestedInput->clientData = clientData; // Set our keymap to be the same as the server's NestedInputUpdateKeymap(dev); // Send the device to the client so that the client can send the // device back to the input driver when events are being posted. NestedClientSetDevicePtr(clientData, dev); } void NestedInputPostMouseMotionEvent(DeviceIntPtr dev, int x, int y) { xf86PostMotionEvent(dev, TRUE, 0, 2, x, y); } void NestedInputPostButtonEvent(DeviceIntPtr dev, int button, int isDown) { xf86PostButtonEvent(dev, 0, button, isDown, 0, 0); } void NestedInputPostKeyboardEvent(DeviceIntPtr dev, unsigned int keycode, int isDown) { xf86PostKeyboardEvent(dev, keycode, isDown); }