git-svn-id: svn://svn.code.sf.net/p/tigervnc/code/trunk@3887 3789f03b-4d11-0410-bbf8-ca57d06f2519tags/v1.0.90
@@ -21,13 +21,49 @@ | |||
#include <dix-config.h> | |||
#endif | |||
#include <rfb/LogWriter.h> | |||
#include "Input.h" | |||
#include "xorg-version.h" | |||
#include "vncExtInit.h" | |||
extern "C" { | |||
#define public c_public | |||
#define class c_class | |||
#include "inputstr.h" | |||
#include "mi.h" | |||
#ifndef XKB_IN_SERVER | |||
#define XKB_IN_SERVER | |||
#endif | |||
#ifdef XKB | |||
/* | |||
* This include is needed to use XkbConvertCase instead of XConvertCase even if | |||
* we don't use XKB extension. | |||
*/ | |||
#include <xkbsrv.h> | |||
#endif | |||
#if XORG >= 16 | |||
#include "exevents.h" | |||
extern void | |||
CopyKeyClass(DeviceIntPtr device, DeviceIntPtr master); | |||
#endif | |||
#include <X11/keysym.h> | |||
#include <X11/Xutil.h> | |||
#undef public | |||
#undef class | |||
} | |||
using namespace rdr; | |||
using namespace rfb; | |||
static LogWriter vlog("Input"); | |||
#define BUTTONS 5 | |||
static int pointerProc(DeviceIntPtr pDevice, int onoff); | |||
static int keyboardProc(DeviceIntPtr pDevice, int onoff); | |||
static KeySym KeyCodetoKeySym(KeySymsPtr keymap, int keycode, int col); | |||
static KeyCode KeysymToKeycode(KeySymsPtr keymap, KeySym ks, int* col); | |||
/* Event queue is shared between all devices. */ | |||
#if XORG == 15 | |||
static xEvent *eventq = NULL; | |||
@@ -70,10 +106,6 @@ static void enqueueEvents(DeviceIntPtr dev, int n) | |||
} | |||
} | |||
/* Pointer device pre-declarations */ | |||
#define BUTTONS 5 | |||
static int pointerProc(DeviceIntPtr pDevice, int onoff); | |||
/* Pointer device methods */ | |||
PointerDevice::PointerDevice(rfb::VNCServerST *_server) | |||
@@ -165,3 +197,569 @@ static int pointerProc(DeviceIntPtr pDevice, int onoff) | |||
return Success; | |||
} | |||
/* KeyboardDevice methods */ | |||
KeyboardDevice::KeyboardDevice(void) | |||
{ | |||
dev = AddInputDevice( | |||
#if XORG >= 16 | |||
serverClient, | |||
#endif | |||
keyboardProc, TRUE); | |||
RegisterKeyboardDevice(dev); | |||
initEventq(); | |||
} | |||
#define IS_PRESSED(keyc, keycode) \ | |||
((keyc)->down[(keycode) >> 3] & (1 << ((keycode) & 7))) | |||
/* | |||
* ModifierState is a class which helps simplify generating a "fake" press or | |||
* release of shift, ctrl, alt, etc. An instance of the class is created for | |||
* every modifier which may need to be pressed or released. Then either | |||
* press() or release() may be called to make sure that the corresponding keys | |||
* are in the right state. The destructor of the class automatically reverts | |||
* to the previous state. Each modifier may have multiple keys associated with | |||
* it, so in the case of a fake release, this may involve releasing more than | |||
* one key. | |||
*/ | |||
class ModifierState { | |||
public: | |||
ModifierState(DeviceIntPtr _dev, int _modIndex) | |||
: modIndex(_modIndex), nKeys(0), keys(0), pressed(false), | |||
dev(_dev) {} | |||
~ModifierState() | |||
{ | |||
for (int i = 0; i < nKeys; i++) | |||
generateXKeyEvent(keys[i], !pressed); | |||
delete [] keys; | |||
} | |||
void press() | |||
{ | |||
KeyClassPtr keyc = dev->key; | |||
if (!(keyc->state & (1 << modIndex))) { | |||
int index = modIndex * keyc->maxKeysPerModifier; | |||
tempKeyEvent(keyc->modifierKeyMap[index], true); | |||
pressed = true; | |||
} | |||
} | |||
void release() | |||
{ | |||
KeyClassPtr keyc = dev->key; | |||
if ((keyc->state & (1 << modIndex)) == 0) | |||
return; | |||
for (int k = 0; k < keyc->maxKeysPerModifier; k++) { | |||
int index = modIndex * keyc->maxKeysPerModifier + k; | |||
int keycode = keyc->modifierKeyMap[index]; | |||
if (keycode && IS_PRESSED(keyc, keycode)) | |||
tempKeyEvent(keycode, false); | |||
} | |||
} | |||
private: | |||
void tempKeyEvent(int keycode, bool down) | |||
{ | |||
if (keycode) { | |||
if (!keys) keys = new int[dev->key->maxKeysPerModifier]; | |||
keys[nKeys++] = keycode; | |||
generateXKeyEvent(keycode, down); | |||
} | |||
} | |||
void generateXKeyEvent(int keycode, bool down) | |||
{ | |||
int n, action; | |||
action = down ? KeyPress : KeyRelease; | |||
n = GetKeyboardEvents(eventq, dev, action, keycode); | |||
enqueueEvents(dev, n); | |||
vlog.debug("fake keycode %d %s", keycode, | |||
down ? "down" : "up"); | |||
} | |||
int modIndex; | |||
int nKeys; | |||
int *keys; | |||
bool pressed; | |||
DeviceIntPtr dev; | |||
}; | |||
/* altKeysym is a table of alternative keysyms which have the same meaning. */ | |||
static struct altKeysym_t { | |||
KeySym a, b; | |||
} altKeysym[] = { | |||
{ XK_Shift_L, XK_Shift_R }, | |||
{ XK_Control_L, XK_Control_R }, | |||
{ XK_Meta_L, XK_Meta_R }, | |||
{ XK_Alt_L, XK_Alt_R }, | |||
{ XK_Super_L, XK_Super_R }, | |||
{ XK_Hyper_L, XK_Hyper_R }, | |||
{ XK_KP_Space, XK_space }, | |||
{ XK_KP_Tab, XK_Tab }, | |||
{ XK_KP_Enter, XK_Return }, | |||
{ XK_KP_F1, XK_F1 }, | |||
{ XK_KP_F2, XK_F2 }, | |||
{ XK_KP_F3, XK_F3 }, | |||
{ XK_KP_F4, XK_F4 }, | |||
{ XK_KP_Home, XK_Home }, | |||
{ XK_KP_Left, XK_Left }, | |||
{ XK_KP_Up, XK_Up }, | |||
{ XK_KP_Right, XK_Right }, | |||
{ XK_KP_Down, XK_Down }, | |||
{ XK_KP_Page_Up, XK_Page_Up }, | |||
{ XK_KP_Page_Down, XK_Page_Down }, | |||
{ XK_KP_End, XK_End }, | |||
{ XK_KP_Begin, XK_Begin }, | |||
{ XK_KP_Insert, XK_Insert }, | |||
{ XK_KP_Delete, XK_Delete }, | |||
{ XK_KP_Equal, XK_equal }, | |||
{ XK_KP_Multiply, XK_asterisk }, | |||
{ XK_KP_Add, XK_plus }, | |||
{ XK_KP_Separator, XK_comma }, | |||
{ XK_KP_Subtract, XK_minus }, | |||
{ XK_KP_Decimal, XK_period }, | |||
{ XK_KP_Divide, XK_slash }, | |||
{ XK_KP_0, XK_0 }, | |||
{ XK_KP_1, XK_1 }, | |||
{ XK_KP_2, XK_2 }, | |||
{ XK_KP_3, XK_3 }, | |||
{ XK_KP_4, XK_4 }, | |||
{ XK_KP_5, XK_5 }, | |||
{ XK_KP_6, XK_6 }, | |||
{ XK_KP_7, XK_7 }, | |||
{ XK_KP_8, XK_8 }, | |||
{ XK_KP_9, XK_9 }, | |||
}; | |||
/* | |||
* keyEvent() - work out the best keycode corresponding to the keysym sent by | |||
* the viewer. This is non-trivial because we can't assume much about the | |||
* local keyboard layout. We must also find out which column of the keyboard | |||
* mapping the keysym is in, and alter the shift state appropriately. Column 0 | |||
* means both shift and "mode_switch" (AltGr) must be released, column 1 means | |||
* shift must be pressed and mode_switch released, column 2 means shift must be | |||
* released and mode_switch pressed, and column 3 means both shift and | |||
* mode_switch must be pressed. | |||
* | |||
* Magic, which dynamically adds keysym<->keycode mapping depends on X.Org | |||
* version. Quick explanation of that "magic": | |||
* | |||
* 1.5 | |||
* - has only one core keyboard so we have to keep core keyboard mapping | |||
* synchronized with vncKeyboardDevice. Do it via SwitchCoreKeyboard() | |||
* | |||
* 1.6 (aka MPX - Multi pointer X) | |||
* - multiple master devices (= core devices) exists, keep vncKeyboardDevice | |||
* synchronized with proper master device | |||
*/ | |||
void KeyboardDevice::keyEvent(rdr::U32 keysym, bool down) | |||
{ | |||
DeviceIntPtr master; | |||
KeyClassPtr keyc = dev->key; | |||
KeySymsPtr keymap = &keyc->curKeySyms; | |||
KeySym *map = keymap->map; | |||
KeyCode minKeyCode = keymap->minKeyCode; | |||
KeyCode maxKeyCode = keymap->maxKeyCode; | |||
int mapWidth = keymap->mapWidth; | |||
unsigned int i, n; | |||
int j, k, action; | |||
if (keysym == XK_Caps_Lock) { | |||
vlog.debug("Ignoring caps lock"); | |||
return; | |||
} | |||
/* find which modifier Mode_switch is on. */ | |||
int modeSwitchMapIndex = 0; | |||
for (i = 3; i < 8; i++) { | |||
for (k = 0; k < keyc->maxKeysPerModifier; k++) { | |||
int index = i * keyc->maxKeysPerModifier + k; | |||
int keycode = keyc->modifierKeyMap[index]; | |||
if (keycode == 0) | |||
continue; | |||
for (j = 0; j < mapWidth; j++) { | |||
if (map[(keycode - minKeyCode) * mapWidth + j] | |||
== XK_Mode_switch) { | |||
modeSwitchMapIndex = i; | |||
goto ModeSwitchFound; | |||
} | |||
} | |||
} | |||
} | |||
ModeSwitchFound: | |||
int col = 0; | |||
if ((keyc->state & (1 << ShiftMapIndex)) != 0) | |||
col |= 1; | |||
if (modeSwitchMapIndex != 0 && | |||
((keyc->state & (1 << modeSwitchMapIndex))) != 0) | |||
col |= 2; | |||
int kc = KeysymToKeycode(keymap, keysym, &col); | |||
/* | |||
* Sort out the "shifted Tab" mess. If we are sent a shifted Tab, | |||
* generate a local shifted Tab regardless of what the "shifted Tab" | |||
* keysym is on the local keyboard (it might be Tab, ISO_Left_Tab or | |||
* HP's private BackTab keysym, and quite possibly some others too). | |||
* We never get ISO_Left_Tab here because it's already been translated | |||
* in VNCSConnectionST. | |||
*/ | |||
if (keysym == XK_Tab && ((keyc->state & (1 << ShiftMapIndex))) != 0) | |||
col |= 1; | |||
if (kc == 0) { | |||
/* | |||
* Not a direct match in the local keyboard mapping. Check for | |||
* alternative keysyms with the same meaning. | |||
*/ | |||
for (i = 0; i < sizeof(altKeysym) / sizeof(altKeysym_t); i++) { | |||
if (keysym == altKeysym[i].a) | |||
kc = KeysymToKeycode(keymap, altKeysym[i].b, | |||
&col); | |||
else if (keysym == altKeysym[i].b) | |||
kc = KeysymToKeycode(keymap, altKeysym[i].a, | |||
&col); | |||
if (kc) | |||
break; | |||
} | |||
} | |||
if (kc == 0) { | |||
/* Dynamically add a new key to the keyboard mapping. */ | |||
for (kc = maxKeyCode; kc >= minKeyCode; kc--) { | |||
if (map[(kc - minKeyCode) * mapWidth] != 0) | |||
continue; | |||
map[(kc - minKeyCode) * mapWidth] = keysym; | |||
col = 0; | |||
vlog.info("Added unknown keysym 0x%x to keycode %d", | |||
keysym, kc); | |||
#if XORG == 15 | |||
master = inputInfo.keyboard; | |||
#else | |||
master = dev->u.master; | |||
#endif | |||
void *slave = dixLookupPrivate(&master->devPrivates, | |||
CoreDevicePrivateKey); | |||
if (dev == slave) { | |||
dixSetPrivate(&master->devPrivates, | |||
CoreDevicePrivateKey, NULL); | |||
#if XORG == 15 | |||
SwitchCoreKeyboard(dev); | |||
#else | |||
CopyKeyClass(dev, master); | |||
#endif | |||
} | |||
break; | |||
} | |||
} | |||
if (kc < minKeyCode) { | |||
vlog.info("Keyboard mapping full - ignoring unknown keysym " | |||
"0x%x",keysym); | |||
return; | |||
} | |||
/* | |||
* See if it's a modifier key. If so, then don't do any auto-repeat, | |||
* because the X server will translate each press into a release | |||
* followed by a press. | |||
*/ | |||
for (i = 0; i < 8; i++) { | |||
for (k = 0; k < keyc->maxKeysPerModifier; k++) { | |||
int index = i * keyc->maxKeysPerModifier + k; | |||
if (kc == keyc->modifierKeyMap[index] && | |||
IS_PRESSED(keyc,kc) && down) | |||
return; | |||
} | |||
} | |||
ModifierState shift(dev, ShiftMapIndex); | |||
ModifierState modeSwitch(dev, modeSwitchMapIndex); | |||
if (down) { | |||
if (col & 1) | |||
shift.press(); | |||
else | |||
shift.release(); | |||
if (modeSwitchMapIndex) { | |||
if (col & 2) | |||
modeSwitch.press(); | |||
else | |||
modeSwitch.release(); | |||
} | |||
} | |||
vlog.debug("keycode %d %s", kc, down ? "down" : "up"); | |||
action = down ? KeyPress : KeyRelease; | |||
n = GetKeyboardEvents(eventq, dev, action, kc); | |||
enqueueEvents(dev, n); | |||
} | |||
static KeySym KeyCodetoKeySym(KeySymsPtr keymap, int keycode, int col) | |||
{ | |||
int per = keymap->mapWidth; | |||
KeySym *syms; | |||
KeySym lsym, usym; | |||
if ((col < 0) || ((col >= per) && (col > 3)) || | |||
(keycode < keymap->minKeyCode) || (keycode > keymap->maxKeyCode)) | |||
return NoSymbol; | |||
syms = &keymap->map[(keycode - keymap->minKeyCode) * per]; | |||
if (col >= 4) | |||
return syms[col]; | |||
if (col > 1) { | |||
while ((per > 2) && (syms[per - 1] == NoSymbol)) | |||
per--; | |||
if (per < 3) | |||
col -= 2; | |||
} | |||
if ((per <= (col|1)) || (syms[col|1] == NoSymbol)) { | |||
XConvertCase(syms[col&~1], &lsym, &usym); | |||
if (!(col & 1)) | |||
return lsym; | |||
/* | |||
* I'm commenting out this logic because it's incorrect even | |||
* though it was copied from the Xlib sources. The X protocol | |||
* book quite clearly states that where a group consists of | |||
* element 1 being a non-alphabetic keysym and element 2 being | |||
* NoSymbol that you treat the second element as being the | |||
* same as the first. This also tallies with the behaviour | |||
* produced by the installed Xlib on my linux box (I believe | |||
* this is because it uses some XKB code rather than the | |||
* original Xlib code - compare XKBBind.c with KeyBind.c in | |||
* lib/X11). | |||
*/ | |||
#if 0 | |||
else if (usym == lsym) | |||
return NoSymbol; | |||
#endif | |||
else | |||
return usym; | |||
} | |||
return syms[col]; | |||
} | |||
/* | |||
* KeysymToKeycode() - find the keycode and column corresponding to the given | |||
* keysym. The value of col passed in should be the column determined from the | |||
* current shift state. If the keysym can be found in that column we prefer | |||
* that to finding it in a different column (which would require fake events to | |||
* alter the shift state). | |||
*/ | |||
static KeyCode KeysymToKeycode(KeySymsPtr keymap, KeySym ks, int* col) | |||
{ | |||
int i, j; | |||
j = *col; | |||
for (i = keymap->minKeyCode; i <= keymap->maxKeyCode; i++) { | |||
if (KeyCodetoKeySym(keymap, i, j) == ks) | |||
return i; | |||
} | |||
for (j = 0; j < keymap->mapWidth; j++) { | |||
for (i = keymap->minKeyCode; i <= keymap->maxKeyCode; i++) { | |||
if (KeyCodetoKeySym(keymap, i, j) == ks) { | |||
*col = j; | |||
return i; | |||
} | |||
} | |||
} | |||
return 0; | |||
} | |||
/* Fairly standard US PC Keyboard */ | |||
#define MIN_KEY 8 | |||
#define MAX_KEY 255 | |||
#define MAP_LEN (MAX_KEY - MIN_KEY + 1) | |||
#define KEYSYMS_PER_KEY 2 | |||
KeySym keyboardMap[MAP_LEN * KEYSYMS_PER_KEY] = { | |||
NoSymbol, NoSymbol, | |||
XK_Escape, NoSymbol, | |||
XK_1, XK_exclam, | |||
XK_2, XK_at, | |||
XK_3, XK_numbersign, | |||
XK_4, XK_dollar, | |||
XK_5, XK_percent, | |||
XK_6, XK_asciicircum, | |||
XK_7, XK_ampersand, | |||
XK_8, XK_asterisk, | |||
XK_9, XK_parenleft, | |||
XK_0, XK_parenright, | |||
XK_minus, XK_underscore, | |||
XK_equal, XK_plus, | |||
XK_BackSpace, NoSymbol, | |||
XK_Tab, NoSymbol, | |||
XK_q, XK_Q, | |||
XK_w, XK_W, | |||
XK_e, XK_E, | |||
XK_r, XK_R, | |||
XK_t, XK_T, | |||
XK_y, XK_Y, | |||
XK_u, XK_U, | |||
XK_i, XK_I, | |||
XK_o, XK_O, | |||
XK_p, XK_P, | |||
XK_bracketleft, XK_braceleft, | |||
XK_bracketright, XK_braceright, | |||
XK_Return, NoSymbol, | |||
XK_Control_L, NoSymbol, | |||
XK_a, XK_A, | |||
XK_s, XK_S, | |||
XK_d, XK_D, | |||
XK_f, XK_F, | |||
XK_g, XK_G, | |||
XK_h, XK_H, | |||
XK_j, XK_J, | |||
XK_k, XK_K, | |||
XK_l, XK_L, | |||
XK_semicolon, XK_colon, | |||
XK_apostrophe, XK_quotedbl, | |||
XK_grave, XK_asciitilde, | |||
XK_Shift_L, NoSymbol, | |||
XK_backslash, XK_bar, | |||
XK_z, XK_Z, | |||
XK_x, XK_X, | |||
XK_c, XK_C, | |||
XK_v, XK_V, | |||
XK_b, XK_B, | |||
XK_n, XK_N, | |||
XK_m, XK_M, | |||
XK_comma, XK_less, | |||
XK_period, XK_greater, | |||
XK_slash, XK_question, | |||
XK_Shift_R, NoSymbol, | |||
XK_KP_Multiply, NoSymbol, | |||
XK_Alt_L, XK_Meta_L, | |||
XK_space, NoSymbol, | |||
/* XK_Caps_Lock */ NoSymbol, NoSymbol, | |||
XK_F1, NoSymbol, | |||
XK_F2, NoSymbol, | |||
XK_F3, NoSymbol, | |||
XK_F4, NoSymbol, | |||
XK_F5, NoSymbol, | |||
XK_F6, NoSymbol, | |||
XK_F7, NoSymbol, | |||
XK_F8, NoSymbol, | |||
XK_F9, NoSymbol, | |||
XK_F10, NoSymbol, | |||
XK_Num_Lock, XK_Pointer_EnableKeys, | |||
XK_Scroll_Lock, NoSymbol, | |||
XK_KP_Home, XK_KP_7, | |||
XK_KP_Up, XK_KP_8, | |||
XK_KP_Prior, XK_KP_9, | |||
XK_KP_Subtract, NoSymbol, | |||
XK_KP_Left, XK_KP_4, | |||
XK_KP_Begin, XK_KP_5, | |||
XK_KP_Right, XK_KP_6, | |||
XK_KP_Add, NoSymbol, | |||
XK_KP_End, XK_KP_1, | |||
XK_KP_Down, XK_KP_2, | |||
XK_KP_Next, XK_KP_3, | |||
XK_KP_Insert, XK_KP_0, | |||
XK_KP_Delete, XK_KP_Decimal, | |||
NoSymbol, NoSymbol, | |||
NoSymbol, NoSymbol, | |||
NoSymbol, NoSymbol, | |||
XK_F11, NoSymbol, | |||
XK_F12, NoSymbol, | |||
XK_Home, NoSymbol, | |||
XK_Up, NoSymbol, | |||
XK_Prior, NoSymbol, | |||
XK_Left, NoSymbol, | |||
NoSymbol, NoSymbol, | |||
XK_Right, NoSymbol, | |||
XK_End, NoSymbol, | |||
XK_Down, NoSymbol, | |||
XK_Next, NoSymbol, | |||
XK_Insert, NoSymbol, | |||
XK_Delete, NoSymbol, | |||
XK_KP_Enter, NoSymbol, | |||
XK_Control_R, NoSymbol, | |||
XK_Pause, XK_Break, | |||
XK_Print, XK_Execute, | |||
XK_KP_Divide, NoSymbol, | |||
XK_Alt_R, XK_Meta_R, | |||
}; | |||
static Bool GetMappings(KeySymsPtr pKeySyms, CARD8 *pModMap) | |||
{ | |||
int i; | |||
for (i = 0; i < MAP_LENGTH; i++) | |||
pModMap[i] = NoSymbol; | |||
for (i = 0; i < MAP_LEN; i++) { | |||
if (keyboardMap[i * KEYSYMS_PER_KEY] == XK_Caps_Lock) | |||
pModMap[i + MIN_KEY] = LockMask; | |||
else if (keyboardMap[i * KEYSYMS_PER_KEY] == XK_Shift_L || | |||
keyboardMap[i * KEYSYMS_PER_KEY] == XK_Shift_R) | |||
pModMap[i + MIN_KEY] = ShiftMask; | |||
else if (keyboardMap[i * KEYSYMS_PER_KEY] == XK_Control_L || | |||
keyboardMap[i * KEYSYMS_PER_KEY] == XK_Control_R) | |||
pModMap[i + MIN_KEY] = ControlMask; | |||
else if (keyboardMap[i * KEYSYMS_PER_KEY] == XK_Alt_L || | |||
keyboardMap[i * KEYSYMS_PER_KEY] == XK_Alt_R) | |||
pModMap[i + MIN_KEY] = Mod1Mask; | |||
} | |||
pKeySyms->minKeyCode = MIN_KEY; | |||
pKeySyms->maxKeyCode = MAX_KEY; | |||
pKeySyms->mapWidth = KEYSYMS_PER_KEY; | |||
pKeySyms->map = keyboardMap; | |||
return TRUE; | |||
} | |||
static void keyboardBell(int percent, DeviceIntPtr device, pointer ctrl, | |||
int class_) | |||
{ | |||
if (percent > 0) | |||
vncBell(); | |||
} | |||
static int keyboardProc(DeviceIntPtr pDevice, int onoff) | |||
{ | |||
KeySymsRec keySyms; | |||
CARD8 modMap[MAP_LENGTH]; | |||
DevicePtr pDev = (DevicePtr)pDevice; | |||
switch (onoff) { | |||
case DEVICE_INIT: | |||
GetMappings(&keySyms, modMap); | |||
InitKeyboardDeviceStruct(pDev, &keySyms, modMap, keyboardBell, | |||
(KbdCtrlProcPtr)NoopDDA); | |||
break; | |||
case DEVICE_ON: | |||
pDev->on = TRUE; | |||
break; | |||
case DEVICE_OFF: | |||
pDev->on = FALSE; | |||
break; | |||
#if 0 | |||
case DEVICE_CLOSE: | |||
break; | |||
#endif | |||
} | |||
return Success; | |||
} | |||
@@ -58,4 +58,17 @@ private: | |||
rfb::Point cursorPos, oldCursorPos; | |||
}; | |||
/* Represents keyboard device. */ | |||
class KeyboardDevice { | |||
public: | |||
/* Create new Keyboard device instance. */ | |||
KeyboardDevice(void); | |||
void Press(rdr::U32 keysym) { keyEvent(keysym, true); } | |||
void Release(rdr::U32 keysym) { keyEvent(keysym, false); } | |||
private: | |||
void keyEvent(rdr::U32 keysym, bool down); | |||
DeviceIntPtr dev; | |||
}; | |||
#endif |
@@ -50,26 +50,7 @@ extern "C" { | |||
extern char *display; | |||
#include "inputstr.h" | |||
#include "servermd.h" | |||
#include "colormapst.h" | |||
#include "resource.h" | |||
#include "cursorstr.h" | |||
#include "windowstr.h" | |||
#include "mi.h" | |||
#define XK_CYRILLIC | |||
#include <X11/keysym.h> | |||
#ifndef XKB_IN_SERVER | |||
#define XKB_IN_SERVER | |||
#endif | |||
#ifdef XKB | |||
#include <xkbsrv.h> | |||
#endif | |||
#if XORG >= 16 | |||
#include "exevents.h" | |||
extern void | |||
CopyKeyClass(DeviceIntPtr device, DeviceIntPtr master); | |||
#endif | |||
#ifdef RANDR | |||
#include "randrstr.h" | |||
#endif | |||
@@ -77,15 +58,6 @@ CopyKeyClass(DeviceIntPtr device, DeviceIntPtr master); | |||
#undef class | |||
} | |||
static DeviceIntPtr vncKeyboardDevice = NULL; | |||
#if XORG == 15 | |||
static xEvent *eventq = NULL; | |||
#else | |||
static EventList *eventq = NULL; | |||
#endif | |||
static int vfbKeybdProc(DeviceIntPtr pDevice, int onoff); | |||
using namespace rfb; | |||
using namespace network; | |||
@@ -102,8 +74,6 @@ IntParameter queryConnectTimeout("QueryConnectTimeout", | |||
"rejecting the connection", | |||
10); | |||
static KeyCode KeysymToKeycode(KeySymsPtr keymap, KeySym ks, int* col); | |||
static rdr::U8 reverseBits[] = { | |||
0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0, 0x10, 0x90, 0x50, 0xd0, | |||
0x30, 0xb0, 0x70, 0xf0, 0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8, | |||
@@ -193,33 +163,8 @@ XserverDesktop::XserverDesktop(ScreenPtr pScreen_, | |||
if (httpListener) | |||
httpServer = new FileHTTPServer(this); | |||
#if XORG == 15 | |||
/* | |||
* XXX eventq is never free()-ed because it has to exist during server life | |||
* */ | |||
if (!eventq) | |||
eventq = (xEvent *) xcalloc(sizeof(xEvent), GetMaximumEventsNum()); | |||
if (!eventq) | |||
FatalError("Couldn't allocate eventq\n"); | |||
#else | |||
GetEventList(&eventq); | |||
#endif | |||
/* | |||
* NOTE: | |||
* We _might_ have to call ActivateDevice function for both keyboard and | |||
* mouse. For Xvnc it's not needed but I have to check libvnc.so module. | |||
*/ | |||
if (vncKeyboardDevice == NULL) { | |||
vncKeyboardDevice = AddInputDevice( | |||
#if XORG >= 16 | |||
serverClient, | |||
#endif | |||
vfbKeybdProc, TRUE); | |||
RegisterKeyboardDevice(vncKeyboardDevice); | |||
} | |||
pointerDevice = new PointerDevice(server); | |||
keyboardDevice = new KeyboardDevice(); | |||
} | |||
XserverDesktop::~XserverDesktop() | |||
@@ -229,6 +174,7 @@ XserverDesktop::~XserverDesktop() | |||
TimerFree(deferredUpdateTimer); | |||
TimerFree(dummyTimer); | |||
delete pointerDevice; | |||
delete keyboardDevice; | |||
delete httpServer; | |||
delete server; | |||
} | |||
@@ -854,533 +800,10 @@ void XserverDesktop::lookup(int index, int* r, int* g, int* b) | |||
} | |||
} | |||
// | |||
// Keyboard handling | |||
// | |||
#define IS_PRESSED(keyc, keycode) \ | |||
((keyc)->down[(keycode) >> 3] & (1 << ((keycode) & 7))) | |||
// ModifierState is a class which helps simplify generating a "fake" press | |||
// or release of shift, ctrl, alt, etc. An instance of the class is created | |||
// for every modifier which may need to be pressed or released. Then either | |||
// press() or release() may be called to make sure that the corresponding keys | |||
// are in the right state. The destructor of the class automatically reverts | |||
// to the previous state. Each modifier may have multiple keys associated with | |||
// it, so in the case of a fake release, this may involve releasing more than | |||
// one key. | |||
class ModifierState { | |||
public: | |||
ModifierState(int modIndex_) | |||
: modIndex(modIndex_), nKeys(0), keys(0), pressed(false) | |||
{ | |||
} | |||
~ModifierState() { | |||
for (int i = 0; i < nKeys; i++) | |||
generateXKeyEvent(keys[i], !pressed); | |||
delete [] keys; | |||
} | |||
void press() { | |||
KeyClassPtr keyc = vncKeyboardDevice->key; | |||
if (!(keyc->state & (1<<modIndex))) { | |||
tempKeyEvent(keyc->modifierKeyMap[modIndex * keyc->maxKeysPerModifier], | |||
true); | |||
pressed = true; | |||
} | |||
} | |||
void release() { | |||
KeyClassPtr keyc = vncKeyboardDevice->key; | |||
if (keyc->state & (1<<modIndex)) { | |||
for (int k = 0; k < keyc->maxKeysPerModifier; k++) { | |||
int keycode | |||
= keyc->modifierKeyMap[modIndex * keyc->maxKeysPerModifier + k]; | |||
if (keycode && IS_PRESSED(keyc, keycode)) | |||
tempKeyEvent(keycode, false); | |||
} | |||
} | |||
} | |||
private: | |||
void tempKeyEvent(int keycode, bool down) { | |||
if (keycode) { | |||
if (!keys) keys = new int[vncKeyboardDevice->key->maxKeysPerModifier]; | |||
keys[nKeys++] = keycode; | |||
generateXKeyEvent(keycode, down); | |||
} | |||
} | |||
void generateXKeyEvent(int keycode, bool down) { | |||
int i, n; | |||
n = GetKeyboardEvents (eventq, vncKeyboardDevice, | |||
down ? KeyPress : KeyRelease, keycode); | |||
for (i = 0; i < n; i++) { | |||
mieqEnqueue (vncKeyboardDevice, | |||
#if XORG == 15 | |||
eventq + i | |||
#else | |||
(eventq + i)->event | |||
#endif | |||
); | |||
} | |||
vlog.debug("fake keycode %d %s", keycode, down ? "down" : "up"); | |||
} | |||
int modIndex; | |||
int nKeys; | |||
int* keys; | |||
bool pressed; | |||
}; | |||
// altKeysym is a table of alternative keysyms which have the same meaning. | |||
struct altKeysym_t { | |||
KeySym a, b; | |||
}; | |||
altKeysym_t altKeysym[] = { | |||
{ XK_Shift_L, XK_Shift_R }, | |||
{ XK_Control_L, XK_Control_R }, | |||
{ XK_Meta_L, XK_Meta_R }, | |||
{ XK_Alt_L, XK_Alt_R }, | |||
{ XK_Super_L, XK_Super_R }, | |||
{ XK_Hyper_L, XK_Hyper_R }, | |||
{ XK_KP_Space, XK_space }, | |||
{ XK_KP_Tab, XK_Tab }, | |||
{ XK_KP_Enter, XK_Return }, | |||
{ XK_KP_F1, XK_F1 }, | |||
{ XK_KP_F2, XK_F2 }, | |||
{ XK_KP_F3, XK_F3 }, | |||
{ XK_KP_F4, XK_F4 }, | |||
{ XK_KP_Home, XK_Home }, | |||
{ XK_KP_Left, XK_Left }, | |||
{ XK_KP_Up, XK_Up }, | |||
{ XK_KP_Right, XK_Right }, | |||
{ XK_KP_Down, XK_Down }, | |||
{ XK_KP_Page_Up, XK_Page_Up }, | |||
{ XK_KP_Page_Down, XK_Page_Down }, | |||
{ XK_KP_End, XK_End }, | |||
{ XK_KP_Begin, XK_Begin }, | |||
{ XK_KP_Insert, XK_Insert }, | |||
{ XK_KP_Delete, XK_Delete }, | |||
{ XK_KP_Equal, XK_equal }, | |||
{ XK_KP_Multiply, XK_asterisk }, | |||
{ XK_KP_Add, XK_plus }, | |||
{ XK_KP_Separator, XK_comma }, | |||
{ XK_KP_Subtract, XK_minus }, | |||
{ XK_KP_Decimal, XK_period }, | |||
{ XK_KP_Divide, XK_slash }, | |||
{ XK_KP_0, XK_0 }, | |||
{ XK_KP_1, XK_1 }, | |||
{ XK_KP_2, XK_2 }, | |||
{ XK_KP_3, XK_3 }, | |||
{ XK_KP_4, XK_4 }, | |||
{ XK_KP_5, XK_5 }, | |||
{ XK_KP_6, XK_6 }, | |||
{ XK_KP_7, XK_7 }, | |||
{ XK_KP_8, XK_8 }, | |||
{ XK_KP_9, XK_9 }, | |||
}; | |||
/* | |||
* keyEvent() - work out the best keycode corresponding to the keysym sent by | |||
* the viewer. This is non-trivial because we can't assume much about the | |||
* local keyboard layout. We must also find out which column of the keyboard | |||
* mapping the keysym is in, and alter the shift state appropriately. Column 0 | |||
* means both shift and "mode_switch" (AltGr) must be released, column 1 means | |||
* shift must be pressed and mode_switch released, column 2 means shift must be | |||
* released and mode_switch pressed, and column 3 means both shift and | |||
* mode_switch must be pressed. | |||
* | |||
* Magic, which dynamically adds keysym<->keycode mapping depends on X.Org | |||
* version. Quick explanation of that "magic": | |||
* | |||
* 1.5 | |||
* - has only one core keyboard so we have to keep core keyboard mapping | |||
* synchronized with vncKeyboardDevice. Do it via SwitchCoreKeyboard() | |||
* | |||
* 1.6 (aka MPX - Multi pointer X) | |||
* - multiple master devices (= core devices) exists, keep vncKeyboardDevice | |||
* synchronized with proper master device | |||
*/ | |||
void XserverDesktop::keyEvent(rdr::U32 keysym, bool down) | |||
{ | |||
DeviceIntPtr master; | |||
KeyClassPtr keyc = vncKeyboardDevice->key; | |||
KeySymsPtr keymap = &keyc->curKeySyms; | |||
unsigned int i, n; | |||
int j, k; | |||
if (keysym == XK_Caps_Lock) { | |||
vlog.debug("Ignoring caps lock"); | |||
return; | |||
} | |||
// find which modifier Mode_switch is on. | |||
int modeSwitchMapIndex = 0; | |||
for (i = 3; i < 8; i++) { | |||
for (k = 0; k < keyc->maxKeysPerModifier; k++) { | |||
int keycode = keyc->modifierKeyMap[i * keyc->maxKeysPerModifier + k]; | |||
for (j = 0; j < keymap->mapWidth; j++) { | |||
if (keycode != 0 && | |||
keymap->map[(keycode - keymap->minKeyCode) | |||
* keymap->mapWidth + j] == XK_Mode_switch) | |||
{ | |||
modeSwitchMapIndex = i; | |||
break; | |||
} | |||
} | |||
} | |||
} | |||
int col = 0; | |||
if (keyc->state & (1<<ShiftMapIndex)) col |= 1; | |||
if (modeSwitchMapIndex && (keyc->state & (1<<modeSwitchMapIndex))) col |= 2; | |||
int kc = KeysymToKeycode(keymap, keysym, &col); | |||
// Sort out the "shifted Tab" mess. If we are sent a shifted Tab, generate a | |||
// local shifted Tab regardless of what the "shifted Tab" keysym is on the | |||
// local keyboard (it might be Tab, ISO_Left_Tab or HP's private BackTab | |||
// keysym, and quite possibly some others too). We never get ISO_Left_Tab | |||
// here because it's already been translated in VNCSConnectionST. | |||
if (keysym == XK_Tab && (keyc->state & (1<<ShiftMapIndex))) | |||
col |= 1; | |||
if (kc == 0) { | |||
// Not a direct match in the local keyboard mapping. Check for alternative | |||
// keysyms with the same meaning. | |||
for (i = 0; i < sizeof(altKeysym) / sizeof(altKeysym_t); i++) { | |||
if (keysym == altKeysym[i].a) | |||
kc = KeysymToKeycode(keymap, altKeysym[i].b, &col); | |||
else if (keysym == altKeysym[i].b) | |||
kc = KeysymToKeycode(keymap, altKeysym[i].a, &col); | |||
if (kc) break; | |||
} | |||
} | |||
if (kc == 0) { | |||
// Last resort - dynamically add a new key to the keyboard mapping. | |||
for (kc = keymap->maxKeyCode; kc >= keymap->minKeyCode; kc--) { | |||
if (!keymap->map[(kc - keymap->minKeyCode) * keymap->mapWidth]) { | |||
keymap->map[(kc - keymap->minKeyCode) * keymap->mapWidth] = keysym; | |||
col = 0; | |||
vlog.info("Added unknown keysym 0x%x to keycode %d",keysym,kc); | |||
#if XORG == 15 | |||
master = inputInfo.keyboard; | |||
#else | |||
master = vncKeyboardDevice->u.master; | |||
#endif | |||
if (vncKeyboardDevice == | |||
dixLookupPrivate(&master->devPrivates, CoreDevicePrivateKey)) { | |||
dixSetPrivate(&master->devPrivates, CoreDevicePrivateKey, NULL); | |||
#if XORG == 15 | |||
SwitchCoreKeyboard(vncKeyboardDevice); | |||
#else | |||
CopyKeyClass(vncKeyboardDevice, master); | |||
#endif | |||
} | |||
break; | |||
} | |||
} | |||
if (kc < keymap->minKeyCode) { | |||
vlog.info("Keyboard mapping full - ignoring unknown keysym 0x%x",keysym); | |||
return; | |||
} | |||
} | |||
// See if it's a modifier key. If so, then don't do any auto-repeat, because | |||
// the X server will translate each press into a release followed by a press. | |||
for (i = 0; i < 8; i++) { | |||
for (k = 0; k < keyc->maxKeysPerModifier; k++) { | |||
if (kc == keyc->modifierKeyMap[i * keyc->maxKeysPerModifier + k] && | |||
IS_PRESSED(keyc,kc) && down) | |||
return; | |||
} | |||
} | |||
ModifierState shift(ShiftMapIndex); | |||
ModifierState modeSwitch(modeSwitchMapIndex); | |||
if (down) { | |||
if (col & 1) | |||
shift.press(); | |||
else | |||
shift.release(); | |||
if (modeSwitchMapIndex) { | |||
if (col & 2) | |||
modeSwitch.press(); | |||
else | |||
modeSwitch.release(); | |||
} | |||
} | |||
vlog.debug("keycode %d %s", kc, down ? "down" : "up"); | |||
n = GetKeyboardEvents (eventq, vncKeyboardDevice, down ? | |||
KeyPress : KeyRelease, kc); | |||
for (i = 0; i < n; i++) { | |||
mieqEnqueue (vncKeyboardDevice, | |||
#if XORG == 15 | |||
eventq + i | |||
#else | |||
(eventq + i)->event | |||
#endif | |||
); | |||
} | |||
if (down) | |||
keyboardDevice->Press(keysym); | |||
else | |||
keyboardDevice->Release(keysym); | |||
} | |||
static KeySym KeyCodetoKeySym(KeySymsPtr keymap, int keycode, int col) | |||
{ | |||
register int per = keymap->mapWidth; | |||
register KeySym *syms; | |||
KeySym lsym, usym; | |||
if ((col < 0) || ((col >= per) && (col > 3)) || | |||
(keycode < keymap->minKeyCode) || (keycode > keymap->maxKeyCode)) | |||
return NoSymbol; | |||
syms = &keymap->map[(keycode - keymap->minKeyCode) * per]; | |||
if (col < 4) { | |||
if (col > 1) { | |||
while ((per > 2) && (syms[per - 1] == NoSymbol)) | |||
per--; | |||
if (per < 3) | |||
col -= 2; | |||
} | |||
if ((per <= (col|1)) || (syms[col|1] == NoSymbol)) { | |||
XConvertCase(syms[col&~1], &lsym, &usym); | |||
if (!(col & 1)) | |||
return lsym; | |||
// I'm commenting out this logic because it's incorrect even though it | |||
// was copied from the Xlib sources. The X protocol book quite clearly | |||
// states that where a group consists of element 1 being a non-alphabetic | |||
// keysym and element 2 being NoSymbol that you treat the second element | |||
// as being the same as the first. This also tallies with the behaviour | |||
// produced by the installed Xlib on my linux box (I believe this is | |||
// because it uses some XKB code rather than the original Xlib code - | |||
// compare XKBBind.c with KeyBind.c in lib/X11). | |||
// else if (usym == lsym) | |||
// return NoSymbol; | |||
else | |||
return usym; | |||
} | |||
} | |||
return syms[col]; | |||
} | |||
// KeysymToKeycode() - find the keycode and column corresponding to the given | |||
// keysym. The value of col passed in should be the column determined from the | |||
// current shift state. If the keysym can be found in that column we prefer | |||
// that to finding it in a different column (which would require fake events to | |||
// alter the shift state). | |||
static KeyCode KeysymToKeycode(KeySymsPtr keymap, KeySym ks, int* col) | |||
{ | |||
register int i, j; | |||
j = *col; | |||
for (i = keymap->minKeyCode; i <= keymap->maxKeyCode; i++) { | |||
if (KeyCodetoKeySym(keymap, i, j) == ks) | |||
return i; | |||
} | |||
for (j = 0; j < keymap->mapWidth; j++) { | |||
for (i = keymap->minKeyCode; i <= keymap->maxKeyCode; i++) { | |||
if (KeyCodetoKeySym(keymap, i, j) == ks) { | |||
*col = j; | |||
return i; | |||
} | |||
} | |||
} | |||
return 0; | |||
} | |||
/* Fairly standard US PC Keyboard */ | |||
#define VFB_MIN_KEY 8 | |||
#define VFB_MAX_KEY 255 | |||
#define VFB_MAP_LEN (VFB_MAX_KEY - VFB_MIN_KEY + 1) | |||
#define KEYSYMS_PER_KEY 2 | |||
KeySym keyboardMap[VFB_MAP_LEN * KEYSYMS_PER_KEY] = { | |||
NoSymbol, NoSymbol, | |||
XK_Escape, NoSymbol, | |||
XK_1, XK_exclam, | |||
XK_2, XK_at, | |||
XK_3, XK_numbersign, | |||
XK_4, XK_dollar, | |||
XK_5, XK_percent, | |||
XK_6, XK_asciicircum, | |||
XK_7, XK_ampersand, | |||
XK_8, XK_asterisk, | |||
XK_9, XK_parenleft, | |||
XK_0, XK_parenright, | |||
XK_minus, XK_underscore, | |||
XK_equal, XK_plus, | |||
XK_BackSpace, NoSymbol, | |||
XK_Tab, NoSymbol, | |||
XK_q, XK_Q, | |||
XK_w, XK_W, | |||
XK_e, XK_E, | |||
XK_r, XK_R, | |||
XK_t, XK_T, | |||
XK_y, XK_Y, | |||
XK_u, XK_U, | |||
XK_i, XK_I, | |||
XK_o, XK_O, | |||
XK_p, XK_P, | |||
XK_bracketleft, XK_braceleft, | |||
XK_bracketright, XK_braceright, | |||
XK_Return, NoSymbol, | |||
XK_Control_L, NoSymbol, | |||
XK_a, XK_A, | |||
XK_s, XK_S, | |||
XK_d, XK_D, | |||
XK_f, XK_F, | |||
XK_g, XK_G, | |||
XK_h, XK_H, | |||
XK_j, XK_J, | |||
XK_k, XK_K, | |||
XK_l, XK_L, | |||
XK_semicolon, XK_colon, | |||
XK_apostrophe, XK_quotedbl, | |||
XK_grave, XK_asciitilde, | |||
XK_Shift_L, NoSymbol, | |||
XK_backslash, XK_bar, | |||
XK_z, XK_Z, | |||
XK_x, XK_X, | |||
XK_c, XK_C, | |||
XK_v, XK_V, | |||
XK_b, XK_B, | |||
XK_n, XK_N, | |||
XK_m, XK_M, | |||
XK_comma, XK_less, | |||
XK_period, XK_greater, | |||
XK_slash, XK_question, | |||
XK_Shift_R, NoSymbol, | |||
XK_KP_Multiply, NoSymbol, | |||
XK_Alt_L, XK_Meta_L, | |||
XK_space, NoSymbol, | |||
/*XK_Caps_Lock*/ NoSymbol, NoSymbol, | |||
XK_F1, NoSymbol, | |||
XK_F2, NoSymbol, | |||
XK_F3, NoSymbol, | |||
XK_F4, NoSymbol, | |||
XK_F5, NoSymbol, | |||
XK_F6, NoSymbol, | |||
XK_F7, NoSymbol, | |||
XK_F8, NoSymbol, | |||
XK_F9, NoSymbol, | |||
XK_F10, NoSymbol, | |||
XK_Num_Lock, XK_Pointer_EnableKeys, | |||
XK_Scroll_Lock, NoSymbol, | |||
XK_KP_Home, XK_KP_7, | |||
XK_KP_Up, XK_KP_8, | |||
XK_KP_Prior, XK_KP_9, | |||
XK_KP_Subtract, NoSymbol, | |||
XK_KP_Left, XK_KP_4, | |||
XK_KP_Begin, XK_KP_5, | |||
XK_KP_Right, XK_KP_6, | |||
XK_KP_Add, NoSymbol, | |||
XK_KP_End, XK_KP_1, | |||
XK_KP_Down, XK_KP_2, | |||
XK_KP_Next, XK_KP_3, | |||
XK_KP_Insert, XK_KP_0, | |||
XK_KP_Delete, XK_KP_Decimal, | |||
NoSymbol, NoSymbol, | |||
NoSymbol, NoSymbol, | |||
NoSymbol, NoSymbol, | |||
XK_F11, NoSymbol, | |||
XK_F12, NoSymbol, | |||
XK_Home, NoSymbol, | |||
XK_Up, NoSymbol, | |||
XK_Prior, NoSymbol, | |||
XK_Left, NoSymbol, | |||
NoSymbol, NoSymbol, | |||
XK_Right, NoSymbol, | |||
XK_End, NoSymbol, | |||
XK_Down, NoSymbol, | |||
XK_Next, NoSymbol, | |||
XK_Insert, NoSymbol, | |||
XK_Delete, NoSymbol, | |||
XK_KP_Enter, NoSymbol, | |||
XK_Control_R, NoSymbol, | |||
XK_Pause, XK_Break, | |||
XK_Print, XK_Execute, | |||
XK_KP_Divide, NoSymbol, | |||
XK_Alt_R, XK_Meta_R, | |||
}; | |||
static Bool GetMappings(KeySymsPtr pKeySyms, CARD8 *pModMap) | |||
{ | |||
int i; | |||
for (i = 0; i < MAP_LENGTH; i++) | |||
pModMap[i] = NoSymbol; | |||
for (i = 0; i < VFB_MAP_LEN; i++) { | |||
if (keyboardMap[i * KEYSYMS_PER_KEY] == XK_Caps_Lock) | |||
pModMap[i + VFB_MIN_KEY] = LockMask; | |||
else if (keyboardMap[i * KEYSYMS_PER_KEY] == XK_Shift_L || | |||
keyboardMap[i * KEYSYMS_PER_KEY] == XK_Shift_R) | |||
pModMap[i + VFB_MIN_KEY] = ShiftMask; | |||
else if (keyboardMap[i * KEYSYMS_PER_KEY] == XK_Control_L || | |||
keyboardMap[i * KEYSYMS_PER_KEY] == XK_Control_R) { | |||
pModMap[i + VFB_MIN_KEY] = ControlMask; | |||
} | |||
else if (keyboardMap[i * KEYSYMS_PER_KEY] == XK_Alt_L || | |||
keyboardMap[i * KEYSYMS_PER_KEY] == XK_Alt_R) | |||
pModMap[i + VFB_MIN_KEY] = Mod1Mask; | |||
} | |||
pKeySyms->minKeyCode = VFB_MIN_KEY; | |||
pKeySyms->maxKeyCode = VFB_MAX_KEY; | |||
pKeySyms->mapWidth = KEYSYMS_PER_KEY; | |||
pKeySyms->map = keyboardMap; | |||
return TRUE; | |||
} | |||
static void vfbBell(int percent, DeviceIntPtr device, pointer ctrl, int class_) | |||
{ | |||
if (percent > 0) | |||
vncBell(); | |||
} | |||
static int vfbKeybdProc(DeviceIntPtr pDevice, int onoff) | |||
{ | |||
KeySymsRec keySyms; | |||
CARD8 modMap[MAP_LENGTH]; | |||
DevicePtr pDev = (DevicePtr)pDevice; | |||
#ifdef XKB | |||
XkbComponentNamesRec names; | |||
#endif | |||
switch (onoff) | |||
{ | |||
case DEVICE_INIT: | |||
GetMappings(&keySyms, modMap); | |||
#ifdef XKB | |||
if (!noXkbExtension) { | |||
memset(&names, 0, sizeof (names)); | |||
XkbSetRulesDflts("base", "pc105", "us", NULL, NULL); | |||
XkbInitKeyboardDeviceStruct(pDevice, &names, &keySyms, modMap, | |||
(BellProcPtr)vfbBell, | |||
(KbdCtrlProcPtr)NoopDDA); | |||
} else | |||
#endif | |||
{ | |||
InitKeyboardDeviceStruct(pDev, &keySyms, modMap, | |||
(BellProcPtr)vfbBell, (KbdCtrlProcPtr)NoopDDA); | |||
} | |||
break; | |||
case DEVICE_ON: | |||
pDev->on = TRUE; | |||
break; | |||
case DEVICE_OFF: | |||
pDev->on = FALSE; | |||
break; | |||
case DEVICE_CLOSE: | |||
break; | |||
} | |||
return Success; | |||
} | |||
@@ -123,6 +123,7 @@ private: | |||
void deferUpdate(); | |||
ScreenPtr pScreen; | |||
PointerDevice *pointerDevice; | |||
KeyboardDevice *keyboardDevice; | |||
OsTimerPtr deferredUpdateTimer, dummyTimer; | |||
rfb::VNCServerST* server; | |||
rfb::HTTPServer* httpServer; |