314 lines
10 KiB
C
314 lines
10 KiB
C
/*
|
|
|
|
Copyright 1993 by Davor Matic
|
|
|
|
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. Davor Matic makes no representations about
|
|
the suitability of this software for any purpose. It is provided "as
|
|
is" without express or implied warranty.
|
|
|
|
*/
|
|
#include <dix-config.h>
|
|
|
|
#ifdef WIN32
|
|
#include <X11/Xwindows.h>
|
|
#endif
|
|
|
|
#include <X11/X.h>
|
|
#include <X11/Xdefs.h>
|
|
#include <X11/Xproto.h>
|
|
#include <X11/keysym.h>
|
|
#include <xcb/xkb.h>
|
|
|
|
#include "screenint.h"
|
|
#include "inputstr.h"
|
|
#include "misc.h"
|
|
#include "scrnintstr.h"
|
|
#include "servermd.h"
|
|
|
|
#include "xnest-xcb.h"
|
|
|
|
#include "Display.h"
|
|
#include "Screen.h"
|
|
#include "Keyboard.h"
|
|
#include "Args.h"
|
|
#include "Events.h"
|
|
|
|
#include <X11/extensions/XKB.h>
|
|
#include "xkbsrv.h"
|
|
|
|
DeviceIntPtr xnestKeyboardDevice = NULL;
|
|
|
|
void
|
|
xnestBell(int volume, DeviceIntPtr pDev, void *ctrl, int cls)
|
|
{
|
|
xcb_bell(xnestUpstreamInfo.conn, volume);
|
|
}
|
|
|
|
void
|
|
DDXRingBell(int volume, int pitch, int duration)
|
|
{
|
|
xcb_bell(xnestUpstreamInfo.conn, volume);
|
|
}
|
|
|
|
void
|
|
xnestChangeKeyboardControl(DeviceIntPtr pDev, KeybdCtrl * ctrl)
|
|
{
|
|
#if 0
|
|
unsigned long value_mask;
|
|
int i;
|
|
|
|
value_mask = KBKeyClickPercent |
|
|
KBBellPercent | KBBellPitch | KBBellDuration | KBAutoRepeatMode;
|
|
|
|
xcb_params_keyboard_t values = {
|
|
.key_click_percent = ctrl->click,
|
|
.bell_percent = ctrl->bell,
|
|
.bell_pitch = ctrl->bell_pitch,
|
|
.bell_duration = ctrl->bell_duration,
|
|
.auto_repeat_mode = ctrl->autoRepeat ? AutoRepeatModeOn : AutoRepeatModeOff,
|
|
};
|
|
|
|
xcb_aux_change_keyboard_control(xnestUpstreamInfo.conn, value_mask, &values);
|
|
/*
|
|
value_mask = KBKey | KBAutoRepeatMode;
|
|
At this point, we need to walk through the vector and compare it
|
|
to the current server vector. If there are differences, report them.
|
|
*/
|
|
|
|
value_mask = KBLed | KBLedMode;
|
|
for (i = 1; i <= 32; i++) {
|
|
values.led = i;
|
|
values.led_mode =
|
|
(ctrl->leds & (1 << (i - 1))) ? LedModeOn : LedModeOff;
|
|
|
|
xcb_aux_change_keyboard_control(xnestUpstreamInfo.conn, value_mask, &values);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
int
|
|
xnestKeyboardProc(DeviceIntPtr pDev, int onoff)
|
|
{
|
|
int i, j;
|
|
|
|
switch (onoff) {
|
|
case DEVICE_INIT:
|
|
{
|
|
const int min_keycode = xnestUpstreamInfo.setup->min_keycode;
|
|
const int max_keycode = xnestUpstreamInfo.setup->max_keycode;
|
|
const int num_keycode = max_keycode - min_keycode + 1;
|
|
|
|
xcb_get_keyboard_mapping_reply_t * keymap_reply = xnest_get_keyboard_mapping(
|
|
xnestUpstreamInfo.conn,
|
|
min_keycode,
|
|
num_keycode);
|
|
|
|
if (!keymap_reply) {
|
|
ErrorF("Couldn't get keyboard mappings: no reply");
|
|
goto XkbError;
|
|
}
|
|
|
|
KeySymsRec keySyms = {
|
|
.minKeyCode = min_keycode,
|
|
.maxKeyCode = max_keycode,
|
|
.mapWidth = keymap_reply->keysyms_per_keycode,
|
|
.map = xcb_get_keyboard_mapping_keysyms(keymap_reply),
|
|
};
|
|
|
|
xcb_generic_error_t *mod_err = NULL;
|
|
xcb_get_modifier_mapping_reply_t *mod_reply = xcb_get_modifier_mapping_reply(
|
|
xnestUpstreamInfo.conn,
|
|
xcb_get_modifier_mapping(xnestUpstreamInfo.conn),
|
|
&mod_err);
|
|
|
|
if (mod_err) {
|
|
free(keymap_reply);
|
|
ErrorF("Couldn't get keyboard modifier mapping: %d\n", mod_err->error_code);
|
|
goto XkbError;
|
|
}
|
|
|
|
if (!mod_reply) {
|
|
free(keymap_reply);
|
|
ErrorF("Couldn't get keyboard modifier mapping: no reply\n");
|
|
goto XkbError;
|
|
}
|
|
|
|
xcb_keycode_t *mod_keycodes = xcb_get_modifier_mapping_keycodes(mod_reply);
|
|
CARD8 modmap[MAP_LENGTH] = { 0 };
|
|
for (j = 0; j < 8; j++)
|
|
for (i = 0; i < mod_reply->keycodes_per_modifier; i++) {
|
|
CARD8 keycode;
|
|
|
|
if ((keycode =
|
|
mod_keycodes[j * mod_reply->keycodes_per_modifier + i]))
|
|
modmap[keycode] |= 1 << j;
|
|
}
|
|
|
|
InitKeyboardDeviceStruct(pDev, NULL,
|
|
xnestBell, xnestChangeKeyboardControl);
|
|
|
|
XkbApplyMappingChange(pDev, &keySyms, keySyms.minKeyCode,
|
|
keySyms.maxKeyCode - keySyms.minKeyCode + 1,
|
|
modmap, serverClient);
|
|
|
|
free(keymap_reply);
|
|
|
|
xnest_xkb_init(xnestUpstreamInfo.conn);
|
|
|
|
int device_id = xnest_xkb_device_id(xnestUpstreamInfo.conn);
|
|
|
|
xcb_generic_error_t *err = NULL;
|
|
xcb_xkb_get_controls_reply_t *reply = xcb_xkb_get_controls_reply(
|
|
xnestUpstreamInfo.conn,
|
|
xcb_xkb_get_controls(xnestUpstreamInfo.conn, device_id),
|
|
&err);
|
|
|
|
if (err) {
|
|
ErrorF("Couldn't get keyboard controls for %d: error %d\n", device_id, err->error_code);
|
|
free(err);
|
|
goto XkbError;
|
|
}
|
|
|
|
if (!reply) {
|
|
ErrorF("Couldn't get keyboard controls for %d: no reply", device_id);
|
|
goto XkbError;
|
|
}
|
|
|
|
XkbControlsRec ctrls = {
|
|
.mk_dflt_btn = reply->mouseKeysDfltBtn,
|
|
.num_groups = reply->numGroups,
|
|
.groups_wrap = reply->groupsWrap,
|
|
.internal = (XkbModsRec) {
|
|
.mask = reply->internalModsMask,
|
|
.real_mods = reply->internalModsRealMods,
|
|
.vmods = reply->internalModsVmods,
|
|
},
|
|
.ignore_lock = (XkbModsRec) {
|
|
.mask = reply->ignoreLockModsMask,
|
|
.real_mods = reply->ignoreLockModsRealMods,
|
|
.vmods = reply->ignoreLockModsVmods,
|
|
},
|
|
.enabled_ctrls = reply->enabledControls,
|
|
.repeat_delay = reply->repeatDelay,
|
|
.repeat_interval = reply->repeatInterval,
|
|
.slow_keys_delay = reply->slowKeysDelay,
|
|
.debounce_delay = reply->debounceDelay,
|
|
.mk_delay = reply->mouseKeysDelay,
|
|
.mk_interval = reply->mouseKeysInterval,
|
|
.mk_time_to_max = reply->mouseKeysTimeToMax,
|
|
.mk_max_speed = reply->mouseKeysMaxSpeed,
|
|
.mk_curve = reply->mouseKeysCurve,
|
|
.ax_options = reply->accessXOption,
|
|
.ax_timeout = reply->accessXTimeout,
|
|
.axt_opts_mask = reply->accessXTimeoutOptionsMask,
|
|
.axt_opts_values = reply->accessXTimeoutOptionsValues,
|
|
.axt_ctrls_mask = reply->accessXTimeoutMask,
|
|
.axt_ctrls_values = reply->accessXTimeoutValues,
|
|
};
|
|
memcpy(&ctrls.per_key_repeat, reply->perKeyRepeat, sizeof(ctrls.per_key_repeat));
|
|
|
|
XkbDDXChangeControls(pDev, &ctrls, &ctrls);
|
|
break;
|
|
}
|
|
case DEVICE_ON:
|
|
xnestEventMask |= XNEST_KEYBOARD_EVENT_MASK;
|
|
for (i = 0; i < xnestNumScreens; i++)
|
|
xcb_change_window_attributes(xnestUpstreamInfo.conn,
|
|
xnestDefaultWindows[i],
|
|
XCB_CW_EVENT_MASK,
|
|
&xnestEventMask);
|
|
break;
|
|
case DEVICE_OFF:
|
|
xnestEventMask &= ~XNEST_KEYBOARD_EVENT_MASK;
|
|
for (i = 0; i < xnestNumScreens; i++)
|
|
xcb_change_window_attributes(xnestUpstreamInfo.conn,
|
|
xnestDefaultWindows[i],
|
|
XCB_CW_EVENT_MASK,
|
|
&xnestEventMask);
|
|
break;
|
|
case DEVICE_CLOSE:
|
|
break;
|
|
}
|
|
return Success;
|
|
|
|
XkbError:
|
|
{
|
|
xcb_generic_error_t *ctrl_err = NULL;
|
|
xcb_get_keyboard_control_reply_t *ctrl_reply =
|
|
xcb_get_keyboard_control_reply(xnestUpstreamInfo.conn,
|
|
xcb_get_keyboard_control(xnestUpstreamInfo.conn),
|
|
&ctrl_err);
|
|
if (ctrl_err) {
|
|
ErrorF("failed retrieving keyboard control: %d\n", ctrl_err->error_code);
|
|
free(ctrl_err);
|
|
}
|
|
else if (!ctrl_reply) {
|
|
ErrorF("failed retrieving keyboard control: no reply\n");
|
|
}
|
|
else {
|
|
memcpy(defaultKeyboardControl.autoRepeats,
|
|
ctrl_reply->auto_repeats,
|
|
sizeof(ctrl_reply->auto_repeats));
|
|
free(ctrl_reply);
|
|
}
|
|
}
|
|
|
|
InitKeyboardDeviceStruct(pDev, NULL, xnestBell, xnestChangeKeyboardControl);
|
|
return Success;
|
|
}
|
|
|
|
void
|
|
xnestUpdateModifierState(unsigned int state)
|
|
{
|
|
DeviceIntPtr pDev = xnestKeyboardDevice;
|
|
KeyClassPtr keyc = pDev->key;
|
|
int i;
|
|
CARD8 mask;
|
|
int xkb_state;
|
|
|
|
if (!pDev)
|
|
return;
|
|
|
|
xkb_state = XkbStateFieldFromRec(&pDev->key->xkbInfo->state);
|
|
state = state & 0xff;
|
|
|
|
if (xkb_state == state)
|
|
return;
|
|
|
|
for (i = 0, mask = 1; i < 8; i++, mask <<= 1) {
|
|
int key;
|
|
|
|
/* Modifier is down, but shouldn't be */
|
|
if ((xkb_state & mask) && !(state & mask)) {
|
|
int count = keyc->modifierKeyCount[i];
|
|
|
|
for (key = 0; key < MAP_LENGTH; key++)
|
|
if (keyc->xkbInfo->desc->map->modmap[key] & mask) {
|
|
if (mask == LockMask) {
|
|
xnestQueueKeyEvent(KeyPress, key);
|
|
xnestQueueKeyEvent(KeyRelease, key);
|
|
}
|
|
else if (key_is_down(pDev, key, KEY_PROCESSED))
|
|
xnestQueueKeyEvent(KeyRelease, key);
|
|
|
|
if (--count == 0)
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* Modifier should be down, but isn't */
|
|
if (!(xkb_state & mask) && (state & mask))
|
|
for (key = 0; key < MAP_LENGTH; key++)
|
|
if (keyc->xkbInfo->desc->map->modmap[key] & mask) {
|
|
xnestQueueKeyEvent(KeyPress, key);
|
|
if (mask == LockMask)
|
|
xnestQueueKeyEvent(KeyRelease, key);
|
|
break;
|
|
}
|
|
}
|
|
}
|