1/* 2 SDL - Simple DirectMedia Layer 3 Copyright (C) 1997-2006 Sam Lantinga 4 5 This library is free software; you can redistribute it and/or 6 modify it under the terms of the GNU Lesser General Public 7 License as published by the Free Software Foundation; either 8 version 2.1 of the License, or (at your option) any later version. 9 10 This library is distributed in the hope that it will be useful, 11 but WITHOUT ANY WARRANTY; without even the implied warranty of 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 Lesser General Public License for more details. 14 15 You should have received a copy of the GNU Lesser General Public 16 License along with this library; if not, write to the Free Software 17 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 18 19 Sam Lantinga 20 slouken@libsdl.org 21*/ 22#include "SDL_config.h" 23 24/* Handle the event stream, converting photon events into SDL events */ 25 26#include <stdio.h> 27#include <setjmp.h> 28#include <sys/time.h> 29 30#include <Ph.h> 31#include <photon/PkKeyDef.h> 32 33#include "SDL.h" 34#include "SDL_syswm.h" 35#include "../SDL_sysvideo.h" 36#include "../../events/SDL_sysevents.h" 37#include "../../events/SDL_events_c.h" 38#include "SDL_ph_video.h" 39#include "SDL_ph_modes_c.h" 40#include "SDL_ph_image_c.h" 41#include "SDL_ph_events_c.h" 42#include "SDL_phyuv_c.h" 43 44/* The translation tables from a photon keysym to a SDL keysym */ 45static SDLKey ODD_keymap[256]; 46static SDLKey MISC_keymap[0xFF + 1]; 47SDL_keysym *ph_TranslateKey(PhKeyEvent_t *key, SDL_keysym *keysym); 48 49/* Check to see if this is a repeated key. 50 (idea shamelessly lifted from GII -- thanks guys! :) */ 51static int ph_WarpedMotion(_THIS, PhEvent_t *winEvent) 52{ 53 PhRect_t *rect = PhGetRects( winEvent ); 54 55 int centre_x, centre_y; 56 int dx, dy; 57 short abs_x, abs_y; 58 int posted; 59 60 centre_x = SDL_VideoSurface->w / 2; 61 centre_y = SDL_VideoSurface->h / 2; 62 63 dx = rect->ul.x - centre_x; 64 dy = rect->ul.y - centre_y; 65 66 posted = SDL_PrivateMouseMotion( 0, 1, dx, dy ); 67 68 /* Move mouse cursor to middle of the window */ 69 PtGetAbsPosition( window, &abs_x, &abs_y ); 70 PhMoveCursorAbs(PhInputGroup(NULL), abs_x + centre_x, abs_y + centre_y); 71 72 return (posted); 73} 74 75/* Control which motion flags the window has set, a flags value of -1 sets 76 * MOTION_BUTTON and MOTION_NOBUTTON */ 77 78static void set_motion_sensitivity(_THIS, unsigned int flags) 79{ 80 int rid; 81 int fields = Ph_EV_PTR_MOTION_BUTTON | Ph_EV_PTR_MOTION_NOBUTTON; 82 PhRegion_t region; 83 84 if( window ) 85 { 86 rid = PtWidgetRid(window); 87 if( rid != 0 && PhRegionQuery(rid, ®ion, NULL, NULL, 0) == 0 ) 88 { 89 region.events_sense=(region.events_sense & ~fields)|(flags & fields); 90 PhRegionChange(Ph_REGION_EV_SENSE, 0, ®ion, NULL, NULL); 91 } 92 } 93} 94 95/* Convert the photon button state value to an SDL value */ 96static Uint8 ph2sdl_mousebutton(unsigned short button_state) 97{ 98 Uint8 mouse_button = 0; 99 100 if (button_state & Ph_BUTTON_SELECT) 101 mouse_button |= SDL_BUTTON_LEFT; 102 if (button_state & Ph_BUTTON_MENU) 103 mouse_button |= SDL_BUTTON_RIGHT; 104 if (button_state & Ph_BUTTON_ADJUST) 105 mouse_button |= SDL_BUTTON_MIDDLE; 106 107 return (mouse_button); 108} 109 110static int ph_DispatchEvent(_THIS) 111{ 112 int posted; 113 PhRect_t* rect; 114 PhPointerEvent_t* pointerEvent; 115 PhKeyEvent_t* keyEvent; 116 PhWindowEvent_t* winEvent; 117 int i, buttons; 118 SDL_Rect sdlrects[PH_SDL_MAX_RECTS]; 119 120 posted = 0; 121 122 switch (phevent->type) 123 { 124 case Ph_EV_BOUNDARY: 125 { 126 if (phevent->subtype == Ph_EV_PTR_ENTER) 127 { 128 posted = SDL_PrivateAppActive(1, SDL_APPMOUSEFOCUS); 129 } 130 else if (phevent->subtype ==Ph_EV_PTR_LEAVE) 131 { 132 posted = SDL_PrivateAppActive(0, SDL_APPMOUSEFOCUS); 133 } 134 } 135 break; 136 137 case Ph_EV_PTR_MOTION_BUTTON: 138 case Ph_EV_PTR_MOTION_NOBUTTON: 139 { 140 if (SDL_VideoSurface) 141 { 142 pointerEvent = PhGetData(phevent); 143 rect = PhGetRects(phevent); 144 145 if (mouse_relative) 146 { 147 posted = ph_WarpedMotion(this, phevent); 148 } 149 else 150 { 151 posted = SDL_PrivateMouseMotion(0, 0, rect->ul.x, rect->ul.y); 152 } 153 } 154 } 155 break; 156 157 case Ph_EV_BUT_PRESS: 158 { 159 pointerEvent = PhGetData(phevent); 160 buttons = ph2sdl_mousebutton(pointerEvent->buttons); 161 if (buttons != 0) 162 { 163 posted = SDL_PrivateMouseButton(SDL_PRESSED, buttons, 0, 0); 164 } 165 } 166 break; 167 168 case Ph_EV_BUT_RELEASE: 169 { 170 pointerEvent = PhGetData(phevent); 171 buttons = ph2sdl_mousebutton(pointerEvent->buttons); 172 if (phevent->subtype == Ph_EV_RELEASE_REAL && buttons != 0) 173 { 174 posted = SDL_PrivateMouseButton(SDL_RELEASED, buttons, 0, 0); 175 } 176 else if(phevent->subtype == Ph_EV_RELEASE_PHANTOM) 177 { 178 /* If the mouse is outside the window, 179 * only a phantom release event is sent, so 180 * check if the window doesn't have mouse focus. 181 * Not perfect, maybe checking the mouse button 182 * state for Ph_EV_BOUNDARY events would be 183 * better. */ 184 if ((SDL_GetAppState() & SDL_APPMOUSEFOCUS) == 0) 185 { 186 posted = SDL_PrivateMouseButton(SDL_RELEASED, buttons, 0, 0); 187 } 188 } 189 } 190 break; 191 192 case Ph_EV_WM: 193 { 194 winEvent = PhGetData(phevent); 195 196 /* losing focus */ 197 if ((winEvent->event_f==Ph_WM_FOCUS) && (winEvent->event_state==Ph_WM_EVSTATE_FOCUSLOST)) 198 { 199 set_motion_sensitivity(this, Ph_EV_PTR_MOTION_BUTTON); 200 posted = SDL_PrivateAppActive(0, SDL_APPINPUTFOCUS); 201 } 202 /* gaining focus */ 203 else if ((winEvent->event_f==Ph_WM_FOCUS) && (winEvent->event_state==Ph_WM_EVSTATE_FOCUS)) 204 { 205 set_motion_sensitivity(this, -1); 206 posted = SDL_PrivateAppActive(1, SDL_APPINPUTFOCUS); 207 } 208 /* request quit */ 209 else if (winEvent->event_f==Ph_WM_CLOSE) 210 { 211 posted = SDL_PrivateQuit(); 212 } 213 /* request hide/unhide */ 214 else if (winEvent->event_f==Ph_WM_HIDE) 215 { 216 if (currently_hided) 217 { 218 /* got unhide window event */ 219 /* TODO: restore application's palette if in palette mode */ 220 currently_hided=0; 221 } 222 else 223 { 224 /* got hide window event */ 225 /* TODO: restore original palette if in palette mode */ 226 currently_hided=1; 227 } 228 } 229 /* request to resize */ 230 else if (winEvent->event_f==Ph_WM_RESIZE) 231 { 232 currently_maximized=0; 233 #if (_NTO_VERSION < 630) 234 SDL_PrivateResize(winEvent->size.w+1, winEvent->size.h+1); 235 #else 236 /* QNX 6.3.0 have this bug fixed */ 237 SDL_PrivateResize(winEvent->size.w, winEvent->size.h); 238 #endif /* _NTO_VERSION */ 239 } 240 /* request to move */ 241 else if (winEvent->event_f==Ph_WM_MOVE) 242 { 243 if (current_overlay!=NULL) 244 { 245 int lockedstate=current_overlay->hwdata->locked; 246 int chromastate=current_overlay->hwdata->ischromakey; 247 int error; 248 SDL_Rect src, dst; 249 250 current_overlay->hwdata->locked=1; 251 src.x = 0; 252 src.y = 0; 253 src.w = current_overlay->w; 254 src.y = current_overlay->h; 255 dst.x=current_overlay->hwdata->CurrentViewPort.pos.x; 256 dst.y=current_overlay->hwdata->CurrentViewPort.pos.y; 257 dst.w=current_overlay->hwdata->CurrentViewPort.size.w; 258 dst.h=current_overlay->hwdata->CurrentViewPort.size.h; 259 current_overlay->hwdata->ischromakey=0; 260 error=ph_DisplayYUVOverlay(this, current_overlay, &src, &dst); 261 if (!error) 262 { 263 current_overlay->hwdata->ischromakey=chromastate; 264 current_overlay->hwdata->locked=lockedstate; 265 } 266 } 267 } 268 /* maximize request */ 269 else if (winEvent->event_f==Ph_WM_MAX) 270 { 271 /* window already moved and resized here */ 272 currently_maximized=1; 273 } 274 /* restore request */ 275 else if (winEvent->event_f==Ph_WM_RESTORE) 276 { 277 /* window already moved and resized here */ 278 currently_maximized=0; 279 } 280 } 281 break; 282 283 /* window has been resized, moved or removed */ 284 case Ph_EV_EXPOSE: 285 { 286 if (phevent->num_rects!=0) 287 { 288 int numrects; 289 290 if (SDL_VideoSurface) 291 { 292 rect = PhGetRects(phevent); 293 if (phevent->num_rects>PH_SDL_MAX_RECTS) 294 { 295 /* sorry, buffers underrun, we'll update only first PH_SDL_MAX_RECTS rects */ 296 numrects=PH_SDL_MAX_RECTS; 297 } 298 299 for(i=0; i<phevent->num_rects; i++) 300 { 301 sdlrects[i].x = rect[i].ul.x; 302 sdlrects[i].y = rect[i].ul.y; 303 sdlrects[i].w = rect[i].lr.x - rect[i].ul.x + 1; 304 sdlrects[i].h = rect[i].lr.y - rect[i].ul.y + 1; 305 } 306 307 this->UpdateRects(this, phevent->num_rects, sdlrects); 308 309 if (current_overlay!=NULL) 310 { 311 int lockedstate=current_overlay->hwdata->locked; 312 int error; 313 SDL_Rect src, dst; 314 315 current_overlay->hwdata->locked=1; 316 src.x = 0; 317 src.y = 0; 318 src.w = current_overlay->w; 319 src.y = current_overlay->h; 320 dst.x=current_overlay->hwdata->CurrentViewPort.pos.x; 321 dst.y=current_overlay->hwdata->CurrentViewPort.pos.y; 322 dst.w=current_overlay->hwdata->CurrentViewPort.size.w; 323 dst.h=current_overlay->hwdata->CurrentViewPort.size.h; 324 current_overlay->hwdata->forcedredraw=1; 325 error=ph_DisplayYUVOverlay(this, current_overlay, &src, &dst); 326 if (!error) 327 { 328 current_overlay->hwdata->forcedredraw=0; 329 current_overlay->hwdata->locked=lockedstate; 330 } 331 } 332 } 333 } 334 } 335 break; 336 337 case Ph_EV_KEY: 338 { 339 SDL_keysym keysym; 340 341 posted = 0; 342 343 keyEvent = PhGetData(phevent); 344 345 if (Pk_KF_Key_Down & keyEvent->key_flags) 346 { 347 /* split the wheel events from real key events */ 348 if ((keyEvent->key_cap==Pk_Up) && (keyEvent->key_scan==0) && ((keyEvent->key_flags & Pk_KF_Scan_Valid)==Pk_KF_Scan_Valid)) 349 { 350 posted = SDL_PrivateMouseButton(SDL_PRESSED, SDL_BUTTON_WHEELUP, 0, 0); 351 break; 352 } 353 if ((keyEvent->key_cap==Pk_Down) && (keyEvent->key_scan==0) && ((keyEvent->key_flags & Pk_KF_Scan_Valid)==Pk_KF_Scan_Valid)) 354 { 355 posted = SDL_PrivateMouseButton(SDL_PRESSED, SDL_BUTTON_WHEELDOWN, 0, 0); 356 break; 357 } 358 posted = SDL_PrivateKeyboard(SDL_PRESSED, ph_TranslateKey(keyEvent, &keysym)); 359 } 360 else /* must be key release */ 361 { 362 /* split the wheel events from real key events */ 363 if ((keyEvent->key_cap==Pk_Up) && (keyEvent->key_scan==0) && ((keyEvent->key_flags & Pk_KF_Scan_Valid)==Pk_KF_Scan_Valid)) 364 { 365 posted = SDL_PrivateMouseButton(SDL_RELEASED, SDL_BUTTON_WHEELUP, 0, 0); 366 break; 367 } 368 if ((keyEvent->key_cap==Pk_Down) && (keyEvent->key_scan==0) && ((keyEvent->key_flags & Pk_KF_Scan_Valid)==Pk_KF_Scan_Valid)) 369 { 370 posted = SDL_PrivateMouseButton(SDL_RELEASED, SDL_BUTTON_WHEELDOWN, 0, 0); 371 break; 372 } 373 posted = SDL_PrivateKeyboard(SDL_RELEASED, ph_TranslateKey( keyEvent, &keysym)); 374 } 375 } 376 break; 377 378 case Ph_EV_INFO: 379 { 380 if (phevent->subtype==Ph_OFFSCREEN_INVALID) 381 { 382 unsigned long* EvInfoData; 383 384 EvInfoData=(unsigned long*)PhGetData(phevent); 385 386 switch (*EvInfoData) 387 { 388 case Pg_VIDEO_MODE_SWITCHED: 389 { 390 } 391 break; 392 case Pg_ENTERED_DIRECT: 393 { 394 } 395 break; 396 case Pg_EXITED_DIRECT: 397 { 398 } 399 break; 400 case Pg_DRIVER_STARTED: 401 { 402 } 403 break; 404 } 405 } 406 } 407 break; 408 } 409 410 return(posted); 411} 412 413/* perform a blocking read if no events available */ 414int ph_Pending(_THIS) 415{ 416 /* Flush the display connection and look to see if events are queued */ 417 PgFlush(); 418 419 while (1) 420 { 421 switch(PhEventPeek(phevent, EVENT_SIZE)) 422 { 423 case Ph_EVENT_MSG: 424 return 1; 425 case -1: 426 SDL_SetError("ph_Pending(): PhEventNext failed.\n"); 427 return 0; 428 default: 429 return 0; 430 } 431 } 432 433 /* Oh well, nothing is ready .. */ 434 return(0); 435} 436 437void ph_PumpEvents(_THIS) 438{ 439 /* Flush the display connection and look to see if events are queued */ 440 PgFlush(); 441 442 while (ph_Pending(this)) 443 { 444 PtEventHandler(phevent); 445 ph_DispatchEvent(this); 446 } 447} 448 449void ph_InitKeymap(void) 450{ 451 int i; 452 453 /* Odd keys used in international keyboards */ 454 for (i=0; i<SDL_arraysize(ODD_keymap); ++i) 455 { 456 ODD_keymap[i] = SDLK_UNKNOWN; 457 } 458 459 /* Map the miscellaneous keys */ 460 for (i=0; i<SDL_arraysize(MISC_keymap); ++i) 461 { 462 MISC_keymap[i] = SDLK_UNKNOWN; 463 } 464 465 MISC_keymap[Pk_BackSpace&0xFF] = SDLK_BACKSPACE; 466 MISC_keymap[Pk_Tab&0xFF] = SDLK_TAB; 467 MISC_keymap[Pk_Clear&0xFF] = SDLK_CLEAR; 468 MISC_keymap[Pk_Return&0xFF] = SDLK_RETURN; 469 MISC_keymap[Pk_Pause&0xFF] = SDLK_PAUSE; 470 MISC_keymap[Pk_Escape&0xFF] = SDLK_ESCAPE; 471 MISC_keymap[Pk_Delete&0xFF] = SDLK_DELETE; 472 473 MISC_keymap[Pk_KP_0&0xFF] = SDLK_KP0; 474 MISC_keymap[Pk_KP_1&0xFF] = SDLK_KP1; 475 MISC_keymap[Pk_KP_2&0xFF] = SDLK_KP2; 476 MISC_keymap[Pk_KP_3&0xFF] = SDLK_KP3; 477 MISC_keymap[Pk_KP_4&0xFF] = SDLK_KP4; 478 MISC_keymap[Pk_KP_5&0xFF] = SDLK_KP5; 479 MISC_keymap[Pk_KP_6&0xFF] = SDLK_KP6; 480 MISC_keymap[Pk_KP_7&0xFF] = SDLK_KP7; 481 MISC_keymap[Pk_KP_8&0xFF] = SDLK_KP8; 482 MISC_keymap[Pk_KP_9&0xFF] = SDLK_KP9; 483 484 MISC_keymap[Pk_KP_Decimal&0xFF] = SDLK_KP_PERIOD; 485 MISC_keymap[Pk_KP_Divide&0xFF] = SDLK_KP_DIVIDE; 486 MISC_keymap[Pk_KP_Multiply&0xFF] = SDLK_KP_MULTIPLY; 487 MISC_keymap[Pk_KP_Subtract&0xFF] = SDLK_KP_MINUS; 488 MISC_keymap[Pk_KP_Add&0xFF] = SDLK_KP_PLUS; 489 MISC_keymap[Pk_KP_Enter&0xFF] = SDLK_KP_ENTER; 490 MISC_keymap[Pk_KP_Equal&0xFF] = SDLK_KP_EQUALS; 491 492 MISC_keymap[Pk_Up&0xFF] = SDLK_UP; 493 MISC_keymap[Pk_Down&0xFF] = SDLK_DOWN; 494 MISC_keymap[Pk_Right&0xFF] = SDLK_RIGHT; 495 MISC_keymap[Pk_Left&0xFF] = SDLK_LEFT; 496 MISC_keymap[Pk_Insert&0xFF] = SDLK_INSERT; 497 MISC_keymap[Pk_Home&0xFF] = SDLK_HOME; 498 MISC_keymap[Pk_End&0xFF] = SDLK_END; 499 MISC_keymap[Pk_Pg_Up&0xFF] = SDLK_PAGEUP; 500 MISC_keymap[Pk_Pg_Down&0xFF] = SDLK_PAGEDOWN; 501 502 MISC_keymap[Pk_F1&0xFF] = SDLK_F1; 503 MISC_keymap[Pk_F2&0xFF] = SDLK_F2; 504 MISC_keymap[Pk_F3&0xFF] = SDLK_F3; 505 MISC_keymap[Pk_F4&0xFF] = SDLK_F4; 506 MISC_keymap[Pk_F5&0xFF] = SDLK_F5; 507 MISC_keymap[Pk_F6&0xFF] = SDLK_F6; 508 MISC_keymap[Pk_F7&0xFF] = SDLK_F7; 509 MISC_keymap[Pk_F8&0xFF] = SDLK_F8; 510 MISC_keymap[Pk_F9&0xFF] = SDLK_F9; 511 MISC_keymap[Pk_F10&0xFF] = SDLK_F10; 512 MISC_keymap[Pk_F11&0xFF] = SDLK_F11; 513 MISC_keymap[Pk_F12&0xFF] = SDLK_F12; 514 MISC_keymap[Pk_F13&0xFF] = SDLK_F13; 515 MISC_keymap[Pk_F14&0xFF] = SDLK_F14; 516 MISC_keymap[Pk_F15&0xFF] = SDLK_F15; 517 518 MISC_keymap[Pk_Num_Lock&0xFF] = SDLK_NUMLOCK; 519 MISC_keymap[Pk_Caps_Lock&0xFF] = SDLK_CAPSLOCK; 520 MISC_keymap[Pk_Scroll_Lock&0xFF] = SDLK_SCROLLOCK; 521 MISC_keymap[Pk_Shift_R&0xFF] = SDLK_RSHIFT; 522 MISC_keymap[Pk_Shift_L&0xFF] = SDLK_LSHIFT; 523 MISC_keymap[Pk_Control_R&0xFF] = SDLK_RCTRL; 524 MISC_keymap[Pk_Control_L&0xFF] = SDLK_LCTRL; 525 MISC_keymap[Pk_Alt_R&0xFF] = SDLK_RALT; 526 MISC_keymap[Pk_Alt_L&0xFF] = SDLK_LALT; 527 MISC_keymap[Pk_Meta_R&0xFF] = SDLK_RMETA; 528 MISC_keymap[Pk_Meta_L&0xFF] = SDLK_LMETA; 529 MISC_keymap[Pk_Super_L&0xFF] = SDLK_LSUPER; 530 MISC_keymap[Pk_Super_R&0xFF] = SDLK_RSUPER; 531 MISC_keymap[Pk_Mode_switch&0xFF] = SDLK_MODE; /* "Alt Gr" key */ 532 533 MISC_keymap[Pk_Help&0xFF] = SDLK_HELP; 534 MISC_keymap[Pk_Print&0xFF] = SDLK_PRINT; 535 MISC_keymap[Pk_Break&0xFF] = SDLK_BREAK; 536 MISC_keymap[Pk_Menu&0xFF] = SDLK_MENU; /* Windows "Menu" key */ 537 538 MISC_keymap[Pk_Hyper_R&0xFF] = SDLK_RSUPER; /* Right "Windows" */ 539 540 /* Left "Windows" key, but it can't be catched by application */ 541 MISC_keymap[Pk_Hyper_L&0xFF] = SDLK_LSUPER; 542} 543 544static unsigned long cap; 545 546SDL_keysym *ph_TranslateKey(PhKeyEvent_t *key, SDL_keysym *keysym) 547{ 548 /* 'sym' is set to the value of the key with modifiers applied to it. 549 This member is valid only if Pk_KF_Sym_Valid is set in the key_flags. 550 We will assume it is valid. */ 551 552 /* FIXME: This needs to check whether the cap & scancode is valid */ 553 554 cap = key->key_cap; 555 556 switch (cap>>8) 557 { 558 case 0x00: /* Latin 1 */ 559 case 0x01: /* Latin 2 */ 560 case 0x02: /* Latin 3 */ 561 case 0x03: /* Latin 4 */ 562 case 0x04: /* Katakana */ 563 case 0x05: /* Arabic */ 564 case 0x06: /* Cyrillic */ 565 case 0x07: /* Greek */ 566 case 0x08: /* Technical */ 567 case 0x0A: /* Publishing */ 568 case 0x0C: /* Hebrew */ 569 case 0x0D: /* Thai */ 570 keysym->sym = (SDLKey)(cap&0xFF); 571 /* Map capital letter syms to lowercase */ 572 if ((keysym->sym >= 'A')&&(keysym->sym <= 'Z')) 573 keysym->sym += ('a'-'A'); 574 break; 575 case 0xF0: 576 keysym->sym = MISC_keymap[cap&0xFF]; 577 break; 578 default: 579 keysym->sym = SDLK_UNKNOWN; 580 break; 581 } 582 583 keysym->scancode = key->key_scan; 584 keysym->unicode = 0; 585 586 if (SDL_TranslateUNICODE) 587 { 588 char utf8[MB_CUR_MAX]; 589 int utf8len; 590 wchar_t unicode; 591 592 switch (keysym->scancode) 593 { 594 /* Esc key */ 595 case 0x01: keysym->unicode = 27; 596 break; 597 /* BackSpace key */ 598 case 0x0E: keysym->unicode = 127; 599 break; 600 /* Enter key */ 601 case 0x1C: keysym->unicode = 10; 602 break; 603 default: 604 utf8len = PhKeyToMb(utf8, key); 605 if (utf8len > 0) 606 { 607 utf8len = mbtowc(&unicode, utf8, utf8len); 608 if (utf8len > 0) 609 { 610 keysym->unicode = unicode; 611 } 612 } 613 break; 614 } 615 616 } 617 618 return (keysym); 619} 620 621void ph_InitOSKeymap(_THIS) 622{ 623 ph_InitKeymap(); 624} 625