mirror of
https://gitlab.freedesktop.org/xorg/xserver.git
synced 2025-12-20 23:20:03 +01:00
2413 lines
55 KiB
C
2413 lines
55 KiB
C
/*
|
|
* Copyright © 2008 Novell, Inc.
|
|
*
|
|
* 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, and that the name of
|
|
* Novell, Inc. not be used in advertising or publicity pertaining to
|
|
* distribution of the software without specific, written prior permission.
|
|
* Novell, Inc. makes no representations about the suitability of this
|
|
* software for any purpose. It is provided "as is" without express or
|
|
* implied warranty.
|
|
*
|
|
* NOVELL, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
|
|
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
|
|
* NO EVENT SHALL NOVELL, INC. BE LIABLE FOR ANY SPECIAL, INDIRECT OR
|
|
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
|
|
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
|
|
* NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
|
|
* WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
*
|
|
* Author: David Reveman <davidr@novell.com>
|
|
*/
|
|
|
|
#ifdef HAVE_DMX_CONFIG_H
|
|
#include <dmx-config.h>
|
|
#endif
|
|
|
|
#include "dmx.h"
|
|
#include "dmxlog.h"
|
|
#include "dmxinput.h"
|
|
#include "dmxgrab.h"
|
|
#include "dmxdnd.h"
|
|
#include "dmxwindow.h"
|
|
#include "dmxcursor.h"
|
|
#include "dmxscrinit.h"
|
|
#include "dmxxlibio.h"
|
|
|
|
#include "inputstr.h"
|
|
#include "input.h"
|
|
#include "mi.h"
|
|
#include "exevents.h"
|
|
#include "XIstubs.h"
|
|
#include "xace.h"
|
|
|
|
#ifdef PANORAMIX
|
|
#include "panoramiX.h"
|
|
#include "panoramiXsrv.h"
|
|
#endif
|
|
|
|
#include <X11/keysym.h>
|
|
#include <xcb/xinput.h>
|
|
|
|
#define DMX_KEYBOARD_EVENT_MASK \
|
|
(KeyPressMask | KeyReleaseMask | KeymapStateMask | FocusChangeMask)
|
|
|
|
#define DMX_POINTER_EVENT_MASK \
|
|
(ButtonPressMask | ButtonReleaseMask | PointerMotionMask | \
|
|
LeaveWindowMask)
|
|
|
|
static EventListPtr dmxEvents = NULL;
|
|
|
|
static void
|
|
dmxUpdateKeycodeMap (DeviceIntPtr pDevice)
|
|
{
|
|
dmxDevicePrivPtr pDevPriv = DMX_GET_DEVICE_PRIV (pDevice);
|
|
DMXScreenInfo *dmxScreen = (DMXScreenInfo *) pDevPriv->dmxInput;
|
|
const xcb_setup_t *setup = xcb_get_setup (dmxScreen->connection);
|
|
KeySymsPtr dst = &pDevice->key->curKeySyms;
|
|
KeySymsPtr src = &pDevPriv->keySyms;
|
|
int width = src->mapWidth;
|
|
int i;
|
|
|
|
if (!pDevice->isMaster && pDevice->u.master)
|
|
{
|
|
if (IsKeyboardDevice (pDevice->u.master))
|
|
dst = &pDevice->u.master->key->curKeySyms;
|
|
}
|
|
|
|
if (dst->mapWidth < width)
|
|
width = dst->mapWidth;
|
|
|
|
memset (pDevPriv->keycode, 0,
|
|
sizeof (KeyCode) * (setup->max_keycode - setup->min_keycode));
|
|
|
|
for (i = src->minKeyCode - setup->min_keycode;
|
|
i < (src->maxKeyCode - src->minKeyCode);
|
|
i++)
|
|
{
|
|
int j;
|
|
|
|
for (j = 0; j < (dst->maxKeyCode - dst->minKeyCode); j++)
|
|
{
|
|
int k;
|
|
|
|
for (k = 0; k < i; k++)
|
|
if (pDevPriv->keycode[k] == (dst->minKeyCode + j))
|
|
break;
|
|
|
|
/* make sure the keycode is not already in use */
|
|
if (k < i)
|
|
continue;
|
|
|
|
for (k = 0; k < width; k++)
|
|
if (dst->map[j * dst->mapWidth + k] != NoSymbol &&
|
|
src->map[i * src->mapWidth + k] != NoSymbol)
|
|
if (dst->map[j * dst->mapWidth + k] !=
|
|
src->map[i * src->mapWidth + k])
|
|
break;
|
|
|
|
if (k == width)
|
|
break;
|
|
}
|
|
|
|
if (j < (dst->maxKeyCode - dst->minKeyCode))
|
|
pDevPriv->keycode[i] = dst->minKeyCode + j;
|
|
}
|
|
}
|
|
|
|
static void
|
|
dmxUpdateKeyboardMapping (DeviceIntPtr pDevice,
|
|
int first,
|
|
int count)
|
|
{
|
|
dmxDevicePrivPtr pDevPriv = DMX_GET_DEVICE_PRIV (pDevice);
|
|
DMXScreenInfo *dmxScreen = (DMXScreenInfo *) pDevPriv->dmxInput;
|
|
KeySymsRec keysyms;
|
|
xcb_keysym_t *syms;
|
|
int n;
|
|
|
|
if (pDevPriv->deviceId >= 0)
|
|
{
|
|
xcb_input_get_device_key_mapping_reply_t *reply;
|
|
|
|
reply = xcb_input_get_device_key_mapping_reply
|
|
(dmxScreen->connection,
|
|
xcb_input_get_device_key_mapping (dmxScreen->connection,
|
|
pDevPriv->deviceId,
|
|
first,
|
|
count),
|
|
NULL);
|
|
|
|
if (reply)
|
|
{
|
|
syms = xcb_input_get_device_key_mapping_keysyms (reply);
|
|
n = xcb_input_get_device_key_mapping_keysyms_length (reply);
|
|
|
|
keysyms.minKeyCode = first;
|
|
keysyms.maxKeyCode = first + n - 1;
|
|
keysyms.mapWidth = reply->keysyms_per_keycode;
|
|
keysyms.map = (KeySym *) syms;
|
|
|
|
SetKeySymsMap (&pDevPriv->keySyms, &keysyms);
|
|
|
|
free (reply);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
xcb_get_keyboard_mapping_reply_t *reply;
|
|
|
|
reply = xcb_get_keyboard_mapping_reply
|
|
(dmxScreen->connection,
|
|
xcb_get_keyboard_mapping (dmxScreen->connection,
|
|
first,
|
|
count),
|
|
NULL);
|
|
|
|
if (reply)
|
|
{
|
|
syms = xcb_get_keyboard_mapping_keysyms (reply);
|
|
n = xcb_get_keyboard_mapping_keysyms_length (reply);
|
|
|
|
keysyms.minKeyCode = first;
|
|
keysyms.maxKeyCode = first + n - 1;
|
|
keysyms.mapWidth = reply->keysyms_per_keycode;
|
|
keysyms.map = (KeySym *) syms;
|
|
|
|
SetKeySymsMap (&pDevPriv->keySyms, &keysyms);
|
|
|
|
free (reply);
|
|
}
|
|
}
|
|
|
|
dmxUpdateKeycodeMap (pDevice);
|
|
}
|
|
|
|
static DeviceIntPtr
|
|
dmxGetButtonDevice (DMXInputInfo *dmxInput,
|
|
XID deviceId)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < dmxInput->numDevs; i++)
|
|
{
|
|
dmxDevicePrivPtr pDevPriv = DMX_GET_DEVICE_PRIV (dmxInput->devs[i]);
|
|
|
|
if (!IsPointerDevice (dmxInput->devs[i]))
|
|
continue;
|
|
|
|
if (deviceId >= 0)
|
|
{
|
|
if (pDevPriv->deviceId != deviceId)
|
|
continue;
|
|
}
|
|
|
|
return dmxInput->devs[i];
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
static DeviceIntPtr
|
|
dmxGetPairedButtonDevice (DeviceIntPtr pDev)
|
|
{
|
|
dmxDevicePrivPtr pDevPriv = DMX_GET_DEVICE_PRIV (pDev);
|
|
|
|
return dmxGetButtonDevice (pDevPriv->dmxInput, pDevPriv->masterId);
|
|
}
|
|
|
|
static int
|
|
dmxButtonEvent (DeviceIntPtr pDevice,
|
|
int button,
|
|
int x,
|
|
int y,
|
|
int type)
|
|
{
|
|
int v[2] = { x, y };
|
|
int nEvents, i;
|
|
|
|
GetEventList (&dmxEvents);
|
|
nEvents = GetPointerEvents (dmxEvents,
|
|
pDevice,
|
|
type,
|
|
button,
|
|
POINTER_ABSOLUTE,
|
|
0, 2,
|
|
v);
|
|
|
|
for (i = 0; i < nEvents; i++)
|
|
mieqEnqueue (pDevice, dmxEvents[i].event);
|
|
|
|
if (button > 0 && button <= 255)
|
|
{
|
|
dmxDevicePrivPtr pDevPriv = DMX_GET_DEVICE_PRIV (pDevice);
|
|
|
|
switch (type) {
|
|
case XCB_BUTTON_PRESS:
|
|
pDevPriv->state[button >> 3] |= 1 << (button & 7);
|
|
break;
|
|
case XCB_BUTTON_RELEASE:
|
|
pDevPriv->state[button >> 3] &= ~(1 << (button & 7));
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
return nEvents;
|
|
}
|
|
|
|
static int
|
|
dmxKeyEvent (DeviceIntPtr pDevice,
|
|
int key,
|
|
int type)
|
|
{
|
|
dmxDevicePrivPtr pDevPriv = DMX_GET_DEVICE_PRIV (pDevice);
|
|
DMXScreenInfo *dmxScreen = (DMXScreenInfo *) pDevPriv->dmxInput;
|
|
const xcb_setup_t *setup = xcb_get_setup (dmxScreen->connection);
|
|
int nEvents = 0;
|
|
|
|
if (key >= setup->min_keycode && key <= setup->max_keycode)
|
|
{
|
|
int keycode = pDevPriv->keycode[key - setup->min_keycode];
|
|
|
|
if (keycode)
|
|
{
|
|
int i;
|
|
|
|
GetEventList (&dmxEvents);
|
|
nEvents = GetKeyboardEvents (dmxEvents, pDevice, type, keycode);
|
|
for (i = 0; i < nEvents; i++)
|
|
mieqEnqueue (pDevice, dmxEvents[i].event);
|
|
}
|
|
}
|
|
|
|
if (key > 0 && key <= 255)
|
|
{
|
|
switch (type) {
|
|
case XCB_KEY_PRESS:
|
|
pDevPriv->state[key >> 3] |= 1 << (key & 7);
|
|
break;
|
|
case XCB_KEY_RELEASE:
|
|
pDevPriv->state[key >> 3] &= ~(1 << (key & 7));
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
return nEvents;
|
|
}
|
|
|
|
static int
|
|
dmxUpdateButtonState (DeviceIntPtr pDevice,
|
|
const char *buttons)
|
|
{
|
|
dmxDevicePrivPtr pDevPriv = DMX_GET_DEVICE_PRIV (pDevice);
|
|
int i, j, nEvents = 0;
|
|
|
|
for (i = 0; i < 32; i++)
|
|
{
|
|
if (!(pDevPriv->state[i] ^ buttons[i]))
|
|
continue;
|
|
|
|
for (j = 0; j < 8; j++)
|
|
{
|
|
/* button is down, but shouldn't be */
|
|
if ((pDevPriv->state[i] & (1 << j)) && !(buttons[i] & (1 << j)))
|
|
nEvents += dmxButtonEvent (pDevice,
|
|
(i << 3) + j,
|
|
pDevice->last.valuators[0],
|
|
pDevice->last.valuators[1],
|
|
XCB_BUTTON_RELEASE);
|
|
|
|
/* button should be down, but isn't */
|
|
if (!(pDevPriv->state[i] & (1 << j)) && (buttons[i] & (1 << j)))
|
|
nEvents += dmxButtonEvent (pDevice,
|
|
(i << 3) + j,
|
|
pDevice->last.valuators[0],
|
|
pDevice->last.valuators[1],
|
|
XCB_BUTTON_PRESS);
|
|
}
|
|
}
|
|
|
|
return nEvents;
|
|
}
|
|
|
|
static int
|
|
dmxUpdateKeyState (DeviceIntPtr pDevice,
|
|
const char *keys)
|
|
{
|
|
dmxDevicePrivPtr pDevPriv = DMX_GET_DEVICE_PRIV (pDevice);
|
|
int i, j, nEvents = 0;
|
|
|
|
for (i = 0; i < 32; i++)
|
|
{
|
|
if (!(pDevPriv->state[i] ^ keys[i]))
|
|
continue;
|
|
|
|
for (j = 0; j < 8; j++)
|
|
{
|
|
/* key is down, but shouldn't be */
|
|
if ((pDevPriv->state[i] & (1 << j)) && !(keys[i] & (1 << j)))
|
|
nEvents += dmxKeyEvent (pDevice,
|
|
(i << 3) + j,
|
|
XCB_KEY_RELEASE);
|
|
|
|
/* key should be down, but isn't */
|
|
if (!(pDevPriv->state[i] & (1 << j)) && (keys[i] & (1 << j)))
|
|
nEvents += dmxKeyEvent (pDevice,
|
|
(i << 3) + j,
|
|
XCB_KEY_PRESS);
|
|
}
|
|
}
|
|
|
|
return nEvents;
|
|
}
|
|
|
|
static int
|
|
dmxChangeButtonState (DeviceIntPtr pDevice,
|
|
int button,
|
|
int how)
|
|
{
|
|
int nEvents = 0;
|
|
|
|
if (button > 0 && button <= 255)
|
|
{
|
|
dmxDevicePrivPtr pDevPriv = DMX_GET_DEVICE_PRIV (pDevice);
|
|
char buttons[32];
|
|
|
|
memcpy (buttons, pDevPriv->state, sizeof (buttons));
|
|
|
|
switch (how) {
|
|
case XCB_BUTTON_PRESS:
|
|
buttons[button >> 3] |= 1 << (button & 7);
|
|
break;
|
|
case XCB_BUTTON_RELEASE:
|
|
buttons[button >> 3] &= ~(1 << (button & 7));
|
|
default:
|
|
break;
|
|
}
|
|
|
|
dmxUpdateButtonState (pDevice, buttons);
|
|
}
|
|
|
|
return nEvents;
|
|
}
|
|
|
|
static int
|
|
dmxChangeKeyState (DeviceIntPtr pDevice,
|
|
int key,
|
|
int how)
|
|
{
|
|
int nEvents = 0;
|
|
|
|
if (key > 0 && key <= 255)
|
|
{
|
|
dmxDevicePrivPtr pDevPriv = DMX_GET_DEVICE_PRIV (pDevice);
|
|
char keys[32];
|
|
|
|
memcpy (keys, pDevPriv->state, sizeof (keys));
|
|
|
|
switch (how) {
|
|
case XCB_KEY_PRESS:
|
|
keys[key >> 3] |= 1 << (key & 7);
|
|
break;
|
|
case XCB_KEY_RELEASE:
|
|
keys[key >> 3] &= ~(1 << (key & 7));
|
|
default:
|
|
break;
|
|
}
|
|
|
|
dmxUpdateKeyState (pDevice, keys);
|
|
}
|
|
|
|
return nEvents;
|
|
}
|
|
|
|
static int
|
|
dmxUpdateSpritePosition (DeviceIntPtr pDevice,
|
|
int x,
|
|
int y)
|
|
{
|
|
ScreenPtr pScreen = miPointerGetScreen (pDevice);
|
|
|
|
if (x >= pScreen->width)
|
|
x = pScreen->width - 1;
|
|
else if (x < 0)
|
|
x = 0;
|
|
|
|
if (y >= pScreen->height)
|
|
y = pScreen->height - 1;
|
|
else if (y < 0)
|
|
y = 0;
|
|
|
|
if (x == pDevice->last.valuators[0] && y == pDevice->last.valuators[1])
|
|
return 0;
|
|
|
|
return dmxButtonEvent (pDevice, 0, x, y, XCB_MOTION_NOTIFY);
|
|
}
|
|
|
|
static Bool
|
|
dmxFakePointerGrab (DMXInputInfo *dmxInput)
|
|
{
|
|
DMXScreenInfo *dmxScreen = (DMXScreenInfo *) dmxInput;
|
|
WindowPtr pWin = WindowTable[dmxScreen->index];
|
|
GrabRec newGrab;
|
|
int i;
|
|
|
|
#ifdef PANORAMIX
|
|
if (!noPanoramiXExtension)
|
|
pWin = WindowTable[0];
|
|
#endif
|
|
|
|
memset (&newGrab, 0, sizeof (GrabRec));
|
|
|
|
newGrab.window = pWin;
|
|
newGrab.resource = 0;
|
|
newGrab.ownerEvents = xFalse;
|
|
newGrab.cursor = NULL;
|
|
newGrab.confineTo = NullWindow;
|
|
newGrab.eventMask = NoEventMask;
|
|
newGrab.genericMasks = NULL;
|
|
newGrab.next = NULL;
|
|
newGrab.keyboardMode = GrabModeAsync;
|
|
newGrab.pointerMode = GrabModeAsync;
|
|
|
|
for (i = 0; i < dmxInput->numDevs; i++)
|
|
{
|
|
DeviceIntPtr pDevice = dmxInput->devs[i];
|
|
|
|
if (!pDevice->isMaster && pDevice->u.master)
|
|
pDevice = pDevice->u.master;
|
|
|
|
if (!IsPointerDevice (pDevice))
|
|
continue;
|
|
|
|
newGrab.device = pDevice;
|
|
|
|
if (!dmxActivateFakeGrab (pDevice, &newGrab))
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static void
|
|
dmxReleaseFakePointerGrab (DMXInputInfo *dmxInput)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < dmxInput->numDevs; i++)
|
|
{
|
|
DeviceIntPtr pDevice = dmxInput->devs[i];
|
|
|
|
if (!pDevice->isMaster && pDevice->u.master)
|
|
pDevice = pDevice->u.master;
|
|
|
|
if (!IsPointerDevice (pDevice))
|
|
continue;
|
|
|
|
dmxDeactivateFakeGrab (pDevice);
|
|
}
|
|
}
|
|
|
|
static Bool
|
|
dmxFakeKeyboardGrab (DMXInputInfo *dmxInput)
|
|
{
|
|
DMXScreenInfo *dmxScreen = (DMXScreenInfo *) dmxInput;
|
|
WindowPtr pWin = WindowTable[dmxScreen->index];
|
|
GrabRec newGrab;
|
|
int i;
|
|
|
|
#ifdef PANORAMIX
|
|
if (!noPanoramiXExtension)
|
|
pWin = WindowTable[0];
|
|
#endif
|
|
|
|
memset (&newGrab, 0, sizeof (GrabRec));
|
|
|
|
newGrab.window = pWin;
|
|
newGrab.resource = 0;
|
|
newGrab.ownerEvents = xFalse;
|
|
newGrab.cursor = NULL;
|
|
newGrab.confineTo = NullWindow;
|
|
newGrab.eventMask = NoEventMask;
|
|
newGrab.genericMasks = NULL;
|
|
newGrab.next = NULL;
|
|
newGrab.keyboardMode = GrabModeAsync;
|
|
newGrab.pointerMode = GrabModeAsync;
|
|
|
|
for (i = 0; i < dmxInput->numDevs; i++)
|
|
{
|
|
DeviceIntPtr pDevice = dmxInput->devs[i];
|
|
|
|
if (!pDevice->isMaster && pDevice->u.master)
|
|
pDevice = pDevice->u.master;
|
|
|
|
if (!IsKeyboardDevice (pDevice))
|
|
continue;
|
|
|
|
newGrab.device = pDevice;
|
|
|
|
if (!dmxActivateFakeGrab (pDevice, &newGrab))
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static void
|
|
dmxReleaseFakeKeyboardGrab (DMXInputInfo *dmxInput)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < dmxInput->numDevs; i++)
|
|
{
|
|
DeviceIntPtr pDevice = dmxInput->devs[i];
|
|
|
|
if (!pDevice->isMaster && pDevice->u.master)
|
|
pDevice = pDevice->u.master;
|
|
|
|
if (!IsKeyboardDevice (pDevice))
|
|
continue;
|
|
|
|
dmxDeactivateFakeGrab (pDevice);
|
|
}
|
|
}
|
|
|
|
Bool
|
|
dmxFakeMotion (DMXInputInfo *dmxInput,
|
|
int x,
|
|
int y)
|
|
{
|
|
int i;
|
|
|
|
if (!dmxFakePointerGrab (dmxInput))
|
|
return FALSE;
|
|
|
|
for (i = 0; i < dmxInput->numDevs; i++)
|
|
{
|
|
DeviceIntPtr pDevice = dmxInput->devs[i];
|
|
|
|
if (!IsPointerDevice (pDevice))
|
|
continue;
|
|
|
|
dmxUpdateSpritePosition (pDevice, x, y);
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
void
|
|
dmxEndFakeMotion (DMXInputInfo *dmxInput)
|
|
{
|
|
dmxReleaseFakePointerGrab (dmxInput);
|
|
}
|
|
|
|
static void
|
|
dmxInputGrabDeviceReply (ScreenPtr pScreen,
|
|
unsigned int sequence,
|
|
xcb_generic_reply_t *reply,
|
|
xcb_generic_error_t *error,
|
|
void *data)
|
|
{
|
|
DMXInputInfo *dmxInput = &dmxScreens[pScreen->myNum].input;
|
|
int i;
|
|
|
|
for (i = 0; i < dmxInput->numDevs; i++)
|
|
{
|
|
DeviceIntPtr pDevice = dmxInput->devs[i];
|
|
dmxDevicePrivPtr pDevPriv = DMX_GET_DEVICE_PRIV (pDevice);
|
|
|
|
if ((*pDevPriv->ReplyCheck) (pDevice, sequence, reply))
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* not in xcb-xinput yet */
|
|
|
|
#define DMX_XCB_WARP_DEVICE_POINTER 41
|
|
|
|
typedef struct dmx_xcb_warp_device_pointer_request_t {
|
|
uint8_t major_opcode;
|
|
uint8_t minor_opcode;
|
|
uint16_t length;
|
|
xcb_window_t src_win;
|
|
xcb_window_t dst_win;
|
|
int16_t src_x;
|
|
int16_t src_y;
|
|
uint16_t src_width;
|
|
uint16_t src_height;
|
|
int16_t dst_x;
|
|
int16_t dst_y;
|
|
uint8_t deviceid;
|
|
uint8_t pad0;
|
|
uint16_t pad1;
|
|
} dmx_xcb_warp_device_pointer_request_t;
|
|
|
|
#define DMX_XCB_INPUT_EXTENDED_GRAB_DEVICE 45
|
|
|
|
typedef struct dmx_xcb_input_extended_grab_device_request_t {
|
|
uint8_t major_opcode;
|
|
uint8_t minor_opcode;
|
|
uint16_t length;
|
|
xcb_window_t grab_window;
|
|
xcb_timestamp_t time;
|
|
uint8_t deviceid;
|
|
uint8_t device_mode;
|
|
uint8_t owner_events;
|
|
uint8_t pad0;
|
|
xcb_window_t confine_to;
|
|
xcb_cursor_t cursor;
|
|
uint16_t event_count;
|
|
uint16_t generic_event_count;
|
|
} dmx_xcb_input_extended_grab_device_request_t;
|
|
|
|
#define DMX_XCB_INPUT_DEVICE_LEAVE_NOTIFY 17
|
|
|
|
typedef struct dmx_xcb_input_device_state_notify_event_t {
|
|
uint8_t response_type;
|
|
uint8_t detail;
|
|
uint16_t sequence;
|
|
xcb_timestamp_t time;
|
|
xcb_window_t root;
|
|
xcb_window_t event;
|
|
xcb_window_t child;
|
|
int16_t root_x;
|
|
int16_t root_y;
|
|
int16_t event_x;
|
|
int16_t event_y;
|
|
uint16_t state;
|
|
uint8_t mode;
|
|
uint8_t device_id;
|
|
} dmx_xcb_input_device_state_notify_event_t;
|
|
|
|
typedef xcb_input_focus_in_event_t dmx_xcb_input_focus_out_event_t;
|
|
|
|
static void
|
|
dmxDeviceGrabKeyboard (DeviceIntPtr pDevice,
|
|
WindowPtr pWindow)
|
|
{
|
|
dmxDevicePrivPtr pDevPriv = DMX_GET_DEVICE_PRIV (pDevice);
|
|
DMXScreenInfo *dmxScreen = (DMXScreenInfo *) pDevPriv->dmxInput;
|
|
Window window = (DMX_GET_WINDOW_PRIV (pWindow))->window;
|
|
|
|
if (pDevPriv->grabStatus != XCB_GRAB_STATUS_SUCCESS && !pDevPriv->active)
|
|
return;
|
|
|
|
if (pDevPriv->deviceId >= 0)
|
|
{
|
|
dmx_xcb_input_extended_grab_device_request_t grab = {
|
|
.grab_window = window,
|
|
.deviceid = pDevPriv->deviceId,
|
|
.device_mode = XCB_GRAB_MODE_ASYNC,
|
|
.owner_events = TRUE,
|
|
.event_count = 2
|
|
};
|
|
xcb_protocol_request_t request = {
|
|
2,
|
|
&xcb_input_id,
|
|
DMX_XCB_INPUT_EXTENDED_GRAB_DEVICE,
|
|
FALSE
|
|
};
|
|
XEventClass cls[3];
|
|
int type;
|
|
struct iovec vector[] = {
|
|
{ &grab, sizeof (grab) },
|
|
{ cls, sizeof (cls) }
|
|
};
|
|
|
|
DeviceKeyPress (pDevPriv->device, type, cls[1]);
|
|
DeviceKeyRelease (pDevPriv->device, type, cls[2]);
|
|
|
|
pDevPriv->grab.sequence =
|
|
xcb_send_request (dmxScreen->connection,
|
|
0,
|
|
vector,
|
|
&request);
|
|
}
|
|
else
|
|
{
|
|
pDevPriv->grab.sequence =
|
|
xcb_grab_keyboard (dmxScreen->connection,
|
|
TRUE,
|
|
window,
|
|
0,
|
|
XCB_GRAB_MODE_ASYNC,
|
|
XCB_GRAB_MODE_ASYNC).sequence;
|
|
}
|
|
|
|
dmxAddRequest (&dmxScreen->request,
|
|
dmxInputGrabDeviceReply,
|
|
pDevPriv->grab.sequence,
|
|
0);
|
|
}
|
|
|
|
static void
|
|
dmxDeviceUngrabKeyboard (DeviceIntPtr pDevice)
|
|
{
|
|
dmxDevicePrivPtr pDevPriv = DMX_GET_DEVICE_PRIV (pDevice);
|
|
DMXScreenInfo *dmxScreen = (DMXScreenInfo *) pDevPriv->dmxInput;
|
|
|
|
if (pDevPriv->deviceId >= 0)
|
|
{
|
|
xcb_input_ungrab_device (dmxScreen->connection,
|
|
0,
|
|
pDevPriv->deviceId);
|
|
}
|
|
else
|
|
{
|
|
xcb_ungrab_keyboard (dmxScreen->connection, 0);
|
|
}
|
|
|
|
pDevPriv->grabStatus = !XCB_GRAB_STATUS_SUCCESS;
|
|
}
|
|
|
|
static Bool
|
|
dmxDeviceKeyboardReplyCheck (DeviceIntPtr pDevice,
|
|
unsigned int request,
|
|
xcb_generic_reply_t *reply)
|
|
{
|
|
dmxDevicePrivPtr pDevPriv = DMX_GET_DEVICE_PRIV (pDevice);
|
|
|
|
if (request == pDevPriv->grab.sequence)
|
|
{
|
|
if (reply)
|
|
{
|
|
if (pDevPriv->deviceId >= 0)
|
|
{
|
|
xcb_input_grab_device_reply_t *xgrab =
|
|
(xcb_input_grab_device_reply_t *) reply;
|
|
|
|
pDevPriv->grabStatus = xgrab->status;
|
|
}
|
|
else
|
|
{
|
|
xcb_grab_keyboard_reply_t *xgrab =
|
|
(xcb_grab_keyboard_reply_t *) reply;
|
|
|
|
pDevPriv->grabStatus = xgrab->status;
|
|
}
|
|
}
|
|
|
|
pDevPriv->grab.sequence = 0;
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
static void
|
|
dmxDeviceGrabPointer (DeviceIntPtr pDevice,
|
|
WindowPtr pWindow,
|
|
WindowPtr pConfineTo,
|
|
CursorPtr pCursor)
|
|
{
|
|
dmxDevicePrivPtr pDevPriv = DMX_GET_DEVICE_PRIV (pDevice);
|
|
DMXScreenInfo *dmxScreen = (DMXScreenInfo *) pDevPriv->dmxInput;
|
|
ScreenPtr pScreen = screenInfo.screens[dmxScreen->index];
|
|
Window window = (DMX_GET_WINDOW_PRIV (pWindow))->window;
|
|
Window confineTo = None;
|
|
Cursor cursor = None;
|
|
|
|
if (pDevPriv->grabStatus != XCB_GRAB_STATUS_SUCCESS && !pDevPriv->active)
|
|
return;
|
|
|
|
if (pConfineTo)
|
|
confineTo = (DMX_GET_WINDOW_PRIV (pConfineTo))->window;
|
|
|
|
if (pCursor)
|
|
cursor = (DMX_GET_CURSOR_PRIV (pCursor, pScreen))->cursor;
|
|
|
|
if (pDevPriv->deviceId >= 0)
|
|
{
|
|
dmx_xcb_input_extended_grab_device_request_t grab = {
|
|
.grab_window = window,
|
|
.deviceid = pDevPriv->deviceId,
|
|
.device_mode = XCB_GRAB_MODE_ASYNC,
|
|
.owner_events = TRUE,
|
|
.confine_to = confineTo,
|
|
.cursor = cursor,
|
|
.event_count = 3
|
|
};
|
|
xcb_protocol_request_t request = {
|
|
2,
|
|
&xcb_input_id,
|
|
DMX_XCB_INPUT_EXTENDED_GRAB_DEVICE,
|
|
FALSE
|
|
};
|
|
XEventClass cls[3];
|
|
int type;
|
|
struct iovec vector[] = {
|
|
{ &grab, sizeof (grab) },
|
|
{ cls, sizeof (cls) }
|
|
};
|
|
|
|
DeviceMotionNotify (pDevPriv->device, type, cls[0]);
|
|
DeviceButtonPress (pDevPriv->device, type, cls[1]);
|
|
DeviceButtonRelease (pDevPriv->device, type, cls[2]);
|
|
|
|
pDevPriv->grab.sequence =
|
|
xcb_send_request (dmxScreen->connection,
|
|
0,
|
|
vector,
|
|
&request);
|
|
}
|
|
else
|
|
{
|
|
pDevPriv->grab.sequence =
|
|
xcb_grab_pointer (dmxScreen->connection,
|
|
TRUE,
|
|
window,
|
|
DMX_POINTER_EVENT_MASK,
|
|
XCB_GRAB_MODE_ASYNC,
|
|
XCB_GRAB_MODE_ASYNC,
|
|
confineTo,
|
|
cursor,
|
|
0).sequence;
|
|
}
|
|
|
|
dmxAddRequest (&dmxScreen->request,
|
|
dmxInputGrabDeviceReply,
|
|
pDevPriv->grab.sequence,
|
|
0);
|
|
}
|
|
|
|
static void
|
|
dmxDeviceUngrabPointer (DeviceIntPtr pDevice)
|
|
{
|
|
dmxDevicePrivPtr pDevPriv = DMX_GET_DEVICE_PRIV (pDevice);
|
|
DMXScreenInfo *dmxScreen = (DMXScreenInfo *) pDevPriv->dmxInput;
|
|
|
|
if (pDevPriv->deviceId >= 0)
|
|
{
|
|
xcb_input_ungrab_device (dmxScreen->connection,
|
|
0,
|
|
pDevPriv->deviceId);
|
|
}
|
|
else
|
|
{
|
|
xcb_ungrab_pointer (dmxScreen->connection, 0);
|
|
}
|
|
|
|
pDevPriv->grabStatus = !XCB_GRAB_STATUS_SUCCESS;
|
|
}
|
|
|
|
static Bool
|
|
dmxDevicePointerReplyCheck (DeviceIntPtr pDevice,
|
|
unsigned int request,
|
|
xcb_generic_reply_t *reply)
|
|
{
|
|
dmxDevicePrivPtr pDevPriv = DMX_GET_DEVICE_PRIV (pDevice);
|
|
|
|
if (request == pDevPriv->grab.sequence)
|
|
{
|
|
if (reply)
|
|
{
|
|
if (pDevPriv->deviceId >= 0)
|
|
{
|
|
xcb_input_grab_device_reply_t *xgrab =
|
|
(xcb_input_grab_device_reply_t *) reply;
|
|
|
|
pDevPriv->grabStatus = xgrab->status;
|
|
}
|
|
else
|
|
{
|
|
xcb_grab_pointer_reply_t *xgrab =
|
|
(xcb_grab_pointer_reply_t *) reply;
|
|
|
|
pDevPriv->grabStatus = xgrab->status;
|
|
}
|
|
}
|
|
|
|
pDevPriv->grab.sequence = 0;
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
static void
|
|
dmxDevicePointerActivate (DeviceIntPtr pDevice)
|
|
{
|
|
dmxDevicePrivPtr pDevPriv = DMX_GET_DEVICE_PRIV (pDevice);
|
|
DMXScreenInfo *dmxScreen = (DMXScreenInfo *) pDevPriv->dmxInput;
|
|
|
|
if (pDevPriv->active)
|
|
return;
|
|
|
|
pDevPriv->active = TRUE;
|
|
|
|
dmxReleaseFakePointerGrab (pDevPriv->dmxInput);
|
|
|
|
if (pDevPriv->grabStatus != XCB_GRAB_STATUS_SUCCESS &&
|
|
pDevPriv->grab.sequence == 0)
|
|
{
|
|
DeviceIntPtr pMaster = pDevice;
|
|
|
|
if (!pDevice->isMaster && pDevice->u.master)
|
|
pMaster = pDevice->u.master;
|
|
|
|
if (pMaster->deviceGrab.grab)
|
|
{
|
|
GrabPtr pGrab = pMaster->deviceGrab.grab;
|
|
WindowPtr pWin, pConfineTo = NULL;
|
|
|
|
#ifdef PANORAMIX
|
|
if (!noPanoramiXExtension)
|
|
{
|
|
PanoramiXRes *win, *confineToWin = NULL;
|
|
int i = dmxScreen->index;
|
|
|
|
if (!(win = (PanoramiXRes *)
|
|
SecurityLookupIDByType(
|
|
serverClient, pGrab->window->drawable.id, XRT_WINDOW,
|
|
DixGetAttrAccess)))
|
|
return;
|
|
if (pGrab->confineTo)
|
|
if (!(confineToWin = (PanoramiXRes *)
|
|
SecurityLookupIDByType(
|
|
serverClient, pGrab->confineTo->drawable.id,
|
|
XRT_WINDOW, DixGetAttrAccess)))
|
|
return;
|
|
|
|
if (dixLookupWindow (&pWin,
|
|
win->info[i].id,
|
|
serverClient,
|
|
DixGetAttrAccess) != Success)
|
|
return;
|
|
|
|
if (confineToWin)
|
|
if (dixLookupWindow (&pConfineTo,
|
|
confineToWin->info[i].id,
|
|
serverClient,
|
|
DixGetAttrAccess) != Success)
|
|
return;
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
pWin = pGrab->window;
|
|
pConfineTo = pGrab->confineTo;
|
|
}
|
|
|
|
dmxDeviceGrabPointer (pDevice,
|
|
pWin,
|
|
pConfineTo,
|
|
pGrab->cursor);
|
|
}
|
|
}
|
|
}
|
|
|
|
static void
|
|
dmxDevicePointerDeactivate (DeviceIntPtr pDevice)
|
|
{
|
|
dmxDevicePrivPtr pDevPriv = DMX_GET_DEVICE_PRIV (pDevice);
|
|
|
|
if (!pDevPriv->active)
|
|
return;
|
|
|
|
pDevPriv->active = FALSE;
|
|
|
|
dmxFakePointerGrab (pDevPriv->dmxInput);
|
|
}
|
|
|
|
static void
|
|
dmxUpdateSpriteFromEvent (DeviceIntPtr pDevice,
|
|
xcb_window_t event,
|
|
int x,
|
|
int y,
|
|
int rootX,
|
|
int rootY)
|
|
{
|
|
dmxDevicePrivPtr pDevPriv = DMX_GET_DEVICE_PRIV (pDevice);
|
|
DMXScreenInfo *dmxScreen = (DMXScreenInfo *) pDevPriv->dmxInput;
|
|
ScreenPtr pScreen = screenInfo.screens[dmxScreen->index];
|
|
|
|
if (event != dmxScreen->rootWin)
|
|
{
|
|
DeviceIntPtr pMaster = pDevice;
|
|
WindowPtr pWin;
|
|
|
|
if (!pDevice->isMaster && pDevice->u.master)
|
|
pMaster = pDevice->u.master;
|
|
|
|
if (!pMaster->deviceGrab.grab)
|
|
{
|
|
dmxDeviceUngrabPointer (pDevice);
|
|
dmxLog (dmxWarning, "non-root window event without active grab\n");
|
|
return;
|
|
}
|
|
|
|
pWin = WindowTable[dmxScreen->index];
|
|
for (;;)
|
|
{
|
|
dmxWinPrivPtr pWinPriv = DMX_GET_WINDOW_PRIV (pWin);
|
|
|
|
if (pWinPriv->window == event)
|
|
break;
|
|
|
|
if (pWin->firstChild)
|
|
{
|
|
pWin = pWin->firstChild;
|
|
continue;
|
|
}
|
|
|
|
while (!pWin->nextSib && (pWin != WindowTable[dmxScreen->index]))
|
|
pWin = pWin->parent;
|
|
|
|
if (pWin == WindowTable[dmxScreen->index])
|
|
break;
|
|
|
|
pWin = pWin->nextSib;
|
|
}
|
|
|
|
if (!pWin)
|
|
return;
|
|
|
|
x += pWin->drawable.x;
|
|
y += pWin->drawable.y;
|
|
}
|
|
|
|
dmxEndFakeMotion (&dmxScreen->input);
|
|
dmxBEDnDSpriteUpdate (pScreen, event, rootX, rootY);
|
|
dmxUpdateSpritePosition (pDevice, x, y);
|
|
dmxDevicePointerActivate (pDevice);
|
|
}
|
|
|
|
static Bool
|
|
dmxDevicePointerEventCheck (DeviceIntPtr pDevice,
|
|
xcb_generic_event_t *event)
|
|
{
|
|
DeviceIntPtr pButtonDev = pDevice;
|
|
dmxDevicePrivPtr pDevPriv = DMX_GET_DEVICE_PRIV (pButtonDev);
|
|
DMXInputInfo *dmxInput = pDevPriv->dmxInput;
|
|
int reltype, type = event->response_type & 0x7f;
|
|
int id = pDevPriv->deviceId;
|
|
|
|
switch (type) {
|
|
case XCB_MOTION_NOTIFY: {
|
|
xcb_motion_notify_event_t *xmotion =
|
|
(xcb_motion_notify_event_t *) event;
|
|
|
|
dmxUpdateSpriteFromEvent (pButtonDev,
|
|
xmotion->event,
|
|
xmotion->event_x,
|
|
xmotion->event_y,
|
|
xmotion->root_x,
|
|
xmotion->root_y);
|
|
} break;
|
|
case XCB_BUTTON_PRESS:
|
|
case XCB_BUTTON_RELEASE: {
|
|
xcb_button_press_event_t *xbutton =
|
|
(xcb_button_press_event_t *) event;
|
|
|
|
dmxUpdateSpriteFromEvent (pButtonDev,
|
|
xbutton->event,
|
|
xbutton->event_x,
|
|
xbutton->event_y,
|
|
xbutton->root_x,
|
|
xbutton->root_y);
|
|
dmxChangeButtonState (pButtonDev,
|
|
xbutton->detail,
|
|
type);
|
|
} break;
|
|
case XCB_LEAVE_NOTIFY: {
|
|
xcb_leave_notify_event_t *xcrossing =
|
|
(xcb_leave_notify_event_t *) event;
|
|
|
|
if (xcrossing->detail != XCB_NOTIFY_DETAIL_INFERIOR)
|
|
dmxDevicePointerDeactivate (pButtonDev);
|
|
} break;
|
|
default:
|
|
if (id < 0)
|
|
return FALSE;
|
|
|
|
reltype = type - dmxInput->eventBase;
|
|
|
|
switch (reltype) {
|
|
case XCB_INPUT_DEVICE_VALUATOR: {
|
|
xcb_input_device_valuator_event_t *xvaluator =
|
|
(xcb_input_device_valuator_event_t *) event;
|
|
|
|
if (id != (xvaluator->device_id & DEVICE_BITS))
|
|
return FALSE;
|
|
|
|
/* eat valuator events */
|
|
} break;
|
|
case XCB_INPUT_DEVICE_MOTION_NOTIFY: {
|
|
xcb_input_device_motion_notify_event_t *xmotion =
|
|
(xcb_input_device_motion_notify_event_t *) event;
|
|
|
|
if (id != (xmotion->device_id & DEVICE_BITS))
|
|
return FALSE;
|
|
|
|
dmxUpdateSpriteFromEvent (pButtonDev,
|
|
xmotion->event,
|
|
xmotion->event_x,
|
|
xmotion->event_y,
|
|
xmotion->root_x,
|
|
xmotion->root_y);
|
|
} break;
|
|
case XCB_INPUT_DEVICE_BUTTON_PRESS:
|
|
case XCB_INPUT_DEVICE_BUTTON_RELEASE: {
|
|
xcb_input_device_button_press_event_t *xbutton =
|
|
(xcb_input_device_button_press_event_t *) event;
|
|
|
|
if (id != (xbutton->device_id & DEVICE_BITS))
|
|
return FALSE;
|
|
|
|
dmxUpdateSpriteFromEvent (pButtonDev,
|
|
xbutton->event,
|
|
xbutton->event_x,
|
|
xbutton->event_y,
|
|
xbutton->root_x,
|
|
xbutton->root_y);
|
|
dmxChangeButtonState (pButtonDev,
|
|
xbutton->detail, XCB_BUTTON_RELEASE +
|
|
(reltype -
|
|
XCB_INPUT_DEVICE_BUTTON_RELEASE));
|
|
} break;
|
|
case XCB_INPUT_DEVICE_STATE_NOTIFY: {
|
|
xcb_input_device_state_notify_event_t *xstate =
|
|
(xcb_input_device_state_notify_event_t *) event;
|
|
|
|
if (id != (xstate->device_id & DEVICE_BITS))
|
|
return FALSE;
|
|
|
|
if (!(xstate->classes_reported & (1 << ButtonClass)))
|
|
return FALSE;
|
|
|
|
memset (pDevPriv->keysbuttons, 0, 32);
|
|
|
|
if (xstate->response_type & MORE_EVENTS)
|
|
{
|
|
memcpy (pDevPriv->keysbuttons, xstate->buttons, 4);
|
|
}
|
|
else
|
|
{
|
|
memcpy (pDevPriv->keysbuttons, xstate->buttons, 4);
|
|
dmxUpdateButtonState (pButtonDev,
|
|
pDevPriv->keysbuttons);
|
|
}
|
|
} break;
|
|
case XCB_INPUT_DEVICE_BUTTON_STATE_NOTIFY: {
|
|
xcb_input_device_button_state_notify_event_t *xstate =
|
|
(xcb_input_device_button_state_notify_event_t *) event;
|
|
|
|
if (id != (xstate->device_id & DEVICE_BITS))
|
|
return FALSE;
|
|
|
|
memcpy (&pDevPriv->keysbuttons[4], xstate->buttons, 28);
|
|
dmxUpdateButtonState (pButtonDev, pDevPriv->keysbuttons);
|
|
} break;
|
|
case DMX_XCB_INPUT_DEVICE_LEAVE_NOTIFY: {
|
|
dmx_xcb_input_device_state_notify_event_t *xcrossing =
|
|
(dmx_xcb_input_device_state_notify_event_t *) event;
|
|
|
|
if (id != (xcrossing->device_id & DEVICE_BITS))
|
|
return FALSE;
|
|
|
|
if (xcrossing->detail != XCB_NOTIFY_DETAIL_INFERIOR)
|
|
dmxDevicePointerDeactivate (pButtonDev);
|
|
} break;
|
|
default:
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static void
|
|
dmxDeviceKeyboardActivate (DeviceIntPtr pDevice)
|
|
{
|
|
dmxDevicePrivPtr pDevPriv = DMX_GET_DEVICE_PRIV (pDevice);
|
|
DMXScreenInfo *dmxScreen = (DMXScreenInfo *) pDevPriv->dmxInput;
|
|
|
|
if (pDevPriv->active)
|
|
return;
|
|
|
|
dmxReleaseFakeKeyboardGrab (pDevPriv->dmxInput);
|
|
|
|
pDevPriv->active = TRUE;
|
|
|
|
if (pDevPriv->grabStatus != XCB_GRAB_STATUS_SUCCESS &&
|
|
pDevPriv->grab.sequence == 0)
|
|
{
|
|
DeviceIntPtr pMaster = pDevice;
|
|
|
|
if (!pDevice->isMaster && pDevice->u.master)
|
|
pMaster = pDevice->u.master;
|
|
|
|
if (pMaster->deviceGrab.grab)
|
|
{
|
|
GrabPtr pGrab = pMaster->deviceGrab.grab;
|
|
WindowPtr pWin;
|
|
|
|
#ifdef PANORAMIX
|
|
if (!noPanoramiXExtension)
|
|
{
|
|
PanoramiXRes *win;
|
|
int i = dmxScreen->index;
|
|
|
|
if (!(win = (PanoramiXRes *)
|
|
SecurityLookupIDByType(
|
|
serverClient, pGrab->window->drawable.id, XRT_WINDOW,
|
|
DixGetAttrAccess)))
|
|
return;
|
|
|
|
if (dixLookupWindow (&pWin,
|
|
win->info[i].id,
|
|
serverClient,
|
|
DixGetAttrAccess) != Success)
|
|
return;
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
pWin = pGrab->window;
|
|
}
|
|
|
|
dmxDeviceGrabKeyboard (pDevice, pWin);
|
|
}
|
|
}
|
|
}
|
|
|
|
static void
|
|
dmxDeviceKeyboardDeactivate (DeviceIntPtr pDevice)
|
|
{
|
|
dmxDevicePrivPtr pDevPriv = DMX_GET_DEVICE_PRIV (pDevice);
|
|
|
|
if (!pDevPriv->active)
|
|
return;
|
|
|
|
pDevPriv->active = FALSE;
|
|
|
|
dmxFakeKeyboardGrab (pDevPriv->dmxInput);
|
|
}
|
|
|
|
static void
|
|
dmxUpdateKeyStateFromEvent (DeviceIntPtr pDevice,
|
|
xcb_window_t event,
|
|
int detail,
|
|
int x,
|
|
int y,
|
|
int rootX,
|
|
int rootY,
|
|
int type)
|
|
{
|
|
dmxDevicePrivPtr pDevPriv = DMX_GET_DEVICE_PRIV (pDevice);
|
|
DMXScreenInfo *dmxScreen = (DMXScreenInfo *) pDevPriv->dmxInput;
|
|
ScreenPtr pScreen = screenInfo.screens[dmxScreen->index];
|
|
DeviceIntPtr pButtonDev;
|
|
|
|
if (event != dmxScreen->rootWin)
|
|
{
|
|
DeviceIntPtr pMaster = pDevice;
|
|
WindowPtr pWin;
|
|
|
|
if (!pDevice->isMaster && pDevice->u.master)
|
|
pMaster = pDevice->u.master;
|
|
|
|
if (!pMaster->deviceGrab.grab)
|
|
{
|
|
dmxDeviceUngrabKeyboard (pDevice);
|
|
dmxLog (dmxWarning, "non-root window event without active grab\n");
|
|
return;
|
|
}
|
|
|
|
pWin = WindowTable[dmxScreen->index];
|
|
for (;;)
|
|
{
|
|
dmxWinPrivPtr pWinPriv = DMX_GET_WINDOW_PRIV (pWin);
|
|
|
|
if (pWinPriv->window == event)
|
|
break;
|
|
|
|
if (pWin->firstChild)
|
|
{
|
|
pWin = pWin->firstChild;
|
|
continue;
|
|
}
|
|
|
|
while (!pWin->nextSib && (pWin != WindowTable[dmxScreen->index]))
|
|
pWin = pWin->parent;
|
|
|
|
if (pWin == WindowTable[dmxScreen->index])
|
|
break;
|
|
|
|
pWin = pWin->nextSib;
|
|
}
|
|
|
|
if (!pWin)
|
|
return;
|
|
|
|
x += pWin->drawable.x;
|
|
y += pWin->drawable.y;
|
|
}
|
|
|
|
pButtonDev = dmxGetPairedButtonDevice (pDevice);
|
|
if (pButtonDev && DMX_GET_DEVICE_PRIV (pButtonDev)->active)
|
|
{
|
|
dmxEndFakeMotion (&dmxScreen->input);
|
|
dmxBEDnDSpriteUpdate (pScreen, event, rootX, rootY);
|
|
dmxUpdateSpritePosition (pButtonDev, x, y);
|
|
}
|
|
|
|
dmxChangeKeyState (pDevice, detail, type);
|
|
}
|
|
|
|
static Bool
|
|
dmxDeviceKeyboardEventCheck (DeviceIntPtr pDevice,
|
|
xcb_generic_event_t *event)
|
|
{
|
|
DeviceIntPtr pKeyDev = pDevice;
|
|
dmxDevicePrivPtr pDevPriv = DMX_GET_DEVICE_PRIV (pKeyDev);
|
|
DMXInputInfo *dmxInput = pDevPriv->dmxInput;
|
|
int reltype, type = event->response_type & 0x7f;
|
|
int id = pDevPriv->deviceId;
|
|
|
|
switch (type) {
|
|
case XCB_KEY_PRESS:
|
|
case XCB_KEY_RELEASE: {
|
|
xcb_key_press_event_t *xkey = (xcb_key_press_event_t *) event;
|
|
|
|
dmxUpdateKeyStateFromEvent (pKeyDev,
|
|
xkey->event,
|
|
xkey->detail,
|
|
xkey->event_x,
|
|
xkey->event_y,
|
|
xkey->root_x,
|
|
xkey->root_y,
|
|
type);
|
|
} break;
|
|
case XCB_KEYMAP_NOTIFY: {
|
|
xcb_keymap_notify_event_t *xkeymap =
|
|
(xcb_keymap_notify_event_t *) event;
|
|
char state[32];
|
|
|
|
state[0] = 0;
|
|
memcpy (&state[1], xkeymap->keys, 31);
|
|
|
|
dmxUpdateKeyState (pKeyDev, state);
|
|
} break;
|
|
case XCB_MAPPING_NOTIFY: {
|
|
xcb_mapping_notify_event_t *xmapping =
|
|
(xcb_mapping_notify_event_t *) event;
|
|
|
|
if (xmapping->request == XCB_MAPPING_KEYBOARD)
|
|
dmxUpdateKeyboardMapping (pKeyDev,
|
|
xmapping->first_keycode,
|
|
xmapping->count);
|
|
} break;
|
|
case XCB_FOCUS_IN: {
|
|
xcb_focus_in_event_t *xfocus = (xcb_focus_in_event_t *) event;
|
|
|
|
if (xfocus->detail != XCB_NOTIFY_DETAIL_INFERIOR)
|
|
dmxDeviceKeyboardActivate (pKeyDev);
|
|
} break;
|
|
case XCB_FOCUS_OUT: {
|
|
xcb_focus_out_event_t *xfocus = (xcb_focus_out_event_t *) event;
|
|
|
|
if (xfocus->detail != XCB_NOTIFY_DETAIL_INFERIOR)
|
|
dmxDeviceKeyboardDeactivate (pKeyDev);
|
|
} break;
|
|
default:
|
|
if (id < 0)
|
|
return FALSE;
|
|
|
|
reltype = type - dmxInput->eventBase;
|
|
|
|
switch (reltype) {
|
|
case XCB_INPUT_DEVICE_VALUATOR: {
|
|
xcb_input_device_valuator_event_t *xvaluator =
|
|
(xcb_input_device_valuator_event_t *) event;
|
|
|
|
if (id != (xvaluator->device_id & DEVICE_BITS))
|
|
return FALSE;
|
|
|
|
/* eat valuator events */
|
|
} break;
|
|
case XCB_INPUT_DEVICE_KEY_PRESS:
|
|
case XCB_INPUT_DEVICE_KEY_RELEASE: {
|
|
xcb_input_device_key_press_event_t *xkey =
|
|
(xcb_input_device_key_press_event_t *) event;
|
|
|
|
if (id != (xkey->device_id & DEVICE_BITS))
|
|
return FALSE;
|
|
|
|
dmxUpdateKeyStateFromEvent (pKeyDev,
|
|
xkey->event,
|
|
xkey->detail,
|
|
xkey->event_x,
|
|
xkey->event_y,
|
|
xkey->root_x,
|
|
xkey->root_y,
|
|
XCB_KEY_PRESS +
|
|
(reltype - XCB_INPUT_DEVICE_KEY_PRESS));
|
|
} break;
|
|
case XCB_INPUT_DEVICE_STATE_NOTIFY: {
|
|
xcb_input_device_state_notify_event_t *xstate =
|
|
(xcb_input_device_state_notify_event_t *) event;
|
|
|
|
if (id != (xstate->device_id & DEVICE_BITS))
|
|
return FALSE;
|
|
|
|
if (!(xstate->classes_reported & (1 << KeyClass)))
|
|
return FALSE;
|
|
|
|
memset (pDevPriv->keysbuttons, 0, 32);
|
|
|
|
if (xstate->response_type & MORE_EVENTS)
|
|
{
|
|
memcpy (pDevPriv->keysbuttons, xstate->keys, 4);
|
|
}
|
|
else
|
|
{
|
|
memcpy (pDevPriv->keysbuttons, xstate->keys, 4);
|
|
dmxUpdateKeyState (pKeyDev, pDevPriv->keysbuttons);
|
|
}
|
|
} break;
|
|
case XCB_INPUT_DEVICE_KEY_STATE_NOTIFY: {
|
|
xcb_input_device_key_state_notify_event_t *xstate =
|
|
(xcb_input_device_key_state_notify_event_t *) event;
|
|
|
|
if (id != (xstate->device_id & DEVICE_BITS))
|
|
return FALSE;
|
|
|
|
memcpy (&pDevPriv->keysbuttons[4], xstate->keys, 28);
|
|
dmxUpdateKeyState (pKeyDev, pDevPriv->keysbuttons);
|
|
} break;
|
|
case XCB_INPUT_DEVICE_MAPPING_NOTIFY: {
|
|
xcb_input_device_mapping_notify_event_t *xmapping =
|
|
(xcb_input_device_mapping_notify_event_t *) event;
|
|
|
|
if (id != (xmapping->device_id & DEVICE_BITS))
|
|
return FALSE;
|
|
|
|
if (xmapping->request == XCB_MAPPING_KEYBOARD)
|
|
dmxUpdateKeyboardMapping (pKeyDev,
|
|
xmapping->first_keycode,
|
|
xmapping->count);
|
|
} break;
|
|
case XCB_INPUT_FOCUS_IN: {
|
|
xcb_input_focus_in_event_t *xfocus =
|
|
(xcb_input_focus_in_event_t *) event;
|
|
|
|
if (id != (xfocus->device_id & DEVICE_BITS))
|
|
return FALSE;
|
|
|
|
if (xfocus->detail != XCB_NOTIFY_DETAIL_INFERIOR)
|
|
dmxDeviceKeyboardActivate (pKeyDev);
|
|
} break;
|
|
case XCB_INPUT_FOCUS_OUT: {
|
|
dmx_xcb_input_focus_out_event_t *xfocus =
|
|
(dmx_xcb_input_focus_out_event_t *) event;
|
|
|
|
if (id != (xfocus->device_id & DEVICE_BITS))
|
|
return FALSE;
|
|
|
|
if (xfocus->detail != XCB_NOTIFY_DETAIL_INFERIOR)
|
|
dmxDeviceKeyboardDeactivate (pKeyDev);
|
|
} break;
|
|
default:
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
Bool
|
|
dmxInputEventCheck (DMXInputInfo *dmxInput,
|
|
xcb_generic_event_t *event)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < dmxInput->numDevs; i++)
|
|
{
|
|
DeviceIntPtr pDevice = dmxInput->devs[i];
|
|
dmxDevicePrivPtr pDevPriv = DMX_GET_DEVICE_PRIV (pDevice);
|
|
|
|
if ((*pDevPriv->EventCheck) (pDevice, event))
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
void
|
|
dmxInputGrabKeyboard (DMXInputInfo *dmxInput,
|
|
DeviceIntPtr pDevice,
|
|
WindowPtr pWindow)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < dmxInput->numDevs; i++)
|
|
{
|
|
DeviceIntPtr pExtDevice = dmxInput->devs[i];
|
|
|
|
if (pExtDevice->u.master != pDevice)
|
|
continue;
|
|
|
|
if (!IsKeyboardDevice (pExtDevice))
|
|
continue;
|
|
|
|
dmxDeviceGrabKeyboard (pExtDevice, pWindow);
|
|
}
|
|
}
|
|
|
|
void
|
|
dmxInputUngrabKeyboard (DMXInputInfo *dmxInput,
|
|
DeviceIntPtr pDevice,
|
|
WindowPtr pWindow)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < dmxInput->numDevs; i++)
|
|
{
|
|
DeviceIntPtr pExtDevice = dmxInput->devs[i];
|
|
|
|
if (pExtDevice->u.master != pDevice)
|
|
continue;
|
|
|
|
if (!IsKeyboardDevice (pExtDevice))
|
|
continue;
|
|
|
|
dmxDeviceUngrabKeyboard (pExtDevice);
|
|
}
|
|
}
|
|
|
|
void
|
|
dmxInputGrabPointer (DMXInputInfo *dmxInput,
|
|
DeviceIntPtr pDevice,
|
|
WindowPtr pWindow,
|
|
WindowPtr pConfineTo,
|
|
CursorPtr pCursor)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < dmxInput->numDevs; i++)
|
|
{
|
|
DeviceIntPtr pExtDevice = dmxInput->devs[i];
|
|
|
|
if (pExtDevice->u.master != pDevice)
|
|
continue;
|
|
|
|
if (!IsPointerDevice (pExtDevice))
|
|
continue;
|
|
|
|
dmxDeviceGrabPointer (pExtDevice,
|
|
pWindow,
|
|
pConfineTo,
|
|
pCursor);
|
|
}
|
|
}
|
|
|
|
void
|
|
dmxInputUngrabPointer (DMXInputInfo *dmxInput,
|
|
DeviceIntPtr pDevice,
|
|
WindowPtr pWindow)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < dmxInput->numDevs; i++)
|
|
{
|
|
DeviceIntPtr pExtDevice = dmxInput->devs[i];
|
|
|
|
if (pExtDevice->u.master != pDevice)
|
|
continue;
|
|
|
|
if (!IsPointerDevice (pExtDevice))
|
|
continue;
|
|
|
|
dmxDeviceUngrabPointer (pExtDevice);
|
|
}
|
|
}
|
|
|
|
void
|
|
dmxInputWarpPointer (DMXInputInfo *dmxInput,
|
|
DeviceIntPtr pDevice,
|
|
int x,
|
|
int y)
|
|
{
|
|
DMXScreenInfo *dmxScreen = (DMXScreenInfo *) dmxInput;
|
|
int i;
|
|
|
|
for (i = 0; i < dmxInput->numDevs; i++)
|
|
{
|
|
DeviceIntPtr pExtDevice = dmxInput->devs[i];
|
|
dmxDevicePrivPtr pDevPriv = DMX_GET_DEVICE_PRIV (pExtDevice);
|
|
|
|
if (pExtDevice->u.master != pDevice)
|
|
continue;
|
|
|
|
if (!IsPointerDevice (pExtDevice))
|
|
continue;
|
|
|
|
if (!pDevPriv->active)
|
|
continue;
|
|
|
|
if (pDevPriv->deviceId >= 0)
|
|
{
|
|
dmx_xcb_warp_device_pointer_request_t warp = {
|
|
.src_win = dmxScreen->rootWin,
|
|
.dst_win = dmxScreen->rootWin,
|
|
.dst_x = x,
|
|
.dst_y = y,
|
|
.deviceid = pDevPriv->deviceId
|
|
};
|
|
xcb_protocol_request_t request = {
|
|
1,
|
|
&xcb_input_id,
|
|
DMX_XCB_WARP_DEVICE_POINTER,
|
|
FALSE
|
|
};
|
|
struct iovec vector[] = {
|
|
{ &warp, sizeof (warp) }
|
|
};
|
|
|
|
xcb_send_request (dmxScreen->connection,
|
|
0,
|
|
vector,
|
|
&request);
|
|
}
|
|
else
|
|
{
|
|
xcb_warp_pointer (dmxScreen->connection,
|
|
dmxScreen->rootWin, dmxScreen->rootWin,
|
|
0, 0,
|
|
0, 0,
|
|
x, y);
|
|
}
|
|
}
|
|
}
|
|
|
|
static void
|
|
dmxKeyboardBell (int volume,
|
|
DeviceIntPtr pDevice,
|
|
pointer arg,
|
|
int something)
|
|
{
|
|
dmxDevicePrivPtr pDevPriv = DMX_GET_DEVICE_PRIV (pDevice);
|
|
DMXScreenInfo *dmxScreen = (DMXScreenInfo *) pDevPriv->dmxInput;
|
|
|
|
if (dmxScreen)
|
|
xcb_bell (dmxScreen->connection, volume);
|
|
}
|
|
|
|
static int
|
|
dmxKeyboardOn (DeviceIntPtr pDevice)
|
|
{
|
|
dmxDevicePrivPtr pDevPriv = DMX_GET_DEVICE_PRIV (pDevice);
|
|
DMXScreenInfo *dmxScreen = (DMXScreenInfo *) pDevPriv->dmxInput;
|
|
const xcb_setup_t *setup = xcb_get_setup (dmxScreen->connection);
|
|
int nKeycode = setup->max_keycode - setup->min_keycode;
|
|
|
|
pDevPriv->keycode = xalloc (nKeycode * sizeof (KeyCode));
|
|
if (!pDevPriv->keycode)
|
|
return -1;
|
|
|
|
pDevPriv->keySyms.map = (KeySym *) NULL;
|
|
pDevPriv->keySyms.mapWidth = 0;
|
|
pDevPriv->keySyms.minKeyCode = setup->min_keycode;
|
|
pDevPriv->keySyms.maxKeyCode = setup->max_keycode;
|
|
|
|
dmxUpdateKeyboardMapping (pDevice, setup->min_keycode, nKeycode);
|
|
|
|
if (pDevPriv->deviceId >= 0)
|
|
{
|
|
XEventClass cls[5];
|
|
int type;
|
|
|
|
pDevPriv->device = XOpenDevice (dmxScreen->beDisplay,
|
|
pDevPriv->deviceId);
|
|
if (!pDevPriv->device)
|
|
{
|
|
dmxLog (dmxWarning, "Cannot open %s device (id=%d) on %s\n",
|
|
pDevice->name, pDevPriv->deviceId, dmxScreen->name);
|
|
xfree (pDevPriv->keycode);
|
|
return -1;
|
|
}
|
|
|
|
DeviceKeyPress (pDevPriv->device, type, cls[0]);
|
|
DeviceKeyRelease (pDevPriv->device, type, cls[1]);
|
|
DeviceStateNotify (pDevPriv->device, type, cls[2]);
|
|
DeviceFocusIn (pDevPriv->device, type, cls[3]);
|
|
DeviceFocusOut (pDevPriv->device, type, cls[4]);
|
|
|
|
XLIB_PROLOGUE (dmxScreen);
|
|
XSelectExtensionEvent (dmxScreen->beDisplay, dmxScreen->rootWin,
|
|
cls, 5);
|
|
XLIB_EPILOGUE (dmxScreen);
|
|
}
|
|
else
|
|
{
|
|
dmxScreen->rootEventMask |= DMX_KEYBOARD_EVENT_MASK;
|
|
|
|
XLIB_PROLOGUE (dmxScreen);
|
|
XSelectInput (dmxScreen->beDisplay, dmxScreen->rootWin,
|
|
dmxScreen->rootEventMask);
|
|
XLIB_EPILOGUE (dmxScreen);
|
|
}
|
|
|
|
return Success;
|
|
}
|
|
|
|
static void
|
|
dmxKeyboardOff (DeviceIntPtr pDevice)
|
|
{
|
|
dmxDevicePrivPtr pDevPriv = DMX_GET_DEVICE_PRIV (pDevice);
|
|
DMXScreenInfo *dmxScreen = (DMXScreenInfo *) pDevPriv->dmxInput;
|
|
|
|
if (pDevPriv->deviceId >= 0)
|
|
{
|
|
if (pDevPriv->device)
|
|
{
|
|
XLIB_PROLOGUE (dmxScreen);
|
|
XCloseDevice (dmxScreen->beDisplay, pDevPriv->device);
|
|
XLIB_EPILOGUE (dmxScreen);
|
|
|
|
pDevPriv->device = NULL;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
dmxScreen->rootEventMask &= ~DMX_KEYBOARD_EVENT_MASK;
|
|
|
|
if (dmxScreen->scrnWin)
|
|
{
|
|
XLIB_PROLOGUE (dmxScreen);
|
|
XSelectInput (dmxScreen->beDisplay, dmxScreen->rootWin,
|
|
dmxScreen->rootEventMask);
|
|
XLIB_EPILOGUE (dmxScreen);
|
|
}
|
|
}
|
|
|
|
if (pDevPriv->keySyms.map)
|
|
xfree (pDevPriv->keySyms.map);
|
|
|
|
xfree (pDevPriv->keycode);
|
|
}
|
|
|
|
static int
|
|
dmxKeyboardProc (DeviceIntPtr pDevice,
|
|
int what)
|
|
{
|
|
DevicePtr pDev = (DevicePtr) pDevice;
|
|
CARD8 modMap[MAP_LENGTH];
|
|
KeySymsRec keySyms;
|
|
|
|
#ifdef XKB
|
|
XkbComponentNamesRec names;
|
|
#endif
|
|
|
|
switch (what) {
|
|
case DEVICE_INIT:
|
|
keySyms.minKeyCode = 8;
|
|
keySyms.maxKeyCode = 255;
|
|
keySyms.mapWidth = 4;
|
|
keySyms.map = (KeySym *) Xcalloc (sizeof (KeySym),
|
|
(keySyms.maxKeyCode -
|
|
keySyms.minKeyCode + 1) *
|
|
keySyms.mapWidth);
|
|
if (!keySyms.map)
|
|
{
|
|
ErrorF ("[dmx] Couldn't allocate keymap\n");
|
|
return BadAlloc;
|
|
}
|
|
|
|
bzero ((char *) modMap, MAP_LENGTH);
|
|
|
|
#ifdef XKB
|
|
if (!noXkbExtension)
|
|
{
|
|
bzero (&names, sizeof (names));
|
|
|
|
XkbSetRulesDflts ("base", "pc105", "us", NULL, NULL);
|
|
XkbInitKeyboardDeviceStruct (pDevice,
|
|
&names,
|
|
&keySyms,
|
|
modMap,
|
|
dmxKeyboardBell,
|
|
(KbdCtrlProcPtr) NoopDDA);
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
/* FIXME Our keymap here isn't exactly useful. */
|
|
InitKeyboardDeviceStruct (pDev,
|
|
&keySyms,
|
|
modMap,
|
|
dmxKeyboardBell,
|
|
(KbdCtrlProcPtr) NoopDDA);
|
|
}
|
|
|
|
xfree (keySyms.map);
|
|
break;
|
|
case DEVICE_ON:
|
|
pDev->on = 1;
|
|
dmxKeyboardOn (pDevice);
|
|
break;
|
|
case DEVICE_OFF:
|
|
pDev->on = 0;
|
|
dmxKeyboardOff (pDevice);
|
|
break;
|
|
case DEVICE_CLOSE:
|
|
if (pDev->on)
|
|
{
|
|
pDev->on = 0;
|
|
dmxKeyboardOff (pDevice);
|
|
}
|
|
break;
|
|
}
|
|
|
|
return Success;
|
|
}
|
|
|
|
static int
|
|
dmxPointerOn (DeviceIntPtr pDevice)
|
|
{
|
|
dmxDevicePrivPtr pDevPriv = DMX_GET_DEVICE_PRIV (pDevice);
|
|
DMXInputInfo *dmxInput = pDevPriv->dmxInput;
|
|
DMXScreenInfo *dmxScreen = (DMXScreenInfo *) dmxInput;
|
|
|
|
if (pDevPriv->deviceId >= 0)
|
|
{
|
|
XEventClass cls[6];
|
|
int type;
|
|
|
|
pDevPriv->device = XOpenDevice (dmxScreen->beDisplay,
|
|
pDevPriv->deviceId);
|
|
if (!pDevPriv->device)
|
|
{
|
|
dmxLog (dmxWarning, "Cannot open %s device (id=%d) on %s\n",
|
|
pDevice->name, pDevPriv->deviceId, dmxScreen->name);
|
|
return -1;
|
|
}
|
|
|
|
DeviceMotionNotify (pDevPriv->device, type, cls[0]);
|
|
DeviceButtonPress (pDevPriv->device, type, cls[1]);
|
|
DeviceButtonRelease (pDevPriv->device, type, cls[2]);
|
|
DeviceButtonPressGrab (pDevPriv->device, type, cls[3]);
|
|
DeviceStateNotify (pDevPriv->device, type, cls[4]);
|
|
|
|
cls[5] = (pDevPriv->device->device_id << 8) |
|
|
(dmxInput->eventBase + DMX_XCB_INPUT_DEVICE_LEAVE_NOTIFY);
|
|
|
|
XLIB_PROLOGUE (dmxScreen);
|
|
XSelectExtensionEvent (dmxScreen->beDisplay, dmxScreen->rootWin,
|
|
cls, 6);
|
|
XLIB_EPILOGUE (dmxScreen);
|
|
}
|
|
else
|
|
{
|
|
dmxScreen->rootEventMask |= DMX_POINTER_EVENT_MASK;
|
|
|
|
XLIB_PROLOGUE (dmxScreen);
|
|
XSelectInput (dmxScreen->beDisplay, dmxScreen->rootWin,
|
|
dmxScreen->rootEventMask);
|
|
XLIB_EPILOGUE (dmxScreen);
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
static void
|
|
dmxPointerOff (DeviceIntPtr pDevice)
|
|
{
|
|
dmxDevicePrivPtr pDevPriv = DMX_GET_DEVICE_PRIV (pDevice);
|
|
DMXScreenInfo *dmxScreen = (DMXScreenInfo *) pDevPriv->dmxInput;
|
|
|
|
if (pDevPriv->deviceId >= 0)
|
|
{
|
|
if (pDevPriv->device)
|
|
{
|
|
XLIB_PROLOGUE (dmxScreen);
|
|
XCloseDevice (dmxScreen->beDisplay, pDevPriv->device);
|
|
XLIB_EPILOGUE (dmxScreen);
|
|
|
|
pDevPriv->device = NULL;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
dmxScreen->rootEventMask &= ~DMX_POINTER_EVENT_MASK;
|
|
|
|
if (dmxScreen->scrnWin)
|
|
{
|
|
XLIB_PROLOGUE (dmxScreen);
|
|
XSelectInput (dmxScreen->beDisplay, dmxScreen->rootWin,
|
|
dmxScreen->rootEventMask);
|
|
XLIB_EPILOGUE (dmxScreen);
|
|
}
|
|
}
|
|
}
|
|
|
|
static int
|
|
dmxPointerProc (DeviceIntPtr pDevice,
|
|
int what)
|
|
{
|
|
DevicePtr pDev = (DevicePtr) pDevice;
|
|
BYTE map[33];
|
|
int i;
|
|
|
|
switch (what) {
|
|
case DEVICE_INIT:
|
|
for (i = 1; i <= 32; i++)
|
|
map[i] = i;
|
|
|
|
InitPointerDeviceStruct (pDev,
|
|
map, 32,
|
|
(PtrCtrlProcPtr) NoopDDA,
|
|
GetMotionHistorySize (), 2);
|
|
|
|
pDevice->valuator->axisVal[0] = screenInfo.screens[0]->width / 2;
|
|
pDevice->last.valuators[0] = pDevice->valuator->axisVal[0];
|
|
pDevice->valuator->axisVal[1] = screenInfo.screens[0]->height / 2;
|
|
pDevice->last.valuators[1] = pDevice->valuator->axisVal[1];
|
|
break;
|
|
case DEVICE_ON:
|
|
pDev->on = 1;
|
|
dmxPointerOn (pDevice);
|
|
break;
|
|
case DEVICE_OFF:
|
|
pDev->on = 0;
|
|
dmxPointerOff (pDevice);
|
|
break;
|
|
case DEVICE_CLOSE:
|
|
if (pDev->on)
|
|
{
|
|
pDev->on = 0;
|
|
dmxPointerOff (pDevice);
|
|
}
|
|
break;
|
|
}
|
|
|
|
return Success;
|
|
}
|
|
|
|
static char *
|
|
dmxMakeUniqueDeviceName (DMXInputInfo *dmxInput,
|
|
const char *deviceName)
|
|
{
|
|
DMXScreenInfo *dmxScreen = (DMXScreenInfo *) dmxInput;
|
|
char *name;
|
|
int i, n = 2;
|
|
|
|
#define LEN 32
|
|
|
|
name = xalloc (strlen (dmxScreen->name) + strlen (deviceName) + LEN);
|
|
if (!name)
|
|
return NULL;
|
|
|
|
sprintf (name, "%s's %s", dmxScreen->name, deviceName);
|
|
|
|
do {
|
|
for (i = 0; i < dmxInput->numDevs; i++)
|
|
{
|
|
if (strcmp (dmxInput->devs[i]->name, name) == 0)
|
|
{
|
|
sprintf (name, "%s's %s%d", dmxScreen->name, deviceName, n++);
|
|
break;
|
|
}
|
|
}
|
|
} while (i < dmxInput->numDevs);
|
|
|
|
return name;
|
|
}
|
|
|
|
static DeviceIntPtr
|
|
dmxAddInputDevice (DMXInputInfo *dmxInput,
|
|
DeviceProc deviceProc,
|
|
const char *deviceName,
|
|
int deviceId,
|
|
int masterId,
|
|
Bool (*EventCheck) (DeviceIntPtr,
|
|
xcb_generic_event_t *),
|
|
Bool (*ReplyCheck) (DeviceIntPtr,
|
|
unsigned int,
|
|
xcb_generic_reply_t *))
|
|
{
|
|
DeviceIntPtr pDevice, *devs;
|
|
char *name;
|
|
|
|
devs = xrealloc (dmxInput->devs, sizeof (DeviceIntPtr) *
|
|
(dmxInput->numDevs + 1));
|
|
if (!devs)
|
|
return NULL;
|
|
|
|
dmxInput->devs = devs;
|
|
|
|
name = dmxMakeUniqueDeviceName (dmxInput, deviceName);
|
|
if (!name)
|
|
return NULL;
|
|
|
|
pDevice = AddInputDevice (serverClient, deviceProc, TRUE);
|
|
if (pDevice)
|
|
{
|
|
dmxDevicePrivPtr pDevPriv = DMX_GET_DEVICE_PRIV (pDevice);
|
|
|
|
pDevice->name = name;
|
|
|
|
pDevPriv->dmxInput = dmxInput;
|
|
pDevPriv->deviceId = deviceId;
|
|
pDevPriv->masterId = masterId;
|
|
pDevPriv->device = NULL;
|
|
pDevPriv->fakeGrab = xFalse;
|
|
pDevPriv->grabStatus = !XCB_GRAB_STATUS_SUCCESS;
|
|
pDevPriv->active = xFalse;
|
|
pDevPriv->EventCheck = EventCheck;
|
|
pDevPriv->ReplyCheck = ReplyCheck;
|
|
|
|
memset (pDevPriv->state, 0, sizeof (pDevPriv->state));
|
|
memset (pDevPriv->keysbuttons, 0, sizeof (pDevPriv->keysbuttons));
|
|
|
|
pDevPriv->grab.sequence = 0;
|
|
|
|
RegisterOtherDevice (pDevice);
|
|
|
|
dmxInput->devs[dmxInput->numDevs] = pDevice;
|
|
dmxInput->numDevs++;
|
|
|
|
dmxLogInput (dmxInput, "Added extension device called %s\n", name);
|
|
}
|
|
else
|
|
{
|
|
xfree (name);
|
|
}
|
|
|
|
return pDevice;
|
|
}
|
|
|
|
static XID
|
|
dmxGetMasterDevice (XDeviceInfo *device)
|
|
{
|
|
XAttachInfoPtr ai;
|
|
int i;
|
|
|
|
for (i = 0, ai = (XAttachInfoPtr) device->inputclassinfo;
|
|
i < device->num_classes;
|
|
ai = (XAttachInfoPtr) ((char *) ai + ai->length), i++)
|
|
if (ai->class == AttachClass)
|
|
return ai->attached;
|
|
|
|
return -1;
|
|
}
|
|
|
|
static Bool
|
|
dmxInputAddExtensionDevices (DMXInputInfo *dmxInput)
|
|
{
|
|
DMXScreenInfo *dmxScreen = (DMXScreenInfo *) dmxInput;
|
|
XExtensionVersion *ext;
|
|
XDeviceInfo *devices;
|
|
int num;
|
|
int i;
|
|
|
|
ext = XQueryInputVersion (dmxScreen->beDisplay, XI_2_Major, XI_2_Minor);
|
|
if (!ext || ext == (XExtensionVersion *) NoSuchExtension)
|
|
{
|
|
dmxLogInput (dmxInput, "%s is not available\n", INAME);
|
|
return FALSE;
|
|
}
|
|
|
|
/* Only use XInput Extension if 2.0 or greater */
|
|
if (ext->major_version < 2)
|
|
{
|
|
dmxLogInput (dmxInput, "%s version %d.%d is too old\n",
|
|
INAME, ext->major_version, ext->minor_version);
|
|
XFree (ext);
|
|
return FALSE;
|
|
}
|
|
|
|
XQueryExtension (dmxScreen->beDisplay,
|
|
INAME,
|
|
&i,
|
|
&dmxInput->eventBase,
|
|
&i);
|
|
|
|
dmxLogInput (dmxInput, "Locating devices on %s (%s version %d.%d)\n",
|
|
dmxScreen->name, INAME,
|
|
ext->major_version, ext->minor_version);
|
|
|
|
XFree (ext);
|
|
|
|
devices = XListInputDevices (dmxScreen->beDisplay, &num);
|
|
if (devices)
|
|
{
|
|
for (i = 0; i < num; i++)
|
|
{
|
|
switch (devices[i].use) {
|
|
case IsXKeyboard:
|
|
dmxAddInputDevice (dmxInput,
|
|
dmxKeyboardProc,
|
|
devices[i].name,
|
|
devices[i].id,
|
|
dmxGetMasterDevice (&devices[i]),
|
|
dmxDeviceKeyboardEventCheck,
|
|
dmxDeviceKeyboardReplyCheck);
|
|
break;
|
|
case IsXPointer:
|
|
dmxAddInputDevice (dmxInput,
|
|
dmxPointerProc,
|
|
devices[i].name,
|
|
devices[i].id,
|
|
dmxGetMasterDevice (&devices[i]),
|
|
dmxDevicePointerEventCheck,
|
|
dmxDevicePointerReplyCheck);
|
|
break;
|
|
}
|
|
}
|
|
|
|
XFreeDeviceList (devices);
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static void
|
|
dmxInputAddDevices (DMXInputInfo *dmxInput)
|
|
{
|
|
if (!dmxInputAddExtensionDevices (dmxInput))
|
|
{
|
|
dmxLogInput (dmxInput, "Using core devices from %s\n",
|
|
((DMXScreenInfo *) dmxInput)->name);
|
|
|
|
dmxAddInputDevice (dmxInput,
|
|
dmxKeyboardProc, "core keyboard",
|
|
-1, -1,
|
|
dmxDeviceKeyboardEventCheck,
|
|
dmxDeviceKeyboardReplyCheck);
|
|
dmxAddInputDevice (dmxInput,
|
|
dmxPointerProc, "core pointer",
|
|
-1, -1,
|
|
dmxDevicePointerEventCheck,
|
|
dmxDevicePointerReplyCheck);
|
|
}
|
|
}
|
|
|
|
static void
|
|
dmxInputRemoveDevices (DMXInputInfo *dmxInput)
|
|
{
|
|
dmxLogInput (dmxInput, "Removing devices from %s\n",
|
|
((DMXScreenInfo *) dmxInput)->name);
|
|
|
|
while (dmxInput->numDevs)
|
|
DeleteInputDeviceRequest (*dmxInput->devs);
|
|
}
|
|
|
|
int
|
|
dmxInputEnable (DMXInputInfo *dmxInput)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < dmxInput->numDevs; i++)
|
|
{
|
|
dmxLogInput (dmxInput, "Activate device id %d: %s\n",
|
|
dmxInput->devs[i]->id, dmxInput->devs[i]->name);
|
|
|
|
if (ActivateDevice (dmxInput->devs[i]) != Success)
|
|
return BadImplementation;
|
|
|
|
if (!EnableDevice (dmxInput->devs[i]))
|
|
return BadImplementation;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
dmxInputDisable (DMXInputInfo *dmxInput)
|
|
{
|
|
char state[32];
|
|
int i;
|
|
|
|
memset (state, 0, sizeof (state));
|
|
|
|
for (i = 0; i < dmxInput->numDevs; i++)
|
|
{
|
|
dmxLogInput (dmxInput, "Disable device id %d: %s\n",
|
|
dmxInput->devs[i]->id, dmxInput->devs[i]->name);
|
|
|
|
if (IsKeyboardDevice (dmxInput->devs[i]))
|
|
dmxUpdateKeyState (dmxInput->devs[i], state);
|
|
else if (IsPointerDevice (dmxInput->devs[i]))
|
|
dmxUpdateButtonState (dmxInput->devs[i], state);
|
|
|
|
DisableDevice (dmxInput->devs[i]);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
dmxInputAttach (DMXInputInfo *dmxInput)
|
|
{
|
|
dmxInputAddDevices (dmxInput);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
dmxInputDetach (DMXInputInfo *dmxInput)
|
|
{
|
|
ProcessInputEvents ();
|
|
|
|
dmxInputRemoveDevices (dmxInput);
|
|
|
|
return 0;
|
|
}
|
|
|
|
void
|
|
dmxInputInit (DMXInputInfo *dmxInput)
|
|
{
|
|
dmxInput->devs = NULL;
|
|
dmxInput->numDevs = 0;
|
|
dmxInput->eventBase = 0;
|
|
}
|
|
|
|
void
|
|
dmxInputFini (DMXInputInfo *dmxInput)
|
|
{
|
|
if (dmxInput->devs)
|
|
xfree (dmxInput->devs);
|
|
}
|
|
|
|
Bool
|
|
LegalModifier (unsigned int key,
|
|
DeviceIntPtr pDev)
|
|
{
|
|
return TRUE;
|
|
}
|
|
|
|
static void
|
|
dmxInitMasterKeyboard (DeviceIntPtr pDev)
|
|
{
|
|
dmxDevicePrivPtr pDevPriv = DMX_GET_DEVICE_PRIV (pDev);
|
|
|
|
DMX_WRAP (ActivateGrab, dmxActivateKeyboardGrab, pDevPriv,
|
|
&pDev->deviceGrab);
|
|
DMX_WRAP (DeactivateGrab, dmxDeactivateKeyboardGrab, pDevPriv,
|
|
&pDev->deviceGrab);
|
|
}
|
|
|
|
static void
|
|
dmxInitMasterPointer (DeviceIntPtr pDev)
|
|
{
|
|
dmxDevicePrivPtr pDevPriv = DMX_GET_DEVICE_PRIV (pDev);
|
|
|
|
DMX_WRAP (ActivateGrab, dmxActivatePointerGrab, pDevPriv,
|
|
&pDev->deviceGrab);
|
|
DMX_WRAP (DeactivateGrab, dmxDeactivatePointerGrab, pDevPriv,
|
|
&pDev->deviceGrab);
|
|
}
|
|
|
|
void
|
|
InitInput (int argc, char **argv)
|
|
{
|
|
int i;
|
|
|
|
GetEventList (&dmxEvents);
|
|
|
|
for (i = 0; i < dmxNumScreens; i++)
|
|
if (dmxScreens[i].beDisplay && !dmxScreens[i].virtualFb)
|
|
dmxInputAddDevices (&dmxScreens[i].input);
|
|
|
|
/* XXX: init devices created using XChangeDeviceHierarchy */
|
|
dmxInitMasterKeyboard (inputInfo.keyboard);
|
|
dmxInitMasterPointer (inputInfo.pointer);
|
|
|
|
mieqInit ();
|
|
}
|
|
|
|
void
|
|
ProcessInputEvents (void)
|
|
{
|
|
mieqProcessInputEvents ();
|
|
}
|
|
|
|
void
|
|
CloseInputDevice (DeviceIntPtr pDevice,
|
|
ClientPtr client)
|
|
{
|
|
}
|
|
|
|
void
|
|
AddOtherInputDevices (void)
|
|
{
|
|
}
|
|
|
|
void
|
|
OpenInputDevice (DeviceIntPtr pDevice,
|
|
ClientPtr client,
|
|
int *status)
|
|
{
|
|
*status = XaceHook (XACE_DEVICE_ACCESS, client, pDevice, DixReadAccess);
|
|
}
|
|
|
|
int
|
|
SetDeviceMode (ClientPtr client,
|
|
DeviceIntPtr pDevice,
|
|
int mode)
|
|
{
|
|
return BadMatch;
|
|
}
|
|
|
|
int
|
|
SetDeviceValuators (ClientPtr client,
|
|
DeviceIntPtr pDevice,
|
|
int *valuators,
|
|
int first_valuator,
|
|
int num_valuators)
|
|
{
|
|
return BadMatch;
|
|
}
|
|
|
|
int
|
|
ChangeDeviceControl (ClientPtr client,
|
|
DeviceIntPtr pDevice,
|
|
xDeviceCtl *control)
|
|
{
|
|
return BadMatch;
|
|
}
|
|
|
|
int
|
|
NewInputDeviceRequest (InputOption *options,
|
|
DeviceIntPtr *ppDevice)
|
|
{
|
|
return BadRequest;
|
|
}
|
|
|
|
void
|
|
DeleteInputDeviceRequest (DeviceIntPtr pDevice)
|
|
{
|
|
int i, j;
|
|
|
|
RemoveDevice (pDevice);
|
|
|
|
for (i = 0; i < dmxNumScreens; i++)
|
|
{
|
|
for (j = 0; j < dmxScreens[i].input.numDevs; j++)
|
|
{
|
|
if (dmxScreens[i].input.devs[j] == pDevice)
|
|
{
|
|
for (; j < dmxScreens[i].input.numDevs - 1; j++)
|
|
dmxScreens[i].input.devs[j] =
|
|
dmxScreens[i].input.devs[j + 1];
|
|
|
|
dmxScreens[i].input.numDevs--;
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
DDXRingBell (int volume,
|
|
int pitch,
|
|
int duration)
|
|
{
|
|
}
|