From 96d6df5da9cddedf4931bf8e17f96e242467c661 Mon Sep 17 00:00:00 2001 From: marha Date: Wed, 27 Apr 2011 06:58:32 +0000 Subject: xserver libX11 libxtrans mesa pixman xkeyboard-config git update 27 Apr 2011 --- xorg-server/hw/dmx/input/dmxevents.c | 1600 +++++++++++++++++----------------- 1 file changed, 800 insertions(+), 800 deletions(-) (limited to 'xorg-server/hw/dmx/input') diff --git a/xorg-server/hw/dmx/input/dmxevents.c b/xorg-server/hw/dmx/input/dmxevents.c index efcd07da3..15d80f5bb 100644 --- a/xorg-server/hw/dmx/input/dmxevents.c +++ b/xorg-server/hw/dmx/input/dmxevents.c @@ -1,800 +1,800 @@ -/* - * Copyright 2002-2003 Red Hat Inc., Durham, North Carolina. - * - * All Rights Reserved. - * - * 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 on 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 - * NON-INFRINGEMENT. IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS - * 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: - * Rickard E. (Rik) Faith - * - */ - -/** \file - * Provide support and helper functions for enqueing events received by - * the low-level input drivers. */ - -#ifdef HAVE_DMX_CONFIG_H -#include -#endif - -#define DMX_EVENTS_DEBUG 0 - -#include "dmxinputinit.h" -#include "dmxevents.h" -#include "dmxcb.h" -#include "dmxcommon.h" -#include "dmxcursor.h" -#include "dmxmotion.h" -#include "dmxsigio.h" -#include "dmxmap.h" - -#include -#include "opaque.h" -#include "inputstr.h" -#include "inpututils.h" -#include "mipointer.h" -#include "mi.h" -#include "exglobals.h" - -#include "xkbsrv.h" -#include "XIstubs.h" - -static int dmxGlobalX, dmxGlobalY; /* Global cursor position */ -static int dmxGlobalInvalid; /* Flag indicating dmxCoreMotion - * should move the mouse anyway. */ - -#if DMX_EVENTS_DEBUG -#define DMXDBG0(f) dmxLog(dmxDebug,f) -#define DMXDBG1(f,a) dmxLog(dmxDebug,f,a) -#define DMXDBG2(f,a,b) dmxLog(dmxDebug,f,a,b) -#define DMXDBG3(f,a,b,c) dmxLog(dmxDebug,f,a,b,c) -#define DMXDBG4(f,a,b,c,d) dmxLog(dmxDebug,f,a,b,c,d) -#define DMXDBG5(f,a,b,c,d,e) dmxLog(dmxDebug,f,a,b,c,d,e) -#define DMXDBG6(f,a,b,c,d,e,g) dmxLog(dmxDebug,f,a,b,c,d,e,g) -#define DMXDBG7(f,a,b,c,d,e,g,h) dmxLog(dmxDebug,f,a,b,c,d,e,g,h) -#else -#define DMXDBG0(f) -#define DMXDBG1(f,a) -#define DMXDBG2(f,a,b) -#define DMXDBG3(f,a,b,c) -#define DMXDBG4(f,a,b,c,d) -#define DMXDBG5(f,a,b,c,d,e) -#define DMXDBG6(f,a,b,c,d,e,g) -#define DMXDBG7(f,a,b,c,d,e,g,h) -#endif - -static int dmxApplyFunctions(DMXInputInfo *dmxInput, DMXFunctionType f) -{ - int i; - int rc = 0; - - for (i = 0; i < dmxInput->numDevs; i+= dmxInput->devs[i]->binding) - if (dmxInput->devs[i]->functions) - rc += dmxInput->devs[i]->functions(dmxInput->devs[i]->private, f); - return rc; -} - -static int dmxCheckFunctionKeys(DMXLocalInputInfoPtr dmxLocal, - int type, - KeySym keySym) -{ - DMXInputInfo *dmxInput = &dmxInputs[dmxLocal->inputIdx]; - -#if 1 /* hack to detect ctrl-alt-q, etc */ - static int ctrl = 0, alt = 0; - /* keep track of ctrl/alt key status */ - if (type == KeyPress && keySym == 0xffe3) { - ctrl = 1; - } - else if (type == KeyRelease && keySym == 0xffe3) { - ctrl = 0; - } - else if (type == KeyPress && keySym == 0xffe9) { - alt = 1; - } - else if (type == KeyRelease && keySym == 0xffe9) { - alt = 0; - } - if (!ctrl || !alt) - return 0; -#else - unsigned short state = 0; - - if (dmxLocal->sendsCore) - state = dmxLocalCoreKeyboard->pDevice->key->state; - else if (dmxLocal->pDevice->key) - state = dmxLocal->pDevice->key->state; - - DMXDBG3("dmxCheckFunctionKeys: keySym=0x%04x %s state=0x%04x\n", - keySym, type == KeyPress ? "press" : "release", state); - - if ((state & (ControlMask|Mod1Mask)) != (ControlMask|Mod1Mask)) - return 0; -#endif - - switch (keySym) { - case XK_g: - if (type == KeyPress) - dmxApplyFunctions(dmxInput, DMX_FUNCTION_GRAB); - return 1; - case XK_f: - if (type == KeyPress) - dmxApplyFunctions(dmxInput, DMX_FUNCTION_FINE); - return 1; - case XK_q: - if (type == KeyPress && dmxLocal->sendsCore) - if (dmxApplyFunctions(dmxInput, DMX_FUNCTION_TERMINATE)) { - dmxLog(dmxInfo, "User request for termination\n"); - dispatchException |= DE_TERMINATE; - } - return 1; - } - - return 0; -} - - -DMXScreenInfo *dmxFindFirstScreen(int x, int y) -{ - int i; - - for (i = 0; i < dmxNumScreens; i++) { - DMXScreenInfo *dmxScreen = &dmxScreens[i]; - if (dmxOnScreen(x, y, dmxScreen)) - return dmxScreen; - } - return NULL; -} - - -/** - * Enqueue a motion event. - */ -static void enqueueMotion(DevicePtr pDev, int x, int y) -{ - GETDMXLOCALFROMPDEV; - DeviceIntPtr p = dmxLocal->pDevice; - int i, nevents, valuators[3]; - EventListPtr events; - int detail = 0; /* XXX should this be mask of pressed buttons? */ - ValuatorMask mask; - valuators[0] = x; - valuators[1] = y; - - valuator_mask_set_range(&mask, 0, 2, valuators); - GetEventList(&events); - nevents = GetPointerEvents(events, p, MotionNotify, detail, - POINTER_ABSOLUTE | POINTER_SCREEN, &mask); - for (i = 0; i < nevents; i++) - mieqEnqueue(p, (InternalEvent*)(events + i)->event); - return; -} - - -void -dmxCoreMotion(DevicePtr pDev, int x, int y, int delta, DMXBlockType block) -{ - DMXScreenInfo *dmxScreen; - DMXInputInfo *dmxInput; - ScreenPtr pScreen; - int localX; - int localY; - int i; - - if (!dmxGlobalInvalid && dmxGlobalX == x && dmxGlobalY == y) - return; - - DMXDBG5("dmxCoreMotion(%d,%d,%d) dmxGlobalX=%d dmxGlobalY=%d\n", - x, y, delta, dmxGlobalX, dmxGlobalY); - - dmxGlobalInvalid = 0; - dmxGlobalX = x; - dmxGlobalY = y; - - if (dmxGlobalX < 0) - dmxGlobalX = 0; - if (dmxGlobalY < 0) - dmxGlobalY = 0; - if (dmxGlobalX >= dmxGlobalWidth) - dmxGlobalX = dmxGlobalWidth + delta -1; - if (dmxGlobalY >= dmxGlobalHeight) - dmxGlobalY = dmxGlobalHeight + delta -1; - - if ((dmxScreen = dmxFindFirstScreen(dmxGlobalX, dmxGlobalY))) { - localX = dmxGlobalX - dmxScreen->rootXOrigin; - localY = dmxGlobalY - dmxScreen->rootYOrigin; - if ((pScreen = miPointerGetScreen(inputInfo.pointer)) - && pScreen->myNum == dmxScreen->index) { - /* Screen is old screen */ - if (block) - dmxSigioBlock(); - if (pDev) - enqueueMotion(pDev, localX, localY); - if (block) - dmxSigioUnblock(); - } else { - /* Screen is new */ - DMXDBG4(" New screen: old=%d new=%d localX=%d localY=%d\n", - pScreen->myNum, dmxScreen->index, localX, localY); - if (block) - dmxSigioBlock(); - mieqProcessInputEvents(); - miPointerSetScreen(inputInfo.pointer, dmxScreen->index, - localX, localY); - if (pDev) - enqueueMotion(pDev, localX, localY); - if (block) - dmxSigioUnblock(); - } -#if 00 - miPointerGetPosition(inputInfo.pointer, &localX, &localY); - - if ((pScreen = miPointerGetScreen(inputInfo.pointer))) { - dmxGlobalX = localX + dmxScreens[pScreen->myNum].rootXOrigin; - dmxGlobalY = localY + dmxScreens[pScreen->myNum].rootYOrigin; - ErrorF("Global is now %d, %d %d, %d\n", dmxGlobalX, dmxGlobalY, - localX, localY); - DMXDBG6(" Moved to dmxGlobalX=%d dmxGlobalY=%d" - " on screen index=%d/%d localX=%d localY=%d\n", - dmxGlobalX, dmxGlobalY, - dmxScreen ? dmxScreen->index : -1, pScreen->myNum, - localX, localY); - } -#endif - } - /* Send updates down to all core input - * drivers */ - for (i = 0, dmxInput = &dmxInputs[0]; i < dmxNumInputs; i++, dmxInput++) { - int j; - for (j = 0; j < dmxInput->numDevs; j += dmxInput->devs[j]->binding) - if (!dmxInput->detached - && dmxInput->devs[j]->sendsCore - && dmxInput->devs[j]->update_position) - dmxInput->devs[j]->update_position(dmxInput->devs[j]->private, - dmxGlobalX, dmxGlobalY); - } - if (!dmxScreen) ProcessInputEvents(); -} - - - -#define DMX_MAX_AXES 32 /* Max axes reported by this routine */ -static void dmxExtMotion(DMXLocalInputInfoPtr dmxLocal, - int *v, int firstAxis, int axesCount, - DMXMotionType type, DMXBlockType block) -{ - DeviceIntPtr pDevice = dmxLocal->pDevice; - xEvent xE[2 * DMX_MAX_AXES/6]; - deviceKeyButtonPointer *xev = (deviceKeyButtonPointer *)xE; - deviceValuator *xv = (deviceValuator *)xev+1; - int thisX = 0; - int thisY = 0; - int i; - int count; - EventListPtr events; - int nevents; - ValuatorMask mask; - - memset(xE, 0, sizeof(xE)); - - if (axesCount > DMX_MAX_AXES) axesCount = DMX_MAX_AXES; - - if ((valuator_get_mode(pDevice,0) == Relative) && axesCount == 2) { - /* The dmx console is a relative mode - * device that sometimes reports - * absolute motion. It only has two - * axes. */ - if (type == DMX_RELATIVE) { - thisX = -v[0]; - thisY = -v[1]; - dmxLocal->lastX += thisX; - dmxLocal->lastY += thisY; - if (dmxLocal->update_position) - dmxLocal->update_position(dmxLocal->private, - dmxLocal->lastX, dmxLocal->lastY); - } else { /* Convert to relative */ - if (dmxLocal->lastX || dmxLocal->lastY) { - thisX = v[0] - dmxLocal->lastX; - thisY = v[1] - dmxLocal->lastY; - } - dmxLocal->lastX = v[0]; - dmxLocal->lastY = v[1]; - } - v[0] = thisX; - v[1] = thisY; - } - - if (axesCount <= 6) { - /* Optimize for the common case when - * only 1 or 2 axes change. */ - xev->time = GetTimeInMillis(); - xev->type = DeviceMotionNotify; - xev->detail = 0; - xev->deviceid = pDevice->id | MORE_EVENTS; - - xv->type = DeviceValuator; - xv->deviceid = pDevice->id; - xv->num_valuators = axesCount; - xv->first_valuator = firstAxis; - switch (xv->num_valuators) { - case 6: xv->valuator5 = v[5]; - case 5: xv->valuator4 = v[4]; - case 4: xv->valuator3 = v[3]; - case 3: xv->valuator2 = v[2]; - case 2: xv->valuator1 = v[1]; - case 1: xv->valuator0 = v[0]; - } - count = 2; - } else { - for (i = 0, count = 0; i < axesCount; i += 6) { - xev->time = GetTimeInMillis(); - xev->type = DeviceMotionNotify; - xev->detail = 0; - xev->deviceid = pDevice->id | MORE_EVENTS; - xev += 2; - - xv->type = DeviceValuator; - xv->deviceid = pDevice->id; - xv->num_valuators = (i+6 >= axesCount ? axesCount - i : 6); - xv->first_valuator = firstAxis + i; - switch (xv->num_valuators) { - case 6: xv->valuator5 = v[i+5]; - case 5: xv->valuator4 = v[i+4]; - case 4: xv->valuator3 = v[i+3]; - case 3: xv->valuator2 = v[i+2]; - case 2: xv->valuator1 = v[i+1]; - case 1: xv->valuator0 = v[i+0]; - } - xv += 2; - count += 2; - } - } - - if (block) - dmxSigioBlock(); - valuator_mask_set_range(&mask, firstAxis, axesCount, v); - GetEventList(&events); - nevents = GetPointerEvents(events, pDevice, MotionNotify, 0, - POINTER_ABSOLUTE, &mask); - for (i = 0; i < nevents; i++) - mieqEnqueue(pDevice, (InternalEvent*)(events + i)->event); - - if (block) - dmxSigioUnblock(); -} - -static int dmxTranslateAndEnqueueExtEvent(DMXLocalInputInfoPtr dmxLocal, - XEvent *e, DMXBlockType block) -{ - int type; - int event = -1; - XDeviceKeyEvent *ke = (XDeviceKeyEvent *)e; - XDeviceMotionEvent *me = (XDeviceMotionEvent *)e; - DeviceIntPtr pDevice = dmxLocal->pDevice; - int valuators[MAX_VALUATORS]; - EventListPtr events; - int nevents, i; - ValuatorMask mask; - - if (!e) - return -1; /* No extended event passed, cannot handle */ - - if ((XID)dmxLocal->deviceId != ke->deviceid) { - /* Search for the correct dmxLocal, - * since backend and console events are - * picked up for the first device on - * that X server. */ - int i; - DMXInputInfo *dmxInput = &dmxInputs[dmxLocal->inputIdx]; - for (i = 0; i < dmxInput->numDevs; i++) { - dmxLocal = dmxInput->devs[i]; - if ((XID)dmxLocal->deviceId == ke->deviceid) - break; - } - } - - if ((XID)dmxLocal->deviceId != ke->deviceid - || (type = dmxMapLookup(dmxLocal, e->type)) < 0) - return -1; /* No mapping, so this event is unhandled */ - - switch (type) { - case XI_DeviceValuator: event = DeviceValuator; break; - case XI_DeviceKeyPress: event = KeyPress; break; - case XI_DeviceKeyRelease: event = KeyRelease; break; - case XI_DeviceButtonPress: event = ButtonPress; break; - case XI_DeviceButtonRelease: event = ButtonRelease; break; - case XI_DeviceMotionNotify: event = MotionNotify; break; - case XI_DeviceFocusIn: event = DeviceFocusIn; break; - case XI_DeviceFocusOut: event = DeviceFocusOut; break; - case XI_ProximityIn: event = ProximityIn; break; - case XI_ProximityOut: event = ProximityOut; break; - case XI_DeviceStateNotify: event = DeviceStateNotify; break; - case XI_DeviceMappingNotify: event = DeviceMappingNotify; break; - case XI_ChangeDeviceNotify: event = ChangeDeviceNotify; break; - case XI_DeviceKeystateNotify: event = DeviceStateNotify; break; - case XI_DeviceButtonstateNotify: event = DeviceStateNotify; break; - } - -#define EXTRACT_VALUATORS(ke, valuators) \ - valuators[0] = ke->axis_data[0]; \ - valuators[1] = ke->axis_data[1]; \ - valuators[2] = ke->axis_data[2]; \ - valuators[3] = ke->axis_data[3]; \ - valuators[4] = ke->axis_data[4]; \ - valuators[5] = ke->axis_data[5]; \ - - switch (type) { - case XI_DeviceKeyPress: - case XI_DeviceKeyRelease: - EXTRACT_VALUATORS(ke, valuators); - valuator_mask_set_range(&mask, ke->first_axis, ke->axes_count, valuators); - if (block) - dmxSigioBlock(); - GetEventList(&events); - nevents = GetKeyboardValuatorEvents(events, pDevice, event, - ke->keycode, &mask); - for (i = 0; i < nevents; i++) - mieqEnqueue(pDevice, (InternalEvent*)(events + i)->event); - - if (block) - dmxSigioUnblock(); - break; - case XI_DeviceButtonPress: - case XI_DeviceButtonRelease: - EXTRACT_VALUATORS(ke, valuators); - valuator_mask_set_range(&mask, ke->first_axis, ke->axes_count, valuators); - if (block) - dmxSigioBlock(); - GetEventList(&events); - nevents = GetPointerEvents(events, pDevice, event, ke->keycode, - POINTER_ABSOLUTE, &mask); - for (i = 0; i < nevents; i++) - mieqEnqueue(pDevice, (InternalEvent*)(events + i)->event); - - if (block) - dmxSigioUnblock(); - break; - case XI_ProximityIn: - case XI_ProximityOut: - EXTRACT_VALUATORS(ke, valuators); - valuator_mask_set_range(&mask, ke->first_axis, ke->axes_count, valuators); - if (block) - dmxSigioBlock(); - GetEventList(&events); - nevents = GetProximityEvents(events, pDevice, event, &mask); - for (i = 0; i < nevents; i++) - mieqEnqueue(pDevice, (InternalEvent*)(events + i)->event); - - if (block) - dmxSigioUnblock(); - break; - - break; - - case XI_DeviceMotionNotify: - dmxExtMotion(dmxLocal, me->axis_data, me->first_axis, me->axes_count, - DMX_ABSOLUTE, block); - break; - case XI_DeviceFocusIn: - case XI_DeviceFocusOut: - case XI_DeviceStateNotify: - case XI_DeviceMappingNotify: - case XI_ChangeDeviceNotify: - case XI_DeviceKeystateNotify: - case XI_DeviceButtonstateNotify: - /* These are ignored, since DMX will - * generate its own events of these - * types, as necessary. - - * Perhaps ChangeDeviceNotify should - * generate an error, because it is - * unexpected? */ - break; - case XI_DeviceValuator: - default: - dmxLog(dmxWarning, - "XInput extension event (remote=%d -> zero-based=%d)" - " not supported yet\n", e->type, type); - return -1; - } - return 0; -} - -static int dmxGetButtonMapping(DMXLocalInputInfoPtr dmxLocal, int button) -{ - ButtonClassPtr b = dmxLocal->pDevice->button; - - if (button > b->numButtons) { /* This shouldn't happen. */ - dmxLog(dmxWarning, "Button %d pressed, but only %d buttons?!?\n", - button, b->numButtons); - return button; - } - return b->map[button]; -} - -/** Return DMX's notion of the pointer position in the global coordinate - * space. */ -void dmxGetGlobalPosition(int *x, int *y) -{ - *x = dmxGlobalX; - *y = dmxGlobalY; -} - -/** Invalidate the global position for #dmxCoreMotion. */ -void dmxInvalidateGlobalPosition(void) -{ - dmxGlobalInvalid = 1; -} - -/** Enqueue a motion event for \a pDev. The \a v vector has length \a - * axesCount, and contains values for each of the axes, starting at \a - * firstAxes. - * - * The \a type of the motion may be \a DMX_RELATIVE, \a DMX_ABSOLUTE, or - * \a DMX_ABSOLUTE_CONFINED (in the latter case, the pointer will not be - * allowed to move outside the global boundaires). - * - * If \a block is set to \a DMX_BLOCK, then the SIGIO handler will be - * blocked around calls to \a enqueueMotion(). */ -void dmxMotion(DevicePtr pDev, int *v, int firstAxes, int axesCount, - DMXMotionType type, DMXBlockType block) -{ - GETDMXLOCALFROMPDEV; - - if (!dmxLocal->sendsCore) { - dmxExtMotion(dmxLocal, v, firstAxes, axesCount, type, block); - return; - } - if (axesCount == 2) { - switch (type) { - case DMX_RELATIVE: - dmxCoreMotion(pDev, dmxGlobalX - v[0], dmxGlobalY - v[1], 0, block); - break; - case DMX_ABSOLUTE: - dmxCoreMotion(pDev, v[0], v[1], 0, block); - break; - case DMX_ABSOLUTE_CONFINED: - dmxCoreMotion(pDev, v[0], v[1], -1, block); - break; - } - } -} - -static KeySym dmxKeyCodeToKeySym(DMXLocalInputInfoPtr dmxLocal, - KeyCode keyCode) -{ - KeySym keysym = NoSymbol; - int effectiveGroup; - XkbSrvInfoPtr xkbi; - - if (!dmxLocal || !dmxLocal->pDevice || !dmxLocal->pDevice->key) - goto out; - - xkbi = dmxLocal->pDevice->key->xkbInfo; - effectiveGroup = XkbGetEffectiveGroup(xkbi, &xkbi->state, keyCode); - - if (effectiveGroup == -1) - goto out; - - keysym = XkbKeySym(xkbi->desc, keyCode, effectiveGroup); - DMXDBG2("dmxKeyCodeToKeySym: Translated keyCode=%d to keySym=0x%04x\n", - keyCode, keysym); - -out: - return keysym; -} - -static KeyCode dmxKeySymToKeyCode(DMXLocalInputInfoPtr dmxLocal, KeySym keySym, - int tryFirst) -{ - /* FIXME: this is quite ineffective, converting to a core map first and - * then extracting the info from there. It'd be better to run the actual - * xkb map */ - XkbSrvInfoPtr xkbi = dmxLocal->pDevice->key->xkbInfo; - KeySymsPtr pKeySyms = XkbGetCoreMap(dmxLocal->pDevice); - int i; - - /* Optimize for similar maps */ - if (XkbKeycodeInRange(xkbi->desc, tryFirst) - && pKeySyms->map[(tryFirst - xkbi->desc->min_key_code) - * pKeySyms->mapWidth] == keySym) - return tryFirst; - - for (i = pKeySyms->minKeyCode; i <= pKeySyms->maxKeyCode; i++) { - if (pKeySyms->map[(i - pKeySyms->minKeyCode) - * pKeySyms->mapWidth] == keySym) { - DMXDBG3("dmxKeySymToKeyCode: Translated keySym=0x%04x to" - " keyCode=%d (reverses to core keySym=0x%04x)\n", - keySym, i, dmxKeyCodeToKeySym(dmxLocalCoreKeyboard,i)); - return i; - } - } - return 0; -} - -static int dmxFixup(DevicePtr pDev, int detail, KeySym keySym) -{ - GETDMXLOCALFROMPDEV; - int keyCode; - - if (!dmxLocal->pDevice->key) { - dmxLog(dmxWarning, "dmxFixup: not a keyboard device (%s)\n", - dmxLocal->pDevice->name); - return NoSymbol; - } - if (!keySym) - keySym = dmxKeyCodeToKeySym(dmxLocal, detail); - if (keySym == NoSymbol) - return detail; - keyCode = dmxKeySymToKeyCode(dmxLocalCoreKeyboard, keySym, detail); - - return keyCode ? keyCode : detail; -} - -/** Enqueue an event from the \a pDev device with the - * specified \a type and \a detail. If the event is a KeyPress or - * KeyRelease event, then the \a keySym is also specified. - * - * FIXME: make the code do what the comment says, or remove this comment. - * If \a block is set to \a DMX_BLOCK, then the SIGIO handler will be - * blocked around calls to dmxeqEnqueue(). */ - -void dmxEnqueue(DevicePtr pDev, int type, int detail, KeySym keySym, - XEvent *e, DMXBlockType block) -{ - GETDMXINPUTFROMPDEV; - xEvent xE; - DeviceIntPtr p = dmxLocal->pDevice; - int i, nevents, valuators[3]; - EventListPtr events; - ValuatorMask mask; - - DMXDBG2("dmxEnqueue: Enqueuing type=%d detail=0x%0x\n", type, detail); - - switch (type) { - case KeyPress: - case KeyRelease: - if (!keySym) - keySym = dmxKeyCodeToKeySym(dmxLocal, detail); - if (dmxCheckFunctionKeys(dmxLocal, type, keySym)) - return; - if (dmxLocal->sendsCore && dmxLocal != dmxLocalCoreKeyboard) - xE.u.u.detail = dmxFixup(pDev, detail, keySym); - - GetEventList(&events); - /*ErrorF("KEY %d sym %d\n", detail, (int) keySym);*/ - nevents = GetKeyboardEvents(events, p, type, detail); - for (i = 0; i < nevents; i++) - mieqEnqueue(p, (InternalEvent*)(events + i)->event); - return; - - case ButtonPress: - case ButtonRelease: - detail = dmxGetButtonMapping(dmxLocal, detail); - valuator_mask_zero(&mask); - GetEventList(&events); - nevents = GetPointerEvents(events, p, type, detail, - POINTER_ABSOLUTE | POINTER_SCREEN, &mask); - for (i = 0; i < nevents; i++) - mieqEnqueue(p, (InternalEvent*)(events + i)->event); - return; - - case MotionNotify: - GetEventList(&events); - valuators[0] = e->xmotion.x; - valuators[1] = e->xmotion.y; - valuators[2] = e->xmotion.state; /* FIXME: WTF?? */ - valuator_mask_set_range(&mask, 0, 3, valuators); - nevents = GetPointerEvents(events, p, type, detail, - POINTER_ABSOLUTE | POINTER_SCREEN, &mask); - for (i = 0; i < nevents; i++) - mieqEnqueue(p, (InternalEvent*)(events + i)->event); - return; - - case EnterNotify: - case LeaveNotify: - case KeymapNotify: - case MappingNotify: /* This is sent because we change the - * modifier map on the backend/console - * input device so that we have complete - * control of the input device LEDs. */ - return; - default: - if (type == ProximityIn || type == ProximityOut) { - if (dmxLocal->sendsCore) - return; /* Not a core event */ - break; - } - if (type >= LASTEvent) { - if (dmxTranslateAndEnqueueExtEvent(dmxLocal, e, block)) - dmxLogInput(dmxInput, "Unhandled extension event: %d\n", type); - } else { - dmxLogInput(dmxInput, "Unhandled event: %d (%s)\n", - type, dmxEventName(type)); - } - return; - } - -} - -/** A pointer to this routine is passed to low-level input drivers so - * that all special keychecking is unified to this file. This function - * returns 0 if no special keys have been pressed. If the user has - * requested termination of the DMX server, -1 is returned. If the user - * has requested a switch to a VT, then the (1-based) number of that VT - * is returned. */ -int dmxCheckSpecialKeys(DevicePtr pDev, KeySym keySym) -{ - GETDMXINPUTFROMPDEV; - int vt = 0; - unsigned short state = 0; - - if (dmxLocal->sendsCore) - state = XkbStateFieldFromRec(&dmxLocalCoreKeyboard->pDevice->key->xkbInfo->state); - else if (dmxLocal->pDevice->key) - state = XkbStateFieldFromRec(&dmxLocal->pDevice->key->xkbInfo->state); - - if (!dmxLocal->sendsCore) return 0; /* Only for core devices */ - - DMXDBG2("dmxCheckSpecialKeys: keySym=0x%04x state=0x%04x\n", keySym,state); - - if ((state & (ControlMask|Mod1Mask)) != (ControlMask|Mod1Mask)) return 0; - - switch (keySym) { - case XK_F1: - case XK_F2: - case XK_F3: - case XK_F4: - case XK_F5: - case XK_F6: - case XK_F7: - case XK_F8: - case XK_F9: - case XK_F10: - vt = keySym - XK_F1 + 1; - break; - - case XK_F11: - case XK_F12: - vt = keySym - XK_F11 + 11; - break; - - case XK_q: /* To avoid confusion */ - case XK_BackSpace: - case XK_Delete: - case XK_KP_Delete: - dmxLog(dmxInfo, "User request for termination\n"); - dispatchException |= DE_TERMINATE; - return -1; /* Terminate */ - } - - if (vt) { - dmxLog(dmxInfo, "Request to switch to VT %d\n", vt); - dmxInput->vt_switch_pending = vt; - return vt; - } - - return 0; /* Do nothing */ -} +/* + * Copyright 2002-2003 Red Hat Inc., Durham, North Carolina. + * + * All Rights Reserved. + * + * 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 on 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 + * NON-INFRINGEMENT. IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS + * 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: + * Rickard E. (Rik) Faith + * + */ + +/** \file + * Provide support and helper functions for enqueing events received by + * the low-level input drivers. */ + +#ifdef HAVE_DMX_CONFIG_H +#include +#endif + +#define DMX_EVENTS_DEBUG 0 + +#include "dmxinputinit.h" +#include "dmxevents.h" +#include "dmxcb.h" +#include "dmxcommon.h" +#include "dmxcursor.h" +#include "dmxmotion.h" +#include "dmxsigio.h" +#include "dmxmap.h" + +#include +#include "opaque.h" +#include "inputstr.h" +#include "inpututils.h" +#include "mipointer.h" +#include "mi.h" +#include "exglobals.h" + +#include "xkbsrv.h" +#include "XIstubs.h" + +static int dmxGlobalX, dmxGlobalY; /* Global cursor position */ +static int dmxGlobalInvalid; /* Flag indicating dmxCoreMotion + * should move the mouse anyway. */ + +#if DMX_EVENTS_DEBUG +#define DMXDBG0(f) dmxLog(dmxDebug,f) +#define DMXDBG1(f,a) dmxLog(dmxDebug,f,a) +#define DMXDBG2(f,a,b) dmxLog(dmxDebug,f,a,b) +#define DMXDBG3(f,a,b,c) dmxLog(dmxDebug,f,a,b,c) +#define DMXDBG4(f,a,b,c,d) dmxLog(dmxDebug,f,a,b,c,d) +#define DMXDBG5(f,a,b,c,d,e) dmxLog(dmxDebug,f,a,b,c,d,e) +#define DMXDBG6(f,a,b,c,d,e,g) dmxLog(dmxDebug,f,a,b,c,d,e,g) +#define DMXDBG7(f,a,b,c,d,e,g,h) dmxLog(dmxDebug,f,a,b,c,d,e,g,h) +#else +#define DMXDBG0(f) +#define DMXDBG1(f,a) +#define DMXDBG2(f,a,b) +#define DMXDBG3(f,a,b,c) +#define DMXDBG4(f,a,b,c,d) +#define DMXDBG5(f,a,b,c,d,e) +#define DMXDBG6(f,a,b,c,d,e,g) +#define DMXDBG7(f,a,b,c,d,e,g,h) +#endif + +static int dmxApplyFunctions(DMXInputInfo *dmxInput, DMXFunctionType f) +{ + int i; + int rc = 0; + + for (i = 0; i < dmxInput->numDevs; i+= dmxInput->devs[i]->binding) + if (dmxInput->devs[i]->functions) + rc += dmxInput->devs[i]->functions(dmxInput->devs[i]->private, f); + return rc; +} + +static int dmxCheckFunctionKeys(DMXLocalInputInfoPtr dmxLocal, + int type, + KeySym keySym) +{ + DMXInputInfo *dmxInput = &dmxInputs[dmxLocal->inputIdx]; + +#if 1 /* hack to detect ctrl-alt-q, etc */ + static int ctrl = 0, alt = 0; + /* keep track of ctrl/alt key status */ + if (type == KeyPress && keySym == 0xffe3) { + ctrl = 1; + } + else if (type == KeyRelease && keySym == 0xffe3) { + ctrl = 0; + } + else if (type == KeyPress && keySym == 0xffe9) { + alt = 1; + } + else if (type == KeyRelease && keySym == 0xffe9) { + alt = 0; + } + if (!ctrl || !alt) + return 0; +#else + unsigned short state = 0; + + if (dmxLocal->sendsCore) + state = dmxLocalCoreKeyboard->pDevice->key->state; + else if (dmxLocal->pDevice->key) + state = dmxLocal->pDevice->key->state; + + DMXDBG3("dmxCheckFunctionKeys: keySym=0x%04x %s state=0x%04x\n", + keySym, type == KeyPress ? "press" : "release", state); + + if ((state & (ControlMask|Mod1Mask)) != (ControlMask|Mod1Mask)) + return 0; +#endif + + switch (keySym) { + case XK_g: + if (type == KeyPress) + dmxApplyFunctions(dmxInput, DMX_FUNCTION_GRAB); + return 1; + case XK_f: + if (type == KeyPress) + dmxApplyFunctions(dmxInput, DMX_FUNCTION_FINE); + return 1; + case XK_q: + if (type == KeyPress && dmxLocal->sendsCore) + if (dmxApplyFunctions(dmxInput, DMX_FUNCTION_TERMINATE)) { + dmxLog(dmxInfo, "User request for termination\n"); + dispatchException |= DE_TERMINATE; + } + return 1; + } + + return 0; +} + + +DMXScreenInfo *dmxFindFirstScreen(int x, int y) +{ + int i; + + for (i = 0; i < dmxNumScreens; i++) { + DMXScreenInfo *dmxScreen = &dmxScreens[i]; + if (dmxOnScreen(x, y, dmxScreen)) + return dmxScreen; + } + return NULL; +} + + +/** + * Enqueue a motion event. + */ +static void enqueueMotion(DevicePtr pDev, int x, int y) +{ + GETDMXLOCALFROMPDEV; + DeviceIntPtr p = dmxLocal->pDevice; + int i, nevents, valuators[3]; + EventListPtr events; + int detail = 0; /* XXX should this be mask of pressed buttons? */ + ValuatorMask mask; + valuators[0] = x; + valuators[1] = y; + + valuator_mask_set_range(&mask, 0, 2, valuators); + GetEventList(&events); + nevents = GetPointerEvents(events, p, MotionNotify, detail, + POINTER_ABSOLUTE | POINTER_SCREEN, &mask); + for (i = 0; i < nevents; i++) + mieqEnqueue(p, (InternalEvent*)(events + i)->event); + return; +} + + +void +dmxCoreMotion(DevicePtr pDev, int x, int y, int delta, DMXBlockType block) +{ + DMXScreenInfo *dmxScreen; + DMXInputInfo *dmxInput; + ScreenPtr pScreen; + int localX; + int localY; + int i; + + if (!dmxGlobalInvalid && dmxGlobalX == x && dmxGlobalY == y) + return; + + DMXDBG5("dmxCoreMotion(%d,%d,%d) dmxGlobalX=%d dmxGlobalY=%d\n", + x, y, delta, dmxGlobalX, dmxGlobalY); + + dmxGlobalInvalid = 0; + dmxGlobalX = x; + dmxGlobalY = y; + + if (dmxGlobalX < 0) + dmxGlobalX = 0; + if (dmxGlobalY < 0) + dmxGlobalY = 0; + if (dmxGlobalX >= dmxGlobalWidth) + dmxGlobalX = dmxGlobalWidth + delta -1; + if (dmxGlobalY >= dmxGlobalHeight) + dmxGlobalY = dmxGlobalHeight + delta -1; + + if ((dmxScreen = dmxFindFirstScreen(dmxGlobalX, dmxGlobalY))) { + localX = dmxGlobalX - dmxScreen->rootXOrigin; + localY = dmxGlobalY - dmxScreen->rootYOrigin; + if ((pScreen = miPointerGetScreen(inputInfo.pointer)) + && pScreen->myNum == dmxScreen->index) { + /* Screen is old screen */ + if (block) + dmxSigioBlock(); + if (pDev) + enqueueMotion(pDev, localX, localY); + if (block) + dmxSigioUnblock(); + } else { + /* Screen is new */ + DMXDBG4(" New screen: old=%d new=%d localX=%d localY=%d\n", + pScreen->myNum, dmxScreen->index, localX, localY); + if (block) + dmxSigioBlock(); + mieqProcessInputEvents(); + miPointerSetScreen(inputInfo.pointer, dmxScreen->index, + localX, localY); + if (pDev) + enqueueMotion(pDev, localX, localY); + if (block) + dmxSigioUnblock(); + } +#if 00 + miPointerGetPosition(inputInfo.pointer, &localX, &localY); + + if ((pScreen = miPointerGetScreen(inputInfo.pointer))) { + dmxGlobalX = localX + dmxScreens[pScreen->myNum].rootXOrigin; + dmxGlobalY = localY + dmxScreens[pScreen->myNum].rootYOrigin; + ErrorF("Global is now %d, %d %d, %d\n", dmxGlobalX, dmxGlobalY, + localX, localY); + DMXDBG6(" Moved to dmxGlobalX=%d dmxGlobalY=%d" + " on screen index=%d/%d localX=%d localY=%d\n", + dmxGlobalX, dmxGlobalY, + dmxScreen ? dmxScreen->index : -1, pScreen->myNum, + localX, localY); + } +#endif + } + /* Send updates down to all core input + * drivers */ + for (i = 0, dmxInput = &dmxInputs[0]; i < dmxNumInputs; i++, dmxInput++) { + int j; + for (j = 0; j < dmxInput->numDevs; j += dmxInput->devs[j]->binding) + if (!dmxInput->detached + && dmxInput->devs[j]->sendsCore + && dmxInput->devs[j]->update_position) + dmxInput->devs[j]->update_position(dmxInput->devs[j]->private, + dmxGlobalX, dmxGlobalY); + } + if (!dmxScreen) ProcessInputEvents(); +} + + + +#define DMX_MAX_AXES 32 /* Max axes reported by this routine */ +static void dmxExtMotion(DMXLocalInputInfoPtr dmxLocal, + int *v, int firstAxis, int axesCount, + DMXMotionType type, DMXBlockType block) +{ + DeviceIntPtr pDevice = dmxLocal->pDevice; + xEvent xE[2 * DMX_MAX_AXES/6]; + deviceKeyButtonPointer *xev = (deviceKeyButtonPointer *)xE; + deviceValuator *xv = (deviceValuator *)xev+1; + int thisX = 0; + int thisY = 0; + int i; + int count; + EventListPtr events; + int nevents; + ValuatorMask mask; + + memset(xE, 0, sizeof(xE)); + + if (axesCount > DMX_MAX_AXES) axesCount = DMX_MAX_AXES; + + if ((valuator_get_mode(pDevice,0) == Relative) && axesCount == 2) { + /* The dmx console is a relative mode + * device that sometimes reports + * absolute motion. It only has two + * axes. */ + if (type == DMX_RELATIVE) { + thisX = -v[0]; + thisY = -v[1]; + dmxLocal->lastX += thisX; + dmxLocal->lastY += thisY; + if (dmxLocal->update_position) + dmxLocal->update_position(dmxLocal->private, + dmxLocal->lastX, dmxLocal->lastY); + } else { /* Convert to relative */ + if (dmxLocal->lastX || dmxLocal->lastY) { + thisX = v[0] - dmxLocal->lastX; + thisY = v[1] - dmxLocal->lastY; + } + dmxLocal->lastX = v[0]; + dmxLocal->lastY = v[1]; + } + v[0] = thisX; + v[1] = thisY; + } + + if (axesCount <= 6) { + /* Optimize for the common case when + * only 1 or 2 axes change. */ + xev->time = GetTimeInMillis(); + xev->type = DeviceMotionNotify; + xev->detail = 0; + xev->deviceid = pDevice->id | MORE_EVENTS; + + xv->type = DeviceValuator; + xv->deviceid = pDevice->id; + xv->num_valuators = axesCount; + xv->first_valuator = firstAxis; + switch (xv->num_valuators) { + case 6: xv->valuator5 = v[5]; + case 5: xv->valuator4 = v[4]; + case 4: xv->valuator3 = v[3]; + case 3: xv->valuator2 = v[2]; + case 2: xv->valuator1 = v[1]; + case 1: xv->valuator0 = v[0]; + } + count = 2; + } else { + for (i = 0, count = 0; i < axesCount; i += 6) { + xev->time = GetTimeInMillis(); + xev->type = DeviceMotionNotify; + xev->detail = 0; + xev->deviceid = pDevice->id | MORE_EVENTS; + xev += 2; + + xv->type = DeviceValuator; + xv->deviceid = pDevice->id; + xv->num_valuators = (i+6 >= axesCount ? axesCount - i : 6); + xv->first_valuator = firstAxis + i; + switch (xv->num_valuators) { + case 6: xv->valuator5 = v[i+5]; + case 5: xv->valuator4 = v[i+4]; + case 4: xv->valuator3 = v[i+3]; + case 3: xv->valuator2 = v[i+2]; + case 2: xv->valuator1 = v[i+1]; + case 1: xv->valuator0 = v[i+0]; + } + xv += 2; + count += 2; + } + } + + if (block) + dmxSigioBlock(); + valuator_mask_set_range(&mask, firstAxis, axesCount, v); + GetEventList(&events); + nevents = GetPointerEvents(events, pDevice, MotionNotify, 0, + POINTER_ABSOLUTE, &mask); + for (i = 0; i < nevents; i++) + mieqEnqueue(pDevice, (InternalEvent*)(events + i)->event); + + if (block) + dmxSigioUnblock(); +} + +static int dmxTranslateAndEnqueueExtEvent(DMXLocalInputInfoPtr dmxLocal, + XEvent *e, DMXBlockType block) +{ + int type; + int event = -1; + XDeviceKeyEvent *ke = (XDeviceKeyEvent *)e; + XDeviceMotionEvent *me = (XDeviceMotionEvent *)e; + DeviceIntPtr pDevice = dmxLocal->pDevice; + int valuators[MAX_VALUATORS]; + EventListPtr events; + int nevents, i; + ValuatorMask mask; + + if (!e) + return -1; /* No extended event passed, cannot handle */ + + if ((XID)dmxLocal->deviceId != ke->deviceid) { + /* Search for the correct dmxLocal, + * since backend and console events are + * picked up for the first device on + * that X server. */ + int i; + DMXInputInfo *dmxInput = &dmxInputs[dmxLocal->inputIdx]; + for (i = 0; i < dmxInput->numDevs; i++) { + dmxLocal = dmxInput->devs[i]; + if ((XID)dmxLocal->deviceId == ke->deviceid) + break; + } + } + + if ((XID)dmxLocal->deviceId != ke->deviceid + || (type = dmxMapLookup(dmxLocal, e->type)) < 0) + return -1; /* No mapping, so this event is unhandled */ + + switch (type) { + case XI_DeviceValuator: event = DeviceValuator; break; + case XI_DeviceKeyPress: event = KeyPress; break; + case XI_DeviceKeyRelease: event = KeyRelease; break; + case XI_DeviceButtonPress: event = ButtonPress; break; + case XI_DeviceButtonRelease: event = ButtonRelease; break; + case XI_DeviceMotionNotify: event = MotionNotify; break; + case XI_DeviceFocusIn: event = DeviceFocusIn; break; + case XI_DeviceFocusOut: event = DeviceFocusOut; break; + case XI_ProximityIn: event = ProximityIn; break; + case XI_ProximityOut: event = ProximityOut; break; + case XI_DeviceStateNotify: event = DeviceStateNotify; break; + case XI_DeviceMappingNotify: event = DeviceMappingNotify; break; + case XI_ChangeDeviceNotify: event = ChangeDeviceNotify; break; + case XI_DeviceKeystateNotify: event = DeviceStateNotify; break; + case XI_DeviceButtonstateNotify: event = DeviceStateNotify; break; + } + +#define EXTRACT_VALUATORS(ke, valuators) \ + valuators[0] = ke->axis_data[0]; \ + valuators[1] = ke->axis_data[1]; \ + valuators[2] = ke->axis_data[2]; \ + valuators[3] = ke->axis_data[3]; \ + valuators[4] = ke->axis_data[4]; \ + valuators[5] = ke->axis_data[5]; \ + + switch (type) { + case XI_DeviceKeyPress: + case XI_DeviceKeyRelease: + EXTRACT_VALUATORS(ke, valuators); + valuator_mask_set_range(&mask, ke->first_axis, ke->axes_count, valuators); + if (block) + dmxSigioBlock(); + GetEventList(&events); + nevents = GetKeyboardEvents(events, pDevice, event, + ke->keycode, &mask); + for (i = 0; i < nevents; i++) + mieqEnqueue(pDevice, (InternalEvent*)(events + i)->event); + + if (block) + dmxSigioUnblock(); + break; + case XI_DeviceButtonPress: + case XI_DeviceButtonRelease: + EXTRACT_VALUATORS(ke, valuators); + valuator_mask_set_range(&mask, ke->first_axis, ke->axes_count, valuators); + if (block) + dmxSigioBlock(); + GetEventList(&events); + nevents = GetPointerEvents(events, pDevice, event, ke->keycode, + POINTER_ABSOLUTE, &mask); + for (i = 0; i < nevents; i++) + mieqEnqueue(pDevice, (InternalEvent*)(events + i)->event); + + if (block) + dmxSigioUnblock(); + break; + case XI_ProximityIn: + case XI_ProximityOut: + EXTRACT_VALUATORS(ke, valuators); + valuator_mask_set_range(&mask, ke->first_axis, ke->axes_count, valuators); + if (block) + dmxSigioBlock(); + GetEventList(&events); + nevents = GetProximityEvents(events, pDevice, event, &mask); + for (i = 0; i < nevents; i++) + mieqEnqueue(pDevice, (InternalEvent*)(events + i)->event); + + if (block) + dmxSigioUnblock(); + break; + + break; + + case XI_DeviceMotionNotify: + dmxExtMotion(dmxLocal, me->axis_data, me->first_axis, me->axes_count, + DMX_ABSOLUTE, block); + break; + case XI_DeviceFocusIn: + case XI_DeviceFocusOut: + case XI_DeviceStateNotify: + case XI_DeviceMappingNotify: + case XI_ChangeDeviceNotify: + case XI_DeviceKeystateNotify: + case XI_DeviceButtonstateNotify: + /* These are ignored, since DMX will + * generate its own events of these + * types, as necessary. + + * Perhaps ChangeDeviceNotify should + * generate an error, because it is + * unexpected? */ + break; + case XI_DeviceValuator: + default: + dmxLog(dmxWarning, + "XInput extension event (remote=%d -> zero-based=%d)" + " not supported yet\n", e->type, type); + return -1; + } + return 0; +} + +static int dmxGetButtonMapping(DMXLocalInputInfoPtr dmxLocal, int button) +{ + ButtonClassPtr b = dmxLocal->pDevice->button; + + if (button > b->numButtons) { /* This shouldn't happen. */ + dmxLog(dmxWarning, "Button %d pressed, but only %d buttons?!?\n", + button, b->numButtons); + return button; + } + return b->map[button]; +} + +/** Return DMX's notion of the pointer position in the global coordinate + * space. */ +void dmxGetGlobalPosition(int *x, int *y) +{ + *x = dmxGlobalX; + *y = dmxGlobalY; +} + +/** Invalidate the global position for #dmxCoreMotion. */ +void dmxInvalidateGlobalPosition(void) +{ + dmxGlobalInvalid = 1; +} + +/** Enqueue a motion event for \a pDev. The \a v vector has length \a + * axesCount, and contains values for each of the axes, starting at \a + * firstAxes. + * + * The \a type of the motion may be \a DMX_RELATIVE, \a DMX_ABSOLUTE, or + * \a DMX_ABSOLUTE_CONFINED (in the latter case, the pointer will not be + * allowed to move outside the global boundaires). + * + * If \a block is set to \a DMX_BLOCK, then the SIGIO handler will be + * blocked around calls to \a enqueueMotion(). */ +void dmxMotion(DevicePtr pDev, int *v, int firstAxes, int axesCount, + DMXMotionType type, DMXBlockType block) +{ + GETDMXLOCALFROMPDEV; + + if (!dmxLocal->sendsCore) { + dmxExtMotion(dmxLocal, v, firstAxes, axesCount, type, block); + return; + } + if (axesCount == 2) { + switch (type) { + case DMX_RELATIVE: + dmxCoreMotion(pDev, dmxGlobalX - v[0], dmxGlobalY - v[1], 0, block); + break; + case DMX_ABSOLUTE: + dmxCoreMotion(pDev, v[0], v[1], 0, block); + break; + case DMX_ABSOLUTE_CONFINED: + dmxCoreMotion(pDev, v[0], v[1], -1, block); + break; + } + } +} + +static KeySym dmxKeyCodeToKeySym(DMXLocalInputInfoPtr dmxLocal, + KeyCode keyCode) +{ + KeySym keysym = NoSymbol; + int effectiveGroup; + XkbSrvInfoPtr xkbi; + + if (!dmxLocal || !dmxLocal->pDevice || !dmxLocal->pDevice->key) + goto out; + + xkbi = dmxLocal->pDevice->key->xkbInfo; + effectiveGroup = XkbGetEffectiveGroup(xkbi, &xkbi->state, keyCode); + + if (effectiveGroup == -1) + goto out; + + keysym = XkbKeySym(xkbi->desc, keyCode, effectiveGroup); + DMXDBG2("dmxKeyCodeToKeySym: Translated keyCode=%d to keySym=0x%04x\n", + keyCode, keysym); + +out: + return keysym; +} + +static KeyCode dmxKeySymToKeyCode(DMXLocalInputInfoPtr dmxLocal, KeySym keySym, + int tryFirst) +{ + /* FIXME: this is quite ineffective, converting to a core map first and + * then extracting the info from there. It'd be better to run the actual + * xkb map */ + XkbSrvInfoPtr xkbi = dmxLocal->pDevice->key->xkbInfo; + KeySymsPtr pKeySyms = XkbGetCoreMap(dmxLocal->pDevice); + int i; + + /* Optimize for similar maps */ + if (XkbKeycodeInRange(xkbi->desc, tryFirst) + && pKeySyms->map[(tryFirst - xkbi->desc->min_key_code) + * pKeySyms->mapWidth] == keySym) + return tryFirst; + + for (i = pKeySyms->minKeyCode; i <= pKeySyms->maxKeyCode; i++) { + if (pKeySyms->map[(i - pKeySyms->minKeyCode) + * pKeySyms->mapWidth] == keySym) { + DMXDBG3("dmxKeySymToKeyCode: Translated keySym=0x%04x to" + " keyCode=%d (reverses to core keySym=0x%04x)\n", + keySym, i, dmxKeyCodeToKeySym(dmxLocalCoreKeyboard,i)); + return i; + } + } + return 0; +} + +static int dmxFixup(DevicePtr pDev, int detail, KeySym keySym) +{ + GETDMXLOCALFROMPDEV; + int keyCode; + + if (!dmxLocal->pDevice->key) { + dmxLog(dmxWarning, "dmxFixup: not a keyboard device (%s)\n", + dmxLocal->pDevice->name); + return NoSymbol; + } + if (!keySym) + keySym = dmxKeyCodeToKeySym(dmxLocal, detail); + if (keySym == NoSymbol) + return detail; + keyCode = dmxKeySymToKeyCode(dmxLocalCoreKeyboard, keySym, detail); + + return keyCode ? keyCode : detail; +} + +/** Enqueue an event from the \a pDev device with the + * specified \a type and \a detail. If the event is a KeyPress or + * KeyRelease event, then the \a keySym is also specified. + * + * FIXME: make the code do what the comment says, or remove this comment. + * If \a block is set to \a DMX_BLOCK, then the SIGIO handler will be + * blocked around calls to dmxeqEnqueue(). */ + +void dmxEnqueue(DevicePtr pDev, int type, int detail, KeySym keySym, + XEvent *e, DMXBlockType block) +{ + GETDMXINPUTFROMPDEV; + xEvent xE; + DeviceIntPtr p = dmxLocal->pDevice; + int i, nevents, valuators[3]; + EventListPtr events; + ValuatorMask mask; + + DMXDBG2("dmxEnqueue: Enqueuing type=%d detail=0x%0x\n", type, detail); + + switch (type) { + case KeyPress: + case KeyRelease: + if (!keySym) + keySym = dmxKeyCodeToKeySym(dmxLocal, detail); + if (dmxCheckFunctionKeys(dmxLocal, type, keySym)) + return; + if (dmxLocal->sendsCore && dmxLocal != dmxLocalCoreKeyboard) + xE.u.u.detail = dmxFixup(pDev, detail, keySym); + + GetEventList(&events); + /*ErrorF("KEY %d sym %d\n", detail, (int) keySym);*/ + nevents = GetKeyboardEvents(events, p, type, detail, NULL); + for (i = 0; i < nevents; i++) + mieqEnqueue(p, (InternalEvent*)(events + i)->event); + return; + + case ButtonPress: + case ButtonRelease: + detail = dmxGetButtonMapping(dmxLocal, detail); + valuator_mask_zero(&mask); + GetEventList(&events); + nevents = GetPointerEvents(events, p, type, detail, + POINTER_ABSOLUTE | POINTER_SCREEN, &mask); + for (i = 0; i < nevents; i++) + mieqEnqueue(p, (InternalEvent*)(events + i)->event); + return; + + case MotionNotify: + GetEventList(&events); + valuators[0] = e->xmotion.x; + valuators[1] = e->xmotion.y; + valuators[2] = e->xmotion.state; /* FIXME: WTF?? */ + valuator_mask_set_range(&mask, 0, 3, valuators); + nevents = GetPointerEvents(events, p, type, detail, + POINTER_ABSOLUTE | POINTER_SCREEN, &mask); + for (i = 0; i < nevents; i++) + mieqEnqueue(p, (InternalEvent*)(events + i)->event); + return; + + case EnterNotify: + case LeaveNotify: + case KeymapNotify: + case MappingNotify: /* This is sent because we change the + * modifier map on the backend/console + * input device so that we have complete + * control of the input device LEDs. */ + return; + default: + if (type == ProximityIn || type == ProximityOut) { + if (dmxLocal->sendsCore) + return; /* Not a core event */ + break; + } + if (type >= LASTEvent) { + if (dmxTranslateAndEnqueueExtEvent(dmxLocal, e, block)) + dmxLogInput(dmxInput, "Unhandled extension event: %d\n", type); + } else { + dmxLogInput(dmxInput, "Unhandled event: %d (%s)\n", + type, dmxEventName(type)); + } + return; + } + +} + +/** A pointer to this routine is passed to low-level input drivers so + * that all special keychecking is unified to this file. This function + * returns 0 if no special keys have been pressed. If the user has + * requested termination of the DMX server, -1 is returned. If the user + * has requested a switch to a VT, then the (1-based) number of that VT + * is returned. */ +int dmxCheckSpecialKeys(DevicePtr pDev, KeySym keySym) +{ + GETDMXINPUTFROMPDEV; + int vt = 0; + unsigned short state = 0; + + if (dmxLocal->sendsCore) + state = XkbStateFieldFromRec(&dmxLocalCoreKeyboard->pDevice->key->xkbInfo->state); + else if (dmxLocal->pDevice->key) + state = XkbStateFieldFromRec(&dmxLocal->pDevice->key->xkbInfo->state); + + if (!dmxLocal->sendsCore) return 0; /* Only for core devices */ + + DMXDBG2("dmxCheckSpecialKeys: keySym=0x%04x state=0x%04x\n", keySym,state); + + if ((state & (ControlMask|Mod1Mask)) != (ControlMask|Mod1Mask)) return 0; + + switch (keySym) { + case XK_F1: + case XK_F2: + case XK_F3: + case XK_F4: + case XK_F5: + case XK_F6: + case XK_F7: + case XK_F8: + case XK_F9: + case XK_F10: + vt = keySym - XK_F1 + 1; + break; + + case XK_F11: + case XK_F12: + vt = keySym - XK_F11 + 11; + break; + + case XK_q: /* To avoid confusion */ + case XK_BackSpace: + case XK_Delete: + case XK_KP_Delete: + dmxLog(dmxInfo, "User request for termination\n"); + dispatchException |= DE_TERMINATE; + return -1; /* Terminate */ + } + + if (vt) { + dmxLog(dmxInfo, "Request to switch to VT %d\n", vt); + dmxInput->vt_switch_pending = vt; + return vt; + } + + return 0; /* Do nothing */ +} -- cgit v1.2.3