src/video/x11/SDL_x11events.c
author Sam Lantinga <slouken@lokigames.com>
Tue, 19 Jun 2001 13:33:54 +0000
changeset 75 b0ae59d0f3ee
parent 14 c3e9d4a623c1
child 82 2bddc38a9f5d
permissions -rw-r--r--
Added patches from FreeBSD ports
     1 /*
     2     SDL - Simple DirectMedia Layer
     3     Copyright (C) 1997, 1998, 1999, 2000, 2001  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@devolution.com
    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, 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 ( XPending(display) ) {
    78 		XPeekEvent(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 			XNextEvent(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 ( XCheckTypedEvent(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 		XWarpPointer(SDL_Display, None, SDL_Window, 0, 0, 0, 0,
   131 					mouse_last.x, mouse_last.y);
   132 		for ( i=0; i<10; ++i ) {
   133         		XMaskEvent(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 	XNextEvent(SDL_Display, &xevent);
   163 
   164 	posted = 0;
   165 	switch (xevent.type) {
   166 
   167 	    /* Gaining mouse coverage? */
   168 	    case EnterNotify: {
   169 #ifdef DEBUG_XEVENTS
   170 printf("EnterNotify!\n");
   171 if ( xevent.xcrossing.mode == NotifyGrab )
   172 printf("Mode: NotifyGrab\n");
   173 if ( xevent.xcrossing.mode == NotifyUngrab )
   174 printf("Mode: NotifyUngrab\n");
   175 #endif
   176 		if ( (xevent.xcrossing.mode != NotifyGrab) &&
   177 		     (xevent.xcrossing.mode != NotifyUngrab) ) {
   178 			posted = SDL_PrivateAppActive(1, SDL_APPMOUSEFOCUS);
   179 		}
   180 	    }
   181 	    break;
   182 
   183 	    /* Losing mouse coverage? */
   184 	    case LeaveNotify: {
   185 #ifdef DEBUG_XEVENTS
   186 printf("LeaveNotify!\n");
   187 if ( xevent.xcrossing.mode == NotifyGrab )
   188 printf("Mode: NotifyGrab\n");
   189 if ( xevent.xcrossing.mode == NotifyUngrab )
   190 printf("Mode: NotifyUngrab\n");
   191 #endif
   192 		if ( (xevent.xcrossing.mode != NotifyGrab) &&
   193 		     (xevent.xcrossing.mode != NotifyUngrab) ) {
   194 			posted = SDL_PrivateAppActive(0, SDL_APPMOUSEFOCUS);
   195 		}
   196 	    }
   197 	    break;
   198 
   199 	    /* Gaining input focus? */
   200 	    case FocusIn: {
   201 #ifdef DEBUG_XEVENTS
   202 printf("FocusIn!\n");
   203 #endif
   204 		posted = SDL_PrivateAppActive(1, SDL_APPINPUTFOCUS);
   205 
   206 		/* Queue entry into fullscreen mode */
   207 		switch_waiting = 0x01 | SDL_FULLSCREEN;
   208 		switch_time = SDL_GetTicks() + 1500;
   209 	    }
   210 	    break;
   211 
   212 	    /* Losing input focus? */
   213 	    case FocusOut: {
   214 #ifdef DEBUG_XEVENTS
   215 printf("FocusOut!\n");
   216 #endif
   217 		posted = SDL_PrivateAppActive(0, SDL_APPINPUTFOCUS);
   218 
   219 		/* Queue leaving fullscreen mode */
   220 		switch_waiting = 0x01;
   221 		switch_time = SDL_GetTicks() + 200;
   222 	    }
   223 	    break;
   224 
   225 	    /* Generated upon EnterWindow and FocusIn */
   226 	    case KeymapNotify: {
   227 #ifdef DEBUG_XEVENTS
   228 printf("KeymapNotify!\n");
   229 #endif
   230 		X11_SetKeyboardState(SDL_Display, xevent.xkeymap.key_vector);
   231 	    }
   232 	    break;
   233 
   234 	    /* Mouse motion? */
   235 	    case MotionNotify: {
   236 		if ( SDL_VideoSurface ) {
   237 			if ( mouse_relative ) {
   238 				if ( using_dga & DGA_MOUSE ) {
   239 #ifdef DEBUG_MOTION
   240   printf("DGA motion: %d,%d\n", xevent.xmotion.x_root, xevent.xmotion.y_root);
   241 #endif
   242 					posted = SDL_PrivateMouseMotion(0, 1,
   243 							xevent.xmotion.x_root,
   244 							xevent.xmotion.y_root);
   245 				} else {
   246 					posted = X11_WarpedMotion(this,&xevent);
   247 				}
   248 			} else {
   249 				posted = SDL_PrivateMouseMotion(0, 0,
   250 						xevent.xmotion.x,
   251 						xevent.xmotion.y);
   252 			}
   253 		}
   254 	    }
   255 	    break;
   256 
   257 	    /* Mouse button press? */
   258 	    case ButtonPress: {
   259 		posted = SDL_PrivateMouseButton(SDL_PRESSED, 
   260 					xevent.xbutton.button, 0, 0);
   261 	    }
   262 	    break;
   263 
   264 	    /* Mouse button release? */
   265 	    case ButtonRelease: {
   266 		posted = SDL_PrivateMouseButton(SDL_RELEASED, 
   267 					xevent.xbutton.button, 0, 0);
   268 	    }
   269 	    break;
   270 
   271 	    /* Key press? */
   272 	    case KeyPress: {
   273 		SDL_keysym keysym;
   274 
   275 #ifdef DEBUG_XEVENTS
   276 printf("KeyPress (X11 keycode = 0x%X)\n", xevent.xkey.keycode);
   277 #endif
   278 		posted = SDL_PrivateKeyboard(SDL_PRESSED,
   279 				X11_TranslateKey(SDL_Display, &xevent.xkey,
   280 						 xevent.xkey.keycode,
   281 						 &keysym));
   282 	    }
   283 	    break;
   284 
   285 	    /* Key release? */
   286 	    case KeyRelease: {
   287 		SDL_keysym keysym;
   288 
   289 #ifdef DEBUG_XEVENTS
   290 printf("KeyRelease (X11 keycode = 0x%X)\n", xevent.xkey.keycode);
   291 #endif
   292 		/* Check to see if this is a repeated key */
   293 		if ( ! X11_KeyRepeat(SDL_Display, &xevent) ) {
   294 			posted = SDL_PrivateKeyboard(SDL_RELEASED, 
   295 				X11_TranslateKey(SDL_Display, &xevent.xkey,
   296 						 xevent.xkey.keycode,
   297 						 &keysym));
   298 		}
   299 	    }
   300 	    break;
   301 
   302 	    /* Have we been iconified? */
   303 	    case UnmapNotify: {
   304 #ifdef DEBUG_XEVENTS
   305 printf("UnmapNotify!\n");
   306 #endif
   307 		/* If we're active, make ourselves inactive */
   308 		if ( SDL_GetAppState() & SDL_APPACTIVE ) {
   309 			/* Swap out the gamma before we go inactive */
   310 			X11_SwapVidModeGamma(this);
   311 
   312 			/* Send an internal deactivate event */
   313 			posted = SDL_PrivateAppActive(0,
   314 					SDL_APPACTIVE|SDL_APPINPUTFOCUS);
   315 		}
   316 	    }
   317 	    break;
   318 
   319 	    /* Have we been restored? */
   320 	    case MapNotify: {
   321 #ifdef DEBUG_XEVENTS
   322 printf("MapNotify!\n");
   323 #endif
   324 		/* If we're not active, make ourselves active */
   325 		if ( !(SDL_GetAppState() & SDL_APPACTIVE) ) {
   326 			/* Send an internal activate event */
   327 			posted = SDL_PrivateAppActive(1, SDL_APPACTIVE);
   328 
   329 			/* Now that we're active, swap the gamma back */
   330 			X11_SwapVidModeGamma(this);
   331 		}
   332 
   333 		if ( SDL_VideoSurface &&
   334 		     (SDL_VideoSurface->flags & SDL_FULLSCREEN) ) {
   335 #ifdef GRAB_FULLSCREEN
   336 			X11_EnterFullScreen(this);
   337 #else
   338 			/* Queue entry into fullscreen mode */
   339 			switch_waiting = 0x01 | SDL_FULLSCREEN;
   340 			switch_time = SDL_GetTicks() + 1500;
   341 #endif
   342 		} else {
   343 			X11_GrabInputNoLock(this, this->input_grab);
   344 		}
   345 		X11_CheckMouseModeNoLock(this);
   346 
   347 		if ( SDL_VideoSurface ) {
   348 			X11_RefreshDisplay(this);
   349 		}
   350 	    }
   351 	    break;
   352 
   353 	    /* Have we been resized or moved? */
   354 	    case ConfigureNotify: {
   355 #ifdef DEBUG_XEVENTS
   356 printf("ConfigureNotify! (resize: %dx%d)\n", xevent.xconfigure.width, xevent.xconfigure.height);
   357 #endif
   358 		if ( SDL_VideoSurface ) {
   359 		    if ((xevent.xconfigure.width != SDL_VideoSurface->w) ||
   360 		        (xevent.xconfigure.height != SDL_VideoSurface->h)) {
   361 			/* FIXME: Find a better fix for the bug with KDE 1.2 */
   362 			if ( ! ((xevent.xconfigure.width == 32) &&
   363 			        (xevent.xconfigure.height == 32)) ) {
   364 				SDL_PrivateResize(xevent.xconfigure.width,
   365 				                  xevent.xconfigure.height);
   366 			}
   367 		    } else {
   368 			/* OpenGL windows need to know about the change */
   369 			if ( SDL_VideoSurface->flags & SDL_OPENGL ) {
   370 				SDL_PrivateExpose();
   371 			}
   372 		    }
   373 		}
   374 	    }
   375 	    break;
   376 
   377 	    /* Have we been requested to quit (or another client message?) */
   378 	    case ClientMessage: {
   379 		if ( (xevent.xclient.format == 32) &&
   380 		     (xevent.xclient.data.l[0] == WM_DELETE_WINDOW) )
   381 		{
   382 			posted = SDL_PrivateQuit();
   383 		} else
   384 		if ( SDL_ProcessEvents[SDL_SYSWMEVENT] == SDL_ENABLE ) {
   385 			SDL_SysWMmsg wmmsg;
   386 
   387 			SDL_VERSION(&wmmsg.version);
   388 			wmmsg.subsystem = SDL_SYSWM_X11;
   389 			wmmsg.event.xevent = xevent;
   390 			posted = SDL_PrivateSysWMEvent(&wmmsg);
   391 		}
   392 	    }
   393 	    break;
   394 
   395 	    /* Do we need to refresh ourselves? */
   396 	    case Expose: {
   397 #ifdef DEBUG_XEVENTS
   398 printf("Expose (count = %d)\n", xevent.xexpose.count);
   399 #endif
   400 		if ( SDL_VideoSurface && (xevent.xexpose.count == 0) ) {
   401 			if ( SDL_VideoSurface->flags & SDL_OPENGL ) {
   402 				SDL_PrivateExpose();
   403 			} else {
   404 				X11_RefreshDisplay(this);
   405 			}
   406 		}
   407 	    }
   408 	    break;
   409 
   410 	    default: {
   411 #ifdef DEBUG_XEVENTS
   412 printf("Unhandled event %d\n", xevent.type);
   413 #endif
   414 		/* Only post the event if we're watching for it */
   415 		if ( SDL_ProcessEvents[SDL_SYSWMEVENT] == SDL_ENABLE ) {
   416 			SDL_SysWMmsg wmmsg;
   417 
   418 			SDL_VERSION(&wmmsg.version);
   419 			wmmsg.subsystem = SDL_SYSWM_X11;
   420 			wmmsg.event.xevent = xevent;
   421 			posted = SDL_PrivateSysWMEvent(&wmmsg);
   422 		}
   423 	    }
   424 	    break;
   425 	}
   426 	return(posted);
   427 }
   428 
   429 /* Ack!  XPending() actually performs a blocking read if no events available */
   430 int X11_Pending(Display *display)
   431 {
   432 	/* Flush the display connection and look to see if events are queued */
   433 	XFlush(display);
   434 	if ( XEventsQueued(display, QueuedAlready) ) {
   435 		return(1);
   436 	}
   437 
   438 	/* More drastic measures are required -- see if X is ready to talk */
   439 	{
   440 		static struct timeval zero_time;	/* static == 0 */
   441 		int x11_fd;
   442 		fd_set fdset;
   443 
   444 		x11_fd = ConnectionNumber(display);
   445 		FD_ZERO(&fdset);
   446 		FD_SET(x11_fd, &fdset);
   447 		if ( select(x11_fd+1, &fdset, NULL, NULL, &zero_time) == 1 ) {
   448 			return(XPending(display));
   449 		}
   450 	}
   451 
   452 	/* Oh well, nothing is ready .. */
   453 	return(0);
   454 }
   455 
   456 void X11_PumpEvents(_THIS)
   457 {
   458 	int pending;
   459 
   460 	/* Keep processing pending events */
   461 	pending = 0;
   462 	while ( X11_Pending(SDL_Display) ) {
   463 		X11_DispatchEvent(this);
   464 		++pending;
   465 	}
   466 	if ( switch_waiting ) {
   467 		Uint32 now;
   468 
   469 		now  = SDL_GetTicks();
   470 		if ( pending || !SDL_VideoSurface ) {
   471 			/* Try again later... */
   472 			if ( switch_waiting & SDL_FULLSCREEN ) {
   473 				switch_time = now + 1500;
   474 			} else {
   475 				switch_time = now + 200;
   476 			}
   477 		} else if ( now >= switch_time ) {
   478 			Uint32 go_fullscreen;
   479 
   480 			go_fullscreen = switch_waiting & SDL_FULLSCREEN;
   481 			switch_waiting = 0;
   482 			if ( SDL_VideoSurface->flags & SDL_FULLSCREEN ) {
   483 				if ( go_fullscreen ) {
   484 					X11_EnterFullScreen(this);
   485 				} else {
   486 					X11_LeaveFullScreen(this);
   487 				}
   488 			}
   489 			/* Handle focus in/out when grabbed */
   490 			if ( go_fullscreen ) {
   491 				X11_GrabInputNoLock(this, this->input_grab);
   492 			} else {
   493 				X11_GrabInputNoLock(this, SDL_GRAB_OFF);
   494 			}
   495 			X11_CheckMouseModeNoLock(this);
   496 		}
   497 	}
   498 }
   499 
   500 void X11_InitKeymap(void)
   501 {
   502 	int i;
   503 
   504 	/* Odd keys used in international keyboards */
   505 	for ( i=0; i<SDL_TABLESIZE(ODD_keymap); ++i )
   506 		ODD_keymap[i] = SDLK_UNKNOWN;
   507 
   508 #ifdef XK_dead_circumflex
   509 	/* These X keysyms have 0xFE as the high byte */
   510 	ODD_keymap[XK_dead_circumflex&0xFF] = SDLK_CARET;
   511 #endif
   512 
   513 	/* Map the miscellaneous keys */
   514 	for ( i=0; i<SDL_TABLESIZE(MISC_keymap); ++i )
   515 		MISC_keymap[i] = SDLK_UNKNOWN;
   516 
   517 	/* These X keysyms have 0xFF as the high byte */
   518 	MISC_keymap[XK_BackSpace&0xFF] = SDLK_BACKSPACE;
   519 	MISC_keymap[XK_Tab&0xFF] = SDLK_TAB;
   520 	MISC_keymap[XK_Clear&0xFF] = SDLK_CLEAR;
   521 	MISC_keymap[XK_Return&0xFF] = SDLK_RETURN;
   522 	MISC_keymap[XK_Pause&0xFF] = SDLK_PAUSE;
   523 	MISC_keymap[XK_Escape&0xFF] = SDLK_ESCAPE;
   524 	MISC_keymap[XK_Delete&0xFF] = SDLK_DELETE;
   525 
   526 	MISC_keymap[XK_KP_0&0xFF] = SDLK_KP0;		/* Keypad 0-9 */
   527 	MISC_keymap[XK_KP_1&0xFF] = SDLK_KP1;
   528 	MISC_keymap[XK_KP_2&0xFF] = SDLK_KP2;
   529 	MISC_keymap[XK_KP_3&0xFF] = SDLK_KP3;
   530 	MISC_keymap[XK_KP_4&0xFF] = SDLK_KP4;
   531 	MISC_keymap[XK_KP_5&0xFF] = SDLK_KP5;
   532 	MISC_keymap[XK_KP_6&0xFF] = SDLK_KP6;
   533 	MISC_keymap[XK_KP_7&0xFF] = SDLK_KP7;
   534 	MISC_keymap[XK_KP_8&0xFF] = SDLK_KP8;
   535 	MISC_keymap[XK_KP_9&0xFF] = SDLK_KP9;
   536 	MISC_keymap[XK_KP_Insert&0xFF] = SDLK_KP0;
   537 	MISC_keymap[XK_KP_End&0xFF] = SDLK_KP1;	
   538 	MISC_keymap[XK_KP_Down&0xFF] = SDLK_KP2;
   539 	MISC_keymap[XK_KP_Page_Down&0xFF] = SDLK_KP3;
   540 	MISC_keymap[XK_KP_Left&0xFF] = SDLK_KP4;
   541 	MISC_keymap[XK_KP_Begin&0xFF] = SDLK_KP5;
   542 	MISC_keymap[XK_KP_Right&0xFF] = SDLK_KP6;
   543 	MISC_keymap[XK_KP_Home&0xFF] = SDLK_KP7;
   544 	MISC_keymap[XK_KP_Up&0xFF] = SDLK_KP8;
   545 	MISC_keymap[XK_KP_Page_Up&0xFF] = SDLK_KP9;
   546 	MISC_keymap[XK_KP_Delete&0xFF] = SDLK_KP_PERIOD;
   547 	MISC_keymap[XK_KP_Decimal&0xFF] = SDLK_KP_PERIOD;
   548 	MISC_keymap[XK_KP_Divide&0xFF] = SDLK_KP_DIVIDE;
   549 	MISC_keymap[XK_KP_Multiply&0xFF] = SDLK_KP_MULTIPLY;
   550 	MISC_keymap[XK_KP_Subtract&0xFF] = SDLK_KP_MINUS;
   551 	MISC_keymap[XK_KP_Add&0xFF] = SDLK_KP_PLUS;
   552 	MISC_keymap[XK_KP_Enter&0xFF] = SDLK_KP_ENTER;
   553 	MISC_keymap[XK_KP_Equal&0xFF] = SDLK_KP_EQUALS;
   554 
   555 	MISC_keymap[XK_Up&0xFF] = SDLK_UP;
   556 	MISC_keymap[XK_Down&0xFF] = SDLK_DOWN;
   557 	MISC_keymap[XK_Right&0xFF] = SDLK_RIGHT;
   558 	MISC_keymap[XK_Left&0xFF] = SDLK_LEFT;
   559 	MISC_keymap[XK_Insert&0xFF] = SDLK_INSERT;
   560 	MISC_keymap[XK_Home&0xFF] = SDLK_HOME;
   561 	MISC_keymap[XK_End&0xFF] = SDLK_END;
   562 	MISC_keymap[XK_Page_Up&0xFF] = SDLK_PAGEUP;
   563 	MISC_keymap[XK_Page_Down&0xFF] = SDLK_PAGEDOWN;
   564 
   565 	MISC_keymap[XK_F1&0xFF] = SDLK_F1;
   566 	MISC_keymap[XK_F2&0xFF] = SDLK_F2;
   567 	MISC_keymap[XK_F3&0xFF] = SDLK_F3;
   568 	MISC_keymap[XK_F4&0xFF] = SDLK_F4;
   569 	MISC_keymap[XK_F5&0xFF] = SDLK_F5;
   570 	MISC_keymap[XK_F6&0xFF] = SDLK_F6;
   571 	MISC_keymap[XK_F7&0xFF] = SDLK_F7;
   572 	MISC_keymap[XK_F8&0xFF] = SDLK_F8;
   573 	MISC_keymap[XK_F9&0xFF] = SDLK_F9;
   574 	MISC_keymap[XK_F10&0xFF] = SDLK_F10;
   575 	MISC_keymap[XK_F11&0xFF] = SDLK_F11;
   576 	MISC_keymap[XK_F12&0xFF] = SDLK_F12;
   577 	MISC_keymap[XK_F13&0xFF] = SDLK_F13;
   578 	MISC_keymap[XK_F14&0xFF] = SDLK_F14;
   579 	MISC_keymap[XK_F15&0xFF] = SDLK_F15;
   580 
   581 	MISC_keymap[XK_Num_Lock&0xFF] = SDLK_NUMLOCK;
   582 	MISC_keymap[XK_Caps_Lock&0xFF] = SDLK_CAPSLOCK;
   583 	MISC_keymap[XK_Scroll_Lock&0xFF] = SDLK_SCROLLOCK;
   584 	MISC_keymap[XK_Shift_R&0xFF] = SDLK_RSHIFT;
   585 	MISC_keymap[XK_Shift_L&0xFF] = SDLK_LSHIFT;
   586 	MISC_keymap[XK_Control_R&0xFF] = SDLK_RCTRL;
   587 	MISC_keymap[XK_Control_L&0xFF] = SDLK_LCTRL;
   588 	MISC_keymap[XK_Alt_R&0xFF] = SDLK_RALT;
   589 	MISC_keymap[XK_Alt_L&0xFF] = SDLK_LALT;
   590 	MISC_keymap[XK_Meta_R&0xFF] = SDLK_RMETA;
   591 	MISC_keymap[XK_Meta_L&0xFF] = SDLK_LMETA;
   592 	MISC_keymap[XK_Super_L&0xFF] = SDLK_LSUPER; /* Left "Windows" */
   593 	MISC_keymap[XK_Super_R&0xFF] = SDLK_RSUPER; /* Right "Windows */
   594 	MISC_keymap[XK_Mode_switch&0xFF] = SDLK_MODE; /* "Alt Gr" key */
   595 	MISC_keymap[XK_Multi_key&0xFF] = SDLK_COMPOSE; /* Multi-key compose */
   596 
   597 	MISC_keymap[XK_Help&0xFF] = SDLK_HELP;
   598 	MISC_keymap[XK_Print&0xFF] = SDLK_PRINT;
   599 	MISC_keymap[XK_Sys_Req&0xFF] = SDLK_SYSREQ;
   600 	MISC_keymap[XK_Break&0xFF] = SDLK_BREAK;
   601 	MISC_keymap[XK_Menu&0xFF] = SDLK_MENU;
   602 	MISC_keymap[XK_Hyper_R&0xFF] = SDLK_MENU;   /* Windows "Menu" key */
   603 }
   604 
   605 SDL_keysym *X11_TranslateKey(Display *display, XKeyEvent *xkey, KeyCode kc,
   606 			     SDL_keysym *keysym)
   607 {
   608 	KeySym xsym;
   609 
   610 	/* Get the raw keyboard scancode */
   611 	keysym->scancode = kc;
   612 	xsym = XKeycodeToKeysym(display, kc, 0);
   613 #ifdef DEBUG_KEYS
   614 	fprintf(stderr, "Translating key 0x%.4x (%d)\n", xsym, kc);
   615 #endif
   616 	/* Get the translated SDL virtual keysym */
   617 	keysym->sym = SDLK_UNKNOWN;
   618 	if ( xsym ) {
   619 		switch (xsym>>8) {
   620 			case 0x1005FF:
   621 #ifdef SunXK_F36
   622 				if ( xsym == SunXK_F36 )
   623 					keysym->sym = SDLK_F11;
   624 #endif
   625 #ifdef SunXK_F37
   626 				if ( xsym == SunXK_F37 )
   627 					keysym->sym = SDLK_F12;
   628 #endif
   629 				break;
   630 			case 0x00:	/* Latin 1 */
   631 			case 0x01:	/* Latin 2 */
   632 			case 0x02:	/* Latin 3 */
   633 			case 0x03:	/* Latin 4 */
   634 			case 0x04:	/* Katakana */
   635 			case 0x05:	/* Arabic */
   636 			case 0x06:	/* Cyrillic */
   637 			case 0x07:	/* Greek */
   638 			case 0x08:	/* Technical */
   639 			case 0x0A:	/* Publishing */
   640 			case 0x0C:	/* Hebrew */
   641 			case 0x0D:	/* Thai */
   642 				keysym->sym = (SDLKey)(xsym&0xFF);
   643 				/* Map capital letter syms to lowercase */
   644 				if ((keysym->sym >= 'A')&&(keysym->sym <= 'Z'))
   645 					keysym->sym += ('a'-'A');
   646 				break;
   647 			case 0xFE:
   648 				keysym->sym = ODD_keymap[xsym&0xFF];
   649 				break;
   650 			case 0xFF:
   651 				keysym->sym = MISC_keymap[xsym&0xFF];
   652 				break;
   653 			default:
   654 				fprintf(stderr,
   655 					"X11: Unknown xsym, sym = 0x%04x\n",
   656 					(unsigned int)xsym);
   657 				break;
   658 		}
   659 	} else {
   660 		/* X11 doesn't know how to translate the key! */
   661 		switch (kc) {
   662 			/* Caution:
   663 			   These keycodes are from the Microsoft Keyboard
   664 			 */
   665 			case 115:
   666 				keysym->sym = SDLK_LSUPER;
   667 				break;
   668 			case 116:
   669 				keysym->sym = SDLK_RSUPER;
   670 				break;
   671 			case 117:
   672 				keysym->sym = SDLK_MENU;
   673 				break;
   674 			default:
   675 				/*
   676 				 * no point in an error message; happens for
   677 				 * several keys when we get a keymap notify
   678 				 */
   679 				break;
   680 		}
   681 	}
   682 	keysym->mod = KMOD_NONE;
   683 
   684 	/* If UNICODE is on, get the UNICODE value for the key */
   685 	keysym->unicode = 0;
   686 	if ( SDL_TranslateUNICODE && xkey ) {
   687 		static XComposeStatus state;
   688 		/* Until we handle the IM protocol, use XLookupString() */
   689 		unsigned char keybuf[32];
   690 
   691 #define BROKEN_XFREE86_INTERNATIONAL_KBD
   692 /* This appears to be a magical flag that is used with AltGr on
   693    international keyboards to signal alternate key translations.
   694    The flag doesn't show up when in fullscreen mode (?)
   695    FIXME:  Check to see if this code is safe for other servers.
   696 */
   697 #ifdef BROKEN_XFREE86_INTERNATIONAL_KBD
   698 		/* Work around what appears to be a bug in XFree86 */
   699 		if ( SDL_GetModState() & KMOD_MODE ) {
   700 			xkey->state |= (1<<13);
   701 		}
   702 #endif
   703 		/* Look up the translated value for the key event */
   704 		if ( XLookupString(xkey, (char *)keybuf, sizeof(keybuf),
   705 							NULL, &state) ) {
   706 			/*
   707 			 * FIXME,: XLookupString() may yield more than one
   708 			 * character, so we need a mechanism to allow for
   709 			 * this (perhaps generate null keypress events with
   710 			 * a unicode value)
   711 			 */
   712 			keysym->unicode = keybuf[0];
   713 		}
   714 	}
   715 	return(keysym);
   716 }
   717 
   718 /* X11 modifier masks for various keys */
   719 static unsigned meta_l_mask, meta_r_mask, alt_l_mask, alt_r_mask;
   720 static unsigned num_mask, mode_switch_mask;
   721 
   722 static void get_modifier_masks(Display *display)
   723 {
   724 	static unsigned got_masks;
   725 	int i, j;
   726 	XModifierKeymap *xmods;
   727 	unsigned n;
   728 
   729 	if(got_masks)
   730 		return;
   731 
   732 	xmods = XGetModifierMapping(display);
   733 	n = xmods->max_keypermod;
   734 	for(i = 3; i < 8; i++) {
   735 		for(j = 0; j < n; j++) {
   736 			KeyCode kc = xmods->modifiermap[i * n + j];
   737 			KeySym ks = XKeycodeToKeysym(display, kc, 0);
   738 			unsigned mask = 1 << i;
   739 			switch(ks) {
   740 			case XK_Num_Lock:
   741 				num_mask = mask; break;
   742 			case XK_Alt_L:
   743 				alt_l_mask = mask; break;
   744 			case XK_Alt_R:
   745 				alt_r_mask = mask; break;
   746 			case XK_Meta_L:
   747 				meta_l_mask = mask; break;
   748 			case XK_Meta_R:
   749 				meta_r_mask = mask; break;
   750 			case XK_Mode_switch:
   751 				mode_switch_mask = mask; break;
   752 			}
   753 		}
   754 	}
   755 	XFreeModifiermap(xmods);
   756 	got_masks = 1;
   757 }
   758 
   759 
   760 /*
   761  * This function is semi-official; it is not officially exported and should
   762  * not be considered part of the SDL API, but may be used by client code
   763  * that *really* needs it (including legacy code).
   764  * It is slow, though, and should be avoided if possible.
   765  *
   766  * Note that it isn't completely accurate either; in particular, multi-key
   767  * sequences (dead accents, compose key sequences) will not work since the
   768  * state has been irrevocably lost.
   769  */
   770 Uint16 X11_KeyToUnicode(SDLKey keysym, SDLMod modifiers)
   771 {
   772 	struct SDL_VideoDevice *this = current_video;
   773 	char keybuf[32];
   774 	int i;
   775 	KeySym xsym = 0;
   776 	XKeyEvent xkey;
   777 	Uint16 unicode;
   778 
   779 	if ( !this || !SDL_Display ) {
   780 		return 0;
   781 	}
   782 
   783 	memset(&xkey, 0, sizeof(xkey));
   784 	xkey.display = SDL_Display;
   785 
   786 	xsym = keysym;		/* last resort if not found */
   787 	for (i = 0; i < 256; ++i) {
   788 		if ( MISC_keymap[i] == keysym ) {
   789 			xsym = 0xFF00 | i;
   790 			break;
   791 		} else if ( ODD_keymap[i] == keysym ) {
   792 			xsym = 0xFE00 | i;
   793 			break;
   794 		}
   795 	}
   796 
   797 	xkey.keycode = XKeysymToKeycode(xkey.display, xsym);
   798 
   799 	get_modifier_masks(SDL_Display);
   800 	if(modifiers & KMOD_SHIFT)
   801 		xkey.state |= ShiftMask;
   802 	if(modifiers & KMOD_CAPS)
   803 		xkey.state |= LockMask;
   804 	if(modifiers & KMOD_CTRL)
   805 		xkey.state |= ControlMask;
   806 	if(modifiers & KMOD_MODE)
   807 		xkey.state |= mode_switch_mask;
   808 	if(modifiers & KMOD_LALT)
   809 		xkey.state |= alt_l_mask;
   810 	if(modifiers & KMOD_RALT)
   811 		xkey.state |= alt_r_mask;
   812 	if(modifiers & KMOD_LMETA)
   813 		xkey.state |= meta_l_mask;
   814 	if(modifiers & KMOD_RMETA)
   815 		xkey.state |= meta_r_mask;
   816 	if(modifiers & KMOD_NUM)
   817 		xkey.state |= num_mask;
   818 
   819 	unicode = 0;
   820 	if ( XLookupString(&xkey, keybuf, sizeof(keybuf), NULL, NULL) )
   821 		unicode = (unsigned char)keybuf[0];
   822 	return(unicode);
   823 }
   824 
   825 /*
   826  * Called when focus is regained, to read the keyboard state and generate
   827  * synthetic keypress/release events.
   828  * key_vec is a bit vector of keycodes (256 bits)
   829  */
   830 void X11_SetKeyboardState(Display *display, const char *key_vec)
   831 {
   832 	char keys_return[32];
   833 	int i, gen_event;
   834 	KeyCode xcode[SDLK_LAST];
   835 	Uint8 new_kstate[SDLK_LAST];
   836 	Uint8 *kstate = SDL_GetKeyState(NULL);
   837 
   838 	/* The first time the window is mapped, we initialize key state */
   839 	if ( ! key_vec ) {
   840 		key_vec = keys_return;
   841 		XQueryKeymap(display, keys_return);
   842 		gen_event = 0;
   843 	} else {
   844 		gen_event = 1;
   845 	}
   846 
   847 	/* Zero the new state and generate it */
   848 	memset(new_kstate, 0, sizeof(new_kstate));
   849 	/*
   850 	 * An obvious optimisation is to check entire longwords at a time in
   851 	 * both loops, but we can't be sure the arrays are aligned so it's not
   852 	 * worth the extra complexity
   853 	 */
   854 	for(i = 0; i < 32; i++) {
   855 		int j;
   856 		if(!key_vec[i])
   857 			continue;
   858 		for(j = 0; j < 8; j++) {
   859 			if(key_vec[i] & (1 << j)) {
   860 				SDL_keysym sk;
   861 				KeyCode kc = i << 3 | j;
   862 				X11_TranslateKey(display, NULL, kc, &sk);
   863 				new_kstate[sk.sym] = 1;
   864 				xcode[sk.sym] = kc;
   865 			}
   866 		}
   867 	}
   868 	for(i = SDLK_FIRST+1; i < SDLK_LAST; i++) {
   869 		int st;
   870 		SDL_keysym sk;
   871 
   872 		if(kstate[i] == new_kstate[i])
   873 			continue;
   874 		/*
   875 		 * Send a fake keyboard event correcting the difference between
   876 		 * SDL's keyboard state and the actual. Note that there is no
   877 		 * way to find out the scancode for key releases, but since all
   878 		 * keys are released when focus is lost only keypresses should
   879 		 * be sent here
   880 		 */
   881 		st = new_kstate[i] ? SDL_PRESSED : SDL_RELEASED;
   882 		memset(&sk, 0, sizeof(sk));
   883 		sk.sym = i;
   884 		sk.scancode = xcode[i];		/* only valid for key press */
   885 		if ( gen_event ) {
   886 			SDL_PrivateKeyboard(st, &sk);
   887 		} else {
   888 			kstate[i] = new_kstate[i];
   889 		}
   890 	}
   891 }
   892 
   893 void X11_InitOSKeymap(_THIS)
   894 {
   895 	X11_InitKeymap();
   896 }
   897