kbd.c revision 557964ce
1/* 2 * Copyright (c) 2002 by The XFree86 Project, Inc. 3 * Author: Ivan Pascal. 4 * 5 * Based on the code from 6 * xf86Config.c which is 7 * Copyright 1991-2002 by The XFree86 Project, Inc. 8 * Copyright 1997 by Metro Link, Inc. 9 * xf86Events.c and xf86Io.c which are 10 * Copyright 1990,91 by Thomas Roell, Dinkelscherben, Germany. 11 */ 12 13#ifdef HAVE_CONFIG_H 14#include "config.h" 15#endif 16 17#include <stdio.h> 18#include <string.h> 19#include <stdlib.h> 20#include <unistd.h> 21#include <xorg-server.h> 22 23#include <X11/X.h> 24#include <X11/Xproto.h> 25 26#include "xf86.h" 27#include "atKeynames.h" 28#include "xf86Privstr.h" 29 30#include <X11/extensions/XI.h> 31#include <X11/extensions/XIproto.h> 32#include "extnsionst.h" 33#include "extinit.h" 34#include "inputstr.h" 35 36#include "xf86Xinput.h" 37#include "xf86_OSproc.h" 38#include "xf86OSKbd.h" 39#include "compiler.h" 40 41#include "xkbstr.h" 42#include "xkbsrv.h" 43 44#define CAPSFLAG 1 45#define NUMFLAG 2 46#define SCROLLFLAG 4 47#define MODEFLAG 8 48#define COMPOSEFLAG 16 49/* Used to know when the first DEVICE_ON after a DEVICE_INIT is called */ 50#define INITFLAG (1U << 31) 51 52static InputInfoPtr KbdPreInit(InputDriverPtr drv, IDevPtr dev, int flags); 53static int KbdProc(DeviceIntPtr device, int what); 54static void KbdCtrl(DeviceIntPtr device, KeybdCtrl *ctrl); 55static void KbdBell(int percent, DeviceIntPtr dev, pointer ctrl, int unused); 56static void PostKbdEvent(InputInfoPtr pInfo, unsigned int key, Bool down); 57 58static void InitKBD(InputInfoPtr pInfo, Bool init); 59static void SetXkbOption(InputInfoPtr pInfo, char *name, char **option); 60static void UpdateLeds(InputInfoPtr pInfo); 61 62_X_EXPORT InputDriverRec KBD = { 63 1, 64 "kbd", 65 NULL, 66 KbdPreInit, 67 NULL, 68 NULL 69}; 70 71_X_EXPORT InputDriverRec KEYBOARD = { 72 1, 73 "keyboard", 74 NULL, 75 KbdPreInit, 76 NULL, 77 NULL 78}; 79 80static const char *kbdDefaults[] = { 81#ifdef __NetBSD__ 82 "Protocol", "wskbd", 83 "Device", "/dev/wskbd", 84#else /* NetBSD */ 85#ifdef XQUEUE 86 "Protocol", "Xqueue", 87#else 88 "Protocol", "standard", 89#endif 90#endif /* NetBSD */ 91 "XkbRules", "base", 92 "XkbModel", "pc105", 93 "XkbLayout", "us", 94 "CustomKeycodes", "off", 95 NULL 96}; 97 98static const char *kbd98Defaults[] = { 99#ifdef XQUEUE 100 "Protocol", "Xqueue", 101#else 102 "Protocol", "standard", 103#endif 104 "XkbRules", "xfree98", 105 "XkbModel", "pc98", 106 "XkbLayout", "jp", 107 "CustomKeycodes", "off", 108 NULL 109}; 110 111static char *xkb_rules; 112static char *xkb_model; 113static char *xkb_layout; 114static char *xkb_variant; 115static char *xkb_options; 116 117static void 118SetXkbOption(InputInfoPtr pInfo, char *name, char **option) 119{ 120 char *s; 121 122 if ((s = xf86SetStrOption(pInfo->options, name, NULL))) { 123 if (!s[0]) { 124 free(s); 125 *option = NULL; 126 } else { 127 *option = s; 128 xf86Msg(X_CONFIG, "%s: %s: \"%s\"\n", pInfo->name, name, s); 129 } 130 } 131} 132 133static InputInfoPtr 134KbdPreInit(InputDriverPtr drv, IDevPtr dev, int flags) 135{ 136 InputInfoPtr pInfo; 137 KbdDevPtr pKbd; 138 MessageType from = X_DEFAULT; 139 char *s; 140 141 if (!(pInfo = xf86AllocateInput(drv, 0))) 142 return NULL; 143 144 /* Initialise the InputInfoRec. */ 145 pInfo->name = dev->identifier; 146 pInfo->type_name = XI_KEYBOARD; 147 pInfo->flags = XI86_KEYBOARD_CAPABLE; 148 pInfo->device_control = KbdProc; 149 /* 150 * We don't specify our own read_input function. We expect 151 * an OS specific readInput() function to handle this. 152 */ 153 pInfo->read_input = NULL; 154 pInfo->control_proc = NULL; 155 pInfo->close_proc = NULL; 156 pInfo->switch_mode = NULL; 157 pInfo->conversion_proc = NULL; 158 pInfo->reverse_conversion_proc = NULL; 159 pInfo->fd = -1; 160 pInfo->dev = NULL; 161 pInfo->private_flags = 0; 162 pInfo->always_core_feedback = NULL; 163 pInfo->conf_idev = dev; 164 165 if (!xf86IsPc98()) 166 xf86CollectInputOptions(pInfo, kbdDefaults, NULL); 167 else 168 xf86CollectInputOptions(pInfo, kbd98Defaults, NULL); 169 xf86ProcessCommonOptions(pInfo, pInfo->options); 170 171 if (!(pKbd = calloc(sizeof(KbdDevRec), 1))) 172 return pInfo; 173 174 pInfo->private = pKbd; 175 pKbd->PostEvent = PostKbdEvent; 176 177 if (!xf86OSKbdPreInit(pInfo)) 178 return pInfo; 179 180 if (!pKbd->OpenKeyboard(pInfo)) { 181 return pInfo; 182 } 183 184 if ((s = xf86SetStrOption(pInfo->options, "XLeds", NULL))) { 185 char *l, *end; 186 unsigned int i; 187 l = strtok(s, " \t\n"); 188 while (l) { 189 i = strtoul(l, &end, 0); 190 if (*end == '\0') 191 pKbd->xledsMask |= 1L << (i - 1); 192 else { 193 xf86Msg(X_ERROR, "\"%s\" is not a valid XLeds value", l); 194 } 195 l = strtok(NULL, " \t\n"); 196 } 197 free(s); 198 } 199 200 SetXkbOption(pInfo, "XkbRules", &xkb_rules); 201 SetXkbOption(pInfo, "XkbModel", &xkb_model); 202 SetXkbOption(pInfo, "XkbLayout", &xkb_layout); 203 SetXkbOption(pInfo, "XkbVariant", &xkb_variant); 204 SetXkbOption(pInfo, "XkbOptions", &xkb_options); 205 206 pKbd->CustomKeycodes = FALSE; 207 from = X_DEFAULT; 208 if (xf86FindOption(pInfo->options, "CustomKeycodes")) { 209 pKbd->CustomKeycodes = xf86SetBoolOption(pInfo->options, "CustomKeycodes", 210 pKbd->CustomKeycodes); 211 from = X_CONFIG; 212 } 213 214 xf86Msg(from, "%s: CustomKeycodes %s\n", 215 pInfo->name, pKbd->CustomKeycodes ? "enabled" : "disabled"); 216 217 pInfo->flags |= XI86_CONFIGURED; 218 219 return pInfo; 220} 221 222static void 223KbdBell(int percent, DeviceIntPtr dev, pointer ctrl, int unused) 224{ 225 InputInfoPtr pInfo = (InputInfoPtr) dev->public.devicePrivate; 226 KbdDevPtr pKbd = (KbdDevPtr) pInfo->private; 227 pKbd->Bell(pInfo, percent, ((KeybdCtrl*) ctrl)->bell_pitch, 228 ((KeybdCtrl*) ctrl)->bell_duration); 229} 230 231static void 232UpdateLeds(InputInfoPtr pInfo) 233{ 234 KbdDevPtr pKbd = (KbdDevPtr) pInfo->private; 235 unsigned long leds = 0; 236 237 if (pKbd->keyLeds & CAPSFLAG) leds |= XLED1; 238 if (pKbd->keyLeds & NUMFLAG) leds |= XLED2; 239 if (pKbd->keyLeds & SCROLLFLAG || 240 pKbd->keyLeds & MODEFLAG) leds |= XLED3; 241 if (pKbd->keyLeds & COMPOSEFLAG) leds |= XLED4; 242 243 pKbd->leds = (pKbd->leds & pKbd->xledsMask) | (leds & ~pKbd->xledsMask); 244 pKbd->SetLeds(pInfo, pKbd->leds); 245} 246 247static void 248KbdCtrl( DeviceIntPtr device, KeybdCtrl *ctrl) 249{ 250 unsigned long leds; 251 InputInfoPtr pInfo = (InputInfoPtr) device->public.devicePrivate; 252 KbdDevPtr pKbd = (KbdDevPtr) pInfo->private; 253 254 if ( ctrl->leds & XLED1) { 255 pKbd->keyLeds |= CAPSFLAG; 256 } else { 257 pKbd->keyLeds &= ~CAPSFLAG; 258 } 259 if ( ctrl->leds & XLED2) { 260 pKbd->keyLeds |= NUMFLAG; 261 } else { 262 pKbd->keyLeds &= ~NUMFLAG; 263 } 264 if ( ctrl->leds & XLED3) { 265 pKbd->keyLeds |= SCROLLFLAG; 266 } else { 267 pKbd->keyLeds &= ~SCROLLFLAG; 268 } 269 if ( ctrl->leds & (XCOMP|XLED4) ) { 270 pKbd->keyLeds |= COMPOSEFLAG; 271 } else { 272 pKbd->keyLeds &= ~COMPOSEFLAG; 273 } 274 leds = ctrl->leds & ~(XCAPS | XNUM | XSCR); /* ??? */ 275 pKbd->leds = leds; 276 pKbd->SetLeds(pInfo, pKbd->leds); 277} 278 279static void 280InitKBD(InputInfoPtr pInfo, Bool init) 281{ 282 xEvent kevent; 283 KbdDevPtr pKbd = (KbdDevPtr) pInfo->private; 284#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) < 1 285 DeviceIntPtr pKeyboard = pInfo->dev; 286 KeyClassRec *keyc = pKeyboard->key; 287 KeySym *map = keyc->curKeySyms.map; 288 unsigned int i; 289#endif 290 291 kevent.u.keyButtonPointer.time = GetTimeInMillis(); 292 kevent.u.keyButtonPointer.rootX = 0; 293 kevent.u.keyButtonPointer.rootY = 0; 294 295/* The server does this for us with i-h. */ 296#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) < 1 297 /* 298 * Hmm... here is the biggest hack of every time ! 299 * It may be possible that a switch-vt procedure has finished BEFORE 300 * you released all keys neccessary to do this. That peculiar behavior 301 * can fool the X-server pretty much, cause it assumes that some keys 302 * were not released. TWM may stuck alsmost completly.... 303 * OK, what we are doing here is after returning from the vt-switch 304 * exeplicitely unrelease all keyboard keys before the input-devices 305 * are reenabled. 306 */ 307 for (i = keyc->curKeySyms.minKeyCode, map = keyc->curKeySyms.map; 308 i < keyc->curKeySyms.maxKeyCode; 309 i++, map += keyc->curKeySyms.mapWidth) 310 if (KeyPressed(i)) 311 { 312 switch (*map) { 313 /* Don't release the lock keys */ 314 case XK_Caps_Lock: 315 case XK_Shift_Lock: 316 case XK_Num_Lock: 317 case XK_Scroll_Lock: 318 case XK_Kana_Lock: 319 break; 320 default: 321 kevent.u.u.detail = i; 322 kevent.u.u.type = KeyRelease; 323 (* pKeyboard->public.processInputProc)(&kevent, pKeyboard, 1); 324 } 325 } 326#endif 327 328 pKbd->scanPrefix = 0; 329 330 if (init) { 331 pKbd->keyLeds = pKbd->GetLeds(pInfo); 332 UpdateLeds(pInfo); 333 pKbd->keyLeds |= INITFLAG; 334 } else { 335 unsigned long leds = pKbd->keyLeds; 336 337 pKbd->keyLeds = pKbd->GetLeds(pInfo); 338 UpdateLeds(pInfo); 339 if ((pKbd->keyLeds & CAPSFLAG) != 340 ((leds & INITFLAG) ? 0 : (leds & CAPSFLAG))) { 341 pKbd->PostEvent(pInfo, KEY_CapsLock, TRUE); 342 pKbd->PostEvent(pInfo, KEY_CapsLock, FALSE); 343 } 344 if ((pKbd->keyLeds & NUMFLAG) != 345 (leds & INITFLAG ? 0 : leds & NUMFLAG)) { 346 pKbd->PostEvent(pInfo, KEY_NumLock, TRUE); 347 pKbd->PostEvent(pInfo, KEY_NumLock, FALSE); 348 } 349 } 350} 351 352static int 353KbdProc(DeviceIntPtr device, int what) 354{ 355 356 InputInfoPtr pInfo = device->public.devicePrivate; 357 KbdDevPtr pKbd = (KbdDevPtr) pInfo->private; 358 KeySymsRec keySyms; 359 CARD8 modMap[MAP_LENGTH]; 360 int ret; 361 362 switch (what) { 363 case DEVICE_INIT: 364 ret = pKbd->KbdInit(pInfo, what); 365 if (ret != Success) 366 return ret; 367 368 pKbd->KbdGetMapping(pInfo, &keySyms, modMap); 369 370 device->public.on = FALSE; 371#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 5 372 { 373 XkbRMLVOSet rmlvo; 374 rmlvo.rules = xkb_rules; 375 rmlvo.model = xkb_model; 376 rmlvo.layout = xkb_layout; 377 rmlvo.variant = xkb_variant; 378 rmlvo.options = xkb_options; 379 380 if (!InitKeyboardDeviceStruct(device, &rmlvo, KbdBell, KbdCtrl)) 381 { 382 xf86Msg(X_ERROR, "%s: Keyboard initialization failed. This " 383 "could be a missing or incorrect setup of " 384 "xkeyboard-config.\n", device->name); 385 386 return BadValue; 387 } 388 } 389#else 390 { 391 XkbComponentNamesRec xkbnames; 392 memset(&xkbnames, 0, sizeof(xkbnames)); 393 XkbSetRulesDflts(xkb_rules, xkb_model, xkb_layout, 394 xkb_variant, xkb_options); 395 XkbInitKeyboardDeviceStruct(device, &xkbnames, &keySyms, 396 modMap, KbdBell, 397 (KbdCtrlProcPtr)KbdCtrl); 398 } 399#endif /* XINPUT ABI 5*/ 400 InitKBD(pInfo, TRUE); 401 break; 402 case DEVICE_ON: 403 if (device->public.on) 404 break; 405 /* 406 * Set the keyboard into "direct" mode and turn on 407 * event translation. 408 */ 409 if ((ret = pKbd->KbdOn(pInfo, what)) != Success) 410 return ret; 411 /* 412 * Discard any pending input after a VT switch to prevent the server 413 * passing on parts of the VT switch sequence. 414 */ 415 if (pInfo->fd >= 0) { 416 xf86FlushInput(pInfo->fd); 417 AddEnabledDevice(pInfo->fd); 418 } 419 420 device->public.on = TRUE; 421 InitKBD(pInfo, FALSE); 422 break; 423 424 case DEVICE_CLOSE: 425 case DEVICE_OFF: 426 427 /* 428 * Restore original keyboard directness and translation. 429 */ 430 if (pInfo->fd != -1) 431 RemoveEnabledDevice(pInfo->fd); 432 pKbd->KbdOff(pInfo, what); 433 device->public.on = FALSE; 434 break; 435 } 436 return (Success); 437} 438 439static void 440PostKbdEvent(InputInfoPtr pInfo, unsigned int scanCode, Bool down) 441{ 442 443 KbdDevPtr pKbd = (KbdDevPtr) pInfo->private; 444 DeviceIntPtr device = pInfo->dev; 445 KeyClassRec *keyc = device->key; 446 447#ifdef DEBUG 448 ErrorF("kbd driver rec scancode: 0x02%x %s\n", scanCode, down?"down":"up"); 449#endif 450 451 /* Disable any keyboard processing while in suspend */ 452 if (xf86inSuspend) 453 return; 454 455 /* 456 * First do some special scancode remapping ... 457 */ 458 if (pKbd->RemapScanCode != NULL) { 459 if (pKbd->RemapScanCode(pInfo, (int*) &scanCode)) 460 return; 461 } else { 462 if (pKbd->scancodeMap != NULL) { 463 TransMapPtr map = pKbd->scancodeMap; 464 if (scanCode >= map->begin && scanCode < map->end) 465 scanCode = map->map[scanCode - map->begin]; 466 } 467 } 468 469 /* 470 * PC keyboards generate separate key codes for 471 * Alt+Print and Control+Pause but in the X keyboard model 472 * they need to get the same key code as the base key on the same 473 * physical keyboard key. 474 */ 475 476 if (!xf86IsPc98()) { 477 int state; 478 479 state = XkbStateFieldFromRec(&keyc->xkbInfo->state); 480 481 if (((state & AltMask) == AltMask) && (scanCode == KEY_SysReqest)) 482 scanCode = KEY_Print; 483 else if (scanCode == KEY_Break) 484 scanCode = KEY_Pause; 485 } 486 487 xf86PostKeyboardEvent(device, scanCode + MIN_KEYCODE, down); 488} 489 490static void 491xf86KbdUnplug(pointer p) 492{ 493} 494 495static pointer 496xf86KbdPlug(pointer module, 497 pointer options, 498 int *errmaj, 499 int *errmin) 500{ 501 xf86AddInputDriver(&KBD, module, 0); 502 503 return module; 504} 505 506static XF86ModuleVersionInfo xf86KbdVersionRec = 507{ 508 "kbd", 509 MODULEVENDORSTRING, 510 MODINFOSTRING1, 511 MODINFOSTRING2, 512 XORG_VERSION_CURRENT, 513 PACKAGE_VERSION_MAJOR, PACKAGE_VERSION_MINOR, PACKAGE_VERSION_PATCHLEVEL, 514 ABI_CLASS_XINPUT, 515 ABI_XINPUT_VERSION, 516 MOD_CLASS_XINPUT, 517 {0, 0, 0, 0} /* signature, to be patched into the file by */ 518 /* a tool */ 519}; 520 521_X_EXPORT XF86ModuleData kbdModuleData = { 522 &xf86KbdVersionRec, 523 xf86KbdPlug, 524 xf86KbdUnplug 525}; 526