1 /*
2 SDL - Simple DirectMedia Layer
3 Copyright (C) 1997-2006 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
Utf8ToUcs4(const Uint8 * utf8)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
Utf8ToUtf16(const Uint8 * utf8,const int utf8_length,Uint16 * utf16,const int utf16_max_length)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 if (p >= max_ptr) {
239 /* No more output space. */
240 return -1;
241 }
242 Uint8 const c = *utf8;
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 */
X11_KeyRepeat(Display * display,XEvent * event)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
X11_WarpedMotion(_THIS,XEvent * xevent)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
X11_DispatchEvent(_THIS)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 ( (xevent.xcrossing.mode != NotifyGrab) &&
427 (xevent.xcrossing.mode != NotifyUngrab) ) {
428 if ( this->input_grab == SDL_GRAB_OFF ) {
429 posted = SDL_PrivateAppActive(1, SDL_APPMOUSEFOCUS);
430 }
431 posted = SDL_PrivateMouseMotion(0, 0,
432 xevent.xcrossing.x,
433 xevent.xcrossing.y);
434 }
435 }
436 break;
437
438 /* Losing mouse coverage? */
439 case LeaveNotify: {
440 #ifdef DEBUG_XEVENTS
441 printf("LeaveNotify! (%d,%d)\n", xevent.xcrossing.x, xevent.xcrossing.y);
442 if ( xevent.xcrossing.mode == NotifyGrab )
443 printf("Mode: NotifyGrab\n");
444 if ( xevent.xcrossing.mode == NotifyUngrab )
445 printf("Mode: NotifyUngrab\n");
446 #endif
447 if ( (xevent.xcrossing.mode != NotifyGrab) &&
448 (xevent.xcrossing.mode != NotifyUngrab) &&
449 (xevent.xcrossing.detail != NotifyInferior) ) {
450 if ( this->input_grab == SDL_GRAB_OFF ) {
451 posted = SDL_PrivateAppActive(0, SDL_APPMOUSEFOCUS);
452 } else {
453 posted = SDL_PrivateMouseMotion(0, 0,
454 xevent.xcrossing.x,
455 xevent.xcrossing.y);
456 }
457 }
458 }
459 break;
460
461 /* Gaining input focus? */
462 case FocusIn: {
463 #ifdef DEBUG_XEVENTS
464 printf("FocusIn!\n");
465 #endif
466 posted = SDL_PrivateAppActive(1, SDL_APPINPUTFOCUS);
467
468 #ifdef X_HAVE_UTF8_STRING
469 if ( SDL_IC != NULL ) {
470 XSetICFocus(SDL_IC);
471 }
472 #endif
473 /* Queue entry into fullscreen mode */
474 switch_waiting = 0x01 | SDL_FULLSCREEN;
475 switch_time = SDL_GetTicks() + 1500;
476 }
477 break;
478
479 /* Losing input focus? */
480 case FocusOut: {
481 #ifdef DEBUG_XEVENTS
482 printf("FocusOut!\n");
483 #endif
484 posted = SDL_PrivateAppActive(0, SDL_APPINPUTFOCUS);
485
486 #ifdef X_HAVE_UTF8_STRING
487 if ( SDL_IC != NULL ) {
488 XUnsetICFocus(SDL_IC);
489 }
490 #endif
491 /* Queue leaving fullscreen mode */
492 switch_waiting = 0x01;
493 switch_time = SDL_GetTicks() + 200;
494 }
495 break;
496
497 /* Some IM requires MappingNotify to be passed to
498 XRefreshKeyboardMapping by the app. */
499 case MappingNotify: {
500 XRefreshKeyboardMapping(&xevent.xmapping);
501 }
502 break;
503
504 /* Generated upon EnterWindow and FocusIn */
505 case KeymapNotify: {
506 #ifdef DEBUG_XEVENTS
507 printf("KeymapNotify!\n");
508 #endif
509 X11_SetKeyboardState(SDL_Display, xevent.xkeymap.key_vector);
510 }
511 break;
512
513 /* Mouse motion? */
514 case MotionNotify: {
515 if ( SDL_VideoSurface ) {
516 if ( mouse_relative ) {
517 if ( using_dga & DGA_MOUSE ) {
518 #ifdef DEBUG_MOTION
519 printf("DGA motion: %d,%d\n", xevent.xmotion.x_root, xevent.xmotion.y_root);
520 #endif
521 posted = SDL_PrivateMouseMotion(0, 1,
522 xevent.xmotion.x_root,
523 xevent.xmotion.y_root);
524 } else {
525 posted = X11_WarpedMotion(this,&xevent);
526 }
527 } else {
528 #ifdef DEBUG_MOTION
529 printf("X11 motion: %d,%d\n", xevent.xmotion.x, xevent.xmotion.y);
530 #endif
531 posted = SDL_PrivateMouseMotion(0, 0,
532 xevent.xmotion.x,
533 xevent.xmotion.y);
534 }
535 }
536 }
537 break;
538
539 /* Mouse button press? */
540 case ButtonPress: {
541 posted = SDL_PrivateMouseButton(SDL_PRESSED,
542 xevent.xbutton.button, 0, 0);
543 }
544 break;
545
546 /* Mouse button release? */
547 case ButtonRelease: {
548 posted = SDL_PrivateMouseButton(SDL_RELEASED,
549 xevent.xbutton.button, 0, 0);
550 }
551 break;
552
553 /* Key press? */
554 case KeyPress: {
555 SDL_keysym keysym;
556 KeyCode keycode = xevent.xkey.keycode;
557
558 #ifdef DEBUG_XEVENTS
559 printf("KeyPress (X11 keycode = 0x%X)\n", xevent.xkey.keycode);
560 #endif
561 /* If we're not doing translation, we're done! */
562 if ( !SDL_TranslateUNICODE ) {
563 /* Get the translated SDL virtual keysym and put it on the queue.*/
564 keysym.scancode = keycode;
565 keysym.sym = X11_TranslateKeycode(SDL_Display, keycode);
566 keysym.mod = KMOD_NONE;
567 keysym.unicode = 0;
568 posted = SDL_PrivateKeyboard(SDL_PRESSED, &keysym);
569 break;
570 }
571
572 /* Look up the translated value for the key event */
573 #ifdef X_HAVE_UTF8_STRING
574 if ( SDL_IC != NULL ) {
575 Status status;
576 KeySym xkeysym;
577 int i;
578 /* A UTF-8 character can be at most 6 bytes */
579 /* ... It's true, but Xutf8LookupString can
580 return more than one characters. Moreover,
581 the spec. put no upper bound, so we should
582 be ready for longer strings. */
583 char keybuf[32];
584 char *keydata = keybuf;
585 int count;
586 Uint16 utf16buf[32];
587 Uint16 *utf16data = utf16buf;
588 int utf16size;
589 int utf16length;
590
591 count = Xutf8LookupString(SDL_IC, &xevent.xkey, keydata, sizeof(keybuf), &xkeysym, &status);
592 if (XBufferOverflow == status) {
593 /* The IM has just generated somewhat long
594 string. We need a longer buffer in this
595 case. */
596 keydata = SDL_malloc(count);
597 if ( keydata == NULL ) {
598 SDL_OutOfMemory();
599 break;
600 }
601 count = Xutf8LookupString(SDL_IC, &xevent.xkey, keydata, count, &xkeysym, &status);
602 }
603
604 switch (status) {
605
606 case XBufferOverflow: {
607 /* Oops! We have allocated the bytes as
608 requested by Xutf8LookupString, so the
609 length of the buffer must be
610 sufficient. This case should never
611 happen! */
612 SDL_SetError("Xutf8LookupString indicated a double buffer overflow!");
613 break;
614 }
615
616 case XLookupChars:
617 case XLookupBoth: {
618 if (0 == count) {
619 break;
620 }
621
622 /* We got a converted string from IM. Make
623 sure to deliver all characters to the
624 application as SDL events. Note that
625 an SDL event can only carry one UTF-16
626 encoding unit, and a surrogate pair is
627 delivered as two SDL events. I guess
628 this behaviour is probably _imported_
629 from Windows or MacOS. To do so, we need
630 to convert the UTF-8 data into UTF-16
631 data (not UCS4/UTF-32!). We need an
632 estimate of the number of UTF-16 encoding
633 units here. The worst case is pure ASCII
634 string. Assume so. */
635 /* In 1.3 SDL may have a text event instead, that
636 carries the whole UTF-8 string with it. */
637 utf16size = count * sizeof(Uint16);
638 if (utf16size > sizeof(utf16buf)) {
639 utf16data = (Uint16 *) SDL_malloc(utf16size);
640 if (utf16data == NULL) {
641 SDL_OutOfMemory();
642 break;
643 }
644 }
645 utf16length = Utf8ToUtf16((Uint8 *)keydata, count, utf16data, utf16size);
646 if (utf16length < 0) {
647 /* The keydata contained an invalid byte
648 sequence. It should be a bug of the IM
649 or Xlib... */
650 SDL_SetError("Oops! Xutf8LookupString returned an invalid UTF-8 sequence!");
651 break;
652 }
653
654 /* Deliver all UTF-16 encoding units. At
655 this moment, SDL event queue has a
656 fixed size (128 events), and an SDL
657 event can hold just one UTF-16 encoding
658 unit. So, if we receive more than 128
659 UTF-16 encoding units from a commit,
660 exceeded characters will be lost. */
661 for (i = 0; i < utf16length - 1; i++) {
662 keysym.scancode = 0;
663 keysym.sym = SDLK_UNKNOWN;
664 keysym.mod = KMOD_NONE;
665 keysym.unicode = utf16data[i];
666 posted = SDL_PrivateKeyboard(SDL_PRESSED, &keysym);
667 }
668 /* The keysym for the last character carries the
669 scancode and symbol that corresponds to the X11
670 keycode. */
671 if (utf16length > 0) {
672 keysym.scancode = keycode;
673 keysym.sym = (keycode ? X11_TranslateKeycode(SDL_Display, keycode) : 0);
674 keysym.mod = KMOD_NONE;
675 keysym.unicode = utf16data[utf16length - 1];
676 posted = SDL_PrivateKeyboard(SDL_PRESSED, &keysym);
677 }
678 break;
679 }
680
681 case XLookupKeySym: {
682 /* I'm not sure whether it is possible that
683 a zero keycode makes XLookupKeySym
684 status. What I'm sure is that a
685 combination of a zero scan code and a non
686 zero sym makes SDL_PrivateKeyboard
687 strange state... So, just discard it.
688 If this doesn't work, I'm receiving bug
689 reports, and I can know under what
690 condition this case happens. */
691 if (keycode) {
692 keysym.scancode = keycode;
693 keysym.sym = X11_TranslateKeycode(SDL_Display, keycode);
694 keysym.mod = KMOD_NONE;
695 keysym.unicode = 0;
696 posted = SDL_PrivateKeyboard(SDL_PRESSED, &keysym);
697 }
698 break;
699 }
700
701 case XLookupNone: {
702 /* IM has eaten the event. */
703 break;
704 }
705
706 default:
707 /* An unknown status from Xutf8LookupString. */
708 SDL_SetError("Oops! Xutf8LookupStringreturned an unknown status");
709 }
710
711 /* Release dynamic buffers if allocated. */
712 if (keydata != NULL && keybuf != keydata) {
713 SDL_free(keydata);
714 }
715 if (utf16data != NULL && utf16buf != utf16data) {
716 SDL_free(utf16data);
717 }
718 }
719 else
720 #endif
721 {
722 static XComposeStatus state;
723 char keybuf[32];
724
725 keysym.scancode = keycode;
726 keysym.sym = X11_TranslateKeycode(SDL_Display, keycode);
727 keysym.mod = KMOD_NONE;
728 keysym.unicode = 0;
729 if ( XLookupString(&xevent.xkey,
730 keybuf, sizeof(keybuf),
731 NULL, &state) ) {
732 /*
733 * FIXME: XLookupString() may yield more than one
734 * character, so we need a mechanism to allow for
735 * this (perhaps null keypress events with a
736 * unicode value)
737 */
738 keysym.unicode = (Uint8)keybuf[0];
739 }
740
741 posted = SDL_PrivateKeyboard(SDL_PRESSED, &keysym);
742 }
743 }
744 break;
745
746 /* Key release? */
747 case KeyRelease: {
748 SDL_keysym keysym;
749 KeyCode keycode = xevent.xkey.keycode;
750
751 if (keycode == 0) {
752 /* There should be no KeyRelease for keycode == 0,
753 since it is a notification from IM but a real
754 keystroke. */
755 /* We need to emit some diagnostic message here. */
756 break;
757 }
758
759 #ifdef DEBUG_XEVENTS
760 printf("KeyRelease (X11 keycode = 0x%X)\n", xevent.xkey.keycode);
761 #endif
762
763 /* Get the translated SDL virtual keysym */
764 keysym.scancode = keycode;
765 keysym.sym = X11_TranslateKeycode(SDL_Display, keycode);
766 keysym.mod = KMOD_NONE;
767 keysym.unicode = 0;
768
769 posted = SDL_PrivateKeyboard(SDL_RELEASED, &keysym);
770 }
771 break;
772
773 /* Have we been iconified? */
774 case UnmapNotify: {
775 #ifdef DEBUG_XEVENTS
776 printf("UnmapNotify!\n");
777 #endif
778 /* If we're active, make ourselves inactive */
779 if ( SDL_GetAppState() & SDL_APPACTIVE ) {
780 /* Swap out the gamma before we go inactive */
781 X11_SwapVidModeGamma(this);
782
783 /* Send an internal deactivate event */
784 posted = SDL_PrivateAppActive(0,
785 SDL_APPACTIVE|SDL_APPINPUTFOCUS);
786 }
787 }
788 break;
789
790 /* Have we been restored? */
791 case MapNotify: {
792 #ifdef DEBUG_XEVENTS
793 printf("MapNotify!\n");
794 #endif
795 /* If we're not active, make ourselves active */
796 if ( !(SDL_GetAppState() & SDL_APPACTIVE) ) {
797 /* Send an internal activate event */
798 posted = SDL_PrivateAppActive(1, SDL_APPACTIVE);
799
800 /* Now that we're active, swap the gamma back */
801 X11_SwapVidModeGamma(this);
802 }
803
804 if ( SDL_VideoSurface &&
805 (SDL_VideoSurface->flags & SDL_FULLSCREEN) ) {
806 X11_EnterFullScreen(this);
807 } else {
808 X11_GrabInputNoLock(this, this->input_grab);
809 }
810 X11_CheckMouseModeNoLock(this);
811
812 if ( SDL_VideoSurface ) {
813 X11_RefreshDisplay(this);
814 }
815 }
816 break;
817
818 /* Have we been resized or moved? */
819 case ConfigureNotify: {
820 #ifdef DEBUG_XEVENTS
821 printf("ConfigureNotify! (resize: %dx%d)\n", xevent.xconfigure.width, xevent.xconfigure.height);
822 #endif
823 if ( SDL_VideoSurface ) {
824 if ((xevent.xconfigure.width != SDL_VideoSurface->w) ||
825 (xevent.xconfigure.height != SDL_VideoSurface->h)) {
826 /* FIXME: Find a better fix for the bug with KDE 1.2 */
827 if ( ! ((xevent.xconfigure.width == 32) &&
828 (xevent.xconfigure.height == 32)) ) {
829 SDL_PrivateResize(xevent.xconfigure.width,
830 xevent.xconfigure.height);
831 }
832 } else {
833 /* OpenGL windows need to know about the change */
834 if ( SDL_VideoSurface->flags & SDL_OPENGL ) {
835 SDL_PrivateExpose();
836 }
837 }
838 }
839 }
840 break;
841
842 /* Have we been requested to quit (or another client message?) */
843 case ClientMessage: {
844 if ( (xevent.xclient.format == 32) &&
845 (xevent.xclient.data.l[0] == WM_DELETE_WINDOW) )
846 {
847 posted = SDL_PrivateQuit();
848 } else
849 if ( SDL_ProcessEvents[SDL_SYSWMEVENT] == SDL_ENABLE ) {
850 SDL_SysWMmsg wmmsg;
851
852 SDL_VERSION(&wmmsg.version);
853 wmmsg.subsystem = SDL_SYSWM_X11;
854 wmmsg.event.xevent = xevent;
855 posted = SDL_PrivateSysWMEvent(&wmmsg);
856 }
857 }
858 break;
859
860 /* Do we need to refresh ourselves? */
861 case Expose: {
862 #ifdef DEBUG_XEVENTS
863 printf("Expose (count = %d)\n", xevent.xexpose.count);
864 #endif
865 if ( SDL_VideoSurface && (xevent.xexpose.count == 0) ) {
866 X11_RefreshDisplay(this);
867 }
868 }
869 break;
870
871 default: {
872 #ifdef DEBUG_XEVENTS
873 printf("Unhandled event %d\n", xevent.type);
874 #endif
875 /* Only post the event if we're watching for it */
876 if ( SDL_ProcessEvents[SDL_SYSWMEVENT] == SDL_ENABLE ) {
877 SDL_SysWMmsg wmmsg;
878
879 SDL_VERSION(&wmmsg.version);
880 wmmsg.subsystem = SDL_SYSWM_X11;
881 wmmsg.event.xevent = xevent;
882 posted = SDL_PrivateSysWMEvent(&wmmsg);
883 }
884 }
885 break;
886 }
887 return(posted);
888 }
889
890 /* Ack! XPending() actually performs a blocking read if no events available */
X11_Pending(Display * display)891 int X11_Pending(Display *display)
892 {
893 /* Flush the display connection and look to see if events are queued */
894 XFlush(display);
895 if ( XEventsQueued(display, QueuedAlready) ) {
896 return(1);
897 }
898
899 /* More drastic measures are required -- see if X is ready to talk */
900 {
901 static struct timeval zero_time; /* static == 0 */
902 int x11_fd;
903 fd_set fdset;
904
905 x11_fd = ConnectionNumber(display);
906 FD_ZERO(&fdset);
907 FD_SET(x11_fd, &fdset);
908 if ( select(x11_fd+1, &fdset, NULL, NULL, &zero_time) == 1 ) {
909 return(XPending(display));
910 }
911 }
912
913 /* Oh well, nothing is ready .. */
914 return(0);
915 }
916
X11_PumpEvents(_THIS)917 void X11_PumpEvents(_THIS)
918 {
919 int pending;
920
921 /* Keep processing pending events */
922 pending = 0;
923 while ( X11_Pending(SDL_Display) ) {
924 X11_DispatchEvent(this);
925 ++pending;
926 }
927 if ( switch_waiting ) {
928 Uint32 now;
929
930 now = SDL_GetTicks();
931 if ( pending || !SDL_VideoSurface ) {
932 /* Try again later... */
933 if ( switch_waiting & SDL_FULLSCREEN ) {
934 switch_time = now + 1500;
935 } else {
936 switch_time = now + 200;
937 }
938 } else if ( (int)(switch_time-now) <= 0 ) {
939 Uint32 go_fullscreen;
940
941 go_fullscreen = switch_waiting & SDL_FULLSCREEN;
942 switch_waiting = 0;
943 if ( SDL_VideoSurface->flags & SDL_FULLSCREEN ) {
944 if ( go_fullscreen ) {
945 X11_EnterFullScreen(this);
946 } else {
947 X11_LeaveFullScreen(this);
948 }
949 }
950 /* Handle focus in/out when grabbed */
951 if ( go_fullscreen ) {
952 X11_GrabInputNoLock(this, this->input_grab);
953 } else {
954 X11_GrabInputNoLock(this, SDL_GRAB_OFF);
955 }
956 X11_CheckMouseModeNoLock(this);
957 }
958 }
959 }
960
X11_InitKeymap(void)961 void X11_InitKeymap(void)
962 {
963 int i;
964
965 /* Odd keys used in international keyboards */
966 for ( i=0; i<SDL_arraysize(ODD_keymap); ++i )
967 ODD_keymap[i] = SDLK_UNKNOWN;
968
969 /* Some of these might be mappable to an existing SDLK_ code */
970 ODD_keymap[XK_dead_grave&0xFF] = SDLK_COMPOSE;
971 ODD_keymap[XK_dead_acute&0xFF] = SDLK_COMPOSE;
972 ODD_keymap[XK_dead_tilde&0xFF] = SDLK_COMPOSE;
973 ODD_keymap[XK_dead_macron&0xFF] = SDLK_COMPOSE;
974 ODD_keymap[XK_dead_breve&0xFF] = SDLK_COMPOSE;
975 ODD_keymap[XK_dead_abovedot&0xFF] = SDLK_COMPOSE;
976 ODD_keymap[XK_dead_diaeresis&0xFF] = SDLK_COMPOSE;
977 ODD_keymap[XK_dead_abovering&0xFF] = SDLK_COMPOSE;
978 ODD_keymap[XK_dead_doubleacute&0xFF] = SDLK_COMPOSE;
979 ODD_keymap[XK_dead_caron&0xFF] = SDLK_COMPOSE;
980 ODD_keymap[XK_dead_cedilla&0xFF] = SDLK_COMPOSE;
981 ODD_keymap[XK_dead_ogonek&0xFF] = SDLK_COMPOSE;
982 ODD_keymap[XK_dead_iota&0xFF] = SDLK_COMPOSE;
983 ODD_keymap[XK_dead_voiced_sound&0xFF] = SDLK_COMPOSE;
984 ODD_keymap[XK_dead_semivoiced_sound&0xFF] = SDLK_COMPOSE;
985 ODD_keymap[XK_dead_belowdot&0xFF] = SDLK_COMPOSE;
986 #ifdef XK_dead_hook
987 ODD_keymap[XK_dead_hook&0xFF] = SDLK_COMPOSE;
988 #endif
989 #ifdef XK_dead_horn
990 ODD_keymap[XK_dead_horn&0xFF] = SDLK_COMPOSE;
991 #endif
992
993 #ifdef XK_dead_circumflex
994 /* These X keysyms have 0xFE as the high byte */
995 ODD_keymap[XK_dead_circumflex&0xFF] = SDLK_CARET;
996 #endif
997 #ifdef XK_ISO_Level3_Shift
998 ODD_keymap[XK_ISO_Level3_Shift&0xFF] = SDLK_MODE; /* "Alt Gr" key */
999 #endif
1000
1001 /* Map the miscellaneous keys */
1002 for ( i=0; i<SDL_arraysize(MISC_keymap); ++i )
1003 MISC_keymap[i] = SDLK_UNKNOWN;
1004
1005 /* These X keysyms have 0xFF as the high byte */
1006 MISC_keymap[XK_BackSpace&0xFF] = SDLK_BACKSPACE;
1007 MISC_keymap[XK_Tab&0xFF] = SDLK_TAB;
1008 MISC_keymap[XK_Clear&0xFF] = SDLK_CLEAR;
1009 MISC_keymap[XK_Return&0xFF] = SDLK_RETURN;
1010 MISC_keymap[XK_Pause&0xFF] = SDLK_PAUSE;
1011 MISC_keymap[XK_Escape&0xFF] = SDLK_ESCAPE;
1012 MISC_keymap[XK_Delete&0xFF] = SDLK_DELETE;
1013
1014 MISC_keymap[XK_KP_0&0xFF] = SDLK_KP0; /* Keypad 0-9 */
1015 MISC_keymap[XK_KP_1&0xFF] = SDLK_KP1;
1016 MISC_keymap[XK_KP_2&0xFF] = SDLK_KP2;
1017 MISC_keymap[XK_KP_3&0xFF] = SDLK_KP3;
1018 MISC_keymap[XK_KP_4&0xFF] = SDLK_KP4;
1019 MISC_keymap[XK_KP_5&0xFF] = SDLK_KP5;
1020 MISC_keymap[XK_KP_6&0xFF] = SDLK_KP6;
1021 MISC_keymap[XK_KP_7&0xFF] = SDLK_KP7;
1022 MISC_keymap[XK_KP_8&0xFF] = SDLK_KP8;
1023 MISC_keymap[XK_KP_9&0xFF] = SDLK_KP9;
1024 MISC_keymap[XK_KP_Insert&0xFF] = SDLK_KP0;
1025 MISC_keymap[XK_KP_End&0xFF] = SDLK_KP1;
1026 MISC_keymap[XK_KP_Down&0xFF] = SDLK_KP2;
1027 MISC_keymap[XK_KP_Page_Down&0xFF] = SDLK_KP3;
1028 MISC_keymap[XK_KP_Left&0xFF] = SDLK_KP4;
1029 MISC_keymap[XK_KP_Begin&0xFF] = SDLK_KP5;
1030 MISC_keymap[XK_KP_Right&0xFF] = SDLK_KP6;
1031 MISC_keymap[XK_KP_Home&0xFF] = SDLK_KP7;
1032 MISC_keymap[XK_KP_Up&0xFF] = SDLK_KP8;
1033 MISC_keymap[XK_KP_Page_Up&0xFF] = SDLK_KP9;
1034 MISC_keymap[XK_KP_Delete&0xFF] = SDLK_KP_PERIOD;
1035 MISC_keymap[XK_KP_Decimal&0xFF] = SDLK_KP_PERIOD;
1036 MISC_keymap[XK_KP_Divide&0xFF] = SDLK_KP_DIVIDE;
1037 MISC_keymap[XK_KP_Multiply&0xFF] = SDLK_KP_MULTIPLY;
1038 MISC_keymap[XK_KP_Subtract&0xFF] = SDLK_KP_MINUS;
1039 MISC_keymap[XK_KP_Add&0xFF] = SDLK_KP_PLUS;
1040 MISC_keymap[XK_KP_Enter&0xFF] = SDLK_KP_ENTER;
1041 MISC_keymap[XK_KP_Equal&0xFF] = SDLK_KP_EQUALS;
1042
1043 MISC_keymap[XK_Up&0xFF] = SDLK_UP;
1044 MISC_keymap[XK_Down&0xFF] = SDLK_DOWN;
1045 MISC_keymap[XK_Right&0xFF] = SDLK_RIGHT;
1046 MISC_keymap[XK_Left&0xFF] = SDLK_LEFT;
1047 MISC_keymap[XK_Insert&0xFF] = SDLK_INSERT;
1048 MISC_keymap[XK_Home&0xFF] = SDLK_HOME;
1049 MISC_keymap[XK_End&0xFF] = SDLK_END;
1050 MISC_keymap[XK_Page_Up&0xFF] = SDLK_PAGEUP;
1051 MISC_keymap[XK_Page_Down&0xFF] = SDLK_PAGEDOWN;
1052
1053 MISC_keymap[XK_F1&0xFF] = SDLK_F1;
1054 MISC_keymap[XK_F2&0xFF] = SDLK_F2;
1055 MISC_keymap[XK_F3&0xFF] = SDLK_F3;
1056 MISC_keymap[XK_F4&0xFF] = SDLK_F4;
1057 MISC_keymap[XK_F5&0xFF] = SDLK_F5;
1058 MISC_keymap[XK_F6&0xFF] = SDLK_F6;
1059 MISC_keymap[XK_F7&0xFF] = SDLK_F7;
1060 MISC_keymap[XK_F8&0xFF] = SDLK_F8;
1061 MISC_keymap[XK_F9&0xFF] = SDLK_F9;
1062 MISC_keymap[XK_F10&0xFF] = SDLK_F10;
1063 MISC_keymap[XK_F11&0xFF] = SDLK_F11;
1064 MISC_keymap[XK_F12&0xFF] = SDLK_F12;
1065 MISC_keymap[XK_F13&0xFF] = SDLK_F13;
1066 MISC_keymap[XK_F14&0xFF] = SDLK_F14;
1067 MISC_keymap[XK_F15&0xFF] = SDLK_F15;
1068
1069 MISC_keymap[XK_Num_Lock&0xFF] = SDLK_NUMLOCK;
1070 MISC_keymap[XK_Caps_Lock&0xFF] = SDLK_CAPSLOCK;
1071 MISC_keymap[XK_Scroll_Lock&0xFF] = SDLK_SCROLLOCK;
1072 MISC_keymap[XK_Shift_R&0xFF] = SDLK_RSHIFT;
1073 MISC_keymap[XK_Shift_L&0xFF] = SDLK_LSHIFT;
1074 MISC_keymap[XK_Control_R&0xFF] = SDLK_RCTRL;
1075 MISC_keymap[XK_Control_L&0xFF] = SDLK_LCTRL;
1076 MISC_keymap[XK_Alt_R&0xFF] = SDLK_RALT;
1077 MISC_keymap[XK_Alt_L&0xFF] = SDLK_LALT;
1078 MISC_keymap[XK_Meta_R&0xFF] = SDLK_RMETA;
1079 MISC_keymap[XK_Meta_L&0xFF] = SDLK_LMETA;
1080 MISC_keymap[XK_Super_L&0xFF] = SDLK_LSUPER; /* Left "Windows" */
1081 MISC_keymap[XK_Super_R&0xFF] = SDLK_RSUPER; /* Right "Windows */
1082 MISC_keymap[XK_Mode_switch&0xFF] = SDLK_MODE; /* "Alt Gr" key */
1083 MISC_keymap[XK_Multi_key&0xFF] = SDLK_COMPOSE; /* Multi-key compose */
1084
1085 MISC_keymap[XK_Help&0xFF] = SDLK_HELP;
1086 MISC_keymap[XK_Print&0xFF] = SDLK_PRINT;
1087 MISC_keymap[XK_Sys_Req&0xFF] = SDLK_SYSREQ;
1088 MISC_keymap[XK_Break&0xFF] = SDLK_BREAK;
1089 MISC_keymap[XK_Menu&0xFF] = SDLK_MENU;
1090 MISC_keymap[XK_Hyper_R&0xFF] = SDLK_MENU; /* Windows "Menu" key */
1091 }
1092
1093 /* Get the translated SDL virtual keysym */
X11_TranslateKeycode(Display * display,KeyCode kc)1094 SDLKey X11_TranslateKeycode(Display *display, KeyCode kc)
1095 {
1096 KeySym xsym;
1097 SDLKey key;
1098
1099 xsym = XKeycodeToKeysym(display, kc, 0);
1100 #ifdef DEBUG_KEYS
1101 fprintf(stderr, "Translating key code %d -> 0x%.4x\n", kc, xsym);
1102 #endif
1103 key = SDLK_UNKNOWN;
1104 if ( xsym ) {
1105 switch (xsym>>8) {
1106 case 0x1005FF:
1107 #ifdef SunXK_F36
1108 if ( xsym == SunXK_F36 )
1109 key = SDLK_F11;
1110 #endif
1111 #ifdef SunXK_F37
1112 if ( xsym == SunXK_F37 )
1113 key = SDLK_F12;
1114 #endif
1115 break;
1116 case 0x00: /* Latin 1 */
1117 key = (SDLKey)(xsym & 0xFF);
1118 break;
1119 case 0x01: /* Latin 2 */
1120 case 0x02: /* Latin 3 */
1121 case 0x03: /* Latin 4 */
1122 case 0x04: /* Katakana */
1123 case 0x05: /* Arabic */
1124 case 0x06: /* Cyrillic */
1125 case 0x07: /* Greek */
1126 case 0x08: /* Technical */
1127 case 0x0A: /* Publishing */
1128 case 0x0C: /* Hebrew */
1129 case 0x0D: /* Thai */
1130 /* These are wrong, but it's better than nothing */
1131 key = (SDLKey)(xsym & 0xFF);
1132 break;
1133 case 0xFE:
1134 key = ODD_keymap[xsym&0xFF];
1135 break;
1136 case 0xFF:
1137 key = MISC_keymap[xsym&0xFF];
1138 break;
1139 default:
1140 /*
1141 fprintf(stderr, "X11: Unhandled xsym, sym = 0x%04x\n",
1142 (unsigned int)xsym);
1143 */
1144 break;
1145 }
1146 } else {
1147 /* X11 doesn't know how to translate the key! */
1148 switch (kc) {
1149 /* Caution:
1150 These keycodes are from the Microsoft Keyboard
1151 */
1152 case 115:
1153 key = SDLK_LSUPER;
1154 break;
1155 case 116:
1156 key = SDLK_RSUPER;
1157 break;
1158 case 117:
1159 key = SDLK_MENU;
1160 break;
1161 default:
1162 /*
1163 * no point in an error message; happens for
1164 * several keys when we get a keymap notify
1165 */
1166 break;
1167 }
1168 }
1169 return key;
1170 }
1171
1172 /* X11 modifier masks for various keys */
1173 static unsigned meta_l_mask, meta_r_mask, alt_l_mask, alt_r_mask;
1174 static unsigned num_mask, mode_switch_mask;
1175
get_modifier_masks(Display * display)1176 static void get_modifier_masks(Display *display)
1177 {
1178 static unsigned got_masks;
1179 int i, j;
1180 XModifierKeymap *xmods;
1181 unsigned n;
1182
1183 if(got_masks)
1184 return;
1185
1186 xmods = XGetModifierMapping(display);
1187 n = xmods->max_keypermod;
1188 for(i = 3; i < 8; i++) {
1189 for(j = 0; j < n; j++) {
1190 KeyCode kc = xmods->modifiermap[i * n + j];
1191 KeySym ks = XKeycodeToKeysym(display, kc, 0);
1192 unsigned mask = 1 << i;
1193 switch(ks) {
1194 case XK_Num_Lock:
1195 num_mask = mask; break;
1196 case XK_Alt_L:
1197 alt_l_mask = mask; break;
1198 case XK_Alt_R:
1199 alt_r_mask = mask; break;
1200 case XK_Meta_L:
1201 meta_l_mask = mask; break;
1202 case XK_Meta_R:
1203 meta_r_mask = mask; break;
1204 case XK_Mode_switch:
1205 mode_switch_mask = mask; break;
1206 }
1207 }
1208 }
1209 XFreeModifiermap(xmods);
1210 got_masks = 1;
1211 }
1212
1213
1214 /*
1215 * This function is semi-official; it is not officially exported and should
1216 * not be considered part of the SDL API, but may be used by client code
1217 * that *really* needs it (including legacy code).
1218 * It is slow, though, and should be avoided if possible.
1219 *
1220 * Note that it isn't completely accurate either; in particular, multi-key
1221 * sequences (dead accents, compose key sequences) will not work since the
1222 * state has been irrevocably lost.
1223 */
X11_KeyToUnicode(SDLKey keysym,SDLMod modifiers)1224 Uint16 X11_KeyToUnicode(SDLKey keysym, SDLMod modifiers)
1225 {
1226 struct SDL_VideoDevice *this = current_video;
1227 char keybuf[32];
1228 int i;
1229 KeySym xsym = 0;
1230 XKeyEvent xkey;
1231 Uint16 unicode;
1232
1233 if ( !this || !SDL_Display ) {
1234 return 0;
1235 }
1236
1237 SDL_memset(&xkey, 0, sizeof(xkey));
1238 xkey.display = SDL_Display;
1239
1240 xsym = keysym; /* last resort if not found */
1241 for (i = 0; i < 256; ++i) {
1242 if ( MISC_keymap[i] == keysym ) {
1243 xsym = 0xFF00 | i;
1244 break;
1245 } else if ( ODD_keymap[i] == keysym ) {
1246 xsym = 0xFE00 | i;
1247 break;
1248 }
1249 }
1250
1251 xkey.keycode = XKeysymToKeycode(xkey.display, xsym);
1252
1253 get_modifier_masks(SDL_Display);
1254 if(modifiers & KMOD_SHIFT)
1255 xkey.state |= ShiftMask;
1256 if(modifiers & KMOD_CAPS)
1257 xkey.state |= LockMask;
1258 if(modifiers & KMOD_CTRL)
1259 xkey.state |= ControlMask;
1260 if(modifiers & KMOD_MODE)
1261 xkey.state |= mode_switch_mask;
1262 if(modifiers & KMOD_LALT)
1263 xkey.state |= alt_l_mask;
1264 if(modifiers & KMOD_RALT)
1265 xkey.state |= alt_r_mask;
1266 if(modifiers & KMOD_LMETA)
1267 xkey.state |= meta_l_mask;
1268 if(modifiers & KMOD_RMETA)
1269 xkey.state |= meta_r_mask;
1270 if(modifiers & KMOD_NUM)
1271 xkey.state |= num_mask;
1272
1273 unicode = 0;
1274 if ( XLookupString(&xkey, keybuf, sizeof(keybuf), NULL, NULL) )
1275 unicode = (unsigned char)keybuf[0];
1276 return(unicode);
1277 }
1278
1279
1280 /*
1281 * Called when focus is regained, to read the keyboard state and generate
1282 * synthetic keypress/release events.
1283 * key_vec is a bit vector of keycodes (256 bits)
1284 */
X11_SetKeyboardState(Display * display,const char * key_vec)1285 void X11_SetKeyboardState(Display *display, const char *key_vec)
1286 {
1287 char keys_return[32];
1288 int i;
1289 Uint8 *kstate = SDL_GetKeyState(NULL);
1290 SDLMod modstate;
1291 Window junk_window;
1292 int x, y;
1293 unsigned int mask;
1294
1295 /* The first time the window is mapped, we initialize key state */
1296 if ( ! key_vec ) {
1297 XQueryKeymap(display, keys_return);
1298 key_vec = keys_return;
1299 }
1300
1301 /* Get the keyboard modifier state */
1302 modstate = 0;
1303 get_modifier_masks(display);
1304 if ( XQueryPointer(display, DefaultRootWindow(display),
1305 &junk_window, &junk_window, &x, &y, &x, &y, &mask) ) {
1306 if ( mask & LockMask ) {
1307 modstate |= KMOD_CAPS;
1308 }
1309 if ( mask & mode_switch_mask ) {
1310 modstate |= KMOD_MODE;
1311 }
1312 if ( mask & num_mask ) {
1313 modstate |= KMOD_NUM;
1314 }
1315 }
1316
1317 /* Zero the new keyboard state and generate it */
1318 SDL_memset(kstate, 0, SDLK_LAST);
1319 /*
1320 * An obvious optimisation is to check entire longwords at a time in
1321 * both loops, but we can't be sure the arrays are aligned so it's not
1322 * worth the extra complexity
1323 */
1324 for ( i = 0; i < 32; i++ ) {
1325 int j;
1326 if ( !key_vec[i] )
1327 continue;
1328 for ( j = 0; j < 8; j++ ) {
1329 if ( key_vec[i] & (1 << j) ) {
1330 SDLKey key;
1331 KeyCode kc = (i << 3 | j);
1332 key = X11_TranslateKeycode(display, kc);
1333 if ( key == SDLK_UNKNOWN ) {
1334 continue;
1335 }
1336 kstate[key] = SDL_PRESSED;
1337 switch (key) {
1338 case SDLK_LSHIFT:
1339 modstate |= KMOD_LSHIFT;
1340 break;
1341 case SDLK_RSHIFT:
1342 modstate |= KMOD_RSHIFT;
1343 break;
1344 case SDLK_LCTRL:
1345 modstate |= KMOD_LCTRL;
1346 break;
1347 case SDLK_RCTRL:
1348 modstate |= KMOD_RCTRL;
1349 break;
1350 case SDLK_LALT:
1351 modstate |= KMOD_LALT;
1352 break;
1353 case SDLK_RALT:
1354 modstate |= KMOD_RALT;
1355 break;
1356 case SDLK_LMETA:
1357 modstate |= KMOD_LMETA;
1358 break;
1359 case SDLK_RMETA:
1360 modstate |= KMOD_RMETA;
1361 break;
1362 default:
1363 break;
1364 }
1365 }
1366 }
1367 }
1368
1369 /* Hack - set toggle key state */
1370 if ( modstate & KMOD_CAPS ) {
1371 kstate[SDLK_CAPSLOCK] = SDL_PRESSED;
1372 } else {
1373 kstate[SDLK_CAPSLOCK] = SDL_RELEASED;
1374 }
1375 if ( modstate & KMOD_NUM ) {
1376 kstate[SDLK_NUMLOCK] = SDL_PRESSED;
1377 } else {
1378 kstate[SDLK_NUMLOCK] = SDL_RELEASED;
1379 }
1380
1381 /* Set the final modifier state */
1382 SDL_SetModState(modstate);
1383 }
1384
X11_InitOSKeymap(_THIS)1385 void X11_InitOSKeymap(_THIS)
1386 {
1387 X11_InitKeymap();
1388 }
1389
X11_SaveScreenSaver(Display * display,int * saved_timeout,BOOL * dpms)1390 void X11_SaveScreenSaver(Display *display, int *saved_timeout, BOOL *dpms)
1391 {
1392 int timeout, interval, prefer_blank, allow_exp;
1393 XGetScreenSaver(display, &timeout, &interval, &prefer_blank, &allow_exp);
1394 *saved_timeout = timeout;
1395
1396 #if SDL_VIDEO_DRIVER_X11_DPMS
1397 if ( SDL_X11_HAVE_DPMS ) {
1398 int dummy;
1399 if ( DPMSQueryExtension(display, &dummy, &dummy) ) {
1400 CARD16 state;
1401 DPMSInfo(display, &state, dpms);
1402 }
1403 }
1404 #else
1405 *dpms = 0;
1406 #endif /* SDL_VIDEO_DRIVER_X11_DPMS */
1407 }
1408
X11_DisableScreenSaver(_THIS,Display * display)1409 void X11_DisableScreenSaver(_THIS, Display *display)
1410 {
1411 int timeout, interval, prefer_blank, allow_exp;
1412
1413 if (this->hidden->allow_screensaver) {
1414 return;
1415 }
1416
1417 XGetScreenSaver(display, &timeout, &interval, &prefer_blank, &allow_exp);
1418 timeout = 0;
1419 XSetScreenSaver(display, timeout, interval, prefer_blank, allow_exp);
1420
1421 #if SDL_VIDEO_DRIVER_X11_DPMS
1422 if ( SDL_X11_HAVE_DPMS ) {
1423 int dummy;
1424 if ( DPMSQueryExtension(display, &dummy, &dummy) ) {
1425 DPMSDisable(display);
1426 }
1427 }
1428 #endif /* SDL_VIDEO_DRIVER_X11_DPMS */
1429 }
1430
X11_RestoreScreenSaver(_THIS,Display * display,int saved_timeout,BOOL dpms)1431 void X11_RestoreScreenSaver(_THIS, Display *display, int saved_timeout, BOOL dpms)
1432 {
1433 int timeout, interval, prefer_blank, allow_exp;
1434
1435 if (this->hidden->allow_screensaver) {
1436 return;
1437 }
1438
1439 XGetScreenSaver(display, &timeout, &interval, &prefer_blank, &allow_exp);
1440 timeout = saved_timeout;
1441 XSetScreenSaver(display, timeout, interval, prefer_blank, allow_exp);
1442
1443 #if SDL_VIDEO_DRIVER_X11_DPMS
1444 if ( SDL_X11_HAVE_DPMS ) {
1445 int dummy;
1446 if ( DPMSQueryExtension(display, &dummy, &dummy) ) {
1447 if ( dpms ) {
1448 DPMSEnable(display);
1449 }
1450 }
1451 }
1452 #endif /* SDL_VIDEO_DRIVER_X11_DPMS */
1453 }
1454