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 */
56static SDLKey ODD_keymap[256];
57static SDLKey MISC_keymap[256];
58SDLKey X11_TranslateKeycode(Display *display, KeyCode kc);
59
60
61#ifdef X_HAVE_UTF8_STRING
62Uint32 Utf8ToUcs4(const Uint8 *utf8)
63{
64	Uint32 c;
65	int i = 1;
66	int noOctets = 0;
67	int firstOctetMask = 0;
68	unsigned char firstOctet = utf8[0];
69	if (firstOctet < 0x80) {
70		/*
71		  Characters in the range:
72		    00000000 to 01111111 (ASCII Range)
73		  are stored in one octet:
74		    0xxxxxxx (The same as its ASCII representation)
75		  The least 6 significant bits of the first octet is the most 6 significant nonzero bits
76		  of the UCS4 representation.
77		*/
78		noOctets = 1;
79		firstOctetMask = 0x7F;  /* 0(1111111) - The most significant bit is ignored */
80	} else if ((firstOctet & 0xE0) /* get the most 3 significant bits by AND'ing with 11100000 */
81	              == 0xC0 ) {  /* see if those 3 bits are 110. If so, the char is in this range */
82		/*
83		  Characters in the range:
84		    00000000 10000000 to 00000111 11111111
85		  are stored in two octets:
86		    110xxxxx 10xxxxxx
87		  The least 5 significant bits of the first octet is the most 5 significant nonzero bits
88		  of the UCS4 representation.
89		*/
90		noOctets = 2;
91		firstOctetMask = 0x1F;  /* 000(11111) - The most 3 significant bits are ignored */
92	} else if ((firstOctet & 0xF0) /* get the most 4 significant bits by AND'ing with 11110000 */
93	              == 0xE0) {  /* see if those 4 bits are 1110. If so, the char is in this range */
94		/*
95		  Characters in the range:
96		    00001000 00000000 to 11111111 11111111
97		  are stored in three octets:
98		    1110xxxx 10xxxxxx 10xxxxxx
99		  The least 4 significant bits of the first octet is the most 4 significant nonzero bits
100		  of the UCS4 representation.
101		*/
102		noOctets = 3;
103		firstOctetMask = 0x0F; /* 0000(1111) - The most 4 significant bits are ignored */
104	} else if ((firstOctet & 0xF8) /* get the most 5 significant bits by AND'ing with 11111000 */
105	              == 0xF0) {  /* see if those 5 bits are 11110. If so, the char is in this range */
106		/*
107		  Characters in the range:
108		    00000001 00000000 00000000 to 00011111 11111111 11111111
109		  are stored in four octets:
110		    11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
111		  The least 3 significant bits of the first octet is the most 3 significant nonzero bits
112		  of the UCS4 representation.
113		*/
114		noOctets = 4;
115		firstOctetMask = 0x07; /* 11110(111) - The most 5 significant bits are ignored */
116	} else if ((firstOctet & 0xFC) /* get the most 6 significant bits by AND'ing with 11111100 */
117	              == 0xF8) { /* see if those 6 bits are 111110. If so, the char is in this range */
118		/*
119		  Characters in the range:
120		    00000000 00100000 00000000 00000000 to
121		    00000011 11111111 11111111 11111111
122		  are stored in five octets:
123		    111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
124		  The least 2 significant bits of the first octet is the most 2 significant nonzero bits
125		  of the UCS4 representation.
126		*/
127		noOctets = 5;
128		firstOctetMask = 0x03; /* 111110(11) - The most 6 significant bits are ignored */
129	} else if ((firstOctet & 0xFE) /* get the most 7 significant bits by AND'ing with 11111110 */
130	              == 0xFC) { /* see if those 7 bits are 1111110. If so, the char is in this range */
131		/*
132		  Characters in the range:
133		    00000100 00000000 00000000 00000000 to
134		    01111111 11111111 11111111 11111111
135		  are stored in six octets:
136		    1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
137		  The least significant bit of the first octet is the most significant nonzero bit
138		  of the UCS4 representation.
139		*/
140		noOctets = 6;
141		firstOctetMask = 0x01; /* 1111110(1) - The most 7 significant bits are ignored */
142	} else
143		return 0;  /* The given chunk is not a valid UTF-8 encoded Unicode character */
144
145	/*
146	  The least noOctets significant bits of the first octet is the most 2 significant nonzero bits
147	  of the UCS4 representation.
148	  The first 6 bits of the UCS4 representation is the least 8-noOctets-1 significant bits of
149	  firstOctet if the character is not ASCII. If so, it's the least 7 significant bits of firstOctet.
150	  This done by AND'ing firstOctet with its mask to trim the bits used for identifying the
151	  number of continuing octets (if any) and leave only the free bits (the x's)
152	  Sample:
153	  1-octet:    0xxxxxxx  &  01111111 = 0xxxxxxx
154	  2-octets:  110xxxxx  &  00011111 = 000xxxxx
155	*/
156	c = firstOctet & firstOctetMask;
157
158	/* Now, start filling c.ucs4 with the bits from the continuing octets from utf8. */
159	for (i = 1; i < noOctets; i++) {
160		/* A valid continuing octet is of the form 10xxxxxx */
161		if ((utf8[i] & 0xC0) /* get the most 2 significant bits by AND'ing with 11000000 */
162		    != 0x80) /* see if those 2 bits are 10. If not, the is a malformed sequence. */
163			/*The given chunk is a partial sequence at the end of a string that could
164			   begin a valid character */
165			return 0;
166
167		/* Make room for the next 6-bits */
168		c <<= 6;
169
170		/*
171		  Take only the least 6 significance bits of the current octet (utf8[i]) and fill the created room
172		  of c.ucs4 with them.
173		  This done by AND'ing utf8[i] with 00111111 and the OR'ing the result with c.ucs4.
174		*/
175		c |= utf8[i] & 0x3F;
176	}
177	return c;
178}
179
180/* Given a UTF-8 encoded string pointed to by utf8 of length length in
181   bytes, returns the corresponding UTF-16 encoded string in the
182   buffer pointed to by utf16.  The maximum number of UTF-16 encoding
183   units (i.e., Unit16s) allowed in the buffer is specified in
184   utf16_max_length.  The return value is the number of UTF-16
185   encoding units placed in the output buffer pointed to by utf16.
186
187   In case of an error, -1 is returned, leaving some unusable partial
188   results in the output buffer.
189
190   The caller must estimate the size of utf16 buffer by itself before
191   calling this function.  Insufficient output buffer is considered as
192   an error, and once an error occured, this function doesn't give any
193   clue how large the result will be.
194
195   The error cases include following:
196
197   - Invalid byte sequences were in the input UTF-8 bytes.  The caller
198     has no way to know what point in the input buffer was the
199     errornous byte.
200
201   - The input contained a character (a valid UTF-8 byte sequence)
202     whose scalar value exceeded the range that UTF-16 can represent
203     (i.e., characters whose Unicode scalar value above 0x110000).
204
205   - The output buffer has no enough space to hold entire utf16 data.
206
207   Please note:
208
209   - '\0'-termination is not assumed both on the input UTF-8 string
210     and on the output UTF-16 string; any legal zero byte in the input
211     UTF-8 string will be converted to a 16-bit zero in output.  As a
212     side effect, the last UTF-16 encoding unit stored in the output
213     buffer will have a non-zero value if the input UTF-8 was not
214     '\0'-terminated.
215
216   - UTF-8 aliases are *not* considered as an error.  They are
217     converted to UTF-16.  For example, 0xC0 0xA0, 0xE0 0x80 0xA0,
218     and 0xF0 0x80 0x80 0xA0 are all mapped to a single UTF-16
219     encoding unit 0x0020.
220
221   - Three byte UTF-8 sequences whose value corresponds to a surrogate
222     code or other reserved scalar value are not considered as an
223     error either.  They may cause an invalid UTF-16 data (e.g., those
224     containing unpaired surrogates).
225
226*/
227
228static int Utf8ToUtf16(const Uint8 *utf8, const int utf8_length, Uint16 *utf16, const int utf16_max_length) {
229
230    /* p moves over the output buffer.  max_ptr points to the next to the last slot of the buffer.  */
231    Uint16 *p = utf16;
232    Uint16 const *const max_ptr = utf16 + utf16_max_length;
233
234    /* end_of_input points to the last byte of input as opposed to the next to the last byte.  */
235    Uint8 const *const end_of_input = utf8 + utf8_length - 1;
236
237    while (utf8 <= end_of_input) {
238	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 */
302static int X11_KeyRepeat(Display *display, XEvent *event)
303{
304	XEvent peekevent;
305	int repeated;
306
307	repeated = 0;
308	if ( XPending(display) ) {
309		XPeekEvent(display, &peekevent);
310		if ( (peekevent.type == KeyPress) &&
311		     (peekevent.xkey.keycode == event->xkey.keycode) &&
312		     ((peekevent.xkey.time-event->xkey.time) < 2) ) {
313			repeated = 1;
314			XNextEvent(display, &peekevent);
315		}
316	}
317	return(repeated);
318}
319
320/* Note:  The X server buffers and accumulates mouse motion events, so
321   the motion event generated by the warp may not appear exactly as we
322   expect it to.  We work around this (and improve performance) by only
323   warping the pointer when it reaches the edge, and then wait for it.
324*/
325#define MOUSE_FUDGE_FACTOR	8
326
327static __inline__ int X11_WarpedMotion(_THIS, XEvent *xevent)
328{
329	int w, h, i;
330	int deltax, deltay;
331	int posted;
332
333	w = SDL_VideoSurface->w;
334	h = SDL_VideoSurface->h;
335	deltax = xevent->xmotion.x - mouse_last.x;
336	deltay = xevent->xmotion.y - mouse_last.y;
337#ifdef DEBUG_MOTION
338  printf("Warped mouse motion: %d,%d\n", deltax, deltay);
339#endif
340	mouse_last.x = xevent->xmotion.x;
341	mouse_last.y = xevent->xmotion.y;
342	posted = SDL_PrivateMouseMotion(0, 1, deltax, deltay);
343
344	if ( (xevent->xmotion.x < MOUSE_FUDGE_FACTOR) ||
345	     (xevent->xmotion.x > (w-MOUSE_FUDGE_FACTOR)) ||
346	     (xevent->xmotion.y < MOUSE_FUDGE_FACTOR) ||
347	     (xevent->xmotion.y > (h-MOUSE_FUDGE_FACTOR)) ) {
348		/* Get the events that have accumulated */
349		while ( XCheckTypedEvent(SDL_Display, MotionNotify, xevent) ) {
350			deltax = xevent->xmotion.x - mouse_last.x;
351			deltay = xevent->xmotion.y - mouse_last.y;
352#ifdef DEBUG_MOTION
353  printf("Extra mouse motion: %d,%d\n", deltax, deltay);
354#endif
355			mouse_last.x = xevent->xmotion.x;
356			mouse_last.y = xevent->xmotion.y;
357			posted += SDL_PrivateMouseMotion(0, 1, deltax, deltay);
358		}
359		mouse_last.x = w/2;
360		mouse_last.y = h/2;
361		XWarpPointer(SDL_Display, None, SDL_Window, 0, 0, 0, 0,
362					mouse_last.x, mouse_last.y);
363		for ( i=0; i<10; ++i ) {
364        		XMaskEvent(SDL_Display, PointerMotionMask, xevent);
365			if ( (xevent->xmotion.x >
366			          (mouse_last.x-MOUSE_FUDGE_FACTOR)) &&
367			     (xevent->xmotion.x <
368			          (mouse_last.x+MOUSE_FUDGE_FACTOR)) &&
369			     (xevent->xmotion.y >
370			          (mouse_last.y-MOUSE_FUDGE_FACTOR)) &&
371			     (xevent->xmotion.y <
372			          (mouse_last.y+MOUSE_FUDGE_FACTOR)) ) {
373				break;
374			}
375#ifdef DEBUG_XEVENTS
376  printf("Lost mouse motion: %d,%d\n", xevent->xmotion.x, xevent->xmotion.y);
377#endif
378		}
379#ifdef DEBUG_XEVENTS
380		if ( i == 10 ) {
381			printf("Warning: didn't detect mouse warp motion\n");
382		}
383#endif
384	}
385	return(posted);
386}
387
388static int X11_DispatchEvent(_THIS)
389{
390	int posted;
391	XEvent xevent;
392
393	SDL_memset(&xevent, '\0', sizeof (XEvent));  /* valgrind fix. --ryan. */
394	XNextEvent(SDL_Display, &xevent);
395
396	/* Discard KeyRelease and KeyPress events generated by auto-repeat.
397	   We need to do it before passing event to XFilterEvent.  Otherwise,
398	   KeyRelease aware IMs are confused...  */
399	if ( xevent.type == KeyRelease
400	     && X11_KeyRepeat(SDL_Display, &xevent) ) {
401		return 0;
402	}
403
404#ifdef X_HAVE_UTF8_STRING
405	/* If we are translating with IM, we need to pass all events
406	   to XFilterEvent, and discard those filtered events immediately.  */
407	if ( SDL_TranslateUNICODE
408	     && SDL_IM != NULL
409	     && XFilterEvent(&xevent, None) ) {
410		return 0;
411	}
412#endif
413
414	posted = 0;
415	switch (xevent.type) {
416
417	    /* Gaining mouse coverage? */
418	    case EnterNotify: {
419#ifdef DEBUG_XEVENTS
420printf("EnterNotify! (%d,%d)\n", xevent.xcrossing.x, xevent.xcrossing.y);
421if ( xevent.xcrossing.mode == NotifyGrab )
422printf("Mode: NotifyGrab\n");
423if ( xevent.xcrossing.mode == NotifyUngrab )
424printf("Mode: NotifyUngrab\n");
425#endif
426		if ( (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
441printf("LeaveNotify! (%d,%d)\n", xevent.xcrossing.x, xevent.xcrossing.y);
442if ( xevent.xcrossing.mode == NotifyGrab )
443printf("Mode: NotifyGrab\n");
444if ( xevent.xcrossing.mode == NotifyUngrab )
445printf("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
464printf("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
482printf("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
507printf("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
559printf("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
760printf("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
776printf("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
793printf("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
821printf("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
863printf("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
873printf("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 */
891int 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
917void 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
961void 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 */
1094SDLKey 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 */
1173static unsigned meta_l_mask, meta_r_mask, alt_l_mask, alt_r_mask;
1174static unsigned num_mask, mode_switch_mask;
1175
1176static 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 */
1224Uint16 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 */
1285void 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
1385void X11_InitOSKeymap(_THIS)
1386{
1387	X11_InitKeymap();
1388}
1389
1390void 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
1409void 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
1431void 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