X-Git-Url: https://git.sesse.net/?p=rdpsrv;a=blobdiff_plain;f=Xserver%2Fprograms%2FXserver%2Fhw%2Fvnc%2Fkbdptr.c;fp=Xserver%2Fprograms%2FXserver%2Fhw%2Fvnc%2Fkbdptr.c;h=707755dc6cddc7aef0cdb76bae50d1e268f360c1;hp=0000000000000000000000000000000000000000;hb=b6e6afccf37f4ad0515ef2a698f714fdf1bf23b3;hpb=e3340a110a3b01756b8e67531395a33b40a17d37 diff --git a/Xserver/programs/Xserver/hw/vnc/kbdptr.c b/Xserver/programs/Xserver/hw/vnc/kbdptr.c new file mode 100644 index 0000000..707755d --- /dev/null +++ b/Xserver/programs/Xserver/hw/vnc/kbdptr.c @@ -0,0 +1,600 @@ +/* + * kbdptr.c - deal with keyboard and pointer device over TCP & UDP. + * + * + */ + +/* + * Copyright (C) 2002-2003 RealVNC Ltd. + * Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved. + * + * This is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + * USA. + */ + +#include + +#include "X11/X.h" +#define NEED_EVENTS +#include "X11/Xproto.h" +#include "inputstr.h" +#define XK_CYRILLIC +#include +#include +#include +#include +#include +#include "rfb.h" + +extern WindowPtr *WindowTable; /* Why isn't this in a header file? */ + +#define KEY_IS_PRESSED(keycode) \ + (kbdDevice->key->down[(keycode) >> 3] & (1 << ((keycode) & 7))) + + +static void XConvertCase(KeySym sym, KeySym *lower, KeySym *upper); + +static DeviceIntPtr kbdDevice; + +#define MIN_KEY_CODE 8 +#define MAX_KEY_CODE 255 +#define NO_OF_KEYS (MAX_KEY_CODE - MIN_KEY_CODE + 1) +#define GLYPHS_PER_KEY 2 + +static KeySym kbdMap[] = { + + /* Modifiers */ + + XK_Control_L, NoSymbol, +#define CONTROL_L_KEY_CODE MIN_KEY_CODE + + XK_Control_R, NoSymbol, +#define CONTROL_R_KEY_CODE (MIN_KEY_CODE + 1) + + XK_Shift_L, NoSymbol, +#define SHIFT_L_KEY_CODE (MIN_KEY_CODE + 2) + + XK_Shift_R, NoSymbol, +#define SHIFT_R_KEY_CODE (MIN_KEY_CODE + 3) + + XK_Meta_L, NoSymbol, +#define META_L_KEY_CODE (MIN_KEY_CODE + 4) + + XK_Meta_R, NoSymbol, +#define META_R_KEY_CODE (MIN_KEY_CODE + 5) + + XK_Alt_L, NoSymbol, +#define ALT_L_KEY_CODE (MIN_KEY_CODE + 6) + + XK_Alt_R, NoSymbol, +#define ALT_R_KEY_CODE (MIN_KEY_CODE + 7) + + /* Standard US keyboard */ + + XK_space, NoSymbol, + XK_0, XK_parenright, + 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_minus, XK_underscore, + XK_equal, XK_plus, + XK_bracketleft, XK_braceleft, + XK_bracketright, XK_braceright, + XK_semicolon, XK_colon, + XK_apostrophe, XK_quotedbl, + XK_grave, XK_asciitilde, + XK_comma, XK_less, + XK_period, XK_greater, + XK_slash, XK_question, + XK_backslash, XK_bar, + + XK_a, XK_A, + XK_b, XK_B, + XK_c, XK_C, + XK_d, XK_D, + XK_e, XK_E, + XK_f, XK_F, + XK_g, XK_G, + XK_h, XK_H, + XK_i, XK_I, + XK_j, XK_J, + XK_k, XK_K, + XK_l, XK_L, + XK_m, XK_M, + XK_n, XK_N, + XK_o, XK_O, + XK_p, XK_P, + XK_q, XK_Q, + XK_r, XK_R, + XK_s, XK_S, + XK_t, XK_T, + XK_u, XK_U, + XK_v, XK_V, + XK_w, XK_W, + XK_x, XK_X, + XK_y, XK_Y, + XK_z, XK_Z, + + /* Other useful keys */ + + XK_BackSpace, NoSymbol, + XK_Return, NoSymbol, + XK_Tab, NoSymbol, + XK_Escape, NoSymbol, + XK_Delete, NoSymbol, + + XK_Home, NoSymbol, + XK_End, NoSymbol, + XK_Page_Up, NoSymbol, + XK_Page_Down, NoSymbol, + XK_Up, NoSymbol, + XK_Down, NoSymbol, + XK_Left, NoSymbol, + XK_Right, 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_F11, NoSymbol, + XK_F12, NoSymbol, + + /* Plus blank ones which can be filled in using xmodmap */ + +}; + +#define N_PREDEFINED_KEYS (sizeof(kbdMap) / (sizeof(KeySym) * GLYPHS_PER_KEY)) + + +void +PtrDeviceInit() +{ +} + + +void +KbdDeviceInit(pDevice, pKeySyms, pModMap) + DeviceIntPtr pDevice; + KeySymsPtr pKeySyms; + CARD8 *pModMap; +{ + int i; + + kbdDevice = pDevice; + + for (i = 0; i < MAP_LENGTH; i++) + pModMap[i] = NoSymbol; + + pModMap[CONTROL_L_KEY_CODE] = ControlMask; + pModMap[CONTROL_R_KEY_CODE] = ControlMask; + pModMap[SHIFT_L_KEY_CODE] = ShiftMask; + pModMap[SHIFT_R_KEY_CODE] = ShiftMask; + pModMap[META_L_KEY_CODE] = Mod1Mask; + pModMap[META_R_KEY_CODE] = Mod1Mask; + pModMap[ALT_L_KEY_CODE] = Mod1Mask; + pModMap[ALT_R_KEY_CODE] = Mod1Mask; + + pKeySyms->minKeyCode = MIN_KEY_CODE; + pKeySyms->maxKeyCode = MAX_KEY_CODE; + pKeySyms->mapWidth = GLYPHS_PER_KEY; + + pKeySyms->map = (KeySym *)xalloc(sizeof(KeySym) + * MAP_LENGTH * GLYPHS_PER_KEY); + + if (!pKeySyms->map) { + rfbLog("xalloc failed\n"); + exit(1); + } + + for (i = 0; i < MAP_LENGTH * GLYPHS_PER_KEY; i++) + pKeySyms->map[i] = NoSymbol; + + for (i = 0; i < N_PREDEFINED_KEYS * GLYPHS_PER_KEY; i++) { + pKeySyms->map[i] = kbdMap[i]; + } +} + + + +void +KbdDeviceOn() +{ +} + + +void +KbdDeviceOff() +{ +} + + +void +PtrDeviceOn(pDev) + DeviceIntPtr pDev; +{ +} + + +void +PtrDeviceOff() +{ +} + + +void +PtrDeviceControl(dev, ctrl) + DevicePtr dev; + PtrCtrl *ctrl; +{ +} + + +void +KbdAddEvent(down, keySym, cl) + Bool down; + KeySym keySym; + rfbClientPtr cl; +{ + xEvent ev, fake; + KeySymsPtr keySyms = &kbdDevice->key->curKeySyms; + int i; + int keyCode = 0; + int freeIndex = -1; + unsigned long time; + Bool fakeShiftPress = FALSE; + Bool fakeShiftLRelease = FALSE; + Bool fakeShiftRRelease = FALSE; + Bool shiftMustBeReleased = FALSE; + Bool shiftMustBePressed = FALSE; + + if (cl) { + CARD32 clientId = cl->sock; + ChangeWindowProperty(WindowTable[0], VNC_LAST_CLIENT_ID, XA_INTEGER, + 32, PropModeReplace, 1, (pointer)&clientId, TRUE); + } + + if (down) { + if (rfbTrace) rfbLog("KeyPress: 0x%x\n",keySym); + ev.u.u.type = KeyPress; + } else { + ev.u.u.type = KeyRelease; + } + + /* First check if it's one of our predefined keys. If so then we can make + some attempt at allowing an xmodmap inside a VNC desktop behave + something like you'd expect - e.g. if keys A & B are swapped over and + the VNC client sends an A, then map it to a B when generating the X + event. We don't attempt to do this for keycodes which we make up on the + fly because it's too hard... */ + + for (i = 0; i < N_PREDEFINED_KEYS * GLYPHS_PER_KEY; i++) { + if (keySym == kbdMap[i]) { + keyCode = MIN_KEY_CODE + i / GLYPHS_PER_KEY; + + if (kbdMap[(i/GLYPHS_PER_KEY) * GLYPHS_PER_KEY + 1] != NoSymbol) { + + /* this keycode has more than one symbol associated with it, + so shift state is important */ + + if ((i % GLYPHS_PER_KEY) == 0) + shiftMustBeReleased = TRUE; + else + shiftMustBePressed = TRUE; + } + break; + } + } + + if (!keyCode) { + + /* not one of our predefined keys - see if it's in the current keyboard + mapping (i.e. we've already allocated an extra keycode for it) */ + + if (keySyms->mapWidth < 2) { + rfbLog("KbdAddEvent: Sanity check failed - Keyboard mapping has " + "less than 2 keysyms per keycode (KeySym 0x%x)\n", keySym); + return; + } + + for (i = 0; i < NO_OF_KEYS * keySyms->mapWidth; i++) { + if (keySym == keySyms->map[i]) { + keyCode = MIN_KEY_CODE + i / keySyms->mapWidth; + + if (keySyms->map[(i / keySyms->mapWidth) + * keySyms->mapWidth + 1] != NoSymbol) { + + /* this keycode has more than one symbol associated with + it, so shift state is important */ + + if ((i % keySyms->mapWidth) == 0) + shiftMustBeReleased = TRUE; + else + shiftMustBePressed = TRUE; + } + break; + } + if ((freeIndex == -1) && (keySyms->map[i] == NoSymbol) + && (i % keySyms->mapWidth) == 0) + { + freeIndex = i; + } + } + } + + if (!keyCode) { + KeySym lower, upper; + + /* we don't have an existing keycode - make one up on the fly and add + it to the keyboard mapping. Thanks to Vlad Harchev for pointing + out problems with non-ascii capitalisation. */ + + if (freeIndex == -1) { + rfbLog("KbdAddEvent: ignoring KeySym 0x%x - no free KeyCodes\n", + keySym); + return; + } + + keyCode = MIN_KEY_CODE + freeIndex / keySyms->mapWidth; + + XConvertCase(keySym, &lower, &upper); + + if (lower == upper) { + keySyms->map[freeIndex] = keySym; + + } else { + keySyms->map[freeIndex] = lower; + keySyms->map[freeIndex+1] = upper; + + if (keySym == lower) + shiftMustBeReleased = TRUE; + else + shiftMustBePressed = TRUE; + } + + SendMappingNotify(MappingKeyboard, keyCode, 1, serverClient); + + rfbLog("KbdAddEvent: unknown KeySym 0x%x - allocating KeyCode %d\n", + keySym, keyCode); + } + + time = GetTimeInMillis(); + + if (down) { + if (shiftMustBePressed && !(kbdDevice->key->state & ShiftMask)) { + fakeShiftPress = TRUE; + fake.u.u.type = KeyPress; + fake.u.u.detail = SHIFT_L_KEY_CODE; + fake.u.keyButtonPointer.time = time; + mieqEnqueue(&fake); + } + if (shiftMustBeReleased && (kbdDevice->key->state & ShiftMask)) { + if (KEY_IS_PRESSED(SHIFT_L_KEY_CODE)) { + fakeShiftLRelease = TRUE; + fake.u.u.type = KeyRelease; + fake.u.u.detail = SHIFT_L_KEY_CODE; + fake.u.keyButtonPointer.time = time; + mieqEnqueue(&fake); + } + if (KEY_IS_PRESSED(SHIFT_R_KEY_CODE)) { + fakeShiftRRelease = TRUE; + fake.u.u.type = KeyRelease; + fake.u.u.detail = SHIFT_R_KEY_CODE; + fake.u.keyButtonPointer.time = time; + mieqEnqueue(&fake); + } + } + } + + ev.u.u.detail = keyCode; + ev.u.keyButtonPointer.time = time; + mieqEnqueue(&ev); + + if (fakeShiftPress) { + fake.u.u.type = KeyRelease; + fake.u.u.detail = SHIFT_L_KEY_CODE; + fake.u.keyButtonPointer.time = time; + mieqEnqueue(&fake); + } + if (fakeShiftLRelease) { + fake.u.u.type = KeyPress; + fake.u.u.detail = SHIFT_L_KEY_CODE; + fake.u.keyButtonPointer.time = time; + mieqEnqueue(&fake); + } + if (fakeShiftRRelease) { + fake.u.u.type = KeyPress; + fake.u.u.detail = SHIFT_R_KEY_CODE; + fake.u.keyButtonPointer.time = time; + mieqEnqueue(&fake); + } +} + +void +PtrAddEvent(buttonMask, x, y, cl) + int buttonMask; + int x; + int y; + rfbClientPtr cl; +{ + xEvent ev; + int i; + unsigned long time; + static int oldButtonMask = 0; + + if (cl) { + CARD32 clientId = cl->sock; + ChangeWindowProperty(WindowTable[0], VNC_LAST_CLIENT_ID, XA_INTEGER, + 32, PropModeReplace, 1, (pointer)&clientId, TRUE); + } + + time = GetTimeInMillis(); + + miPointerAbsoluteCursor(x, y, time); + + for (i = 0; i < 5; i++) { + if ((buttonMask ^ oldButtonMask) & (1<key->down[i] != 0) { + for (j = 0; j < 8; j++) { + if (kbdDevice->key->down[i] & (1 << j)) { + ev.u.u.type = KeyRelease; + ev.u.u.detail = (i << 3) | j; + ev.u.keyButtonPointer.time = time; + mieqEnqueue(&ev); + } + } + } + } +} + + +/* copied from Xlib source */ + +static void XConvertCase(KeySym sym, KeySym *lower, KeySym *upper) +{ + *lower = sym; + *upper = sym; + switch(sym >> 8) { + case 0: /* Latin 1 */ + if ((sym >= XK_A) && (sym <= XK_Z)) + *lower += (XK_a - XK_A); + else if ((sym >= XK_a) && (sym <= XK_z)) + *upper -= (XK_a - XK_A); + else if ((sym >= XK_Agrave) && (sym <= XK_Odiaeresis)) + *lower += (XK_agrave - XK_Agrave); + else if ((sym >= XK_agrave) && (sym <= XK_odiaeresis)) + *upper -= (XK_agrave - XK_Agrave); + else if ((sym >= XK_Ooblique) && (sym <= XK_Thorn)) + *lower += (XK_oslash - XK_Ooblique); + else if ((sym >= XK_oslash) && (sym <= XK_thorn)) + *upper -= (XK_oslash - XK_Ooblique); + break; + case 1: /* Latin 2 */ + /* Assume the KeySym is a legal value (ignore discontinuities) */ + if (sym == XK_Aogonek) + *lower = XK_aogonek; + else if (sym >= XK_Lstroke && sym <= XK_Sacute) + *lower += (XK_lstroke - XK_Lstroke); + else if (sym >= XK_Scaron && sym <= XK_Zacute) + *lower += (XK_scaron - XK_Scaron); + else if (sym >= XK_Zcaron && sym <= XK_Zabovedot) + *lower += (XK_zcaron - XK_Zcaron); + else if (sym == XK_aogonek) + *upper = XK_Aogonek; + else if (sym >= XK_lstroke && sym <= XK_sacute) + *upper -= (XK_lstroke - XK_Lstroke); + else if (sym >= XK_scaron && sym <= XK_zacute) + *upper -= (XK_scaron - XK_Scaron); + else if (sym >= XK_zcaron && sym <= XK_zabovedot) + *upper -= (XK_zcaron - XK_Zcaron); + else if (sym >= XK_Racute && sym <= XK_Tcedilla) + *lower += (XK_racute - XK_Racute); + else if (sym >= XK_racute && sym <= XK_tcedilla) + *upper -= (XK_racute - XK_Racute); + break; + case 2: /* Latin 3 */ + /* Assume the KeySym is a legal value (ignore discontinuities) */ + if (sym >= XK_Hstroke && sym <= XK_Hcircumflex) + *lower += (XK_hstroke - XK_Hstroke); + else if (sym >= XK_Gbreve && sym <= XK_Jcircumflex) + *lower += (XK_gbreve - XK_Gbreve); + else if (sym >= XK_hstroke && sym <= XK_hcircumflex) + *upper -= (XK_hstroke - XK_Hstroke); + else if (sym >= XK_gbreve && sym <= XK_jcircumflex) + *upper -= (XK_gbreve - XK_Gbreve); + else if (sym >= XK_Cabovedot && sym <= XK_Scircumflex) + *lower += (XK_cabovedot - XK_Cabovedot); + else if (sym >= XK_cabovedot && sym <= XK_scircumflex) + *upper -= (XK_cabovedot - XK_Cabovedot); + break; + case 3: /* Latin 4 */ + /* Assume the KeySym is a legal value (ignore discontinuities) */ + if (sym >= XK_Rcedilla && sym <= XK_Tslash) + *lower += (XK_rcedilla - XK_Rcedilla); + else if (sym >= XK_rcedilla && sym <= XK_tslash) + *upper -= (XK_rcedilla - XK_Rcedilla); + else if (sym == XK_ENG) + *lower = XK_eng; + else if (sym == XK_eng) + *upper = XK_ENG; + else if (sym >= XK_Amacron && sym <= XK_Umacron) + *lower += (XK_amacron - XK_Amacron); + else if (sym >= XK_amacron && sym <= XK_umacron) + *upper -= (XK_amacron - XK_Amacron); + break; + case 6: /* Cyrillic */ + /* Assume the KeySym is a legal value (ignore discontinuities) */ + if (sym >= XK_Serbian_DJE && sym <= XK_Serbian_DZE) + *lower -= (XK_Serbian_DJE - XK_Serbian_dje); + else if (sym >= XK_Serbian_dje && sym <= XK_Serbian_dze) + *upper += (XK_Serbian_DJE - XK_Serbian_dje); + else if (sym >= XK_Cyrillic_YU && sym <= XK_Cyrillic_HARDSIGN) + *lower -= (XK_Cyrillic_YU - XK_Cyrillic_yu); + else if (sym >= XK_Cyrillic_yu && sym <= XK_Cyrillic_hardsign) + *upper += (XK_Cyrillic_YU - XK_Cyrillic_yu); + break; + case 7: /* Greek */ + /* Assume the KeySym is a legal value (ignore discontinuities) */ + if (sym >= XK_Greek_ALPHAaccent && sym <= XK_Greek_OMEGAaccent) + *lower += (XK_Greek_alphaaccent - XK_Greek_ALPHAaccent); + else if (sym >= XK_Greek_alphaaccent && sym <= XK_Greek_omegaaccent && + sym != XK_Greek_iotaaccentdieresis && + sym != XK_Greek_upsilonaccentdieresis) + *upper -= (XK_Greek_alphaaccent - XK_Greek_ALPHAaccent); + else if (sym >= XK_Greek_ALPHA && sym <= XK_Greek_OMEGA) + *lower += (XK_Greek_alpha - XK_Greek_ALPHA); + else if (sym >= XK_Greek_alpha && sym <= XK_Greek_omega && + sym != XK_Greek_finalsmallsigma) + *upper -= (XK_Greek_alpha - XK_Greek_ALPHA); + break; + } +}