src/video/x11/SDL_x11events.c
author Ryan C. Gordon <icculus@icculus.org>
Wed, 22 Mar 2006 05:00:59 +0000
changeset 1575 3ba88cb7eb1b
parent 1402 d910939febfa
child 1657 5b0805ceb50f
permissions -rw-r--r--
Updated dynamic X11 code. See details in Bugzilla #170.
     1 /*
     2     SDL - Simple DirectMedia Layer
     3     Copyright (C) 1997-2006 Sam Lantinga
     4 
     5     This library is free software; you can redistribute it and/or
     6     modify it under the terms of the GNU Lesser General Public
     7     License as published by the Free Software Foundation; either
     8     version 2.1 of the License, or (at your option) any later version.
     9 
    10     This library is distributed in the hope that it will be useful,
    11     but WITHOUT ANY WARRANTY; without even the implied warranty of
    12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    13     Lesser General Public License for more details.
    14 
    15     You should have received a copy of the GNU Lesser General Public
    16     License along with this library; if not, write to the Free Software
    17     Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
    18 
    19     Sam Lantinga
    20     slouken@libsdl.org
    21 */
    22 #include "SDL_config.h"
    23 
    24 /* Handle the event stream, converting X11 events into SDL events */
    25 
    26 #include <setjmp.h>
    27 #include <X11/Xlib.h>
    28 #include <X11/Xutil.h>
    29 #include <X11/keysym.h>
    30 #ifdef __SVR4
    31 #include <X11/Sunkeysym.h>
    32 #endif
    33 #include <sys/types.h>
    34 #include <sys/time.h>
    35 #include <unistd.h>
    36 
    37 #include "SDL_timer.h"
    38 #include "SDL_syswm.h"
    39 #include "../SDL_sysvideo.h"
    40 #include "../../events/SDL_sysevents.h"
    41 #include "../../events/SDL_events_c.h"
    42 #include "SDL_x11video.h"
    43 #include "SDL_x11dga_c.h"
    44 #include "SDL_x11modes_c.h"
    45 #include "SDL_x11image_c.h"
    46 #include "SDL_x11gamma_c.h"
    47 #include "SDL_x11wm_c.h"
    48 #include "SDL_x11mouse_c.h"
    49 #include "SDL_x11events_c.h"
    50 
    51 
    52 /* Define this if you want to debug X11 events */
    53 /*#define DEBUG_XEVENTS*/
    54 
    55 /* The translation tables from an X11 keysym to a SDL keysym */
    56 static SDLKey ODD_keymap[256];
    57 static SDLKey MISC_keymap[256];
    58 SDLKey X11_TranslateKeycode(Display *display, KeyCode kc);
    59 
    60 
    61 #ifdef X_HAVE_UTF8_STRING
    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 #endif
   180 
   181 /* Check to see if this is a repeated key.
   182    (idea shamelessly lifted from GII -- thanks guys! :)
   183  */
   184 static int X11_KeyRepeat(Display *display, XEvent *event)
   185 {
   186 	XEvent peekevent;
   187 	int repeated;
   188 
   189 	repeated = 0;
   190 	if ( XPending(display) ) {
   191 		XPeekEvent(display, &peekevent);
   192 		if ( (peekevent.type == KeyPress) &&
   193 		     (peekevent.xkey.keycode == event->xkey.keycode) &&
   194 		     ((peekevent.xkey.time-event->xkey.time) < 2) ) {
   195 			repeated = 1;
   196 			XNextEvent(display, &peekevent);
   197 		}
   198 	}
   199 	return(repeated);
   200 }
   201 
   202 /* Note:  The X server buffers and accumulates mouse motion events, so
   203    the motion event generated by the warp may not appear exactly as we
   204    expect it to.  We work around this (and improve performance) by only
   205    warping the pointer when it reaches the edge, and then wait for it.
   206 */
   207 #define MOUSE_FUDGE_FACTOR	8
   208 
   209 static __inline__ int X11_WarpedMotion(_THIS, XEvent *xevent)
   210 {
   211 	int w, h, i;
   212 	int deltax, deltay;
   213 	int posted;
   214 
   215 	w = SDL_VideoSurface->w;
   216 	h = SDL_VideoSurface->h;
   217 	deltax = xevent->xmotion.x - mouse_last.x;
   218 	deltay = xevent->xmotion.y - mouse_last.y;
   219 #ifdef DEBUG_MOTION
   220   printf("Warped mouse motion: %d,%d\n", deltax, deltay);
   221 #endif
   222 	mouse_last.x = xevent->xmotion.x;
   223 	mouse_last.y = xevent->xmotion.y;
   224 	posted = SDL_PrivateMouseMotion(0, 1, deltax, deltay);
   225 
   226 	if ( (xevent->xmotion.x < MOUSE_FUDGE_FACTOR) ||
   227 	     (xevent->xmotion.x > (w-MOUSE_FUDGE_FACTOR)) ||
   228 	     (xevent->xmotion.y < MOUSE_FUDGE_FACTOR) ||
   229 	     (xevent->xmotion.y > (h-MOUSE_FUDGE_FACTOR)) ) {
   230 		/* Get the events that have accumulated */
   231 		while ( XCheckTypedEvent(SDL_Display, MotionNotify, xevent) ) {
   232 			deltax = xevent->xmotion.x - mouse_last.x;
   233 			deltay = xevent->xmotion.y - mouse_last.y;
   234 #ifdef DEBUG_MOTION
   235   printf("Extra mouse motion: %d,%d\n", deltax, deltay);
   236 #endif
   237 			mouse_last.x = xevent->xmotion.x;
   238 			mouse_last.y = xevent->xmotion.y;
   239 			posted += SDL_PrivateMouseMotion(0, 1, deltax, deltay);
   240 		}
   241 		mouse_last.x = w/2;
   242 		mouse_last.y = h/2;
   243 		XWarpPointer(SDL_Display, None, SDL_Window, 0, 0, 0, 0,
   244 					mouse_last.x, mouse_last.y);
   245 		for ( i=0; i<10; ++i ) {
   246         		XMaskEvent(SDL_Display, PointerMotionMask, xevent);
   247 			if ( (xevent->xmotion.x >
   248 			          (mouse_last.x-MOUSE_FUDGE_FACTOR)) &&
   249 			     (xevent->xmotion.x <
   250 			          (mouse_last.x+MOUSE_FUDGE_FACTOR)) &&
   251 			     (xevent->xmotion.y >
   252 			          (mouse_last.y-MOUSE_FUDGE_FACTOR)) &&
   253 			     (xevent->xmotion.y <
   254 			          (mouse_last.y+MOUSE_FUDGE_FACTOR)) ) {
   255 				break;
   256 			}
   257 #ifdef DEBUG_XEVENTS
   258   printf("Lost mouse motion: %d,%d\n", xevent->xmotion.x, xevent->xmotion.y);
   259 #endif
   260 		}
   261 #ifdef DEBUG_XEVENTS
   262 		if ( i == 10 ) {
   263 			printf("Warning: didn't detect mouse warp motion\n");
   264 		}
   265 #endif
   266 	}
   267 	return(posted);
   268 }
   269 
   270 static int X11_DispatchEvent(_THIS)
   271 {
   272 	int posted;
   273 	XEvent xevent;
   274 
   275 	SDL_memset(&xevent, '\0', sizeof (XEvent));  /* valgrind fix. --ryan. */
   276 	XNextEvent(SDL_Display, &xevent);
   277 
   278 	posted = 0;
   279 	switch (xevent.type) {
   280 
   281 	    /* Gaining mouse coverage? */
   282 	    case EnterNotify: {
   283 #ifdef DEBUG_XEVENTS
   284 printf("EnterNotify! (%d,%d)\n", xevent.xcrossing.x, xevent.xcrossing.y);
   285 if ( xevent.xcrossing.mode == NotifyGrab )
   286 printf("Mode: NotifyGrab\n");
   287 if ( xevent.xcrossing.mode == NotifyUngrab )
   288 printf("Mode: NotifyUngrab\n");
   289 #endif
   290 		if ( (xevent.xcrossing.mode != NotifyGrab) &&
   291 		     (xevent.xcrossing.mode != NotifyUngrab) ) {
   292 			if ( this->input_grab == SDL_GRAB_OFF ) {
   293 				posted = SDL_PrivateAppActive(1, SDL_APPMOUSEFOCUS);
   294 			} else {
   295 				posted = SDL_PrivateMouseMotion(0, 0,
   296 						xevent.xcrossing.x,
   297 						xevent.xcrossing.y);
   298 			}
   299 		}
   300 	    }
   301 	    break;
   302 
   303 	    /* Losing mouse coverage? */
   304 	    case LeaveNotify: {
   305 #ifdef DEBUG_XEVENTS
   306 printf("LeaveNotify! (%d,%d)\n", xevent.xcrossing.x, xevent.xcrossing.y);
   307 if ( xevent.xcrossing.mode == NotifyGrab )
   308 printf("Mode: NotifyGrab\n");
   309 if ( xevent.xcrossing.mode == NotifyUngrab )
   310 printf("Mode: NotifyUngrab\n");
   311 #endif
   312 		if ( (xevent.xcrossing.mode != NotifyGrab) &&
   313 		     (xevent.xcrossing.mode != NotifyUngrab) &&
   314 		     (xevent.xcrossing.detail != NotifyInferior) ) {
   315 			if ( this->input_grab == SDL_GRAB_OFF ) {
   316 				posted = SDL_PrivateAppActive(0, SDL_APPMOUSEFOCUS);
   317 			} else {
   318 				posted = SDL_PrivateMouseMotion(0, 0,
   319 						xevent.xcrossing.x,
   320 						xevent.xcrossing.y);
   321 			}
   322 		}
   323 	    }
   324 	    break;
   325 
   326 	    /* Gaining input focus? */
   327 	    case FocusIn: {
   328 #ifdef DEBUG_XEVENTS
   329 printf("FocusIn!\n");
   330 #endif
   331 		posted = SDL_PrivateAppActive(1, SDL_APPINPUTFOCUS);
   332 
   333 #ifdef X_HAVE_UTF8_STRING
   334 		if ( SDL_IC != NULL ) {
   335 			XSetICFocus(SDL_IC);
   336 		}
   337 #endif
   338 		/* Queue entry into fullscreen mode */
   339 		switch_waiting = 0x01 | SDL_FULLSCREEN;
   340 		switch_time = SDL_GetTicks() + 1500;
   341 	    }
   342 	    break;
   343 
   344 	    /* Losing input focus? */
   345 	    case FocusOut: {
   346 #ifdef DEBUG_XEVENTS
   347 printf("FocusOut!\n");
   348 #endif
   349 		posted = SDL_PrivateAppActive(0, SDL_APPINPUTFOCUS);
   350 
   351 #ifdef X_HAVE_UTF8_STRING
   352 		if ( SDL_IC != NULL ) {
   353 			XUnsetICFocus(SDL_IC);
   354 		}
   355 #endif
   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 ( XFilterEvent(&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 ( Xutf8LookupString(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 ( XLookupString(&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 	XFlush(display);
   626 	if ( XEventsQueued(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(XPending(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_arraysize(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 #ifdef XK_dead_hook
   718  	ODD_keymap[XK_dead_hook&0xFF] = SDLK_COMPOSE;
   719 #endif
   720 #ifdef XK_dead_horn
   721  	ODD_keymap[XK_dead_horn&0xFF] = SDLK_COMPOSE;
   722 #endif
   723 
   724 #ifdef XK_dead_circumflex
   725 	/* These X keysyms have 0xFE as the high byte */
   726 	ODD_keymap[XK_dead_circumflex&0xFF] = SDLK_CARET;
   727 #endif
   728 #ifdef XK_ISO_Level3_Shift
   729 	ODD_keymap[XK_ISO_Level3_Shift&0xFF] = SDLK_MODE; /* "Alt Gr" key */
   730 #endif
   731 
   732 	/* Map the miscellaneous keys */
   733 	for ( i=0; i<SDL_arraysize(MISC_keymap); ++i )
   734 		MISC_keymap[i] = SDLK_UNKNOWN;
   735 
   736 	/* These X keysyms have 0xFF as the high byte */
   737 	MISC_keymap[XK_BackSpace&0xFF] = SDLK_BACKSPACE;
   738 	MISC_keymap[XK_Tab&0xFF] = SDLK_TAB;
   739 	MISC_keymap[XK_Clear&0xFF] = SDLK_CLEAR;
   740 	MISC_keymap[XK_Return&0xFF] = SDLK_RETURN;
   741 	MISC_keymap[XK_Pause&0xFF] = SDLK_PAUSE;
   742 	MISC_keymap[XK_Escape&0xFF] = SDLK_ESCAPE;
   743 	MISC_keymap[XK_Delete&0xFF] = SDLK_DELETE;
   744 
   745 	MISC_keymap[XK_KP_0&0xFF] = SDLK_KP0;		/* Keypad 0-9 */
   746 	MISC_keymap[XK_KP_1&0xFF] = SDLK_KP1;
   747 	MISC_keymap[XK_KP_2&0xFF] = SDLK_KP2;
   748 	MISC_keymap[XK_KP_3&0xFF] = SDLK_KP3;
   749 	MISC_keymap[XK_KP_4&0xFF] = SDLK_KP4;
   750 	MISC_keymap[XK_KP_5&0xFF] = SDLK_KP5;
   751 	MISC_keymap[XK_KP_6&0xFF] = SDLK_KP6;
   752 	MISC_keymap[XK_KP_7&0xFF] = SDLK_KP7;
   753 	MISC_keymap[XK_KP_8&0xFF] = SDLK_KP8;
   754 	MISC_keymap[XK_KP_9&0xFF] = SDLK_KP9;
   755 	MISC_keymap[XK_KP_Insert&0xFF] = SDLK_KP0;
   756 	MISC_keymap[XK_KP_End&0xFF] = SDLK_KP1;	
   757 	MISC_keymap[XK_KP_Down&0xFF] = SDLK_KP2;
   758 	MISC_keymap[XK_KP_Page_Down&0xFF] = SDLK_KP3;
   759 	MISC_keymap[XK_KP_Left&0xFF] = SDLK_KP4;
   760 	MISC_keymap[XK_KP_Begin&0xFF] = SDLK_KP5;
   761 	MISC_keymap[XK_KP_Right&0xFF] = SDLK_KP6;
   762 	MISC_keymap[XK_KP_Home&0xFF] = SDLK_KP7;
   763 	MISC_keymap[XK_KP_Up&0xFF] = SDLK_KP8;
   764 	MISC_keymap[XK_KP_Page_Up&0xFF] = SDLK_KP9;
   765 	MISC_keymap[XK_KP_Delete&0xFF] = SDLK_KP_PERIOD;
   766 	MISC_keymap[XK_KP_Decimal&0xFF] = SDLK_KP_PERIOD;
   767 	MISC_keymap[XK_KP_Divide&0xFF] = SDLK_KP_DIVIDE;
   768 	MISC_keymap[XK_KP_Multiply&0xFF] = SDLK_KP_MULTIPLY;
   769 	MISC_keymap[XK_KP_Subtract&0xFF] = SDLK_KP_MINUS;
   770 	MISC_keymap[XK_KP_Add&0xFF] = SDLK_KP_PLUS;
   771 	MISC_keymap[XK_KP_Enter&0xFF] = SDLK_KP_ENTER;
   772 	MISC_keymap[XK_KP_Equal&0xFF] = SDLK_KP_EQUALS;
   773 
   774 	MISC_keymap[XK_Up&0xFF] = SDLK_UP;
   775 	MISC_keymap[XK_Down&0xFF] = SDLK_DOWN;
   776 	MISC_keymap[XK_Right&0xFF] = SDLK_RIGHT;
   777 	MISC_keymap[XK_Left&0xFF] = SDLK_LEFT;
   778 	MISC_keymap[XK_Insert&0xFF] = SDLK_INSERT;
   779 	MISC_keymap[XK_Home&0xFF] = SDLK_HOME;
   780 	MISC_keymap[XK_End&0xFF] = SDLK_END;
   781 	MISC_keymap[XK_Page_Up&0xFF] = SDLK_PAGEUP;
   782 	MISC_keymap[XK_Page_Down&0xFF] = SDLK_PAGEDOWN;
   783 
   784 	MISC_keymap[XK_F1&0xFF] = SDLK_F1;
   785 	MISC_keymap[XK_F2&0xFF] = SDLK_F2;
   786 	MISC_keymap[XK_F3&0xFF] = SDLK_F3;
   787 	MISC_keymap[XK_F4&0xFF] = SDLK_F4;
   788 	MISC_keymap[XK_F5&0xFF] = SDLK_F5;
   789 	MISC_keymap[XK_F6&0xFF] = SDLK_F6;
   790 	MISC_keymap[XK_F7&0xFF] = SDLK_F7;
   791 	MISC_keymap[XK_F8&0xFF] = SDLK_F8;
   792 	MISC_keymap[XK_F9&0xFF] = SDLK_F9;
   793 	MISC_keymap[XK_F10&0xFF] = SDLK_F10;
   794 	MISC_keymap[XK_F11&0xFF] = SDLK_F11;
   795 	MISC_keymap[XK_F12&0xFF] = SDLK_F12;
   796 	MISC_keymap[XK_F13&0xFF] = SDLK_F13;
   797 	MISC_keymap[XK_F14&0xFF] = SDLK_F14;
   798 	MISC_keymap[XK_F15&0xFF] = SDLK_F15;
   799 
   800 	MISC_keymap[XK_Num_Lock&0xFF] = SDLK_NUMLOCK;
   801 	MISC_keymap[XK_Caps_Lock&0xFF] = SDLK_CAPSLOCK;
   802 	MISC_keymap[XK_Scroll_Lock&0xFF] = SDLK_SCROLLOCK;
   803 	MISC_keymap[XK_Shift_R&0xFF] = SDLK_RSHIFT;
   804 	MISC_keymap[XK_Shift_L&0xFF] = SDLK_LSHIFT;
   805 	MISC_keymap[XK_Control_R&0xFF] = SDLK_RCTRL;
   806 	MISC_keymap[XK_Control_L&0xFF] = SDLK_LCTRL;
   807 	MISC_keymap[XK_Alt_R&0xFF] = SDLK_RALT;
   808 	MISC_keymap[XK_Alt_L&0xFF] = SDLK_LALT;
   809 	MISC_keymap[XK_Meta_R&0xFF] = SDLK_RMETA;
   810 	MISC_keymap[XK_Meta_L&0xFF] = SDLK_LMETA;
   811 	MISC_keymap[XK_Super_L&0xFF] = SDLK_LSUPER; /* Left "Windows" */
   812 	MISC_keymap[XK_Super_R&0xFF] = SDLK_RSUPER; /* Right "Windows */
   813 	MISC_keymap[XK_Mode_switch&0xFF] = SDLK_MODE; /* "Alt Gr" key */
   814 	MISC_keymap[XK_Multi_key&0xFF] = SDLK_COMPOSE; /* Multi-key compose */
   815 
   816 	MISC_keymap[XK_Help&0xFF] = SDLK_HELP;
   817 	MISC_keymap[XK_Print&0xFF] = SDLK_PRINT;
   818 	MISC_keymap[XK_Sys_Req&0xFF] = SDLK_SYSREQ;
   819 	MISC_keymap[XK_Break&0xFF] = SDLK_BREAK;
   820 	MISC_keymap[XK_Menu&0xFF] = SDLK_MENU;
   821 	MISC_keymap[XK_Hyper_R&0xFF] = SDLK_MENU;   /* Windows "Menu" key */
   822 }
   823 
   824 /* Get the translated SDL virtual keysym */
   825 SDLKey X11_TranslateKeycode(Display *display, KeyCode kc)
   826 {
   827 	KeySym xsym;
   828 	SDLKey key;
   829 
   830 	xsym = XKeycodeToKeysym(display, kc, 0);
   831 #ifdef DEBUG_KEYS
   832 	fprintf(stderr, "Translating key code %d -> 0x%.4x\n", kc, xsym);
   833 #endif
   834 	key = SDLK_UNKNOWN;
   835 	if ( xsym ) {
   836 		switch (xsym>>8) {
   837 		    case 0x1005FF:
   838 #ifdef SunXK_F36
   839 			if ( xsym == SunXK_F36 )
   840 				key = SDLK_F11;
   841 #endif
   842 #ifdef SunXK_F37
   843 			if ( xsym == SunXK_F37 )
   844 				key = SDLK_F12;
   845 #endif
   846 			break;
   847 		    case 0x00:	/* Latin 1 */
   848 			key = (SDLKey)(xsym & 0xFF);
   849 			break;
   850 		    case 0x01:	/* Latin 2 */
   851 		    case 0x02:	/* Latin 3 */
   852 		    case 0x03:	/* Latin 4 */
   853 		    case 0x04:	/* Katakana */
   854 		    case 0x05:	/* Arabic */
   855 		    case 0x06:	/* Cyrillic */
   856 		    case 0x07:	/* Greek */
   857 		    case 0x08:	/* Technical */
   858 		    case 0x0A:	/* Publishing */
   859 		    case 0x0C:	/* Hebrew */
   860 		    case 0x0D:	/* Thai */
   861 			/* These are wrong, but it's better than nothing */
   862 			key = (SDLKey)(xsym & 0xFF);
   863 			break;
   864 		    case 0xFE:
   865 			key = ODD_keymap[xsym&0xFF];
   866 			break;
   867 		    case 0xFF:
   868 			key = MISC_keymap[xsym&0xFF];
   869 			break;
   870 		    default:
   871 			/*
   872 			fprintf(stderr, "X11: Unhandled xsym, sym = 0x%04x\n",
   873 					(unsigned int)xsym);
   874 			*/
   875 			break;
   876 		}
   877 	} else {
   878 		/* X11 doesn't know how to translate the key! */
   879 		switch (kc) {
   880 		    /* Caution:
   881 		       These keycodes are from the Microsoft Keyboard
   882 		     */
   883 		    case 115:
   884 			key = SDLK_LSUPER;
   885 			break;
   886 		    case 116:
   887 			key = SDLK_RSUPER;
   888 			break;
   889 		    case 117:
   890 			key = SDLK_MENU;
   891 			break;
   892 		    default:
   893 			/*
   894 			 * no point in an error message; happens for
   895 			 * several keys when we get a keymap notify
   896 			 */
   897 			break;
   898 		}
   899 	}
   900 	return key;
   901 }
   902 
   903 /* X11 modifier masks for various keys */
   904 static unsigned meta_l_mask, meta_r_mask, alt_l_mask, alt_r_mask;
   905 static unsigned num_mask, mode_switch_mask;
   906 
   907 static void get_modifier_masks(Display *display)
   908 {
   909 	static unsigned got_masks;
   910 	int i, j;
   911 	XModifierKeymap *xmods;
   912 	unsigned n;
   913 
   914 	if(got_masks)
   915 		return;
   916 
   917 	xmods = XGetModifierMapping(display);
   918 	n = xmods->max_keypermod;
   919 	for(i = 3; i < 8; i++) {
   920 		for(j = 0; j < n; j++) {
   921 			KeyCode kc = xmods->modifiermap[i * n + j];
   922 			KeySym ks = XKeycodeToKeysym(display, kc, 0);
   923 			unsigned mask = 1 << i;
   924 			switch(ks) {
   925 			case XK_Num_Lock:
   926 				num_mask = mask; break;
   927 			case XK_Alt_L:
   928 				alt_l_mask = mask; break;
   929 			case XK_Alt_R:
   930 				alt_r_mask = mask; break;
   931 			case XK_Meta_L:
   932 				meta_l_mask = mask; break;
   933 			case XK_Meta_R:
   934 				meta_r_mask = mask; break;
   935 			case XK_Mode_switch:
   936 				mode_switch_mask = mask; break;
   937 			}
   938 		}
   939 	}
   940 	XFreeModifiermap(xmods);
   941 	got_masks = 1;
   942 }
   943 
   944 
   945 /*
   946  * This function is semi-official; it is not officially exported and should
   947  * not be considered part of the SDL API, but may be used by client code
   948  * that *really* needs it (including legacy code).
   949  * It is slow, though, and should be avoided if possible.
   950  *
   951  * Note that it isn't completely accurate either; in particular, multi-key
   952  * sequences (dead accents, compose key sequences) will not work since the
   953  * state has been irrevocably lost.
   954  */
   955 Uint16 X11_KeyToUnicode(SDLKey keysym, SDLMod modifiers)
   956 {
   957 	struct SDL_VideoDevice *this = current_video;
   958 	char keybuf[32];
   959 	int i;
   960 	KeySym xsym = 0;
   961 	XKeyEvent xkey;
   962 	Uint16 unicode;
   963 
   964 	if ( !this || !SDL_Display ) {
   965 		return 0;
   966 	}
   967 
   968 	SDL_memset(&xkey, 0, sizeof(xkey));
   969 	xkey.display = SDL_Display;
   970 
   971 	xsym = keysym;		/* last resort if not found */
   972 	for (i = 0; i < 256; ++i) {
   973 		if ( MISC_keymap[i] == keysym ) {
   974 			xsym = 0xFF00 | i;
   975 			break;
   976 		} else if ( ODD_keymap[i] == keysym ) {
   977 			xsym = 0xFE00 | i;
   978 			break;
   979 		}
   980 	}
   981 
   982 	xkey.keycode = XKeysymToKeycode(xkey.display, xsym);
   983 
   984 	get_modifier_masks(SDL_Display);
   985 	if(modifiers & KMOD_SHIFT)
   986 		xkey.state |= ShiftMask;
   987 	if(modifiers & KMOD_CAPS)
   988 		xkey.state |= LockMask;
   989 	if(modifiers & KMOD_CTRL)
   990 		xkey.state |= ControlMask;
   991 	if(modifiers & KMOD_MODE)
   992 		xkey.state |= mode_switch_mask;
   993 	if(modifiers & KMOD_LALT)
   994 		xkey.state |= alt_l_mask;
   995 	if(modifiers & KMOD_RALT)
   996 		xkey.state |= alt_r_mask;
   997 	if(modifiers & KMOD_LMETA)
   998 		xkey.state |= meta_l_mask;
   999 	if(modifiers & KMOD_RMETA)
  1000 		xkey.state |= meta_r_mask;
  1001 	if(modifiers & KMOD_NUM)
  1002 		xkey.state |= num_mask;
  1003 
  1004 	unicode = 0;
  1005 	if ( XLookupString(&xkey, keybuf, sizeof(keybuf), NULL, NULL) )
  1006 		unicode = (unsigned char)keybuf[0];
  1007 	return(unicode);
  1008 }
  1009 
  1010 
  1011 /*
  1012  * Called when focus is regained, to read the keyboard state and generate
  1013  * synthetic keypress/release events.
  1014  * key_vec is a bit vector of keycodes (256 bits)
  1015  */
  1016 void X11_SetKeyboardState(Display *display, const char *key_vec)
  1017 {
  1018 	char keys_return[32];
  1019 	int i;
  1020 	Uint8 *kstate = SDL_GetKeyState(NULL);
  1021 	SDLMod modstate;
  1022 	Window junk_window;
  1023 	int x, y;
  1024 	unsigned int mask;
  1025 
  1026 	/* The first time the window is mapped, we initialize key state */
  1027 	if ( ! key_vec ) {
  1028 		XQueryKeymap(display, keys_return);
  1029 		key_vec = keys_return;
  1030 	}
  1031 
  1032 	/* Get the keyboard modifier state */
  1033 	modstate = 0;
  1034 	get_modifier_masks(display);
  1035 	if ( XQueryPointer(display, DefaultRootWindow(display),
  1036 		&junk_window, &junk_window, &x, &y, &x, &y, &mask) ) {
  1037 		if ( mask & LockMask ) {
  1038 			modstate |= KMOD_CAPS;
  1039 		}
  1040 		if ( mask & mode_switch_mask ) {
  1041 			modstate |= KMOD_MODE;
  1042 		}
  1043 		if ( mask & num_mask ) {
  1044 			modstate |= KMOD_NUM;
  1045 		}
  1046 	}
  1047 
  1048 	/* Zero the new keyboard state and generate it */
  1049 	SDL_memset(kstate, 0, SDLK_LAST);
  1050 	/*
  1051 	 * An obvious optimisation is to check entire longwords at a time in
  1052 	 * both loops, but we can't be sure the arrays are aligned so it's not
  1053 	 * worth the extra complexity
  1054 	 */
  1055 	for ( i = 0; i < 32; i++ ) {
  1056 		int j;
  1057 		if ( !key_vec[i] )
  1058 			continue;
  1059 		for ( j = 0; j < 8; j++ ) {
  1060 			if ( key_vec[i] & (1 << j) ) {
  1061 				SDLKey key;
  1062 				KeyCode kc = (i << 3 | j);
  1063 				key = X11_TranslateKeycode(display, kc);
  1064 				if ( key == SDLK_UNKNOWN ) {
  1065 					continue;
  1066 				}
  1067 				kstate[key] = SDL_PRESSED;
  1068 				switch (key) {
  1069 				    case SDLK_LSHIFT:
  1070 					modstate |= KMOD_LSHIFT;
  1071 					break;
  1072 				    case SDLK_RSHIFT:
  1073 					modstate |= KMOD_RSHIFT;
  1074 					break;
  1075 				    case SDLK_LCTRL:
  1076 					modstate |= KMOD_LCTRL;
  1077 					break;
  1078 				    case SDLK_RCTRL:
  1079 					modstate |= KMOD_RCTRL;
  1080 					break;
  1081 				    case SDLK_LALT:
  1082 					modstate |= KMOD_LALT;
  1083 					break;
  1084 				    case SDLK_RALT:
  1085 					modstate |= KMOD_RALT;
  1086 					break;
  1087 				    case SDLK_LMETA:
  1088 					modstate |= KMOD_LMETA;
  1089 					break;
  1090 				    case SDLK_RMETA:
  1091 					modstate |= KMOD_RMETA;
  1092 					break;
  1093 				    default:
  1094 					break;
  1095 				}
  1096 			}
  1097 		}
  1098 	}
  1099 
  1100 	/* Hack - set toggle key state */
  1101 	if ( modstate & KMOD_CAPS ) {
  1102 		kstate[SDLK_CAPSLOCK] = SDL_PRESSED;
  1103 	} else {
  1104 		kstate[SDLK_CAPSLOCK] = SDL_RELEASED;
  1105 	}
  1106 	if ( modstate & KMOD_NUM ) {
  1107 		kstate[SDLK_NUMLOCK] = SDL_PRESSED;
  1108 	} else {
  1109 		kstate[SDLK_NUMLOCK] = SDL_RELEASED;
  1110 	}
  1111 
  1112 	/* Set the final modifier state */
  1113 	SDL_SetModState(modstate);
  1114 }
  1115 
  1116 void X11_InitOSKeymap(_THIS)
  1117 {
  1118 	X11_InitKeymap();
  1119 }
  1120