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