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