src/video/x11/SDL_x11events.c
author Sam Lantinga <slouken@libsdl.org>
Sat, 04 Feb 2006 08:35:11 +0000
changeset 1327 d12a63a8d95a
parent 1312 c9b51268668f
child 1328 27ddb06a0bca
permissions -rw-r--r--
Resolved bug #130
Use XFilterEvent() to handle dead-key composition under X11
Cleaned up the code in preparation for 1.3 API changes
     1 /*
     2     SDL - Simple DirectMedia Layer
     3     Copyright (C) 1997-2006 Sam Lantinga
     4 
     5     This library is free software; you can redistribute it and/or
     6     modify it under the terms of the GNU Lesser General Public
     7     License as published by the Free Software Foundation; either
     8     version 2.1 of the License, or (at your option) any later version.
     9 
    10     This library is distributed in the hope that it will be useful,
    11     but WITHOUT ANY WARRANTY; without even the implied warranty of
    12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    13     Lesser General Public License for more details.
    14 
    15     You should have received a copy of the GNU Lesser General Public
    16     License along with this library; if not, write to the Free Software
    17     Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
    18 
    19     Sam Lantinga
    20     slouken@libsdl.org
    21 */
    22 
    23 /* Handle the event stream, converting X11 events into SDL events */
    24 
    25 #include <stdio.h>
    26 #include <stdlib.h>
    27 #include <string.h>
    28 #include <setjmp.h>
    29 #include <X11/Xlib.h>
    30 #include <X11/Xutil.h>
    31 #include <X11/keysym.h>
    32 #ifdef __SVR4
    33 #include <X11/Sunkeysym.h>
    34 #endif
    35 #include <sys/types.h>
    36 #include <sys/time.h>
    37 #include <unistd.h>
    38 
    39 #include "SDL.h"
    40 #include "SDL_syswm.h"
    41 #include "SDL_sysevents.h"
    42 #include "SDL_sysvideo.h"
    43 #include "SDL_events_c.h"
    44 #include "SDL_x11video.h"
    45 #include "SDL_x11dga_c.h"
    46 #include "SDL_x11modes_c.h"
    47 #include "SDL_x11image_c.h"
    48 #include "SDL_x11gamma_c.h"
    49 #include "SDL_x11wm_c.h"
    50 #include "SDL_x11mouse_c.h"
    51 #include "SDL_x11events_c.h"
    52 
    53 
    54 /* Define this if you want to debug X11 events */
    55 /*#define DEBUG_XEVENTS*/
    56 
    57 /* The translation tables from an X11 keysym to a SDL keysym */
    58 static SDLKey ODD_keymap[256];
    59 static SDLKey MISC_keymap[256];
    60 SDLKey X11_TranslateKeycode(Display *display, KeyCode kc);
    61 
    62 
    63 #ifdef X_HAVE_UTF8_STRING
    64 Uint32 Utf8ToUcs4(const Uint8 *utf8)
    65 {
    66 	Uint32 c;
    67 	int i = 1;
    68 	int noOctets = 0;
    69 	int firstOctetMask = 0;
    70 	unsigned char firstOctet = utf8[0];
    71 	if (firstOctet < 0x80) {
    72 		/*
    73 		  Characters in the range:
    74 		    00000000 to 01111111 (ASCII Range)
    75 		  are stored in one octet:
    76 		    0xxxxxxx (The same as its ASCII representation)
    77 		  The least 6 significant bits of the first octet is the most 6 significant nonzero bits
    78 		  of the UCS4 representation.
    79 		*/
    80 		noOctets = 1;
    81 		firstOctetMask = 0x7F;  /* 0(1111111) - The most significant bit is ignored */
    82 	} else if ((firstOctet & 0xE0) /* get the most 3 significant bits by AND'ing with 11100000 */
    83 	              == 0xC0 ) {  /* see if those 3 bits are 110. If so, the char is in this range */
    84 		/*
    85 		  Characters in the range:
    86 		    00000000 10000000 to 00000111 11111111
    87 		  are stored in two octets:
    88 		    110xxxxx 10xxxxxx
    89 		  The least 5 significant bits of the first octet is the most 5 significant nonzero bits
    90 		  of the UCS4 representation.
    91 		*/
    92 		noOctets = 2;
    93 		firstOctetMask = 0x1F;  /* 000(11111) - The most 3 significant bits are ignored */
    94 	} else if ((firstOctet & 0xF0) /* get the most 4 significant bits by AND'ing with 11110000 */
    95 	              == 0xE0) {  /* see if those 4 bits are 1110. If so, the char is in this range */
    96 		/*
    97 		  Characters in the range:
    98 		    00001000 00000000 to 11111111 11111111
    99 		  are stored in three octets:
   100 		    1110xxxx 10xxxxxx 10xxxxxx
   101 		  The least 4 significant bits of the first octet is the most 4 significant nonzero bits
   102 		  of the UCS4 representation.
   103 		*/
   104 		noOctets = 3;
   105 		firstOctetMask = 0x0F; /* 0000(1111) - The most 4 significant bits are ignored */
   106 	} else if ((firstOctet & 0xF8) /* get the most 5 significant bits by AND'ing with 11111000 */
   107 	              == 0xF0) {  /* see if those 5 bits are 11110. If so, the char is in this range */
   108 		/*
   109 		  Characters in the range:
   110 		    00000001 00000000 00000000 to 00011111 11111111 11111111
   111 		  are stored in four octets:
   112 		    11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
   113 		  The least 3 significant bits of the first octet is the most 3 significant nonzero bits
   114 		  of the UCS4 representation.
   115 		*/
   116 		noOctets = 4;
   117 		firstOctetMask = 0x07; /* 11110(111) - The most 5 significant bits are ignored */
   118 	} else if ((firstOctet & 0xFC) /* get the most 6 significant bits by AND'ing with 11111100 */
   119 	              == 0xF8) { /* see if those 6 bits are 111110. If so, the char is in this range */
   120 		/*
   121 		  Characters in the range:
   122 		    00000000 00100000 00000000 00000000 to
   123 		    00000011 11111111 11111111 11111111
   124 		  are stored in five octets:
   125 		    111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
   126 		  The least 2 significant bits of the first octet is the most 2 significant nonzero bits
   127 		  of the UCS4 representation.
   128 		*/
   129 		noOctets = 5;
   130 		firstOctetMask = 0x03; /* 111110(11) - The most 6 significant bits are ignored */
   131 	} else if ((firstOctet & 0xFE) /* get the most 7 significant bits by AND'ing with 11111110 */
   132 	              == 0xFC) { /* see if those 7 bits are 1111110. If so, the char is in this range */
   133 		/*
   134 		  Characters in the range:
   135 		    00000100 00000000 00000000 00000000 to
   136 		    01111111 11111111 11111111 11111111
   137 		  are stored in six octets:
   138 		    1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
   139 		  The least significant bit of the first octet is the most significant nonzero bit
   140 		  of the UCS4 representation.
   141 		*/
   142 		noOctets = 6;
   143 		firstOctetMask = 0x01; /* 1111110(1) - The most 7 significant bits are ignored */
   144 	} else
   145 		return 0;  /* The given chunk is not a valid UTF-8 encoded Unicode character */
   146 	
   147 	/*
   148 	  The least noOctets significant bits of the first octet is the most 2 significant nonzero bits
   149 	  of the UCS4 representation.
   150 	  The first 6 bits of the UCS4 representation is the least 8-noOctets-1 significant bits of
   151 	  firstOctet if the character is not ASCII. If so, it's the least 7 significant bits of firstOctet.
   152 	  This done by AND'ing firstOctet with its mask to trim the bits used for identifying the
   153 	  number of continuing octets (if any) and leave only the free bits (the x's)
   154 	  Sample:
   155 	  1-octet:    0xxxxxxx  &  01111111 = 0xxxxxxx
   156 	  2-octets:  110xxxxx  &  00011111 = 000xxxxx
   157 	*/
   158 	c = firstOctet & firstOctetMask;
   159 	
   160 	/* Now, start filling c.ucs4 with the bits from the continuing octets from utf8. */
   161 	for (i = 1; i < noOctets; i++) {
   162 		/* A valid continuing octet is of the form 10xxxxxx */
   163 		if ((utf8[i] & 0xC0) /* get the most 2 significant bits by AND'ing with 11000000 */
   164 		    != 0x80) /* see if those 2 bits are 10. If not, the is a malformed sequence. */
   165 			/*The given chunk is a partial sequence at the end of a string that could
   166 			   begin a valid character */
   167 			return 0;
   168 		
   169 		/* Make room for the next 6-bits */
   170 		c <<= 6;
   171 		
   172 		/*
   173 		  Take only the least 6 significance bits of the current octet (utf8[i]) and fill the created room
   174 		  of c.ucs4 with them.
   175 		  This done by AND'ing utf8[i] with 00111111 and the OR'ing the result with c.ucs4.
   176 		*/
   177 		c |= utf8[i] & 0x3F;
   178 	}
   179 	return c;
   180 }
   181 #endif
   182 
   183 /* Check to see if this is a repeated key.
   184    (idea shamelessly lifted from GII -- thanks guys! :)
   185  */
   186 static int X11_KeyRepeat(Display *display, XEvent *event)
   187 {
   188 	XEvent peekevent;
   189 	int repeated;
   190 
   191 	repeated = 0;
   192 	if ( pXPending(display) ) {
   193 		pXPeekEvent(display, &peekevent);
   194 		if ( (peekevent.type == KeyPress) &&
   195 		     (peekevent.xkey.keycode == event->xkey.keycode) &&
   196 		     ((peekevent.xkey.time-event->xkey.time) < 2) ) {
   197 			repeated = 1;
   198 			pXNextEvent(display, &peekevent);
   199 		}
   200 	}
   201 	return(repeated);
   202 }
   203 
   204 /* Note:  The X server buffers and accumulates mouse motion events, so
   205    the motion event generated by the warp may not appear exactly as we
   206    expect it to.  We work around this (and improve performance) by only
   207    warping the pointer when it reaches the edge, and then wait for it.
   208 */
   209 #define MOUSE_FUDGE_FACTOR	8
   210 
   211 static __inline__ int X11_WarpedMotion(_THIS, XEvent *xevent)
   212 {
   213 	int w, h, i;
   214 	int deltax, deltay;
   215 	int posted;
   216 
   217 	w = SDL_VideoSurface->w;
   218 	h = SDL_VideoSurface->h;
   219 	deltax = xevent->xmotion.x - mouse_last.x;
   220 	deltay = xevent->xmotion.y - mouse_last.y;
   221 #ifdef DEBUG_MOTION
   222   printf("Warped mouse motion: %d,%d\n", deltax, deltay);
   223 #endif
   224 	mouse_last.x = xevent->xmotion.x;
   225 	mouse_last.y = xevent->xmotion.y;
   226 	posted = SDL_PrivateMouseMotion(0, 1, deltax, deltay);
   227 
   228 	if ( (xevent->xmotion.x < MOUSE_FUDGE_FACTOR) ||
   229 	     (xevent->xmotion.x > (w-MOUSE_FUDGE_FACTOR)) ||
   230 	     (xevent->xmotion.y < MOUSE_FUDGE_FACTOR) ||
   231 	     (xevent->xmotion.y > (h-MOUSE_FUDGE_FACTOR)) ) {
   232 		/* Get the events that have accumulated */
   233 		while ( pXCheckTypedEvent(SDL_Display, MotionNotify, xevent) ) {
   234 			deltax = xevent->xmotion.x - mouse_last.x;
   235 			deltay = xevent->xmotion.y - mouse_last.y;
   236 #ifdef DEBUG_MOTION
   237   printf("Extra mouse motion: %d,%d\n", deltax, deltay);
   238 #endif
   239 			mouse_last.x = xevent->xmotion.x;
   240 			mouse_last.y = xevent->xmotion.y;
   241 			posted += SDL_PrivateMouseMotion(0, 1, deltax, deltay);
   242 		}
   243 		mouse_last.x = w/2;
   244 		mouse_last.y = h/2;
   245 		pXWarpPointer(SDL_Display, None, SDL_Window, 0, 0, 0, 0,
   246 					mouse_last.x, mouse_last.y);
   247 		for ( i=0; i<10; ++i ) {
   248         		pXMaskEvent(SDL_Display, PointerMotionMask, xevent);
   249 			if ( (xevent->xmotion.x >
   250 			          (mouse_last.x-MOUSE_FUDGE_FACTOR)) &&
   251 			     (xevent->xmotion.x <
   252 			          (mouse_last.x+MOUSE_FUDGE_FACTOR)) &&
   253 			     (xevent->xmotion.y >
   254 			          (mouse_last.y-MOUSE_FUDGE_FACTOR)) &&
   255 			     (xevent->xmotion.y <
   256 			          (mouse_last.y+MOUSE_FUDGE_FACTOR)) ) {
   257 				break;
   258 			}
   259 #ifdef DEBUG_XEVENTS
   260   printf("Lost mouse motion: %d,%d\n", xevent->xmotion.x, xevent->xmotion.y);
   261 #endif
   262 		}
   263 #ifdef DEBUG_XEVENTS
   264 		if ( i == 10 ) {
   265 			printf("Warning: didn't detect mouse warp motion\n");
   266 		}
   267 #endif
   268 	}
   269 	return(posted);
   270 }
   271 
   272 static int X11_DispatchEvent(_THIS)
   273 {
   274 	int posted;
   275 	XEvent xevent;
   276 
   277 	memset(&xevent, '\0', sizeof (XEvent));  /* valgrind fix. --ryan. */
   278 	pXNextEvent(SDL_Display, &xevent);
   279 
   280 	posted = 0;
   281 	switch (xevent.type) {
   282 
   283 	    /* Gaining mouse coverage? */
   284 	    case EnterNotify: {
   285 #ifdef DEBUG_XEVENTS
   286 printf("EnterNotify! (%d,%d)\n", xevent.xcrossing.x, xevent.xcrossing.y);
   287 if ( xevent.xcrossing.mode == NotifyGrab )
   288 printf("Mode: NotifyGrab\n");
   289 if ( xevent.xcrossing.mode == NotifyUngrab )
   290 printf("Mode: NotifyUngrab\n");
   291 #endif
   292 		if ( (xevent.xcrossing.mode != NotifyGrab) &&
   293 		     (xevent.xcrossing.mode != NotifyUngrab) ) {
   294 			if ( this->input_grab == SDL_GRAB_OFF ) {
   295 				posted = SDL_PrivateAppActive(1, SDL_APPMOUSEFOCUS);
   296 			} else {
   297 				posted = SDL_PrivateMouseMotion(0, 0,
   298 						xevent.xcrossing.x,
   299 						xevent.xcrossing.y);
   300 			}
   301 		}
   302 	    }
   303 	    break;
   304 
   305 	    /* Losing mouse coverage? */
   306 	    case LeaveNotify: {
   307 #ifdef DEBUG_XEVENTS
   308 printf("LeaveNotify! (%d,%d)\n", xevent.xcrossing.x, xevent.xcrossing.y);
   309 if ( xevent.xcrossing.mode == NotifyGrab )
   310 printf("Mode: NotifyGrab\n");
   311 if ( xevent.xcrossing.mode == NotifyUngrab )
   312 printf("Mode: NotifyUngrab\n");
   313 #endif
   314 		if ( (xevent.xcrossing.mode != NotifyGrab) &&
   315 		     (xevent.xcrossing.mode != NotifyUngrab) &&
   316 		     (xevent.xcrossing.detail != NotifyInferior) ) {
   317 			if ( this->input_grab == SDL_GRAB_OFF ) {
   318 				posted = SDL_PrivateAppActive(0, SDL_APPMOUSEFOCUS);
   319 			} else {
   320 				posted = SDL_PrivateMouseMotion(0, 0,
   321 						xevent.xcrossing.x,
   322 						xevent.xcrossing.y);
   323 			}
   324 		}
   325 	    }
   326 	    break;
   327 
   328 	    /* Gaining input focus? */
   329 	    case FocusIn: {
   330 #ifdef DEBUG_XEVENTS
   331 printf("FocusIn!\n");
   332 #endif
   333 		posted = SDL_PrivateAppActive(1, SDL_APPINPUTFOCUS);
   334 
   335 		if ( SDL_IC != NULL ) {
   336 			pXSetICFocus(SDL_IC);
   337 		}
   338 
   339 		/* Queue entry into fullscreen mode */
   340 		switch_waiting = 0x01 | SDL_FULLSCREEN;
   341 		switch_time = SDL_GetTicks() + 1500;
   342 	    }
   343 	    break;
   344 
   345 	    /* Losing input focus? */
   346 	    case FocusOut: {
   347 #ifdef DEBUG_XEVENTS
   348 printf("FocusOut!\n");
   349 #endif
   350 		posted = SDL_PrivateAppActive(0, SDL_APPINPUTFOCUS);
   351 
   352 		if ( SDL_IC != NULL ) {
   353 			pXUnsetICFocus(SDL_IC);
   354 		}
   355 
   356 		/* Queue leaving fullscreen mode */
   357 		switch_waiting = 0x01;
   358 		switch_time = SDL_GetTicks() + 200;
   359 	    }
   360 	    break;
   361 
   362 	    /* Generated upon EnterWindow and FocusIn */
   363 	    case KeymapNotify: {
   364 #ifdef DEBUG_XEVENTS
   365 printf("KeymapNotify!\n");
   366 #endif
   367 		X11_SetKeyboardState(SDL_Display,  xevent.xkeymap.key_vector);
   368 	    }
   369 	    break;
   370 
   371 	    /* Mouse motion? */
   372 	    case MotionNotify: {
   373 		if ( SDL_VideoSurface ) {
   374 			if ( mouse_relative ) {
   375 				if ( using_dga & DGA_MOUSE ) {
   376 #ifdef DEBUG_MOTION
   377   printf("DGA motion: %d,%d\n", xevent.xmotion.x_root, xevent.xmotion.y_root);
   378 #endif
   379 					posted = SDL_PrivateMouseMotion(0, 1,
   380 							xevent.xmotion.x_root,
   381 							xevent.xmotion.y_root);
   382 				} else {
   383 					posted = X11_WarpedMotion(this,&xevent);
   384 				}
   385 			} else {
   386 #ifdef DEBUG_MOTION
   387   printf("X11 motion: %d,%d\n", xevent.xmotion.x, xevent.xmotion.y);
   388 #endif
   389 				posted = SDL_PrivateMouseMotion(0, 0,
   390 						xevent.xmotion.x,
   391 						xevent.xmotion.y);
   392 			}
   393 		}
   394 	    }
   395 	    break;
   396 
   397 	    /* Mouse button press? */
   398 	    case ButtonPress: {
   399 		posted = SDL_PrivateMouseButton(SDL_PRESSED, 
   400 					xevent.xbutton.button, 0, 0);
   401 	    }
   402 	    break;
   403 
   404 	    /* Mouse button release? */
   405 	    case ButtonRelease: {
   406 		posted = SDL_PrivateMouseButton(SDL_RELEASED, 
   407 					xevent.xbutton.button, 0, 0);
   408 	    }
   409 	    break;
   410 
   411 	    /* Key press? */
   412 	    case KeyPress: {
   413 		static SDL_keysym saved_keysym;
   414 		SDL_keysym keysym;
   415 		KeyCode keycode = xevent.xkey.keycode;
   416 
   417 #ifdef DEBUG_XEVENTS
   418 printf("KeyPress (X11 keycode = 0x%X)\n", xevent.xkey.keycode);
   419 #endif
   420 		/* Get the translated SDL virtual keysym */
   421 		if ( keycode ) {
   422 			keysym.scancode = keycode;
   423 			keysym.sym = X11_TranslateKeycode(SDL_Display, keycode);
   424 			keysym.mod = KMOD_NONE;
   425 			keysym.unicode = 0;
   426 		} else {
   427 			keysym = saved_keysym;
   428 		}
   429 
   430 		/* If we're not doing translation, we're done! */
   431 		if ( !SDL_TranslateUNICODE ) {
   432 			posted = SDL_PrivateKeyboard(SDL_PRESSED, &keysym);
   433 			break;
   434 		}
   435 
   436 		if ( pXFilterEvent(&xevent, None) ) {
   437 			if ( xevent.xkey.keycode ) {
   438 				posted = SDL_PrivateKeyboard(SDL_PRESSED, &keysym);
   439 			} else {
   440 				/* Save event to be associated with IM text
   441 				   In 1.3 we'll have a text event instead.. */
   442 				saved_keysym = keysym;
   443 			}
   444 			break;
   445 		}
   446 
   447 		/* Look up the translated value for the key event */
   448 #ifdef X_HAVE_UTF8_STRING
   449 		if ( SDL_IC != NULL ) {
   450 			static Status state;
   451 			/* A UTF-8 character can be at most 6 bytes */
   452 			char keybuf[6];
   453 			if ( pXutf8LookupString(SDL_IC, &xevent.xkey,
   454 			                        keybuf, sizeof(keybuf),
   455 			                        NULL, &state) ) {
   456 				keysym.unicode = Utf8ToUcs4((Uint8*)keybuf);
   457 			}
   458 		}
   459 		else
   460 #endif
   461 		{
   462 			static XComposeStatus state;
   463 			char keybuf[32];
   464 
   465 			if ( pXLookupString(&xevent.xkey,
   466 			                    keybuf, sizeof(keybuf),
   467 			                    NULL, &state) ) {
   468 				/*
   469 				* FIXME: XLookupString() may yield more than one
   470 				* character, so we need a mechanism to allow for
   471 				* this (perhaps null keypress events with a
   472 				* unicode value)
   473 				*/
   474 				keysym.unicode = (Uint8)keybuf[0];
   475 			}
   476 		}
   477 		posted = SDL_PrivateKeyboard(SDL_PRESSED, &keysym);
   478 	    }
   479 	    break;
   480 
   481 	    /* Key release? */
   482 	    case KeyRelease: {
   483 		SDL_keysym keysym;
   484 		KeyCode keycode = xevent.xkey.keycode;
   485 
   486 #ifdef DEBUG_XEVENTS
   487 printf("KeyRelease (X11 keycode = 0x%X)\n", xevent.xkey.keycode);
   488 #endif
   489 		/* Check to see if this is a repeated key */
   490 		if ( X11_KeyRepeat(SDL_Display, &xevent) ) {
   491 			break;
   492 		}
   493 
   494 		/* Get the translated SDL virtual keysym */
   495 		keysym.scancode = keycode;
   496 		keysym.sym = X11_TranslateKeycode(SDL_Display, keycode);
   497 		keysym.mod = KMOD_NONE;
   498 		keysym.unicode = 0;
   499 
   500 		posted = SDL_PrivateKeyboard(SDL_RELEASED, &keysym);
   501 	    }
   502 	    break;
   503 
   504 	    /* Have we been iconified? */
   505 	    case UnmapNotify: {
   506 #ifdef DEBUG_XEVENTS
   507 printf("UnmapNotify!\n");
   508 #endif
   509 		/* If we're active, make ourselves inactive */
   510 		if ( SDL_GetAppState() & SDL_APPACTIVE ) {
   511 			/* Swap out the gamma before we go inactive */
   512 			X11_SwapVidModeGamma(this);
   513 
   514 			/* Send an internal deactivate event */
   515 			posted = SDL_PrivateAppActive(0,
   516 					SDL_APPACTIVE|SDL_APPINPUTFOCUS);
   517 		}
   518 	    }
   519 	    break;
   520 
   521 	    /* Have we been restored? */
   522 	    case MapNotify: {
   523 #ifdef DEBUG_XEVENTS
   524 printf("MapNotify!\n");
   525 #endif
   526 		/* If we're not active, make ourselves active */
   527 		if ( !(SDL_GetAppState() & SDL_APPACTIVE) ) {
   528 			/* Send an internal activate event */
   529 			posted = SDL_PrivateAppActive(1, SDL_APPACTIVE);
   530 
   531 			/* Now that we're active, swap the gamma back */
   532 			X11_SwapVidModeGamma(this);
   533 		}
   534 
   535 		if ( SDL_VideoSurface &&
   536 		     (SDL_VideoSurface->flags & SDL_FULLSCREEN) ) {
   537 			X11_EnterFullScreen(this);
   538 		} else {
   539 			X11_GrabInputNoLock(this, this->input_grab);
   540 		}
   541 		X11_CheckMouseModeNoLock(this);
   542 
   543 		if ( SDL_VideoSurface ) {
   544 			X11_RefreshDisplay(this);
   545 		}
   546 	    }
   547 	    break;
   548 
   549 	    /* Have we been resized or moved? */
   550 	    case ConfigureNotify: {
   551 #ifdef DEBUG_XEVENTS
   552 printf("ConfigureNotify! (resize: %dx%d)\n", xevent.xconfigure.width, xevent.xconfigure.height);
   553 #endif
   554 		if ( SDL_VideoSurface ) {
   555 		    if ((xevent.xconfigure.width != SDL_VideoSurface->w) ||
   556 		        (xevent.xconfigure.height != SDL_VideoSurface->h)) {
   557 			/* FIXME: Find a better fix for the bug with KDE 1.2 */
   558 			if ( ! ((xevent.xconfigure.width == 32) &&
   559 			        (xevent.xconfigure.height == 32)) ) {
   560 				SDL_PrivateResize(xevent.xconfigure.width,
   561 				                  xevent.xconfigure.height);
   562 			}
   563 		    } else {
   564 			/* OpenGL windows need to know about the change */
   565 			if ( SDL_VideoSurface->flags & SDL_OPENGL ) {
   566 				SDL_PrivateExpose();
   567 			}
   568 		    }
   569 		}
   570 	    }
   571 	    break;
   572 
   573 	    /* Have we been requested to quit (or another client message?) */
   574 	    case ClientMessage: {
   575 		if ( (xevent.xclient.format == 32) &&
   576 		     (xevent.xclient.data.l[0] == WM_DELETE_WINDOW) )
   577 		{
   578 			posted = SDL_PrivateQuit();
   579 		} else
   580 		if ( SDL_ProcessEvents[SDL_SYSWMEVENT] == SDL_ENABLE ) {
   581 			SDL_SysWMmsg wmmsg;
   582 
   583 			SDL_VERSION(&wmmsg.version);
   584 			wmmsg.subsystem = SDL_SYSWM_X11;
   585 			wmmsg.event.xevent = xevent;
   586 			posted = SDL_PrivateSysWMEvent(&wmmsg);
   587 		}
   588 	    }
   589 	    break;
   590 
   591 	    /* Do we need to refresh ourselves? */
   592 	    case Expose: {
   593 #ifdef DEBUG_XEVENTS
   594 printf("Expose (count = %d)\n", xevent.xexpose.count);
   595 #endif
   596 		if ( SDL_VideoSurface && (xevent.xexpose.count == 0) ) {
   597 			X11_RefreshDisplay(this);
   598 		}
   599 	    }
   600 	    break;
   601 
   602 	    default: {
   603 #ifdef DEBUG_XEVENTS
   604 printf("Unhandled event %d\n", xevent.type);
   605 #endif
   606 		/* Only post the event if we're watching for it */
   607 		if ( SDL_ProcessEvents[SDL_SYSWMEVENT] == SDL_ENABLE ) {
   608 			SDL_SysWMmsg wmmsg;
   609 
   610 			SDL_VERSION(&wmmsg.version);
   611 			wmmsg.subsystem = SDL_SYSWM_X11;
   612 			wmmsg.event.xevent = xevent;
   613 			posted = SDL_PrivateSysWMEvent(&wmmsg);
   614 		}
   615 	    }
   616 	    break;
   617 	}
   618 	return(posted);
   619 }
   620 
   621 /* Ack!  XPending() actually performs a blocking read if no events available */
   622 int X11_Pending(Display *display)
   623 {
   624 	/* Flush the display connection and look to see if events are queued */
   625 	pXFlush(display);
   626 	if ( pXEventsQueued(display, QueuedAlready) ) {
   627 		return(1);
   628 	}
   629 
   630 	/* More drastic measures are required -- see if X is ready to talk */
   631 	{
   632 		static struct timeval zero_time;	/* static == 0 */
   633 		int x11_fd;
   634 		fd_set fdset;
   635 
   636 		x11_fd = ConnectionNumber(display);
   637 		FD_ZERO(&fdset);
   638 		FD_SET(x11_fd, &fdset);
   639 		if ( select(x11_fd+1, &fdset, NULL, NULL, &zero_time) == 1 ) {
   640 			return(pXPending(display));
   641 		}
   642 	}
   643 
   644 	/* Oh well, nothing is ready .. */
   645 	return(0);
   646 }
   647 
   648 void X11_PumpEvents(_THIS)
   649 {
   650 	int pending;
   651 
   652 	/* Keep processing pending events */
   653 	pending = 0;
   654 	while ( X11_Pending(SDL_Display) ) {
   655 		X11_DispatchEvent(this);
   656 		++pending;
   657 	}
   658 	if ( switch_waiting ) {
   659 		Uint32 now;
   660 
   661 		now  = SDL_GetTicks();
   662 		if ( pending || !SDL_VideoSurface ) {
   663 			/* Try again later... */
   664 			if ( switch_waiting & SDL_FULLSCREEN ) {
   665 				switch_time = now + 1500;
   666 			} else {
   667 				switch_time = now + 200;
   668 			}
   669 		} else if ( now >= switch_time ) {
   670 			Uint32 go_fullscreen;
   671 
   672 			go_fullscreen = switch_waiting & SDL_FULLSCREEN;
   673 			switch_waiting = 0;
   674 			if ( SDL_VideoSurface->flags & SDL_FULLSCREEN ) {
   675 				if ( go_fullscreen ) {
   676 					X11_EnterFullScreen(this);
   677 				} else {
   678 					X11_LeaveFullScreen(this);
   679 				}
   680 			}
   681 			/* Handle focus in/out when grabbed */
   682 			if ( go_fullscreen ) {
   683 				X11_GrabInputNoLock(this, this->input_grab);
   684 			} else {
   685 				X11_GrabInputNoLock(this, SDL_GRAB_OFF);
   686 			}
   687 			X11_CheckMouseModeNoLock(this);
   688 		}
   689 	}
   690 }
   691 
   692 void X11_InitKeymap(void)
   693 {
   694 	int i;
   695 
   696 	/* Odd keys used in international keyboards */
   697 	for ( i=0; i<SDL_TABLESIZE(ODD_keymap); ++i )
   698 		ODD_keymap[i] = SDLK_UNKNOWN;
   699 
   700  	/* Some of these might be mappable to an existing SDLK_ code */
   701  	ODD_keymap[XK_dead_grave&0xFF] = SDLK_COMPOSE;
   702  	ODD_keymap[XK_dead_acute&0xFF] = SDLK_COMPOSE;
   703  	ODD_keymap[XK_dead_tilde&0xFF] = SDLK_COMPOSE;
   704  	ODD_keymap[XK_dead_macron&0xFF] = SDLK_COMPOSE;
   705  	ODD_keymap[XK_dead_breve&0xFF] = SDLK_COMPOSE;
   706  	ODD_keymap[XK_dead_abovedot&0xFF] = SDLK_COMPOSE;
   707  	ODD_keymap[XK_dead_diaeresis&0xFF] = SDLK_COMPOSE;
   708  	ODD_keymap[XK_dead_abovering&0xFF] = SDLK_COMPOSE;
   709  	ODD_keymap[XK_dead_doubleacute&0xFF] = SDLK_COMPOSE;
   710  	ODD_keymap[XK_dead_caron&0xFF] = SDLK_COMPOSE;
   711  	ODD_keymap[XK_dead_cedilla&0xFF] = SDLK_COMPOSE;
   712  	ODD_keymap[XK_dead_ogonek&0xFF] = SDLK_COMPOSE;
   713  	ODD_keymap[XK_dead_iota&0xFF] = SDLK_COMPOSE;
   714  	ODD_keymap[XK_dead_voiced_sound&0xFF] = SDLK_COMPOSE;
   715  	ODD_keymap[XK_dead_semivoiced_sound&0xFF] = SDLK_COMPOSE;
   716  	ODD_keymap[XK_dead_belowdot&0xFF] = SDLK_COMPOSE;
   717  	ODD_keymap[XK_dead_hook&0xFF] = SDLK_COMPOSE;
   718  	ODD_keymap[XK_dead_horn&0xFF] = SDLK_COMPOSE;
   719 
   720 #ifdef XK_dead_circumflex
   721 	/* These X keysyms have 0xFE as the high byte */
   722 	ODD_keymap[XK_dead_circumflex&0xFF] = SDLK_CARET;
   723 #endif
   724 #ifdef XK_ISO_Level3_Shift
   725 	ODD_keymap[XK_ISO_Level3_Shift&0xFF] = SDLK_MODE; /* "Alt Gr" key */
   726 #endif
   727 
   728 	/* Map the miscellaneous keys */
   729 	for ( i=0; i<SDL_TABLESIZE(MISC_keymap); ++i )
   730 		MISC_keymap[i] = SDLK_UNKNOWN;
   731 
   732 	/* These X keysyms have 0xFF as the high byte */
   733 	MISC_keymap[XK_BackSpace&0xFF] = SDLK_BACKSPACE;
   734 	MISC_keymap[XK_Tab&0xFF] = SDLK_TAB;
   735 	MISC_keymap[XK_Clear&0xFF] = SDLK_CLEAR;
   736 	MISC_keymap[XK_Return&0xFF] = SDLK_RETURN;
   737 	MISC_keymap[XK_Pause&0xFF] = SDLK_PAUSE;
   738 	MISC_keymap[XK_Escape&0xFF] = SDLK_ESCAPE;
   739 	MISC_keymap[XK_Delete&0xFF] = SDLK_DELETE;
   740 
   741 	MISC_keymap[XK_KP_0&0xFF] = SDLK_KP0;		/* Keypad 0-9 */
   742 	MISC_keymap[XK_KP_1&0xFF] = SDLK_KP1;
   743 	MISC_keymap[XK_KP_2&0xFF] = SDLK_KP2;
   744 	MISC_keymap[XK_KP_3&0xFF] = SDLK_KP3;
   745 	MISC_keymap[XK_KP_4&0xFF] = SDLK_KP4;
   746 	MISC_keymap[XK_KP_5&0xFF] = SDLK_KP5;
   747 	MISC_keymap[XK_KP_6&0xFF] = SDLK_KP6;
   748 	MISC_keymap[XK_KP_7&0xFF] = SDLK_KP7;
   749 	MISC_keymap[XK_KP_8&0xFF] = SDLK_KP8;
   750 	MISC_keymap[XK_KP_9&0xFF] = SDLK_KP9;
   751 	MISC_keymap[XK_KP_Insert&0xFF] = SDLK_KP0;
   752 	MISC_keymap[XK_KP_End&0xFF] = SDLK_KP1;	
   753 	MISC_keymap[XK_KP_Down&0xFF] = SDLK_KP2;
   754 	MISC_keymap[XK_KP_Page_Down&0xFF] = SDLK_KP3;
   755 	MISC_keymap[XK_KP_Left&0xFF] = SDLK_KP4;
   756 	MISC_keymap[XK_KP_Begin&0xFF] = SDLK_KP5;
   757 	MISC_keymap[XK_KP_Right&0xFF] = SDLK_KP6;
   758 	MISC_keymap[XK_KP_Home&0xFF] = SDLK_KP7;
   759 	MISC_keymap[XK_KP_Up&0xFF] = SDLK_KP8;
   760 	MISC_keymap[XK_KP_Page_Up&0xFF] = SDLK_KP9;
   761 	MISC_keymap[XK_KP_Delete&0xFF] = SDLK_KP_PERIOD;
   762 	MISC_keymap[XK_KP_Decimal&0xFF] = SDLK_KP_PERIOD;
   763 	MISC_keymap[XK_KP_Divide&0xFF] = SDLK_KP_DIVIDE;
   764 	MISC_keymap[XK_KP_Multiply&0xFF] = SDLK_KP_MULTIPLY;
   765 	MISC_keymap[XK_KP_Subtract&0xFF] = SDLK_KP_MINUS;
   766 	MISC_keymap[XK_KP_Add&0xFF] = SDLK_KP_PLUS;
   767 	MISC_keymap[XK_KP_Enter&0xFF] = SDLK_KP_ENTER;
   768 	MISC_keymap[XK_KP_Equal&0xFF] = SDLK_KP_EQUALS;
   769 
   770 	MISC_keymap[XK_Up&0xFF] = SDLK_UP;
   771 	MISC_keymap[XK_Down&0xFF] = SDLK_DOWN;
   772 	MISC_keymap[XK_Right&0xFF] = SDLK_RIGHT;
   773 	MISC_keymap[XK_Left&0xFF] = SDLK_LEFT;
   774 	MISC_keymap[XK_Insert&0xFF] = SDLK_INSERT;
   775 	MISC_keymap[XK_Home&0xFF] = SDLK_HOME;
   776 	MISC_keymap[XK_End&0xFF] = SDLK_END;
   777 	MISC_keymap[XK_Page_Up&0xFF] = SDLK_PAGEUP;
   778 	MISC_keymap[XK_Page_Down&0xFF] = SDLK_PAGEDOWN;
   779 
   780 	MISC_keymap[XK_F1&0xFF] = SDLK_F1;
   781 	MISC_keymap[XK_F2&0xFF] = SDLK_F2;
   782 	MISC_keymap[XK_F3&0xFF] = SDLK_F3;
   783 	MISC_keymap[XK_F4&0xFF] = SDLK_F4;
   784 	MISC_keymap[XK_F5&0xFF] = SDLK_F5;
   785 	MISC_keymap[XK_F6&0xFF] = SDLK_F6;
   786 	MISC_keymap[XK_F7&0xFF] = SDLK_F7;
   787 	MISC_keymap[XK_F8&0xFF] = SDLK_F8;
   788 	MISC_keymap[XK_F9&0xFF] = SDLK_F9;
   789 	MISC_keymap[XK_F10&0xFF] = SDLK_F10;
   790 	MISC_keymap[XK_F11&0xFF] = SDLK_F11;
   791 	MISC_keymap[XK_F12&0xFF] = SDLK_F12;
   792 	MISC_keymap[XK_F13&0xFF] = SDLK_F13;
   793 	MISC_keymap[XK_F14&0xFF] = SDLK_F14;
   794 	MISC_keymap[XK_F15&0xFF] = SDLK_F15;
   795 
   796 	MISC_keymap[XK_Num_Lock&0xFF] = SDLK_NUMLOCK;
   797 	MISC_keymap[XK_Caps_Lock&0xFF] = SDLK_CAPSLOCK;
   798 	MISC_keymap[XK_Scroll_Lock&0xFF] = SDLK_SCROLLOCK;
   799 	MISC_keymap[XK_Shift_R&0xFF] = SDLK_RSHIFT;
   800 	MISC_keymap[XK_Shift_L&0xFF] = SDLK_LSHIFT;
   801 	MISC_keymap[XK_Control_R&0xFF] = SDLK_RCTRL;
   802 	MISC_keymap[XK_Control_L&0xFF] = SDLK_LCTRL;
   803 	MISC_keymap[XK_Alt_R&0xFF] = SDLK_RALT;
   804 	MISC_keymap[XK_Alt_L&0xFF] = SDLK_LALT;
   805 	MISC_keymap[XK_Meta_R&0xFF] = SDLK_RMETA;
   806 	MISC_keymap[XK_Meta_L&0xFF] = SDLK_LMETA;
   807 	MISC_keymap[XK_Super_L&0xFF] = SDLK_LSUPER; /* Left "Windows" */
   808 	MISC_keymap[XK_Super_R&0xFF] = SDLK_RSUPER; /* Right "Windows */
   809 	MISC_keymap[XK_Mode_switch&0xFF] = SDLK_MODE; /* "Alt Gr" key */
   810 	MISC_keymap[XK_Multi_key&0xFF] = SDLK_COMPOSE; /* Multi-key compose */
   811 
   812 	MISC_keymap[XK_Help&0xFF] = SDLK_HELP;
   813 	MISC_keymap[XK_Print&0xFF] = SDLK_PRINT;
   814 	MISC_keymap[XK_Sys_Req&0xFF] = SDLK_SYSREQ;
   815 	MISC_keymap[XK_Break&0xFF] = SDLK_BREAK;
   816 	MISC_keymap[XK_Menu&0xFF] = SDLK_MENU;
   817 	MISC_keymap[XK_Hyper_R&0xFF] = SDLK_MENU;   /* Windows "Menu" key */
   818 }
   819 
   820 /* Get the translated SDL virtual keysym */
   821 SDLKey X11_TranslateKeycode(Display *display, KeyCode kc)
   822 {
   823 	KeySym xsym;
   824 	SDLKey key;
   825 
   826 	xsym = pXKeycodeToKeysym(display, kc, 0);
   827 #ifdef DEBUG_KEYS
   828 	fprintf(stderr, "Translating key code %d -> 0x%.4x\n", kc, xsym);
   829 #endif
   830 	key = SDLK_UNKNOWN;
   831 	if ( xsym ) {
   832 		switch (xsym>>8) {
   833 		    case 0x1005FF:
   834 #ifdef SunXK_F36
   835 			if ( xsym == SunXK_F36 )
   836 				key = SDLK_F11;
   837 #endif
   838 #ifdef SunXK_F37
   839 			if ( xsym == SunXK_F37 )
   840 				key = SDLK_F12;
   841 #endif
   842 			break;
   843 		    case 0x00:	/* Latin 1 */
   844 			key = (SDLKey)(xsym & 0xFF);
   845 			break;
   846 		    case 0x01:	/* Latin 2 */
   847 		    case 0x02:	/* Latin 3 */
   848 		    case 0x03:	/* Latin 4 */
   849 		    case 0x04:	/* Katakana */
   850 		    case 0x05:	/* Arabic */
   851 		    case 0x06:	/* Cyrillic */
   852 		    case 0x07:	/* Greek */
   853 		    case 0x08:	/* Technical */
   854 		    case 0x0A:	/* Publishing */
   855 		    case 0x0C:	/* Hebrew */
   856 		    case 0x0D:	/* Thai */
   857 			/* These are wrong, but it's better than nothing */
   858 			key = (SDLKey)(xsym & 0xFF);
   859 			break;
   860 		    case 0xFE:
   861 			key = ODD_keymap[xsym&0xFF];
   862 			break;
   863 		    case 0xFF:
   864 			key = MISC_keymap[xsym&0xFF];
   865 			break;
   866 		    default:
   867 			/*
   868 			fprintf(stderr, "X11: Unhandled xsym, sym = 0x%04x\n",
   869 					(unsigned int)xsym);
   870 			*/
   871 			break;
   872 		}
   873 	} else {
   874 		/* X11 doesn't know how to translate the key! */
   875 		switch (kc) {
   876 		    /* Caution:
   877 		       These keycodes are from the Microsoft Keyboard
   878 		     */
   879 		    case 115:
   880 			key = SDLK_LSUPER;
   881 			break;
   882 		    case 116:
   883 			key = SDLK_RSUPER;
   884 			break;
   885 		    case 117:
   886 			key = SDLK_MENU;
   887 			break;
   888 		    default:
   889 			/*
   890 			 * no point in an error message; happens for
   891 			 * several keys when we get a keymap notify
   892 			 */
   893 			break;
   894 		}
   895 	}
   896 	return key;
   897 }
   898 
   899 /* X11 modifier masks for various keys */
   900 static unsigned meta_l_mask, meta_r_mask, alt_l_mask, alt_r_mask;
   901 static unsigned num_mask, mode_switch_mask;
   902 
   903 static void get_modifier_masks(Display *display)
   904 {
   905 	static unsigned got_masks;
   906 	int i, j;
   907 	XModifierKeymap *xmods;
   908 	unsigned n;
   909 
   910 	if(got_masks)
   911 		return;
   912 
   913 	xmods = pXGetModifierMapping(display);
   914 	n = xmods->max_keypermod;
   915 	for(i = 3; i < 8; i++) {
   916 		for(j = 0; j < n; j++) {
   917 			KeyCode kc = xmods->modifiermap[i * n + j];
   918 			KeySym ks = pXKeycodeToKeysym(display, kc, 0);
   919 			unsigned mask = 1 << i;
   920 			switch(ks) {
   921 			case XK_Num_Lock:
   922 				num_mask = mask; break;
   923 			case XK_Alt_L:
   924 				alt_l_mask = mask; break;
   925 			case XK_Alt_R:
   926 				alt_r_mask = mask; break;
   927 			case XK_Meta_L:
   928 				meta_l_mask = mask; break;
   929 			case XK_Meta_R:
   930 				meta_r_mask = mask; break;
   931 			case XK_Mode_switch:
   932 				mode_switch_mask = mask; break;
   933 			}
   934 		}
   935 	}
   936 	pXFreeModifiermap(xmods);
   937 	got_masks = 1;
   938 }
   939 
   940 
   941 /*
   942  * This function is semi-official; it is not officially exported and should
   943  * not be considered part of the SDL API, but may be used by client code
   944  * that *really* needs it (including legacy code).
   945  * It is slow, though, and should be avoided if possible.
   946  *
   947  * Note that it isn't completely accurate either; in particular, multi-key
   948  * sequences (dead accents, compose key sequences) will not work since the
   949  * state has been irrevocably lost.
   950  */
   951 Uint16 X11_KeyToUnicode(SDLKey keysym, SDLMod modifiers)
   952 {
   953 	struct SDL_VideoDevice *this = current_video;
   954 	char keybuf[32];
   955 	int i;
   956 	KeySym xsym = 0;
   957 	XKeyEvent xkey;
   958 	Uint16 unicode;
   959 
   960 	if ( !this || !SDL_Display ) {
   961 		return 0;
   962 	}
   963 
   964 	memset(&xkey, 0, sizeof(xkey));
   965 	xkey.display = SDL_Display;
   966 
   967 	xsym = keysym;		/* last resort if not found */
   968 	for (i = 0; i < 256; ++i) {
   969 		if ( MISC_keymap[i] == keysym ) {
   970 			xsym = 0xFF00 | i;
   971 			break;
   972 		} else if ( ODD_keymap[i] == keysym ) {
   973 			xsym = 0xFE00 | i;
   974 			break;
   975 		}
   976 	}
   977 
   978 	xkey.keycode = pXKeysymToKeycode(xkey.display, xsym);
   979 
   980 	get_modifier_masks(SDL_Display);
   981 	if(modifiers & KMOD_SHIFT)
   982 		xkey.state |= ShiftMask;
   983 	if(modifiers & KMOD_CAPS)
   984 		xkey.state |= LockMask;
   985 	if(modifiers & KMOD_CTRL)
   986 		xkey.state |= ControlMask;
   987 	if(modifiers & KMOD_MODE)
   988 		xkey.state |= mode_switch_mask;
   989 	if(modifiers & KMOD_LALT)
   990 		xkey.state |= alt_l_mask;
   991 	if(modifiers & KMOD_RALT)
   992 		xkey.state |= alt_r_mask;
   993 	if(modifiers & KMOD_LMETA)
   994 		xkey.state |= meta_l_mask;
   995 	if(modifiers & KMOD_RMETA)
   996 		xkey.state |= meta_r_mask;
   997 	if(modifiers & KMOD_NUM)
   998 		xkey.state |= num_mask;
   999 
  1000 	unicode = 0;
  1001 	if ( pXLookupString(&xkey, keybuf, sizeof(keybuf), NULL, NULL) )
  1002 		unicode = (unsigned char)keybuf[0];
  1003 	return(unicode);
  1004 }
  1005 
  1006 
  1007 /*
  1008  * Called when focus is regained, to read the keyboard state and generate
  1009  * synthetic keypress/release events.
  1010  * key_vec is a bit vector of keycodes (256 bits)
  1011  */
  1012 void X11_SetKeyboardState(Display *display, const char *key_vec)
  1013 {
  1014 	char keys_return[32];
  1015 	int i;
  1016 	Uint8 *kstate = SDL_GetKeyState(NULL);
  1017 	SDLMod modstate;
  1018 	Window junk_window;
  1019 	int x, y;
  1020 	unsigned int mask;
  1021 
  1022 	/* The first time the window is mapped, we initialize key state */
  1023 	if ( ! key_vec ) {
  1024 		pXQueryKeymap(display, keys_return);
  1025 		key_vec = keys_return;
  1026 	}
  1027 
  1028 	/* Get the keyboard modifier state */
  1029 	modstate = 0;
  1030 	get_modifier_masks(display);
  1031 	if ( pXQueryPointer(display, DefaultRootWindow(display),
  1032 		&junk_window, &junk_window, &x, &y, &x, &y, &mask) ) {
  1033 		if ( mask & LockMask ) {
  1034 			modstate |= KMOD_CAPS;
  1035 		}
  1036 		if ( mask & mode_switch_mask ) {
  1037 			modstate |= KMOD_MODE;
  1038 		}
  1039 		if ( mask & num_mask ) {
  1040 			modstate |= KMOD_NUM;
  1041 		}
  1042 	}
  1043 
  1044 	/* Zero the new keyboard state and generate it */
  1045 	memset(kstate, 0, SDLK_LAST);
  1046 	/*
  1047 	 * An obvious optimisation is to check entire longwords at a time in
  1048 	 * both loops, but we can't be sure the arrays are aligned so it's not
  1049 	 * worth the extra complexity
  1050 	 */
  1051 	for ( i = 0; i < 32; i++ ) {
  1052 		int j;
  1053 		if ( !key_vec[i] )
  1054 			continue;
  1055 		for ( j = 0; j < 8; j++ ) {
  1056 			if ( key_vec[i] & (1 << j) ) {
  1057 				SDLKey key;
  1058 				KeyCode kc = (i << 3 | j);
  1059 				key = X11_TranslateKeycode(display, kc);
  1060 				if ( key == SDLK_UNKNOWN ) {
  1061 					continue;
  1062 				}
  1063 				kstate[key] = SDL_PRESSED;
  1064 				switch (key) {
  1065 				    case SDLK_LSHIFT:
  1066 					modstate |= KMOD_LSHIFT;
  1067 					break;
  1068 				    case SDLK_RSHIFT:
  1069 					modstate |= KMOD_RSHIFT;
  1070 					break;
  1071 				    case SDLK_LCTRL:
  1072 					modstate |= KMOD_LCTRL;
  1073 					break;
  1074 				    case SDLK_RCTRL:
  1075 					modstate |= KMOD_RCTRL;
  1076 					break;
  1077 				    case SDLK_LALT:
  1078 					modstate |= KMOD_LALT;
  1079 					break;
  1080 				    case SDLK_RALT:
  1081 					modstate |= KMOD_RALT;
  1082 					break;
  1083 				    case SDLK_LMETA:
  1084 					modstate |= KMOD_LMETA;
  1085 					break;
  1086 				    case SDLK_RMETA:
  1087 					modstate |= KMOD_RMETA;
  1088 					break;
  1089 				    default:
  1090 					break;
  1091 				}
  1092 			}
  1093 		}
  1094 	}
  1095 
  1096 	/* Hack - set toggle key state */
  1097 	if ( modstate & KMOD_CAPS ) {
  1098 		kstate[SDLK_CAPSLOCK] = SDL_PRESSED;
  1099 	} else {
  1100 		kstate[SDLK_CAPSLOCK] = SDL_RELEASED;
  1101 	}
  1102 	if ( modstate & KMOD_NUM ) {
  1103 		kstate[SDLK_NUMLOCK] = SDL_PRESSED;
  1104 	} else {
  1105 		kstate[SDLK_NUMLOCK] = SDL_RELEASED;
  1106 	}
  1107 
  1108 	/* Set the final modifier state */
  1109 	SDL_SetModState(modstate);
  1110 }
  1111 
  1112 void X11_InitOSKeymap(_THIS)
  1113 {
  1114 	X11_InitKeymap();
  1115 }
  1116