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