xspice: add inputs (mouse and keyboard)

uses xf86AddInputDriver, xf86PostButtonEvent, xf86PostMotionEvent and xf86PostKeyboardEvent

reused xspice_get_spice_server to access the single spice server instance.
This commit is contained in:
Alon Levy
2011-04-27 18:20:09 +03:00
parent c54fef726e
commit 4d04f2bb72
4 changed files with 388 additions and 0 deletions

View File

@@ -65,6 +65,7 @@ spiceqxl_drv_la_SOURCES = \
spiceqxl_driver.c \
spiceqxl_main_loop.c \
spiceqxl_display.c \
spiceqxl_inputs.c \
qxl_driver.c \
qxl_image.c \
qxl_surface.c \

View File

@@ -41,6 +41,7 @@
#include "spiceqxl_driver.h"
#include "spiceqxl_main_loop.h"
#include "spiceqxl_display.h"
#include "spiceqxl_inputs.h"
#endif /* XSPICE */
#if 0
@@ -1624,6 +1625,9 @@ qxl_setup(pointer module, pointer opts, int *errmaj, int *errmin)
if (!loaded) {
loaded = TRUE;
xf86AddDriver(&qxl_driver, module, HaveDriverFuncs);
#ifdef XSPICE
xspice_add_input_drivers(module);
#endif
return (void *)1;
} else {
if (errmaj)

375
src/spiceqxl_inputs.c Normal file
View File

@@ -0,0 +1,375 @@
/* Handle inputs channel for spice, and register the X parts,
* a mouse and a keyboard device pair.
*/
#include <xorg/xf86Xinput.h>
#include <xorg/exevents.h>
#include <xorg/xserver-properties.h>
#include <xorg/list.h>
#include <xorg/input.h>
#include <xorg/xkbsrv.h>
#include <spice.h>
#include "qxl.h"
#include "spiceqxl_inputs.h"
static
int XSpicePointerPreInit(InputDriverPtr drv, InputInfoPtr pInfo, int flags);
static
int XSpiceKeyboardPreInit(InputDriverPtr drv, InputInfoPtr pInfo, int flags);
static
void XSpicePointerUnInit(InputDriverPtr drv, InputInfoPtr pInfo, int flags);
static
void XSpiceKeyboardUnInit(InputDriverPtr drv, InputInfoPtr pInfo, int flags);
static InputDriverRec XSPICE_POINTER = {
1,
"xspice pointer",
NULL,
XSpicePointerPreInit,
XSpicePointerUnInit,
NULL,
NULL /* defaults */
};
static InputDriverRec XSPICE_KEYBOARD = {
1,
"xspice keyboard",
NULL,
XSpiceKeyboardPreInit,
XSpiceKeyboardUnInit,
NULL,
NULL
};
#define BUTTONS 5
typedef struct XSpiceKbd {
SpiceKbdInstance sin;
uint8_t ledstate;
InputInfoPtr pInfo; /* xf86 device handle to post events */
/* Note: spice sends some of the keys escaped by this.
* This is supposed to be AT key codes, but I can't figure out where that
* thing is defined after looking at xf86-input-keyboard. Ended up reverse
* engineering a escaped table using xev.
*/
int escape;
} XSpiceKbd;
static int xspice_pointer_proc(DeviceIntPtr pDevice, int onoff)
{
DevicePtr pDev = (DevicePtr)pDevice;
BYTE map[BUTTONS + 1];
Atom btn_labels[BUTTONS];
Atom axes_labels[2];
int i;
switch (onoff) {
case DEVICE_INIT:
for (i = 0; i < BUTTONS + 1; i++) {
map[i] = i;
}
btn_labels[0] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_LEFT);
btn_labels[1] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_MIDDLE);
btn_labels[2] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_RIGHT);
btn_labels[3] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_WHEEL_UP);
btn_labels[4] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_WHEEL_DOWN);
axes_labels[0] = XIGetKnownProperty(AXIS_LABEL_PROP_REL_X);
axes_labels[1] = XIGetKnownProperty(AXIS_LABEL_PROP_REL_Y);
InitPointerDeviceStruct(pDev, map, BUTTONS,btn_labels,(PtrCtrlProcPtr)NoopDDA,
GetMotionHistorySize(), 2, axes_labels);
break;
case DEVICE_ON:
pDev->on = TRUE;
break;
case DEVICE_OFF:
pDev->on = FALSE;
break;
}
return Success;
}
static void xspice_keyboard_bell(int percent, DeviceIntPtr device, pointer ctrl, int class_)
{
}
#define CAPSFLAG 1
#define NUMFLAG 2
#define SCROLLFLAG 4
/* MODEFLAG and COMPOSEFLAG currently unused (reminder for future) */
#define MODEFLAG 8
#define COMPOSEFLAG 16
#define ArrayLength(a) (sizeof(a) / (sizeof((a)[0])))
static void xspice_keyboard_control(DeviceIntPtr device, KeybdCtrl *ctrl)
{
static struct { int xbit, code; } bits[] = {
{ CAPSFLAG, SPICE_KEYBOARD_MODIFIER_FLAGS_CAPS_LOCK },
{ NUMFLAG, SPICE_KEYBOARD_MODIFIER_FLAGS_NUM_LOCK },
{ SCROLLFLAG, SPICE_KEYBOARD_MODIFIER_FLAGS_SCROLL_LOCK },
/* TODO: there is no MODEFLAG nor COMPOSEFLAG in SPICE. */
};
XSpiceKbd *kbd;
int i;
kbd = device->public.devicePrivate;
kbd->ledstate = 0;
for (i = 0; i < ArrayLength(bits); i++) {
if (ctrl->leds & bits[i].xbit) {
kbd->ledstate |= bits[i].code;
} else {
kbd->ledstate &= ~bits[i].code;
}
}
}
static int xspice_keyboard_proc(DeviceIntPtr pDevice, int onoff)
{
DevicePtr pDev = (DevicePtr)pDevice;
switch (onoff) {
case DEVICE_INIT:
InitKeyboardDeviceStruct(
pDevice, NULL, xspice_keyboard_bell, xspice_keyboard_control
);
break;
case DEVICE_ON:
pDev->on = TRUE;
break;
case DEVICE_OFF:
pDev->on = FALSE;
break;
}
return Success;
}
/* from spice-input.c */
/* keyboard bits */
static void kbd_push_key(SpiceKbdInstance *sin, uint8_t frag);
static uint8_t kbd_get_leds(SpiceKbdInstance *sin);
static const SpiceKbdInterface kbd_interface = {
.base.type = SPICE_INTERFACE_KEYBOARD,
.base.description = "xspice keyboard",
.base.major_version = SPICE_INTERFACE_KEYBOARD_MAJOR,
.base.minor_version = SPICE_INTERFACE_KEYBOARD_MINOR,
.push_scan_freg = kbd_push_key,
.get_leds = kbd_get_leds,
};
/* spice sends AT scancodes (with a strange escape).
* But xf86PostKeyboardEvent expects scancodes. Apparently most of the time
* you just need to add MIN_KEYCODE, see xf86-input-keyboard/src/atKeynames
* and xf86-input-keyboard/src/kbd.c:PostKbdEvent:
* xf86PostKeyboardEvent(device, scanCode + MIN_KEYCODE, down); */
#define MIN_KEYCODE 8
static uint8_t escaped_map[256] = {
[0x1c] = 104, //KEY_KP_Enter,
[0x1d] = 105, //KEY_RCtrl,
[0x2a] = 0,//KEY_LMeta, // REDKEY_FAKE_L_SHIFT
[0x35] = 106,//KEY_KP_Divide,
[0x36] = 0,//KEY_RMeta, // REDKEY_FAKE_R_SHIFT
[0x37] = 107,//KEY_Print,
[0x38] = 108,//KEY_AltLang,
[0x46] = 127,//KEY_Break,
[0x47] = 110,//KEY_Home,
[0x48] = 111,//KEY_Up,
[0x49] = 112,//KEY_PgUp,
[0x4b] = 113,//KEY_Left,
[0x4d] = 114,//KEY_Right,
[0x4f] = 115,//KEY_End,
[0x50] = 116,//KEY_Down,
[0x51] = 117,//KEY_PgDown,
[0x52] = 118,//KEY_Insert,
[0x53] = 119,//KEY_Delete,
[0x5b] = 133,//0, // REDKEY_LEFT_CMD,
[0x5c] = 134,//0, // REDKEY_RIGHT_CMD,
[0x5d] = 135,//KEY_Menu,
};
static void kbd_push_key(SpiceKbdInstance *sin, uint8_t frag)
{
XSpiceKbd *kbd = container_of(sin, XSpiceKbd, sin);
int is_down;
if (frag == 224) {
kbd->escape = frag;
return;
}
is_down = frag & 0x80 ? FALSE : TRUE;
frag = frag & 0x7f;
if (kbd->escape == 224) {
kbd->escape = 0;
if (escaped_map[frag] == 0) {
fprintf(stderr, "spiceqxl_inputs.c: kbd_push_key: escaped_map[%d] == 0\n", frag);
}
frag = escaped_map[frag];
} else {
frag += MIN_KEYCODE;
}
xf86PostKeyboardEvent(kbd->pInfo->dev, frag, is_down);
}
static uint8_t kbd_get_leds(SpiceKbdInstance *sin)
{
XSpiceKbd *kbd = container_of(sin, XSpiceKbd, sin);
return kbd->ledstate;
}
/* mouse bits */
typedef struct XSpicePointer {
SpiceMouseInstance mouse;
SpiceTabletInstance tablet;
int width, height, x, y;
Bool absolute;
InputInfoPtr pInfo; /* xf86 device handle to post events */
} XSpicePointer;
static void mouse_motion(SpiceMouseInstance *sin, int dx, int dy, int dz,
uint32_t buttons_state)
{
// TODO
}
static void mouse_buttons(SpiceMouseInstance *sin, uint32_t buttons_state)
{
// TODO
}
static const SpiceMouseInterface mouse_interface = {
.base.type = SPICE_INTERFACE_MOUSE,
.base.description = "xspice mouse",
.base.major_version = SPICE_INTERFACE_MOUSE_MAJOR,
.base.minor_version = SPICE_INTERFACE_MOUSE_MINOR,
.motion = mouse_motion,
.buttons = mouse_buttons,
};
static void tablet_set_logical_size(SpiceTabletInstance* sin, int width, int height)
{
XSpicePointer *pointer = container_of(sin, XSpicePointer, tablet);
if (height < 16) {
height = 16;
}
if (width < 16) {
width = 16;
}
pointer->width = width;
pointer->height = height;
}
static void tablet_position(SpiceTabletInstance* sin, int x, int y,
uint32_t buttons_state)
{
XSpicePointer *pointer = container_of(sin, XSpicePointer, tablet);
// TODO: don't ignore buttons_state
xf86PostMotionEvent(pointer->pInfo->dev, 1, 0, 2, x, y);
}
static void tablet_buttons(SpiceTabletInstance *sin,
uint32_t buttons_state)
{
XSpicePointer *pointer = container_of(sin, XSpicePointer, tablet);
static uint32_t old_buttons_state = 0;
int i;
// For some reason spice switches the second and third button, undo that.
// basically undo RED_MOUSE_STATE_TO_LOCAL
buttons_state = (buttons_state & SPICE_MOUSE_BUTTON_MASK_LEFT) |
((buttons_state & SPICE_MOUSE_BUTTON_MASK_MIDDLE) << 1) |
((buttons_state & SPICE_MOUSE_BUTTON_MASK_RIGHT) >> 1) |
(buttons_state & ~(SPICE_MOUSE_BUTTON_MASK_LEFT | SPICE_MOUSE_BUTTON_MASK_MIDDLE
|SPICE_MOUSE_BUTTON_MASK_RIGHT));
for (i = 0; i < BUTTONS; i++) {
if ((buttons_state ^ old_buttons_state) & (1 << i)) {
int action = (buttons_state & (1 << i));
xf86PostButtonEvent(pointer->pInfo->dev, 0, i + 1, action, 0, 0);
}
}
old_buttons_state = buttons_state;
}
static void tablet_wheel(SpiceTabletInstance* sin, int wheel,
uint32_t buttons_state)
{
// convert wheel into fourth and fifth buttons
tablet_buttons(sin, buttons_state
| (wheel > 0 ? (1<<4) : 0)
| (wheel < 0 ? (1<<3) : 0));
}
static const SpiceTabletInterface tablet_interface = {
.base.type = SPICE_INTERFACE_TABLET,
.base.description = "xspice tablet",
.base.major_version = SPICE_INTERFACE_TABLET_MAJOR,
.base.minor_version = SPICE_INTERFACE_TABLET_MINOR,
.set_logical_size = tablet_set_logical_size,
.position = tablet_position,
.wheel = tablet_wheel,
.buttons = tablet_buttons,
};
static int
XSpiceKeyboardPreInit(InputDriverPtr drv, InputInfoPtr pInfo, int flags)
{
XSpiceKbd *kbd;
kbd = calloc(sizeof(*kbd), 1);
kbd->sin.base.sif = &kbd_interface.base;
kbd->pInfo = pInfo;
pInfo->private = kbd;
pInfo->type_name = "UNKNOWN";
pInfo->device_control = xspice_keyboard_proc;
pInfo->read_input = NULL;
pInfo->switch_mode = NULL;
spice_server_add_interface(xspice_get_spice_server(), &kbd->sin.base);
return Success;
}
static int
XSpicePointerPreInit(InputDriverPtr drv, InputInfoPtr pInfo, int flags)
{
XSpicePointer *pointer;
pointer = calloc(sizeof(*pointer), 1);
pointer->mouse.base.sif = &mouse_interface.base;
pointer->tablet.base.sif = &tablet_interface.base;
pointer->absolute = TRUE;
pointer->pInfo = pInfo;
pInfo->private = NULL;
pInfo->type_name = "UNKNOWN";
pInfo->device_control = xspice_pointer_proc;
pInfo->read_input = NULL;
pInfo->switch_mode = NULL;
spice_server_add_interface(xspice_get_spice_server(), &pointer->tablet.base);
return Success;
}
static void
XSpicePointerUnInit(InputDriverPtr drv, InputInfoPtr pInfo, int flags)
{
}
static void
XSpiceKeyboardUnInit(InputDriverPtr drv, InputInfoPtr pInfo, int flags)
{
}
void xspice_add_input_drivers(pointer module)
{
xf86AddInputDriver(&XSPICE_POINTER, module, 0);
xf86AddInputDriver(&XSPICE_KEYBOARD, module, 0);
}

8
src/spiceqxl_inputs.h Normal file
View File

@@ -0,0 +1,8 @@
#ifndef QXL_SPICE_INPUTS_H
#define QXL_SPICE_INPUTS_H
#include "qxl.h"
void xspice_add_input_drivers(pointer module);
#endif // QXL_SPICE_INPUTS_H