src/video/photon/SDL_ph_events.c
author Sam Lantinga <slouken@lokigames.com>
Thu, 26 Apr 2001 16:45:43 +0000
changeset 0 74212992fb08
child 19 8cc4dbfab9ab
permissions -rw-r--r--
Initial revision
     1 /*
     2     SDL - Simple DirectMedia Layer
     3     Copyright (C) 1997, 1998, 1999, 2000, 2001  Sam Lantinga
     4 
     5     This library is free software; you can redistribute it and/or
     6     modify it under the terms of the GNU Library General Public
     7     License as published by the Free Software Foundation; either
     8     version 2 of the License, or (at your option) any later version.
     9 
    10     This library is distributed in the hope that it will be useful,
    11     but WITHOUT ANY WARRANTY; without even the implied warranty of
    12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    13     Library General Public License for more details.
    14 
    15     You should have received a copy of the GNU Library General Public
    16     License along with this library; if not, write to the Free
    17     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
    18 
    19     Sam Lantinga
    20     slouken@devolution.com
    21 */
    22 
    23 #ifdef SAVE_RCSID
    24 static char rcsid =
    25  "@(#) $Id$";
    26 #endif
    27 
    28 /* Handle the event stream, converting photon events into SDL events */
    29 
    30 #include <Ph.h>
    31 #include <stdio.h>
    32 #include <setjmp.h>
    33 #include <photon/PkKeyDef.h>
    34 #include <sys/time.h>
    35 
    36 #include "SDL.h"
    37 #include "SDL_syswm.h"
    38 #include "SDL_sysevents.h"
    39 #include "SDL_sysvideo.h"
    40 #include "SDL_events_c.h"
    41 #include "SDL_ph_video.h"
    42 #include "SDL_ph_modes_c.h"
    43 #include "SDL_ph_image_c.h"
    44 #include "SDL_ph_events_c.h"
    45 
    46 
    47 /* The translation tables from a photon keysym to a SDL keysym */
    48 static SDLKey ODD_keymap[256];
    49 static SDLKey MISC_keymap[0xFF + 1];
    50 SDL_keysym *ph_TranslateKey(PhKeyEvent_t *key, SDL_keysym *keysym);
    51 
    52 /* Check to see if this is a repeated key.
    53    (idea shamelessly lifted from GII -- thanks guys! :)
    54  */
    55 
    56 static int ph_KeyRepeat(_THIS, PhKeyEvent_t* keyevent)
    57 {
    58 	PhEvent_t* peekevent;
    59 	PhKeyEvent_t* keyEvent;
    60 	int repeated;
    61 
    62 	repeated = 0;
    63 	switch (PhEventPeek( peekevent, EVENT_SIZE ))
    64 	{
    65 		case Ph_EVENT_MSG: {
    66 			if(peekevent->type == Ph_EV_KEY)
    67 			{
    68 				keyEvent = PhGetData( peekevent );
    69 				if ( !(Pk_KF_Key_Down & keyEvent->key_flags) &&
    70 					(keyEvent->key_cap == keyevent->key_cap) &&
    71 					(peekevent->timestamp == event->timestamp)	
    72 				) {
    73 					repeated = 1;
    74 					 //PhEventNext( peekevent, EVENT_SIZE );  
    75 				}				
    76 			}
    77 		}
    78 		break;
    79 
    80 		case -1: {
    81 			perror( "PhEventPeek failed" );
    82 		}
    83 		break;
    84 
    85 		default: /* no events pending */
    86 	}
    87 	return(repeated);
    88 }
    89 
    90 /* Note:  The X server buffers and accumulates mouse motion events, so
    91    the motion event generated by the warp may not appear exactly as we
    92    expect it to.  We work around this (and improve performance) by only
    93    warping the pointer when it reaches the edge, and then wait for it.
    94 */
    95 /*
    96 #define MOUSE_FUDGE_FACTOR	8
    97 
    98 static inline int X11_WarpedMotion(_THIS, XEvent *xevent)
    99 {
   100 	int w, h, i;
   101 	int deltax, deltay;
   102 	int posted;
   103 
   104 	w = SDL_VideoSurface->w;
   105 	h = SDL_VideoSurface->h;
   106 	deltax = xevent->xmotion.x - mouse_last.x;
   107 	deltay = xevent->xmotion.y - mouse_last.y;
   108 #ifdef DEBUG_MOTION
   109   printf("Warped mouse motion: %d,%d\n", deltax, deltay);
   110 #endif
   111 	mouse_last.x = xevent->xmotion.x;
   112 	mouse_last.y = xevent->xmotion.y;
   113 	posted = SDL_PrivateMouseMotion(0, 1, deltax, deltay);
   114 
   115 	if ( (xevent->xmotion.x < MOUSE_FUDGE_FACTOR) ||
   116 	     (xevent->xmotion.x > (w-MOUSE_FUDGE_FACTOR)) ||
   117 	     (xevent->xmotion.y < MOUSE_FUDGE_FACTOR) ||
   118 	     (xevent->xmotion.y > (h-MOUSE_FUDGE_FACTOR)) ) {
   119 		/* Get the events that have accumulated */
   120 /*		while ( XCheckTypedEvent(SDL_Display, MotionNotify, xevent) ) {
   121 			deltax = xevent->xmotion.x - mouse_last.x;
   122 			deltay = xevent->xmotion.y - mouse_last.y;
   123 #ifdef DEBUG_MOTION
   124   printf("Extra mouse motion: %d,%d\n", deltax, deltay);
   125 #endif
   126 			mouse_last.x = xevent->xmotion.x;
   127 			mouse_last.y = xevent->xmotion.y;
   128 			posted += SDL_PrivateMouseMotion(0, 1, deltax, deltay);
   129 		}
   130 		mouse_last.x = w/2;
   131 		mouse_last.y = h/2;
   132 		XWarpPointer(SDL_Display, None, SDL_Window, 0, 0, 0, 0,
   133 					mouse_last.x, mouse_last.y);
   134 		for ( i=0; i<10; ++i ) {
   135         		XMaskEvent(SDL_Display, PointerMotionMask, xevent);
   136 			if ( (xevent->xmotion.x >
   137 			          (mouse_last.x-MOUSE_FUDGE_FACTOR)) &&
   138 			     (xevent->xmotion.x <
   139 			          (mouse_last.x+MOUSE_FUDGE_FACTOR)) &&
   140 			     (xevent->xmotion.y >
   141 			          (mouse_last.y-MOUSE_FUDGE_FACTOR)) &&
   142 			     (xevent->xmotion.y <
   143 			          (mouse_last.y+MOUSE_FUDGE_FACTOR)) ) {
   144 				break;
   145 			}
   146 #ifdef DEBUG_XEVENTS
   147   printf("Lost mouse motion: %d,%d\n", xevent->xmotion.x, xevent->xmotion.y);
   148 #endif
   149 		}
   150 #ifdef DEBUG_XEVENTS
   151 		if ( i == 10 ) {
   152 			printf("Warning: didn't detect mouse warp motion\n");
   153 		}
   154 #endif
   155 	}
   156 	return(posted);
   157 }
   158 */
   159 
   160 static int ph_DispatchEvent(_THIS)
   161 {
   162 	int posted;
   163 	PhRect_t* rect;
   164 	PhPointerEvent_t* pointerEvent;
   165 	PhKeyEvent_t* keyEvent;
   166 	PhWindowEvent_t* winEvent;
   167 	int i;
   168 	SDL_Rect sdlrects[50]; 
   169 	
   170 	posted = 0;
   171 	
   172 	switch (event->type) {
   173 		case Ph_EV_BOUNDARY:
   174 		{
   175 		
   176 			if (event->subtype == Ph_EV_PTR_ENTER)
   177 				posted = SDL_PrivateAppActive(1, SDL_APPMOUSEFOCUS);
   178 			else if (event->subtype ==Ph_EV_PTR_LEAVE)
   179 				posted = SDL_PrivateAppActive(0, SDL_APPMOUSEFOCUS);	
   180 		}
   181 		break;
   182 
   183 		case Ph_EV_PTR_MOTION_BUTTON:
   184 		case Ph_EV_PTR_MOTION_NOBUTTON:
   185 		{
   186 		
   187 			if ( SDL_VideoSurface ) {
   188 				pointerEvent = PhGetData( event );
   189 				rect = PhGetRects( event );
   190 				posted = SDL_PrivateMouseMotion(0, 1,
   191                 		pointerEvent->pos.x - rect[0].ul.x,
   192                 		pointerEvent->pos.y - rect[0].ul.y);		
   193 			}
   194 		}
   195 		break;
   196 
   197 		case Ph_EV_BUT_PRESS:
   198 		{
   199 
   200 			pointerEvent = PhGetData( event );
   201 			/* TODO: is 'buttons' the right mapping? */
   202 			posted = SDL_PrivateMouseButton(SDL_PRESSED,
   203                         	pointerEvent->buttons, 0, 0);
   204 		}
   205 		break;
   206 
   207 		case Ph_EV_BUT_RELEASE:
   208 		{
   209 			
   210 			pointerEvent = PhGetData( event );
   211 			 posted = SDL_PrivateMouseButton(SDL_RELEASED,
   212          			pointerEvent->buttons, 0, 0);
   213 		}
   214 		break;
   215 
   216 		case Ph_EV_WM:
   217 		{
   218 
   219 		
   220 			winEvent = PhGetData( event );
   221 			
   222 			/* losing focus */
   223 			if ((winEvent->event_f==Ph_WM_FOCUS)&&
   224 				(winEvent->event_state==Ph_WM_EVSTATE_FOCUSLOST))
   225 			{
   226 				posted = SDL_PrivateAppActive(0, SDL_APPINPUTFOCUS);	
   227 
   228 				/* Queue leaving fullscreen mode */
   229 				switch_waiting = 0x01;
   230 				switch_time = SDL_GetTicks() + 200;
   231 			}
   232 
   233 			/* gaining focus */
   234 			else if ((winEvent->event_f==Ph_WM_FOCUS)&&
   235 					(winEvent->event_state==Ph_WM_EVSTATE_FOCUS))
   236 			{
   237 				posted = SDL_PrivateAppActive(1, SDL_APPINPUTFOCUS);
   238 
   239 				/* Queue entry into fullscreen mode */
   240 				switch_waiting = 0x01 | SDL_FULLSCREEN;
   241 				switch_time = SDL_GetTicks() + 1500;
   242 			}
   243 
   244 			/* request to quit */
   245 			else if (winEvent->event_f==Ph_WM_CLOSE)
   246 			{
   247 				posted = SDL_PrivateQuit();
   248 			}
   249 		}
   250 		break;
   251 		
   252 		/* window has been resized, moved or removed */
   253 		case Ph_EV_EXPOSE:
   254 		{
   255 
   256 			if (SDL_VideoSurface)
   257 			{
   258 			  
   259 			  
   260 					rect = PhGetRects( event );
   261 
   262 				//PgSetClipping(1, rect );
   263 				 for(i=0;i<event->num_rects;i++)
   264 			   {
   265 			      sdlrects[i].x = rect[i].ul.x;
   266 			      sdlrects[i].y = rect[i].ul.y;
   267 			      sdlrects[i].w = rect[i].lr.x - rect[i].ul.x;
   268 			      sdlrects[i].h = rect[i].lr.y - rect[i].ul.y;
   269 			      	
   270 				}
   271 			
   272 					this->UpdateRects(this, event->num_rects, sdlrects);
   273 
   274 			}
   275 		}
   276 		break;
   277 
   278 		case Ph_EV_KEY:
   279 		{
   280 	
   281 			SDL_keysym keysym;
   282 			
   283 			posted = 0;
   284 			
   285 			keyEvent = PhGetData( event );
   286 
   287 			if (Pk_KF_Key_Down & keyEvent->key_flags)
   288 			{
   289 				
   290 				posted = SDL_PrivateKeyboard(SDL_PRESSED,
   291                 			ph_TranslateKey( keyEvent, &keysym));
   292 			}
   293 			else /* must be key release */
   294  			{
   295  				/* Ignore repeated key release events */
   296 				/*if (! Pk_KF_Key_Repeat & keyEvent->key_flags )*/
   297 				
   298 					posted = SDL_PrivateKeyboard(SDL_RELEASED,
   299         					ph_TranslateKey( keyEvent, &keysym));
   300 				/*}*/
   301 			}
   302 		}
   303 		break;
   304 	}
   305 	
   306 		
   307 	
   308 	return(posted);
   309 }
   310 
   311 /* perform a blocking read if no events available */
   312 int ph_Pending(_THIS)
   313 {
   314 	
   315 	/* Flush the display connection and look to see if events are queued */
   316 
   317 	PgFlush();
   318 
   319      while( 1 )
   320       {   //note this is a non-blocking call
   321           switch( PhEventPeek( event, EVENT_SIZE ) )
   322            {
   323               case Ph_EVENT_MSG:
   324                  
   325                  return 1;
   326                  break;
   327               case -1:
   328                  perror( "PhEventNext failed" );
   329                  break;
   330               default:
   331              	  
   332                 return 0;
   333        }
   334    }
   335 
   336 	/* Oh well, nothing is ready .. */
   337 	return(0);
   338 }
   339 
   340 /*
   341 SAMPLE EVENT PUMP
   342 =================
   343 static void update( int block ){
   344 
   345     int ch,fl;
   346     PhKeyEvent_t *key;
   347 
   348     for( ;; ){
   349 
   350         if( block ){
   351             do{
   352                 fl=PhEventNext( event,EVENT_SIZE );
   353             }while( fl!=Ph_EVENT_MSG );
   354             block=0;
   355         }else{
   356             do{
   357                 fl=PhEventPeek( event,EVENT_SIZE );
   358                 if( !fl ) return;
   359             }while( fl!=Ph_EVENT_MSG );
   360         }
   361 
   362         switch( event->type ){
   363         case Ph_EV_KEY:
   364             key=PhGetData( event );
   365             ch=key->key_cap;    // & 127;
   366             fl=key->key_flags;
   367             if( ch<32 || ch>127 ) break;
   368             if( fl & Pk_KF_Key_Down ){
   369                 if( !(fl & Pk_KF_Key_Repeat) ){
   370                     if( queput-queget<QUE_SIZE ) keyque[ queput++ & QUE_MASK ]=ch;
   371                     keyMatrix[ch]=1;
   372                 }
   373             }else{
   374                 keyMatrix[ch]=0;
   375             }
   376             break;
   377         default:
   378             PtEventHandler( event );
   379         }
   380     }
   381 }
   382 */
   383 
   384 void ph_PumpEvents(_THIS)
   385 {
   386 	int pending;
   387 
   388 	/* Keep processing pending events */
   389 	pending = 0;
   390 	while ( ph_Pending(this) ) {
   391 		ph_DispatchEvent(this);
   392 		++pending;
   393 	}
   394 	if ( switch_waiting ) {
   395 		Uint32 now;
   396 
   397 		now  = SDL_GetTicks();
   398 		if ( pending || !SDL_VideoSurface ) {
   399 			/* Try again later... */
   400 			if ( switch_waiting & SDL_FULLSCREEN ) {
   401 				switch_time = now + 1500;
   402 			} else {
   403 				switch_time = now + 200;
   404 			}
   405 		} else if ( now >= switch_time ) {
   406 			Uint32 go_fullscreen;
   407 
   408 			go_fullscreen = switch_waiting & SDL_FULLSCREEN;
   409 			switch_waiting = 0;
   410 			if ( SDL_VideoSurface->flags & SDL_FULLSCREEN ) {
   411 				if ( go_fullscreen ) {
   412 					ph_EnterFullScreen(this);
   413 				} else {
   414 					ph_LeaveFullScreen(this);
   415 				}
   416 			}
   417 			/* Handle focus in/out when grabbed */
   418 /*
   419 			if ( go_fullscreen ) {
   420 				ph_GrabInputNoLock(this, this->input_grab);
   421 			} else {
   422 				ph_GrabInputNoLock(this, SDL_GRAB_OFF);
   423 			}
   424 */
   425 		}
   426 	}
   427 }
   428 
   429 void ph_InitKeymap(void)
   430 {
   431 	int i;
   432 
   433 	/* Odd keys used in international keyboards */
   434 	for ( i=0; i<SDL_TABLESIZE(ODD_keymap); ++i )
   435 		ODD_keymap[i] = SDLK_UNKNOWN;
   436 
   437 	/* Map the miscellaneous keys */
   438 	for ( i=0; i<SDL_TABLESIZE(MISC_keymap); ++i )
   439 		MISC_keymap[i] = SDLK_UNKNOWN;
   440 
   441 	MISC_keymap[Pk_BackSpace&0xFF] = SDLK_BACKSPACE;
   442 	MISC_keymap[Pk_Tab&0xFF] = SDLK_TAB;
   443 	MISC_keymap[Pk_Clear&0xFF] = SDLK_CLEAR;
   444 	MISC_keymap[Pk_Return&0xFF] = SDLK_RETURN;
   445 	MISC_keymap[Pk_Pause&0xFF] = SDLK_PAUSE;
   446 	MISC_keymap[Pk_Escape&0xFF] = SDLK_ESCAPE;
   447 	MISC_keymap[Pk_Delete&0xFF] = SDLK_DELETE;
   448 
   449 	MISC_keymap[Pk_KP_0&0xFF] = SDLK_KP0;
   450 	MISC_keymap[Pk_KP_1&0xFF] = SDLK_KP1;
   451 	MISC_keymap[Pk_KP_2&0xFF] = SDLK_KP2;
   452 	MISC_keymap[Pk_KP_3&0xFF] = SDLK_KP3;
   453 	MISC_keymap[Pk_KP_4&0xFF] = SDLK_KP4;
   454 	MISC_keymap[Pk_KP_5&0xFF] = SDLK_KP5;
   455 	MISC_keymap[Pk_KP_6&0xFF] = SDLK_KP6;
   456 	MISC_keymap[Pk_KP_7&0xFF] = SDLK_KP7;
   457 	MISC_keymap[Pk_KP_8&0xFF] = SDLK_KP8;
   458 	MISC_keymap[Pk_KP_9&0xFF] = SDLK_KP9;
   459 
   460 	MISC_keymap[Pk_KP_Decimal&0xFF] = SDLK_KP_PERIOD;
   461 	MISC_keymap[Pk_KP_Divide&0xFF] = SDLK_KP_DIVIDE;
   462 	MISC_keymap[Pk_KP_Multiply&0xFF] = SDLK_KP_MULTIPLY;
   463 	MISC_keymap[Pk_KP_Subtract&0xFF] = SDLK_KP_MINUS;
   464 	MISC_keymap[Pk_KP_Add&0xFF] = SDLK_KP_PLUS;
   465 	MISC_keymap[Pk_KP_Enter&0xFF] = SDLK_KP_ENTER;
   466 	MISC_keymap[Pk_KP_Equal&0xFF] = SDLK_KP_EQUALS;
   467 
   468 	MISC_keymap[Pk_Up&0xFF] = SDLK_UP;
   469 	MISC_keymap[Pk_Down&0xFF] = SDLK_DOWN;
   470 	MISC_keymap[Pk_Right&0xFF] = SDLK_RIGHT;
   471 	MISC_keymap[Pk_Left&0xFF] = SDLK_LEFT;
   472 	MISC_keymap[Pk_Insert&0xFF] = SDLK_INSERT;
   473 	MISC_keymap[Pk_Home&0xFF] = SDLK_HOME;
   474 	MISC_keymap[Pk_End&0xFF] = SDLK_END;
   475 	MISC_keymap[Pk_Pg_Up&0xFF] = SDLK_PAGEUP;
   476 	MISC_keymap[Pk_Pg_Down&0xFF] = SDLK_PAGEDOWN;
   477 
   478 	MISC_keymap[Pk_F1&0xFF] = SDLK_F1;
   479 	MISC_keymap[Pk_F2&0xFF] = SDLK_F2;
   480 	MISC_keymap[Pk_F3&0xFF] = SDLK_F3;
   481 	MISC_keymap[Pk_F4&0xFF] = SDLK_F4;
   482 	MISC_keymap[Pk_F5&0xFF] = SDLK_F5;
   483 	MISC_keymap[Pk_F6&0xFF] = SDLK_F6;
   484 	MISC_keymap[Pk_F7&0xFF] = SDLK_F7;
   485 	MISC_keymap[Pk_F8&0xFF] = SDLK_F8;
   486 	MISC_keymap[Pk_F9&0xFF] = SDLK_F9;
   487 	MISC_keymap[Pk_F10&0xFF] = SDLK_F10;
   488 	MISC_keymap[Pk_F11&0xFF] = SDLK_F11;
   489 	MISC_keymap[Pk_F12&0xFF] = SDLK_F12;
   490 	MISC_keymap[Pk_F13&0xFF] = SDLK_F13;
   491 	MISC_keymap[Pk_F14&0xFF] = SDLK_F14;
   492 	MISC_keymap[Pk_F15&0xFF] = SDLK_F15;
   493 
   494 	MISC_keymap[Pk_Num_Lock&0xFF] = SDLK_NUMLOCK;
   495 	MISC_keymap[Pk_Caps_Lock&0xFF] = SDLK_CAPSLOCK;
   496 	MISC_keymap[Pk_Scroll_Lock&0xFF] = SDLK_SCROLLOCK;
   497 	MISC_keymap[Pk_Shift_R&0xFF] = SDLK_RSHIFT;
   498 	MISC_keymap[Pk_Shift_L&0xFF] = SDLK_LSHIFT;
   499 	MISC_keymap[Pk_Control_R&0xFF] = SDLK_RCTRL;
   500 	MISC_keymap[Pk_Control_L&0xFF] = SDLK_LCTRL;
   501 	MISC_keymap[Pk_Alt_R&0xFF] = SDLK_RALT;
   502 	MISC_keymap[Pk_Alt_L&0xFF] = SDLK_LALT;
   503 	MISC_keymap[Pk_Meta_R&0xFF] = SDLK_RMETA;
   504 	MISC_keymap[Pk_Meta_L&0xFF] = SDLK_LMETA;
   505 	MISC_keymap[Pk_Super_L&0xFF] = SDLK_LSUPER; /* Left "Windows" */
   506 	MISC_keymap[Pk_Super_R&0xFF] = SDLK_RSUPER; /* Right "Windows */
   507 	MISC_keymap[Pk_Mode_switch&0xFF] = SDLK_MODE; /* "Alt Gr" key */
   508 
   509 	MISC_keymap[Pk_Help&0xFF] = SDLK_HELP;
   510 	MISC_keymap[Pk_Print&0xFF] = SDLK_PRINT;
   511 //	MISC_keymap[Pk_Sys_Req] = SDLK_SYSREQ;
   512 	MISC_keymap[Pk_Break&0xFF] = SDLK_BREAK;
   513 	MISC_keymap[Pk_Menu&0xFF] = SDLK_MENU;
   514 	MISC_keymap[Pk_Hyper_R&0xFF] = SDLK_MENU;   /* Windows "Menu" key */
   515 }
   516 
   517 static unsigned long cap;
   518 
   519 SDL_keysym *ph_TranslateKey(PhKeyEvent_t *key, SDL_keysym *keysym)
   520 {
   521 /*	
   522 	'sym' is set to the value of the key with modifiers applied to it. 
   523 	This member is valid only if Pk_KF_Sym_Valid is set in the key_flags.
   524 	We will assume it is valid.
   525 */
   526 	cap = key->key_cap;
   527     switch (cap>>8) {
   528             case 0x00:  /* Latin 1 */
   529             case 0x01:  /* Latin 2 */
   530             case 0x02:  /* Latin 3 */
   531             case 0x03:  /* Latin 4 */
   532             case 0x04:  /* Katakana */
   533             case 0x05:  /* Arabic */
   534             case 0x06:  /* Cyrillic */
   535             case 0x07:  /* Greek */
   536             case 0x08:  /* Technical */
   537             case 0x0A:  /* Publishing */
   538             case 0x0C:  /* Hebrew */
   539             case 0x0D:  /* Thai */
   540                 keysym->sym = (SDLKey)(cap&0xFF);
   541                 /* Map capital letter syms to lowercase */
   542                 if ((keysym->sym >= 'A')&&(keysym->sym <= 'Z'))
   543                     keysym->sym += ('a'-'A');
   544                 break;
   545 //            case 0xFE:
   546 //                keysym->sym = ODD_keymap[sym&0xFF];
   547 //                break;
   548             case 0xF0:
   549                 keysym->sym = MISC_keymap[cap&0xFF];
   550                 break;
   551             default:
   552                 fprintf(stderr,"Photon: Unknown key_cap, cap = 0x%.4x\n", (unsigned int)cap);
   553                 break;
   554     }	
   555 	return (keysym);
   556 }
   557 
   558 void ph_InitOSKeymap(_THIS)
   559 {
   560 
   561 	ph_InitKeymap();
   562 }
   563