comparison src/video/x11/SDL_x11events.c @ 1327:d12a63a8d95a

Resolved bug #130 Use XFilterEvent() to handle dead-key composition under X11 Cleaned up the code in preparation for 1.3 API changes
author Sam Lantinga <slouken@libsdl.org>
date Sat, 04 Feb 2006 08:35:11 +0000
parents c9b51268668f
children 27ddb06a0bca
comparison
equal deleted inserted replaced
1326:9439c2f1da89 1327:d12a63a8d95a
55 /*#define DEBUG_XEVENTS*/ 55 /*#define DEBUG_XEVENTS*/
56 56
57 /* The translation tables from an X11 keysym to a SDL keysym */ 57 /* The translation tables from an X11 keysym to a SDL keysym */
58 static SDLKey ODD_keymap[256]; 58 static SDLKey ODD_keymap[256];
59 static SDLKey MISC_keymap[256]; 59 static SDLKey MISC_keymap[256];
60 SDL_keysym *X11_TranslateKey(Display *display, XIC ic, XKeyEvent *xkey, KeyCode kc, 60 SDLKey X11_TranslateKeycode(Display *display, KeyCode kc);
61 SDL_keysym *keysym); 61
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 ( pXPending(display) ) {
73 pXPeekEvent(display, &peekevent);
74 if ( (peekevent.type == KeyPress) &&
75 (peekevent.xkey.keycode == event->xkey.keycode) &&
76 ((peekevent.xkey.time-event->xkey.time) < 2) ) {
77 repeated = 1;
78 pXNextEvent(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 ( pXCheckTypedEvent(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 pXWarpPointer(SDL_Display, None, SDL_Window, 0, 0, 0, 0,
126 mouse_last.x, mouse_last.y);
127 for ( i=0; i<10; ++i ) {
128 pXMaskEvent(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 memset(&xevent, '\0', sizeof (XEvent)); /* valgrind fix. --ryan. */
158 pXNextEvent(SDL_Display, &xevent);
159
160 posted = 0;
161 switch (xevent.type) {
162
163 /* Gaining mouse coverage? */
164 case EnterNotify: {
165 #ifdef DEBUG_XEVENTS
166 printf("EnterNotify! (%d,%d)\n", xevent.xcrossing.x, xevent.xcrossing.y);
167 if ( xevent.xcrossing.mode == NotifyGrab )
168 printf("Mode: NotifyGrab\n");
169 if ( xevent.xcrossing.mode == NotifyUngrab )
170 printf("Mode: NotifyUngrab\n");
171 #endif
172 if ( (xevent.xcrossing.mode != NotifyGrab) &&
173 (xevent.xcrossing.mode != NotifyUngrab) ) {
174 if ( this->input_grab == SDL_GRAB_OFF ) {
175 posted = SDL_PrivateAppActive(1, SDL_APPMOUSEFOCUS);
176 } else {
177 posted = SDL_PrivateMouseMotion(0, 0,
178 xevent.xcrossing.x,
179 xevent.xcrossing.y);
180 }
181 }
182 }
183 break;
184
185 /* Losing mouse coverage? */
186 case LeaveNotify: {
187 #ifdef DEBUG_XEVENTS
188 printf("LeaveNotify! (%d,%d)\n", xevent.xcrossing.x, xevent.xcrossing.y);
189 if ( xevent.xcrossing.mode == NotifyGrab )
190 printf("Mode: NotifyGrab\n");
191 if ( xevent.xcrossing.mode == NotifyUngrab )
192 printf("Mode: NotifyUngrab\n");
193 #endif
194 if ( (xevent.xcrossing.mode != NotifyGrab) &&
195 (xevent.xcrossing.mode != NotifyUngrab) &&
196 (xevent.xcrossing.detail != NotifyInferior) ) {
197 if ( this->input_grab == SDL_GRAB_OFF ) {
198 posted = SDL_PrivateAppActive(0, SDL_APPMOUSEFOCUS);
199 } else {
200 posted = SDL_PrivateMouseMotion(0, 0,
201 xevent.xcrossing.x,
202 xevent.xcrossing.y);
203 }
204 }
205 }
206 break;
207
208 /* Gaining input focus? */
209 case FocusIn: {
210 #ifdef DEBUG_XEVENTS
211 printf("FocusIn!\n");
212 #endif
213 posted = SDL_PrivateAppActive(1, SDL_APPINPUTFOCUS);
214
215 /* Queue entry into fullscreen mode */
216 switch_waiting = 0x01 | SDL_FULLSCREEN;
217 switch_time = SDL_GetTicks() + 1500;
218 }
219 break;
220
221 /* Losing input focus? */
222 case FocusOut: {
223 #ifdef DEBUG_XEVENTS
224 printf("FocusOut!\n");
225 #endif
226 posted = SDL_PrivateAppActive(0, SDL_APPINPUTFOCUS);
227
228 /* Queue leaving fullscreen mode */
229 switch_waiting = 0x01;
230 switch_time = SDL_GetTicks() + 200;
231 }
232 break;
233
234 /* Generated upon EnterWindow and FocusIn */
235 case KeymapNotify: {
236 #ifdef DEBUG_XEVENTS
237 printf("KeymapNotify!\n");
238 #endif
239 X11_SetKeyboardState(SDL_Display, SDL_IC, xevent.xkeymap.key_vector);
240 }
241 break;
242
243 /* Mouse motion? */
244 case MotionNotify: {
245 if ( SDL_VideoSurface ) {
246 if ( mouse_relative ) {
247 if ( using_dga & DGA_MOUSE ) {
248 #ifdef DEBUG_MOTION
249 printf("DGA motion: %d,%d\n", xevent.xmotion.x_root, xevent.xmotion.y_root);
250 #endif
251 posted = SDL_PrivateMouseMotion(0, 1,
252 xevent.xmotion.x_root,
253 xevent.xmotion.y_root);
254 } else {
255 posted = X11_WarpedMotion(this,&xevent);
256 }
257 } else {
258 #ifdef DEBUG_MOTION
259 printf("X11 motion: %d,%d\n", xevent.xmotion.x, xevent.xmotion.y);
260 #endif
261 posted = SDL_PrivateMouseMotion(0, 0,
262 xevent.xmotion.x,
263 xevent.xmotion.y);
264 }
265 }
266 }
267 break;
268
269 /* Mouse button press? */
270 case ButtonPress: {
271 posted = SDL_PrivateMouseButton(SDL_PRESSED,
272 xevent.xbutton.button, 0, 0);
273 }
274 break;
275
276 /* Mouse button release? */
277 case ButtonRelease: {
278 posted = SDL_PrivateMouseButton(SDL_RELEASED,
279 xevent.xbutton.button, 0, 0);
280 }
281 break;
282
283 /* Key press? */
284 case KeyPress: {
285 SDL_keysym keysym;
286
287 #ifdef DEBUG_XEVENTS
288 printf("KeyPress (X11 keycode = 0x%X)\n", xevent.xkey.keycode);
289 #endif
290 posted = SDL_PrivateKeyboard(SDL_PRESSED,
291 X11_TranslateKey(SDL_Display, SDL_IC, &xevent.xkey,
292 xevent.xkey.keycode,
293 &keysym));
294 }
295 break;
296
297 /* Key release? */
298 case KeyRelease: {
299 SDL_keysym keysym;
300
301 #ifdef DEBUG_XEVENTS
302 printf("KeyRelease (X11 keycode = 0x%X)\n", xevent.xkey.keycode);
303 #endif
304 /* Check to see if this is a repeated key */
305 if ( ! X11_KeyRepeat(SDL_Display, &xevent) ) {
306 posted = SDL_PrivateKeyboard(SDL_RELEASED,
307 X11_TranslateKey(SDL_Display, SDL_IC, &xevent.xkey,
308 xevent.xkey.keycode,
309 &keysym));
310 }
311 }
312 break;
313
314 /* Have we been iconified? */
315 case UnmapNotify: {
316 #ifdef DEBUG_XEVENTS
317 printf("UnmapNotify!\n");
318 #endif
319 /* If we're active, make ourselves inactive */
320 if ( SDL_GetAppState() & SDL_APPACTIVE ) {
321 /* Swap out the gamma before we go inactive */
322 X11_SwapVidModeGamma(this);
323
324 /* Send an internal deactivate event */
325 posted = SDL_PrivateAppActive(0,
326 SDL_APPACTIVE|SDL_APPINPUTFOCUS);
327 }
328 }
329 break;
330
331 /* Have we been restored? */
332 case MapNotify: {
333 #ifdef DEBUG_XEVENTS
334 printf("MapNotify!\n");
335 #endif
336 /* If we're not active, make ourselves active */
337 if ( !(SDL_GetAppState() & SDL_APPACTIVE) ) {
338 /* Send an internal activate event */
339 posted = SDL_PrivateAppActive(1, SDL_APPACTIVE);
340
341 /* Now that we're active, swap the gamma back */
342 X11_SwapVidModeGamma(this);
343 }
344
345 if ( SDL_VideoSurface &&
346 (SDL_VideoSurface->flags & SDL_FULLSCREEN) ) {
347 X11_EnterFullScreen(this);
348 } else {
349 X11_GrabInputNoLock(this, this->input_grab);
350 }
351 X11_CheckMouseModeNoLock(this);
352
353 if ( SDL_VideoSurface ) {
354 X11_RefreshDisplay(this);
355 }
356 }
357 break;
358
359 /* Have we been resized or moved? */
360 case ConfigureNotify: {
361 #ifdef DEBUG_XEVENTS
362 printf("ConfigureNotify! (resize: %dx%d)\n", xevent.xconfigure.width, xevent.xconfigure.height);
363 #endif
364 if ( SDL_VideoSurface ) {
365 if ((xevent.xconfigure.width != SDL_VideoSurface->w) ||
366 (xevent.xconfigure.height != SDL_VideoSurface->h)) {
367 /* FIXME: Find a better fix for the bug with KDE 1.2 */
368 if ( ! ((xevent.xconfigure.width == 32) &&
369 (xevent.xconfigure.height == 32)) ) {
370 SDL_PrivateResize(xevent.xconfigure.width,
371 xevent.xconfigure.height);
372 }
373 } else {
374 /* OpenGL windows need to know about the change */
375 if ( SDL_VideoSurface->flags & SDL_OPENGL ) {
376 SDL_PrivateExpose();
377 }
378 }
379 }
380 }
381 break;
382
383 /* Have we been requested to quit (or another client message?) */
384 case ClientMessage: {
385 if ( (xevent.xclient.format == 32) &&
386 (xevent.xclient.data.l[0] == WM_DELETE_WINDOW) )
387 {
388 posted = SDL_PrivateQuit();
389 } else
390 if ( SDL_ProcessEvents[SDL_SYSWMEVENT] == SDL_ENABLE ) {
391 SDL_SysWMmsg wmmsg;
392
393 SDL_VERSION(&wmmsg.version);
394 wmmsg.subsystem = SDL_SYSWM_X11;
395 wmmsg.event.xevent = xevent;
396 posted = SDL_PrivateSysWMEvent(&wmmsg);
397 }
398 }
399 break;
400
401 /* Do we need to refresh ourselves? */
402 case Expose: {
403 #ifdef DEBUG_XEVENTS
404 printf("Expose (count = %d)\n", xevent.xexpose.count);
405 #endif
406 if ( SDL_VideoSurface && (xevent.xexpose.count == 0) ) {
407 X11_RefreshDisplay(this);
408 }
409 }
410 break;
411
412 default: {
413 #ifdef DEBUG_XEVENTS
414 printf("Unhandled event %d\n", xevent.type);
415 #endif
416 /* Only post the event if we're watching for it */
417 if ( SDL_ProcessEvents[SDL_SYSWMEVENT] == SDL_ENABLE ) {
418 SDL_SysWMmsg wmmsg;
419
420 SDL_VERSION(&wmmsg.version);
421 wmmsg.subsystem = SDL_SYSWM_X11;
422 wmmsg.event.xevent = xevent;
423 posted = SDL_PrivateSysWMEvent(&wmmsg);
424 }
425 }
426 break;
427 }
428 return(posted);
429 }
430
431 /* Ack! XPending() actually performs a blocking read if no events available */
432 int X11_Pending(Display *display)
433 {
434 /* Flush the display connection and look to see if events are queued */
435 pXFlush(display);
436 if ( pXEventsQueued(display, QueuedAlready) ) {
437 return(1);
438 }
439
440 /* More drastic measures are required -- see if X is ready to talk */
441 {
442 static struct timeval zero_time; /* static == 0 */
443 int x11_fd;
444 fd_set fdset;
445
446 x11_fd = ConnectionNumber(display);
447 FD_ZERO(&fdset);
448 FD_SET(x11_fd, &fdset);
449 if ( select(x11_fd+1, &fdset, NULL, NULL, &zero_time) == 1 ) {
450 return(pXPending(display));
451 }
452 }
453
454 /* Oh well, nothing is ready .. */
455 return(0);
456 }
457
458 void X11_PumpEvents(_THIS)
459 {
460 int pending;
461
462 /* Keep processing pending events */
463 pending = 0;
464 while ( X11_Pending(SDL_Display) ) {
465 X11_DispatchEvent(this);
466 ++pending;
467 }
468 if ( switch_waiting ) {
469 Uint32 now;
470
471 now = SDL_GetTicks();
472 if ( pending || !SDL_VideoSurface ) {
473 /* Try again later... */
474 if ( switch_waiting & SDL_FULLSCREEN ) {
475 switch_time = now + 1500;
476 } else {
477 switch_time = now + 200;
478 }
479 } else if ( now >= switch_time ) {
480 Uint32 go_fullscreen;
481
482 go_fullscreen = switch_waiting & SDL_FULLSCREEN;
483 switch_waiting = 0;
484 if ( SDL_VideoSurface->flags & SDL_FULLSCREEN ) {
485 if ( go_fullscreen ) {
486 X11_EnterFullScreen(this);
487 } else {
488 X11_LeaveFullScreen(this);
489 }
490 }
491 /* Handle focus in/out when grabbed */
492 if ( go_fullscreen ) {
493 X11_GrabInputNoLock(this, this->input_grab);
494 } else {
495 X11_GrabInputNoLock(this, SDL_GRAB_OFF);
496 }
497 X11_CheckMouseModeNoLock(this);
498 }
499 }
500 }
501
502 void X11_InitKeymap(void)
503 {
504 int i;
505
506 /* Odd keys used in international keyboards */
507 for ( i=0; i<SDL_TABLESIZE(ODD_keymap); ++i )
508 ODD_keymap[i] = SDLK_UNKNOWN;
509
510 #ifdef XK_dead_circumflex
511 /* These X keysyms have 0xFE as the high byte */
512 ODD_keymap[XK_dead_circumflex&0xFF] = SDLK_CARET;
513 #endif
514 #ifdef XK_ISO_Level3_Shift
515 ODD_keymap[XK_ISO_Level3_Shift&0xFF] = SDLK_MODE; /* "Alt Gr" key */
516 #endif
517
518 /* Map the miscellaneous keys */
519 for ( i=0; i<SDL_TABLESIZE(MISC_keymap); ++i )
520 MISC_keymap[i] = SDLK_UNKNOWN;
521
522 /* These X keysyms have 0xFF as the high byte */
523 MISC_keymap[XK_BackSpace&0xFF] = SDLK_BACKSPACE;
524 MISC_keymap[XK_Tab&0xFF] = SDLK_TAB;
525 MISC_keymap[XK_Clear&0xFF] = SDLK_CLEAR;
526 MISC_keymap[XK_Return&0xFF] = SDLK_RETURN;
527 MISC_keymap[XK_Pause&0xFF] = SDLK_PAUSE;
528 MISC_keymap[XK_Escape&0xFF] = SDLK_ESCAPE;
529 MISC_keymap[XK_Delete&0xFF] = SDLK_DELETE;
530
531 MISC_keymap[XK_KP_0&0xFF] = SDLK_KP0; /* Keypad 0-9 */
532 MISC_keymap[XK_KP_1&0xFF] = SDLK_KP1;
533 MISC_keymap[XK_KP_2&0xFF] = SDLK_KP2;
534 MISC_keymap[XK_KP_3&0xFF] = SDLK_KP3;
535 MISC_keymap[XK_KP_4&0xFF] = SDLK_KP4;
536 MISC_keymap[XK_KP_5&0xFF] = SDLK_KP5;
537 MISC_keymap[XK_KP_6&0xFF] = SDLK_KP6;
538 MISC_keymap[XK_KP_7&0xFF] = SDLK_KP7;
539 MISC_keymap[XK_KP_8&0xFF] = SDLK_KP8;
540 MISC_keymap[XK_KP_9&0xFF] = SDLK_KP9;
541 MISC_keymap[XK_KP_Insert&0xFF] = SDLK_KP0;
542 MISC_keymap[XK_KP_End&0xFF] = SDLK_KP1;
543 MISC_keymap[XK_KP_Down&0xFF] = SDLK_KP2;
544 MISC_keymap[XK_KP_Page_Down&0xFF] = SDLK_KP3;
545 MISC_keymap[XK_KP_Left&0xFF] = SDLK_KP4;
546 MISC_keymap[XK_KP_Begin&0xFF] = SDLK_KP5;
547 MISC_keymap[XK_KP_Right&0xFF] = SDLK_KP6;
548 MISC_keymap[XK_KP_Home&0xFF] = SDLK_KP7;
549 MISC_keymap[XK_KP_Up&0xFF] = SDLK_KP8;
550 MISC_keymap[XK_KP_Page_Up&0xFF] = SDLK_KP9;
551 MISC_keymap[XK_KP_Delete&0xFF] = SDLK_KP_PERIOD;
552 MISC_keymap[XK_KP_Decimal&0xFF] = SDLK_KP_PERIOD;
553 MISC_keymap[XK_KP_Divide&0xFF] = SDLK_KP_DIVIDE;
554 MISC_keymap[XK_KP_Multiply&0xFF] = SDLK_KP_MULTIPLY;
555 MISC_keymap[XK_KP_Subtract&0xFF] = SDLK_KP_MINUS;
556 MISC_keymap[XK_KP_Add&0xFF] = SDLK_KP_PLUS;
557 MISC_keymap[XK_KP_Enter&0xFF] = SDLK_KP_ENTER;
558 MISC_keymap[XK_KP_Equal&0xFF] = SDLK_KP_EQUALS;
559
560 MISC_keymap[XK_Up&0xFF] = SDLK_UP;
561 MISC_keymap[XK_Down&0xFF] = SDLK_DOWN;
562 MISC_keymap[XK_Right&0xFF] = SDLK_RIGHT;
563 MISC_keymap[XK_Left&0xFF] = SDLK_LEFT;
564 MISC_keymap[XK_Insert&0xFF] = SDLK_INSERT;
565 MISC_keymap[XK_Home&0xFF] = SDLK_HOME;
566 MISC_keymap[XK_End&0xFF] = SDLK_END;
567 MISC_keymap[XK_Page_Up&0xFF] = SDLK_PAGEUP;
568 MISC_keymap[XK_Page_Down&0xFF] = SDLK_PAGEDOWN;
569
570 MISC_keymap[XK_F1&0xFF] = SDLK_F1;
571 MISC_keymap[XK_F2&0xFF] = SDLK_F2;
572 MISC_keymap[XK_F3&0xFF] = SDLK_F3;
573 MISC_keymap[XK_F4&0xFF] = SDLK_F4;
574 MISC_keymap[XK_F5&0xFF] = SDLK_F5;
575 MISC_keymap[XK_F6&0xFF] = SDLK_F6;
576 MISC_keymap[XK_F7&0xFF] = SDLK_F7;
577 MISC_keymap[XK_F8&0xFF] = SDLK_F8;
578 MISC_keymap[XK_F9&0xFF] = SDLK_F9;
579 MISC_keymap[XK_F10&0xFF] = SDLK_F10;
580 MISC_keymap[XK_F11&0xFF] = SDLK_F11;
581 MISC_keymap[XK_F12&0xFF] = SDLK_F12;
582 MISC_keymap[XK_F13&0xFF] = SDLK_F13;
583 MISC_keymap[XK_F14&0xFF] = SDLK_F14;
584 MISC_keymap[XK_F15&0xFF] = SDLK_F15;
585
586 MISC_keymap[XK_Num_Lock&0xFF] = SDLK_NUMLOCK;
587 MISC_keymap[XK_Caps_Lock&0xFF] = SDLK_CAPSLOCK;
588 MISC_keymap[XK_Scroll_Lock&0xFF] = SDLK_SCROLLOCK;
589 MISC_keymap[XK_Shift_R&0xFF] = SDLK_RSHIFT;
590 MISC_keymap[XK_Shift_L&0xFF] = SDLK_LSHIFT;
591 MISC_keymap[XK_Control_R&0xFF] = SDLK_RCTRL;
592 MISC_keymap[XK_Control_L&0xFF] = SDLK_LCTRL;
593 MISC_keymap[XK_Alt_R&0xFF] = SDLK_RALT;
594 MISC_keymap[XK_Alt_L&0xFF] = SDLK_LALT;
595 MISC_keymap[XK_Meta_R&0xFF] = SDLK_RMETA;
596 MISC_keymap[XK_Meta_L&0xFF] = SDLK_LMETA;
597 MISC_keymap[XK_Super_L&0xFF] = SDLK_LSUPER; /* Left "Windows" */
598 MISC_keymap[XK_Super_R&0xFF] = SDLK_RSUPER; /* Right "Windows */
599 MISC_keymap[XK_Mode_switch&0xFF] = SDLK_MODE; /* "Alt Gr" key */
600 MISC_keymap[XK_Multi_key&0xFF] = SDLK_COMPOSE; /* Multi-key compose */
601
602 MISC_keymap[XK_Help&0xFF] = SDLK_HELP;
603 MISC_keymap[XK_Print&0xFF] = SDLK_PRINT;
604 MISC_keymap[XK_Sys_Req&0xFF] = SDLK_SYSREQ;
605 MISC_keymap[XK_Break&0xFF] = SDLK_BREAK;
606 MISC_keymap[XK_Menu&0xFF] = SDLK_MENU;
607 MISC_keymap[XK_Hyper_R&0xFF] = SDLK_MENU; /* Windows "Menu" key */
608 }
609 62
610 #ifdef X_HAVE_UTF8_STRING 63 #ifdef X_HAVE_UTF8_STRING
611 Uint32 Utf8ToUcs4(const unsigned char *utf8) 64 Uint32 Utf8ToUcs4(const Uint8 *utf8)
612 { 65 {
613 Uint32 c; 66 Uint32 c;
614 int i = 1; 67 int i = 1;
615 int noOctets = 0; 68 int noOctets = 0;
616 int firstOctetMask = 0; 69 int firstOctetMask = 0;
725 } 178 }
726 return c; 179 return c;
727 } 180 }
728 #endif 181 #endif
729 182
730 183 /* Check to see if this is a repeated key.
731 SDL_keysym *X11_TranslateKey(Display *display, XIC ic, XKeyEvent *xkey, KeyCode kc, 184 (idea shamelessly lifted from GII -- thanks guys! :)
732 SDL_keysym *keysym) 185 */
186 static int X11_KeyRepeat(Display *display, XEvent *event)
187 {
188 XEvent peekevent;
189 int repeated;
190
191 repeated = 0;
192 if ( pXPending(display) ) {
193 pXPeekEvent(display, &peekevent);
194 if ( (peekevent.type == KeyPress) &&
195 (peekevent.xkey.keycode == event->xkey.keycode) &&
196 ((peekevent.xkey.time-event->xkey.time) < 2) ) {
197 repeated = 1;
198 pXNextEvent(display, &peekevent);
199 }
200 }
201 return(repeated);
202 }
203
204 /* Note: The X server buffers and accumulates mouse motion events, so
205 the motion event generated by the warp may not appear exactly as we
206 expect it to. We work around this (and improve performance) by only
207 warping the pointer when it reaches the edge, and then wait for it.
208 */
209 #define MOUSE_FUDGE_FACTOR 8
210
211 static __inline__ int X11_WarpedMotion(_THIS, XEvent *xevent)
212 {
213 int w, h, i;
214 int deltax, deltay;
215 int posted;
216
217 w = SDL_VideoSurface->w;
218 h = SDL_VideoSurface->h;
219 deltax = xevent->xmotion.x - mouse_last.x;
220 deltay = xevent->xmotion.y - mouse_last.y;
221 #ifdef DEBUG_MOTION
222 printf("Warped mouse motion: %d,%d\n", deltax, deltay);
223 #endif
224 mouse_last.x = xevent->xmotion.x;
225 mouse_last.y = xevent->xmotion.y;
226 posted = SDL_PrivateMouseMotion(0, 1, deltax, deltay);
227
228 if ( (xevent->xmotion.x < MOUSE_FUDGE_FACTOR) ||
229 (xevent->xmotion.x > (w-MOUSE_FUDGE_FACTOR)) ||
230 (xevent->xmotion.y < MOUSE_FUDGE_FACTOR) ||
231 (xevent->xmotion.y > (h-MOUSE_FUDGE_FACTOR)) ) {
232 /* Get the events that have accumulated */
233 while ( pXCheckTypedEvent(SDL_Display, MotionNotify, xevent) ) {
234 deltax = xevent->xmotion.x - mouse_last.x;
235 deltay = xevent->xmotion.y - mouse_last.y;
236 #ifdef DEBUG_MOTION
237 printf("Extra mouse motion: %d,%d\n", deltax, deltay);
238 #endif
239 mouse_last.x = xevent->xmotion.x;
240 mouse_last.y = xevent->xmotion.y;
241 posted += SDL_PrivateMouseMotion(0, 1, deltax, deltay);
242 }
243 mouse_last.x = w/2;
244 mouse_last.y = h/2;
245 pXWarpPointer(SDL_Display, None, SDL_Window, 0, 0, 0, 0,
246 mouse_last.x, mouse_last.y);
247 for ( i=0; i<10; ++i ) {
248 pXMaskEvent(SDL_Display, PointerMotionMask, xevent);
249 if ( (xevent->xmotion.x >
250 (mouse_last.x-MOUSE_FUDGE_FACTOR)) &&
251 (xevent->xmotion.x <
252 (mouse_last.x+MOUSE_FUDGE_FACTOR)) &&
253 (xevent->xmotion.y >
254 (mouse_last.y-MOUSE_FUDGE_FACTOR)) &&
255 (xevent->xmotion.y <
256 (mouse_last.y+MOUSE_FUDGE_FACTOR)) ) {
257 break;
258 }
259 #ifdef DEBUG_XEVENTS
260 printf("Lost mouse motion: %d,%d\n", xevent->xmotion.x, xevent->xmotion.y);
261 #endif
262 }
263 #ifdef DEBUG_XEVENTS
264 if ( i == 10 ) {
265 printf("Warning: didn't detect mouse warp motion\n");
266 }
267 #endif
268 }
269 return(posted);
270 }
271
272 static int X11_DispatchEvent(_THIS)
273 {
274 int posted;
275 XEvent xevent;
276
277 memset(&xevent, '\0', sizeof (XEvent)); /* valgrind fix. --ryan. */
278 pXNextEvent(SDL_Display, &xevent);
279
280 posted = 0;
281 switch (xevent.type) {
282
283 /* Gaining mouse coverage? */
284 case EnterNotify: {
285 #ifdef DEBUG_XEVENTS
286 printf("EnterNotify! (%d,%d)\n", xevent.xcrossing.x, xevent.xcrossing.y);
287 if ( xevent.xcrossing.mode == NotifyGrab )
288 printf("Mode: NotifyGrab\n");
289 if ( xevent.xcrossing.mode == NotifyUngrab )
290 printf("Mode: NotifyUngrab\n");
291 #endif
292 if ( (xevent.xcrossing.mode != NotifyGrab) &&
293 (xevent.xcrossing.mode != NotifyUngrab) ) {
294 if ( this->input_grab == SDL_GRAB_OFF ) {
295 posted = SDL_PrivateAppActive(1, SDL_APPMOUSEFOCUS);
296 } else {
297 posted = SDL_PrivateMouseMotion(0, 0,
298 xevent.xcrossing.x,
299 xevent.xcrossing.y);
300 }
301 }
302 }
303 break;
304
305 /* Losing mouse coverage? */
306 case LeaveNotify: {
307 #ifdef DEBUG_XEVENTS
308 printf("LeaveNotify! (%d,%d)\n", xevent.xcrossing.x, xevent.xcrossing.y);
309 if ( xevent.xcrossing.mode == NotifyGrab )
310 printf("Mode: NotifyGrab\n");
311 if ( xevent.xcrossing.mode == NotifyUngrab )
312 printf("Mode: NotifyUngrab\n");
313 #endif
314 if ( (xevent.xcrossing.mode != NotifyGrab) &&
315 (xevent.xcrossing.mode != NotifyUngrab) &&
316 (xevent.xcrossing.detail != NotifyInferior) ) {
317 if ( this->input_grab == SDL_GRAB_OFF ) {
318 posted = SDL_PrivateAppActive(0, SDL_APPMOUSEFOCUS);
319 } else {
320 posted = SDL_PrivateMouseMotion(0, 0,
321 xevent.xcrossing.x,
322 xevent.xcrossing.y);
323 }
324 }
325 }
326 break;
327
328 /* Gaining input focus? */
329 case FocusIn: {
330 #ifdef DEBUG_XEVENTS
331 printf("FocusIn!\n");
332 #endif
333 posted = SDL_PrivateAppActive(1, SDL_APPINPUTFOCUS);
334
335 if ( SDL_IC != NULL ) {
336 pXSetICFocus(SDL_IC);
337 }
338
339 /* Queue entry into fullscreen mode */
340 switch_waiting = 0x01 | SDL_FULLSCREEN;
341 switch_time = SDL_GetTicks() + 1500;
342 }
343 break;
344
345 /* Losing input focus? */
346 case FocusOut: {
347 #ifdef DEBUG_XEVENTS
348 printf("FocusOut!\n");
349 #endif
350 posted = SDL_PrivateAppActive(0, SDL_APPINPUTFOCUS);
351
352 if ( SDL_IC != NULL ) {
353 pXUnsetICFocus(SDL_IC);
354 }
355
356 /* Queue leaving fullscreen mode */
357 switch_waiting = 0x01;
358 switch_time = SDL_GetTicks() + 200;
359 }
360 break;
361
362 /* Generated upon EnterWindow and FocusIn */
363 case KeymapNotify: {
364 #ifdef DEBUG_XEVENTS
365 printf("KeymapNotify!\n");
366 #endif
367 X11_SetKeyboardState(SDL_Display, xevent.xkeymap.key_vector);
368 }
369 break;
370
371 /* Mouse motion? */
372 case MotionNotify: {
373 if ( SDL_VideoSurface ) {
374 if ( mouse_relative ) {
375 if ( using_dga & DGA_MOUSE ) {
376 #ifdef DEBUG_MOTION
377 printf("DGA motion: %d,%d\n", xevent.xmotion.x_root, xevent.xmotion.y_root);
378 #endif
379 posted = SDL_PrivateMouseMotion(0, 1,
380 xevent.xmotion.x_root,
381 xevent.xmotion.y_root);
382 } else {
383 posted = X11_WarpedMotion(this,&xevent);
384 }
385 } else {
386 #ifdef DEBUG_MOTION
387 printf("X11 motion: %d,%d\n", xevent.xmotion.x, xevent.xmotion.y);
388 #endif
389 posted = SDL_PrivateMouseMotion(0, 0,
390 xevent.xmotion.x,
391 xevent.xmotion.y);
392 }
393 }
394 }
395 break;
396
397 /* Mouse button press? */
398 case ButtonPress: {
399 posted = SDL_PrivateMouseButton(SDL_PRESSED,
400 xevent.xbutton.button, 0, 0);
401 }
402 break;
403
404 /* Mouse button release? */
405 case ButtonRelease: {
406 posted = SDL_PrivateMouseButton(SDL_RELEASED,
407 xevent.xbutton.button, 0, 0);
408 }
409 break;
410
411 /* Key press? */
412 case KeyPress: {
413 static SDL_keysym saved_keysym;
414 SDL_keysym keysym;
415 KeyCode keycode = xevent.xkey.keycode;
416
417 #ifdef DEBUG_XEVENTS
418 printf("KeyPress (X11 keycode = 0x%X)\n", xevent.xkey.keycode);
419 #endif
420 /* Get the translated SDL virtual keysym */
421 if ( keycode ) {
422 keysym.scancode = keycode;
423 keysym.sym = X11_TranslateKeycode(SDL_Display, keycode);
424 keysym.mod = KMOD_NONE;
425 keysym.unicode = 0;
426 } else {
427 keysym = saved_keysym;
428 }
429
430 /* If we're not doing translation, we're done! */
431 if ( !SDL_TranslateUNICODE ) {
432 posted = SDL_PrivateKeyboard(SDL_PRESSED, &keysym);
433 break;
434 }
435
436 if ( pXFilterEvent(&xevent, None) ) {
437 if ( xevent.xkey.keycode ) {
438 posted = SDL_PrivateKeyboard(SDL_PRESSED, &keysym);
439 } else {
440 /* Save event to be associated with IM text
441 In 1.3 we'll have a text event instead.. */
442 saved_keysym = keysym;
443 }
444 break;
445 }
446
447 /* Look up the translated value for the key event */
448 #ifdef X_HAVE_UTF8_STRING
449 if ( SDL_IC != NULL ) {
450 static Status state;
451 /* A UTF-8 character can be at most 6 bytes */
452 char keybuf[6];
453 if ( pXutf8LookupString(SDL_IC, &xevent.xkey,
454 keybuf, sizeof(keybuf),
455 NULL, &state) ) {
456 keysym.unicode = Utf8ToUcs4((Uint8*)keybuf);
457 }
458 }
459 else
460 #endif
461 {
462 static XComposeStatus state;
463 char keybuf[32];
464
465 if ( pXLookupString(&xevent.xkey,
466 keybuf, sizeof(keybuf),
467 NULL, &state) ) {
468 /*
469 * FIXME: XLookupString() may yield more than one
470 * character, so we need a mechanism to allow for
471 * this (perhaps null keypress events with a
472 * unicode value)
473 */
474 keysym.unicode = (Uint8)keybuf[0];
475 }
476 }
477 posted = SDL_PrivateKeyboard(SDL_PRESSED, &keysym);
478 }
479 break;
480
481 /* Key release? */
482 case KeyRelease: {
483 SDL_keysym keysym;
484 KeyCode keycode = xevent.xkey.keycode;
485
486 #ifdef DEBUG_XEVENTS
487 printf("KeyRelease (X11 keycode = 0x%X)\n", xevent.xkey.keycode);
488 #endif
489 /* Check to see if this is a repeated key */
490 if ( X11_KeyRepeat(SDL_Display, &xevent) ) {
491 break;
492 }
493
494 /* Get the translated SDL virtual keysym */
495 keysym.scancode = keycode;
496 keysym.sym = X11_TranslateKeycode(SDL_Display, keycode);
497 keysym.mod = KMOD_NONE;
498 keysym.unicode = 0;
499
500 posted = SDL_PrivateKeyboard(SDL_RELEASED, &keysym);
501 }
502 break;
503
504 /* Have we been iconified? */
505 case UnmapNotify: {
506 #ifdef DEBUG_XEVENTS
507 printf("UnmapNotify!\n");
508 #endif
509 /* If we're active, make ourselves inactive */
510 if ( SDL_GetAppState() & SDL_APPACTIVE ) {
511 /* Swap out the gamma before we go inactive */
512 X11_SwapVidModeGamma(this);
513
514 /* Send an internal deactivate event */
515 posted = SDL_PrivateAppActive(0,
516 SDL_APPACTIVE|SDL_APPINPUTFOCUS);
517 }
518 }
519 break;
520
521 /* Have we been restored? */
522 case MapNotify: {
523 #ifdef DEBUG_XEVENTS
524 printf("MapNotify!\n");
525 #endif
526 /* If we're not active, make ourselves active */
527 if ( !(SDL_GetAppState() & SDL_APPACTIVE) ) {
528 /* Send an internal activate event */
529 posted = SDL_PrivateAppActive(1, SDL_APPACTIVE);
530
531 /* Now that we're active, swap the gamma back */
532 X11_SwapVidModeGamma(this);
533 }
534
535 if ( SDL_VideoSurface &&
536 (SDL_VideoSurface->flags & SDL_FULLSCREEN) ) {
537 X11_EnterFullScreen(this);
538 } else {
539 X11_GrabInputNoLock(this, this->input_grab);
540 }
541 X11_CheckMouseModeNoLock(this);
542
543 if ( SDL_VideoSurface ) {
544 X11_RefreshDisplay(this);
545 }
546 }
547 break;
548
549 /* Have we been resized or moved? */
550 case ConfigureNotify: {
551 #ifdef DEBUG_XEVENTS
552 printf("ConfigureNotify! (resize: %dx%d)\n", xevent.xconfigure.width, xevent.xconfigure.height);
553 #endif
554 if ( SDL_VideoSurface ) {
555 if ((xevent.xconfigure.width != SDL_VideoSurface->w) ||
556 (xevent.xconfigure.height != SDL_VideoSurface->h)) {
557 /* FIXME: Find a better fix for the bug with KDE 1.2 */
558 if ( ! ((xevent.xconfigure.width == 32) &&
559 (xevent.xconfigure.height == 32)) ) {
560 SDL_PrivateResize(xevent.xconfigure.width,
561 xevent.xconfigure.height);
562 }
563 } else {
564 /* OpenGL windows need to know about the change */
565 if ( SDL_VideoSurface->flags & SDL_OPENGL ) {
566 SDL_PrivateExpose();
567 }
568 }
569 }
570 }
571 break;
572
573 /* Have we been requested to quit (or another client message?) */
574 case ClientMessage: {
575 if ( (xevent.xclient.format == 32) &&
576 (xevent.xclient.data.l[0] == WM_DELETE_WINDOW) )
577 {
578 posted = SDL_PrivateQuit();
579 } else
580 if ( SDL_ProcessEvents[SDL_SYSWMEVENT] == SDL_ENABLE ) {
581 SDL_SysWMmsg wmmsg;
582
583 SDL_VERSION(&wmmsg.version);
584 wmmsg.subsystem = SDL_SYSWM_X11;
585 wmmsg.event.xevent = xevent;
586 posted = SDL_PrivateSysWMEvent(&wmmsg);
587 }
588 }
589 break;
590
591 /* Do we need to refresh ourselves? */
592 case Expose: {
593 #ifdef DEBUG_XEVENTS
594 printf("Expose (count = %d)\n", xevent.xexpose.count);
595 #endif
596 if ( SDL_VideoSurface && (xevent.xexpose.count == 0) ) {
597 X11_RefreshDisplay(this);
598 }
599 }
600 break;
601
602 default: {
603 #ifdef DEBUG_XEVENTS
604 printf("Unhandled event %d\n", xevent.type);
605 #endif
606 /* Only post the event if we're watching for it */
607 if ( SDL_ProcessEvents[SDL_SYSWMEVENT] == SDL_ENABLE ) {
608 SDL_SysWMmsg wmmsg;
609
610 SDL_VERSION(&wmmsg.version);
611 wmmsg.subsystem = SDL_SYSWM_X11;
612 wmmsg.event.xevent = xevent;
613 posted = SDL_PrivateSysWMEvent(&wmmsg);
614 }
615 }
616 break;
617 }
618 return(posted);
619 }
620
621 /* Ack! XPending() actually performs a blocking read if no events available */
622 int X11_Pending(Display *display)
623 {
624 /* Flush the display connection and look to see if events are queued */
625 pXFlush(display);
626 if ( pXEventsQueued(display, QueuedAlready) ) {
627 return(1);
628 }
629
630 /* More drastic measures are required -- see if X is ready to talk */
631 {
632 static struct timeval zero_time; /* static == 0 */
633 int x11_fd;
634 fd_set fdset;
635
636 x11_fd = ConnectionNumber(display);
637 FD_ZERO(&fdset);
638 FD_SET(x11_fd, &fdset);
639 if ( select(x11_fd+1, &fdset, NULL, NULL, &zero_time) == 1 ) {
640 return(pXPending(display));
641 }
642 }
643
644 /* Oh well, nothing is ready .. */
645 return(0);
646 }
647
648 void X11_PumpEvents(_THIS)
649 {
650 int pending;
651
652 /* Keep processing pending events */
653 pending = 0;
654 while ( X11_Pending(SDL_Display) ) {
655 X11_DispatchEvent(this);
656 ++pending;
657 }
658 if ( switch_waiting ) {
659 Uint32 now;
660
661 now = SDL_GetTicks();
662 if ( pending || !SDL_VideoSurface ) {
663 /* Try again later... */
664 if ( switch_waiting & SDL_FULLSCREEN ) {
665 switch_time = now + 1500;
666 } else {
667 switch_time = now + 200;
668 }
669 } else if ( now >= switch_time ) {
670 Uint32 go_fullscreen;
671
672 go_fullscreen = switch_waiting & SDL_FULLSCREEN;
673 switch_waiting = 0;
674 if ( SDL_VideoSurface->flags & SDL_FULLSCREEN ) {
675 if ( go_fullscreen ) {
676 X11_EnterFullScreen(this);
677 } else {
678 X11_LeaveFullScreen(this);
679 }
680 }
681 /* Handle focus in/out when grabbed */
682 if ( go_fullscreen ) {
683 X11_GrabInputNoLock(this, this->input_grab);
684 } else {
685 X11_GrabInputNoLock(this, SDL_GRAB_OFF);
686 }
687 X11_CheckMouseModeNoLock(this);
688 }
689 }
690 }
691
692 void X11_InitKeymap(void)
693 {
694 int i;
695
696 /* Odd keys used in international keyboards */
697 for ( i=0; i<SDL_TABLESIZE(ODD_keymap); ++i )
698 ODD_keymap[i] = SDLK_UNKNOWN;
699
700 /* Some of these might be mappable to an existing SDLK_ code */
701 ODD_keymap[XK_dead_grave&0xFF] = SDLK_COMPOSE;
702 ODD_keymap[XK_dead_acute&0xFF] = SDLK_COMPOSE;
703 ODD_keymap[XK_dead_tilde&0xFF] = SDLK_COMPOSE;
704 ODD_keymap[XK_dead_macron&0xFF] = SDLK_COMPOSE;
705 ODD_keymap[XK_dead_breve&0xFF] = SDLK_COMPOSE;
706 ODD_keymap[XK_dead_abovedot&0xFF] = SDLK_COMPOSE;
707 ODD_keymap[XK_dead_diaeresis&0xFF] = SDLK_COMPOSE;
708 ODD_keymap[XK_dead_abovering&0xFF] = SDLK_COMPOSE;
709 ODD_keymap[XK_dead_doubleacute&0xFF] = SDLK_COMPOSE;
710 ODD_keymap[XK_dead_caron&0xFF] = SDLK_COMPOSE;
711 ODD_keymap[XK_dead_cedilla&0xFF] = SDLK_COMPOSE;
712 ODD_keymap[XK_dead_ogonek&0xFF] = SDLK_COMPOSE;
713 ODD_keymap[XK_dead_iota&0xFF] = SDLK_COMPOSE;
714 ODD_keymap[XK_dead_voiced_sound&0xFF] = SDLK_COMPOSE;
715 ODD_keymap[XK_dead_semivoiced_sound&0xFF] = SDLK_COMPOSE;
716 ODD_keymap[XK_dead_belowdot&0xFF] = SDLK_COMPOSE;
717 ODD_keymap[XK_dead_hook&0xFF] = SDLK_COMPOSE;
718 ODD_keymap[XK_dead_horn&0xFF] = SDLK_COMPOSE;
719
720 #ifdef XK_dead_circumflex
721 /* These X keysyms have 0xFE as the high byte */
722 ODD_keymap[XK_dead_circumflex&0xFF] = SDLK_CARET;
723 #endif
724 #ifdef XK_ISO_Level3_Shift
725 ODD_keymap[XK_ISO_Level3_Shift&0xFF] = SDLK_MODE; /* "Alt Gr" key */
726 #endif
727
728 /* Map the miscellaneous keys */
729 for ( i=0; i<SDL_TABLESIZE(MISC_keymap); ++i )
730 MISC_keymap[i] = SDLK_UNKNOWN;
731
732 /* These X keysyms have 0xFF as the high byte */
733 MISC_keymap[XK_BackSpace&0xFF] = SDLK_BACKSPACE;
734 MISC_keymap[XK_Tab&0xFF] = SDLK_TAB;
735 MISC_keymap[XK_Clear&0xFF] = SDLK_CLEAR;
736 MISC_keymap[XK_Return&0xFF] = SDLK_RETURN;
737 MISC_keymap[XK_Pause&0xFF] = SDLK_PAUSE;
738 MISC_keymap[XK_Escape&0xFF] = SDLK_ESCAPE;
739 MISC_keymap[XK_Delete&0xFF] = SDLK_DELETE;
740
741 MISC_keymap[XK_KP_0&0xFF] = SDLK_KP0; /* Keypad 0-9 */
742 MISC_keymap[XK_KP_1&0xFF] = SDLK_KP1;
743 MISC_keymap[XK_KP_2&0xFF] = SDLK_KP2;
744 MISC_keymap[XK_KP_3&0xFF] = SDLK_KP3;
745 MISC_keymap[XK_KP_4&0xFF] = SDLK_KP4;
746 MISC_keymap[XK_KP_5&0xFF] = SDLK_KP5;
747 MISC_keymap[XK_KP_6&0xFF] = SDLK_KP6;
748 MISC_keymap[XK_KP_7&0xFF] = SDLK_KP7;
749 MISC_keymap[XK_KP_8&0xFF] = SDLK_KP8;
750 MISC_keymap[XK_KP_9&0xFF] = SDLK_KP9;
751 MISC_keymap[XK_KP_Insert&0xFF] = SDLK_KP0;
752 MISC_keymap[XK_KP_End&0xFF] = SDLK_KP1;
753 MISC_keymap[XK_KP_Down&0xFF] = SDLK_KP2;
754 MISC_keymap[XK_KP_Page_Down&0xFF] = SDLK_KP3;
755 MISC_keymap[XK_KP_Left&0xFF] = SDLK_KP4;
756 MISC_keymap[XK_KP_Begin&0xFF] = SDLK_KP5;
757 MISC_keymap[XK_KP_Right&0xFF] = SDLK_KP6;
758 MISC_keymap[XK_KP_Home&0xFF] = SDLK_KP7;
759 MISC_keymap[XK_KP_Up&0xFF] = SDLK_KP8;
760 MISC_keymap[XK_KP_Page_Up&0xFF] = SDLK_KP9;
761 MISC_keymap[XK_KP_Delete&0xFF] = SDLK_KP_PERIOD;
762 MISC_keymap[XK_KP_Decimal&0xFF] = SDLK_KP_PERIOD;
763 MISC_keymap[XK_KP_Divide&0xFF] = SDLK_KP_DIVIDE;
764 MISC_keymap[XK_KP_Multiply&0xFF] = SDLK_KP_MULTIPLY;
765 MISC_keymap[XK_KP_Subtract&0xFF] = SDLK_KP_MINUS;
766 MISC_keymap[XK_KP_Add&0xFF] = SDLK_KP_PLUS;
767 MISC_keymap[XK_KP_Enter&0xFF] = SDLK_KP_ENTER;
768 MISC_keymap[XK_KP_Equal&0xFF] = SDLK_KP_EQUALS;
769
770 MISC_keymap[XK_Up&0xFF] = SDLK_UP;
771 MISC_keymap[XK_Down&0xFF] = SDLK_DOWN;
772 MISC_keymap[XK_Right&0xFF] = SDLK_RIGHT;
773 MISC_keymap[XK_Left&0xFF] = SDLK_LEFT;
774 MISC_keymap[XK_Insert&0xFF] = SDLK_INSERT;
775 MISC_keymap[XK_Home&0xFF] = SDLK_HOME;
776 MISC_keymap[XK_End&0xFF] = SDLK_END;
777 MISC_keymap[XK_Page_Up&0xFF] = SDLK_PAGEUP;
778 MISC_keymap[XK_Page_Down&0xFF] = SDLK_PAGEDOWN;
779
780 MISC_keymap[XK_F1&0xFF] = SDLK_F1;
781 MISC_keymap[XK_F2&0xFF] = SDLK_F2;
782 MISC_keymap[XK_F3&0xFF] = SDLK_F3;
783 MISC_keymap[XK_F4&0xFF] = SDLK_F4;
784 MISC_keymap[XK_F5&0xFF] = SDLK_F5;
785 MISC_keymap[XK_F6&0xFF] = SDLK_F6;
786 MISC_keymap[XK_F7&0xFF] = SDLK_F7;
787 MISC_keymap[XK_F8&0xFF] = SDLK_F8;
788 MISC_keymap[XK_F9&0xFF] = SDLK_F9;
789 MISC_keymap[XK_F10&0xFF] = SDLK_F10;
790 MISC_keymap[XK_F11&0xFF] = SDLK_F11;
791 MISC_keymap[XK_F12&0xFF] = SDLK_F12;
792 MISC_keymap[XK_F13&0xFF] = SDLK_F13;
793 MISC_keymap[XK_F14&0xFF] = SDLK_F14;
794 MISC_keymap[XK_F15&0xFF] = SDLK_F15;
795
796 MISC_keymap[XK_Num_Lock&0xFF] = SDLK_NUMLOCK;
797 MISC_keymap[XK_Caps_Lock&0xFF] = SDLK_CAPSLOCK;
798 MISC_keymap[XK_Scroll_Lock&0xFF] = SDLK_SCROLLOCK;
799 MISC_keymap[XK_Shift_R&0xFF] = SDLK_RSHIFT;
800 MISC_keymap[XK_Shift_L&0xFF] = SDLK_LSHIFT;
801 MISC_keymap[XK_Control_R&0xFF] = SDLK_RCTRL;
802 MISC_keymap[XK_Control_L&0xFF] = SDLK_LCTRL;
803 MISC_keymap[XK_Alt_R&0xFF] = SDLK_RALT;
804 MISC_keymap[XK_Alt_L&0xFF] = SDLK_LALT;
805 MISC_keymap[XK_Meta_R&0xFF] = SDLK_RMETA;
806 MISC_keymap[XK_Meta_L&0xFF] = SDLK_LMETA;
807 MISC_keymap[XK_Super_L&0xFF] = SDLK_LSUPER; /* Left "Windows" */
808 MISC_keymap[XK_Super_R&0xFF] = SDLK_RSUPER; /* Right "Windows */
809 MISC_keymap[XK_Mode_switch&0xFF] = SDLK_MODE; /* "Alt Gr" key */
810 MISC_keymap[XK_Multi_key&0xFF] = SDLK_COMPOSE; /* Multi-key compose */
811
812 MISC_keymap[XK_Help&0xFF] = SDLK_HELP;
813 MISC_keymap[XK_Print&0xFF] = SDLK_PRINT;
814 MISC_keymap[XK_Sys_Req&0xFF] = SDLK_SYSREQ;
815 MISC_keymap[XK_Break&0xFF] = SDLK_BREAK;
816 MISC_keymap[XK_Menu&0xFF] = SDLK_MENU;
817 MISC_keymap[XK_Hyper_R&0xFF] = SDLK_MENU; /* Windows "Menu" key */
818 }
819
820 /* Get the translated SDL virtual keysym */
821 SDLKey X11_TranslateKeycode(Display *display, KeyCode kc)
733 { 822 {
734 KeySym xsym; 823 KeySym xsym;
735 824 SDLKey key;
736 /* Get the raw keyboard scancode */ 825
737 keysym->scancode = kc;
738 xsym = pXKeycodeToKeysym(display, kc, 0); 826 xsym = pXKeycodeToKeysym(display, kc, 0);
739 #ifdef DEBUG_KEYS 827 #ifdef DEBUG_KEYS
740 fprintf(stderr, "Translating key 0x%.4x (%d)\n", xsym, kc); 828 fprintf(stderr, "Translating key code %d -> 0x%.4x\n", kc, xsym);
741 #endif 829 #endif
742 /* Get the translated SDL virtual keysym */ 830 key = SDLK_UNKNOWN;
743 keysym->sym = SDLK_UNKNOWN;
744 if ( xsym ) { 831 if ( xsym ) {
745 switch (xsym>>8) { 832 switch (xsym>>8) {
746 case 0x1005FF: 833 case 0x1005FF:
747 #ifdef SunXK_F36 834 #ifdef SunXK_F36
748 if ( xsym == SunXK_F36 ) 835 if ( xsym == SunXK_F36 )
749 keysym->sym = SDLK_F11; 836 key = SDLK_F11;
750 #endif 837 #endif
751 #ifdef SunXK_F37 838 #ifdef SunXK_F37
752 if ( xsym == SunXK_F37 ) 839 if ( xsym == SunXK_F37 )
753 keysym->sym = SDLK_F12; 840 key = SDLK_F12;
754 #endif 841 #endif
755 break; 842 break;
756 case 0x00: /* Latin 1 */ 843 case 0x00: /* Latin 1 */
757 case 0x01: /* Latin 2 */ 844 key = (SDLKey)(xsym & 0xFF);
758 case 0x02: /* Latin 3 */ 845 break;
759 case 0x03: /* Latin 4 */ 846 case 0x01: /* Latin 2 */
760 case 0x04: /* Katakana */ 847 case 0x02: /* Latin 3 */
761 case 0x05: /* Arabic */ 848 case 0x03: /* Latin 4 */
762 case 0x06: /* Cyrillic */ 849 case 0x04: /* Katakana */
763 case 0x07: /* Greek */ 850 case 0x05: /* Arabic */
764 case 0x08: /* Technical */ 851 case 0x06: /* Cyrillic */
765 case 0x0A: /* Publishing */ 852 case 0x07: /* Greek */
766 case 0x0C: /* Hebrew */ 853 case 0x08: /* Technical */
767 case 0x0D: /* Thai */ 854 case 0x0A: /* Publishing */
768 keysym->sym = (SDLKey)(xsym&0xFF); 855 case 0x0C: /* Hebrew */
769 /* Map capital letter syms to lowercase */ 856 case 0x0D: /* Thai */
770 if ((keysym->sym >= 'A')&&(keysym->sym <= 'Z')) 857 /* These are wrong, but it's better than nothing */
771 keysym->sym += ('a'-'A'); 858 key = (SDLKey)(xsym & 0xFF);
772 break; 859 break;
773 case 0xFE: 860 case 0xFE:
774 keysym->sym = ODD_keymap[xsym&0xFF]; 861 key = ODD_keymap[xsym&0xFF];
775 break; 862 break;
776 case 0xFF: 863 case 0xFF:
777 keysym->sym = MISC_keymap[xsym&0xFF]; 864 key = MISC_keymap[xsym&0xFF];
778 break; 865 break;
779 default: 866 default:
780 fprintf(stderr, 867 /*
781 "X11: Unknown xsym, sym = 0x%04x\n", 868 fprintf(stderr, "X11: Unhandled xsym, sym = 0x%04x\n",
782 (unsigned int)xsym); 869 (unsigned int)xsym);
783 break; 870 */
871 break;
784 } 872 }
785 } else { 873 } else {
786 /* X11 doesn't know how to translate the key! */ 874 /* X11 doesn't know how to translate the key! */
787 switch (kc) { 875 switch (kc) {
788 /* Caution: 876 /* Caution:
789 These keycodes are from the Microsoft Keyboard 877 These keycodes are from the Microsoft Keyboard
878 */
879 case 115:
880 key = SDLK_LSUPER;
881 break;
882 case 116:
883 key = SDLK_RSUPER;
884 break;
885 case 117:
886 key = SDLK_MENU;
887 break;
888 default:
889 /*
890 * no point in an error message; happens for
891 * several keys when we get a keymap notify
790 */ 892 */
791 case 115: 893 break;
792 keysym->sym = SDLK_LSUPER; 894 }
793 break; 895 }
794 case 116: 896 return key;
795 keysym->sym = SDLK_RSUPER;
796 break;
797 case 117:
798 keysym->sym = SDLK_MENU;
799 break;
800 default:
801 /*
802 * no point in an error message; happens for
803 * several keys when we get a keymap notify
804 */
805 break;
806 }
807 }
808 keysym->mod = KMOD_NONE;
809
810 /* If UNICODE is on, get the UNICODE value for the key */
811 keysym->unicode = 0;
812 if ( SDL_TranslateUNICODE && xkey ) {
813 static XComposeStatus state;
814
815
816 #define BROKEN_XFREE86_INTERNATIONAL_KBD
817 /* This appears to be a magical flag that is used with AltGr on
818 international keyboards to signal alternate key translations.
819 The flag doesn't show up when in fullscreen mode (?)
820 FIXME: Check to see if this code is safe for other servers.
821 */
822 #ifdef BROKEN_XFREE86_INTERNATIONAL_KBD
823 /* Work around what appears to be a bug in XFree86 */
824 if ( SDL_GetModState() & KMOD_MODE ) {
825 xkey->state |= (1<<13);
826 }
827 #endif
828 /* Look up the translated value for the key event */
829
830 /* if there is no connection with the IM server, use the regular method */
831 if (ic == NULL || xkey->type != KeyPress) {
832 unsigned char keybuf[32];
833
834 if ( pXLookupString(xkey, (char *)keybuf, sizeof(keybuf),
835 NULL, &state) ) {
836 /*
837 * FIXME,: XLookupString() may yield more than one
838 * character, so we need a mechanism to allow for
839 * this (perhaps generate null keypress events with
840 * a unicode value)
841 */
842 keysym->unicode = keybuf[0];
843 }
844 } else { /* else, use the IM protocol */
845 #ifdef X_HAVE_UTF8_STRING
846 /* A UTF-8 character can be at most 6 bytes */
847 unsigned char keybuf[6];
848 pXSetICFocus(ic);
849 if ( pXutf8LookupString(ic, (XKeyPressedEvent *)xkey, (char *)keybuf, sizeof(keybuf),
850 NULL, (Status *)&state) )
851 keysym->unicode = Utf8ToUcs4(keybuf);
852 pXUnsetICFocus(ic);
853 #endif
854 }
855 }
856 return(keysym);
857 } 897 }
858 898
859 /* X11 modifier masks for various keys */ 899 /* X11 modifier masks for various keys */
860 static unsigned meta_l_mask, meta_r_mask, alt_l_mask, alt_r_mask; 900 static unsigned meta_l_mask, meta_r_mask, alt_l_mask, alt_r_mask;
861 static unsigned num_mask, mode_switch_mask; 901 static unsigned num_mask, mode_switch_mask;
967 /* 1007 /*
968 * Called when focus is regained, to read the keyboard state and generate 1008 * Called when focus is regained, to read the keyboard state and generate
969 * synthetic keypress/release events. 1009 * synthetic keypress/release events.
970 * key_vec is a bit vector of keycodes (256 bits) 1010 * key_vec is a bit vector of keycodes (256 bits)
971 */ 1011 */
972 void X11_SetKeyboardState(Display *display, XIC ic, const char *key_vec) 1012 void X11_SetKeyboardState(Display *display, const char *key_vec)
973 { 1013 {
974 char keys_return[32]; 1014 char keys_return[32];
975 int i; 1015 int i;
976 KeyCode xcode[SDLK_LAST];
977 Uint8 new_kstate[SDLK_LAST];
978 Uint8 *kstate = SDL_GetKeyState(NULL); 1016 Uint8 *kstate = SDL_GetKeyState(NULL);
979 SDLMod modstate; 1017 SDLMod modstate;
980 Window junk_window; 1018 Window junk_window;
981 int x, y; 1019 int x, y;
982 unsigned int mask; 1020 unsigned int mask;
1002 modstate |= KMOD_NUM; 1040 modstate |= KMOD_NUM;
1003 } 1041 }
1004 } 1042 }
1005 1043
1006 /* Zero the new keyboard state and generate it */ 1044 /* Zero the new keyboard state and generate it */
1007 memset(new_kstate, SDL_RELEASED, sizeof(new_kstate)); 1045 memset(kstate, 0, SDLK_LAST);
1008 /* 1046 /*
1009 * An obvious optimisation is to check entire longwords at a time in 1047 * An obvious optimisation is to check entire longwords at a time in
1010 * both loops, but we can't be sure the arrays are aligned so it's not 1048 * both loops, but we can't be sure the arrays are aligned so it's not
1011 * worth the extra complexity 1049 * worth the extra complexity
1012 */ 1050 */
1013 for(i = 0; i < 32; i++) { 1051 for ( i = 0; i < 32; i++ ) {
1014 int j; 1052 int j;
1015 if(!key_vec[i]) 1053 if ( !key_vec[i] )
1016 continue; 1054 continue;
1017 for(j = 0; j < 8; j++) { 1055 for ( j = 0; j < 8; j++ ) {
1018 if(key_vec[i] & (1 << j)) { 1056 if ( key_vec[i] & (1 << j) ) {
1019 SDL_keysym sk; 1057 SDLKey key;
1020 KeyCode kc = i << 3 | j; 1058 KeyCode kc = (i << 3 | j);
1021 X11_TranslateKey(display, ic, NULL, kc, &sk); 1059 key = X11_TranslateKeycode(display, kc);
1022 new_kstate[sk.sym] = SDL_PRESSED; 1060 if ( key == SDLK_UNKNOWN ) {
1023 xcode[sk.sym] = kc; 1061 continue;
1024 } 1062 }
1025 } 1063 kstate[key] = SDL_PRESSED;
1026 } 1064 switch (key) {
1027 for(i = SDLK_FIRST+1; i < SDLK_LAST; i++) { 1065 case SDLK_LSHIFT:
1028 int state = new_kstate[i];
1029
1030 if ( state == SDL_PRESSED ) {
1031 switch (i) {
1032 case SDLK_LSHIFT:
1033 modstate |= KMOD_LSHIFT; 1066 modstate |= KMOD_LSHIFT;
1034 break; 1067 break;
1035 case SDLK_RSHIFT: 1068 case SDLK_RSHIFT:
1036 modstate |= KMOD_RSHIFT; 1069 modstate |= KMOD_RSHIFT;
1037 break; 1070 break;
1038 case SDLK_LCTRL: 1071 case SDLK_LCTRL:
1039 modstate |= KMOD_LCTRL; 1072 modstate |= KMOD_LCTRL;
1040 break; 1073 break;
1041 case SDLK_RCTRL: 1074 case SDLK_RCTRL:
1042 modstate |= KMOD_RCTRL; 1075 modstate |= KMOD_RCTRL;
1043 break; 1076 break;
1044 case SDLK_LALT: 1077 case SDLK_LALT:
1045 modstate |= KMOD_LALT; 1078 modstate |= KMOD_LALT;
1046 break; 1079 break;
1047 case SDLK_RALT: 1080 case SDLK_RALT:
1048 modstate |= KMOD_RALT; 1081 modstate |= KMOD_RALT;
1049 break; 1082 break;
1050 case SDLK_LMETA: 1083 case SDLK_LMETA:
1051 modstate |= KMOD_LMETA; 1084 modstate |= KMOD_LMETA;
1052 break; 1085 break;
1053 case SDLK_RMETA: 1086 case SDLK_RMETA:
1054 modstate |= KMOD_RMETA; 1087 modstate |= KMOD_RMETA;
1055 break; 1088 break;
1056 default: 1089 default:
1057 break; 1090 break;
1058 } 1091 }
1059 } 1092 }
1060 if ( kstate[i] != state ) {
1061 kstate[i] = state;
1062 } 1093 }
1063 } 1094 }
1064 1095
1065 /* Hack - set toggle key state */ 1096 /* Hack - set toggle key state */
1066 if ( modstate & KMOD_CAPS ) { 1097 if ( modstate & KMOD_CAPS ) {