src/video/x11/SDL_x11events.c
author Sam Lantinga <slouken@libsdl.org>
Sat, 04 Feb 2006 16:29:22 +0000
changeset 1328 27ddb06a0bca
parent 1327 d12a63a8d95a
child 1336 3692456e7b0f
permissions -rw-r--r--
Date: Sat, 04 Feb 2006 19:47:23 +0900
From: Hayashi Naoyuki
Subject: Re: [SDL] Character Composition problem on X

The compilation fails.
cc: Error: SDL_x11events.c, line 717: In this statement, "XK_dead_hook"
is not declared. (undeclared)
ODD_keymap[XK_dead_hook&0xFF] = SDLK_COMPOSE;
-------------------^
cc: Error: SDL_x11events.c, line 718: In this statement, "XK_dead_horn"
is not declared. (undeclared)
ODD_keymap[XK_dead_horn&0xFF] = SDLK_COMPOSE;

Neither XK_dead_hook nor XK_dead_horn are defined on Tru64.
     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 #ifdef X_HAVE_UTF8_STRING
   336 		if ( SDL_IC != NULL ) {
   337 			pXSetICFocus(SDL_IC);
   338 		}
   339 #endif
   340 		/* Queue entry into fullscreen mode */
   341 		switch_waiting = 0x01 | SDL_FULLSCREEN;
   342 		switch_time = SDL_GetTicks() + 1500;
   343 	    }
   344 	    break;
   345 
   346 	    /* Losing input focus? */
   347 	    case FocusOut: {
   348 #ifdef DEBUG_XEVENTS
   349 printf("FocusOut!\n");
   350 #endif
   351 		posted = SDL_PrivateAppActive(0, SDL_APPINPUTFOCUS);
   352 
   353 #ifdef X_HAVE_UTF8_STRING
   354 		if ( SDL_IC != NULL ) {
   355 			pXUnsetICFocus(SDL_IC);
   356 		}
   357 #endif
   358 		/* Queue leaving fullscreen mode */
   359 		switch_waiting = 0x01;
   360 		switch_time = SDL_GetTicks() + 200;
   361 	    }
   362 	    break;
   363 
   364 	    /* Generated upon EnterWindow and FocusIn */
   365 	    case KeymapNotify: {
   366 #ifdef DEBUG_XEVENTS
   367 printf("KeymapNotify!\n");
   368 #endif
   369 		X11_SetKeyboardState(SDL_Display,  xevent.xkeymap.key_vector);
   370 	    }
   371 	    break;
   372 
   373 	    /* Mouse motion? */
   374 	    case MotionNotify: {
   375 		if ( SDL_VideoSurface ) {
   376 			if ( mouse_relative ) {
   377 				if ( using_dga & DGA_MOUSE ) {
   378 #ifdef DEBUG_MOTION
   379   printf("DGA motion: %d,%d\n", xevent.xmotion.x_root, xevent.xmotion.y_root);
   380 #endif
   381 					posted = SDL_PrivateMouseMotion(0, 1,
   382 							xevent.xmotion.x_root,
   383 							xevent.xmotion.y_root);
   384 				} else {
   385 					posted = X11_WarpedMotion(this,&xevent);
   386 				}
   387 			} else {
   388 #ifdef DEBUG_MOTION
   389   printf("X11 motion: %d,%d\n", xevent.xmotion.x, xevent.xmotion.y);
   390 #endif
   391 				posted = SDL_PrivateMouseMotion(0, 0,
   392 						xevent.xmotion.x,
   393 						xevent.xmotion.y);
   394 			}
   395 		}
   396 	    }
   397 	    break;
   398 
   399 	    /* Mouse button press? */
   400 	    case ButtonPress: {
   401 		posted = SDL_PrivateMouseButton(SDL_PRESSED, 
   402 					xevent.xbutton.button, 0, 0);
   403 	    }
   404 	    break;
   405 
   406 	    /* Mouse button release? */
   407 	    case ButtonRelease: {
   408 		posted = SDL_PrivateMouseButton(SDL_RELEASED, 
   409 					xevent.xbutton.button, 0, 0);
   410 	    }
   411 	    break;
   412 
   413 	    /* Key press? */
   414 	    case KeyPress: {
   415 		static SDL_keysym saved_keysym;
   416 		SDL_keysym keysym;
   417 		KeyCode keycode = xevent.xkey.keycode;
   418 
   419 #ifdef DEBUG_XEVENTS
   420 printf("KeyPress (X11 keycode = 0x%X)\n", xevent.xkey.keycode);
   421 #endif
   422 		/* Get the translated SDL virtual keysym */
   423 		if ( keycode ) {
   424 			keysym.scancode = keycode;
   425 			keysym.sym = X11_TranslateKeycode(SDL_Display, keycode);
   426 			keysym.mod = KMOD_NONE;
   427 			keysym.unicode = 0;
   428 		} else {
   429 			keysym = saved_keysym;
   430 		}
   431 
   432 		/* If we're not doing translation, we're done! */
   433 		if ( !SDL_TranslateUNICODE ) {
   434 			posted = SDL_PrivateKeyboard(SDL_PRESSED, &keysym);
   435 			break;
   436 		}
   437 
   438 		if ( pXFilterEvent(&xevent, None) ) {
   439 			if ( xevent.xkey.keycode ) {
   440 				posted = SDL_PrivateKeyboard(SDL_PRESSED, &keysym);
   441 			} else {
   442 				/* Save event to be associated with IM text
   443 				   In 1.3 we'll have a text event instead.. */
   444 				saved_keysym = keysym;
   445 			}
   446 			break;
   447 		}
   448 
   449 		/* Look up the translated value for the key event */
   450 #ifdef X_HAVE_UTF8_STRING
   451 		if ( SDL_IC != NULL ) {
   452 			static Status state;
   453 			/* A UTF-8 character can be at most 6 bytes */
   454 			char keybuf[6];
   455 			if ( pXutf8LookupString(SDL_IC, &xevent.xkey,
   456 			                        keybuf, sizeof(keybuf),
   457 			                        NULL, &state) ) {
   458 				keysym.unicode = Utf8ToUcs4((Uint8*)keybuf);
   459 			}
   460 		}
   461 		else
   462 #endif
   463 		{
   464 			static XComposeStatus state;
   465 			char keybuf[32];
   466 
   467 			if ( pXLookupString(&xevent.xkey,
   468 			                    keybuf, sizeof(keybuf),
   469 			                    NULL, &state) ) {
   470 				/*
   471 				* FIXME: XLookupString() may yield more than one
   472 				* character, so we need a mechanism to allow for
   473 				* this (perhaps null keypress events with a
   474 				* unicode value)
   475 				*/
   476 				keysym.unicode = (Uint8)keybuf[0];
   477 			}
   478 		}
   479 		posted = SDL_PrivateKeyboard(SDL_PRESSED, &keysym);
   480 	    }
   481 	    break;
   482 
   483 	    /* Key release? */
   484 	    case KeyRelease: {
   485 		SDL_keysym keysym;
   486 		KeyCode keycode = xevent.xkey.keycode;
   487 
   488 #ifdef DEBUG_XEVENTS
   489 printf("KeyRelease (X11 keycode = 0x%X)\n", xevent.xkey.keycode);
   490 #endif
   491 		/* Check to see if this is a repeated key */
   492 		if ( X11_KeyRepeat(SDL_Display, &xevent) ) {
   493 			break;
   494 		}
   495 
   496 		/* Get the translated SDL virtual keysym */
   497 		keysym.scancode = keycode;
   498 		keysym.sym = X11_TranslateKeycode(SDL_Display, keycode);
   499 		keysym.mod = KMOD_NONE;
   500 		keysym.unicode = 0;
   501 
   502 		posted = SDL_PrivateKeyboard(SDL_RELEASED, &keysym);
   503 	    }
   504 	    break;
   505 
   506 	    /* Have we been iconified? */
   507 	    case UnmapNotify: {
   508 #ifdef DEBUG_XEVENTS
   509 printf("UnmapNotify!\n");
   510 #endif
   511 		/* If we're active, make ourselves inactive */
   512 		if ( SDL_GetAppState() & SDL_APPACTIVE ) {
   513 			/* Swap out the gamma before we go inactive */
   514 			X11_SwapVidModeGamma(this);
   515 
   516 			/* Send an internal deactivate event */
   517 			posted = SDL_PrivateAppActive(0,
   518 					SDL_APPACTIVE|SDL_APPINPUTFOCUS);
   519 		}
   520 	    }
   521 	    break;
   522 
   523 	    /* Have we been restored? */
   524 	    case MapNotify: {
   525 #ifdef DEBUG_XEVENTS
   526 printf("MapNotify!\n");
   527 #endif
   528 		/* If we're not active, make ourselves active */
   529 		if ( !(SDL_GetAppState() & SDL_APPACTIVE) ) {
   530 			/* Send an internal activate event */
   531 			posted = SDL_PrivateAppActive(1, SDL_APPACTIVE);
   532 
   533 			/* Now that we're active, swap the gamma back */
   534 			X11_SwapVidModeGamma(this);
   535 		}
   536 
   537 		if ( SDL_VideoSurface &&
   538 		     (SDL_VideoSurface->flags & SDL_FULLSCREEN) ) {
   539 			X11_EnterFullScreen(this);
   540 		} else {
   541 			X11_GrabInputNoLock(this, this->input_grab);
   542 		}
   543 		X11_CheckMouseModeNoLock(this);
   544 
   545 		if ( SDL_VideoSurface ) {
   546 			X11_RefreshDisplay(this);
   547 		}
   548 	    }
   549 	    break;
   550 
   551 	    /* Have we been resized or moved? */
   552 	    case ConfigureNotify: {
   553 #ifdef DEBUG_XEVENTS
   554 printf("ConfigureNotify! (resize: %dx%d)\n", xevent.xconfigure.width, xevent.xconfigure.height);
   555 #endif
   556 		if ( SDL_VideoSurface ) {
   557 		    if ((xevent.xconfigure.width != SDL_VideoSurface->w) ||
   558 		        (xevent.xconfigure.height != SDL_VideoSurface->h)) {
   559 			/* FIXME: Find a better fix for the bug with KDE 1.2 */
   560 			if ( ! ((xevent.xconfigure.width == 32) &&
   561 			        (xevent.xconfigure.height == 32)) ) {
   562 				SDL_PrivateResize(xevent.xconfigure.width,
   563 				                  xevent.xconfigure.height);
   564 			}
   565 		    } else {
   566 			/* OpenGL windows need to know about the change */
   567 			if ( SDL_VideoSurface->flags & SDL_OPENGL ) {
   568 				SDL_PrivateExpose();
   569 			}
   570 		    }
   571 		}
   572 	    }
   573 	    break;
   574 
   575 	    /* Have we been requested to quit (or another client message?) */
   576 	    case ClientMessage: {
   577 		if ( (xevent.xclient.format == 32) &&
   578 		     (xevent.xclient.data.l[0] == WM_DELETE_WINDOW) )
   579 		{
   580 			posted = SDL_PrivateQuit();
   581 		} else
   582 		if ( SDL_ProcessEvents[SDL_SYSWMEVENT] == SDL_ENABLE ) {
   583 			SDL_SysWMmsg wmmsg;
   584 
   585 			SDL_VERSION(&wmmsg.version);
   586 			wmmsg.subsystem = SDL_SYSWM_X11;
   587 			wmmsg.event.xevent = xevent;
   588 			posted = SDL_PrivateSysWMEvent(&wmmsg);
   589 		}
   590 	    }
   591 	    break;
   592 
   593 	    /* Do we need to refresh ourselves? */
   594 	    case Expose: {
   595 #ifdef DEBUG_XEVENTS
   596 printf("Expose (count = %d)\n", xevent.xexpose.count);
   597 #endif
   598 		if ( SDL_VideoSurface && (xevent.xexpose.count == 0) ) {
   599 			X11_RefreshDisplay(this);
   600 		}
   601 	    }
   602 	    break;
   603 
   604 	    default: {
   605 #ifdef DEBUG_XEVENTS
   606 printf("Unhandled event %d\n", xevent.type);
   607 #endif
   608 		/* Only post the event if we're watching for it */
   609 		if ( SDL_ProcessEvents[SDL_SYSWMEVENT] == SDL_ENABLE ) {
   610 			SDL_SysWMmsg wmmsg;
   611 
   612 			SDL_VERSION(&wmmsg.version);
   613 			wmmsg.subsystem = SDL_SYSWM_X11;
   614 			wmmsg.event.xevent = xevent;
   615 			posted = SDL_PrivateSysWMEvent(&wmmsg);
   616 		}
   617 	    }
   618 	    break;
   619 	}
   620 	return(posted);
   621 }
   622 
   623 /* Ack!  XPending() actually performs a blocking read if no events available */
   624 int X11_Pending(Display *display)
   625 {
   626 	/* Flush the display connection and look to see if events are queued */
   627 	pXFlush(display);
   628 	if ( pXEventsQueued(display, QueuedAlready) ) {
   629 		return(1);
   630 	}
   631 
   632 	/* More drastic measures are required -- see if X is ready to talk */
   633 	{
   634 		static struct timeval zero_time;	/* static == 0 */
   635 		int x11_fd;
   636 		fd_set fdset;
   637 
   638 		x11_fd = ConnectionNumber(display);
   639 		FD_ZERO(&fdset);
   640 		FD_SET(x11_fd, &fdset);
   641 		if ( select(x11_fd+1, &fdset, NULL, NULL, &zero_time) == 1 ) {
   642 			return(pXPending(display));
   643 		}
   644 	}
   645 
   646 	/* Oh well, nothing is ready .. */
   647 	return(0);
   648 }
   649 
   650 void X11_PumpEvents(_THIS)
   651 {
   652 	int pending;
   653 
   654 	/* Keep processing pending events */
   655 	pending = 0;
   656 	while ( X11_Pending(SDL_Display) ) {
   657 		X11_DispatchEvent(this);
   658 		++pending;
   659 	}
   660 	if ( switch_waiting ) {
   661 		Uint32 now;
   662 
   663 		now  = SDL_GetTicks();
   664 		if ( pending || !SDL_VideoSurface ) {
   665 			/* Try again later... */
   666 			if ( switch_waiting & SDL_FULLSCREEN ) {
   667 				switch_time = now + 1500;
   668 			} else {
   669 				switch_time = now + 200;
   670 			}
   671 		} else if ( now >= switch_time ) {
   672 			Uint32 go_fullscreen;
   673 
   674 			go_fullscreen = switch_waiting & SDL_FULLSCREEN;
   675 			switch_waiting = 0;
   676 			if ( SDL_VideoSurface->flags & SDL_FULLSCREEN ) {
   677 				if ( go_fullscreen ) {
   678 					X11_EnterFullScreen(this);
   679 				} else {
   680 					X11_LeaveFullScreen(this);
   681 				}
   682 			}
   683 			/* Handle focus in/out when grabbed */
   684 			if ( go_fullscreen ) {
   685 				X11_GrabInputNoLock(this, this->input_grab);
   686 			} else {
   687 				X11_GrabInputNoLock(this, SDL_GRAB_OFF);
   688 			}
   689 			X11_CheckMouseModeNoLock(this);
   690 		}
   691 	}
   692 }
   693 
   694 void X11_InitKeymap(void)
   695 {
   696 	int i;
   697 
   698 	/* Odd keys used in international keyboards */
   699 	for ( i=0; i<SDL_TABLESIZE(ODD_keymap); ++i )
   700 		ODD_keymap[i] = SDLK_UNKNOWN;
   701 
   702  	/* Some of these might be mappable to an existing SDLK_ code */
   703  	ODD_keymap[XK_dead_grave&0xFF] = SDLK_COMPOSE;
   704  	ODD_keymap[XK_dead_acute&0xFF] = SDLK_COMPOSE;
   705  	ODD_keymap[XK_dead_tilde&0xFF] = SDLK_COMPOSE;
   706  	ODD_keymap[XK_dead_macron&0xFF] = SDLK_COMPOSE;
   707  	ODD_keymap[XK_dead_breve&0xFF] = SDLK_COMPOSE;
   708  	ODD_keymap[XK_dead_abovedot&0xFF] = SDLK_COMPOSE;
   709  	ODD_keymap[XK_dead_diaeresis&0xFF] = SDLK_COMPOSE;
   710  	ODD_keymap[XK_dead_abovering&0xFF] = SDLK_COMPOSE;
   711  	ODD_keymap[XK_dead_doubleacute&0xFF] = SDLK_COMPOSE;
   712  	ODD_keymap[XK_dead_caron&0xFF] = SDLK_COMPOSE;
   713  	ODD_keymap[XK_dead_cedilla&0xFF] = SDLK_COMPOSE;
   714  	ODD_keymap[XK_dead_ogonek&0xFF] = SDLK_COMPOSE;
   715  	ODD_keymap[XK_dead_iota&0xFF] = SDLK_COMPOSE;
   716  	ODD_keymap[XK_dead_voiced_sound&0xFF] = SDLK_COMPOSE;
   717  	ODD_keymap[XK_dead_semivoiced_sound&0xFF] = SDLK_COMPOSE;
   718  	ODD_keymap[XK_dead_belowdot&0xFF] = SDLK_COMPOSE;
   719 #ifdef XK_dead_hook
   720  	ODD_keymap[XK_dead_hook&0xFF] = SDLK_COMPOSE;
   721 #endif
   722 #ifdef XK_dead_horn
   723  	ODD_keymap[XK_dead_horn&0xFF] = SDLK_COMPOSE;
   724 #endif
   725 
   726 #ifdef XK_dead_circumflex
   727 	/* These X keysyms have 0xFE as the high byte */
   728 	ODD_keymap[XK_dead_circumflex&0xFF] = SDLK_CARET;
   729 #endif
   730 #ifdef XK_ISO_Level3_Shift
   731 	ODD_keymap[XK_ISO_Level3_Shift&0xFF] = SDLK_MODE; /* "Alt Gr" key */
   732 #endif
   733 
   734 	/* Map the miscellaneous keys */
   735 	for ( i=0; i<SDL_TABLESIZE(MISC_keymap); ++i )
   736 		MISC_keymap[i] = SDLK_UNKNOWN;
   737 
   738 	/* These X keysyms have 0xFF as the high byte */
   739 	MISC_keymap[XK_BackSpace&0xFF] = SDLK_BACKSPACE;
   740 	MISC_keymap[XK_Tab&0xFF] = SDLK_TAB;
   741 	MISC_keymap[XK_Clear&0xFF] = SDLK_CLEAR;
   742 	MISC_keymap[XK_Return&0xFF] = SDLK_RETURN;
   743 	MISC_keymap[XK_Pause&0xFF] = SDLK_PAUSE;
   744 	MISC_keymap[XK_Escape&0xFF] = SDLK_ESCAPE;
   745 	MISC_keymap[XK_Delete&0xFF] = SDLK_DELETE;
   746 
   747 	MISC_keymap[XK_KP_0&0xFF] = SDLK_KP0;		/* Keypad 0-9 */
   748 	MISC_keymap[XK_KP_1&0xFF] = SDLK_KP1;
   749 	MISC_keymap[XK_KP_2&0xFF] = SDLK_KP2;
   750 	MISC_keymap[XK_KP_3&0xFF] = SDLK_KP3;
   751 	MISC_keymap[XK_KP_4&0xFF] = SDLK_KP4;
   752 	MISC_keymap[XK_KP_5&0xFF] = SDLK_KP5;
   753 	MISC_keymap[XK_KP_6&0xFF] = SDLK_KP6;
   754 	MISC_keymap[XK_KP_7&0xFF] = SDLK_KP7;
   755 	MISC_keymap[XK_KP_8&0xFF] = SDLK_KP8;
   756 	MISC_keymap[XK_KP_9&0xFF] = SDLK_KP9;
   757 	MISC_keymap[XK_KP_Insert&0xFF] = SDLK_KP0;
   758 	MISC_keymap[XK_KP_End&0xFF] = SDLK_KP1;	
   759 	MISC_keymap[XK_KP_Down&0xFF] = SDLK_KP2;
   760 	MISC_keymap[XK_KP_Page_Down&0xFF] = SDLK_KP3;
   761 	MISC_keymap[XK_KP_Left&0xFF] = SDLK_KP4;
   762 	MISC_keymap[XK_KP_Begin&0xFF] = SDLK_KP5;
   763 	MISC_keymap[XK_KP_Right&0xFF] = SDLK_KP6;
   764 	MISC_keymap[XK_KP_Home&0xFF] = SDLK_KP7;
   765 	MISC_keymap[XK_KP_Up&0xFF] = SDLK_KP8;
   766 	MISC_keymap[XK_KP_Page_Up&0xFF] = SDLK_KP9;
   767 	MISC_keymap[XK_KP_Delete&0xFF] = SDLK_KP_PERIOD;
   768 	MISC_keymap[XK_KP_Decimal&0xFF] = SDLK_KP_PERIOD;
   769 	MISC_keymap[XK_KP_Divide&0xFF] = SDLK_KP_DIVIDE;
   770 	MISC_keymap[XK_KP_Multiply&0xFF] = SDLK_KP_MULTIPLY;
   771 	MISC_keymap[XK_KP_Subtract&0xFF] = SDLK_KP_MINUS;
   772 	MISC_keymap[XK_KP_Add&0xFF] = SDLK_KP_PLUS;
   773 	MISC_keymap[XK_KP_Enter&0xFF] = SDLK_KP_ENTER;
   774 	MISC_keymap[XK_KP_Equal&0xFF] = SDLK_KP_EQUALS;
   775 
   776 	MISC_keymap[XK_Up&0xFF] = SDLK_UP;
   777 	MISC_keymap[XK_Down&0xFF] = SDLK_DOWN;
   778 	MISC_keymap[XK_Right&0xFF] = SDLK_RIGHT;
   779 	MISC_keymap[XK_Left&0xFF] = SDLK_LEFT;
   780 	MISC_keymap[XK_Insert&0xFF] = SDLK_INSERT;
   781 	MISC_keymap[XK_Home&0xFF] = SDLK_HOME;
   782 	MISC_keymap[XK_End&0xFF] = SDLK_END;
   783 	MISC_keymap[XK_Page_Up&0xFF] = SDLK_PAGEUP;
   784 	MISC_keymap[XK_Page_Down&0xFF] = SDLK_PAGEDOWN;
   785 
   786 	MISC_keymap[XK_F1&0xFF] = SDLK_F1;
   787 	MISC_keymap[XK_F2&0xFF] = SDLK_F2;
   788 	MISC_keymap[XK_F3&0xFF] = SDLK_F3;
   789 	MISC_keymap[XK_F4&0xFF] = SDLK_F4;
   790 	MISC_keymap[XK_F5&0xFF] = SDLK_F5;
   791 	MISC_keymap[XK_F6&0xFF] = SDLK_F6;
   792 	MISC_keymap[XK_F7&0xFF] = SDLK_F7;
   793 	MISC_keymap[XK_F8&0xFF] = SDLK_F8;
   794 	MISC_keymap[XK_F9&0xFF] = SDLK_F9;
   795 	MISC_keymap[XK_F10&0xFF] = SDLK_F10;
   796 	MISC_keymap[XK_F11&0xFF] = SDLK_F11;
   797 	MISC_keymap[XK_F12&0xFF] = SDLK_F12;
   798 	MISC_keymap[XK_F13&0xFF] = SDLK_F13;
   799 	MISC_keymap[XK_F14&0xFF] = SDLK_F14;
   800 	MISC_keymap[XK_F15&0xFF] = SDLK_F15;
   801 
   802 	MISC_keymap[XK_Num_Lock&0xFF] = SDLK_NUMLOCK;
   803 	MISC_keymap[XK_Caps_Lock&0xFF] = SDLK_CAPSLOCK;
   804 	MISC_keymap[XK_Scroll_Lock&0xFF] = SDLK_SCROLLOCK;
   805 	MISC_keymap[XK_Shift_R&0xFF] = SDLK_RSHIFT;
   806 	MISC_keymap[XK_Shift_L&0xFF] = SDLK_LSHIFT;
   807 	MISC_keymap[XK_Control_R&0xFF] = SDLK_RCTRL;
   808 	MISC_keymap[XK_Control_L&0xFF] = SDLK_LCTRL;
   809 	MISC_keymap[XK_Alt_R&0xFF] = SDLK_RALT;
   810 	MISC_keymap[XK_Alt_L&0xFF] = SDLK_LALT;
   811 	MISC_keymap[XK_Meta_R&0xFF] = SDLK_RMETA;
   812 	MISC_keymap[XK_Meta_L&0xFF] = SDLK_LMETA;
   813 	MISC_keymap[XK_Super_L&0xFF] = SDLK_LSUPER; /* Left "Windows" */
   814 	MISC_keymap[XK_Super_R&0xFF] = SDLK_RSUPER; /* Right "Windows */
   815 	MISC_keymap[XK_Mode_switch&0xFF] = SDLK_MODE; /* "Alt Gr" key */
   816 	MISC_keymap[XK_Multi_key&0xFF] = SDLK_COMPOSE; /* Multi-key compose */
   817 
   818 	MISC_keymap[XK_Help&0xFF] = SDLK_HELP;
   819 	MISC_keymap[XK_Print&0xFF] = SDLK_PRINT;
   820 	MISC_keymap[XK_Sys_Req&0xFF] = SDLK_SYSREQ;
   821 	MISC_keymap[XK_Break&0xFF] = SDLK_BREAK;
   822 	MISC_keymap[XK_Menu&0xFF] = SDLK_MENU;
   823 	MISC_keymap[XK_Hyper_R&0xFF] = SDLK_MENU;   /* Windows "Menu" key */
   824 }
   825 
   826 /* Get the translated SDL virtual keysym */
   827 SDLKey X11_TranslateKeycode(Display *display, KeyCode kc)
   828 {
   829 	KeySym xsym;
   830 	SDLKey key;
   831 
   832 	xsym = pXKeycodeToKeysym(display, kc, 0);
   833 #ifdef DEBUG_KEYS
   834 	fprintf(stderr, "Translating key code %d -> 0x%.4x\n", kc, xsym);
   835 #endif
   836 	key = SDLK_UNKNOWN;
   837 	if ( xsym ) {
   838 		switch (xsym>>8) {
   839 		    case 0x1005FF:
   840 #ifdef SunXK_F36
   841 			if ( xsym == SunXK_F36 )
   842 				key = SDLK_F11;
   843 #endif
   844 #ifdef SunXK_F37
   845 			if ( xsym == SunXK_F37 )
   846 				key = SDLK_F12;
   847 #endif
   848 			break;
   849 		    case 0x00:	/* Latin 1 */
   850 			key = (SDLKey)(xsym & 0xFF);
   851 			break;
   852 		    case 0x01:	/* Latin 2 */
   853 		    case 0x02:	/* Latin 3 */
   854 		    case 0x03:	/* Latin 4 */
   855 		    case 0x04:	/* Katakana */
   856 		    case 0x05:	/* Arabic */
   857 		    case 0x06:	/* Cyrillic */
   858 		    case 0x07:	/* Greek */
   859 		    case 0x08:	/* Technical */
   860 		    case 0x0A:	/* Publishing */
   861 		    case 0x0C:	/* Hebrew */
   862 		    case 0x0D:	/* Thai */
   863 			/* These are wrong, but it's better than nothing */
   864 			key = (SDLKey)(xsym & 0xFF);
   865 			break;
   866 		    case 0xFE:
   867 			key = ODD_keymap[xsym&0xFF];
   868 			break;
   869 		    case 0xFF:
   870 			key = MISC_keymap[xsym&0xFF];
   871 			break;
   872 		    default:
   873 			/*
   874 			fprintf(stderr, "X11: Unhandled xsym, sym = 0x%04x\n",
   875 					(unsigned int)xsym);
   876 			*/
   877 			break;
   878 		}
   879 	} else {
   880 		/* X11 doesn't know how to translate the key! */
   881 		switch (kc) {
   882 		    /* Caution:
   883 		       These keycodes are from the Microsoft Keyboard
   884 		     */
   885 		    case 115:
   886 			key = SDLK_LSUPER;
   887 			break;
   888 		    case 116:
   889 			key = SDLK_RSUPER;
   890 			break;
   891 		    case 117:
   892 			key = SDLK_MENU;
   893 			break;
   894 		    default:
   895 			/*
   896 			 * no point in an error message; happens for
   897 			 * several keys when we get a keymap notify
   898 			 */
   899 			break;
   900 		}
   901 	}
   902 	return key;
   903 }
   904 
   905 /* X11 modifier masks for various keys */
   906 static unsigned meta_l_mask, meta_r_mask, alt_l_mask, alt_r_mask;
   907 static unsigned num_mask, mode_switch_mask;
   908 
   909 static void get_modifier_masks(Display *display)
   910 {
   911 	static unsigned got_masks;
   912 	int i, j;
   913 	XModifierKeymap *xmods;
   914 	unsigned n;
   915 
   916 	if(got_masks)
   917 		return;
   918 
   919 	xmods = pXGetModifierMapping(display);
   920 	n = xmods->max_keypermod;
   921 	for(i = 3; i < 8; i++) {
   922 		for(j = 0; j < n; j++) {
   923 			KeyCode kc = xmods->modifiermap[i * n + j];
   924 			KeySym ks = pXKeycodeToKeysym(display, kc, 0);
   925 			unsigned mask = 1 << i;
   926 			switch(ks) {
   927 			case XK_Num_Lock:
   928 				num_mask = mask; break;
   929 			case XK_Alt_L:
   930 				alt_l_mask = mask; break;
   931 			case XK_Alt_R:
   932 				alt_r_mask = mask; break;
   933 			case XK_Meta_L:
   934 				meta_l_mask = mask; break;
   935 			case XK_Meta_R:
   936 				meta_r_mask = mask; break;
   937 			case XK_Mode_switch:
   938 				mode_switch_mask = mask; break;
   939 			}
   940 		}
   941 	}
   942 	pXFreeModifiermap(xmods);
   943 	got_masks = 1;
   944 }
   945 
   946 
   947 /*
   948  * This function is semi-official; it is not officially exported and should
   949  * not be considered part of the SDL API, but may be used by client code
   950  * that *really* needs it (including legacy code).
   951  * It is slow, though, and should be avoided if possible.
   952  *
   953  * Note that it isn't completely accurate either; in particular, multi-key
   954  * sequences (dead accents, compose key sequences) will not work since the
   955  * state has been irrevocably lost.
   956  */
   957 Uint16 X11_KeyToUnicode(SDLKey keysym, SDLMod modifiers)
   958 {
   959 	struct SDL_VideoDevice *this = current_video;
   960 	char keybuf[32];
   961 	int i;
   962 	KeySym xsym = 0;
   963 	XKeyEvent xkey;
   964 	Uint16 unicode;
   965 
   966 	if ( !this || !SDL_Display ) {
   967 		return 0;
   968 	}
   969 
   970 	memset(&xkey, 0, sizeof(xkey));
   971 	xkey.display = SDL_Display;
   972 
   973 	xsym = keysym;		/* last resort if not found */
   974 	for (i = 0; i < 256; ++i) {
   975 		if ( MISC_keymap[i] == keysym ) {
   976 			xsym = 0xFF00 | i;
   977 			break;
   978 		} else if ( ODD_keymap[i] == keysym ) {
   979 			xsym = 0xFE00 | i;
   980 			break;
   981 		}
   982 	}
   983 
   984 	xkey.keycode = pXKeysymToKeycode(xkey.display, xsym);
   985 
   986 	get_modifier_masks(SDL_Display);
   987 	if(modifiers & KMOD_SHIFT)
   988 		xkey.state |= ShiftMask;
   989 	if(modifiers & KMOD_CAPS)
   990 		xkey.state |= LockMask;
   991 	if(modifiers & KMOD_CTRL)
   992 		xkey.state |= ControlMask;
   993 	if(modifiers & KMOD_MODE)
   994 		xkey.state |= mode_switch_mask;
   995 	if(modifiers & KMOD_LALT)
   996 		xkey.state |= alt_l_mask;
   997 	if(modifiers & KMOD_RALT)
   998 		xkey.state |= alt_r_mask;
   999 	if(modifiers & KMOD_LMETA)
  1000 		xkey.state |= meta_l_mask;
  1001 	if(modifiers & KMOD_RMETA)
  1002 		xkey.state |= meta_r_mask;
  1003 	if(modifiers & KMOD_NUM)
  1004 		xkey.state |= num_mask;
  1005 
  1006 	unicode = 0;
  1007 	if ( pXLookupString(&xkey, keybuf, sizeof(keybuf), NULL, NULL) )
  1008 		unicode = (unsigned char)keybuf[0];
  1009 	return(unicode);
  1010 }
  1011 
  1012 
  1013 /*
  1014  * Called when focus is regained, to read the keyboard state and generate
  1015  * synthetic keypress/release events.
  1016  * key_vec is a bit vector of keycodes (256 bits)
  1017  */
  1018 void X11_SetKeyboardState(Display *display, const char *key_vec)
  1019 {
  1020 	char keys_return[32];
  1021 	int i;
  1022 	Uint8 *kstate = SDL_GetKeyState(NULL);
  1023 	SDLMod modstate;
  1024 	Window junk_window;
  1025 	int x, y;
  1026 	unsigned int mask;
  1027 
  1028 	/* The first time the window is mapped, we initialize key state */
  1029 	if ( ! key_vec ) {
  1030 		pXQueryKeymap(display, keys_return);
  1031 		key_vec = keys_return;
  1032 	}
  1033 
  1034 	/* Get the keyboard modifier state */
  1035 	modstate = 0;
  1036 	get_modifier_masks(display);
  1037 	if ( pXQueryPointer(display, DefaultRootWindow(display),
  1038 		&junk_window, &junk_window, &x, &y, &x, &y, &mask) ) {
  1039 		if ( mask & LockMask ) {
  1040 			modstate |= KMOD_CAPS;
  1041 		}
  1042 		if ( mask & mode_switch_mask ) {
  1043 			modstate |= KMOD_MODE;
  1044 		}
  1045 		if ( mask & num_mask ) {
  1046 			modstate |= KMOD_NUM;
  1047 		}
  1048 	}
  1049 
  1050 	/* Zero the new keyboard state and generate it */
  1051 	memset(kstate, 0, SDLK_LAST);
  1052 	/*
  1053 	 * An obvious optimisation is to check entire longwords at a time in
  1054 	 * both loops, but we can't be sure the arrays are aligned so it's not
  1055 	 * worth the extra complexity
  1056 	 */
  1057 	for ( i = 0; i < 32; i++ ) {
  1058 		int j;
  1059 		if ( !key_vec[i] )
  1060 			continue;
  1061 		for ( j = 0; j < 8; j++ ) {
  1062 			if ( key_vec[i] & (1 << j) ) {
  1063 				SDLKey key;
  1064 				KeyCode kc = (i << 3 | j);
  1065 				key = X11_TranslateKeycode(display, kc);
  1066 				if ( key == SDLK_UNKNOWN ) {
  1067 					continue;
  1068 				}
  1069 				kstate[key] = SDL_PRESSED;
  1070 				switch (key) {
  1071 				    case SDLK_LSHIFT:
  1072 					modstate |= KMOD_LSHIFT;
  1073 					break;
  1074 				    case SDLK_RSHIFT:
  1075 					modstate |= KMOD_RSHIFT;
  1076 					break;
  1077 				    case SDLK_LCTRL:
  1078 					modstate |= KMOD_LCTRL;
  1079 					break;
  1080 				    case SDLK_RCTRL:
  1081 					modstate |= KMOD_RCTRL;
  1082 					break;
  1083 				    case SDLK_LALT:
  1084 					modstate |= KMOD_LALT;
  1085 					break;
  1086 				    case SDLK_RALT:
  1087 					modstate |= KMOD_RALT;
  1088 					break;
  1089 				    case SDLK_LMETA:
  1090 					modstate |= KMOD_LMETA;
  1091 					break;
  1092 				    case SDLK_RMETA:
  1093 					modstate |= KMOD_RMETA;
  1094 					break;
  1095 				    default:
  1096 					break;
  1097 				}
  1098 			}
  1099 		}
  1100 	}
  1101 
  1102 	/* Hack - set toggle key state */
  1103 	if ( modstate & KMOD_CAPS ) {
  1104 		kstate[SDLK_CAPSLOCK] = SDL_PRESSED;
  1105 	} else {
  1106 		kstate[SDLK_CAPSLOCK] = SDL_RELEASED;
  1107 	}
  1108 	if ( modstate & KMOD_NUM ) {
  1109 		kstate[SDLK_NUMLOCK] = SDL_PRESSED;
  1110 	} else {
  1111 		kstate[SDLK_NUMLOCK] = SDL_RELEASED;
  1112 	}
  1113 
  1114 	/* Set the final modifier state */
  1115 	SDL_SetModState(modstate);
  1116 }
  1117 
  1118 void X11_InitOSKeymap(_THIS)
  1119 {
  1120 	X11_InitKeymap();
  1121 }
  1122