0
|
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
|