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