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