SDL-1.2.14
[sdl_omap.git] / src / video / x11 / SDL_x11events.c
1 /*
2     SDL - Simple DirectMedia Layer
3     Copyright (C) 1997-2009 Sam Lantinga
4
5     This library is free software; you can redistribute it and/or
6     modify it under the terms of the GNU Lesser General Public
7     License as published by the Free Software Foundation; either
8     version 2.1 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     Lesser General Public License for more details.
14
15     You should have received a copy of the GNU Lesser General Public
16     License along with this library; if not, write to the Free Software
17     Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
18
19     Sam Lantinga
20     slouken@libsdl.org
21 */
22 #include "SDL_config.h"
23
24 /* Handle the event stream, converting X11 events into SDL events */
25
26 #include <setjmp.h>
27 #include <X11/Xlib.h>
28 #include <X11/Xutil.h>
29 #include <X11/keysym.h>
30 #ifdef __SVR4
31 #include <X11/Sunkeysym.h>
32 #endif
33 #include <sys/types.h>
34 #include <sys/time.h>
35 #include <unistd.h>
36
37 #include "SDL_timer.h"
38 #include "SDL_syswm.h"
39 #include "../SDL_sysvideo.h"
40 #include "../../events/SDL_sysevents.h"
41 #include "../../events/SDL_events_c.h"
42 #include "SDL_x11video.h"
43 #include "SDL_x11dga_c.h"
44 #include "SDL_x11modes_c.h"
45 #include "SDL_x11image_c.h"
46 #include "SDL_x11gamma_c.h"
47 #include "SDL_x11wm_c.h"
48 #include "SDL_x11mouse_c.h"
49 #include "SDL_x11events_c.h"
50
51
52 /* Define this if you want to debug X11 events */
53 /*#define DEBUG_XEVENTS*/
54
55 /* The translation tables from an X11 keysym to a SDL keysym */
56 static SDLKey ODD_keymap[256];
57 static SDLKey MISC_keymap[256];
58 SDLKey X11_TranslateKeycode(Display *display, KeyCode kc);
59
60
61 #ifdef X_HAVE_UTF8_STRING
62 Uint32 Utf8ToUcs4(const Uint8 *utf8)
63 {
64         Uint32 c;
65         int i = 1;
66         int noOctets = 0;
67         int firstOctetMask = 0;
68         unsigned char firstOctet = utf8[0];
69         if (firstOctet < 0x80) {
70                 /*
71                   Characters in the range:
72                     00000000 to 01111111 (ASCII Range)
73                   are stored in one octet:
74                     0xxxxxxx (The same as its ASCII representation)
75                   The least 6 significant bits of the first octet is the most 6 significant nonzero bits
76                   of the UCS4 representation.
77                 */
78                 noOctets = 1;
79                 firstOctetMask = 0x7F;  /* 0(1111111) - The most significant bit is ignored */
80         } else if ((firstOctet & 0xE0) /* get the most 3 significant bits by AND'ing with 11100000 */
81                       == 0xC0 ) {  /* see if those 3 bits are 110. If so, the char is in this range */
82                 /*
83                   Characters in the range:
84                     00000000 10000000 to 00000111 11111111
85                   are stored in two octets:
86                     110xxxxx 10xxxxxx
87                   The least 5 significant bits of the first octet is the most 5 significant nonzero bits
88                   of the UCS4 representation.
89                 */
90                 noOctets = 2;
91                 firstOctetMask = 0x1F;  /* 000(11111) - The most 3 significant bits are ignored */
92         } else if ((firstOctet & 0xF0) /* get the most 4 significant bits by AND'ing with 11110000 */
93                       == 0xE0) {  /* see if those 4 bits are 1110. If so, the char is in this range */
94                 /*
95                   Characters in the range:
96                     00001000 00000000 to 11111111 11111111
97                   are stored in three octets:
98                     1110xxxx 10xxxxxx 10xxxxxx
99                   The least 4 significant bits of the first octet is the most 4 significant nonzero bits
100                   of the UCS4 representation.
101                 */
102                 noOctets = 3;
103                 firstOctetMask = 0x0F; /* 0000(1111) - The most 4 significant bits are ignored */
104         } else if ((firstOctet & 0xF8) /* get the most 5 significant bits by AND'ing with 11111000 */
105                       == 0xF0) {  /* see if those 5 bits are 11110. If so, the char is in this range */
106                 /*
107                   Characters in the range:
108                     00000001 00000000 00000000 to 00011111 11111111 11111111
109                   are stored in four octets:
110                     11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
111                   The least 3 significant bits of the first octet is the most 3 significant nonzero bits
112                   of the UCS4 representation.
113                 */
114                 noOctets = 4;
115                 firstOctetMask = 0x07; /* 11110(111) - The most 5 significant bits are ignored */
116         } else if ((firstOctet & 0xFC) /* get the most 6 significant bits by AND'ing with 11111100 */
117                       == 0xF8) { /* see if those 6 bits are 111110. If so, the char is in this range */
118                 /*
119                   Characters in the range:
120                     00000000 00100000 00000000 00000000 to
121                     00000011 11111111 11111111 11111111
122                   are stored in five octets:
123                     111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
124                   The least 2 significant bits of the first octet is the most 2 significant nonzero bits
125                   of the UCS4 representation.
126                 */
127                 noOctets = 5;
128                 firstOctetMask = 0x03; /* 111110(11) - The most 6 significant bits are ignored */
129         } else if ((firstOctet & 0xFE) /* get the most 7 significant bits by AND'ing with 11111110 */
130                       == 0xFC) { /* see if those 7 bits are 1111110. If so, the char is in this range */
131                 /*
132                   Characters in the range:
133                     00000100 00000000 00000000 00000000 to
134                     01111111 11111111 11111111 11111111
135                   are stored in six octets:
136                     1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
137                   The least significant bit of the first octet is the most significant nonzero bit
138                   of the UCS4 representation.
139                 */
140                 noOctets = 6;
141                 firstOctetMask = 0x01; /* 1111110(1) - The most 7 significant bits are ignored */
142         } else
143                 return 0;  /* The given chunk is not a valid UTF-8 encoded Unicode character */
144         
145         /*
146           The least noOctets significant bits of the first octet is the most 2 significant nonzero bits
147           of the UCS4 representation.
148           The first 6 bits of the UCS4 representation is the least 8-noOctets-1 significant bits of
149           firstOctet if the character is not ASCII. If so, it's the least 7 significant bits of firstOctet.
150           This done by AND'ing firstOctet with its mask to trim the bits used for identifying the
151           number of continuing octets (if any) and leave only the free bits (the x's)
152           Sample:
153           1-octet:    0xxxxxxx  &  01111111 = 0xxxxxxx
154           2-octets:  110xxxxx  &  00011111 = 000xxxxx
155         */
156         c = firstOctet & firstOctetMask;
157         
158         /* Now, start filling c.ucs4 with the bits from the continuing octets from utf8. */
159         for (i = 1; i < noOctets; i++) {
160                 /* A valid continuing octet is of the form 10xxxxxx */
161                 if ((utf8[i] & 0xC0) /* get the most 2 significant bits by AND'ing with 11000000 */
162                     != 0x80) /* see if those 2 bits are 10. If not, the is a malformed sequence. */
163                         /*The given chunk is a partial sequence at the end of a string that could
164                            begin a valid character */
165                         return 0;
166                 
167                 /* Make room for the next 6-bits */
168                 c <<= 6;
169                 
170                 /*
171                   Take only the least 6 significance bits of the current octet (utf8[i]) and fill the created room
172                   of c.ucs4 with them.
173                   This done by AND'ing utf8[i] with 00111111 and the OR'ing the result with c.ucs4.
174                 */
175                 c |= utf8[i] & 0x3F;
176         }
177         return c;
178 }
179
180 /* Given a UTF-8 encoded string pointed to by utf8 of length length in
181    bytes, returns the corresponding UTF-16 encoded string in the
182    buffer pointed to by utf16.  The maximum number of UTF-16 encoding
183    units (i.e., Unit16s) allowed in the buffer is specified in
184    utf16_max_length.  The return value is the number of UTF-16
185    encoding units placed in the output buffer pointed to by utf16.
186
187    In case of an error, -1 is returned, leaving some unusable partial
188    results in the output buffer.
189
190    The caller must estimate the size of utf16 buffer by itself before
191    calling this function.  Insufficient output buffer is considered as
192    an error, and once an error occured, this function doesn't give any
193    clue how large the result will be.
194
195    The error cases include following:
196
197    - Invalid byte sequences were in the input UTF-8 bytes.  The caller
198      has no way to know what point in the input buffer was the
199      errornous byte.
200
201    - The input contained a character (a valid UTF-8 byte sequence)
202      whose scalar value exceeded the range that UTF-16 can represent
203      (i.e., characters whose Unicode scalar value above 0x110000).
204
205    - The output buffer has no enough space to hold entire utf16 data.
206
207    Please note:
208
209    - '\0'-termination is not assumed both on the input UTF-8 string
210      and on the output UTF-16 string; any legal zero byte in the input
211      UTF-8 string will be converted to a 16-bit zero in output.  As a
212      side effect, the last UTF-16 encoding unit stored in the output
213      buffer will have a non-zero value if the input UTF-8 was not
214      '\0'-terminated.
215
216    - UTF-8 aliases are *not* considered as an error.  They are
217      converted to UTF-16.  For example, 0xC0 0xA0, 0xE0 0x80 0xA0, 
218      and 0xF0 0x80 0x80 0xA0 are all mapped to a single UTF-16
219      encoding unit 0x0020.
220
221    - Three byte UTF-8 sequences whose value corresponds to a surrogate
222      code or other reserved scalar value are not considered as an
223      error either.  They may cause an invalid UTF-16 data (e.g., those
224      containing unpaired surrogates).
225
226 */
227
228 static int Utf8ToUtf16(const Uint8 *utf8, const int utf8_length, Uint16 *utf16, const int utf16_max_length) {
229
230     /* p moves over the output buffer.  max_ptr points to the next to the last slot of the buffer.  */
231     Uint16 *p = utf16;
232     Uint16 const *const max_ptr = utf16 + utf16_max_length;
233
234     /* end_of_input points to the last byte of input as opposed to the next to the last byte.  */
235     Uint8 const *const end_of_input = utf8 + utf8_length - 1;
236
237     while (utf8 <= end_of_input) {
238         Uint8 const c = *utf8;
239         if (p >= max_ptr) {
240             /* No more output space.  */
241             return -1;
242         }
243         if (c < 0x80) {
244             /* One byte ASCII.  */
245             *p++ = c;
246             utf8 += 1;
247         } else if (c < 0xC0) {
248             /* Follower byte without preceeding leader bytes.  */
249             return -1;
250         } else if (c < 0xE0) {
251             /* Two byte sequence.  We need one follower byte.  */
252             if (end_of_input - utf8 < 1 || (((utf8[1] ^ 0x80)) & 0xC0)) {
253                 return -1;
254             }
255             *p++ = (Uint16)(0xCF80 + (c << 6) + utf8[1]);
256             utf8 += 2;
257         } else if (c < 0xF0) {
258             /* Three byte sequence.  We need two follower byte.  */
259             if (end_of_input - utf8 < 2 || (((utf8[1] ^ 0x80) | (utf8[2] ^ 0x80)) & 0xC0)) {
260                 return -1;
261             }
262             *p++ = (Uint16)(0xDF80 + (c << 12) + (utf8[1] << 6) + utf8[2]);
263             utf8 += 3;
264         } else if (c < 0xF8) {
265             int plane;
266             /* Four byte sequence.  We need three follower bytes.  */
267             if (end_of_input - utf8 < 3 || (((utf8[1] ^ 0x80) | (utf8[2] ^0x80) | (utf8[3] ^ 0x80)) & 0xC0)) {
268                 return -1;
269             }
270             plane = (-0xC8 + (c << 2) + (utf8[1] >> 4));
271             if (plane == 0) {
272                 /* This four byte sequence is an alias that
273                    corresponds to a Unicode scalar value in BMP.
274                    It fits in an UTF-16 encoding unit.  */
275                 *p++ = (Uint16)(0xDF80 + (utf8[1] << 12) + (utf8[2] << 6) + utf8[3]);
276             } else if (plane <= 16) {
277                 /* This is a legal four byte sequence that corresponds to a surrogate pair.  */
278                 if (p + 1 >= max_ptr) {
279                     /* No enough space on the output buffer for the pair.  */
280                     return -1;
281                 }
282                 *p++ = (Uint16)(0xE5B8 + (c << 8) + (utf8[1] << 2) + (utf8[2] >> 4));
283                 *p++ = (Uint16)(0xDB80 + ((utf8[2] & 0x0F) << 6) + utf8[3]);
284             } else {
285                 /* This four byte sequence is out of UTF-16 code space.  */
286                 return -1;
287             }
288             utf8 += 4;
289         } else {
290             /* Longer sequence or unused byte.  */
291             return -1;
292         }
293     }
294     return p - utf16;
295 }
296
297 #endif
298
299 /* Check to see if this is a repeated key.
300    (idea shamelessly lifted from GII -- thanks guys! :)
301  */
302 static int X11_KeyRepeat(Display *display, XEvent *event)
303 {
304         XEvent peekevent;
305         int repeated;
306
307         repeated = 0;
308         if ( XPending(display) ) {
309                 XPeekEvent(display, &peekevent);
310                 if ( (peekevent.type == KeyPress) &&
311                      (peekevent.xkey.keycode == event->xkey.keycode) &&
312                      ((peekevent.xkey.time-event->xkey.time) < 2) ) {
313                         repeated = 1;
314                         XNextEvent(display, &peekevent);
315                 }
316         }
317         return(repeated);
318 }
319
320 /* Note:  The X server buffers and accumulates mouse motion events, so
321    the motion event generated by the warp may not appear exactly as we
322    expect it to.  We work around this (and improve performance) by only
323    warping the pointer when it reaches the edge, and then wait for it.
324 */
325 #define MOUSE_FUDGE_FACTOR      8
326
327 static __inline__ int X11_WarpedMotion(_THIS, XEvent *xevent)
328 {
329         int w, h, i;
330         int deltax, deltay;
331         int posted;
332
333         w = SDL_VideoSurface->w;
334         h = SDL_VideoSurface->h;
335         deltax = xevent->xmotion.x - mouse_last.x;
336         deltay = xevent->xmotion.y - mouse_last.y;
337 #ifdef DEBUG_MOTION
338   printf("Warped mouse motion: %d,%d\n", deltax, deltay);
339 #endif
340         mouse_last.x = xevent->xmotion.x;
341         mouse_last.y = xevent->xmotion.y;
342         posted = SDL_PrivateMouseMotion(0, 1, deltax, deltay);
343
344         if ( (xevent->xmotion.x < MOUSE_FUDGE_FACTOR) ||
345              (xevent->xmotion.x > (w-MOUSE_FUDGE_FACTOR)) ||
346              (xevent->xmotion.y < MOUSE_FUDGE_FACTOR) ||
347              (xevent->xmotion.y > (h-MOUSE_FUDGE_FACTOR)) ) {
348                 /* Get the events that have accumulated */
349                 while ( XCheckTypedEvent(SDL_Display, MotionNotify, xevent) ) {
350                         deltax = xevent->xmotion.x - mouse_last.x;
351                         deltay = xevent->xmotion.y - mouse_last.y;
352 #ifdef DEBUG_MOTION
353   printf("Extra mouse motion: %d,%d\n", deltax, deltay);
354 #endif
355                         mouse_last.x = xevent->xmotion.x;
356                         mouse_last.y = xevent->xmotion.y;
357                         posted += SDL_PrivateMouseMotion(0, 1, deltax, deltay);
358                 }
359                 mouse_last.x = w/2;
360                 mouse_last.y = h/2;
361                 XWarpPointer(SDL_Display, None, SDL_Window, 0, 0, 0, 0,
362                                         mouse_last.x, mouse_last.y);
363                 for ( i=0; i<10; ++i ) {
364                         XMaskEvent(SDL_Display, PointerMotionMask, xevent);
365                         if ( (xevent->xmotion.x >
366                                   (mouse_last.x-MOUSE_FUDGE_FACTOR)) &&
367                              (xevent->xmotion.x <
368                                   (mouse_last.x+MOUSE_FUDGE_FACTOR)) &&
369                              (xevent->xmotion.y >
370                                   (mouse_last.y-MOUSE_FUDGE_FACTOR)) &&
371                              (xevent->xmotion.y <
372                                   (mouse_last.y+MOUSE_FUDGE_FACTOR)) ) {
373                                 break;
374                         }
375 #ifdef DEBUG_XEVENTS
376   printf("Lost mouse motion: %d,%d\n", xevent->xmotion.x, xevent->xmotion.y);
377 #endif
378                 }
379 #ifdef DEBUG_XEVENTS
380                 if ( i == 10 ) {
381                         printf("Warning: didn't detect mouse warp motion\n");
382                 }
383 #endif
384         }
385         return(posted);
386 }
387
388 static int X11_DispatchEvent(_THIS)
389 {
390         int posted;
391         XEvent xevent;
392
393         SDL_memset(&xevent, '\0', sizeof (XEvent));  /* valgrind fix. --ryan. */
394         XNextEvent(SDL_Display, &xevent);
395
396         /* Discard KeyRelease and KeyPress events generated by auto-repeat.
397            We need to do it before passing event to XFilterEvent.  Otherwise,
398            KeyRelease aware IMs are confused...  */
399         if ( xevent.type == KeyRelease
400              && X11_KeyRepeat(SDL_Display, &xevent) ) {
401                 return 0;
402         }
403
404 #ifdef X_HAVE_UTF8_STRING
405         /* If we are translating with IM, we need to pass all events
406            to XFilterEvent, and discard those filtered events immediately.  */
407         if ( SDL_TranslateUNICODE
408              && SDL_IM != NULL
409              && XFilterEvent(&xevent, None) ) {
410                 return 0;
411         }
412 #endif
413
414         posted = 0;
415         switch (xevent.type) {
416
417             /* Gaining mouse coverage? */
418             case EnterNotify: {
419 #ifdef DEBUG_XEVENTS
420 printf("EnterNotify! (%d,%d)\n", xevent.xcrossing.x, xevent.xcrossing.y);
421 if ( xevent.xcrossing.mode == NotifyGrab )
422 printf("Mode: NotifyGrab\n");
423 if ( xevent.xcrossing.mode == NotifyUngrab )
424 printf("Mode: NotifyUngrab\n");
425 #endif
426                 if ( this->input_grab == SDL_GRAB_OFF ) {
427                         posted = SDL_PrivateAppActive(1, SDL_APPMOUSEFOCUS);
428                 }
429                 posted = SDL_PrivateMouseMotion(0, 0,
430                                 xevent.xcrossing.x,
431                                 xevent.xcrossing.y);
432             }
433             break;
434
435             /* Losing mouse coverage? */
436             case LeaveNotify: {
437 #ifdef DEBUG_XEVENTS
438 printf("LeaveNotify! (%d,%d)\n", xevent.xcrossing.x, xevent.xcrossing.y);
439 if ( xevent.xcrossing.mode == NotifyGrab )
440 printf("Mode: NotifyGrab\n");
441 if ( xevent.xcrossing.mode == NotifyUngrab )
442 printf("Mode: NotifyUngrab\n");
443 #endif
444                 if ( xevent.xcrossing.detail != NotifyInferior ) {
445                         if ( this->input_grab == SDL_GRAB_OFF ) {
446                                 posted = SDL_PrivateAppActive(0, SDL_APPMOUSEFOCUS);
447                         } else {
448                                 posted = SDL_PrivateMouseMotion(0, 0,
449                                                 xevent.xcrossing.x,
450                                                 xevent.xcrossing.y);
451                         }
452                 }
453             }
454             break;
455
456             /* Gaining input focus? */
457             case FocusIn: {
458 #ifdef DEBUG_XEVENTS
459 printf("FocusIn!\n");
460 #endif
461                 posted = SDL_PrivateAppActive(1, SDL_APPINPUTFOCUS);
462
463 #ifdef X_HAVE_UTF8_STRING
464                 if ( SDL_IC != NULL ) {
465                         XSetICFocus(SDL_IC);
466                 }
467 #endif
468                 /* Queue entry into fullscreen mode */
469                 switch_waiting = 0x01 | SDL_FULLSCREEN;
470                 switch_time = SDL_GetTicks() + 1500;
471             }
472             break;
473
474             /* Losing input focus? */
475             case FocusOut: {
476 #ifdef DEBUG_XEVENTS
477 printf("FocusOut!\n");
478 #endif
479                 posted = SDL_PrivateAppActive(0, SDL_APPINPUTFOCUS);
480
481 #ifdef X_HAVE_UTF8_STRING
482                 if ( SDL_IC != NULL ) {
483                         XUnsetICFocus(SDL_IC);
484                 }
485 #endif
486                 /* Queue leaving fullscreen mode */
487                 switch_waiting = 0x01;
488                 switch_time = SDL_GetTicks() + 200;
489             }
490             break;
491
492 #ifdef X_HAVE_UTF8_STRING
493             /* Some IM requires MappingNotify to be passed to
494                XRefreshKeyboardMapping by the app.  */
495             case MappingNotify: {
496                 XRefreshKeyboardMapping(&xevent.xmapping);
497             }
498             break;
499 #endif /* X_HAVE_UTF8_STRING */
500
501             /* Generated upon EnterWindow and FocusIn */
502             case KeymapNotify: {
503 #ifdef DEBUG_XEVENTS
504 printf("KeymapNotify!\n");
505 #endif
506                 X11_SetKeyboardState(SDL_Display,  xevent.xkeymap.key_vector);
507             }
508             break;
509
510             /* Mouse motion? */
511             case MotionNotify: {
512                 if ( SDL_VideoSurface ) {
513                         if ( mouse_relative ) {
514                                 if ( using_dga & DGA_MOUSE ) {
515 #ifdef DEBUG_MOTION
516   printf("DGA motion: %d,%d\n", xevent.xmotion.x_root, xevent.xmotion.y_root);
517 #endif
518                                         posted = SDL_PrivateMouseMotion(0, 1,
519                                                         xevent.xmotion.x_root,
520                                                         xevent.xmotion.y_root);
521                                 } else {
522                                         posted = X11_WarpedMotion(this,&xevent);
523                                 }
524                         } else {
525 #ifdef DEBUG_MOTION
526   printf("X11 motion: %d,%d\n", xevent.xmotion.x, xevent.xmotion.y);
527 #endif
528                                 posted = SDL_PrivateMouseMotion(0, 0,
529                                                 xevent.xmotion.x,
530                                                 xevent.xmotion.y);
531                         }
532                 }
533             }
534             break;
535
536             /* Mouse button press? */
537             case ButtonPress: {
538                 posted = SDL_PrivateMouseButton(SDL_PRESSED, 
539                                         xevent.xbutton.button, 0, 0);
540             }
541             break;
542
543             /* Mouse button release? */
544             case ButtonRelease: {
545                 posted = SDL_PrivateMouseButton(SDL_RELEASED, 
546                                         xevent.xbutton.button, 0, 0);
547             }
548             break;
549
550             /* Key press? */
551             case KeyPress: {
552                 SDL_keysym keysym;
553                 KeyCode keycode = xevent.xkey.keycode;
554
555 #ifdef DEBUG_XEVENTS
556 printf("KeyPress (X11 keycode = 0x%X)\n", xevent.xkey.keycode);
557 #endif
558                 /* If we're not doing translation, we're done! */
559                 if ( !SDL_TranslateUNICODE ) {
560                         /* Get the translated SDL virtual keysym and put it on the queue.*/
561                         keysym.scancode = keycode;
562                         keysym.sym = X11_TranslateKeycode(SDL_Display, keycode);
563                         keysym.mod = KMOD_NONE;
564                         keysym.unicode = 0;
565                         posted = SDL_PrivateKeyboard(SDL_PRESSED, &keysym);
566                         break;
567                 }
568
569                 /* Look up the translated value for the key event */
570 #ifdef X_HAVE_UTF8_STRING
571                 if ( SDL_IC != NULL ) {
572                         Status status;
573                         KeySym xkeysym;
574                         int i;
575                         /* A UTF-8 character can be at most 6 bytes */
576                         /* ... It's true, but Xutf8LookupString can
577                            return more than one characters.  Moreover,
578                            the spec. put no upper bound, so we should
579                            be ready for longer strings.  */
580                         char keybuf[32];
581                         char *keydata = keybuf;
582                         int count;
583                         Uint16 utf16buf[32];
584                         Uint16 *utf16data = utf16buf;
585                         int utf16size;
586                         int utf16length;
587
588                         count = Xutf8LookupString(SDL_IC, &xevent.xkey, keydata, sizeof(keybuf), &xkeysym, &status);
589                         if (XBufferOverflow == status) {
590                           /* The IM has just generated somewhat long
591                              string.  We need a longer buffer in this
592                              case.  */
593                           keydata = SDL_malloc(count);
594                           if ( keydata == NULL ) {
595                             SDL_OutOfMemory();
596                             break;
597                           }
598                           count = Xutf8LookupString(SDL_IC, &xevent.xkey, keydata, count, &xkeysym, &status);
599                         }
600
601                         switch (status) {
602
603                         case XBufferOverflow: {
604                           /* Oops!  We have allocated the bytes as
605                              requested by Xutf8LookupString, so the
606                              length of the buffer must be
607                              sufficient.  This case should never
608                              happen! */
609                           SDL_SetError("Xutf8LookupString indicated a double buffer overflow!");
610                           break;
611                         }
612
613                         case XLookupChars:
614                         case XLookupBoth: {
615                           if (0 == count) {
616                             break;
617                           }
618
619                           /* We got a converted string from IM.  Make
620                              sure to deliver all characters to the
621                              application as SDL events.  Note that
622                              an SDL event can only carry one UTF-16
623                              encoding unit, and a surrogate pair is
624                              delivered as two SDL events.  I guess
625                              this behaviour is probably _imported_
626                              from Windows or MacOS.  To do so, we need
627                              to convert the UTF-8 data into UTF-16
628                              data (not UCS4/UTF-32!).  We need an
629                              estimate of the number of UTF-16 encoding
630                              units here.  The worst case is pure ASCII
631                              string.  Assume so. */
632                           /* In 1.3 SDL may have a text event instead, that
633                              carries the whole UTF-8 string with it. */
634                           utf16size = count * sizeof(Uint16);
635                           if (utf16size > sizeof(utf16buf)) {
636                             utf16data = (Uint16 *) SDL_malloc(utf16size);
637                             if (utf16data == NULL) {
638                               SDL_OutOfMemory();
639                               break;
640                             }
641                           }
642                           utf16length = Utf8ToUtf16((Uint8 *)keydata, count, utf16data, utf16size);
643                           if (utf16length < 0) {
644                             /* The keydata contained an invalid byte
645                                sequence.  It should be a bug of the IM
646                                or Xlib... */
647                             SDL_SetError("Oops! Xutf8LookupString returned an invalid UTF-8 sequence!");
648                             break;
649                           }
650
651                           /* Deliver all UTF-16 encoding units.  At
652                              this moment, SDL event queue has a
653                              fixed size (128 events), and an SDL
654                              event can hold just one UTF-16 encoding
655                              unit.  So, if we receive more than 128
656                              UTF-16 encoding units from a commit,
657                              exceeded characters will be lost.  */
658                           for (i = 0; i < utf16length - 1; i++) {
659                             keysym.scancode = 0;
660                             keysym.sym = SDLK_UNKNOWN;
661                             keysym.mod = KMOD_NONE;
662                             keysym.unicode = utf16data[i];
663                             posted = SDL_PrivateKeyboard(SDL_PRESSED, &keysym);
664                           }
665                           /* The keysym for the last character carries the
666                              scancode and symbol that corresponds to the X11
667                              keycode.  */
668                           if (utf16length > 0) {                               
669                             keysym.scancode = keycode;
670                             keysym.sym = (keycode ? X11_TranslateKeycode(SDL_Display, keycode) : 0);
671                             keysym.mod = KMOD_NONE;
672                             keysym.unicode = utf16data[utf16length - 1];
673                             posted = SDL_PrivateKeyboard(SDL_PRESSED, &keysym);
674                           }
675                           break;
676                         }
677
678                         case XLookupKeySym: {
679                           /* I'm not sure whether it is possible that
680                              a zero keycode makes XLookupKeySym
681                              status.  What I'm sure is that a
682                              combination of a zero scan code and a non
683                              zero sym makes SDL_PrivateKeyboard
684                              strange state...  So, just discard it.
685                              If this doesn't work, I'm receiving bug
686                              reports, and I can know under what
687                              condition this case happens.  */
688                           if (keycode) {
689                             keysym.scancode = keycode;
690                             keysym.sym = X11_TranslateKeycode(SDL_Display, keycode);
691                             keysym.mod = KMOD_NONE;
692                             keysym.unicode = 0;
693                             posted = SDL_PrivateKeyboard(SDL_PRESSED, &keysym);
694                           }
695                           break;
696                         }
697
698                         case XLookupNone: {
699                           /* IM has eaten the event.  */
700                           break;
701                         }
702
703                         default:
704                           /* An unknown status from Xutf8LookupString.  */
705                           SDL_SetError("Oops! Xutf8LookupStringreturned an unknown status");
706                         }
707
708                         /* Release dynamic buffers if allocated.  */
709                         if (keydata != NULL && keybuf != keydata) {
710                           SDL_free(keydata);
711                         }
712                         if (utf16data != NULL && utf16buf != utf16data) {
713                           SDL_free(utf16data);
714                         }
715                 }
716                 else
717 #endif
718                 {
719                         static XComposeStatus state;
720                         char keybuf[32];
721
722                         keysym.scancode = keycode;
723                         keysym.sym = X11_TranslateKeycode(SDL_Display, keycode);
724                         keysym.mod = KMOD_NONE;
725                         keysym.unicode = 0;
726                         if ( XLookupString(&xevent.xkey,
727                                             keybuf, sizeof(keybuf),
728                                             NULL, &state) ) {
729                                 /*
730                                 * FIXME: XLookupString() may yield more than one
731                                 * character, so we need a mechanism to allow for
732                                 * this (perhaps null keypress events with a
733                                 * unicode value)
734                                 */
735                                 keysym.unicode = (Uint8)keybuf[0];
736                         }
737
738                         posted = SDL_PrivateKeyboard(SDL_PRESSED, &keysym);
739                 }
740             }
741             break;
742
743             /* Key release? */
744             case KeyRelease: {
745                 SDL_keysym keysym;
746                 KeyCode keycode = xevent.xkey.keycode;
747
748                 if (keycode == 0) {
749                   /* There should be no KeyRelease for keycode == 0,
750                      since it is a notification from IM but a real
751                      keystroke.  */
752                   /* We need to emit some diagnostic message here.  */
753                   break;
754                 }
755
756 #ifdef DEBUG_XEVENTS
757 printf("KeyRelease (X11 keycode = 0x%X)\n", xevent.xkey.keycode);
758 #endif
759
760                 /* Get the translated SDL virtual keysym */
761                 keysym.scancode = keycode;
762                 keysym.sym = X11_TranslateKeycode(SDL_Display, keycode);
763                 keysym.mod = KMOD_NONE;
764                 keysym.unicode = 0;
765
766                 posted = SDL_PrivateKeyboard(SDL_RELEASED, &keysym);
767             }
768             break;
769
770             /* Have we been iconified? */
771             case UnmapNotify: {
772 #ifdef DEBUG_XEVENTS
773 printf("UnmapNotify!\n");
774 #endif
775                 /* If we're active, make ourselves inactive */
776                 if ( SDL_GetAppState() & SDL_APPACTIVE ) {
777                         /* Swap out the gamma before we go inactive */
778                         X11_SwapVidModeGamma(this);
779
780                         /* Send an internal deactivate event */
781                         posted = SDL_PrivateAppActive(0,
782                                         SDL_APPACTIVE|SDL_APPINPUTFOCUS);
783                 }
784             }
785             break;
786
787             /* Have we been restored? */
788             case MapNotify: {
789 #ifdef DEBUG_XEVENTS
790 printf("MapNotify!\n");
791 #endif
792                 /* If we're not active, make ourselves active */
793                 if ( !(SDL_GetAppState() & SDL_APPACTIVE) ) {
794                         /* Send an internal activate event */
795                         posted = SDL_PrivateAppActive(1, SDL_APPACTIVE);
796
797                         /* Now that we're active, swap the gamma back */
798                         X11_SwapVidModeGamma(this);
799                 }
800
801                 if ( SDL_VideoSurface &&
802                      (SDL_VideoSurface->flags & SDL_FULLSCREEN) ) {
803                         X11_EnterFullScreen(this);
804                 } else {
805                         X11_GrabInputNoLock(this, this->input_grab);
806                 }
807                 X11_CheckMouseModeNoLock(this);
808
809                 if ( SDL_VideoSurface ) {
810                         X11_RefreshDisplay(this);
811                 }
812             }
813             break;
814
815             /* Have we been resized or moved? */
816             case ConfigureNotify: {
817 #ifdef DEBUG_XEVENTS
818 printf("ConfigureNotify! (resize: %dx%d)\n", xevent.xconfigure.width, xevent.xconfigure.height);
819 #endif
820                 if ( SDL_VideoSurface ) {
821                     if ((xevent.xconfigure.width != SDL_VideoSurface->w) ||
822                         (xevent.xconfigure.height != SDL_VideoSurface->h)) {
823                         /* FIXME: Find a better fix for the bug with KDE 1.2 */
824                         if ( ! ((xevent.xconfigure.width == 32) &&
825                                 (xevent.xconfigure.height == 32)) ) {
826                                 SDL_PrivateResize(xevent.xconfigure.width,
827                                                   xevent.xconfigure.height);
828                         }
829                     } else {
830                         /* OpenGL windows need to know about the change */
831                         if ( SDL_VideoSurface->flags & SDL_OPENGL ) {
832                                 SDL_PrivateExpose();
833                         }
834                     }
835                 }
836             }
837             break;
838
839             /* Have we been requested to quit (or another client message?) */
840             case ClientMessage: {
841                 if ( (xevent.xclient.format == 32) &&
842                      (xevent.xclient.data.l[0] == WM_DELETE_WINDOW) )
843                 {
844                         posted = SDL_PrivateQuit();
845                 } else
846                 if ( SDL_ProcessEvents[SDL_SYSWMEVENT] == SDL_ENABLE ) {
847                         SDL_SysWMmsg wmmsg;
848
849                         SDL_VERSION(&wmmsg.version);
850                         wmmsg.subsystem = SDL_SYSWM_X11;
851                         wmmsg.event.xevent = xevent;
852                         posted = SDL_PrivateSysWMEvent(&wmmsg);
853                 }
854             }
855             break;
856
857             /* Do we need to refresh ourselves? */
858             case Expose: {
859 #ifdef DEBUG_XEVENTS
860 printf("Expose (count = %d)\n", xevent.xexpose.count);
861 #endif
862                 if ( SDL_VideoSurface && (xevent.xexpose.count == 0) ) {
863                         X11_RefreshDisplay(this);
864                 }
865             }
866             break;
867
868             default: {
869 #ifdef DEBUG_XEVENTS
870 printf("Unhandled event %d\n", xevent.type);
871 #endif
872                 /* Only post the event if we're watching for it */
873                 if ( SDL_ProcessEvents[SDL_SYSWMEVENT] == SDL_ENABLE ) {
874                         SDL_SysWMmsg wmmsg;
875
876                         SDL_VERSION(&wmmsg.version);
877                         wmmsg.subsystem = SDL_SYSWM_X11;
878                         wmmsg.event.xevent = xevent;
879                         posted = SDL_PrivateSysWMEvent(&wmmsg);
880                 }
881             }
882             break;
883         }
884         return(posted);
885 }
886
887 /* Ack!  XPending() actually performs a blocking read if no events available */
888 int X11_Pending(Display *display)
889 {
890         /* Flush the display connection and look to see if events are queued */
891         XFlush(display);
892         if ( XEventsQueued(display, QueuedAlready) ) {
893                 return(1);
894         }
895
896         /* More drastic measures are required -- see if X is ready to talk */
897         {
898                 static struct timeval zero_time;        /* static == 0 */
899                 int x11_fd;
900                 fd_set fdset;
901
902                 x11_fd = ConnectionNumber(display);
903                 FD_ZERO(&fdset);
904                 FD_SET(x11_fd, &fdset);
905                 if ( select(x11_fd+1, &fdset, NULL, NULL, &zero_time) == 1 ) {
906                         return(XPending(display));
907                 }
908         }
909
910         /* Oh well, nothing is ready .. */
911         return(0);
912 }
913
914 void X11_PumpEvents(_THIS)
915 {
916         int pending;
917
918         /* Update activity every five seconds to prevent screensaver. --ryan. */
919         if (!allow_screensaver) {
920                 static Uint32 screensaverTicks;
921                 Uint32 nowTicks = SDL_GetTicks();
922                 if ((nowTicks - screensaverTicks) > 5000) {
923                         XResetScreenSaver(SDL_Display);
924                         screensaverTicks = nowTicks;
925                 }
926         }
927
928         /* Keep processing pending events */
929         pending = 0;
930         while ( X11_Pending(SDL_Display) ) {
931                 X11_DispatchEvent(this);
932                 ++pending;
933         }
934         if ( switch_waiting ) {
935                 Uint32 now;
936
937                 now  = SDL_GetTicks();
938                 if ( pending || !SDL_VideoSurface ) {
939                         /* Try again later... */
940                         if ( switch_waiting & SDL_FULLSCREEN ) {
941                                 switch_time = now + 1500;
942                         } else {
943                                 switch_time = now + 200;
944                         }
945                 } else if ( (int)(switch_time-now) <= 0 ) {
946                         Uint32 go_fullscreen;
947
948                         go_fullscreen = switch_waiting & SDL_FULLSCREEN;
949                         switch_waiting = 0;
950                         if ( SDL_VideoSurface->flags & SDL_FULLSCREEN ) {
951                                 if ( go_fullscreen ) {
952                                         X11_EnterFullScreen(this);
953                                 } else {
954                                         X11_LeaveFullScreen(this);
955                                 }
956                         }
957                         /* Handle focus in/out when grabbed */
958                         if ( go_fullscreen ) {
959                                 X11_GrabInputNoLock(this, this->input_grab);
960                         } else {
961                                 X11_GrabInputNoLock(this, SDL_GRAB_OFF);
962                         }
963                         X11_CheckMouseModeNoLock(this);
964                 }
965         }
966 }
967
968 void X11_InitKeymap(void)
969 {
970         int i;
971
972         /* Odd keys used in international keyboards */
973         for ( i=0; i<SDL_arraysize(ODD_keymap); ++i )
974                 ODD_keymap[i] = SDLK_UNKNOWN;
975
976         /* Some of these might be mappable to an existing SDLK_ code */
977         ODD_keymap[XK_dead_grave&0xFF] = SDLK_COMPOSE;
978         ODD_keymap[XK_dead_acute&0xFF] = SDLK_COMPOSE;
979         ODD_keymap[XK_dead_tilde&0xFF] = SDLK_COMPOSE;
980         ODD_keymap[XK_dead_macron&0xFF] = SDLK_COMPOSE;
981         ODD_keymap[XK_dead_breve&0xFF] = SDLK_COMPOSE;
982         ODD_keymap[XK_dead_abovedot&0xFF] = SDLK_COMPOSE;
983         ODD_keymap[XK_dead_diaeresis&0xFF] = SDLK_COMPOSE;
984         ODD_keymap[XK_dead_abovering&0xFF] = SDLK_COMPOSE;
985         ODD_keymap[XK_dead_doubleacute&0xFF] = SDLK_COMPOSE;
986         ODD_keymap[XK_dead_caron&0xFF] = SDLK_COMPOSE;
987         ODD_keymap[XK_dead_cedilla&0xFF] = SDLK_COMPOSE;
988         ODD_keymap[XK_dead_ogonek&0xFF] = SDLK_COMPOSE;
989         ODD_keymap[XK_dead_iota&0xFF] = SDLK_COMPOSE;
990         ODD_keymap[XK_dead_voiced_sound&0xFF] = SDLK_COMPOSE;
991         ODD_keymap[XK_dead_semivoiced_sound&0xFF] = SDLK_COMPOSE;
992         ODD_keymap[XK_dead_belowdot&0xFF] = SDLK_COMPOSE;
993 #ifdef XK_dead_hook
994         ODD_keymap[XK_dead_hook&0xFF] = SDLK_COMPOSE;
995 #endif
996 #ifdef XK_dead_horn
997         ODD_keymap[XK_dead_horn&0xFF] = SDLK_COMPOSE;
998 #endif
999
1000 #ifdef XK_dead_circumflex
1001         /* These X keysyms have 0xFE as the high byte */
1002         ODD_keymap[XK_dead_circumflex&0xFF] = SDLK_CARET;
1003 #endif
1004 #ifdef XK_ISO_Level3_Shift
1005         ODD_keymap[XK_ISO_Level3_Shift&0xFF] = SDLK_MODE; /* "Alt Gr" key */
1006 #endif
1007
1008         /* Map the miscellaneous keys */
1009         for ( i=0; i<SDL_arraysize(MISC_keymap); ++i )
1010                 MISC_keymap[i] = SDLK_UNKNOWN;
1011
1012         /* These X keysyms have 0xFF as the high byte */
1013         MISC_keymap[XK_BackSpace&0xFF] = SDLK_BACKSPACE;
1014         MISC_keymap[XK_Tab&0xFF] = SDLK_TAB;
1015         MISC_keymap[XK_Clear&0xFF] = SDLK_CLEAR;
1016         MISC_keymap[XK_Return&0xFF] = SDLK_RETURN;
1017         MISC_keymap[XK_Pause&0xFF] = SDLK_PAUSE;
1018         MISC_keymap[XK_Escape&0xFF] = SDLK_ESCAPE;
1019         MISC_keymap[XK_Delete&0xFF] = SDLK_DELETE;
1020
1021         MISC_keymap[XK_KP_0&0xFF] = SDLK_KP0;           /* Keypad 0-9 */
1022         MISC_keymap[XK_KP_1&0xFF] = SDLK_KP1;
1023         MISC_keymap[XK_KP_2&0xFF] = SDLK_KP2;
1024         MISC_keymap[XK_KP_3&0xFF] = SDLK_KP3;
1025         MISC_keymap[XK_KP_4&0xFF] = SDLK_KP4;
1026         MISC_keymap[XK_KP_5&0xFF] = SDLK_KP5;
1027         MISC_keymap[XK_KP_6&0xFF] = SDLK_KP6;
1028         MISC_keymap[XK_KP_7&0xFF] = SDLK_KP7;
1029         MISC_keymap[XK_KP_8&0xFF] = SDLK_KP8;
1030         MISC_keymap[XK_KP_9&0xFF] = SDLK_KP9;
1031         MISC_keymap[XK_KP_Insert&0xFF] = SDLK_KP0;
1032         MISC_keymap[XK_KP_End&0xFF] = SDLK_KP1; 
1033         MISC_keymap[XK_KP_Down&0xFF] = SDLK_KP2;
1034         MISC_keymap[XK_KP_Page_Down&0xFF] = SDLK_KP3;
1035         MISC_keymap[XK_KP_Left&0xFF] = SDLK_KP4;
1036         MISC_keymap[XK_KP_Begin&0xFF] = SDLK_KP5;
1037         MISC_keymap[XK_KP_Right&0xFF] = SDLK_KP6;
1038         MISC_keymap[XK_KP_Home&0xFF] = SDLK_KP7;
1039         MISC_keymap[XK_KP_Up&0xFF] = SDLK_KP8;
1040         MISC_keymap[XK_KP_Page_Up&0xFF] = SDLK_KP9;
1041         MISC_keymap[XK_KP_Delete&0xFF] = SDLK_KP_PERIOD;
1042         MISC_keymap[XK_KP_Decimal&0xFF] = SDLK_KP_PERIOD;
1043         MISC_keymap[XK_KP_Divide&0xFF] = SDLK_KP_DIVIDE;
1044         MISC_keymap[XK_KP_Multiply&0xFF] = SDLK_KP_MULTIPLY;
1045         MISC_keymap[XK_KP_Subtract&0xFF] = SDLK_KP_MINUS;
1046         MISC_keymap[XK_KP_Add&0xFF] = SDLK_KP_PLUS;
1047         MISC_keymap[XK_KP_Enter&0xFF] = SDLK_KP_ENTER;
1048         MISC_keymap[XK_KP_Equal&0xFF] = SDLK_KP_EQUALS;
1049
1050         MISC_keymap[XK_Up&0xFF] = SDLK_UP;
1051         MISC_keymap[XK_Down&0xFF] = SDLK_DOWN;
1052         MISC_keymap[XK_Right&0xFF] = SDLK_RIGHT;
1053         MISC_keymap[XK_Left&0xFF] = SDLK_LEFT;
1054         MISC_keymap[XK_Insert&0xFF] = SDLK_INSERT;
1055         MISC_keymap[XK_Home&0xFF] = SDLK_HOME;
1056         MISC_keymap[XK_End&0xFF] = SDLK_END;
1057         MISC_keymap[XK_Page_Up&0xFF] = SDLK_PAGEUP;
1058         MISC_keymap[XK_Page_Down&0xFF] = SDLK_PAGEDOWN;
1059
1060         MISC_keymap[XK_F1&0xFF] = SDLK_F1;
1061         MISC_keymap[XK_F2&0xFF] = SDLK_F2;
1062         MISC_keymap[XK_F3&0xFF] = SDLK_F3;
1063         MISC_keymap[XK_F4&0xFF] = SDLK_F4;
1064         MISC_keymap[XK_F5&0xFF] = SDLK_F5;
1065         MISC_keymap[XK_F6&0xFF] = SDLK_F6;
1066         MISC_keymap[XK_F7&0xFF] = SDLK_F7;
1067         MISC_keymap[XK_F8&0xFF] = SDLK_F8;
1068         MISC_keymap[XK_F9&0xFF] = SDLK_F9;
1069         MISC_keymap[XK_F10&0xFF] = SDLK_F10;
1070         MISC_keymap[XK_F11&0xFF] = SDLK_F11;
1071         MISC_keymap[XK_F12&0xFF] = SDLK_F12;
1072         MISC_keymap[XK_F13&0xFF] = SDLK_F13;
1073         MISC_keymap[XK_F14&0xFF] = SDLK_F14;
1074         MISC_keymap[XK_F15&0xFF] = SDLK_F15;
1075
1076         MISC_keymap[XK_Num_Lock&0xFF] = SDLK_NUMLOCK;
1077         MISC_keymap[XK_Caps_Lock&0xFF] = SDLK_CAPSLOCK;
1078         MISC_keymap[XK_Scroll_Lock&0xFF] = SDLK_SCROLLOCK;
1079         MISC_keymap[XK_Shift_R&0xFF] = SDLK_RSHIFT;
1080         MISC_keymap[XK_Shift_L&0xFF] = SDLK_LSHIFT;
1081         MISC_keymap[XK_Control_R&0xFF] = SDLK_RCTRL;
1082         MISC_keymap[XK_Control_L&0xFF] = SDLK_LCTRL;
1083         MISC_keymap[XK_Alt_R&0xFF] = SDLK_RALT;
1084         MISC_keymap[XK_Alt_L&0xFF] = SDLK_LALT;
1085         MISC_keymap[XK_Meta_R&0xFF] = SDLK_RMETA;
1086         MISC_keymap[XK_Meta_L&0xFF] = SDLK_LMETA;
1087         MISC_keymap[XK_Super_L&0xFF] = SDLK_LSUPER; /* Left "Windows" */
1088         MISC_keymap[XK_Super_R&0xFF] = SDLK_RSUPER; /* Right "Windows */
1089         MISC_keymap[XK_Mode_switch&0xFF] = SDLK_MODE; /* "Alt Gr" key */
1090         MISC_keymap[XK_Multi_key&0xFF] = SDLK_COMPOSE; /* Multi-key compose */
1091
1092         MISC_keymap[XK_Help&0xFF] = SDLK_HELP;
1093         MISC_keymap[XK_Print&0xFF] = SDLK_PRINT;
1094         MISC_keymap[XK_Sys_Req&0xFF] = SDLK_SYSREQ;
1095         MISC_keymap[XK_Break&0xFF] = SDLK_BREAK;
1096         MISC_keymap[XK_Menu&0xFF] = SDLK_MENU;
1097         MISC_keymap[XK_Hyper_R&0xFF] = SDLK_MENU;   /* Windows "Menu" key */
1098 }
1099
1100 /* Get the translated SDL virtual keysym */
1101 SDLKey X11_TranslateKeycode(Display *display, KeyCode kc)
1102 {
1103         KeySym xsym;
1104         SDLKey key;
1105
1106         xsym = XKeycodeToKeysym(display, kc, 0);
1107 #ifdef DEBUG_KEYS
1108         fprintf(stderr, "Translating key code %d -> 0x%.4x\n", kc, xsym);
1109 #endif
1110         key = SDLK_UNKNOWN;
1111         if ( xsym ) {
1112                 switch (xsym>>8) {
1113                     case 0x1005FF:
1114 #ifdef SunXK_F36
1115                         if ( xsym == SunXK_F36 )
1116                                 key = SDLK_F11;
1117 #endif
1118 #ifdef SunXK_F37
1119                         if ( xsym == SunXK_F37 )
1120                                 key = SDLK_F12;
1121 #endif
1122                         break;
1123                     case 0x00:  /* Latin 1 */
1124                         key = (SDLKey)(xsym & 0xFF);
1125                         break;
1126                     case 0x01:  /* Latin 2 */
1127                     case 0x02:  /* Latin 3 */
1128                     case 0x03:  /* Latin 4 */
1129                     case 0x04:  /* Katakana */
1130                     case 0x05:  /* Arabic */
1131                     case 0x06:  /* Cyrillic */
1132                     case 0x07:  /* Greek */
1133                     case 0x08:  /* Technical */
1134                     case 0x0A:  /* Publishing */
1135                     case 0x0C:  /* Hebrew */
1136                     case 0x0D:  /* Thai */
1137                         /* These are wrong, but it's better than nothing */
1138                         key = (SDLKey)(xsym & 0xFF);
1139                         break;
1140                     case 0xFE:
1141                         key = ODD_keymap[xsym&0xFF];
1142                         break;
1143                     case 0xFF:
1144                         key = MISC_keymap[xsym&0xFF];
1145                         break;
1146                     default:
1147                         /*
1148                         fprintf(stderr, "X11: Unhandled xsym, sym = 0x%04x\n",
1149                                         (unsigned int)xsym);
1150                         */
1151                         break;
1152                 }
1153         } else {
1154                 /* X11 doesn't know how to translate the key! */
1155                 switch (kc) {
1156                     /* Caution:
1157                        These keycodes are from the Microsoft Keyboard
1158                      */
1159                     case 115:
1160                         key = SDLK_LSUPER;
1161                         break;
1162                     case 116:
1163                         key = SDLK_RSUPER;
1164                         break;
1165                     case 117:
1166                         key = SDLK_MENU;
1167                         break;
1168                     default:
1169                         /*
1170                          * no point in an error message; happens for
1171                          * several keys when we get a keymap notify
1172                          */
1173                         break;
1174                 }
1175         }
1176         return key;
1177 }
1178
1179 /* X11 modifier masks for various keys */
1180 static unsigned meta_l_mask, meta_r_mask, alt_l_mask, alt_r_mask;
1181 static unsigned num_mask, mode_switch_mask;
1182
1183 static void get_modifier_masks(Display *display)
1184 {
1185         static unsigned got_masks;
1186         int i, j;
1187         XModifierKeymap *xmods;
1188         unsigned n;
1189
1190         if(got_masks)
1191                 return;
1192
1193         xmods = XGetModifierMapping(display);
1194         n = xmods->max_keypermod;
1195         for(i = 3; i < 8; i++) {
1196                 for(j = 0; j < n; j++) {
1197                         KeyCode kc = xmods->modifiermap[i * n + j];
1198                         KeySym ks = XKeycodeToKeysym(display, kc, 0);
1199                         unsigned mask = 1 << i;
1200                         switch(ks) {
1201                         case XK_Num_Lock:
1202                                 num_mask = mask; break;
1203                         case XK_Alt_L:
1204                                 alt_l_mask = mask; break;
1205                         case XK_Alt_R:
1206                                 alt_r_mask = mask; break;
1207                         case XK_Meta_L:
1208                                 meta_l_mask = mask; break;
1209                         case XK_Meta_R:
1210                                 meta_r_mask = mask; break;
1211                         case XK_Mode_switch:
1212                                 mode_switch_mask = mask; break;
1213                         }
1214                 }
1215         }
1216         XFreeModifiermap(xmods);
1217         got_masks = 1;
1218 }
1219
1220
1221 /*
1222  * This function is semi-official; it is not officially exported and should
1223  * not be considered part of the SDL API, but may be used by client code
1224  * that *really* needs it (including legacy code).
1225  * It is slow, though, and should be avoided if possible.
1226  *
1227  * Note that it isn't completely accurate either; in particular, multi-key
1228  * sequences (dead accents, compose key sequences) will not work since the
1229  * state has been irrevocably lost.
1230  */
1231 Uint16 X11_KeyToUnicode(SDLKey keysym, SDLMod modifiers)
1232 {
1233         struct SDL_VideoDevice *this = current_video;
1234         char keybuf[32];
1235         int i;
1236         KeySym xsym = 0;
1237         XKeyEvent xkey;
1238         Uint16 unicode;
1239
1240         if ( !this || !SDL_Display ) {
1241                 return 0;
1242         }
1243
1244         SDL_memset(&xkey, 0, sizeof(xkey));
1245         xkey.display = SDL_Display;
1246
1247         xsym = keysym;          /* last resort if not found */
1248         for (i = 0; i < 256; ++i) {
1249                 if ( MISC_keymap[i] == keysym ) {
1250                         xsym = 0xFF00 | i;
1251                         break;
1252                 } else if ( ODD_keymap[i] == keysym ) {
1253                         xsym = 0xFE00 | i;
1254                         break;
1255                 }
1256         }
1257
1258         xkey.keycode = XKeysymToKeycode(xkey.display, xsym);
1259
1260         get_modifier_masks(SDL_Display);
1261         if(modifiers & KMOD_SHIFT)
1262                 xkey.state |= ShiftMask;
1263         if(modifiers & KMOD_CAPS)
1264                 xkey.state |= LockMask;
1265         if(modifiers & KMOD_CTRL)
1266                 xkey.state |= ControlMask;
1267         if(modifiers & KMOD_MODE)
1268                 xkey.state |= mode_switch_mask;
1269         if(modifiers & KMOD_LALT)
1270                 xkey.state |= alt_l_mask;
1271         if(modifiers & KMOD_RALT)
1272                 xkey.state |= alt_r_mask;
1273         if(modifiers & KMOD_LMETA)
1274                 xkey.state |= meta_l_mask;
1275         if(modifiers & KMOD_RMETA)
1276                 xkey.state |= meta_r_mask;
1277         if(modifiers & KMOD_NUM)
1278                 xkey.state |= num_mask;
1279
1280         unicode = 0;
1281         if ( XLookupString(&xkey, keybuf, sizeof(keybuf), NULL, NULL) )
1282                 unicode = (unsigned char)keybuf[0];
1283         return(unicode);
1284 }
1285
1286
1287 /*
1288  * Called when focus is regained, to read the keyboard state and generate
1289  * synthetic keypress/release events.
1290  * key_vec is a bit vector of keycodes (256 bits)
1291  */
1292 void X11_SetKeyboardState(Display *display, const char *key_vec)
1293 {
1294         char keys_return[32];
1295         int i;
1296         Uint8 *kstate = SDL_GetKeyState(NULL);
1297         SDLMod modstate;
1298         Window junk_window;
1299         int x, y;
1300         unsigned int mask;
1301
1302         /* The first time the window is mapped, we initialize key state */
1303         if ( ! key_vec ) {
1304                 XQueryKeymap(display, keys_return);
1305                 key_vec = keys_return;
1306         }
1307
1308         /* Get the keyboard modifier state */
1309         modstate = 0;
1310         get_modifier_masks(display);
1311         if ( XQueryPointer(display, DefaultRootWindow(display),
1312                 &junk_window, &junk_window, &x, &y, &x, &y, &mask) ) {
1313                 if ( mask & LockMask ) {
1314                         modstate |= KMOD_CAPS;
1315                 }
1316                 if ( mask & mode_switch_mask ) {
1317                         modstate |= KMOD_MODE;
1318                 }
1319                 if ( mask & num_mask ) {
1320                         modstate |= KMOD_NUM;
1321                 }
1322         }
1323
1324         /* Zero the new keyboard state and generate it */
1325         SDL_memset(kstate, 0, SDLK_LAST);
1326         /*
1327          * An obvious optimisation is to check entire longwords at a time in
1328          * both loops, but we can't be sure the arrays are aligned so it's not
1329          * worth the extra complexity
1330          */
1331         for ( i = 0; i < 32; i++ ) {
1332                 int j;
1333                 if ( !key_vec[i] )
1334                         continue;
1335                 for ( j = 0; j < 8; j++ ) {
1336                         if ( key_vec[i] & (1 << j) ) {
1337                                 SDLKey key;
1338                                 KeyCode kc = (i << 3 | j);
1339                                 key = X11_TranslateKeycode(display, kc);
1340                                 if ( key == SDLK_UNKNOWN ) {
1341                                         continue;
1342                                 }
1343                                 kstate[key] = SDL_PRESSED;
1344                                 switch (key) {
1345                                     case SDLK_LSHIFT:
1346                                         modstate |= KMOD_LSHIFT;
1347                                         break;
1348                                     case SDLK_RSHIFT:
1349                                         modstate |= KMOD_RSHIFT;
1350                                         break;
1351                                     case SDLK_LCTRL:
1352                                         modstate |= KMOD_LCTRL;
1353                                         break;
1354                                     case SDLK_RCTRL:
1355                                         modstate |= KMOD_RCTRL;
1356                                         break;
1357                                     case SDLK_LALT:
1358                                         modstate |= KMOD_LALT;
1359                                         break;
1360                                     case SDLK_RALT:
1361                                         modstate |= KMOD_RALT;
1362                                         break;
1363                                     case SDLK_LMETA:
1364                                         modstate |= KMOD_LMETA;
1365                                         break;
1366                                     case SDLK_RMETA:
1367                                         modstate |= KMOD_RMETA;
1368                                         break;
1369                                     default:
1370                                         break;
1371                                 }
1372                         }
1373                 }
1374         }
1375
1376         /* Hack - set toggle key state */
1377         if ( modstate & KMOD_CAPS ) {
1378                 kstate[SDLK_CAPSLOCK] = SDL_PRESSED;
1379         } else {
1380                 kstate[SDLK_CAPSLOCK] = SDL_RELEASED;
1381         }
1382         if ( modstate & KMOD_NUM ) {
1383                 kstate[SDLK_NUMLOCK] = SDL_PRESSED;
1384         } else {
1385                 kstate[SDLK_NUMLOCK] = SDL_RELEASED;
1386         }
1387
1388         /* Set the final modifier state */
1389         SDL_SetModState(modstate);
1390 }
1391
1392 void X11_InitOSKeymap(_THIS)
1393 {
1394         X11_InitKeymap();
1395 }
1396