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