src/video/x11/SDL_x11events.c
author Ryan C. Gordon <icculus@icculus.org>
Mon, 21 Nov 2005 00:16:34 +0000
changeset 1178 9867f3d86e44
parent 1168 045f186426e1
child 1179 abb4267e7028
permissions -rw-r--r--
Real Unicode support for X11. Based on updated version of this patch:
http://lists.arabeyes.org/archives/developer/2004/June/msg00160.html

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