Commit | Line | Data |
---|---|---|
a09e091a JB |
1 | /* Portions of this file were derived from the following files: |
2 | * | |
3 | ********************************************************************** | |
4 | * | |
5 | * xfree86/common/{xf86Io.c,xf86Kbd.c,xf86Events.c} | |
6 | * | |
7 | * Copyright 1990,91 by Thomas Roell, Dinkelscherben, Germany. | |
8 | * | |
9 | * Permission to use, copy, modify, distribute, and sell this software and its | |
10 | * documentation for any purpose is hereby granted without fee, provided that | |
11 | * the above copyright notice appear in all copies and that both that | |
12 | * copyright notice and this permission notice appear in supporting | |
13 | * documentation, and that the name of Thomas Roell not be used in | |
14 | * advertising or publicity pertaining to distribution of the software without | |
15 | * specific, written prior permission. Thomas Roell makes no representations | |
16 | * about the suitability of this software for any purpose. It is provided | |
17 | * "as is" without express or implied warranty. | |
18 | * | |
19 | * THOMAS ROELL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, | |
20 | * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO | |
21 | * EVENT SHALL THOMAS ROELL BE LIABLE FOR ANY SPECIAL, INDIRECT OR | |
22 | * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, | |
23 | * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER | |
24 | * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR | |
25 | * PERFORMANCE OF THIS SOFTWARE. | |
26 | * | |
27 | ********************************************************************** | |
28 | * | |
29 | * xfree86/common/xf86KbdLnx.c | |
30 | * | |
31 | * Linux version of keymapping setup. The kernel (since 0.99.14) has support | |
32 | * for fully remapping the keyboard, but there are some differences between | |
33 | * the Linux map and the SVR4 map (esp. in the extended keycodes). We also | |
34 | * remove the restriction on what keycodes can be remapped. | |
35 | * Orest Zborowski. | |
36 | * | |
37 | * Copyright 1990,91 by Thomas Roell, Dinkelscherben, Germany. | |
38 | * | |
39 | * Permission to use, copy, modify, distribute, and sell this software and its | |
40 | * documentation for any purpose is hereby granted without fee, provided that | |
41 | * the above copyright notice appear in all copies and that both that | |
42 | * copyright notice and this permission notice appear in supporting | |
43 | * documentation, and that the name of Thomas Roell not be used in | |
44 | * advertising or publicity pertaining to distribution of the software without | |
45 | * specific, written prior permission. Thomas Roell makes no representations | |
46 | * about the suitability of this software for any purpose. It is provided | |
47 | * "as is" without express or implied warranty. | |
48 | * | |
49 | * THOMAS ROELL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, | |
50 | * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO | |
51 | * EVENT SHALL THOMAS ROELL BE LIABLE FOR ANY SPECIAL, INDIRECT OR | |
52 | * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, | |
53 | * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER | |
54 | * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR | |
55 | * PERFORMANCE OF THIS SOFTWARE. | |
56 | * | |
57 | ********************************************************************** | |
58 | * | |
59 | * xfree86/os-support/linux/lnx_io.c | |
60 | * | |
61 | * Copyright 1992 by Orest Zborowski <obz@Kodak.com> | |
62 | * Copyright 1993 by David Dawes <dawes@xfree86.org> | |
63 | * | |
64 | * Permission to use, copy, modify, distribute, and sell this software and its | |
65 | * documentation for any purpose is hereby granted without fee, provided that | |
66 | * the above copyright notice appear in all copies and that both that | |
67 | * copyright notice and this permission notice appear in supporting | |
68 | * documentation, and that the names of Orest Zborowski and David Dawes | |
69 | * not be used in advertising or publicity pertaining to distribution of | |
70 | * the software without specific, written prior permission. Orest Zborowski | |
71 | * and David Dawes make no representations about the suitability of this | |
72 | * software for any purpose. It is provided "as is" without express or | |
73 | * implied warranty. | |
74 | * | |
75 | * OREST ZBOROWSKI AND DAVID DAWES DISCLAIMS ALL WARRANTIES WITH REGARD | |
76 | * TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND | |
77 | * FITNESS, IN NO EVENT SHALL OREST ZBOROWSKI OR DAVID DAWES BE LIABLE | |
78 | * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |
79 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |
80 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |
81 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |
82 | * | |
83 | */ | |
84 | ||
85 | /* | |
86 | * Copyright 2001-2003 Red Hat Inc., Durham, North Carolina. | |
87 | * | |
88 | * All Rights Reserved. | |
89 | * | |
90 | * Permission is hereby granted, free of charge, to any person obtaining | |
91 | * a copy of this software and associated documentation files (the | |
92 | * "Software"), to deal in the Software without restriction, including | |
93 | * without limitation on the rights to use, copy, modify, merge, | |
94 | * publish, distribute, sublicense, and/or sell copies of the Software, | |
95 | * and to permit persons to whom the Software is furnished to do so, | |
96 | * subject to the following conditions: | |
97 | * | |
98 | * The above copyright notice and this permission notice (including the | |
99 | * next paragraph) shall be included in all copies or substantial | |
100 | * portions of the Software. | |
101 | * | |
102 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | |
103 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | |
104 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | |
105 | * NON-INFRINGEMENT. IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS | |
106 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN | |
107 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | |
108 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |
109 | * SOFTWARE. | |
110 | */ | |
111 | ||
112 | /* | |
113 | * Authors: | |
114 | * Rickard E. (Rik) Faith <faith@redhat.com> | |
115 | * | |
116 | */ | |
117 | ||
118 | /** \file | |
119 | * | |
120 | * This code implements a low-level device driver for the Linux | |
121 | * keyboard. The code is derived from code by Thomas Roell, Orest | |
122 | * Zborowski, and David Dawes (see the source code for complete | |
123 | * references). */ | |
124 | ||
125 | #ifdef HAVE_DMX_CONFIG_H | |
126 | #include <dmx-config.h> | |
127 | #endif | |
128 | ||
129 | /*****************************************************************************/ | |
130 | /* Define some macros to make it easier to move this file to another | |
131 | * part of the Xserver tree. All calls to the dmx* layer are #defined | |
132 | * here for the .c file. The .h file will also have to be edited. */ | |
133 | #include "dmxinputinit.h" | |
134 | #include "lnx-keyboard.h" | |
135 | ||
136 | #define GETPRIV myPrivate *priv \ | |
137 | = ((DMXLocalInputInfoPtr)(pDev->devicePrivate))->private | |
138 | ||
139 | #define LOG0(f) dmxLog(dmxDebug,f) | |
140 | #define LOG1(f,a) dmxLog(dmxDebug,f,a) | |
141 | #define LOG2(f,a,b) dmxLog(dmxDebug,f,a,b) | |
142 | #define LOG3(f,a,b,c) dmxLog(dmxDebug,f,a,b,c) | |
143 | #define FATAL0(f) dmxLog(dmxFatal,f) | |
144 | #define FATAL1(f,a) dmxLog(dmxFatal,f,a) | |
145 | #define FATAL2(f,a,b) dmxLog(dmxFatal,f,a,b) | |
146 | #define MOTIONPROC dmxMotionProcPtr | |
147 | #define ENQUEUEPROC dmxEnqueueProcPtr | |
148 | #define CHECKPROC dmxCheckSpecialProcPtr | |
149 | #define SWITCHRETPROC dmxVTSwitchReturnProcPtr | |
150 | #define BLOCK DMXBlockType | |
151 | #define MESSAGE "\033c\n\n\nDMX taking input from this console..." | |
152 | #define FINALMESSAGE "\033cDMX terminated." | |
153 | ||
154 | /* End of interface definitions. */ | |
155 | /*****************************************************************************/ | |
156 | ||
157 | #include "inputstr.h" | |
158 | #include <X11/Xos.h> | |
159 | #include <sys/ioctl.h> | |
160 | #include <errno.h> | |
161 | #include <signal.h> | |
162 | #include <sys/vt.h> | |
163 | #include <sys/kd.h> | |
164 | #include <termios.h> | |
165 | #include "atKeynames.h" | |
166 | #if 00 | |
167 | #include "xf86Keymap.h" | |
168 | #endif | |
169 | #include <linux/keyboard.h> | |
170 | #include <xkbsrv.h> | |
171 | ||
172 | #define NUM_AT2LNX (sizeof(at2lnx) / sizeof(at2lnx[0])) | |
173 | #define NUM_STATE_ENTRIES (256/32) | |
174 | ||
175 | /* Private area for Linux-style keyboards. */ | |
176 | typedef struct _myPrivate { | |
177 | int fd; | |
178 | int vtno; | |
179 | int vtcurrent; | |
180 | int kbdtrans; | |
181 | struct termios kbdtty; | |
182 | int kbdType; | |
183 | CARD32 kbdState[NUM_STATE_ENTRIES]; | |
184 | DeviceIntPtr pKeyboard; | |
185 | unsigned char prefix; | |
186 | ||
187 | int switched; | |
188 | SWITCHRETPROC switch_return; | |
189 | void *switch_return_data; | |
190 | ||
191 | /* For bell */ | |
192 | int pitch; | |
193 | unsigned long duration; | |
194 | } myPrivate; | |
195 | ||
196 | static myPrivate *PRIV = NULL; | |
197 | ||
198 | #undef SYSCALL | |
199 | #define SYSCALL(call) while(((call) == -1) && (errno == EINTR)) | |
200 | ||
201 | static int | |
202 | kbdLinuxKeyDown(myPrivate * priv, int keyCode) | |
203 | { | |
204 | CARD8 byte = keyCode >> 5; | |
205 | CARD32 bit = 1 << (keyCode & 0x1f); | |
206 | ||
207 | if (byte > NUM_STATE_ENTRIES) | |
208 | return 0; | |
209 | return priv->kbdState[byte] & bit; | |
210 | } | |
211 | ||
212 | static void | |
213 | kbdLinuxKeyState(myPrivate * priv, int type, int keyCode) | |
214 | { | |
215 | CARD8 byte = keyCode >> 5; | |
216 | CARD32 bit = 1 << (keyCode & 0x1f); | |
217 | ||
218 | if (byte > NUM_STATE_ENTRIES) | |
219 | return; | |
220 | if (type == KeyPress) | |
221 | priv->kbdState[byte] |= bit; | |
222 | else | |
223 | priv->kbdState[byte] &= ~bit; | |
224 | } | |
225 | ||
226 | static KeySym linux_to_x[256] = { | |
227 | NoSymbol, NoSymbol, NoSymbol, NoSymbol, | |
228 | NoSymbol, NoSymbol, NoSymbol, NoSymbol, | |
229 | XK_BackSpace, XK_Tab, XK_Linefeed, NoSymbol, | |
230 | NoSymbol, NoSymbol, NoSymbol, NoSymbol, | |
231 | NoSymbol, NoSymbol, NoSymbol, NoSymbol, | |
232 | NoSymbol, NoSymbol, NoSymbol, NoSymbol, | |
233 | NoSymbol, NoSymbol, NoSymbol, XK_Escape, | |
234 | NoSymbol, NoSymbol, NoSymbol, NoSymbol, | |
235 | XK_space, XK_exclam, XK_quotedbl, XK_numbersign, | |
236 | XK_dollar, XK_percent, XK_ampersand, XK_apostrophe, | |
237 | XK_parenleft, XK_parenright, XK_asterisk, XK_plus, | |
238 | XK_comma, XK_minus, XK_period, XK_slash, | |
239 | XK_0, XK_1, XK_2, XK_3, | |
240 | XK_4, XK_5, XK_6, XK_7, | |
241 | XK_8, XK_9, XK_colon, XK_semicolon, | |
242 | XK_less, XK_equal, XK_greater, XK_question, | |
243 | XK_at, XK_A, XK_B, XK_C, | |
244 | XK_D, XK_E, XK_F, XK_G, | |
245 | XK_H, XK_I, XK_J, XK_K, | |
246 | XK_L, XK_M, XK_N, XK_O, | |
247 | XK_P, XK_Q, XK_R, XK_S, | |
248 | XK_T, XK_U, XK_V, XK_W, | |
249 | XK_X, XK_Y, XK_Z, XK_bracketleft, | |
250 | XK_backslash, XK_bracketright, XK_asciicircum, XK_underscore, | |
251 | XK_grave, XK_a, XK_b, XK_c, | |
252 | XK_d, XK_e, XK_f, XK_g, | |
253 | XK_h, XK_i, XK_j, XK_k, | |
254 | XK_l, XK_m, XK_n, XK_o, | |
255 | XK_p, XK_q, XK_r, XK_s, | |
256 | XK_t, XK_u, XK_v, XK_w, | |
257 | XK_x, XK_y, XK_z, XK_braceleft, | |
258 | XK_bar, XK_braceright, XK_asciitilde, XK_BackSpace, | |
259 | NoSymbol, NoSymbol, NoSymbol, NoSymbol, | |
260 | NoSymbol, NoSymbol, NoSymbol, NoSymbol, | |
261 | NoSymbol, NoSymbol, NoSymbol, NoSymbol, | |
262 | NoSymbol, NoSymbol, NoSymbol, NoSymbol, | |
263 | NoSymbol, NoSymbol, NoSymbol, NoSymbol, | |
264 | NoSymbol, NoSymbol, NoSymbol, NoSymbol, | |
265 | NoSymbol, NoSymbol, NoSymbol, NoSymbol, | |
266 | NoSymbol, NoSymbol, NoSymbol, NoSymbol, | |
267 | XK_nobreakspace, XK_exclamdown, XK_cent, XK_sterling, | |
268 | XK_currency, XK_yen, XK_brokenbar, XK_section, | |
269 | XK_diaeresis, XK_copyright, XK_ordfeminine, XK_guillemotleft, | |
270 | XK_notsign, XK_hyphen, XK_registered, XK_macron, | |
271 | XK_degree, XK_plusminus, XK_twosuperior, XK_threesuperior, | |
272 | XK_acute, XK_mu, XK_paragraph, XK_periodcentered, | |
273 | XK_cedilla, XK_onesuperior, XK_masculine, XK_guillemotright, | |
274 | XK_onequarter, XK_onehalf, XK_threequarters, XK_questiondown, | |
275 | XK_Agrave, XK_Aacute, XK_Acircumflex, XK_Atilde, | |
276 | XK_Adiaeresis, XK_Aring, XK_AE, XK_Ccedilla, | |
277 | XK_Egrave, XK_Eacute, XK_Ecircumflex, XK_Ediaeresis, | |
278 | XK_Igrave, XK_Iacute, XK_Icircumflex, XK_Idiaeresis, | |
279 | XK_ETH, XK_Ntilde, XK_Ograve, XK_Oacute, | |
280 | XK_Ocircumflex, XK_Otilde, XK_Odiaeresis, XK_multiply, | |
281 | XK_Ooblique, XK_Ugrave, XK_Uacute, XK_Ucircumflex, | |
282 | XK_Udiaeresis, XK_Yacute, XK_THORN, XK_ssharp, | |
283 | XK_agrave, XK_aacute, XK_acircumflex, XK_atilde, | |
284 | XK_adiaeresis, XK_aring, XK_ae, XK_ccedilla, | |
285 | XK_egrave, XK_eacute, XK_ecircumflex, XK_ediaeresis, | |
286 | XK_igrave, XK_iacute, XK_icircumflex, XK_idiaeresis, | |
287 | XK_eth, XK_ntilde, XK_ograve, XK_oacute, | |
288 | XK_ocircumflex, XK_otilde, XK_odiaeresis, XK_division, | |
289 | XK_oslash, XK_ugrave, XK_uacute, XK_ucircumflex, | |
290 | XK_udiaeresis, XK_yacute, XK_thorn, XK_ydiaeresis | |
291 | }; | |
292 | ||
293 | /* | |
294 | * Maps the AT keycodes to Linux keycodes | |
295 | */ | |
296 | static unsigned char at2lnx[NUM_KEYCODES] = { | |
297 | 0x01, /* KEY_Escape */ 0x02, /* KEY_1 */ | |
298 | 0x03, /* KEY_2 */ 0x04, /* KEY_3 */ | |
299 | 0x05, /* KEY_4 */ 0x06, /* KEY_5 */ | |
300 | 0x07, /* KEY_6 */ 0x08, /* KEY_7 */ | |
301 | 0x09, /* KEY_8 */ 0x0a, /* KEY_9 */ | |
302 | 0x0b, /* KEY_0 */ 0x0c, /* KEY_Minus */ | |
303 | 0x0d, /* KEY_Equal */ 0x0e, /* KEY_BackSpace */ | |
304 | 0x0f, /* KEY_Tab */ 0x10, /* KEY_Q */ | |
305 | 0x11, /* KEY_W */ 0x12, /* KEY_E */ | |
306 | 0x13, /* KEY_R */ 0x14, /* KEY_T */ | |
307 | 0x15, /* KEY_Y */ 0x16, /* KEY_U */ | |
308 | 0x17, /* KEY_I */ 0x18, /* KEY_O */ | |
309 | 0x19, /* KEY_P */ 0x1a, /* KEY_LBrace */ | |
310 | 0x1b, /* KEY_RBrace */ 0x1c, /* KEY_Enter */ | |
311 | 0x1d, /* KEY_LCtrl */ 0x1e, /* KEY_A */ | |
312 | 0x1f, /* KEY_S */ 0x20, /* KEY_D */ | |
313 | 0x21, /* KEY_F */ 0x22, /* KEY_G */ | |
314 | 0x23, /* KEY_H */ 0x24, /* KEY_J */ | |
315 | 0x25, /* KEY_K */ 0x26, /* KEY_L */ | |
316 | 0x27, /* KEY_SemiColon */ 0x28, /* KEY_Quote */ | |
317 | 0x29, /* KEY_Tilde */ 0x2a, /* KEY_ShiftL */ | |
318 | 0x2b, /* KEY_BSlash */ 0x2c, /* KEY_Z */ | |
319 | 0x2d, /* KEY_X */ 0x2e, /* KEY_C */ | |
320 | 0x2f, /* KEY_V */ 0x30, /* KEY_B */ | |
321 | 0x31, /* KEY_N */ 0x32, /* KEY_M */ | |
322 | 0x33, /* KEY_Comma */ 0x34, /* KEY_Period */ | |
323 | 0x35, /* KEY_Slash */ 0x36, /* KEY_ShiftR */ | |
324 | 0x37, /* KEY_KP_Multiply */ 0x38, /* KEY_Alt */ | |
325 | 0x39, /* KEY_Space */ 0x3a, /* KEY_CapsLock */ | |
326 | 0x3b, /* KEY_F1 */ 0x3c, /* KEY_F2 */ | |
327 | 0x3d, /* KEY_F3 */ 0x3e, /* KEY_F4 */ | |
328 | 0x3f, /* KEY_F5 */ 0x40, /* KEY_F6 */ | |
329 | 0x41, /* KEY_F7 */ 0x42, /* KEY_F8 */ | |
330 | 0x43, /* KEY_F9 */ 0x44, /* KEY_F10 */ | |
331 | 0x45, /* KEY_NumLock */ 0x46, /* KEY_ScrollLock */ | |
332 | 0x47, /* KEY_KP_7 */ 0x48, /* KEY_KP_8 */ | |
333 | 0x49, /* KEY_KP_9 */ 0x4a, /* KEY_KP_Minus */ | |
334 | 0x4b, /* KEY_KP_4 */ 0x4c, /* KEY_KP_5 */ | |
335 | 0x4d, /* KEY_KP_6 */ 0x4e, /* KEY_KP_Plus */ | |
336 | 0x4f, /* KEY_KP_1 */ 0x50, /* KEY_KP_2 */ | |
337 | 0x51, /* KEY_KP_3 */ 0x52, /* KEY_KP_0 */ | |
338 | 0x53, /* KEY_KP_Decimal */ 0x54, /* KEY_SysReqest */ | |
339 | 0x00, /* 0x55 */ 0x56, /* KEY_Less */ | |
340 | 0x57, /* KEY_F11 */ 0x58, /* KEY_F12 */ | |
341 | 0x66, /* KEY_Home */ 0x67, /* KEY_Up */ | |
342 | 0x68, /* KEY_PgUp */ 0x69, /* KEY_Left */ | |
343 | 0x5d, /* KEY_Begin */ 0x6a, /* KEY_Right */ | |
344 | 0x6b, /* KEY_End */ 0x6c, /* KEY_Down */ | |
345 | 0x6d, /* KEY_PgDown */ 0x6e, /* KEY_Insert */ | |
346 | 0x6f, /* KEY_Delete */ 0x60, /* KEY_KP_Enter */ | |
347 | 0x61, /* KEY_RCtrl */ 0x77, /* KEY_Pause */ | |
348 | 0x63, /* KEY_Print */ 0x62, /* KEY_KP_Divide */ | |
349 | 0x64, /* KEY_AltLang */ 0x65, /* KEY_Break */ | |
350 | 0x00, /* KEY_LMeta */ 0x00, /* KEY_RMeta */ | |
351 | 0x7A, /* KEY_Menu/FOCUS_PF11 */ 0x00, /* 0x6e */ | |
352 | 0x7B, /* FOCUS_PF12 */ 0x00, /* 0x70 */ | |
353 | 0x00, /* 0x71 */ 0x00, /* 0x72 */ | |
354 | 0x59, /* FOCUS_PF2 */ 0x78, /* FOCUS_PF9 */ | |
355 | 0x00, /* 0x75 */ 0x00, /* 0x76 */ | |
356 | 0x5A, /* FOCUS_PF3 */ 0x5B, /* FOCUS_PF4 */ | |
357 | 0x5C, /* FOCUS_PF5 */ 0x5D, /* FOCUS_PF6 */ | |
358 | 0x5E, /* FOCUS_PF7 */ 0x5F, /* FOCUS_PF8 */ | |
359 | 0x7C, /* JAP_86 */ 0x79, /* FOCUS_PF10 */ | |
360 | 0x00, /* 0x7f */ | |
361 | }; | |
362 | ||
363 | /** Create a private structure for use within this file. */ | |
364 | pointer | |
365 | kbdLinuxCreatePrivate(DeviceIntPtr pKeyboard) | |
366 | { | |
367 | myPrivate *priv = calloc(1, sizeof(*priv)); | |
368 | ||
369 | priv->fd = -1; | |
370 | priv->pKeyboard = pKeyboard; | |
371 | return priv; | |
372 | } | |
373 | ||
374 | /** Destroy a private structure. */ | |
375 | void | |
376 | kbdLinuxDestroyPrivate(pointer priv) | |
377 | { | |
378 | free(priv); | |
379 | } | |
380 | ||
381 | /** Ring the bell. | |
382 | * | |
383 | * Note: we completely ignore the \a volume, since Linux's ioctl() | |
384 | * interface does not provide a way to control it. If it did, the XBell | |
385 | * manpage tells how the actual volume is a function of the percent and | |
386 | * the (base) volume. | |
387 | * | |
388 | * Note that most of the other PC-based bell drivers compute the | |
389 | * duration for KDMKTONE as a function of the volume and the duration. | |
390 | * For some drivers, the duration is only measured in mS if the volume | |
391 | * is 50, and is scaled by the volume for other values. This seems | |
392 | * confusing and possibly incorrect (the xset man page says that the | |
393 | * bell will be "as closely as it can to the user's specifications" -- | |
394 | * if we ignore the volume and set the duration correctly, then we'll | |
395 | * get one parameter "wrong" -- but if we use the volume to scale the | |
396 | * duration, then we'll get both parameters "wrong"). */ | |
397 | void | |
398 | kbdLinuxBell(DevicePtr pDev, int percent, int volume, int pitch, int duration) | |
399 | { | |
400 | GETPRIV; | |
401 | ||
402 | if (duration && pitch) { | |
403 | ioctl(priv->fd, KDMKTONE, ((1193190 / pitch) & 0xffff) /* Low bits specify cycle time */ | |
404 | |(duration << 16)); /* High bits are duration in msec */ | |
405 | } | |
406 | } | |
407 | ||
408 | /** Set the LEDs. */ | |
409 | void | |
410 | kbdLinuxCtrl(DevicePtr pDev, KeybdCtrl * ctrl) | |
411 | { | |
412 | GETPRIV; | |
413 | ||
414 | ioctl(priv->fd, KDSETLED, ctrl->leds & 0x07); | |
415 | } | |
416 | ||
417 | static int | |
418 | kbdLinuxGetFreeVTNumber(void) | |
419 | { | |
420 | int fd = -1; | |
421 | int vtno; | |
422 | int i; | |
423 | const char *tty0[] = { "/dev/tty0", "/dev/vc/0", NULL }; | |
424 | ||
425 | for (i = 0; tty0[i]; i++) | |
426 | if ((fd = open(tty0[i], O_WRONLY, 0)) >= 0) | |
427 | break; | |
428 | if (fd < 0) | |
429 | FATAL1("kbdLinuxGetFreeVTNumber: Cannot open tty0 (%s)\n", | |
430 | strerror(errno)); | |
431 | if (ioctl(fd, VT_OPENQRY, &vtno) < 0 || vtno < 0) | |
432 | FATAL0("kbdLinuxGetFreeVTNumber: Cannot find a free VT\n"); | |
433 | return vtno; | |
434 | } | |
435 | ||
436 | static int | |
437 | kbdLinuxOpenVT(int vtno) | |
438 | { | |
439 | int fd = -1; | |
440 | int i; | |
441 | const char *vcs[] = { "/dev/vc/", "/dev/tty", NULL }; | |
442 | char name[64]; /* RATS: Only used in snprintf */ | |
443 | ||
444 | for (i = 0; vcs[i]; i++) { | |
445 | snprintf(name, sizeof(name), "%s%d", vcs[i], vtno); | |
446 | if ((fd = open(name, O_RDWR | O_NONBLOCK, 0)) >= 0) | |
447 | break; | |
448 | } | |
449 | if (fd < 0) | |
450 | FATAL2("kbdLinuxOpenVT: Cannot open VT %d (%s)\n", | |
451 | vtno, strerror(errno)); | |
452 | return fd; | |
453 | } | |
454 | ||
455 | static int | |
456 | kbdLinuxGetCurrentVTNumber(int fd) | |
457 | { | |
458 | struct vt_stat vts; | |
459 | ||
460 | if (!ioctl(fd, VT_GETSTATE, &vts)) | |
461 | return vts.v_active; | |
462 | return -1; | |
463 | } | |
464 | ||
465 | static int kbdLinuxActivate(int fd, int vtno, int setSig); | |
466 | ||
467 | /** Currently unused hook called prior to an VT switch. */ | |
468 | void | |
469 | kbdLinuxVTPreSwitch(pointer p) | |
470 | { | |
471 | } | |
472 | ||
473 | /** Currently unused hook called after returning from a VT switch. */ | |
474 | void | |
475 | kbdLinuxVTPostSwitch(pointer p) | |
476 | { | |
477 | } | |
478 | ||
479 | /** Tell the operating system to switch to \a vt. The \a switch_return | |
480 | * function is called with the \a switch_return_data when the VT is | |
481 | * switched back to the pre-switch VT (i.e., the user returns to the DMX | |
482 | * session). */ | |
483 | int | |
484 | kbdLinuxVTSwitch(pointer p, int vt, | |
485 | void (*switch_return) (pointer), pointer switch_return_data) | |
486 | { | |
487 | myPrivate *priv = p; | |
488 | ||
489 | if (priv->switched) | |
490 | FATAL0("kbdLinuxVTSwitch: already switched...\n"); | |
491 | if (priv->vtno == vt) | |
492 | return 0; | |
493 | ||
494 | PRIV = priv; | |
495 | priv->switched = 0; /* Will switch to 1 in handler */ | |
496 | priv->switch_return = switch_return; | |
497 | priv->switch_return_data = switch_return_data; | |
498 | kbdLinuxActivate(priv->fd, vt, 0); | |
499 | return 1; | |
500 | } | |
501 | ||
502 | /* RATS: This function is only ever used to handle SIGUSR1. */ | |
503 | static void | |
504 | kbdLinuxVTSignalHandler(int sig) | |
505 | { | |
506 | myPrivate *priv = PRIV; | |
507 | ||
508 | signal(sig, kbdLinuxVTSignalHandler); | |
509 | if (priv) { | |
510 | ioctl(priv->fd, VT_RELDISP, VT_ACKACQ); | |
511 | priv->switched = !priv->switched; | |
512 | LOG2("kbdLinuxVTSignalHandler: got signal %d, switched = %d\n", | |
513 | sig, priv->switched); | |
514 | if (!priv->switched && priv->switch_return) | |
515 | priv->switch_return(priv->switch_return_data); | |
516 | } | |
517 | } | |
518 | ||
519 | static int | |
520 | kbdLinuxActivate(int fd, int vtno, int setSig) | |
521 | { | |
522 | int result; | |
523 | struct vt_mode VT; | |
524 | ||
525 | SYSCALL(result = ioctl(fd, VT_ACTIVATE, vtno)); | |
526 | if (result) | |
527 | FATAL0("kbdLinuxActivate: VT_ACTIVATE failed\n"); | |
528 | SYSCALL(result = ioctl(fd, VT_WAITACTIVE, vtno)); | |
529 | if (result) | |
530 | FATAL0("kbdLinuxActivate: VT_WAITACTIVE failed\n"); | |
531 | if (setSig) { | |
532 | SYSCALL(result = ioctl(fd, VT_GETMODE, &VT)); | |
533 | if (result < 0) | |
534 | FATAL0("kbdLinuxActivate: VT_GETMODE failed\n"); | |
535 | VT.mode = VT_PROCESS; | |
536 | VT.relsig = SIGUSR1; | |
537 | VT.acqsig = SIGUSR1; | |
538 | if (ioctl(fd, VT_SETMODE, &VT)) | |
539 | FATAL0("kbdLinuxActivate: VT_SETMODE VT_PROCESS failed\n"); | |
540 | signal(SIGUSR1, kbdLinuxVTSignalHandler); | |
541 | } | |
542 | return Success; | |
543 | } | |
544 | ||
545 | static void | |
546 | kbdLinuxOpenConsole(DevicePtr pDev) | |
547 | { | |
548 | GETPRIV; | |
549 | const char *msg = MESSAGE; | |
550 | ||
551 | if (priv->fd >= 0) | |
552 | return; | |
553 | priv->vtno = kbdLinuxGetFreeVTNumber(); | |
554 | priv->fd = kbdLinuxOpenVT(priv->vtno); | |
555 | priv->vtcurrent = kbdLinuxGetCurrentVTNumber(priv->fd); | |
556 | LOG2("kbdLinuxOpenConsole: current VT %d; using free VT %d\n", | |
557 | priv->vtcurrent, priv->vtno); | |
558 | kbdLinuxActivate(priv->fd, priv->vtno, 1); | |
559 | ioctl(priv->fd, KDSETMODE, KD_GRAPHICS); /* To turn off gpm */ | |
560 | if (msg) | |
561 | write(priv->fd, msg, strlen(msg)); | |
562 | } | |
563 | ||
564 | static void | |
565 | kbdLinuxCloseConsole(DevicePtr pDev) | |
566 | { | |
567 | GETPRIV; | |
568 | struct vt_mode VT; | |
569 | const char *msg = FINALMESSAGE; | |
570 | ||
571 | if (priv->fd < 0) | |
572 | return; | |
573 | ||
574 | ioctl(priv->fd, KDSETMODE, KD_TEXT); | |
575 | if (msg) | |
576 | write(priv->fd, msg, strlen(msg)); | |
577 | if (ioctl(priv->fd, VT_GETMODE, &VT) != -1) { | |
578 | VT.mode = VT_AUTO; | |
579 | ioctl(priv->fd, VT_SETMODE, &VT); | |
580 | } | |
581 | ||
582 | LOG1("kbdLinuxCloseConsole: switching to VT %d\n", priv->vtcurrent); | |
583 | if (priv->vtcurrent >= 0) | |
584 | kbdLinuxActivate(priv->fd, priv->vtcurrent, 0); | |
585 | ||
586 | close(priv->fd); | |
587 | priv->fd = -1; | |
588 | } | |
589 | ||
590 | /** Initialize the \a pDev as a Linux keyboard. */ | |
591 | void | |
592 | kbdLinuxInit(DevicePtr pDev) | |
593 | { | |
594 | GETPRIV; | |
595 | ||
596 | if (priv->fd <= 0) | |
597 | kbdLinuxOpenConsole(pDev); | |
598 | ||
599 | ioctl(priv->fd, KDGKBMODE, &priv->kbdtrans); | |
600 | if (tcgetattr(priv->fd, &priv->kbdtty) < 0) | |
601 | FATAL1("kbdLinuxInit: tcgetattr failed (%s)\n", strerror(errno)); | |
602 | } | |
603 | ||
604 | static int | |
605 | kbdLinuxPrefix0Mapping(unsigned char *scanCode) | |
606 | { | |
607 | /* Table from xfree86/common/xf86Events.c */ | |
608 | switch (*scanCode) { | |
609 | case KEY_KP_7: | |
610 | *scanCode = KEY_Home; | |
611 | break; /* curs home */ | |
612 | case KEY_KP_8: | |
613 | *scanCode = KEY_Up; | |
614 | break; /* curs up */ | |
615 | case KEY_KP_9: | |
616 | *scanCode = KEY_PgUp; | |
617 | break; /* curs pgup */ | |
618 | case KEY_KP_4: | |
619 | *scanCode = KEY_Left; | |
620 | break; /* curs left */ | |
621 | case KEY_KP_5: | |
622 | *scanCode = KEY_Begin; | |
623 | break; /* curs begin */ | |
624 | case KEY_KP_6: | |
625 | *scanCode = KEY_Right; | |
626 | break; /* curs right */ | |
627 | case KEY_KP_1: | |
628 | *scanCode = KEY_End; | |
629 | break; /* curs end */ | |
630 | case KEY_KP_2: | |
631 | *scanCode = KEY_Down; | |
632 | break; /* curs down */ | |
633 | case KEY_KP_3: | |
634 | *scanCode = KEY_PgDown; | |
635 | break; /* curs pgdown */ | |
636 | case KEY_KP_0: | |
637 | *scanCode = KEY_Insert; | |
638 | break; /* curs insert */ | |
639 | case KEY_KP_Decimal: | |
640 | *scanCode = KEY_Delete; | |
641 | break; /* curs delete */ | |
642 | case KEY_Enter: | |
643 | *scanCode = KEY_KP_Enter; | |
644 | break; /* keypad enter */ | |
645 | case KEY_LCtrl: | |
646 | *scanCode = KEY_RCtrl; | |
647 | break; /* right ctrl */ | |
648 | case KEY_KP_Multiply: | |
649 | *scanCode = KEY_Print; | |
650 | break; /* print */ | |
651 | case KEY_Slash: | |
652 | *scanCode = KEY_KP_Divide; | |
653 | break; /* keyp divide */ | |
654 | case KEY_Alt: | |
655 | *scanCode = KEY_AltLang; | |
656 | break; /* right alt */ | |
657 | case KEY_ScrollLock: | |
658 | *scanCode = KEY_Break; | |
659 | break; /* curs break */ | |
660 | case 0x5b: | |
661 | *scanCode = KEY_LMeta; | |
662 | break; | |
663 | case 0x5c: | |
664 | *scanCode = KEY_RMeta; | |
665 | break; | |
666 | case 0x5d: | |
667 | *scanCode = KEY_Menu; | |
668 | break; | |
669 | case KEY_F3: | |
670 | *scanCode = KEY_F13; | |
671 | break; | |
672 | case KEY_F4: | |
673 | *scanCode = KEY_F14; | |
674 | break; | |
675 | case KEY_F5: | |
676 | *scanCode = KEY_F15; | |
677 | break; | |
678 | case KEY_F6: | |
679 | *scanCode = KEY_F16; | |
680 | break; | |
681 | case KEY_F7: | |
682 | *scanCode = KEY_F17; | |
683 | break; | |
684 | case KEY_KP_Plus: | |
685 | *scanCode = KEY_KP_DEC; | |
686 | break; | |
687 | /* | |
688 | * Ignore virtual shifts (E0 2A, E0 AA, E0 36, E0 B6) | |
689 | */ | |
690 | case 0x2A: | |
691 | case 0x36: | |
692 | return 1; | |
693 | default: | |
694 | /* | |
695 | * "Internet" keyboards are generating lots of new codes. | |
696 | * Let them pass. There is little consistency between them, | |
697 | * so don't bother with symbolic names at this level. | |
698 | */ | |
699 | scanCode += 0x78; | |
700 | } | |
701 | return 0; | |
702 | } | |
703 | ||
704 | static int | |
705 | kbdLinuxPrefixMapping(myPrivate * priv, unsigned char *scanCode) | |
706 | { | |
707 | int pressed = *scanCode & 0x80; | |
708 | unsigned char code = *scanCode & 0x7f; | |
709 | ||
710 | /* If we don't have a prefix, check for one */ | |
711 | if (!priv->prefix) { | |
712 | switch (code) { | |
713 | case KEY_Prefix0: | |
714 | case KEY_Prefix1: | |
715 | priv->prefix = code; | |
716 | return 1; | |
717 | } | |
718 | return 0; /* No change */ | |
719 | } | |
720 | ||
721 | /* We have a prefix from the last scanCode */ | |
722 | switch (priv->prefix) { | |
723 | case KEY_Prefix0: | |
724 | priv->prefix = 0; | |
725 | if (kbdLinuxPrefix0Mapping(&code)) | |
726 | return 1; /* Skip sequence */ | |
727 | break; | |
728 | case KEY_Prefix1: | |
729 | priv->prefix = (code = KEY_LCtrl) ? KEY_LCtrl : 0; | |
730 | return 1; /* Use new prefix */ | |
731 | case KEY_LCtrl: | |
732 | priv->prefix = 0; | |
733 | if (code != KEY_NumLock) | |
734 | return 1; /* Skip sequence */ | |
735 | code = KEY_Pause; | |
736 | break; | |
737 | } | |
738 | ||
739 | *scanCode = code | (pressed ? 0x80 : 0x00); | |
740 | return 0; /* Use old scanCode */ | |
741 | } | |
742 | ||
743 | static void | |
744 | kbdLinuxConvert(DevicePtr pDev, | |
745 | unsigned char scanCode, | |
746 | ENQUEUEPROC enqueue, CHECKPROC checkspecial, BLOCK block) | |
747 | { | |
748 | GETPRIV; | |
749 | XkbSrvInfoPtr xkbi = priv->pKeyboard->key->xkbInfo; | |
750 | int type; | |
751 | KeySym keySym = NoSymbol; | |
752 | int keyCode; | |
753 | int switching; | |
754 | ||
755 | /* Do special PC/AT prefix mapping -- may change scanCode! */ | |
756 | if (kbdLinuxPrefixMapping(priv, &scanCode)) | |
757 | return; | |
758 | ||
759 | type = (scanCode & 0x80) ? KeyRelease : KeyPress; | |
760 | keyCode = (scanCode & 0x7f) + MIN_KEYCODE; | |
761 | ||
762 | /* Handle repeats */ | |
763 | ||
764 | if (keyCode >= xkbi->desc->min_key_code && | |
765 | keyCode <= xkbi->desc->max_key_code) { | |
766 | ||
767 | int effectiveGroup = XkbGetEffectiveGroup(xkbi, | |
768 | &xkbi->state, | |
769 | scanCode); | |
770 | ||
771 | keySym = XkbKeySym(xkbi->desc, scanCode, effectiveGroup); | |
772 | #if 0 | |
773 | switch (keySym) { | |
774 | case XK_Num_Lock: | |
775 | case XK_Scroll_Lock: | |
776 | case XK_Shift_Lock: | |
777 | case XK_Caps_Lock: | |
778 | /* Ignore releases and all but first press */ | |
779 | if (kbdLinuxModIgnore(priv, &xE, keySym)) | |
780 | return; | |
781 | if (kbdLinuxKeyDown(priv, &xE)) | |
782 | xE.u.u.type = KeyRelease; | |
783 | else | |
784 | xE.u.u.type = KeyPress; | |
785 | break; | |
786 | } | |
787 | #endif | |
788 | ||
789 | /* If key is already down, ignore or autorepeat */ | |
790 | if (type == KeyPress && kbdLinuxKeyDown(priv, keyCode)) { | |
791 | KbdFeedbackClassRec *feed = priv->pKeyboard->kbdfeed; | |
792 | ||
793 | /* No auto-repeat? */ | |
794 | if ((feed && !feed->ctrl.autoRepeat) | |
795 | || priv->pKeyboard->key->xkbInfo->desc->map->modmap[keyCode] | |
796 | || (feed && !(feed->ctrl.autoRepeats[keyCode >> 3] | |
797 | & (1 << (keyCode & 7))))) | |
798 | return; /* Ignore */ | |
799 | ||
800 | /* Do auto-repeat */ | |
801 | enqueue(pDev, KeyRelease, keyCode, keySym, NULL, block); | |
802 | type = KeyPress; | |
803 | } | |
804 | ||
805 | /* If key is already up, ignore */ | |
806 | if (type == KeyRelease && !kbdLinuxKeyDown(priv, keyCode)) | |
807 | return; | |
808 | } | |
809 | ||
810 | switching = 0; | |
811 | if (checkspecial && type == KeyPress) | |
812 | switching = checkspecial(pDev, keySym); | |
813 | if (!switching) { | |
814 | if (enqueue) | |
815 | enqueue(pDev, type, keyCode, keySym, NULL, block); | |
816 | kbdLinuxKeyState(priv, type, keyCode); /* Update our state bitmap */ | |
817 | } | |
818 | } | |
819 | ||
820 | /** Read an event from the \a pDev device. If the event is a motion | |
821 | * event, enqueue it with the \a motion function. Otherwise, check for | |
822 | * special keys with the \a checkspecial function and enqueue the event | |
823 | * with the \a enqueue function. The \a block type is passed to the | |
824 | * functions so that they may block SIGIO handling as appropriate to the | |
825 | * caller of this function. */ | |
826 | void | |
827 | kbdLinuxRead(DevicePtr pDev, | |
828 | MOTIONPROC motion, | |
829 | ENQUEUEPROC enqueue, CHECKPROC checkspecial, BLOCK block) | |
830 | { | |
831 | GETPRIV; | |
832 | unsigned char buf[256]; /* RATS: Only used in length-limited call */ | |
833 | unsigned char *pt; | |
834 | int n; | |
835 | ||
836 | while ((n = read(priv->fd, buf, sizeof(buf))) > 0) | |
837 | for (pt = buf; n; --n, ++pt) | |
838 | kbdLinuxConvert(pDev, *pt, enqueue, checkspecial, block); | |
839 | } | |
840 | ||
841 | /** Turn \a pDev on (i.e., take input from \a pDev). */ | |
842 | int | |
843 | kbdLinuxOn(DevicePtr pDev) | |
844 | { | |
845 | GETPRIV; | |
846 | struct termios nTty; | |
847 | ||
848 | ioctl(priv->fd, KDSKBMODE, K_RAW); | |
849 | ||
850 | nTty = priv->kbdtty; | |
851 | nTty.c_iflag = (IGNPAR | IGNBRK) & (~PARMRK) & (~ISTRIP); | |
852 | nTty.c_oflag = 0; | |
853 | nTty.c_cflag = CREAD | CS8; | |
854 | nTty.c_lflag = 0; | |
855 | nTty.c_cc[VTIME] = 0; | |
856 | nTty.c_cc[VMIN] = 1; | |
857 | cfsetispeed(&nTty, B9600); | |
858 | cfsetospeed(&nTty, B9600); | |
859 | if (tcsetattr(priv->fd, TCSANOW, &nTty) < 0) | |
860 | FATAL1("kbdLinuxOn: tcsetattr failed (%s)\n", strerror(errno)); | |
861 | return priv->fd; | |
862 | } | |
863 | ||
864 | /** Turn \a pDev off (i.e., stop taking input from \a pDev). */ | |
865 | void | |
866 | kbdLinuxOff(DevicePtr pDev) | |
867 | { | |
868 | GETPRIV; | |
869 | ||
870 | ioctl(priv->fd, KDSKBMODE, priv->kbdtrans); | |
871 | tcsetattr(priv->fd, TCSANOW, &priv->kbdtty); | |
872 | kbdLinuxCloseConsole(pDev); | |
873 | } | |
874 | ||
875 | static void | |
876 | kbdLinuxReadKernelMapping(int fd, KeySymsPtr pKeySyms) | |
877 | { | |
878 | KeySym *k; | |
879 | int i; | |
880 | int maxkey; | |
881 | ||
882 | static unsigned char tbl[GLYPHS_PER_KEY] = { /* RATS: Use ok */ | |
883 | 0, /* unshifted */ | |
884 | 1, /* shifted */ | |
885 | 0, /* modeswitch unshifted */ | |
886 | 0 /* modeswitch shifted */ | |
887 | }; | |
888 | ||
889 | /* | |
890 | * Read the mapping from the kernel. | |
891 | * Since we're still using the XFree86 scancode->AT keycode mapping | |
892 | * routines, we need to convert the AT keycodes to Linux keycodes, | |
893 | * then translate the Linux keysyms into X keysyms. | |
894 | * | |
895 | * First, figure out which tables to use for the modeswitch columns | |
896 | * above, from the XF86Config fields. | |
897 | */ | |
898 | tbl[2] = 8; /* alt */ | |
899 | tbl[3] = tbl[2] | 1; | |
900 | ||
901 | #if 00 /*BP*/ | |
902 | k = map + GLYPHS_PER_KEY; | |
903 | #else | |
904 | ErrorF("kbdLinuxReadKernelMapping() is broken/no-op'd\n"); | |
905 | return; | |
906 | #endif | |
907 | maxkey = NUM_AT2LNX; | |
908 | ||
909 | for (i = 0; i < maxkey; ++i) { | |
910 | struct kbentry kbe; | |
911 | int j; | |
912 | ||
913 | kbe.kb_index = at2lnx[i]; | |
914 | ||
915 | for (j = 0; j < GLYPHS_PER_KEY; ++j, ++k) { | |
916 | unsigned short kval; | |
917 | ||
918 | *k = NoSymbol; | |
919 | ||
920 | kbe.kb_table = tbl[j]; | |
921 | if (kbe.kb_index == 0 || ioctl(fd, KDGKBENT, &kbe)) | |
922 | continue; | |
923 | ||
924 | kval = KVAL(kbe.kb_value); | |
925 | switch (KTYP(kbe.kb_value)) { | |
926 | case KT_LATIN: | |
927 | case KT_LETTER: | |
928 | *k = linux_to_x[kval]; | |
929 | break; | |
930 | case KT_FN: | |
931 | if (kval <= 19) | |
932 | *k = XK_F1 + kval; | |
933 | else | |
934 | switch (kbe.kb_value) { | |
935 | case K_FIND: | |
936 | *k = XK_Home; /* or XK_Find */ | |
937 | break; | |
938 | case K_INSERT: | |
939 | *k = XK_Insert; | |
940 | break; | |
941 | case K_REMOVE: | |
942 | *k = XK_Delete; | |
943 | break; | |
944 | case K_SELECT: | |
945 | *k = XK_End; /* or XK_Select */ | |
946 | break; | |
947 | case K_PGUP: | |
948 | *k = XK_Prior; | |
949 | break; | |
950 | case K_PGDN: | |
951 | *k = XK_Next; | |
952 | break; | |
953 | case K_HELP: | |
954 | *k = XK_Help; | |
955 | break; | |
956 | case K_DO: | |
957 | *k = XK_Execute; | |
958 | break; | |
959 | case K_PAUSE: | |
960 | *k = XK_Pause; | |
961 | break; | |
962 | case K_MACRO: | |
963 | *k = XK_Menu; | |
964 | break; | |
965 | default: | |
966 | break; | |
967 | } | |
968 | break; | |
969 | case KT_SPEC: | |
970 | switch (kbe.kb_value) { | |
971 | case K_ENTER: | |
972 | *k = XK_Return; | |
973 | break; | |
974 | case K_BREAK: | |
975 | *k = XK_Break; | |
976 | break; | |
977 | case K_CAPS: | |
978 | *k = XK_Caps_Lock; | |
979 | break; | |
980 | case K_NUM: | |
981 | *k = XK_Num_Lock; | |
982 | break; | |
983 | case K_HOLD: | |
984 | *k = XK_Scroll_Lock; | |
985 | break; | |
986 | case K_COMPOSE: | |
987 | *k = XK_Multi_key; | |
988 | break; | |
989 | default: | |
990 | break; | |
991 | } | |
992 | break; | |
993 | case KT_PAD: | |
994 | switch (kbe.kb_value) { | |
995 | case K_PPLUS: | |
996 | *k = XK_KP_Add; | |
997 | break; | |
998 | case K_PMINUS: | |
999 | *k = XK_KP_Subtract; | |
1000 | break; | |
1001 | case K_PSTAR: | |
1002 | *k = XK_KP_Multiply; | |
1003 | break; | |
1004 | case K_PSLASH: | |
1005 | *k = XK_KP_Divide; | |
1006 | break; | |
1007 | case K_PENTER: | |
1008 | *k = XK_KP_Enter; | |
1009 | break; | |
1010 | case K_PCOMMA: | |
1011 | *k = XK_KP_Separator; | |
1012 | break; | |
1013 | case K_PDOT: | |
1014 | *k = XK_KP_Decimal; | |
1015 | break; | |
1016 | case K_PPLUSMINUS: | |
1017 | *k = XK_KP_Subtract; | |
1018 | break; | |
1019 | default: | |
1020 | if (kval <= 9) | |
1021 | *k = XK_KP_0 + kval; | |
1022 | break; | |
1023 | } | |
1024 | break; | |
1025 | case KT_DEAD: | |
1026 | /* KT_DEAD keys are for accelerated diacritical creation. */ | |
1027 | switch (kbe.kb_value) { | |
1028 | case K_DGRAVE: | |
1029 | *k = XK_dead_grave; | |
1030 | break; | |
1031 | case K_DACUTE: | |
1032 | *k = XK_dead_acute; | |
1033 | break; | |
1034 | case K_DCIRCM: | |
1035 | *k = XK_dead_circumflex; | |
1036 | break; | |
1037 | case K_DTILDE: | |
1038 | *k = XK_dead_tilde; | |
1039 | break; | |
1040 | case K_DDIERE: | |
1041 | *k = XK_dead_diaeresis; | |
1042 | break; | |
1043 | } | |
1044 | break; | |
1045 | case KT_CUR: | |
1046 | switch (kbe.kb_value) { | |
1047 | case K_DOWN: | |
1048 | *k = XK_Down; | |
1049 | break; | |
1050 | case K_LEFT: | |
1051 | *k = XK_Left; | |
1052 | break; | |
1053 | case K_RIGHT: | |
1054 | *k = XK_Right; | |
1055 | break; | |
1056 | case K_UP: | |
1057 | *k = XK_Up; | |
1058 | break; | |
1059 | } | |
1060 | break; | |
1061 | case KT_SHIFT: | |
1062 | switch (kbe.kb_value) { | |
1063 | case K_ALTGR: | |
1064 | *k = XK_Alt_R; | |
1065 | break; | |
1066 | case K_ALT: | |
1067 | *k = (kbe.kb_index == 0x64 ? XK_Alt_R : XK_Alt_L); | |
1068 | break; | |
1069 | case K_CTRL: | |
1070 | *k = (kbe.kb_index == 0x61 ? XK_Control_R : XK_Control_L); | |
1071 | break; | |
1072 | case K_CTRLL: | |
1073 | *k = XK_Control_L; | |
1074 | break; | |
1075 | case K_CTRLR: | |
1076 | *k = XK_Control_R; | |
1077 | break; | |
1078 | case K_SHIFT: | |
1079 | *k = (kbe.kb_index == 0x36 ? XK_Shift_R : XK_Shift_L); | |
1080 | break; | |
1081 | case K_SHIFTL: | |
1082 | *k = XK_Shift_L; | |
1083 | break; | |
1084 | case K_SHIFTR: | |
1085 | *k = XK_Shift_R; | |
1086 | break; | |
1087 | default: | |
1088 | break; | |
1089 | } | |
1090 | break; | |
1091 | case KT_ASCII: | |
1092 | /* KT_ASCII keys accumulate a 3 digit decimal number that | |
1093 | * gets emitted when the shift state changes. We can't | |
1094 | * emulate that. | |
1095 | */ | |
1096 | break; | |
1097 | case KT_LOCK: | |
1098 | if (kbe.kb_value == K_SHIFTLOCK) | |
1099 | *k = XK_Shift_Lock; | |
1100 | break; | |
1101 | default: | |
1102 | break; | |
1103 | } | |
1104 | } | |
1105 | ||
1106 | if (k[-1] == k[-2]) | |
1107 | k[-1] = NoSymbol; | |
1108 | if (k[-2] == k[-3]) | |
1109 | k[-2] = NoSymbol; | |
1110 | if (k[-3] == k[-4]) | |
1111 | k[-3] = NoSymbol; | |
1112 | if (k[-4] == k[-2] && k[-3] == k[-1]) | |
1113 | k[-2] = k[-1] = NoSymbol; | |
1114 | if (k[-1] == k[-4] && k[-2] == k[-3] | |
1115 | && k[-2] == NoSymbol) | |
1116 | k[-1] = NoSymbol; | |
1117 | } | |
1118 | } | |
1119 | ||
1120 | static void | |
1121 | kbdLinuxGetMap(DevicePtr pDev, KeySymsPtr pKeySyms, CARD8 *pModMap) | |
1122 | { | |
1123 | GETPRIV; | |
1124 | KeySym *k, *mapCopy; | |
1125 | char type; | |
1126 | int i; | |
1127 | ||
1128 | #if 00 /*BP*/ | |
1129 | mapCopy = malloc(sizeof(map)); | |
1130 | memcpy(mapCopy, map, sizeof(map)); | |
1131 | #else | |
1132 | ErrorF("kbdLinuxGetMap() is broken/no-op'd\n"); | |
1133 | return; | |
1134 | #endif | |
1135 | ||
1136 | kbdLinuxReadKernelMapping(priv->fd, pKeySyms); | |
1137 | ||
1138 | /* compute the modifier map */ | |
1139 | for (i = 0; i < MAP_LENGTH; i++) | |
1140 | pModMap[i] = NoSymbol; /* make sure it is restored */ | |
1141 | ||
1142 | for (k = mapCopy, i = MIN_KEYCODE; | |
1143 | i < NUM_KEYCODES + MIN_KEYCODE; i++, k += 4) { | |
1144 | switch (*k) { | |
1145 | case XK_Shift_L: | |
1146 | case XK_Shift_R: | |
1147 | pModMap[i] = ShiftMask; | |
1148 | break; | |
1149 | case XK_Control_L: | |
1150 | case XK_Control_R: | |
1151 | pModMap[i] = ControlMask; | |
1152 | break; | |
1153 | case XK_Caps_Lock: | |
1154 | pModMap[i] = LockMask; | |
1155 | break; | |
1156 | case XK_Alt_L: | |
1157 | case XK_Alt_R: | |
1158 | pModMap[i] = AltMask; | |
1159 | break; | |
1160 | case XK_Num_Lock: | |
1161 | pModMap[i] = NumLockMask; | |
1162 | break; | |
1163 | case XK_Scroll_Lock: | |
1164 | pModMap[i] = ScrollLockMask; | |
1165 | break; | |
1166 | case XK_Kana_Lock: | |
1167 | case XK_Kana_Shift: | |
1168 | pModMap[i] = KanaMask; | |
1169 | break; | |
1170 | case XK_Mode_switch: | |
1171 | pModMap[i] = AltLangMask; | |
1172 | break; | |
1173 | } | |
1174 | } | |
1175 | ||
1176 | priv->kbdType = (ioctl(priv->fd, KDGKBTYPE, &type) < 0) ? KB_101 : type; | |
1177 | ||
1178 | pKeySyms->map = mapCopy; /* Must be XFree'able */ | |
1179 | pKeySyms->mapWidth = GLYPHS_PER_KEY; | |
1180 | pKeySyms->minKeyCode = MIN_KEYCODE; | |
1181 | pKeySyms->maxKeyCode = MAX_KEYCODE; | |
1182 | } | |
1183 | ||
1184 | /** Fill the \a info structure with information needed to initialize \a | |
1185 | * pDev. */ | |
1186 | void | |
1187 | kbdLinuxGetInfo(DevicePtr pDev, DMXLocalInitInfoPtr info) | |
1188 | { | |
1189 | info->keyboard = 1; | |
1190 | info->keyClass = 1; | |
1191 | kbdLinuxGetMap(pDev, &info->keySyms, info->modMap); | |
1192 | info->focusClass = 1; | |
1193 | info->kbdFeedbackClass = 1; | |
1194 | } |