xserver/hw/dmx/dmxinput.c
2008-11-19 13:59:52 -05:00

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)
{
}