kbd.c revision 79a8a9c6
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
22#define NEED_EVENTS
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#ifdef XINPUT
31#include <X11/extensions/XI.h>
32#include <X11/extensions/XIproto.h>
33#include "extnsionst.h"
34#include "extinit.h"
35#else
36#include "inputstr.h"
37#endif
38
39#include "xf86Xinput.h"
40#include "xf86_OSproc.h"
41#include "xf86OSKbd.h"
42#include "compiler.h"
43
44#ifdef XKB
45#include <X11/extensions/XKB.h>
46#include <X11/extensions/XKBstr.h>
47#include <X11/extensions/XKBsrv.h>
48#endif
49
50extern int XkbDfltRepeatDelay;
51extern int XkbDfltRepeatInterval;
52
53#define CAPSFLAG	1
54#define NUMFLAG		2
55#define SCROLLFLAG	4
56#define MODEFLAG	8
57#define COMPOSEFLAG	16
58/* Used to know when the first DEVICE_ON after a DEVICE_INIT is called */
59#define INITFLAG	(1 << 31)
60
61static InputInfoPtr KbdPreInit(InputDriverPtr drv, IDevPtr dev, int flags);
62static int KbdProc(DeviceIntPtr device, int what);
63static int KbdCtrl(DeviceIntPtr device, KeybdCtrl *ctrl);
64static void KbdBell(int percent, DeviceIntPtr dev, pointer ctrl, int unused);
65static void PostKbdEvent(InputInfoPtr pInfo, unsigned int key, Bool down);
66
67static void InitKBD(InputInfoPtr pInfo, Bool init);
68static void SetXkbOption(InputInfoPtr pInfo, char *name, char **option);
69static void UpdateLeds(InputInfoPtr pInfo);
70
71_X_EXPORT InputDriverRec KBD = {
72	1,
73	"kbd",
74	NULL,
75	KbdPreInit,
76	NULL,
77	NULL,
78	0
79};
80
81_X_EXPORT InputDriverRec KEYBOARD = {
82	1,
83	"keyboard",
84	NULL,
85	KbdPreInit,
86	NULL,
87	NULL,
88	0
89};
90
91typedef enum {
92    OPTION_ALWAYS_CORE,
93    OPTION_SEND_CORE_EVENTS,
94    OPTION_CORE_KEYBOARD,
95    OPTION_DEVICE,
96    OPTION_PROTOCOL,
97    OPTION_AUTOREPEAT,
98    OPTION_XLEDS,
99    OPTION_XKB_DISABLE,
100    OPTION_XKB_KEYMAP,
101    OPTION_XKB_KEYCODES,
102    OPTION_XKB_TYPES,
103    OPTION_XKB_COMPAT,
104    OPTION_XKB_SYMBOLS,
105    OPTION_XKB_GEOMETRY,
106    OPTION_XKB_RULES,
107    OPTION_XKB_MODEL,
108    OPTION_XKB_LAYOUT,
109    OPTION_XKB_VARIANT,
110    OPTION_XKB_OPTIONS,
111    OPTION_PANIX106,
112    OPTION_CUSTOM_KEYCODES
113} KeyboardOpts;
114
115/* These aren't actually used ... */
116static const OptionInfoRec KeyboardOptions[] = {
117    { OPTION_ALWAYS_CORE,	"AlwaysCore",	  OPTV_BOOLEAN,	{0}, FALSE },
118    { OPTION_SEND_CORE_EVENTS,	"SendCoreEvents", OPTV_BOOLEAN,	{0}, FALSE },
119    { OPTION_CORE_KEYBOARD,	"CoreKeyboard",	  OPTV_BOOLEAN,	{0}, FALSE },
120    { OPTION_DEVICE,		"Device",	  OPTV_STRING,	{0}, FALSE },
121    { OPTION_PROTOCOL,		"Protocol",	  OPTV_STRING,	{0}, FALSE },
122    { OPTION_AUTOREPEAT,	"AutoRepeat",	  OPTV_STRING,	{0}, FALSE },
123    { OPTION_XLEDS,		"XLeds",	  OPTV_STRING,	{0}, FALSE },
124    { OPTION_XKB_DISABLE,	"XkbDisable",	  OPTV_BOOLEAN,	{0}, FALSE },
125    { OPTION_XKB_KEYMAP,	"XkbKeymap",	  OPTV_STRING,	{0}, FALSE },
126    { OPTION_XKB_KEYCODES,	"XkbKeycodes",	  OPTV_STRING,	{0}, FALSE },
127    { OPTION_XKB_TYPES,		"XkbTypes",	  OPTV_STRING,	{0}, FALSE },
128    { OPTION_XKB_COMPAT,	"XkbCompat",	  OPTV_STRING,	{0}, FALSE },
129    { OPTION_XKB_SYMBOLS,	"XkbSymbols",	  OPTV_STRING,	{0}, FALSE },
130    { OPTION_XKB_GEOMETRY,	"XkbGeometry",	  OPTV_STRING,	{0}, FALSE },
131    { OPTION_XKB_RULES,		"XkbRules",	  OPTV_STRING,	{0}, FALSE },
132    { OPTION_XKB_MODEL,		"XkbModel",	  OPTV_STRING,	{0}, FALSE },
133    { OPTION_XKB_LAYOUT,	"XkbLayout",	  OPTV_STRING,	{0}, FALSE },
134    { OPTION_XKB_VARIANT,	"XkbVariant",	  OPTV_STRING,	{0}, FALSE },
135    { OPTION_XKB_OPTIONS,	"XkbOptions",	  OPTV_STRING,	{0}, FALSE },
136    { OPTION_PANIX106,		"Panix106",	  OPTV_BOOLEAN,	{0}, FALSE },
137    { OPTION_CUSTOM_KEYCODES,   "CustomKeycodes", OPTV_BOOLEAN,	{0}, FALSE },
138    { -1,			NULL,		  OPTV_NONE,	{0}, FALSE }
139};
140
141static const char *kbdDefaults[] = {
142#ifdef XQUEUE
143    "Protocol",		"Xqueue",
144#else
145    "Protocol",		"standard",
146#endif
147    "AutoRepeat",	"500 30",
148    "XkbRules",		__XKBDEFRULES__,
149    "XkbModel",		"pc105",
150    "XkbLayout",	"us",
151    "Panix106",		"off",
152    "CustomKeycodes",	"off",
153    NULL
154};
155
156static const char *kbd98Defaults[] = {
157#ifdef XQUEUE
158    "Protocol",		"Xqueue",
159#else
160    "Protocol",		"standard",
161#endif
162    "AutoRepeat",	"500 30",
163    "XkbRules",		"xfree98",
164    "XkbModel",		"pc98",
165    "XkbLayout",	"nec/jp",
166    "Panix106",		"off",
167    "CustomKeycodes",	"off",
168    NULL
169};
170
171const char *xkbSymbols[] = {
172	"XkbDfltRepeatDelay",
173	"XkbDfltRepeatInterval",
174	NULL,
175};
176
177#ifdef XKB
178static char *xkb_rules;
179static char *xkb_model;
180static char *xkb_layout;
181static char *xkb_variant;
182static char *xkb_options;
183
184static XkbComponentNamesRec xkbnames;
185#endif /* XKB */
186
187/*ARGSUSED*/
188static const OptionInfoRec *
189KeyboardAvailableOptions(void *unused)
190{
191    return (KeyboardOptions);
192}
193
194static void
195SetXkbOption(InputInfoPtr pInfo, char *name, char **option)
196{
197   char *s;
198
199   if ((s = xf86SetStrOption(pInfo->options, name, NULL))) {
200       if (!s[0]) {
201           xfree(s);
202           *option = NULL;
203       } else {
204           *option = s;
205           xf86Msg(X_CONFIG, "%s: %s: \"%s\"\n", pInfo->name, name, s);
206       }
207    }
208}
209
210
211#define ModifierIsSet(k) ((modifiers & (k)) == (k))
212
213static Bool
214CommonSpecialKey(int key, Bool down, int modifiers)
215{
216  if ((!ModifierIsSet(ShiftMask)) &&
217      (((ModifierIsSet(ControlMask | AltMask)) ||
218        (ModifierIsSet(ControlMask | AltLangMask))))) {
219      switch (key) {
220
221      case KEY_BackSpace:
222	xf86ProcessActionEvent(ACTION_TERMINATE, NULL);
223	break;
224
225	/*
226	 * The idea here is to pass the scancode down to a list of
227	 * registered routines. There should be some standard conventions
228	 * for processing certain keys.
229	 */
230      case KEY_KP_Minus:   /* Keypad - */
231	if (down) xf86ProcessActionEvent(ACTION_PREV_MODE, NULL);
232	break;
233
234      case KEY_KP_Plus:   /* Keypad + */
235	if (down) xf86ProcessActionEvent(ACTION_NEXT_MODE, NULL);
236	break;
237      }
238  }
239  return FALSE;
240}
241
242
243static InputInfoPtr
244KbdPreInit(InputDriverPtr drv, IDevPtr dev, int flags)
245{
246    InputInfoPtr pInfo;
247    KbdDevPtr pKbd;
248    MessageType from = X_DEFAULT;
249    char *s;
250
251    if (!(pInfo = xf86AllocateInput(drv, 0)))
252	return NULL;
253
254    /* Initialise the InputInfoRec. */
255    pInfo->name = dev->identifier;
256    pInfo->type_name = XI_KEYBOARD;
257    pInfo->flags = XI86_KEYBOARD_CAPABLE;
258    pInfo->device_control = KbdProc;
259    /*
260     * We don't specify our own read_input function. We expect
261     * an OS specific readInput() function to handle this.
262     */
263    pInfo->read_input = NULL;
264    pInfo->control_proc = NULL;
265    pInfo->close_proc = NULL;
266    pInfo->switch_mode = NULL;
267    pInfo->conversion_proc = NULL;
268    pInfo->reverse_conversion_proc = NULL;
269    pInfo->fd = -1;
270    pInfo->dev = NULL;
271    pInfo->private_flags = 0;
272    pInfo->always_core_feedback = 0;
273    pInfo->conf_idev = dev;
274
275    if (!xf86IsPc98())
276        xf86CollectInputOptions(pInfo, kbdDefaults, NULL);
277    else
278        xf86CollectInputOptions(pInfo, kbd98Defaults, NULL);
279    xf86ProcessCommonOptions(pInfo, pInfo->options);
280
281    if (!(pKbd = xcalloc(sizeof(KbdDevRec), 1)))
282        return pInfo;
283
284    pInfo->private = pKbd;
285    pKbd->PostEvent = PostKbdEvent;
286
287    xf86LoaderReqSymLists(xkbSymbols, NULL);
288
289    if (!xf86OSKbdPreInit(pInfo))
290        return pInfo;
291
292    if (!pKbd->OpenKeyboard(pInfo)) {
293        return pInfo;
294    }
295
296    if ((s = xf86SetStrOption(pInfo->options, "AutoRepeat", NULL))) {
297        int delay, rate;
298        if (sscanf(s, "%d %d", &delay, &rate) != 2) {
299            xf86Msg(X_ERROR, "\"%s\" is not a valid AutoRepeat value", s);
300        } else {
301            pKbd->delay = delay;
302	    XkbDfltRepeatDelay = delay;
303            pKbd->rate = rate;
304	    XkbDfltRepeatInterval = 1000/rate;
305        }
306        xfree(s);
307    }
308
309    if ((s = xf86SetStrOption(pInfo->options, "XLeds", NULL))) {
310        char *l, *end;
311        unsigned int i;
312        l = strtok(s, " \t\n");
313        while (l) {
314    	    i = strtoul(l, &end, 0);
315    	    if (*end == '\0')
316    	        pKbd->xledsMask |= 1L << (i - 1);
317    	    else {
318    	        xf86Msg(X_ERROR, "\"%s\" is not a valid XLeds value", l);
319    	    }
320    	    l = strtok(NULL, " \t\n");
321        }
322        xfree(s);
323    }
324
325#ifdef XKB
326
327/* XkbDisable must be a server flag but for compatibility we check it here */
328
329  if (xf86FindOption(pInfo->options, "XkbDisable"))
330      xf86Msg(X_WARNING,
331             "%s: XKB can't be disabled here. Use \"ServerFlags\" section.\n",
332              pInfo->name);
333
334  pKbd->noXkb = noXkbExtension;
335  if (pKbd->noXkb) {
336      xf86Msg(X_CONFIG, "XKB: disabled\n");
337  } else {
338      SetXkbOption(pInfo, "XkbKeymap", &xkbnames.keymap);
339      if (xkbnames.keymap) {
340          xf86Msg(X_CONFIG, "%s: XkbKeymap overrides all other XKB settings\n",
341                  pInfo->name);
342      } else {
343          SetXkbOption(pInfo, "XkbRules", &xkb_rules);
344          SetXkbOption(pInfo, "XkbModel", &xkb_model);
345          SetXkbOption(pInfo, "XkbLayout", &xkb_layout);
346          SetXkbOption(pInfo, "XkbVariant", &xkb_variant);
347          SetXkbOption(pInfo, "XkbOptions", &xkb_options);
348
349          SetXkbOption(pInfo, "XkbKeycodes", &xkbnames.keycodes);
350          SetXkbOption(pInfo, "XkbTypes", &xkbnames.types);
351          SetXkbOption(pInfo, "XkbCompat", &xkbnames.compat);
352          SetXkbOption(pInfo, "XkbSymbols", &xkbnames.symbols);
353          SetXkbOption(pInfo, "XkbGeometry", &xkbnames.geometry);
354      }
355  }
356
357  if ((xkb_model && !strcmp(xkb_model, "sun")) ||
358      (xkb_rules && !strcmp(xkb_rules, "sun")))
359       pKbd->sunKbd = TRUE;
360#endif
361
362#if defined(SVR4) && defined(i386)
363  if ((pKbd->Panix106 =
364      xf86SetBoolOption(pInfo->options, "Panix106", FALSE))) {
365      xf86Msg(X_CONFIG, "%s: PANIX106: enabled\n", pInfo->name);
366  }
367#endif
368
369  pKbd->CustomKeycodes = FALSE;
370  from = X_DEFAULT;
371  if (xf86FindOption(pInfo->options, "CustomKeycodes")) {
372      pKbd->CustomKeycodes = xf86SetBoolOption(pInfo->options, "CustomKeycodes",
373                                               pKbd->CustomKeycodes);
374     from = X_CONFIG;
375  }
376
377  xf86Msg(from, "%s: CustomKeycodes %s\n",
378               pInfo->name, pKbd->CustomKeycodes ? "enabled" : "disabled");
379
380  pInfo->flags |= XI86_CONFIGURED;
381
382  return pInfo;
383}
384
385static void
386KbdBell(int percent, DeviceIntPtr dev, pointer ctrl, int unused)
387{
388   InputInfoPtr pInfo = (InputInfoPtr) dev->public.devicePrivate;
389   KbdDevPtr pKbd = (KbdDevPtr) pInfo->private;
390   pKbd->Bell(pInfo, percent, ((KeybdCtrl*) ctrl)->bell_pitch,
391                              ((KeybdCtrl*) ctrl)->bell_duration);
392}
393
394static void
395UpdateLeds(InputInfoPtr pInfo)
396{
397    KbdDevPtr pKbd = (KbdDevPtr) pInfo->private;
398    int leds = 0;
399
400    if (pKbd->keyLeds & CAPSFLAG)    leds |= XLED1;
401    if (pKbd->keyLeds & NUMFLAG)     leds |= XLED2;
402    if (pKbd->keyLeds & SCROLLFLAG ||
403        pKbd->keyLeds & MODEFLAG)    leds |= XLED3;
404    if (pKbd->keyLeds & COMPOSEFLAG) leds |= XLED4;
405
406    pKbd->leds = (pKbd->leds & pKbd->xledsMask) | (leds & ~pKbd->xledsMask);
407    pKbd->SetLeds(pInfo, pKbd->leds);
408}
409
410static int
411KbdCtrl( DeviceIntPtr device, KeybdCtrl *ctrl)
412{
413   int leds;
414   InputInfoPtr pInfo = (InputInfoPtr) device->public.devicePrivate;
415   KbdDevPtr pKbd = (KbdDevPtr) pInfo->private;
416
417   if ( ctrl->leds & XLED1) {
418       pKbd->keyLeds |= CAPSFLAG;
419   } else {
420       pKbd->keyLeds &= ~CAPSFLAG;
421   }
422   if ( ctrl->leds & XLED2) {
423       pKbd->keyLeds |= NUMFLAG;
424   } else {
425       pKbd->keyLeds &= ~NUMFLAG;
426   }
427   if ( ctrl->leds & XLED3) {
428       pKbd->keyLeds |= SCROLLFLAG;
429   } else {
430       pKbd->keyLeds &= ~SCROLLFLAG;
431   }
432   if ( ctrl->leds & (XCOMP|XLED4) ) {
433       pKbd->keyLeds |= COMPOSEFLAG;
434   } else {
435       pKbd->keyLeds &= ~COMPOSEFLAG;
436   }
437   leds = ctrl->leds & ~(XCAPS | XNUM | XSCR); /* ??? */
438#ifdef XKB
439   if (pKbd->noXkb) {
440#endif
441       pKbd->leds = (leds & pKbd->xledsMask) | (pKbd->leds & ~pKbd->xledsMask);
442#ifdef XKB
443  } else {
444       pKbd->leds = leds;
445  }
446#endif
447  pKbd->SetLeds(pInfo, pKbd->leds);
448  pKbd->autoRepeat = ctrl->autoRepeat;
449
450  return (Success);
451}
452
453static void
454InitKBD(InputInfoPtr pInfo, Bool init)
455{
456  char            rad;
457  xEvent          kevent;
458  KbdDevPtr pKbd = (KbdDevPtr) pInfo->private;
459#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) < 1
460  DeviceIntPtr    pKeyboard = pInfo->dev;
461  KeyClassRec     *keyc = pKeyboard->key;
462  KeySym          *map = keyc->curKeySyms.map;
463  unsigned int    i;
464#endif
465
466  kevent.u.keyButtonPointer.time = GetTimeInMillis();
467  kevent.u.keyButtonPointer.rootX = 0;
468  kevent.u.keyButtonPointer.rootY = 0;
469
470/* The server does this for us with i-h. */
471#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) < 1
472  /*
473   * Hmm... here is the biggest hack of every time !
474   * It may be possible that a switch-vt procedure has finished BEFORE
475   * you released all keys neccessary to do this. That peculiar behavior
476   * can fool the X-server pretty much, cause it assumes that some keys
477   * were not released. TWM may stuck alsmost completly....
478   * OK, what we are doing here is after returning from the vt-switch
479   * exeplicitely unrelease all keyboard keys before the input-devices
480   * are reenabled.
481   */
482  for (i = keyc->curKeySyms.minKeyCode, map = keyc->curKeySyms.map;
483       i < keyc->curKeySyms.maxKeyCode;
484       i++, map += keyc->curKeySyms.mapWidth)
485     if (KeyPressed(i))
486      {
487        switch (*map) {
488        /* Don't release the lock keys */
489        case XK_Caps_Lock:
490        case XK_Shift_Lock:
491        case XK_Num_Lock:
492        case XK_Scroll_Lock:
493        case XK_Kana_Lock:
494          break;
495        default:
496          kevent.u.u.detail = i;
497          kevent.u.u.type = KeyRelease;
498          (* pKeyboard->public.processInputProc)(&kevent, pKeyboard, 1);
499        }
500      }
501#endif
502
503  pKbd->scanPrefix      = 0;
504
505  if (init) {
506      pKbd->keyLeds = pKbd->GetLeds(pInfo);
507      UpdateLeds(pInfo);
508      pKbd->keyLeds |= INITFLAG;
509      if( pKbd->delay <= 375) rad = 0x00;
510      else if (pKbd->delay <= 625) rad = 0x20;
511      else if (pKbd->delay <= 875) rad = 0x40;
512      else                         rad = 0x60;
513      if      (pKbd->rate <=  2)   rad |= 0x1F;
514      else if (pKbd->rate >= 30)   rad |= 0x00;
515      else                         rad |= ((58 / pKbd->rate) - 2);
516      pKbd->SetKbdRepeat(pInfo, rad);
517  } else {
518      int leds = pKbd->keyLeds;
519
520      pKbd->keyLeds = pKbd->GetLeds(pInfo);
521      UpdateLeds(pInfo);
522      if ((pKbd->keyLeds & CAPSFLAG) !=
523	  ((leds & INITFLAG) ? 0 : (leds & CAPSFLAG))) {
524	  pKbd->PostEvent(pInfo, KEY_CapsLock, TRUE);
525	  pKbd->PostEvent(pInfo, KEY_CapsLock, FALSE);
526      }
527      if ((pKbd->keyLeds & NUMFLAG) !=
528	  (leds & INITFLAG ? 0 : leds & NUMFLAG)) {
529	  pKbd->PostEvent(pInfo, KEY_NumLock, TRUE);
530	  pKbd->PostEvent(pInfo, KEY_NumLock, FALSE);
531      }
532  }
533}
534
535static int
536KbdProc(DeviceIntPtr device, int what)
537{
538
539  InputInfoPtr pInfo = device->public.devicePrivate;
540  KbdDevPtr pKbd = (KbdDevPtr) pInfo->private;
541  KeySymsRec           keySyms;
542  CARD8                modMap[MAP_LENGTH];
543  int                  ret;
544
545  switch (what) {
546     case DEVICE_INIT:
547        ret = pKbd->KbdInit(pInfo, what);
548	if (ret != Success)
549	    return ret;
550
551        pKbd->KbdGetMapping(pInfo, &keySyms, modMap);
552
553        device->public.on = FALSE;
554#ifdef XKB
555        if (pKbd->noXkb) {
556#endif
557            InitKeyboardDeviceStruct((DevicePtr) device,
558                             &keySyms,
559                             modMap,
560                             KbdBell,
561                             (KbdCtrlProcPtr)KbdCtrl);
562#ifdef XKB
563        } else {
564            if (xkbnames.keymap)
565                xkb_rules = NULL;
566            XkbSetRulesDflts(xkb_rules, xkb_model, xkb_layout,
567                             xkb_variant, xkb_options);
568            XkbInitKeyboardDeviceStruct(device,
569                                        &xkbnames,
570                                        &keySyms,
571                                        modMap,
572                                        KbdBell,
573                                        (KbdCtrlProcPtr)KbdCtrl);
574    }
575#endif
576    InitKBD(pInfo, TRUE);
577    break;
578  case DEVICE_ON:
579    if (device->public.on)
580	break;
581    /*
582     * Set the keyboard into "direct" mode and turn on
583     * event translation.
584     */
585    if ((ret = pKbd->KbdOn(pInfo, what)) != Success)
586	return ret;
587    /*
588     * Discard any pending input after a VT switch to prevent the server
589     * passing on parts of the VT switch sequence.
590     */
591    if (pInfo->fd >= 0) {
592	xf86FlushInput(pInfo->fd);
593	AddEnabledDevice(pInfo->fd);
594    }
595
596    device->public.on = TRUE;
597    InitKBD(pInfo, FALSE);
598    break;
599
600  case DEVICE_CLOSE:
601  case DEVICE_OFF:
602
603    /*
604     * Restore original keyboard directness and translation.
605     */
606    if (pInfo->fd != -1)
607      RemoveEnabledDevice(pInfo->fd);
608    pKbd->KbdOff(pInfo, what);
609    device->public.on = FALSE;
610    break;
611  }
612  return (Success);
613}
614
615static void
616PostKbdEvent(InputInfoPtr pInfo, unsigned int scanCode, Bool down)
617{
618
619  KbdDevPtr    pKbd = (KbdDevPtr) pInfo->private;
620  DeviceIntPtr device = pInfo->dev;
621  KeyClassRec  *keyc = device->key;
622  KbdFeedbackClassRec *kbdfeed = device->kbdfeed;
623  int          specialkey = 0;
624
625  Bool        UsePrefix = FALSE;
626  KeySym      *keysym;
627  int         keycode;
628  unsigned long changeLock = 0;
629  static int  lockkeys = 0;
630
631#ifdef DEBUG
632  ErrorF("kbd driver rec scancode: 0x02%x %s\n", scanCode, down?"down":"up");
633#endif
634
635  /* Disable any keyboard processing while in suspend */
636  if (xf86inSuspend)
637      return;
638
639  if (pKbd->sunKbd) {
640     /*
641      * XXX XXX XXX:
642      *
643      * I really don't know what's wrong here, but passing the real
644      * scanCode offsets by one from XKB's point of view.
645      *
646      * (ecd@skynet.be, 980405)
647      */
648      scanCode--;
649      goto sunKeyboards;
650  }
651
652  /*
653   * First do some special scancode remapping ...
654   */
655  if (pKbd->RemapScanCode != NULL) {
656     if (pKbd->RemapScanCode(pInfo, (int*) &scanCode))
657         return;
658  } else {
659     if (pKbd->scancodeMap != NULL) {
660         TransMapPtr map = pKbd->scancodeMap;
661         if (scanCode >= map->begin && scanCode < map->end)
662             scanCode = map->map[scanCode - map->begin];
663     }
664  }
665
666  /*
667   * and now get some special keysequences
668   */
669
670  specialkey = scanCode;
671
672  if (pKbd->GetSpecialKey != NULL) {
673     specialkey = pKbd->GetSpecialKey(pInfo, scanCode);
674  } else {
675     if (pKbd->specialMap != NULL) {
676         TransMapPtr map = pKbd->specialMap;
677         if (scanCode >= map->begin && scanCode < map->end)
678             specialkey = map->map[scanCode - map->begin];
679     }
680  }
681
682#ifndef TERMINATE_FALLBACK
683#define TERMINATE_FALLBACK 0
684#endif
685#ifdef XKB
686  if (noXkbExtension
687#if TERMINATE_FALLBACK
688      || specialkey == KEY_BackSpace
689#endif
690     )
691#endif
692  {
693      if (CommonSpecialKey(specialkey, down, keyc->state))
694	  return;
695      if (pKbd->SpecialKey != NULL)
696	  if (pKbd->SpecialKey(pInfo, specialkey, down, keyc->state))
697	      return;
698  }
699
700#ifndef __sparc64__
701  /*
702   * PC keyboards generate separate key codes for
703   * Alt+Print and Control+Pause but in the X keyboard model
704   * they need to get the same key code as the base key on the same
705   * physical keyboard key.
706   */
707  if (!xf86IsPc98()) {
708    if (ModifierDown(AltMask) && (scanCode == KEY_SysReqest))
709      scanCode = KEY_Print;
710    else if (scanCode == KEY_Break)
711      scanCode = KEY_Pause;
712  }
713#endif
714
715sunKeyboards:
716  /*
717   * Now map the scancodes to real X-keycodes ...
718   */
719  keycode = scanCode + MIN_KEYCODE;
720  keysym = (keyc->curKeySyms.map +
721	    keyc->curKeySyms.mapWidth *
722	    (keycode - keyc->curKeySyms.minKeyCode));
723
724#ifdef XKB
725  if (pKbd->noXkb) {
726#endif
727  /*
728   * Filter autorepeated caps/num/scroll lock keycodes.
729   */
730  if( down ) {
731    switch( keysym[0] ) {
732        case XK_Caps_Lock :
733          if (lockkeys & CAPSFLAG)
734              return;
735	  else
736	      lockkeys |= CAPSFLAG;
737          break;
738
739        case XK_Num_Lock :
740          if (lockkeys & NUMFLAG)
741              return;
742	  else
743	      lockkeys |= NUMFLAG;
744          break;
745
746        case XK_Scroll_Lock :
747          if (lockkeys & SCROLLFLAG)
748              return;
749	  else
750	      lockkeys |= SCROLLFLAG;
751          break;
752    }
753    if (keysym[1] == XF86XK_ModeLock)
754    {
755      if (lockkeys & MODEFLAG)
756          return;
757      else
758          lockkeys |= MODEFLAG;
759    }
760  }
761  else {
762    switch( keysym[0] ) {
763        case XK_Caps_Lock :
764            lockkeys &= ~CAPSFLAG;
765            break;
766
767        case XK_Num_Lock :
768            lockkeys &= ~NUMFLAG;
769            break;
770
771        case XK_Scroll_Lock :
772            lockkeys &= ~SCROLLFLAG;
773            break;
774    }
775    if (keysym[1] == XF86XK_ModeLock)
776      lockkeys &= ~MODEFLAG;
777  }
778
779  /*
780   * LockKey special handling:
781   * ignore releases, toggle on & off on presses.
782   * Don't deal with the Caps_Lock keysym directly, but check the lock modifier
783   */
784
785   if (keyc->modifierMap[keycode] & LockMask)
786       changeLock = CAPSFLAG;
787   if (keysym[0] == XK_Num_Lock)
788       changeLock = NUMFLAG;
789   if (keysym[0] == XK_Scroll_Lock)
790       changeLock = SCROLLFLAG;
791   if (keysym[1] == XF86XK_ModeLock)
792       changeLock = MODEFLAG;
793
794   if (changeLock) {
795      if (!down)
796          return;
797
798      pKbd->keyLeds &= ~changeLock;
799
800      if (KeyPressed(keycode)) {
801	  down = !down;
802      } else {
803          pKbd->keyLeds |= changeLock;
804      }
805      UpdateLeds(pInfo);
806  }
807
808  if (!pKbd->CustomKeycodes) {
809    /*
810     * normal, non-keypad keys
811     */
812    if (scanCode < KEY_KP_7 || scanCode > KEY_KP_Decimal) {
813#if !defined(CSRG_BASED) && \
814    !defined(__GNU__) && \
815     defined(KB_84)
816      /*
817       * magic ALT_L key on AT84 keyboards for multilingual support
818       */
819      if (pKbd->kbdType == KB_84 &&
820	  ModifierDown(AltMask) &&
821	  keysym[2] != NoSymbol)
822	{
823	  UsePrefix = TRUE;
824	}
825#endif /* !CSRG_BASED && ... */
826    }
827  }
828#ifdef XKB
829  }
830#endif
831
832  /*
833   * check for an autorepeat-event
834   */
835  if (down && KeyPressed(keycode)) {
836      int num = keycode >> 3;
837      int bit = 1 << (keycode & 7);
838
839      if ((pKbd->autoRepeat != AutoRepeatModeOn) ||
840	  keyc->modifierMap[keycode] ||
841	  !(kbdfeed->ctrl.autoRepeats[num] & bit))
842	  return;
843  }
844
845   if (UsePrefix) {
846      xf86PostKeyboardEvent(device,
847              keyc->modifierKeyMap[keyc->maxKeysPerModifier*7], TRUE);
848      xf86PostKeyboardEvent(device, keycode, down);
849      xf86PostKeyboardEvent(device,
850              keyc->modifierKeyMap[keyc->maxKeysPerModifier*7], FALSE);
851   } else {
852      xf86PostKeyboardEvent(device, keycode, down);
853   }
854}
855
856ModuleInfoRec KbdInfo = {
857    1,
858    "KBD",
859    NULL,
860    0,
861    KeyboardAvailableOptions,
862};
863
864static void
865xf86KbdUnplug(pointer	p)
866{
867}
868
869static pointer
870xf86KbdPlug(pointer	module,
871	    pointer	options,
872	    int		*errmaj,
873	    int		*errmin)
874{
875    static Bool Initialised = FALSE;
876
877    if (!Initialised)
878	Initialised = TRUE;
879
880    xf86AddInputDriver(&KBD, module, 0);
881
882    return module;
883}
884
885static XF86ModuleVersionInfo xf86KbdVersionRec =
886{
887    "kbd",
888    MODULEVENDORSTRING,
889    MODINFOSTRING1,
890    MODINFOSTRING2,
891    XORG_VERSION_CURRENT,
892    PACKAGE_VERSION_MAJOR, PACKAGE_VERSION_MINOR, PACKAGE_VERSION_PATCHLEVEL,
893    ABI_CLASS_XINPUT,
894    ABI_XINPUT_VERSION,
895    MOD_CLASS_XINPUT,
896    {0, 0, 0, 0}		/* signature, to be patched into the file by */
897				/* a tool */
898};
899
900_X_EXPORT XF86ModuleData kbdModuleData = {
901    &xf86KbdVersionRec,
902    xf86KbdPlug,
903    xf86KbdUnplug
904};
905