| 1 | /* |
| 2 | |
| 3 | Copyright 1993 by Davor Matic |
| 4 | |
| 5 | Permission to use, copy, modify, distribute, and sell this software |
| 6 | and its documentation for any purpose is hereby granted without fee, |
| 7 | provided that the above copyright notice appear in all copies and that |
| 8 | both that copyright notice and this permission notice appear in |
| 9 | supporting documentation. Davor Matic makes no representations about |
| 10 | the suitability of this software for any purpose. It is provided "as |
| 11 | is" without express or implied warranty. |
| 12 | |
| 13 | */ |
| 14 | |
| 15 | #ifdef HAVE_XNEST_CONFIG_H |
| 16 | #include <xnest-config.h> |
| 17 | #endif |
| 18 | |
| 19 | #include <X11/X.h> |
| 20 | #include <X11/Xproto.h> |
| 21 | #include <X11/keysym.h> |
| 22 | #include "screenint.h" |
| 23 | #include "inputstr.h" |
| 24 | #include "misc.h" |
| 25 | #include "scrnintstr.h" |
| 26 | #include "servermd.h" |
| 27 | |
| 28 | #include "Xnest.h" |
| 29 | |
| 30 | #include "Display.h" |
| 31 | #include "Screen.h" |
| 32 | #include "Keyboard.h" |
| 33 | #include "Args.h" |
| 34 | #include "Events.h" |
| 35 | |
| 36 | #include <X11/extensions/XKB.h> |
| 37 | #include "xkbsrv.h" |
| 38 | #include <X11/extensions/XKBconfig.h> |
| 39 | |
| 40 | extern Bool |
| 41 | XkbQueryExtension(Display * /* dpy */ , |
| 42 | int * /* opcodeReturn */ , |
| 43 | int * /* eventBaseReturn */ , |
| 44 | int * /* errorBaseReturn */ , |
| 45 | int * /* majorRtrn */ , |
| 46 | int * /* minorRtrn */ |
| 47 | ); |
| 48 | |
| 49 | extern XkbDescPtr XkbGetKeyboard(Display * /* dpy */ , |
| 50 | unsigned int /* which */ , |
| 51 | unsigned int /* deviceSpec */ |
| 52 | ); |
| 53 | |
| 54 | extern Status XkbGetControls(Display * /* dpy */ , |
| 55 | unsigned long /* which */ , |
| 56 | XkbDescPtr /* desc */ |
| 57 | ); |
| 58 | |
| 59 | DeviceIntPtr xnestKeyboardDevice = NULL; |
| 60 | |
| 61 | void |
| 62 | xnestBell(int volume, DeviceIntPtr pDev, pointer ctrl, int cls) |
| 63 | { |
| 64 | XBell(xnestDisplay, volume); |
| 65 | } |
| 66 | |
| 67 | void |
| 68 | DDXRingBell(int volume, int pitch, int duration) |
| 69 | { |
| 70 | XBell(xnestDisplay, volume); |
| 71 | } |
| 72 | |
| 73 | void |
| 74 | xnestChangeKeyboardControl(DeviceIntPtr pDev, KeybdCtrl * ctrl) |
| 75 | { |
| 76 | #if 0 |
| 77 | unsigned long value_mask; |
| 78 | XKeyboardControl values; |
| 79 | int i; |
| 80 | |
| 81 | value_mask = KBKeyClickPercent | |
| 82 | KBBellPercent | KBBellPitch | KBBellDuration | KBAutoRepeatMode; |
| 83 | |
| 84 | values.key_click_percent = ctrl->click; |
| 85 | values.bell_percent = ctrl->bell; |
| 86 | values.bell_pitch = ctrl->bell_pitch; |
| 87 | values.bell_duration = ctrl->bell_duration; |
| 88 | values.auto_repeat_mode = ctrl->autoRepeat ? |
| 89 | AutoRepeatModeOn : AutoRepeatModeOff; |
| 90 | |
| 91 | XChangeKeyboardControl(xnestDisplay, value_mask, &values); |
| 92 | |
| 93 | /* |
| 94 | value_mask = KBKey | KBAutoRepeatMode; |
| 95 | At this point, we need to walk through the vector and compare it |
| 96 | to the current server vector. If there are differences, report them. |
| 97 | */ |
| 98 | |
| 99 | value_mask = KBLed | KBLedMode; |
| 100 | for (i = 1; i <= 32; i++) { |
| 101 | values.led = i; |
| 102 | values.led_mode = |
| 103 | (ctrl->leds & (1 << (i - 1))) ? LedModeOn : LedModeOff; |
| 104 | XChangeKeyboardControl(xnestDisplay, value_mask, &values); |
| 105 | } |
| 106 | #endif |
| 107 | } |
| 108 | |
| 109 | int |
| 110 | xnestKeyboardProc(DeviceIntPtr pDev, int onoff) |
| 111 | { |
| 112 | XModifierKeymap *modifier_keymap; |
| 113 | KeySym *keymap; |
| 114 | int mapWidth; |
| 115 | int min_keycode, max_keycode; |
| 116 | KeySymsRec keySyms; |
| 117 | CARD8 modmap[MAP_LENGTH]; |
| 118 | int i, j; |
| 119 | XKeyboardState values; |
| 120 | XkbDescPtr xkb; |
| 121 | int op, event, error, major, minor; |
| 122 | |
| 123 | switch (onoff) { |
| 124 | case DEVICE_INIT: |
| 125 | XDisplayKeycodes(xnestDisplay, &min_keycode, &max_keycode); |
| 126 | #ifdef _XSERVER64 |
| 127 | { |
| 128 | KeySym64 *keymap64; |
| 129 | int len; |
| 130 | |
| 131 | keymap64 = XGetKeyboardMapping(xnestDisplay, |
| 132 | min_keycode, |
| 133 | max_keycode - min_keycode + 1, |
| 134 | &mapWidth); |
| 135 | len = (max_keycode - min_keycode + 1) * mapWidth; |
| 136 | keymap = (KeySym *) malloc(len * sizeof(KeySym)); |
| 137 | for (i = 0; i < len; ++i) |
| 138 | keymap[i] = keymap64[i]; |
| 139 | XFree(keymap64); |
| 140 | } |
| 141 | #else |
| 142 | keymap = XGetKeyboardMapping(xnestDisplay, |
| 143 | min_keycode, |
| 144 | max_keycode - min_keycode + 1, &mapWidth); |
| 145 | #endif |
| 146 | |
| 147 | memset(modmap, 0, sizeof(modmap)); |
| 148 | modifier_keymap = XGetModifierMapping(xnestDisplay); |
| 149 | for (j = 0; j < 8; j++) |
| 150 | for (i = 0; i < modifier_keymap->max_keypermod; i++) { |
| 151 | CARD8 keycode; |
| 152 | |
| 153 | if ((keycode = |
| 154 | modifier_keymap->modifiermap[j * |
| 155 | modifier_keymap-> |
| 156 | max_keypermod + i])) |
| 157 | modmap[keycode] |= 1 << j; |
| 158 | } |
| 159 | XFreeModifiermap(modifier_keymap); |
| 160 | |
| 161 | keySyms.minKeyCode = min_keycode; |
| 162 | keySyms.maxKeyCode = max_keycode; |
| 163 | keySyms.mapWidth = mapWidth; |
| 164 | keySyms.map = keymap; |
| 165 | |
| 166 | if (XkbQueryExtension(xnestDisplay, &op, &event, &error, &major, &minor) |
| 167 | == 0) { |
| 168 | ErrorF("Unable to initialize XKEYBOARD extension.\n"); |
| 169 | goto XkbError; |
| 170 | } |
| 171 | xkb = |
| 172 | XkbGetKeyboard(xnestDisplay, XkbGBN_AllComponentsMask, |
| 173 | XkbUseCoreKbd); |
| 174 | if (xkb == NULL || xkb->geom == NULL) { |
| 175 | ErrorF("Couldn't get keyboard.\n"); |
| 176 | goto XkbError; |
| 177 | } |
| 178 | XkbGetControls(xnestDisplay, XkbAllControlsMask, xkb); |
| 179 | |
| 180 | InitKeyboardDeviceStruct(pDev, NULL, |
| 181 | xnestBell, xnestChangeKeyboardControl); |
| 182 | |
| 183 | XkbApplyMappingChange(pDev, &keySyms, keySyms.minKeyCode, |
| 184 | keySyms.maxKeyCode - keySyms.minKeyCode + 1, |
| 185 | modmap, serverClient); |
| 186 | |
| 187 | XkbDDXChangeControls(pDev, xkb->ctrls, xkb->ctrls); |
| 188 | XkbFreeKeyboard(xkb, 0, False); |
| 189 | free(keymap); |
| 190 | break; |
| 191 | case DEVICE_ON: |
| 192 | xnestEventMask |= XNEST_KEYBOARD_EVENT_MASK; |
| 193 | for (i = 0; i < xnestNumScreens; i++) |
| 194 | XSelectInput(xnestDisplay, xnestDefaultWindows[i], xnestEventMask); |
| 195 | break; |
| 196 | case DEVICE_OFF: |
| 197 | xnestEventMask &= ~XNEST_KEYBOARD_EVENT_MASK; |
| 198 | for (i = 0; i < xnestNumScreens; i++) |
| 199 | XSelectInput(xnestDisplay, xnestDefaultWindows[i], xnestEventMask); |
| 200 | break; |
| 201 | case DEVICE_CLOSE: |
| 202 | break; |
| 203 | } |
| 204 | return Success; |
| 205 | |
| 206 | XkbError: |
| 207 | XGetKeyboardControl(xnestDisplay, &values); |
| 208 | memmove((char *) defaultKeyboardControl.autoRepeats, |
| 209 | (char *) values.auto_repeats, sizeof(values.auto_repeats)); |
| 210 | |
| 211 | InitKeyboardDeviceStruct(pDev, NULL, xnestBell, xnestChangeKeyboardControl); |
| 212 | free(keymap); |
| 213 | return Success; |
| 214 | } |
| 215 | |
| 216 | Bool |
| 217 | LegalModifier(unsigned int key, DeviceIntPtr pDev) |
| 218 | { |
| 219 | return TRUE; |
| 220 | } |
| 221 | |
| 222 | void |
| 223 | xnestUpdateModifierState(unsigned int state) |
| 224 | { |
| 225 | DeviceIntPtr pDev = xnestKeyboardDevice; |
| 226 | KeyClassPtr keyc = pDev->key; |
| 227 | int i; |
| 228 | CARD8 mask; |
| 229 | int xkb_state; |
| 230 | |
| 231 | if (!pDev) |
| 232 | return; |
| 233 | |
| 234 | xkb_state = XkbStateFieldFromRec(&pDev->key->xkbInfo->state); |
| 235 | state = state & 0xff; |
| 236 | |
| 237 | if (xkb_state == state) |
| 238 | return; |
| 239 | |
| 240 | for (i = 0, mask = 1; i < 8; i++, mask <<= 1) { |
| 241 | int key; |
| 242 | |
| 243 | /* Modifier is down, but shouldn't be |
| 244 | */ |
| 245 | if ((xkb_state & mask) && !(state & mask)) { |
| 246 | int count = keyc->modifierKeyCount[i]; |
| 247 | |
| 248 | for (key = 0; key < MAP_LENGTH; key++) |
| 249 | if (keyc->xkbInfo->desc->map->modmap[key] & mask) { |
| 250 | if (key_is_down(pDev, key, KEY_PROCESSED)) |
| 251 | xnestQueueKeyEvent(KeyRelease, key); |
| 252 | |
| 253 | if (--count == 0) |
| 254 | break; |
| 255 | } |
| 256 | } |
| 257 | |
| 258 | /* Modifier shoud be down, but isn't |
| 259 | */ |
| 260 | if (!(xkb_state & mask) && (state & mask)) |
| 261 | for (key = 0; key < MAP_LENGTH; key++) |
| 262 | if (keyc->xkbInfo->desc->map->modmap[key] & mask) { |
| 263 | xnestQueueKeyEvent(KeyPress, key); |
| 264 | break; |
| 265 | } |
| 266 | } |
| 267 | } |