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