diff options
Diffstat (limited to 'apps/plugins/sdl/src/video/x11/SDL_x11events.c')
-rw-r--r-- | apps/plugins/sdl/src/video/x11/SDL_x11events.c | 1414 |
1 files changed, 1414 insertions, 0 deletions
diff --git a/apps/plugins/sdl/src/video/x11/SDL_x11events.c b/apps/plugins/sdl/src/video/x11/SDL_x11events.c new file mode 100644 index 0000000000..559a001486 --- /dev/null +++ b/apps/plugins/sdl/src/video/x11/SDL_x11events.c | |||
@@ -0,0 +1,1414 @@ | |||
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 | ||
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 | |||
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 | */ | ||
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 | |||
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 | |||
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 */ | ||
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 | |||
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 | |||
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 */ | ||
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 | |||
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 | */ | ||
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 | */ | ||
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 | |||
1410 | void X11_InitOSKeymap(_THIS) | ||
1411 | { | ||
1412 | X11_InitKeymap(); | ||
1413 | } | ||
1414 | |||