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