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