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