src/video/x11/SDL_x11events.c

/* [<][>]
[^][v][top][bottom][index][help] */

FUNCTIONS

This source file includes following functions.
  1. X11_KeyRepeat
  2. X11_WarpedMotion
  3. X11_DispatchEvent
  4. X11_Pending
  5. X11_PumpEvents
  6. X11_InitKeymap
  7. X11_TranslateKey
  8. get_modifier_masks
  9. X11_KeyToUnicode
  10. X11_SetKeyboardState
  11. X11_InitOSKeymap

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

/* [<][>][^][v][top][bottom][index][help] */