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