SDL-1.2.14
[sdl_omap.git] / src / video / photon / SDL_ph_events.c
1 /*
2     SDL - Simple DirectMedia Layer
3     Copyright (C) 1997-2009 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 */
45 static SDLKey ODD_keymap[256];
46 static SDLKey MISC_keymap[0xFF + 1];
47 SDL_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! :) */
51 static 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
78 static 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, &region, NULL, NULL, 0) == 0 )
88         {
89             region.events_sense=(region.events_sense & ~fields)|(flags & fields);
90             PhRegionChange(Ph_REGION_EV_SENSE, 0, &region, NULL, NULL);
91         }
92     }
93 }
94
95 /* Convert the photon button state value to an SDL value */
96 static 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
110 static 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 */
414 int 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
437 void 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
449 void 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
544 static unsigned long cap;
545
546 SDL_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
621 void ph_InitOSKeymap(_THIS)
622 {
623     ph_InitKeymap();
624 }