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