1 /* 2 SDL - Simple DirectMedia Layer 3 Copyright (C) 1997-2012 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 (at) libsdl.org 21 */ 22 #include "SDL_config.h" 23 24 /* Handle the event stream, converting X11 events into SDL events */ 25 26 #include <setjmp.h> 27 #include <X11/Xlib.h> 28 #include <X11/Xutil.h> 29 #include <X11/keysym.h> 30 #ifdef __SVR4 31 #include <X11/Sunkeysym.h> 32 #endif 33 #include <sys/types.h> 34 #include <sys/time.h> 35 #include <unistd.h> 36 37 #include "SDL_timer.h" 38 #include "SDL_syswm.h" 39 #include "../SDL_sysvideo.h" 40 #include "../../events/SDL_sysevents.h" 41 #include "../../events/SDL_events_c.h" 42 #include "SDL_x11video.h" 43 #include "SDL_x11dga_c.h" 44 #include "SDL_x11modes_c.h" 45 #include "SDL_x11image_c.h" 46 #include "SDL_x11gamma_c.h" 47 #include "SDL_x11wm_c.h" 48 #include "SDL_x11mouse_c.h" 49 #include "SDL_x11events_c.h" 50 51 52 /* Define this if you want to debug X11 events */ 53 /*#define DEBUG_XEVENTS*/ 54 55 /* The translation tables from an X11 keysym to a SDL keysym */ 56 static SDLKey ODD_keymap[256]; 57 static SDLKey MISC_keymap[256]; 58 SDLKey X11_TranslateKeycode(Display *display, KeyCode kc); 59 60 /* 61 Pending resize target for ConfigureNotify (so outdated events don't 62 cause inappropriate resize events) 63 */ 64 int X11_PendingConfigureNotifyWidth = -1; 65 int X11_PendingConfigureNotifyHeight = -1; 66 67 #ifdef X_HAVE_UTF8_STRING 68 Uint32 Utf8ToUcs4(const Uint8 *utf8) 69 { 70 Uint32 c; 71 int i = 1; 72 int noOctets = 0; 73 int firstOctetMask = 0; 74 unsigned char firstOctet = utf8[0]; 75 if (firstOctet < 0x80) { 76 /* 77 Characters in the range: 78 00000000 to 01111111 (ASCII Range) 79 are stored in one octet: 80 0xxxxxxx (The same as its ASCII representation) 81 The least 6 significant bits of the first octet is the most 6 significant nonzero bits 82 of the UCS4 representation. 83 */ 84 noOctets = 1; 85 firstOctetMask = 0x7F; /* 0(1111111) - The most significant bit is ignored */ 86 } else if ((firstOctet & 0xE0) /* get the most 3 significant bits by AND'ing with 11100000 */ 87 == 0xC0 ) { /* see if those 3 bits are 110. If so, the char is in this range */ 88 /* 89 Characters in the range: 90 00000000 10000000 to 00000111 11111111 91 are stored in two octets: 92 110xxxxx 10xxxxxx 93 The least 5 significant bits of the first octet is the most 5 significant nonzero bits 94 of the UCS4 representation. 95 */ 96 noOctets = 2; 97 firstOctetMask = 0x1F; /* 000(11111) - The most 3 significant bits are ignored */ 98 } else if ((firstOctet & 0xF0) /* get the most 4 significant bits by AND'ing with 11110000 */ 99 == 0xE0) { /* see if those 4 bits are 1110. If so, the char is in this range */ 100 /* 101 Characters in the range: 102 00001000 00000000 to 11111111 11111111 103 are stored in three octets: 104 1110xxxx 10xxxxxx 10xxxxxx 105 The least 4 significant bits of the first octet is the most 4 significant nonzero bits 106 of the UCS4 representation. 107 */ 108 noOctets = 3; 109 firstOctetMask = 0x0F; /* 0000(1111) - The most 4 significant bits are ignored */ 110 } else if ((firstOctet & 0xF8) /* get the most 5 significant bits by AND'ing with 11111000 */ 111 == 0xF0) { /* see if those 5 bits are 11110. If so, the char is in this range */ 112 /* 113 Characters in the range: 114 00000001 00000000 00000000 to 00011111 11111111 11111111 115 are stored in four octets: 116 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx 117 The least 3 significant bits of the first octet is the most 3 significant nonzero bits 118 of the UCS4 representation. 119 */ 120 noOctets = 4; 121 firstOctetMask = 0x07; /* 11110(111) - The most 5 significant bits are ignored */ 122 } else if ((firstOctet & 0xFC) /* get the most 6 significant bits by AND'ing with 11111100 */ 123 == 0xF8) { /* see if those 6 bits are 111110. If so, the char is in this range */ 124 /* 125 Characters in the range: 126 00000000 00100000 00000000 00000000 to 127 00000011 11111111 11111111 11111111 128 are stored in five octets: 129 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 130 The least 2 significant bits of the first octet is the most 2 significant nonzero bits 131 of the UCS4 representation. 132 */ 133 noOctets = 5; 134 firstOctetMask = 0x03; /* 111110(11) - The most 6 significant bits are ignored */ 135 } else if ((firstOctet & 0xFE) /* get the most 7 significant bits by AND'ing with 11111110 */ 136 == 0xFC) { /* see if those 7 bits are 1111110. If so, the char is in this range */ 137 /* 138 Characters in the range: 139 00000100 00000000 00000000 00000000 to 140 01111111 11111111 11111111 11111111 141 are stored in six octets: 142 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 143 The least significant bit of the first octet is the most significant nonzero bit 144 of the UCS4 representation. 145 */ 146 noOctets = 6; 147 firstOctetMask = 0x01; /* 1111110(1) - The most 7 significant bits are ignored */ 148 } else 149 return 0; /* The given chunk is not a valid UTF-8 encoded Unicode character */ 150 151 /* 152 The least noOctets significant bits of the first octet is the most 2 significant nonzero bits 153 of the UCS4 representation. 154 The first 6 bits of the UCS4 representation is the least 8-noOctets-1 significant bits of 155 firstOctet if the character is not ASCII. If so, it's the least 7 significant bits of firstOctet. 156 This done by AND'ing firstOctet with its mask to trim the bits used for identifying the 157 number of continuing octets (if any) and leave only the free bits (the x's) 158 Sample: 159 1-octet: 0xxxxxxx & 01111111 = 0xxxxxxx 160 2-octets: 110xxxxx & 00011111 = 000xxxxx 161 */ 162 c = firstOctet & firstOctetMask; 163 164 /* Now, start filling c.ucs4 with the bits from the continuing octets from utf8. */ 165 for (i = 1; i < noOctets; i++) { 166 /* A valid continuing octet is of the form 10xxxxxx */ 167 if ((utf8[i] & 0xC0) /* get the most 2 significant bits by AND'ing with 11000000 */ 168 != 0x80) /* see if those 2 bits are 10. If not, the is a malformed sequence. */ 169 /*The given chunk is a partial sequence at the end of a string that could 170 begin a valid character */ 171 return 0; 172 173 /* Make room for the next 6-bits */ 174 c <<= 6; 175 176 /* 177 Take only the least 6 significance bits of the current octet (utf8[i]) and fill the created room 178 of c.ucs4 with them. 179 This done by AND'ing utf8[i] with 00111111 and the OR'ing the result with c.ucs4. 180 */ 181 c |= utf8[i] & 0x3F; 182 } 183 return c; 184 } 185 186 /* Given a UTF-8 encoded string pointed to by utf8 of length length in 187 bytes, returns the corresponding UTF-16 encoded string in the 188 buffer pointed to by utf16. The maximum number of UTF-16 encoding 189 units (i.e., Unit16s) allowed in the buffer is specified in 190 utf16_max_length. The return value is the number of UTF-16 191 encoding units placed in the output buffer pointed to by utf16. 192 193 In case of an error, -1 is returned, leaving some unusable partial 194 results in the output buffer. 195 196 The caller must estimate the size of utf16 buffer by itself before 197 calling this function. Insufficient output buffer is considered as 198 an error, and once an error occured, this function doesn't give any 199 clue how large the result will be. 200 201 The error cases include following: 202 203 - Invalid byte sequences were in the input UTF-8 bytes. The caller 204 has no way to know what point in the input buffer was the 205 errornous byte. 206 207 - The input contained a character (a valid UTF-8 byte sequence) 208 whose scalar value exceeded the range that UTF-16 can represent 209 (i.e., characters whose Unicode scalar value above 0x110000). 210 211 - The output buffer has no enough space to hold entire utf16 data. 212 213 Please note: 214 215 - '\0'-termination is not assumed both on the input UTF-8 string 216 and on the output UTF-16 string; any legal zero byte in the input 217 UTF-8 string will be converted to a 16-bit zero in output. As a 218 side effect, the last UTF-16 encoding unit stored in the output 219 buffer will have a non-zero value if the input UTF-8 was not 220 '\0'-terminated. 221 222 - UTF-8 aliases are *not* considered as an error. They are 223 converted to UTF-16. For example, 0xC0 0xA0, 0xE0 0x80 0xA0, 224 and 0xF0 0x80 0x80 0xA0 are all mapped to a single UTF-16 225 encoding unit 0x0020. 226 227 - Three byte UTF-8 sequences whose value corresponds to a surrogate 228 code or other reserved scalar value are not considered as an 229 error either. They may cause an invalid UTF-16 data (e.g., those 230 containing unpaired surrogates). 231 232 */ 233 234 static int Utf8ToUtf16(const Uint8 *utf8, const int utf8_length, Uint16 *utf16, const int utf16_max_length) { 235 236 /* p moves over the output buffer. max_ptr points to the next to the last slot of the buffer. */ 237 Uint16 *p = utf16; 238 Uint16 const *const max_ptr = utf16 + utf16_max_length; 239 240 /* end_of_input points to the last byte of input as opposed to the next to the last byte. */ 241 Uint8 const *const end_of_input = utf8 + utf8_length - 1; 242 243 while (utf8 <= end_of_input) { 244 Uint8 const c = *utf8; 245 if (p >= max_ptr) { 246 /* No more output space. */ 247 return -1; 248 } 249 if (c < 0x80) { 250 /* One byte ASCII. */ 251 *p++ = c; 252 utf8 += 1; 253 } else if (c < 0xC0) { 254 /* Follower byte without preceeding leader bytes. */ 255 return -1; 256 } else if (c < 0xE0) { 257 /* Two byte sequence. We need one follower byte. */ 258 if (end_of_input - utf8 < 1 || (((utf8[1] ^ 0x80)) & 0xC0)) { 259 return -1; 260 } 261 *p++ = (Uint16)(0xCF80 + (c << 6) + utf8[1]); 262 utf8 += 2; 263 } else if (c < 0xF0) { 264 /* Three byte sequence. We need two follower byte. */ 265 if (end_of_input - utf8 < 2 || (((utf8[1] ^ 0x80) | (utf8[2] ^ 0x80)) & 0xC0)) { 266 return -1; 267 } 268 *p++ = (Uint16)(0xDF80 + (c << 12) + (utf8[1] << 6) + utf8[2]); 269 utf8 += 3; 270 } else if (c < 0xF8) { 271 int plane; 272 /* Four byte sequence. We need three follower bytes. */ 273 if (end_of_input - utf8 < 3 || (((utf8[1] ^ 0x80) | (utf8[2] ^0x80) | (utf8[3] ^ 0x80)) & 0xC0)) { 274 return -1; 275 } 276 plane = (-0xC8 + (c << 2) + (utf8[1] >> 4)); 277 if (plane == 0) { 278 /* This four byte sequence is an alias that 279 corresponds to a Unicode scalar value in BMP. 280 It fits in an UTF-16 encoding unit. */ 281 *p++ = (Uint16)(0xDF80 + (utf8[1] << 12) + (utf8[2] << 6) + utf8[3]); 282 } else if (plane <= 16) { 283 /* This is a legal four byte sequence that corresponds to a surrogate pair. */ 284 if (p + 1 >= max_ptr) { 285 /* No enough space on the output buffer for the pair. */ 286 return -1; 287 } 288 *p++ = (Uint16)(0xE5B8 + (c << 8) + (utf8[1] << 2) + (utf8[2] >> 4)); 289 *p++ = (Uint16)(0xDB80 + ((utf8[2] & 0x0F) << 6) + utf8[3]); 290 } else { 291 /* This four byte sequence is out of UTF-16 code space. */ 292 return -1; 293 } 294 utf8 += 4; 295 } else { 296 /* Longer sequence or unused byte. */ 297 return -1; 298 } 299 } 300 return p - utf16; 301 } 302 303 #endif 304 305 /* Check to see if this is a repeated key. 306 (idea shamelessly lifted from GII -- thanks guys! :) 307 */ 308 static int X11_KeyRepeat(Display *display, XEvent *event) 309 { 310 XEvent peekevent; 311 int repeated; 312 313 repeated = 0; 314 if ( XPending(display) ) { 315 XPeekEvent(display, &peekevent); 316 if ( (peekevent.type == KeyPress) && 317 (peekevent.xkey.keycode == event->xkey.keycode) && 318 ((peekevent.xkey.time-event->xkey.time) < 2) ) { 319 repeated = 1; 320 XNextEvent(display, &peekevent); 321 } 322 } 323 return(repeated); 324 } 325 326 /* Note: The X server buffers and accumulates mouse motion events, so 327 the motion event generated by the warp may not appear exactly as we 328 expect it to. We work around this (and improve performance) by only 329 warping the pointer when it reaches the edge, and then wait for it. 330 */ 331 #define MOUSE_FUDGE_FACTOR 8 332 333 static __inline__ int X11_WarpedMotion(_THIS, XEvent *xevent) 334 { 335 int w, h, i; 336 int deltax, deltay; 337 int posted; 338 339 w = SDL_VideoSurface->w; 340 h = SDL_VideoSurface->h; 341 deltax = xevent->xmotion.x - mouse_last.x; 342 deltay = xevent->xmotion.y - mouse_last.y; 343 #ifdef DEBUG_MOTION 344 printf("Warped mouse motion: %d,%d\n", deltax, deltay); 345 #endif 346 mouse_last.x = xevent->xmotion.x; 347 mouse_last.y = xevent->xmotion.y; 348 posted = SDL_PrivateMouseMotion(0, 1, deltax, deltay); 349 350 if ( (xevent->xmotion.x < MOUSE_FUDGE_FACTOR) || 351 (xevent->xmotion.x > (w-MOUSE_FUDGE_FACTOR)) || 352 (xevent->xmotion.y < MOUSE_FUDGE_FACTOR) || 353 (xevent->xmotion.y > (h-MOUSE_FUDGE_FACTOR)) ) { 354 /* Get the events that have accumulated */ 355 while ( XCheckTypedEvent(SDL_Display, MotionNotify, xevent) ) { 356 deltax = xevent->xmotion.x - mouse_last.x; 357 deltay = xevent->xmotion.y - mouse_last.y; 358 #ifdef DEBUG_MOTION 359 printf("Extra mouse motion: %d,%d\n", deltax, deltay); 360 #endif 361 mouse_last.x = xevent->xmotion.x; 362 mouse_last.y = xevent->xmotion.y; 363 posted += SDL_PrivateMouseMotion(0, 1, deltax, deltay); 364 } 365 mouse_last.x = w/2; 366 mouse_last.y = h/2; 367 XWarpPointer(SDL_Display, None, SDL_Window, 0, 0, 0, 0, 368 mouse_last.x, mouse_last.y); 369 for ( i=0; i<10; ++i ) { 370 XMaskEvent(SDL_Display, PointerMotionMask, xevent); 371 if ( (xevent->xmotion.x > 372 (mouse_last.x-MOUSE_FUDGE_FACTOR)) && 373 (xevent->xmotion.x < 374 (mouse_last.x+MOUSE_FUDGE_FACTOR)) && 375 (xevent->xmotion.y > 376 (mouse_last.y-MOUSE_FUDGE_FACTOR)) && 377 (xevent->xmotion.y < 378 (mouse_last.y+MOUSE_FUDGE_FACTOR)) ) { 379 break; 380 } 381 #ifdef DEBUG_XEVENTS 382 printf("Lost mouse motion: %d,%d\n", xevent->xmotion.x, xevent->xmotion.y); 383 #endif 384 } 385 #ifdef DEBUG_XEVENTS 386 if ( i == 10 ) { 387 printf("Warning: didn't detect mouse warp motion\n"); 388 } 389 #endif 390 } 391 return(posted); 392 } 393 394 static int X11_DispatchEvent(_THIS) 395 { 396 int posted; 397 XEvent xevent; 398 399 SDL_memset(&xevent, '\0', sizeof (XEvent)); /* valgrind fix. --ryan. */ 400 XNextEvent(SDL_Display, &xevent); 401 402 /* Discard KeyRelease and KeyPress events generated by auto-repeat. 403 We need to do it before passing event to XFilterEvent. Otherwise, 404 KeyRelease aware IMs are confused... */ 405 if ( xevent.type == KeyRelease 406 && X11_KeyRepeat(SDL_Display, &xevent) ) { 407 return 0; 408 } 409 410 #ifdef X_HAVE_UTF8_STRING 411 /* If we are translating with IM, we need to pass all events 412 to XFilterEvent, and discard those filtered events immediately. */ 413 if ( SDL_TranslateUNICODE 414 && SDL_IM != NULL 415 && XFilterEvent(&xevent, None) ) { 416 return 0; 417 } 418 #endif 419 420 posted = 0; 421 switch (xevent.type) { 422 423 /* Gaining mouse coverage? */ 424 case EnterNotify: { 425 #ifdef DEBUG_XEVENTS 426 printf("EnterNotify! (%d,%d)\n", xevent.xcrossing.x, xevent.xcrossing.y); 427 if ( xevent.xcrossing.mode == NotifyGrab ) 428 printf("Mode: NotifyGrab\n"); 429 if ( xevent.xcrossing.mode == NotifyUngrab ) 430 printf("Mode: NotifyUngrab\n"); 431 #endif 432 if ( this->input_grab == SDL_GRAB_OFF ) { 433 posted = SDL_PrivateAppActive(1, SDL_APPMOUSEFOCUS); 434 } 435 posted = SDL_PrivateMouseMotion(0, 0, 436 xevent.xcrossing.x, 437 xevent.xcrossing.y); 438 } 439 break; 440 441 /* Losing mouse coverage? */ 442 case LeaveNotify: { 443 #ifdef DEBUG_XEVENTS 444 printf("LeaveNotify! (%d,%d)\n", xevent.xcrossing.x, xevent.xcrossing.y); 445 if ( xevent.xcrossing.mode == NotifyGrab ) 446 printf("Mode: NotifyGrab\n"); 447 if ( xevent.xcrossing.mode == NotifyUngrab ) 448 printf("Mode: NotifyUngrab\n"); 449 #endif 450 if ( (xevent.xcrossing.mode != NotifyGrab) && 451 (xevent.xcrossing.mode != NotifyUngrab) && 452 (xevent.xcrossing.detail != NotifyInferior) ) { 453 if ( this->input_grab == SDL_GRAB_OFF ) { 454 posted = SDL_PrivateAppActive(0, SDL_APPMOUSEFOCUS); 455 } else { 456 posted = SDL_PrivateMouseMotion(0, 0, 457 xevent.xcrossing.x, 458 xevent.xcrossing.y); 459 } 460 } 461 } 462 break; 463 464 /* Gaining input focus? */ 465 case FocusIn: { 466 #ifdef DEBUG_XEVENTS 467 printf("FocusIn!\n"); 468 #endif 469 posted = SDL_PrivateAppActive(1, SDL_APPINPUTFOCUS); 470 471 #ifdef X_HAVE_UTF8_STRING 472 if ( SDL_IC != NULL ) { 473 XSetICFocus(SDL_IC); 474 } 475 #endif 476 /* Queue entry into fullscreen mode */ 477 switch_waiting = 0x01 | SDL_FULLSCREEN; 478 switch_time = SDL_GetTicks() + 1500; 479 } 480 break; 481 482 /* Losing input focus? */ 483 case FocusOut: { 484 #ifdef DEBUG_XEVENTS 485 printf("FocusOut!\n"); 486 #endif 487 posted = SDL_PrivateAppActive(0, SDL_APPINPUTFOCUS); 488 489 #ifdef X_HAVE_UTF8_STRING 490 if ( SDL_IC != NULL ) { 491 XUnsetICFocus(SDL_IC); 492 } 493 #endif 494 /* Queue leaving fullscreen mode */ 495 switch_waiting = 0x01; 496 switch_time = SDL_GetTicks() + 200; 497 } 498 break; 499 500 #ifdef X_HAVE_UTF8_STRING 501 /* Some IM requires MappingNotify to be passed to 502 XRefreshKeyboardMapping by the app. */ 503 case MappingNotify: { 504 XRefreshKeyboardMapping(&xevent.xmapping); 505 } 506 break; 507 #endif /* X_HAVE_UTF8_STRING */ 508 509 /* Generated upon EnterWindow and FocusIn */ 510 case KeymapNotify: { 511 #ifdef DEBUG_XEVENTS 512 printf("KeymapNotify!\n"); 513 #endif 514 X11_SetKeyboardState(SDL_Display, xevent.xkeymap.key_vector); 515 } 516 break; 517 518 /* Mouse motion? */ 519 case MotionNotify: { 520 if ( SDL_VideoSurface ) { 521 if ( mouse_relative ) { 522 if ( using_dga & DGA_MOUSE ) { 523 #ifdef DEBUG_MOTION 524 printf("DGA motion: %d,%d\n", xevent.xmotion.x_root, xevent.xmotion.y_root); 525 #endif 526 posted = SDL_PrivateMouseMotion(0, 1, 527 xevent.xmotion.x_root, 528 xevent.xmotion.y_root); 529 } else { 530 posted = X11_WarpedMotion(this,&xevent); 531 } 532 } else { 533 #ifdef DEBUG_MOTION 534 printf("X11 motion: %d,%d\n", xevent.xmotion.x, xevent.xmotion.y); 535 #endif 536 posted = SDL_PrivateMouseMotion(0, 0, 537 xevent.xmotion.x, 538 xevent.xmotion.y); 539 } 540 } 541 } 542 break; 543 544 /* Mouse button press? */ 545 case ButtonPress: { 546 posted = SDL_PrivateMouseButton(SDL_PRESSED, 547 xevent.xbutton.button, 0, 0); 548 } 549 break; 550 551 /* Mouse button release? */ 552 case ButtonRelease: { 553 posted = SDL_PrivateMouseButton(SDL_RELEASED, 554 xevent.xbutton.button, 0, 0); 555 } 556 break; 557 558 /* Key press? */ 559 case KeyPress: { 560 SDL_keysym keysym; 561 KeyCode keycode = xevent.xkey.keycode; 562 563 #ifdef DEBUG_XEVENTS 564 printf("KeyPress (X11 keycode = 0x%X)\n", xevent.xkey.keycode); 565 #endif 566 /* If we're not doing translation, we're done! */ 567 if ( !SDL_TranslateUNICODE ) { 568 /* Get the translated SDL virtual keysym and put it on the queue.*/ 569 keysym.scancode = keycode; 570 keysym.sym = X11_TranslateKeycode(SDL_Display, keycode); 571 keysym.mod = KMOD_NONE; 572 keysym.unicode = 0; 573 posted = SDL_PrivateKeyboard(SDL_PRESSED, &keysym); 574 break; 575 } 576 577 /* Look up the translated value for the key event */ 578 #ifdef X_HAVE_UTF8_STRING 579 if ( SDL_IC != NULL ) { 580 Status status; 581 KeySym xkeysym; 582 int i; 583 /* A UTF-8 character can be at most 6 bytes */ 584 /* ... It's true, but Xutf8LookupString can 585 return more than one characters. Moreover, 586 the spec. put no upper bound, so we should 587 be ready for longer strings. */ 588 char keybuf[32]; 589 char *keydata = keybuf; 590 int count; 591 Uint16 utf16buf[32]; 592 Uint16 *utf16data = utf16buf; 593 int utf16size; 594 int utf16length; 595 596 count = Xutf8LookupString(SDL_IC, &xevent.xkey, keydata, sizeof(keybuf), &xkeysym, &status); 597 if (XBufferOverflow == status) { 598 /* The IM has just generated somewhat long 599 string. We need a longer buffer in this 600 case. */ 601 keydata = SDL_malloc(count); 602 if ( keydata == NULL ) { 603 SDL_OutOfMemory(); 604 break; 605 } 606 count = Xutf8LookupString(SDL_IC, &xevent.xkey, keydata, count, &xkeysym, &status); 607 } 608 609 switch (status) { 610 611 case XBufferOverflow: { 612 /* Oops! We have allocated the bytes as 613 requested by Xutf8LookupString, so the 614 length of the buffer must be 615 sufficient. This case should never 616 happen! */ 617 SDL_SetError("Xutf8LookupString indicated a double buffer overflow!"); 618 break; 619 } 620 621 case XLookupChars: 622 case XLookupBoth: { 623 if (0 == count) { 624 break; 625 } 626 627 /* We got a converted string from IM. Make 628 sure to deliver all characters to the 629 application as SDL events. Note that 630 an SDL event can only carry one UTF-16 631 encoding unit, and a surrogate pair is 632 delivered as two SDL events. I guess 633 this behaviour is probably _imported_ 634 from Windows or MacOS. To do so, we need 635 to convert the UTF-8 data into UTF-16 636 data (not UCS4/UTF-32!). We need an 637 estimate of the number of UTF-16 encoding 638 units here. The worst case is pure ASCII 639 string. Assume so. */ 640 /* In 1.3 SDL may have a text event instead, that 641 carries the whole UTF-8 string with it. */ 642 utf16size = count * sizeof(Uint16); 643 if (utf16size > sizeof(utf16buf)) { 644 utf16data = (Uint16 *) SDL_malloc(utf16size); 645 if (utf16data == NULL) { 646 SDL_OutOfMemory(); 647 break; 648 } 649 } 650 utf16length = Utf8ToUtf16((Uint8 *)keydata, count, utf16data, utf16size); 651 if (utf16length < 0) { 652 /* The keydata contained an invalid byte 653 sequence. It should be a bug of the IM 654 or Xlib... */ 655 SDL_SetError("Oops! Xutf8LookupString returned an invalid UTF-8 sequence!"); 656 break; 657 } 658 659 /* Deliver all UTF-16 encoding units. At 660 this moment, SDL event queue has a 661 fixed size (128 events), and an SDL 662 event can hold just one UTF-16 encoding 663 unit. So, if we receive more than 128 664 UTF-16 encoding units from a commit, 665 exceeded characters will be lost. */ 666 for (i = 0; i < utf16length - 1; i++) { 667 keysym.scancode = 0; 668 keysym.sym = SDLK_UNKNOWN; 669 keysym.mod = KMOD_NONE; 670 keysym.unicode = utf16data[i]; 671 posted = SDL_PrivateKeyboard(SDL_PRESSED, &keysym); 672 } 673 /* The keysym for the last character carries the 674 scancode and symbol that corresponds to the X11 675 keycode. */ 676 if (utf16length > 0) { 677 keysym.scancode = keycode; 678 keysym.sym = (keycode ? X11_TranslateKeycode(SDL_Display, keycode) : 0); 679 keysym.mod = KMOD_NONE; 680 keysym.unicode = utf16data[utf16length - 1]; 681 posted = SDL_PrivateKeyboard(SDL_PRESSED, &keysym); 682 } 683 break; 684 } 685 686 case XLookupKeySym: { 687 /* I'm not sure whether it is possible that 688 a zero keycode makes XLookupKeySym 689 status. What I'm sure is that a 690 combination of a zero scan code and a non 691 zero sym makes SDL_PrivateKeyboard 692 strange state... So, just discard it. 693 If this doesn't work, I'm receiving bug 694 reports, and I can know under what 695 condition this case happens. */ 696 if (keycode) { 697 keysym.scancode = keycode; 698 keysym.sym = X11_TranslateKeycode(SDL_Display, keycode); 699 keysym.mod = KMOD_NONE; 700 keysym.unicode = 0; 701 posted = SDL_PrivateKeyboard(SDL_PRESSED, &keysym); 702 } 703 break; 704 } 705 706 case XLookupNone: { 707 /* IM has eaten the event. */ 708 break; 709 } 710 711 default: 712 /* An unknown status from Xutf8LookupString. */ 713 SDL_SetError("Oops! Xutf8LookupStringreturned an unknown status"); 714 } 715 716 /* Release dynamic buffers if allocated. */ 717 if (keydata != NULL && keybuf != keydata) { 718 SDL_free(keydata); 719 } 720 if (utf16data != NULL && utf16buf != utf16data) { 721 SDL_free(utf16data); 722 } 723 } 724 else 725 #endif 726 { 727 static XComposeStatus state; 728 char keybuf[32]; 729 730 keysym.scancode = keycode; 731 keysym.sym = X11_TranslateKeycode(SDL_Display, keycode); 732 keysym.mod = KMOD_NONE; 733 keysym.unicode = 0; 734 if ( XLookupString(&xevent.xkey, 735 keybuf, sizeof(keybuf), 736 NULL, &state) ) { 737 /* 738 * FIXME: XLookupString() may yield more than one 739 * character, so we need a mechanism to allow for 740 * this (perhaps null keypress events with a 741 * unicode value) 742 */ 743 keysym.unicode = (Uint8)keybuf[0]; 744 } 745 746 posted = SDL_PrivateKeyboard(SDL_PRESSED, &keysym); 747 } 748 } 749 break; 750 751 /* Key release? */ 752 case KeyRelease: { 753 SDL_keysym keysym; 754 KeyCode keycode = xevent.xkey.keycode; 755 756 if (keycode == 0) { 757 /* There should be no KeyRelease for keycode == 0, 758 since it is a notification from IM but a real 759 keystroke. */ 760 /* We need to emit some diagnostic message here. */ 761 break; 762 } 763 764 #ifdef DEBUG_XEVENTS 765 printf("KeyRelease (X11 keycode = 0x%X)\n", xevent.xkey.keycode); 766 #endif 767 768 /* Get the translated SDL virtual keysym */ 769 keysym.scancode = keycode; 770 keysym.sym = X11_TranslateKeycode(SDL_Display, keycode); 771 keysym.mod = KMOD_NONE; 772 keysym.unicode = 0; 773 774 posted = SDL_PrivateKeyboard(SDL_RELEASED, &keysym); 775 } 776 break; 777 778 /* Have we been iconified? */ 779 case UnmapNotify: { 780 #ifdef DEBUG_XEVENTS 781 printf("UnmapNotify!\n"); 782 #endif 783 /* If we're active, make ourselves inactive */ 784 if ( SDL_GetAppState() & SDL_APPACTIVE ) { 785 /* Swap out the gamma before we go inactive */ 786 X11_SwapVidModeGamma(this); 787 788 /* Send an internal deactivate event */ 789 posted = SDL_PrivateAppActive(0, 790 SDL_APPACTIVE|SDL_APPINPUTFOCUS); 791 } 792 } 793 break; 794 795 /* Have we been restored? */ 796 case MapNotify: { 797 #ifdef DEBUG_XEVENTS 798 printf("MapNotify!\n"); 799 #endif 800 /* If we're not active, make ourselves active */ 801 if ( !(SDL_GetAppState() & SDL_APPACTIVE) ) { 802 /* Send an internal activate event */ 803 posted = SDL_PrivateAppActive(1, SDL_APPACTIVE); 804 805 /* Now that we're active, swap the gamma back */ 806 X11_SwapVidModeGamma(this); 807 } 808 809 if ( SDL_VideoSurface && 810 (SDL_VideoSurface->flags & SDL_FULLSCREEN) ) { 811 X11_EnterFullScreen(this); 812 } else { 813 X11_GrabInputNoLock(this, this->input_grab); 814 } 815 X11_CheckMouseModeNoLock(this); 816 817 if ( SDL_VideoSurface ) { 818 X11_RefreshDisplay(this); 819 } 820 } 821 break; 822 823 /* Have we been resized or moved? */ 824 case ConfigureNotify: { 825 #ifdef DEBUG_XEVENTS 826 printf("ConfigureNotify! (resize: %dx%d)\n", xevent.xconfigure.width, xevent.xconfigure.height); 827 #endif 828 if ((X11_PendingConfigureNotifyWidth != -1) && 829 (X11_PendingConfigureNotifyHeight != -1)) { 830 if ((xevent.xconfigure.width != X11_PendingConfigureNotifyWidth) && 831 (xevent.xconfigure.height != X11_PendingConfigureNotifyHeight)) { 832 /* Event is from before the resize, so ignore. */ 833 break; 834 } 835 X11_PendingConfigureNotifyWidth = -1; 836 X11_PendingConfigureNotifyHeight = -1; 837 } 838 if ( SDL_VideoSurface ) { 839 if ((xevent.xconfigure.width != SDL_VideoSurface->w) || 840 (xevent.xconfigure.height != SDL_VideoSurface->h)) { 841 /* FIXME: Find a better fix for the bug with KDE 1.2 */ 842 if ( ! ((xevent.xconfigure.width == 32) && 843 (xevent.xconfigure.height == 32)) ) { 844 SDL_PrivateResize(xevent.xconfigure.width, 845 xevent.xconfigure.height); 846 } 847 } else { 848 /* OpenGL windows need to know about the change */ 849 if ( SDL_VideoSurface->flags & SDL_OPENGL ) { 850 SDL_PrivateExpose(); 851 } 852 } 853 } 854 } 855 break; 856 857 /* Have we been requested to quit (or another client message?) */ 858 case ClientMessage: { 859 if ( (xevent.xclient.format == 32) && 860 (xevent.xclient.data.l[0] == WM_DELETE_WINDOW) ) 861 { 862 posted = SDL_PrivateQuit(); 863 } else 864 if ( SDL_ProcessEvents[SDL_SYSWMEVENT] == SDL_ENABLE ) { 865 SDL_SysWMmsg wmmsg; 866 867 SDL_VERSION(&wmmsg.version); 868 wmmsg.subsystem = SDL_SYSWM_X11; 869 wmmsg.event.xevent = xevent; 870 posted = SDL_PrivateSysWMEvent(&wmmsg); 871 } 872 } 873 break; 874 875 /* Do we need to refresh ourselves? */ 876 case Expose: { 877 #ifdef DEBUG_XEVENTS 878 printf("Expose (count = %d)\n", xevent.xexpose.count); 879 #endif 880 if ( SDL_VideoSurface && (xevent.xexpose.count == 0) ) { 881 X11_RefreshDisplay(this); 882 } 883 } 884 break; 885 886 default: { 887 #ifdef DEBUG_XEVENTS 888 printf("Unhandled event %d\n", xevent.type); 889 #endif 890 /* Only post the event if we're watching for it */ 891 if ( SDL_ProcessEvents[SDL_SYSWMEVENT] == SDL_ENABLE ) { 892 SDL_SysWMmsg wmmsg; 893 894 SDL_VERSION(&wmmsg.version); 895 wmmsg.subsystem = SDL_SYSWM_X11; 896 wmmsg.event.xevent = xevent; 897 posted = SDL_PrivateSysWMEvent(&wmmsg); 898 } 899 } 900 break; 901 } 902 return(posted); 903 } 904 905 /* Ack! XPending() actually performs a blocking read if no events available */ 906 int X11_Pending(Display *display) 907 { 908 /* Flush the display connection and look to see if events are queued */ 909 XFlush(display); 910 if ( XEventsQueued(display, QueuedAlready) ) { 911 return(1); 912 } 913 914 /* More drastic measures are required -- see if X is ready to talk */ 915 { 916 static struct timeval zero_time; /* static == 0 */ 917 int x11_fd; 918 fd_set fdset; 919 920 x11_fd = ConnectionNumber(display); 921 FD_ZERO(&fdset); 922 FD_SET(x11_fd, &fdset); 923 if ( select(x11_fd+1, &fdset, NULL, NULL, &zero_time) == 1 ) { 924 return(XPending(display)); 925 } 926 } 927 928 /* Oh well, nothing is ready .. */ 929 return(0); 930 } 931 932 void X11_PumpEvents(_THIS) 933 { 934 int pending; 935 936 /* Update activity every five seconds to prevent screensaver. --ryan. */ 937 if (!allow_screensaver) { 938 static Uint32 screensaverTicks; 939 Uint32 nowTicks = SDL_GetTicks(); 940 if ((nowTicks - screensaverTicks) > 5000) { 941 XResetScreenSaver(SDL_Display); 942 screensaverTicks = nowTicks; 943 } 944 } 945 946 /* Keep processing pending events */ 947 pending = 0; 948 while ( X11_Pending(SDL_Display) ) { 949 X11_DispatchEvent(this); 950 ++pending; 951 } 952 if ( switch_waiting ) { 953 Uint32 now; 954 955 now = SDL_GetTicks(); 956 if ( pending || !SDL_VideoSurface ) { 957 /* Try again later... */ 958 if ( switch_waiting & SDL_FULLSCREEN ) { 959 switch_time = now + 1500; 960 } else { 961 switch_time = now + 200; 962 } 963 } else if ( (int)(switch_time-now) <= 0 ) { 964 Uint32 go_fullscreen; 965 966 go_fullscreen = switch_waiting & SDL_FULLSCREEN; 967 switch_waiting = 0; 968 if ( SDL_VideoSurface->flags & SDL_FULLSCREEN ) { 969 if ( go_fullscreen ) { 970 X11_EnterFullScreen(this); 971 } else { 972 X11_LeaveFullScreen(this); 973 } 974 } 975 /* Handle focus in/out when grabbed */ 976 if ( go_fullscreen ) { 977 X11_GrabInputNoLock(this, this->input_grab); 978 } else { 979 X11_GrabInputNoLock(this, SDL_GRAB_OFF); 980 } 981 X11_CheckMouseModeNoLock(this); 982 } 983 } 984 } 985 986 void X11_InitKeymap(void) 987 { 988 int i; 989 990 /* Odd keys used in international keyboards */ 991 for ( i=0; i<SDL_arraysize(ODD_keymap); ++i ) 992 ODD_keymap[i] = SDLK_UNKNOWN; 993 994 /* Some of these might be mappable to an existing SDLK_ code */ 995 ODD_keymap[XK_dead_grave&0xFF] = SDLK_COMPOSE; 996 ODD_keymap[XK_dead_acute&0xFF] = SDLK_COMPOSE; 997 ODD_keymap[XK_dead_tilde&0xFF] = SDLK_COMPOSE; 998 ODD_keymap[XK_dead_macron&0xFF] = SDLK_COMPOSE; 999 ODD_keymap[XK_dead_breve&0xFF] = SDLK_COMPOSE; 1000 ODD_keymap[XK_dead_abovedot&0xFF] = SDLK_COMPOSE; 1001 ODD_keymap[XK_dead_diaeresis&0xFF] = SDLK_COMPOSE; 1002 ODD_keymap[XK_dead_abovering&0xFF] = SDLK_COMPOSE; 1003 ODD_keymap[XK_dead_doubleacute&0xFF] = SDLK_COMPOSE; 1004 ODD_keymap[XK_dead_caron&0xFF] = SDLK_COMPOSE; 1005 ODD_keymap[XK_dead_cedilla&0xFF] = SDLK_COMPOSE; 1006 ODD_keymap[XK_dead_ogonek&0xFF] = SDLK_COMPOSE; 1007 ODD_keymap[XK_dead_iota&0xFF] = SDLK_COMPOSE; 1008 ODD_keymap[XK_dead_voiced_sound&0xFF] = SDLK_COMPOSE; 1009 ODD_keymap[XK_dead_semivoiced_sound&0xFF] = SDLK_COMPOSE; 1010 ODD_keymap[XK_dead_belowdot&0xFF] = SDLK_COMPOSE; 1011 #ifdef XK_dead_hook 1012 ODD_keymap[XK_dead_hook&0xFF] = SDLK_COMPOSE; 1013 #endif 1014 #ifdef XK_dead_horn 1015 ODD_keymap[XK_dead_horn&0xFF] = SDLK_COMPOSE; 1016 #endif 1017 1018 #ifdef XK_dead_circumflex 1019 /* These X keysyms have 0xFE as the high byte */ 1020 ODD_keymap[XK_dead_circumflex&0xFF] = SDLK_CARET; 1021 #endif 1022 #ifdef XK_ISO_Level3_Shift 1023 ODD_keymap[XK_ISO_Level3_Shift&0xFF] = SDLK_MODE; /* "Alt Gr" key */ 1024 #endif 1025 1026 /* Map the miscellaneous keys */ 1027 for ( i=0; i<SDL_arraysize(MISC_keymap); ++i ) 1028 MISC_keymap[i] = SDLK_UNKNOWN; 1029 1030 /* These X keysyms have 0xFF as the high byte */ 1031 MISC_keymap[XK_BackSpace&0xFF] = SDLK_BACKSPACE; 1032 MISC_keymap[XK_Tab&0xFF] = SDLK_TAB; 1033 MISC_keymap[XK_Clear&0xFF] = SDLK_CLEAR; 1034 MISC_keymap[XK_Return&0xFF] = SDLK_RETURN; 1035 MISC_keymap[XK_Pause&0xFF] = SDLK_PAUSE; 1036 MISC_keymap[XK_Escape&0xFF] = SDLK_ESCAPE; 1037 MISC_keymap[XK_Delete&0xFF] = SDLK_DELETE; 1038 1039 MISC_keymap[XK_KP_0&0xFF] = SDLK_KP0; /* Keypad 0-9 */ 1040 MISC_keymap[XK_KP_1&0xFF] = SDLK_KP1; 1041 MISC_keymap[XK_KP_2&0xFF] = SDLK_KP2; 1042 MISC_keymap[XK_KP_3&0xFF] = SDLK_KP3; 1043 MISC_keymap[XK_KP_4&0xFF] = SDLK_KP4; 1044 MISC_keymap[XK_KP_5&0xFF] = SDLK_KP5; 1045 MISC_keymap[XK_KP_6&0xFF] = SDLK_KP6; 1046 MISC_keymap[XK_KP_7&0xFF] = SDLK_KP7; 1047 MISC_keymap[XK_KP_8&0xFF] = SDLK_KP8; 1048 MISC_keymap[XK_KP_9&0xFF] = SDLK_KP9; 1049 MISC_keymap[XK_KP_Insert&0xFF] = SDLK_KP0; 1050 MISC_keymap[XK_KP_End&0xFF] = SDLK_KP1; 1051 MISC_keymap[XK_KP_Down&0xFF] = SDLK_KP2; 1052 MISC_keymap[XK_KP_Page_Down&0xFF] = SDLK_KP3; 1053 MISC_keymap[XK_KP_Left&0xFF] = SDLK_KP4; 1054 MISC_keymap[XK_KP_Begin&0xFF] = SDLK_KP5; 1055 MISC_keymap[XK_KP_Right&0xFF] = SDLK_KP6; 1056 MISC_keymap[XK_KP_Home&0xFF] = SDLK_KP7; 1057 MISC_keymap[XK_KP_Up&0xFF] = SDLK_KP8; 1058 MISC_keymap[XK_KP_Page_Up&0xFF] = SDLK_KP9; 1059 MISC_keymap[XK_KP_Delete&0xFF] = SDLK_KP_PERIOD; 1060 MISC_keymap[XK_KP_Decimal&0xFF] = SDLK_KP_PERIOD; 1061 MISC_keymap[XK_KP_Divide&0xFF] = SDLK_KP_DIVIDE; 1062 MISC_keymap[XK_KP_Multiply&0xFF] = SDLK_KP_MULTIPLY; 1063 MISC_keymap[XK_KP_Subtract&0xFF] = SDLK_KP_MINUS; 1064 MISC_keymap[XK_KP_Add&0xFF] = SDLK_KP_PLUS; 1065 MISC_keymap[XK_KP_Enter&0xFF] = SDLK_KP_ENTER; 1066 MISC_keymap[XK_KP_Equal&0xFF] = SDLK_KP_EQUALS; 1067 1068 MISC_keymap[XK_Up&0xFF] = SDLK_UP; 1069 MISC_keymap[XK_Down&0xFF] = SDLK_DOWN; 1070 MISC_keymap[XK_Right&0xFF] = SDLK_RIGHT; 1071 MISC_keymap[XK_Left&0xFF] = SDLK_LEFT; 1072 MISC_keymap[XK_Insert&0xFF] = SDLK_INSERT; 1073 MISC_keymap[XK_Home&0xFF] = SDLK_HOME; 1074 MISC_keymap[XK_End&0xFF] = SDLK_END; 1075 MISC_keymap[XK_Page_Up&0xFF] = SDLK_PAGEUP; 1076 MISC_keymap[XK_Page_Down&0xFF] = SDLK_PAGEDOWN; 1077 1078 MISC_keymap[XK_F1&0xFF] = SDLK_F1; 1079 MISC_keymap[XK_F2&0xFF] = SDLK_F2; 1080 MISC_keymap[XK_F3&0xFF] = SDLK_F3; 1081 MISC_keymap[XK_F4&0xFF] = SDLK_F4; 1082 MISC_keymap[XK_F5&0xFF] = SDLK_F5; 1083 MISC_keymap[XK_F6&0xFF] = SDLK_F6; 1084 MISC_keymap[XK_F7&0xFF] = SDLK_F7; 1085 MISC_keymap[XK_F8&0xFF] = SDLK_F8; 1086 MISC_keymap[XK_F9&0xFF] = SDLK_F9; 1087 MISC_keymap[XK_F10&0xFF] = SDLK_F10; 1088 MISC_keymap[XK_F11&0xFF] = SDLK_F11; 1089 MISC_keymap[XK_F12&0xFF] = SDLK_F12; 1090 MISC_keymap[XK_F13&0xFF] = SDLK_F13; 1091 MISC_keymap[XK_F14&0xFF] = SDLK_F14; 1092 MISC_keymap[XK_F15&0xFF] = SDLK_F15; 1093 1094 MISC_keymap[XK_Num_Lock&0xFF] = SDLK_NUMLOCK; 1095 MISC_keymap[XK_Caps_Lock&0xFF] = SDLK_CAPSLOCK; 1096 MISC_keymap[XK_Scroll_Lock&0xFF] = SDLK_SCROLLOCK; 1097 MISC_keymap[XK_Shift_R&0xFF] = SDLK_RSHIFT; 1098 MISC_keymap[XK_Shift_L&0xFF] = SDLK_LSHIFT; 1099 MISC_keymap[XK_Control_R&0xFF] = SDLK_RCTRL; 1100 MISC_keymap[XK_Control_L&0xFF] = SDLK_LCTRL; 1101 MISC_keymap[XK_Alt_R&0xFF] = SDLK_RALT; 1102 MISC_keymap[XK_Alt_L&0xFF] = SDLK_LALT; 1103 MISC_keymap[XK_Meta_R&0xFF] = SDLK_RMETA; 1104 MISC_keymap[XK_Meta_L&0xFF] = SDLK_LMETA; 1105 MISC_keymap[XK_Super_L&0xFF] = SDLK_LSUPER; /* Left "Windows" */ 1106 MISC_keymap[XK_Super_R&0xFF] = SDLK_RSUPER; /* Right "Windows */ 1107 MISC_keymap[XK_Mode_switch&0xFF] = SDLK_MODE; /* "Alt Gr" key */ 1108 MISC_keymap[XK_Multi_key&0xFF] = SDLK_COMPOSE; /* Multi-key compose */ 1109 1110 MISC_keymap[XK_Help&0xFF] = SDLK_HELP; 1111 MISC_keymap[XK_Print&0xFF] = SDLK_PRINT; 1112 MISC_keymap[XK_Sys_Req&0xFF] = SDLK_SYSREQ; 1113 MISC_keymap[XK_Break&0xFF] = SDLK_BREAK; 1114 MISC_keymap[XK_Menu&0xFF] = SDLK_MENU; 1115 MISC_keymap[XK_Hyper_R&0xFF] = SDLK_MENU; /* Windows "Menu" key */ 1116 } 1117 1118 /* Get the translated SDL virtual keysym */ 1119 SDLKey X11_TranslateKeycode(Display *display, KeyCode kc) 1120 { 1121 KeySym xsym; 1122 SDLKey key; 1123 1124 xsym = XKeycodeToKeysym(display, kc, 0); 1125 #ifdef DEBUG_KEYS 1126 fprintf(stderr, "Translating key code %d -> 0x%.4x\n", kc, xsym); 1127 #endif 1128 key = SDLK_UNKNOWN; 1129 if ( xsym ) { 1130 switch (xsym>>8) { 1131 case 0x1005FF: 1132 #ifdef SunXK_F36 1133 if ( xsym == SunXK_F36 ) 1134 key = SDLK_F11; 1135 #endif 1136 #ifdef SunXK_F37 1137 if ( xsym == SunXK_F37 ) 1138 key = SDLK_F12; 1139 #endif 1140 break; 1141 case 0x00: /* Latin 1 */ 1142 key = (SDLKey)(xsym & 0xFF); 1143 break; 1144 case 0x01: /* Latin 2 */ 1145 case 0x02: /* Latin 3 */ 1146 case 0x03: /* Latin 4 */ 1147 case 0x04: /* Katakana */ 1148 case 0x05: /* Arabic */ 1149 case 0x06: /* Cyrillic */ 1150 case 0x07: /* Greek */ 1151 case 0x08: /* Technical */ 1152 case 0x0A: /* Publishing */ 1153 case 0x0C: /* Hebrew */ 1154 case 0x0D: /* Thai */ 1155 /* These are wrong, but it's better than nothing */ 1156 key = (SDLKey)(xsym & 0xFF); 1157 break; 1158 case 0xFE: 1159 key = ODD_keymap[xsym&0xFF]; 1160 break; 1161 case 0xFF: 1162 key = MISC_keymap[xsym&0xFF]; 1163 break; 1164 default: 1165 /* 1166 fprintf(stderr, "X11: Unhandled xsym, sym = 0x%04x\n", 1167 (unsigned int)xsym); 1168 */ 1169 break; 1170 } 1171 } else { 1172 /* X11 doesn't know how to translate the key! */ 1173 switch (kc) { 1174 /* Caution: 1175 These keycodes are from the Microsoft Keyboard 1176 */ 1177 case 115: 1178 key = SDLK_LSUPER; 1179 break; 1180 case 116: 1181 key = SDLK_RSUPER; 1182 break; 1183 case 117: 1184 key = SDLK_MENU; 1185 break; 1186 default: 1187 /* 1188 * no point in an error message; happens for 1189 * several keys when we get a keymap notify 1190 */ 1191 break; 1192 } 1193 } 1194 return key; 1195 } 1196 1197 /* X11 modifier masks for various keys */ 1198 static unsigned meta_l_mask, meta_r_mask, alt_l_mask, alt_r_mask; 1199 static unsigned num_mask, mode_switch_mask; 1200 1201 static void get_modifier_masks(Display *display) 1202 { 1203 static unsigned got_masks; 1204 int i, j; 1205 XModifierKeymap *xmods; 1206 unsigned n; 1207 1208 if(got_masks) 1209 return; 1210 1211 xmods = XGetModifierMapping(display); 1212 n = xmods->max_keypermod; 1213 for(i = 3; i < 8; i++) { 1214 for(j = 0; j < n; j++) { 1215 KeyCode kc = xmods->modifiermap[i * n + j]; 1216 KeySym ks = XKeycodeToKeysym(display, kc, 0); 1217 unsigned mask = 1 << i; 1218 switch(ks) { 1219 case XK_Num_Lock: 1220 num_mask = mask; break; 1221 case XK_Alt_L: 1222 alt_l_mask = mask; break; 1223 case XK_Alt_R: 1224 alt_r_mask = mask; break; 1225 case XK_Meta_L: 1226 meta_l_mask = mask; break; 1227 case XK_Meta_R: 1228 meta_r_mask = mask; break; 1229 case XK_Mode_switch: 1230 mode_switch_mask = mask; break; 1231 } 1232 } 1233 } 1234 XFreeModifiermap(xmods); 1235 got_masks = 1; 1236 } 1237 1238 1239 /* 1240 * This function is semi-official; it is not officially exported and should 1241 * not be considered part of the SDL API, but may be used by client code 1242 * that *really* needs it (including legacy code). 1243 * It is slow, though, and should be avoided if possible. 1244 * 1245 * Note that it isn't completely accurate either; in particular, multi-key 1246 * sequences (dead accents, compose key sequences) will not work since the 1247 * state has been irrevocably lost. 1248 */ 1249 Uint16 X11_KeyToUnicode(SDLKey keysym, SDLMod modifiers) 1250 { 1251 struct SDL_VideoDevice *this = current_video; 1252 char keybuf[32]; 1253 int i; 1254 KeySym xsym = 0; 1255 XKeyEvent xkey; 1256 Uint16 unicode; 1257 1258 if ( !this || !SDL_Display ) { 1259 return 0; 1260 } 1261 1262 SDL_memset(&xkey, 0, sizeof(xkey)); 1263 xkey.display = SDL_Display; 1264 1265 xsym = keysym; /* last resort if not found */ 1266 for (i = 0; i < 256; ++i) { 1267 if ( MISC_keymap[i] == keysym ) { 1268 xsym = 0xFF00 | i; 1269 break; 1270 } else if ( ODD_keymap[i] == keysym ) { 1271 xsym = 0xFE00 | i; 1272 break; 1273 } 1274 } 1275 1276 xkey.keycode = XKeysymToKeycode(xkey.display, xsym); 1277 1278 get_modifier_masks(SDL_Display); 1279 if(modifiers & KMOD_SHIFT) 1280 xkey.state |= ShiftMask; 1281 if(modifiers & KMOD_CAPS) 1282 xkey.state |= LockMask; 1283 if(modifiers & KMOD_CTRL) 1284 xkey.state |= ControlMask; 1285 if(modifiers & KMOD_MODE) 1286 xkey.state |= mode_switch_mask; 1287 if(modifiers & KMOD_LALT) 1288 xkey.state |= alt_l_mask; 1289 if(modifiers & KMOD_RALT) 1290 xkey.state |= alt_r_mask; 1291 if(modifiers & KMOD_LMETA) 1292 xkey.state |= meta_l_mask; 1293 if(modifiers & KMOD_RMETA) 1294 xkey.state |= meta_r_mask; 1295 if(modifiers & KMOD_NUM) 1296 xkey.state |= num_mask; 1297 1298 unicode = 0; 1299 if ( XLookupString(&xkey, keybuf, sizeof(keybuf), NULL, NULL) ) 1300 unicode = (unsigned char)keybuf[0]; 1301 return(unicode); 1302 } 1303 1304 1305 /* 1306 * Called when focus is regained, to read the keyboard state and generate 1307 * synthetic keypress/release events. 1308 * key_vec is a bit vector of keycodes (256 bits) 1309 */ 1310 void X11_SetKeyboardState(Display *display, const char *key_vec) 1311 { 1312 char keys_return[32]; 1313 int i; 1314 Uint8 *kstate = SDL_GetKeyState(NULL); 1315 SDLMod modstate; 1316 Window junk_window; 1317 int x, y; 1318 unsigned int mask; 1319 1320 /* The first time the window is mapped, we initialize key state */ 1321 if ( ! key_vec ) { 1322 XQueryKeymap(display, keys_return); 1323 key_vec = keys_return; 1324 } 1325 1326 /* Get the keyboard modifier state */ 1327 modstate = 0; 1328 get_modifier_masks(display); 1329 if ( XQueryPointer(display, DefaultRootWindow(display), 1330 &junk_window, &junk_window, &x, &y, &x, &y, &mask) ) { 1331 if ( mask & LockMask ) { 1332 modstate |= KMOD_CAPS; 1333 } 1334 if ( mask & mode_switch_mask ) { 1335 modstate |= KMOD_MODE; 1336 } 1337 if ( mask & num_mask ) { 1338 modstate |= KMOD_NUM; 1339 } 1340 } 1341 1342 /* Zero the new keyboard state and generate it */ 1343 SDL_memset(kstate, 0, SDLK_LAST); 1344 /* 1345 * An obvious optimisation is to check entire longwords at a time in 1346 * both loops, but we can't be sure the arrays are aligned so it's not 1347 * worth the extra complexity 1348 */ 1349 for ( i = 0; i < 32; i++ ) { 1350 int j; 1351 if ( !key_vec[i] ) 1352 continue; 1353 for ( j = 0; j < 8; j++ ) { 1354 if ( key_vec[i] & (1 << j) ) { 1355 SDLKey key; 1356 KeyCode kc = (i << 3 | j); 1357 key = X11_TranslateKeycode(display, kc); 1358 if ( key == SDLK_UNKNOWN ) { 1359 continue; 1360 } 1361 kstate[key] = SDL_PRESSED; 1362 switch (key) { 1363 case SDLK_LSHIFT: 1364 modstate |= KMOD_LSHIFT; 1365 break; 1366 case SDLK_RSHIFT: 1367 modstate |= KMOD_RSHIFT; 1368 break; 1369 case SDLK_LCTRL: 1370 modstate |= KMOD_LCTRL; 1371 break; 1372 case SDLK_RCTRL: 1373 modstate |= KMOD_RCTRL; 1374 break; 1375 case SDLK_LALT: 1376 modstate |= KMOD_LALT; 1377 break; 1378 case SDLK_RALT: 1379 modstate |= KMOD_RALT; 1380 break; 1381 case SDLK_LMETA: 1382 modstate |= KMOD_LMETA; 1383 break; 1384 case SDLK_RMETA: 1385 modstate |= KMOD_RMETA; 1386 break; 1387 default: 1388 break; 1389 } 1390 } 1391 } 1392 } 1393 1394 /* Hack - set toggle key state */ 1395 if ( modstate & KMOD_CAPS ) { 1396 kstate[SDLK_CAPSLOCK] = SDL_PRESSED; 1397 } else { 1398 kstate[SDLK_CAPSLOCK] = SDL_RELEASED; 1399 } 1400 if ( modstate & KMOD_NUM ) { 1401 kstate[SDLK_NUMLOCK] = SDL_PRESSED; 1402 } else { 1403 kstate[SDLK_NUMLOCK] = SDL_RELEASED; 1404 } 1405 1406 /* Set the final modifier state */ 1407 SDL_SetModState(modstate); 1408 } 1409 1410 void X11_InitOSKeymap(_THIS) 1411 { 1412 X11_InitKeymap(); 1413 } 1414 1415