kbd.c revision 1450c749
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 "exevents.h"
42#include <X11/Xatom.h>
43#include "xserver-properties.h"
44
45#include "xkbstr.h"
46#include "xkbsrv.h"
47
48#define CAPSFLAG	1
49#define NUMFLAG		2
50#define SCROLLFLAG	4
51#define MODEFLAG	8
52#define COMPOSEFLAG	16
53/* Used to know when the first DEVICE_ON after a DEVICE_INIT is called */
54#define INITFLAG	(1U << 31)
55
56#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) < 12
57static InputInfoPtr KbdPreInit(InputDriverPtr drv, IDevPtr dev, int flags);
58#else
59static int KbdPreInit(InputDriverPtr drv, InputInfoPtr pInfo, int flags);
60#endif
61static int KbdProc(DeviceIntPtr device, int what);
62static void KbdCtrl(DeviceIntPtr device, KeybdCtrl *ctrl);
63static void KbdBell(int percent, DeviceIntPtr dev, pointer ctrl, int unused);
64static void PostKbdEvent(InputInfoPtr pInfo, unsigned int key, Bool down);
65
66static void InitKBD(InputInfoPtr pInfo, Bool init);
67static void UpdateLeds(InputInfoPtr pInfo);
68
69_X_EXPORT InputDriverRec KBD = {
70	1,
71	"kbd",
72	NULL,
73	KbdPreInit,
74	NULL,
75	NULL
76};
77
78_X_EXPORT InputDriverRec KEYBOARD = {
79	1,
80	"keyboard",
81	NULL,
82	KbdPreInit,
83	NULL,
84	NULL
85};
86
87static const char *kbdDefaults[] = {
88#ifdef __NetBSD__
89#ifdef DEFAULT_TO_WSKBD
90    "Protocol",		"wskbd",
91#else
92    "Protocol",		"standard",
93#endif
94#else /* NetBSD */
95    "Protocol",		"standard",
96#endif /* NetBSD */
97    "XkbRules",		"base",
98    "XkbModel",		"pc105",
99    "XkbLayout",	"us",
100    NULL
101};
102
103static char *xkb_rules;
104static char *xkb_model;
105static char *xkb_layout;
106static char *xkb_variant;
107static char *xkb_options;
108
109#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) < 12
110static int
111NewKbdPreInit(InputDriverPtr drv, InputInfoPtr pInfo, int flags);
112
113static InputInfoPtr
114KbdPreInit(InputDriverPtr drv, IDevPtr dev, int flags)
115{
116    InputInfoPtr pInfo;
117
118    if (!(pInfo = xf86AllocateInput(drv, 0)))
119	return NULL;
120
121    pInfo->name = dev->identifier;
122    pInfo->flags = XI86_KEYBOARD_CAPABLE;
123    pInfo->conversion_proc = NULL;
124    pInfo->reverse_conversion_proc = NULL;
125    pInfo->private_flags = 0;
126    pInfo->always_core_feedback = NULL;
127    pInfo->conf_idev = dev;
128    pInfo->close_proc = NULL;
129
130    if (NewKbdPreInit(drv, pInfo, flags) == Success)
131    {
132        pInfo->flags |= XI86_CONFIGURED;
133        return pInfo;
134    }
135
136    xf86DeleteInput(pInfo, 0);
137    return NULL;
138}
139
140static int
141NewKbdPreInit(InputDriverPtr drv, InputInfoPtr pInfo, int flags)
142#else
143static int
144KbdPreInit(InputDriverPtr drv, InputInfoPtr pInfo, int flags)
145#endif
146{
147    KbdDevPtr pKbd;
148    char *s;
149    const char **defaults;
150    int rc = Success;
151
152    /* Initialise the InputInfoRec. */
153    pInfo->type_name = XI_KEYBOARD;
154    pInfo->device_control = KbdProc;
155    /*
156     * We don't specify our own read_input function. We expect
157     * an OS specific readInput() function to handle this.
158     */
159    pInfo->read_input = NULL;
160    pInfo->control_proc = NULL;
161    pInfo->switch_mode = NULL;
162    pInfo->fd = -1;
163    pInfo->dev = NULL;
164
165    defaults = kbdDefaults;
166    xf86CollectInputOptions(pInfo, defaults
167#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) < 12
168            , NULL
169#endif
170            );
171    xf86ProcessCommonOptions(pInfo, pInfo->options);
172
173    if (!(pKbd = calloc(sizeof(KbdDevRec), 1))) {
174        rc = BadAlloc;
175        goto out;
176    }
177
178    pInfo->private = pKbd;
179    pKbd->PostEvent = PostKbdEvent;
180
181    if (!xf86OSKbdPreInit(pInfo)) {
182        rc = BadAlloc;
183        goto out;
184    }
185
186    if (!pKbd->OpenKeyboard(pInfo)) {
187        rc = BadMatch;
188        goto out;
189    }
190
191    if ((s = xf86SetStrOption(pInfo->options, "XLeds", NULL))) {
192        char *l, *end;
193        unsigned int i;
194        l = strtok(s, " \t\n");
195        while (l) {
196    	    i = strtoul(l, &end, 0);
197    	    if (*end == '\0')
198    	        pKbd->xledsMask |= 1L << (i - 1);
199    	    else {
200    	        xf86Msg(X_ERROR, "\"%s\" is not a valid XLeds value", l);
201    	    }
202    	    l = strtok(NULL, " \t\n");
203        }
204        free(s);
205    }
206
207    xkb_rules = xf86SetStrOption(pInfo->options, "XkbRules", NULL);
208    xkb_model = xf86SetStrOption(pInfo->options, "XkbModel", NULL);
209    xkb_layout = xf86SetStrOption(pInfo->options, "XkbLayout", NULL);
210    xkb_variant = xf86SetStrOption(pInfo->options, "XkbVariant", NULL);
211    xkb_options = xf86SetStrOption(pInfo->options, "XkbOptions", NULL);
212
213    pKbd->CustomKeycodes = xf86SetBoolOption(pInfo->options, "CustomKeycodes",
214                                             FALSE);
215
216out:
217  return rc;
218}
219
220static void
221KbdBell(int percent, DeviceIntPtr dev, pointer ctrl, int unused)
222{
223   InputInfoPtr pInfo = (InputInfoPtr) dev->public.devicePrivate;
224   KbdDevPtr pKbd = (KbdDevPtr) pInfo->private;
225   pKbd->Bell(pInfo, percent, ((KeybdCtrl*) ctrl)->bell_pitch,
226                              ((KeybdCtrl*) ctrl)->bell_duration);
227}
228
229static void
230UpdateLeds(InputInfoPtr pInfo)
231{
232    KbdDevPtr pKbd = (KbdDevPtr) pInfo->private;
233    unsigned long leds = 0;
234
235    if (pKbd->keyLeds & CAPSFLAG)    leds |= XLED1;
236    if (pKbd->keyLeds & NUMFLAG)     leds |= XLED2;
237    if (pKbd->keyLeds & SCROLLFLAG ||
238        pKbd->keyLeds & MODEFLAG)    leds |= XLED3;
239    if (pKbd->keyLeds & COMPOSEFLAG) leds |= XLED4;
240
241    pKbd->leds = (pKbd->leds & pKbd->xledsMask) | (leds & ~pKbd->xledsMask);
242    pKbd->SetLeds(pInfo, pKbd->leds);
243}
244
245static void
246KbdCtrl( DeviceIntPtr device, KeybdCtrl *ctrl)
247{
248   unsigned long leds;
249   InputInfoPtr pInfo = (InputInfoPtr) device->public.devicePrivate;
250   KbdDevPtr pKbd = (KbdDevPtr) pInfo->private;
251
252   if ( ctrl->leds & XLED1) {
253       pKbd->keyLeds |= CAPSFLAG;
254   } else {
255       pKbd->keyLeds &= ~CAPSFLAG;
256   }
257   if ( ctrl->leds & XLED2) {
258       pKbd->keyLeds |= NUMFLAG;
259   } else {
260       pKbd->keyLeds &= ~NUMFLAG;
261   }
262   if ( ctrl->leds & XLED3) {
263       pKbd->keyLeds |= SCROLLFLAG;
264   } else {
265       pKbd->keyLeds &= ~SCROLLFLAG;
266   }
267   if ( ctrl->leds & (XCOMP|XLED4) ) {
268       pKbd->keyLeds |= COMPOSEFLAG;
269   } else {
270       pKbd->keyLeds &= ~COMPOSEFLAG;
271   }
272   leds = ctrl->leds & ~(XCAPS | XNUM | XSCR); /* ??? */
273   pKbd->leds = leds;
274  pKbd->SetLeds(pInfo, pKbd->leds);
275}
276
277static void
278InitKBD(InputInfoPtr pInfo, Bool init)
279{
280  KbdDevPtr pKbd = (KbdDevPtr) pInfo->private;
281
282  pKbd->scanPrefix      = 0;
283
284  if (init) {
285      pKbd->keyLeds = pKbd->GetLeds(pInfo);
286      UpdateLeds(pInfo);
287      pKbd->keyLeds |= INITFLAG;
288  } else {
289      unsigned long leds = pKbd->keyLeds;
290
291      pKbd->keyLeds = pKbd->GetLeds(pInfo);
292      UpdateLeds(pInfo);
293      if ((pKbd->keyLeds & CAPSFLAG) !=
294	  ((leds & INITFLAG) ? 0 : (leds & CAPSFLAG))) {
295	  pKbd->PostEvent(pInfo, KEY_CapsLock, TRUE);
296	  pKbd->PostEvent(pInfo, KEY_CapsLock, FALSE);
297      }
298      if ((pKbd->keyLeds & NUMFLAG) !=
299	  (leds & INITFLAG ? 0 : leds & NUMFLAG)) {
300	  pKbd->PostEvent(pInfo, KEY_NumLock, TRUE);
301	  pKbd->PostEvent(pInfo, KEY_NumLock, FALSE);
302      }
303  }
304}
305
306static int
307KbdProc(DeviceIntPtr device, int what)
308{
309
310  InputInfoPtr pInfo = device->public.devicePrivate;
311  KbdDevPtr pKbd = (KbdDevPtr) pInfo->private;
312  KeySymsRec           keySyms;
313  CARD8                modMap[MAP_LENGTH];
314  int                  ret;
315
316  switch (what) {
317     case DEVICE_INIT:
318         ret = pKbd->KbdInit(pInfo, what);
319         if (ret != Success)
320             return ret;
321
322         pKbd->KbdGetMapping(pInfo, &keySyms, modMap);
323
324         device->public.on = FALSE;
325#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 5
326         {
327             XkbRMLVOSet rmlvo;
328             rmlvo.rules = xkb_rules;
329             rmlvo.model = xkb_model;
330             rmlvo.layout = xkb_layout;
331             rmlvo.variant = xkb_variant;
332             rmlvo.options = xkb_options;
333
334             if (!InitKeyboardDeviceStruct(device, &rmlvo, KbdBell, KbdCtrl))
335             {
336                 xf86Msg(X_ERROR, "%s: Keyboard initialization failed. This "
337                         "could be a missing or incorrect setup of "
338                         "xkeyboard-config.\n", device->name);
339
340                 return BadValue;
341             }
342         }
343# ifdef XI_PROP_DEVICE_NODE
344         {
345             const char *device_node =
346                 xf86CheckStrOption(pInfo->options, "Device", NULL);
347
348             if (device_node)
349             {
350                 Atom prop_device = MakeAtom(XI_PROP_DEVICE_NODE,
351                                             strlen(XI_PROP_DEVICE_NODE), TRUE);
352                 XIChangeDeviceProperty(device, prop_device, XA_STRING, 8,
353                                        PropModeReplace, strlen(device_node),
354                                        device_node, FALSE);
355             }
356         }
357# endif /* XI_PROP_DEVICE_NODE */
358#else
359         {
360             XkbComponentNamesRec xkbnames;
361             memset(&xkbnames, 0, sizeof(xkbnames));
362             XkbSetRulesDflts(xkb_rules, xkb_model, xkb_layout,
363                              xkb_variant, xkb_options);
364             XkbInitKeyboardDeviceStruct(device, &xkbnames, &keySyms,
365                                         modMap, KbdBell,
366                                         (KbdCtrlProcPtr)KbdCtrl);
367         }
368#endif /* XINPUT ABI 5*/
369         InitKBD(pInfo, TRUE);
370         break;
371  case DEVICE_ON:
372    if (device->public.on)
373	break;
374    /*
375     * Set the keyboard into "direct" mode and turn on
376     * event translation.
377     */
378    if ((ret = pKbd->KbdOn(pInfo, what)) != Success)
379	return ret;
380    /*
381     * Discard any pending input after a VT switch to prevent the server
382     * passing on parts of the VT switch sequence.
383     */
384    if (pInfo->fd >= 0) {
385	xf86FlushInput(pInfo->fd);
386	AddEnabledDevice(pInfo->fd);
387    }
388
389    device->public.on = TRUE;
390    InitKBD(pInfo, FALSE);
391    break;
392
393  case DEVICE_CLOSE:
394  case DEVICE_OFF:
395
396    /*
397     * Restore original keyboard directness and translation.
398     */
399    if (pInfo->fd != -1)
400      RemoveEnabledDevice(pInfo->fd);
401    pKbd->KbdOff(pInfo, what);
402    device->public.on = FALSE;
403    break;
404
405  default:
406    return BadValue;
407  }
408  return (Success);
409}
410
411static void
412PostKbdEvent(InputInfoPtr pInfo, unsigned int scanCode, Bool down)
413{
414
415  KbdDevPtr    pKbd = (KbdDevPtr) pInfo->private;
416  DeviceIntPtr device = pInfo->dev;
417  KeyClassRec  *keyc = device->key;
418  int state;
419
420#ifdef DEBUG
421  LogMessageVerbSigSafe(X_INFO, -1, "kbd driver rec scancode: 0x%x %s\n", scanCode, down ? "down" : "up");
422#endif
423
424  /*
425   * First do some special scancode remapping ...
426   */
427  if (pKbd->RemapScanCode != NULL) {
428     if (pKbd->RemapScanCode(pInfo, (int*) &scanCode))
429         return;
430  } else {
431     if (pKbd->scancodeMap != NULL) {
432         TransMapPtr map = pKbd->scancodeMap;
433         if (scanCode >= map->begin && scanCode < map->end)
434             scanCode = map->map[scanCode - map->begin];
435     }
436  }
437
438  /*
439   * PC keyboards generate separate key codes for
440   * Alt+Print and Control+Pause but in the X keyboard model
441   * they need to get the same key code as the base key on the same
442   * physical keyboard key.
443   */
444
445  state = XkbStateFieldFromRec(&keyc->xkbInfo->state);
446
447  if (((state & AltMask) == AltMask) && (scanCode == KEY_SysReqest))
448    scanCode = KEY_Print;
449  else if (scanCode == KEY_Break)
450    scanCode = KEY_Pause;
451
452  xf86PostKeyboardEvent(device, scanCode + MIN_KEYCODE, down);
453}
454
455static void
456xf86KbdUnplug(pointer	p)
457{
458}
459
460static pointer
461xf86KbdPlug(pointer	module,
462	    pointer	options,
463	    int		*errmaj,
464	    int		*errmin)
465{
466    xf86AddInputDriver(&KBD, module, 0);
467
468    return module;
469}
470
471static XF86ModuleVersionInfo xf86KbdVersionRec =
472{
473    "kbd",
474    MODULEVENDORSTRING,
475    MODINFOSTRING1,
476    MODINFOSTRING2,
477    XORG_VERSION_CURRENT,
478    PACKAGE_VERSION_MAJOR, PACKAGE_VERSION_MINOR, PACKAGE_VERSION_PATCHLEVEL,
479    ABI_CLASS_XINPUT,
480    ABI_XINPUT_VERSION,
481    MOD_CLASS_XINPUT,
482    {0, 0, 0, 0}		/* signature, to be patched into the file by */
483				/* a tool */
484};
485
486_X_EXPORT XF86ModuleData kbdModuleData = {
487    &xf86KbdVersionRec,
488    xf86KbdPlug,
489    xf86KbdUnplug
490};
491