comparison src/video/x11/SDL_x11events.c @ 0:74212992fb08

Initial revision
author Sam Lantinga <slouken@lokigames.com>
date Thu, 26 Apr 2001 16:45:43 +0000
parents
children 5574376c451d
comparison
equal deleted inserted replaced
-1:000000000000 0:74212992fb08
1 /*
2 SDL - Simple DirectMedia Layer
3 Copyright (C) 1997, 1998, 1999, 2000, 2001 Sam Lantinga
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Library General Public
7 License as published by the Free Software Foundation; either
8 version 2 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Library General Public License for more details.
14
15 You should have received a copy of the GNU Library General Public
16 License along with this library; if not, write to the Free
17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18
19 Sam Lantinga
20 slouken@devolution.com
21 */
22
23 #ifdef SAVE_RCSID
24 static char rcsid =
25 "@(#) $Id$";
26 #endif
27
28 /* Handle the event stream, converting X11 events into SDL events */
29
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <setjmp.h>
34 #include <X11/Xlib.h>
35 #include <X11/Xutil.h>
36 #include <X11/keysym.h>
37 #ifdef __SVR4
38 #include <X11/Sunkeysym.h>
39 #endif
40 #include <sys/time.h>
41
42 #include "SDL.h"
43 #include "SDL_syswm.h"
44 #include "SDL_sysevents.h"
45 #include "SDL_sysvideo.h"
46 #include "SDL_events_c.h"
47 #include "SDL_x11video.h"
48 #include "SDL_x11dga_c.h"
49 #include "SDL_x11modes_c.h"
50 #include "SDL_x11image_c.h"
51 #include "SDL_x11gamma_c.h"
52 #include "SDL_x11wm_c.h"
53 #include "SDL_x11mouse_c.h"
54 #include "SDL_x11events_c.h"
55
56
57 /* The translation tables from an X11 keysym to a SDL keysym */
58 static SDLKey ODD_keymap[256];
59 static SDLKey MISC_keymap[256];
60 SDL_keysym *X11_TranslateKey(Display *display, XKeyEvent *xkey, KeyCode kc,
61 SDL_keysym *keysym);
62
63 /* Check to see if this is a repeated key.
64 (idea shamelessly lifted from GII -- thanks guys! :)
65 */
66 static int X11_KeyRepeat(Display *display, XEvent *event)
67 {
68 XEvent peekevent;
69 int repeated;
70
71 repeated = 0;
72 if ( XPending(display) ) {
73 XPeekEvent(display, &peekevent);
74 if ( (peekevent.type == KeyPress) &&
75 (peekevent.xkey.keycode == event->xkey.keycode) &&
76 (peekevent.xkey.time == event->xkey.time) ) {
77 repeated = 1;
78 XNextEvent(display, &peekevent);
79 }
80 }
81 return(repeated);
82 }
83
84 /* Note: The X server buffers and accumulates mouse motion events, so
85 the motion event generated by the warp may not appear exactly as we
86 expect it to. We work around this (and improve performance) by only
87 warping the pointer when it reaches the edge, and then wait for it.
88 */
89 #define MOUSE_FUDGE_FACTOR 8
90
91 static __inline__ int X11_WarpedMotion(_THIS, XEvent *xevent)
92 {
93 int w, h, i;
94 int deltax, deltay;
95 int posted;
96
97 w = SDL_VideoSurface->w;
98 h = SDL_VideoSurface->h;
99 deltax = xevent->xmotion.x - mouse_last.x;
100 deltay = xevent->xmotion.y - mouse_last.y;
101 #ifdef DEBUG_MOTION
102 printf("Warped mouse motion: %d,%d\n", deltax, deltay);
103 #endif
104 mouse_last.x = xevent->xmotion.x;
105 mouse_last.y = xevent->xmotion.y;
106 posted = SDL_PrivateMouseMotion(0, 1, deltax, deltay);
107
108 if ( (xevent->xmotion.x < MOUSE_FUDGE_FACTOR) ||
109 (xevent->xmotion.x > (w-MOUSE_FUDGE_FACTOR)) ||
110 (xevent->xmotion.y < MOUSE_FUDGE_FACTOR) ||
111 (xevent->xmotion.y > (h-MOUSE_FUDGE_FACTOR)) ) {
112 /* Get the events that have accumulated */
113 while ( XCheckTypedEvent(SDL_Display, MotionNotify, xevent) ) {
114 deltax = xevent->xmotion.x - mouse_last.x;
115 deltay = xevent->xmotion.y - mouse_last.y;
116 #ifdef DEBUG_MOTION
117 printf("Extra mouse motion: %d,%d\n", deltax, deltay);
118 #endif
119 mouse_last.x = xevent->xmotion.x;
120 mouse_last.y = xevent->xmotion.y;
121 posted += SDL_PrivateMouseMotion(0, 1, deltax, deltay);
122 }
123 mouse_last.x = w/2;
124 mouse_last.y = h/2;
125 XWarpPointer(SDL_Display, None, SDL_Window, 0, 0, 0, 0,
126 mouse_last.x, mouse_last.y);
127 for ( i=0; i<10; ++i ) {
128 XMaskEvent(SDL_Display, PointerMotionMask, xevent);
129 if ( (xevent->xmotion.x >
130 (mouse_last.x-MOUSE_FUDGE_FACTOR)) &&
131 (xevent->xmotion.x <
132 (mouse_last.x+MOUSE_FUDGE_FACTOR)) &&
133 (xevent->xmotion.y >
134 (mouse_last.y-MOUSE_FUDGE_FACTOR)) &&
135 (xevent->xmotion.y <
136 (mouse_last.y+MOUSE_FUDGE_FACTOR)) ) {
137 break;
138 }
139 #ifdef DEBUG_XEVENTS
140 printf("Lost mouse motion: %d,%d\n", xevent->xmotion.x, xevent->xmotion.y);
141 #endif
142 }
143 #ifdef DEBUG_XEVENTS
144 if ( i == 10 ) {
145 printf("Warning: didn't detect mouse warp motion\n");
146 }
147 #endif
148 }
149 return(posted);
150 }
151
152 static int X11_DispatchEvent(_THIS)
153 {
154 int posted;
155 XEvent xevent;
156
157 XNextEvent(SDL_Display, &xevent);
158
159 posted = 0;
160 switch (xevent.type) {
161
162 /* Gaining mouse coverage? */
163 case EnterNotify: {
164 #ifdef DEBUG_XEVENTS
165 printf("EnterNotify!\n");
166 if ( xevent.xcrossing.mode == NotifyGrab )
167 printf("Mode: NotifyGrab\n");
168 if ( xevent.xcrossing.mode == NotifyUngrab )
169 printf("Mode: NotifyUngrab\n");
170 #endif
171 if ( (xevent.xcrossing.mode != NotifyGrab) &&
172 (xevent.xcrossing.mode != NotifyUngrab) ) {
173 posted = SDL_PrivateAppActive(1, SDL_APPMOUSEFOCUS);
174 }
175 }
176 break;
177
178 /* Losing mouse coverage? */
179 case LeaveNotify: {
180 #ifdef DEBUG_XEVENTS
181 printf("LeaveNotify!\n");
182 if ( xevent.xcrossing.mode == NotifyGrab )
183 printf("Mode: NotifyGrab\n");
184 if ( xevent.xcrossing.mode == NotifyUngrab )
185 printf("Mode: NotifyUngrab\n");
186 #endif
187 if ( (xevent.xcrossing.mode != NotifyGrab) &&
188 (xevent.xcrossing.mode != NotifyUngrab) ) {
189 posted = SDL_PrivateAppActive(0, SDL_APPMOUSEFOCUS);
190 }
191 }
192 break;
193
194 /* Gaining input focus? */
195 case FocusIn: {
196 #ifdef DEBUG_XEVENTS
197 printf("FocusIn!\n");
198 #endif
199 posted = SDL_PrivateAppActive(1, SDL_APPINPUTFOCUS);
200
201 /* Queue entry into fullscreen mode */
202 switch_waiting = 0x01 | SDL_FULLSCREEN;
203 switch_time = SDL_GetTicks() + 1500;
204 }
205 break;
206
207 /* Losing input focus? */
208 case FocusOut: {
209 #ifdef DEBUG_XEVENTS
210 printf("FocusOut!\n");
211 #endif
212 posted = SDL_PrivateAppActive(0, SDL_APPINPUTFOCUS);
213
214 /* Queue leaving fullscreen mode */
215 switch_waiting = 0x01;
216 switch_time = SDL_GetTicks() + 200;
217 }
218 break;
219
220 /* Generated upon EnterWindow and FocusIn */
221 case KeymapNotify: {
222 X11_SetKeyboardState(SDL_Display, xevent.xkeymap.key_vector);
223 }
224 break;
225
226 /* Mouse motion? */
227 case MotionNotify: {
228 if ( SDL_VideoSurface ) {
229 if ( mouse_relative ) {
230 if ( using_dga & DGA_MOUSE ) {
231 #ifdef DEBUG_MOTION
232 printf("DGA motion: %d,%d\n", xevent.xmotion.x_root, xevent.xmotion.y_root);
233 #endif
234 posted = SDL_PrivateMouseMotion(0, 1,
235 xevent.xmotion.x_root,
236 xevent.xmotion.y_root);
237 } else {
238 posted = X11_WarpedMotion(this,&xevent);
239 }
240 } else {
241 posted = SDL_PrivateMouseMotion(0, 0,
242 xevent.xmotion.x,
243 xevent.xmotion.y);
244 }
245 }
246 }
247 break;
248
249 /* Mouse button press? */
250 case ButtonPress: {
251 posted = SDL_PrivateMouseButton(SDL_PRESSED,
252 xevent.xbutton.button, 0, 0);
253 }
254 break;
255
256 /* Mouse button release? */
257 case ButtonRelease: {
258 posted = SDL_PrivateMouseButton(SDL_RELEASED,
259 xevent.xbutton.button, 0, 0);
260 }
261 break;
262
263 /* Key press? */
264 case KeyPress: {
265 SDL_keysym keysym;
266 posted = SDL_PrivateKeyboard(SDL_PRESSED,
267 X11_TranslateKey(SDL_Display, &xevent.xkey,
268 xevent.xkey.keycode,
269 &keysym));
270 }
271 break;
272
273 /* Key release? */
274 case KeyRelease: {
275 SDL_keysym keysym;
276
277 /* Check to see if this is a repeated key */
278 if ( ! X11_KeyRepeat(SDL_Display, &xevent) ) {
279 posted = SDL_PrivateKeyboard(SDL_RELEASED,
280 X11_TranslateKey(SDL_Display, &xevent.xkey,
281 xevent.xkey.keycode,
282 &keysym));
283 }
284 }
285 break;
286
287 /* Have we been iconified? */
288 case UnmapNotify: {
289 #ifdef DEBUG_XEVENTS
290 printf("UnmapNotify!\n");
291 #endif
292 /* If we're active, make ourselves inactive */
293 if ( SDL_GetAppState() & SDL_APPACTIVE ) {
294 /* Swap out the gamma before we go inactive */
295 X11_SwapVidModeGamma(this);
296
297 /* Send an internal deactivate event */
298 posted = SDL_PrivateAppActive(0,
299 SDL_APPACTIVE|SDL_APPINPUTFOCUS);
300 }
301 }
302 break;
303
304 /* Have we been restored? */
305 case MapNotify: {
306 #ifdef DEBUG_XEVENTS
307 printf("MapNotify!\n");
308 #endif
309 /* If we're not active, make ourselves active */
310 if ( !(SDL_GetAppState() & SDL_APPACTIVE) ) {
311 /* Send an internal activate event */
312 posted = SDL_PrivateAppActive(1, SDL_APPACTIVE);
313
314 /* Now that we're active, swap the gamma back */
315 X11_SwapVidModeGamma(this);
316 }
317
318 if ( SDL_VideoSurface &&
319 (SDL_VideoSurface->flags & SDL_FULLSCREEN) ) {
320 #ifdef GRAB_FULLSCREEN
321 X11_EnterFullScreen(this);
322 #else
323 /* Queue entry into fullscreen mode */
324 switch_waiting = 0x01 | SDL_FULLSCREEN;
325 switch_time = SDL_GetTicks() + 1500;
326 #endif
327 } else {
328 X11_GrabInputNoLock(this, this->input_grab);
329 }
330 if ( SDL_VideoSurface ) {
331 X11_RefreshDisplay(this);
332 }
333 }
334 break;
335
336 /* Have we been resized or moved? */
337 case ConfigureNotify: {
338 #ifdef DEBUG_XEVENTS
339 printf("ConfigureNotify! (resize: %dx%d)\n", xevent.xconfigure.width, xevent.xconfigure.height);
340 #endif
341 if ( SDL_VideoSurface ) {
342 if ((xevent.xconfigure.width != SDL_VideoSurface->w) ||
343 (xevent.xconfigure.height != SDL_VideoSurface->h)) {
344 /* FIXME: Find a better fix for the bug with KDE 1.2 */
345 if ( ! ((xevent.xconfigure.width == 32) &&
346 (xevent.xconfigure.height == 32)) ) {
347 SDL_PrivateResize(xevent.xconfigure.width,
348 xevent.xconfigure.height);
349 }
350 } else {
351 /* OpenGL windows need to know about the change */
352 if ( SDL_VideoSurface->flags & SDL_OPENGL ) {
353 SDL_PrivateExpose();
354 }
355 }
356 }
357 }
358 break;
359
360 /* Have we been requested to quit (or another client message?) */
361 case ClientMessage: {
362 if ( (xevent.xclient.format == 32) &&
363 (xevent.xclient.data.l[0] == WM_DELETE_WINDOW) )
364 {
365 posted = SDL_PrivateQuit();
366 } else
367 if ( SDL_ProcessEvents[SDL_SYSWMEVENT] == SDL_ENABLE ) {
368 SDL_SysWMmsg wmmsg;
369
370 SDL_VERSION(&wmmsg.version);
371 wmmsg.subsystem = SDL_SYSWM_X11;
372 wmmsg.event.xevent = xevent;
373 posted = SDL_PrivateSysWMEvent(&wmmsg);
374 }
375 }
376 break;
377
378 /* Do we need to refresh ourselves? */
379 case Expose: {
380 #ifdef DEBUG_XEVENTS
381 printf("Expose (count = %d)\n", xevent.xexpose.count);
382 #endif
383 if ( SDL_VideoSurface && (xevent.xexpose.count == 0) ) {
384 if ( SDL_VideoSurface->flags & SDL_OPENGL ) {
385 SDL_PrivateExpose();
386 } else {
387 X11_RefreshDisplay(this);
388 }
389 }
390 }
391 break;
392
393 default: {
394 #ifdef DEBUG_XEVENTS
395 printf("Unhandled event %d\n", xevent.type);
396 #endif
397 /* Only post the event if we're watching for it */
398 if ( SDL_ProcessEvents[SDL_SYSWMEVENT] == SDL_ENABLE ) {
399 SDL_SysWMmsg wmmsg;
400
401 SDL_VERSION(&wmmsg.version);
402 wmmsg.subsystem = SDL_SYSWM_X11;
403 wmmsg.event.xevent = xevent;
404 posted = SDL_PrivateSysWMEvent(&wmmsg);
405 }
406 }
407 break;
408 }
409 return(posted);
410 }
411
412 /* Ack! XPending() actually performs a blocking read if no events available */
413 int X11_Pending(Display *display)
414 {
415 /* Flush the display connection and look to see if events are queued */
416 XFlush(display);
417 if ( XEventsQueued(display, QueuedAlready) ) {
418 return(1);
419 }
420
421 /* More drastic measures are required -- see if X is ready to talk */
422 {
423 static struct timeval zero_time; /* static == 0 */
424 int x11_fd;
425 fd_set fdset;
426
427 x11_fd = ConnectionNumber(display);
428 FD_ZERO(&fdset);
429 FD_SET(x11_fd, &fdset);
430 if ( select(x11_fd+1, &fdset, NULL, NULL, &zero_time) == 1 ) {
431 return(XPending(display));
432 }
433 }
434
435 /* Oh well, nothing is ready .. */
436 return(0);
437 }
438
439 void X11_PumpEvents(_THIS)
440 {
441 int pending;
442
443 /* Keep processing pending events */
444 pending = 0;
445 while ( X11_Pending(SDL_Display) ) {
446 X11_DispatchEvent(this);
447 ++pending;
448 }
449 if ( switch_waiting ) {
450 Uint32 now;
451
452 now = SDL_GetTicks();
453 if ( pending || !SDL_VideoSurface ) {
454 /* Try again later... */
455 if ( switch_waiting & SDL_FULLSCREEN ) {
456 switch_time = now + 1500;
457 } else {
458 switch_time = now + 200;
459 }
460 } else if ( now >= switch_time ) {
461 Uint32 go_fullscreen;
462
463 go_fullscreen = switch_waiting & SDL_FULLSCREEN;
464 switch_waiting = 0;
465 if ( SDL_VideoSurface->flags & SDL_FULLSCREEN ) {
466 if ( go_fullscreen ) {
467 X11_EnterFullScreen(this);
468 } else {
469 X11_LeaveFullScreen(this);
470 }
471 }
472 /* Handle focus in/out when grabbed */
473 if ( go_fullscreen ) {
474 X11_GrabInputNoLock(this, this->input_grab);
475 } else {
476 X11_GrabInputNoLock(this, SDL_GRAB_OFF);
477 }
478 X11_CheckMouseModeNoLock(this);
479 }
480 }
481 }
482
483 void X11_InitKeymap(void)
484 {
485 int i;
486
487 /* Odd keys used in international keyboards */
488 for ( i=0; i<SDL_TABLESIZE(ODD_keymap); ++i )
489 ODD_keymap[i] = SDLK_UNKNOWN;
490
491 #ifdef XK_dead_circumflex
492 /* These X keysyms have 0xFE as the high byte */
493 ODD_keymap[XK_dead_circumflex&0xFF] = SDLK_CARET;
494 #endif
495
496 /* Map the miscellaneous keys */
497 for ( i=0; i<SDL_TABLESIZE(MISC_keymap); ++i )
498 MISC_keymap[i] = SDLK_UNKNOWN;
499
500 /* These X keysyms have 0xFF as the high byte */
501 MISC_keymap[XK_BackSpace&0xFF] = SDLK_BACKSPACE;
502 MISC_keymap[XK_Tab&0xFF] = SDLK_TAB;
503 MISC_keymap[XK_Clear&0xFF] = SDLK_CLEAR;
504 MISC_keymap[XK_Return&0xFF] = SDLK_RETURN;
505 MISC_keymap[XK_Pause&0xFF] = SDLK_PAUSE;
506 MISC_keymap[XK_Escape&0xFF] = SDLK_ESCAPE;
507 MISC_keymap[XK_Delete&0xFF] = SDLK_DELETE;
508
509 MISC_keymap[XK_KP_0&0xFF] = SDLK_KP0; /* Keypad 0-9 */
510 MISC_keymap[XK_KP_1&0xFF] = SDLK_KP1;
511 MISC_keymap[XK_KP_2&0xFF] = SDLK_KP2;
512 MISC_keymap[XK_KP_3&0xFF] = SDLK_KP3;
513 MISC_keymap[XK_KP_4&0xFF] = SDLK_KP4;
514 MISC_keymap[XK_KP_5&0xFF] = SDLK_KP5;
515 MISC_keymap[XK_KP_6&0xFF] = SDLK_KP6;
516 MISC_keymap[XK_KP_7&0xFF] = SDLK_KP7;
517 MISC_keymap[XK_KP_8&0xFF] = SDLK_KP8;
518 MISC_keymap[XK_KP_9&0xFF] = SDLK_KP9;
519 MISC_keymap[XK_KP_Insert&0xFF] = SDLK_KP0;
520 MISC_keymap[XK_KP_End&0xFF] = SDLK_KP1;
521 MISC_keymap[XK_KP_Down&0xFF] = SDLK_KP2;
522 MISC_keymap[XK_KP_Page_Down&0xFF] = SDLK_KP3;
523 MISC_keymap[XK_KP_Left&0xFF] = SDLK_KP4;
524 MISC_keymap[XK_KP_Begin&0xFF] = SDLK_KP5;
525 MISC_keymap[XK_KP_Right&0xFF] = SDLK_KP6;
526 MISC_keymap[XK_KP_Home&0xFF] = SDLK_KP7;
527 MISC_keymap[XK_KP_Up&0xFF] = SDLK_KP8;
528 MISC_keymap[XK_KP_Page_Up&0xFF] = SDLK_KP9;
529 MISC_keymap[XK_KP_Delete&0xFF] = SDLK_KP_PERIOD;
530 MISC_keymap[XK_KP_Decimal&0xFF] = SDLK_KP_PERIOD;
531 MISC_keymap[XK_KP_Divide&0xFF] = SDLK_KP_DIVIDE;
532 MISC_keymap[XK_KP_Multiply&0xFF] = SDLK_KP_MULTIPLY;
533 MISC_keymap[XK_KP_Subtract&0xFF] = SDLK_KP_MINUS;
534 MISC_keymap[XK_KP_Add&0xFF] = SDLK_KP_PLUS;
535 MISC_keymap[XK_KP_Enter&0xFF] = SDLK_KP_ENTER;
536 MISC_keymap[XK_KP_Equal&0xFF] = SDLK_KP_EQUALS;
537
538 MISC_keymap[XK_Up&0xFF] = SDLK_UP;
539 MISC_keymap[XK_Down&0xFF] = SDLK_DOWN;
540 MISC_keymap[XK_Right&0xFF] = SDLK_RIGHT;
541 MISC_keymap[XK_Left&0xFF] = SDLK_LEFT;
542 MISC_keymap[XK_Insert&0xFF] = SDLK_INSERT;
543 MISC_keymap[XK_Home&0xFF] = SDLK_HOME;
544 MISC_keymap[XK_End&0xFF] = SDLK_END;
545 MISC_keymap[XK_Page_Up&0xFF] = SDLK_PAGEUP;
546 MISC_keymap[XK_Page_Down&0xFF] = SDLK_PAGEDOWN;
547
548 MISC_keymap[XK_F1&0xFF] = SDLK_F1;
549 MISC_keymap[XK_F2&0xFF] = SDLK_F2;
550 MISC_keymap[XK_F3&0xFF] = SDLK_F3;
551 MISC_keymap[XK_F4&0xFF] = SDLK_F4;
552 MISC_keymap[XK_F5&0xFF] = SDLK_F5;
553 MISC_keymap[XK_F6&0xFF] = SDLK_F6;
554 MISC_keymap[XK_F7&0xFF] = SDLK_F7;
555 MISC_keymap[XK_F8&0xFF] = SDLK_F8;
556 MISC_keymap[XK_F9&0xFF] = SDLK_F9;
557 MISC_keymap[XK_F10&0xFF] = SDLK_F10;
558 MISC_keymap[XK_F11&0xFF] = SDLK_F11;
559 MISC_keymap[XK_F12&0xFF] = SDLK_F12;
560 MISC_keymap[XK_F13&0xFF] = SDLK_F13;
561 MISC_keymap[XK_F14&0xFF] = SDLK_F14;
562 MISC_keymap[XK_F15&0xFF] = SDLK_F15;
563
564 MISC_keymap[XK_Num_Lock&0xFF] = SDLK_NUMLOCK;
565 MISC_keymap[XK_Caps_Lock&0xFF] = SDLK_CAPSLOCK;
566 MISC_keymap[XK_Scroll_Lock&0xFF] = SDLK_SCROLLOCK;
567 MISC_keymap[XK_Shift_R&0xFF] = SDLK_RSHIFT;
568 MISC_keymap[XK_Shift_L&0xFF] = SDLK_LSHIFT;
569 MISC_keymap[XK_Control_R&0xFF] = SDLK_RCTRL;
570 MISC_keymap[XK_Control_L&0xFF] = SDLK_LCTRL;
571 MISC_keymap[XK_Alt_R&0xFF] = SDLK_RALT;
572 MISC_keymap[XK_Alt_L&0xFF] = SDLK_LALT;
573 MISC_keymap[XK_Meta_R&0xFF] = SDLK_RMETA;
574 MISC_keymap[XK_Meta_L&0xFF] = SDLK_LMETA;
575 MISC_keymap[XK_Super_L&0xFF] = SDLK_LSUPER; /* Left "Windows" */
576 MISC_keymap[XK_Super_R&0xFF] = SDLK_RSUPER; /* Right "Windows */
577 MISC_keymap[XK_Mode_switch&0xFF] = SDLK_MODE; /* "Alt Gr" key */
578 MISC_keymap[XK_Multi_key&0xFF] = SDLK_COMPOSE; /* Multi-key compose */
579
580 MISC_keymap[XK_Help&0xFF] = SDLK_HELP;
581 MISC_keymap[XK_Print&0xFF] = SDLK_PRINT;
582 MISC_keymap[XK_Sys_Req&0xFF] = SDLK_SYSREQ;
583 MISC_keymap[XK_Break&0xFF] = SDLK_BREAK;
584 MISC_keymap[XK_Menu&0xFF] = SDLK_MENU;
585 MISC_keymap[XK_Hyper_R&0xFF] = SDLK_MENU; /* Windows "Menu" key */
586 }
587
588 SDL_keysym *X11_TranslateKey(Display *display, XKeyEvent *xkey, KeyCode kc,
589 SDL_keysym *keysym)
590 {
591 KeySym xsym;
592
593 /* Get the raw keyboard scancode */
594 keysym->scancode = kc;
595 xsym = XKeycodeToKeysym(display, kc, 0);
596 #ifdef DEBUG_KEYS
597 fprintf(stderr, "Translating key 0x%.4x (%d)\n", xsym, kc);
598 #endif
599 /* Get the translated SDL virtual keysym */
600 keysym->sym = SDLK_UNKNOWN;
601 if ( xsym ) {
602 switch (xsym>>8) {
603 case 0x1005FF:
604 #ifdef SunXK_F36
605 if ( xsym == SunXK_F36 )
606 keysym->sym = SDLK_F11;
607 #endif
608 #ifdef SunXK_F37
609 if ( xsym == SunXK_F37 )
610 keysym->sym = SDLK_F12;
611 #endif
612 break;
613 case 0x00: /* Latin 1 */
614 case 0x01: /* Latin 2 */
615 case 0x02: /* Latin 3 */
616 case 0x03: /* Latin 4 */
617 case 0x04: /* Katakana */
618 case 0x05: /* Arabic */
619 case 0x06: /* Cyrillic */
620 case 0x07: /* Greek */
621 case 0x08: /* Technical */
622 case 0x0A: /* Publishing */
623 case 0x0C: /* Hebrew */
624 case 0x0D: /* Thai */
625 keysym->sym = (SDLKey)(xsym&0xFF);
626 /* Map capital letter syms to lowercase */
627 if ((keysym->sym >= 'A')&&(keysym->sym <= 'Z'))
628 keysym->sym += ('a'-'A');
629 break;
630 case 0xFE:
631 keysym->sym = ODD_keymap[xsym&0xFF];
632 break;
633 case 0xFF:
634 keysym->sym = MISC_keymap[xsym&0xFF];
635 break;
636 default:
637 fprintf(stderr,
638 "X11: Unknown xsym, sym = 0x%04x\n",
639 (unsigned int)xsym);
640 break;
641 }
642 } else {
643 /* X11 doesn't know how to translate the key! */
644 switch (kc) {
645 /* Caution:
646 These keycodes are from the Microsoft Keyboard
647 */
648 case 115:
649 keysym->sym = SDLK_LSUPER;
650 break;
651 case 116:
652 keysym->sym = SDLK_RSUPER;
653 break;
654 case 117:
655 keysym->sym = SDLK_MENU;
656 break;
657 default:
658 /*
659 * no point in an error message; happens for
660 * several keys when we get a keymap notify
661 */
662 break;
663 }
664 }
665 keysym->mod = KMOD_NONE;
666
667 /* If UNICODE is on, get the UNICODE value for the key */
668 keysym->unicode = 0;
669 if ( SDL_TranslateUNICODE && xkey ) {
670 static XComposeStatus state;
671 /* Until we handle the IM protocol, use XLookupString() */
672 unsigned char keybuf[32];
673
674 #define BROKEN_XFREE86_INTERNATIONAL_KBD
675 /* This appears to be a magical flag that is used with AltGr on
676 international keyboards to signal alternate key translations.
677 The flag doesn't show up when in fullscreen mode (?)
678 FIXME: Check to see if this code is safe for other servers.
679 */
680 #ifdef BROKEN_XFREE86_INTERNATIONAL_KBD
681 /* Work around what appears to be a bug in XFree86 */
682 if ( SDL_GetModState() & KMOD_MODE ) {
683 xkey->state |= (1<<13);
684 }
685 #endif
686 /* Look up the translated value for the key event */
687 if ( XLookupString(xkey, (char *)keybuf, sizeof(keybuf),
688 NULL, &state) ) {
689 /*
690 * FIXME,: XLookupString() may yield more than one
691 * character, so we need a mechanism to allow for
692 * this (perhaps generate null keypress events with
693 * a unicode value)
694 */
695 keysym->unicode = keybuf[0];
696 }
697 }
698 return(keysym);
699 }
700
701 /* X11 modifier masks for various keys */
702 static unsigned meta_l_mask, meta_r_mask, alt_l_mask, alt_r_mask;
703 static unsigned num_mask, mode_switch_mask;
704
705 static void get_modifier_masks(Display *display)
706 {
707 static unsigned got_masks;
708 int i, j;
709 XModifierKeymap *xmods;
710 unsigned n;
711
712 if(got_masks)
713 return;
714
715 xmods = XGetModifierMapping(display);
716 n = xmods->max_keypermod;
717 for(i = 3; i < 8; i++) {
718 for(j = 0; j < n; j++) {
719 KeyCode kc = xmods->modifiermap[i * n + j];
720 KeySym ks = XKeycodeToKeysym(display, kc, 0);
721 unsigned mask = 1 << i;
722 switch(ks) {
723 case XK_Num_Lock:
724 num_mask = mask; break;
725 case XK_Alt_L:
726 alt_l_mask = mask; break;
727 case XK_Alt_R:
728 alt_r_mask = mask; break;
729 case XK_Meta_L:
730 meta_l_mask = mask; break;
731 case XK_Meta_R:
732 meta_r_mask = mask; break;
733 case XK_Mode_switch:
734 mode_switch_mask = mask; break;
735 }
736 }
737 }
738 XFreeModifiermap(xmods);
739 got_masks = 1;
740 }
741
742
743 /*
744 * This function is semi-official; it is not officially exported and should
745 * not be considered part of the SDL API, but may be used by client code
746 * that *really* needs it (including legacy code).
747 * It is slow, though, and should be avoided if possible.
748 *
749 * Note that it isn't completely accurate either; in particular, multi-key
750 * sequences (dead accents, compose key sequences) will not work since the
751 * state has been irrevocably lost.
752 */
753 Uint16 X11_KeyToUnicode(SDLKey keysym, SDLMod modifiers)
754 {
755 struct SDL_VideoDevice *this = current_video;
756 char keybuf[32];
757 int i;
758 KeySym xsym = 0;
759 XKeyEvent xkey;
760 Uint16 unicode;
761
762 if ( !this || !SDL_Display ) {
763 return 0;
764 }
765
766 memset(&xkey, 0, sizeof(xkey));
767 xkey.display = SDL_Display;
768
769 xsym = keysym; /* last resort if not found */
770 for (i = 0; i < 256; ++i) {
771 if ( MISC_keymap[i] == keysym ) {
772 xsym = 0xFF00 | i;
773 break;
774 } else if ( ODD_keymap[i] == keysym ) {
775 xsym = 0xFE00 | i;
776 break;
777 }
778 }
779
780 xkey.keycode = XKeysymToKeycode(xkey.display, xsym);
781
782 get_modifier_masks(SDL_Display);
783 if(modifiers & KMOD_SHIFT)
784 xkey.state |= ShiftMask;
785 if(modifiers & KMOD_CAPS)
786 xkey.state |= LockMask;
787 if(modifiers & KMOD_CTRL)
788 xkey.state |= ControlMask;
789 if(modifiers & KMOD_MODE)
790 xkey.state |= mode_switch_mask;
791 if(modifiers & KMOD_LALT)
792 xkey.state |= alt_l_mask;
793 if(modifiers & KMOD_RALT)
794 xkey.state |= alt_r_mask;
795 if(modifiers & KMOD_LMETA)
796 xkey.state |= meta_l_mask;
797 if(modifiers & KMOD_RMETA)
798 xkey.state |= meta_r_mask;
799 if(modifiers & KMOD_NUM)
800 xkey.state |= num_mask;
801
802 unicode = 0;
803 if ( XLookupString(&xkey, keybuf, sizeof(keybuf), NULL, NULL) )
804 unicode = (unsigned char)keybuf[0];
805 return(unicode);
806 }
807
808 /*
809 * Called when focus is regained, to read the keyboard state and generate
810 * synthetic keypress/release events.
811 * key_vec is a bit vector of keycodes (256 bits)
812 */
813 void X11_SetKeyboardState(Display *display, const char *key_vec)
814 {
815 char keys_return[32];
816 int i, gen_event;
817 KeyCode xcode[SDLK_LAST];
818 Uint8 new_kstate[SDLK_LAST];
819 Uint8 *kstate = SDL_GetKeyState(NULL);
820
821 /* The first time the window is mapped, we initialize key state */
822 if ( ! key_vec ) {
823 key_vec = keys_return;
824 XQueryKeymap(display, keys_return);
825 gen_event = 0;
826 } else {
827 gen_event = 1;
828 }
829
830 /* Zero the new state and generate it */
831 memset(new_kstate, 0, sizeof(new_kstate));
832 /*
833 * An obvious optimisation is to check entire longwords at a time in
834 * both loops, but we can't be sure the arrays are aligned so it's not
835 * worth the extra complexity
836 */
837 for(i = 0; i < 32; i++) {
838 int j;
839 if(!key_vec[i])
840 continue;
841 for(j = 0; j < 8; j++) {
842 if(key_vec[i] & (1 << j)) {
843 SDL_keysym sk;
844 KeyCode kc = i << 3 | j;
845 X11_TranslateKey(display, NULL, kc, &sk);
846 new_kstate[sk.sym] = 1;
847 xcode[sk.sym] = kc;
848 }
849 }
850 }
851 for(i = SDLK_FIRST+1; i < SDLK_LAST; i++) {
852 int st;
853 SDL_keysym sk;
854
855 if(kstate[i] == new_kstate[i])
856 continue;
857 /*
858 * Send a fake keyboard event correcting the difference between
859 * SDL's keyboard state and the actual. Note that there is no
860 * way to find out the scancode for key releases, but since all
861 * keys are released when focus is lost only keypresses should
862 * be sent here
863 */
864 st = new_kstate[i] ? SDL_PRESSED : SDL_RELEASED;
865 memset(&sk, 0, sizeof(sk));
866 sk.sym = i;
867 sk.scancode = xcode[i]; /* only valid for key press */
868 if ( gen_event ) {
869 SDL_PrivateKeyboard(st, &sk);
870 } else {
871 kstate[i] = new_kstate[i];
872 }
873 }
874 }
875
876 void X11_InitOSKeymap(_THIS)
877 {
878 X11_InitKeymap();
879 }
880