SDL-1.2.14
[sdl_omap.git] / src / video / x11 / SDL_x11events.c
CommitLineData
e14743d1 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 */
56static SDLKey ODD_keymap[256];
57static SDLKey MISC_keymap[256];
58SDLKey X11_TranslateKeycode(Display *display, KeyCode kc);
59
60
61#ifdef X_HAVE_UTF8_STRING
62Uint32 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
228static 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 */
302static 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
327static __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
388static 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
420printf("EnterNotify! (%d,%d)\n", xevent.xcrossing.x, xevent.xcrossing.y);
421if ( xevent.xcrossing.mode == NotifyGrab )
422printf("Mode: NotifyGrab\n");
423if ( xevent.xcrossing.mode == NotifyUngrab )
424printf("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
438printf("LeaveNotify! (%d,%d)\n", xevent.xcrossing.x, xevent.xcrossing.y);
439if ( xevent.xcrossing.mode == NotifyGrab )
440printf("Mode: NotifyGrab\n");
441if ( xevent.xcrossing.mode == NotifyUngrab )
442printf("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
459printf("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
477printf("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
504printf("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
556printf("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
757printf("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
773printf("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
790printf("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
818printf("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
860printf("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
870printf("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 */
888int 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
914void 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
968void 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 */
1101SDLKey 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 */
1180static unsigned meta_l_mask, meta_r_mask, alt_l_mask, alt_r_mask;
1181static unsigned num_mask, mode_switch_mask;
1182
1183static 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 */
1231Uint16 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 */
1292void 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
1392void X11_InitOSKeymap(_THIS)
1393{
1394 X11_InitKeymap();
1395}
1396