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@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, &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 */
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