/* SDL - Simple DirectMedia Layer Copyright (C) 1997-2006 Sam Lantinga This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA Sam Lantinga slouken@libsdl.org */ #include "SDL_config.h" /* Handle the event stream, converting photon events into SDL events */ #include #include #include #include #include #include "SDL.h" #include "SDL_syswm.h" #include "../SDL_sysvideo.h" #include "../../events/SDL_sysevents.h" #include "../../events/SDL_events_c.h" #include "SDL_ph_video.h" #include "SDL_ph_modes_c.h" #include "SDL_ph_image_c.h" #include "SDL_ph_events_c.h" #include "SDL_phyuv_c.h" /* The translation tables from a photon keysym to a SDL keysym */ static SDLKey ODD_keymap[256]; static SDLKey MISC_keymap[0xFF + 1]; SDL_keysym *ph_TranslateKey (PhKeyEvent_t * key, SDL_keysym * keysym); /* Check to see if this is a repeated key. (idea shamelessly lifted from GII -- thanks guys! :) */ static int ph_WarpedMotion (_THIS, PhEvent_t * winEvent) { PhRect_t *rect = PhGetRects (winEvent); int centre_x, centre_y; int dx, dy; short abs_x, abs_y; int posted; centre_x = SDL_VideoSurface->w / 2; centre_y = SDL_VideoSurface->h / 2; dx = rect->ul.x - centre_x; dy = rect->ul.y - centre_y; posted = SDL_PrivateMouseMotion (0, 1, dx, dy); /* Move mouse cursor to middle of the window */ PtGetAbsPosition (window, &abs_x, &abs_y); PhMoveCursorAbs (PhInputGroup (NULL), abs_x + centre_x, abs_y + centre_y); return (posted); } /* Control which motion flags the window has set, a flags value of -1 sets * MOTION_BUTTON and MOTION_NOBUTTON */ static void set_motion_sensitivity (_THIS, unsigned int flags) { int rid; int fields = Ph_EV_PTR_MOTION_BUTTON | Ph_EV_PTR_MOTION_NOBUTTON; PhRegion_t region; if (window) { rid = PtWidgetRid (window); if (rid != 0 && PhRegionQuery (rid, ®ion, NULL, NULL, 0) == 0) { region.events_sense = (region.events_sense & ~fields) | (flags & fields); PhRegionChange (Ph_REGION_EV_SENSE, 0, ®ion, NULL, NULL); } } } /* Convert the photon button state value to an SDL value */ static Uint8 ph2sdl_mousebutton (unsigned short button_state) { Uint8 mouse_button = 0; if (button_state & Ph_BUTTON_SELECT) mouse_button |= SDL_BUTTON_LEFT; if (button_state & Ph_BUTTON_MENU) mouse_button |= SDL_BUTTON_RIGHT; if (button_state & Ph_BUTTON_ADJUST) mouse_button |= SDL_BUTTON_MIDDLE; return (mouse_button); } static int ph_DispatchEvent (_THIS) { int posted; PhRect_t *rect; PhPointerEvent_t *pointerEvent; PhKeyEvent_t *keyEvent; PhWindowEvent_t *winEvent; int i, buttons; SDL_Rect sdlrects[PH_SDL_MAX_RECTS]; posted = 0; switch (phevent->type) { case Ph_EV_BOUNDARY: { if (phevent->subtype == Ph_EV_PTR_ENTER) { posted = SDL_PrivateAppActive (1, SDL_APPMOUSEFOCUS); } else if (phevent->subtype == Ph_EV_PTR_LEAVE) { posted = SDL_PrivateAppActive (0, SDL_APPMOUSEFOCUS); } } break; case Ph_EV_PTR_MOTION_BUTTON: case Ph_EV_PTR_MOTION_NOBUTTON: { if (SDL_VideoSurface) { pointerEvent = PhGetData (phevent); rect = PhGetRects (phevent); if (mouse_relative) { posted = ph_WarpedMotion (this, phevent); } else { posted = SDL_PrivateMouseMotion (0, 0, rect->ul.x, rect->ul.y); } } } break; case Ph_EV_BUT_PRESS: { pointerEvent = PhGetData (phevent); buttons = ph2sdl_mousebutton (pointerEvent->buttons); if (buttons != 0) { posted = SDL_PrivateMouseButton (SDL_PRESSED, buttons, 0, 0); } } break; case Ph_EV_BUT_RELEASE: { pointerEvent = PhGetData (phevent); buttons = ph2sdl_mousebutton (pointerEvent->buttons); if (phevent->subtype == Ph_EV_RELEASE_REAL && buttons != 0) { posted = SDL_PrivateMouseButton (SDL_RELEASED, buttons, 0, 0); } else if (phevent->subtype == Ph_EV_RELEASE_PHANTOM) { /* If the mouse is outside the window, * only a phantom release event is sent, so * check if the window doesn't have mouse focus. * Not perfect, maybe checking the mouse button * state for Ph_EV_BOUNDARY events would be * better. */ if ((SDL_GetAppState () & SDL_APPMOUSEFOCUS) == 0) { posted = SDL_PrivateMouseButton (SDL_RELEASED, buttons, 0, 0); } } } break; case Ph_EV_WM: { winEvent = PhGetData (phevent); /* losing focus */ if ((winEvent->event_f == Ph_WM_FOCUS) && (winEvent->event_state == Ph_WM_EVSTATE_FOCUSLOST)) { set_motion_sensitivity (this, Ph_EV_PTR_MOTION_BUTTON); posted = SDL_PrivateAppActive (0, SDL_APPINPUTFOCUS); } /* gaining focus */ else if ((winEvent->event_f == Ph_WM_FOCUS) && (winEvent->event_state == Ph_WM_EVSTATE_FOCUS)) { set_motion_sensitivity (this, -1); posted = SDL_PrivateAppActive (1, SDL_APPINPUTFOCUS); } /* request quit */ else if (winEvent->event_f == Ph_WM_CLOSE) { posted = SDL_PrivateQuit (); } /* request hide/unhide */ else if (winEvent->event_f == Ph_WM_HIDE) { if (currently_hided) { /* got unhide window event */ /* TODO: restore application's palette if in palette mode */ currently_hided = 0; } else { /* got hide window event */ /* TODO: restore original palette if in palette mode */ currently_hided = 1; } } /* request to resize */ else if (winEvent->event_f == Ph_WM_RESIZE) { currently_maximized = 0; #if (_NTO_VERSION < 630) SDL_PrivateResize (winEvent->size.w + 1, winEvent->size.h + 1); #else /* QNX 6.3.0 have this bug fixed */ SDL_PrivateResize (winEvent->size.w, winEvent->size.h); #endif /* _NTO_VERSION */ } /* request to move */ else if (winEvent->event_f == Ph_WM_MOVE) { if (current_overlay != NULL) { int lockedstate = current_overlay->hwdata->locked; int chromastate = current_overlay->hwdata->ischromakey; int error; SDL_Rect src, dst; current_overlay->hwdata->locked = 1; src.x = 0; src.y = 0; src.w = current_overlay->w; src.y = current_overlay->h; dst.x = current_overlay->hwdata->CurrentViewPort.pos.x; dst.y = current_overlay->hwdata->CurrentViewPort.pos.y; dst.w = current_overlay->hwdata->CurrentViewPort.size.w; dst.h = current_overlay->hwdata->CurrentViewPort.size.h; current_overlay->hwdata->ischromakey = 0; error = ph_DisplayYUVOverlay (this, current_overlay, &src, &dst); if (!error) { current_overlay->hwdata->ischromakey = chromastate; current_overlay->hwdata->locked = lockedstate; } } } /* maximize request */ else if (winEvent->event_f == Ph_WM_MAX) { /* window already moved and resized here */ currently_maximized = 1; } /* restore request */ else if (winEvent->event_f == Ph_WM_RESTORE) { /* window already moved and resized here */ currently_maximized = 0; } } break; /* window has been resized, moved or removed */ case Ph_EV_EXPOSE: { if (phevent->num_rects != 0) { int numrects; if (SDL_VideoSurface) { rect = PhGetRects (phevent); if (phevent->num_rects > PH_SDL_MAX_RECTS) { /* sorry, buffers underrun, we'll update only first PH_SDL_MAX_RECTS rects */ numrects = PH_SDL_MAX_RECTS; } for (i = 0; i < phevent->num_rects; i++) { sdlrects[i].x = rect[i].ul.x; sdlrects[i].y = rect[i].ul.y; sdlrects[i].w = rect[i].lr.x - rect[i].ul.x + 1; sdlrects[i].h = rect[i].lr.y - rect[i].ul.y + 1; } this->UpdateRects (this, phevent->num_rects, sdlrects); if (current_overlay != NULL) { int lockedstate = current_overlay->hwdata->locked; int error; SDL_Rect src, dst; current_overlay->hwdata->locked = 1; src.x = 0; src.y = 0; src.w = current_overlay->w; src.y = current_overlay->h; dst.x = current_overlay->hwdata->CurrentViewPort.pos.x; dst.y = current_overlay->hwdata->CurrentViewPort.pos.y; dst.w = current_overlay->hwdata->CurrentViewPort.size.w; dst.h = current_overlay->hwdata->CurrentViewPort.size.h; current_overlay->hwdata->forcedredraw = 1; error = ph_DisplayYUVOverlay (this, current_overlay, &src, &dst); if (!error) { current_overlay->hwdata->forcedredraw = 0; current_overlay->hwdata->locked = lockedstate; } } } } } break; case Ph_EV_KEY: { SDL_keysym keysym; posted = 0; keyEvent = PhGetData (phevent); if (Pk_KF_Key_Down & keyEvent->key_flags) { /* split the wheel events from real key events */ if ((keyEvent->key_cap == Pk_Up) && (keyEvent->key_scan == 0) && ((keyEvent->key_flags & Pk_KF_Scan_Valid) == Pk_KF_Scan_Valid)) { posted = SDL_PrivateMouseButton (SDL_PRESSED, SDL_BUTTON_WHEELUP, 0, 0); break; } if ((keyEvent->key_cap == Pk_Down) && (keyEvent->key_scan == 0) && ((keyEvent->key_flags & Pk_KF_Scan_Valid) == Pk_KF_Scan_Valid)) { posted = SDL_PrivateMouseButton (SDL_PRESSED, SDL_BUTTON_WHEELDOWN, 0, 0); break; } posted = SDL_PrivateKeyboard (SDL_PRESSED, ph_TranslateKey (keyEvent, &keysym)); } else { /* must be key release */ /* split the wheel events from real key events */ if ((keyEvent->key_cap == Pk_Up) && (keyEvent->key_scan == 0) && ((keyEvent->key_flags & Pk_KF_Scan_Valid) == Pk_KF_Scan_Valid)) { posted = SDL_PrivateMouseButton (SDL_RELEASED, SDL_BUTTON_WHEELUP, 0, 0); break; } if ((keyEvent->key_cap == Pk_Down) && (keyEvent->key_scan == 0) && ((keyEvent->key_flags & Pk_KF_Scan_Valid) == Pk_KF_Scan_Valid)) { posted = SDL_PrivateMouseButton (SDL_RELEASED, SDL_BUTTON_WHEELDOWN, 0, 0); break; } posted = SDL_PrivateKeyboard (SDL_RELEASED, ph_TranslateKey (keyEvent, &keysym)); } } break; case Ph_EV_INFO: { if (phevent->subtype == Ph_OFFSCREEN_INVALID) { unsigned long *EvInfoData; EvInfoData = (unsigned long *) PhGetData (phevent); switch (*EvInfoData) { case Pg_VIDEO_MODE_SWITCHED: { } break; case Pg_ENTERED_DIRECT: { } break; case Pg_EXITED_DIRECT: { } break; case Pg_DRIVER_STARTED: { } break; } } } break; } return (posted); } /* perform a blocking read if no events available */ int ph_Pending (_THIS) { /* Flush the display connection and look to see if events are queued */ PgFlush (); while (1) { switch (PhEventPeek (phevent, EVENT_SIZE)) { case Ph_EVENT_MSG: return 1; case -1: SDL_SetError ("ph_Pending(): PhEventNext failed.\n"); return 0; default: return 0; } } /* Oh well, nothing is ready .. */ return (0); } void ph_PumpEvents (_THIS) { /* Flush the display connection and look to see if events are queued */ PgFlush (); while (ph_Pending (this)) { PtEventHandler (phevent); ph_DispatchEvent (this); } } void ph_InitKeymap (void) { int i; /* Odd keys used in international keyboards */ for (i = 0; i < SDL_arraysize (ODD_keymap); ++i) { ODD_keymap[i] = SDLK_UNKNOWN; } /* Map the miscellaneous keys */ for (i = 0; i < SDL_arraysize (MISC_keymap); ++i) { MISC_keymap[i] = SDLK_UNKNOWN; } MISC_keymap[Pk_BackSpace & 0xFF] = SDLK_BACKSPACE; MISC_keymap[Pk_Tab & 0xFF] = SDLK_TAB; MISC_keymap[Pk_Clear & 0xFF] = SDLK_CLEAR; MISC_keymap[Pk_Return & 0xFF] = SDLK_RETURN; MISC_keymap[Pk_Pause & 0xFF] = SDLK_PAUSE; MISC_keymap[Pk_Escape & 0xFF] = SDLK_ESCAPE; MISC_keymap[Pk_Delete & 0xFF] = SDLK_DELETE; MISC_keymap[Pk_KP_0 & 0xFF] = SDLK_KP0; MISC_keymap[Pk_KP_1 & 0xFF] = SDLK_KP1; MISC_keymap[Pk_KP_2 & 0xFF] = SDLK_KP2; MISC_keymap[Pk_KP_3 & 0xFF] = SDLK_KP3; MISC_keymap[Pk_KP_4 & 0xFF] = SDLK_KP4; MISC_keymap[Pk_KP_5 & 0xFF] = SDLK_KP5; MISC_keymap[Pk_KP_6 & 0xFF] = SDLK_KP6; MISC_keymap[Pk_KP_7 & 0xFF] = SDLK_KP7; MISC_keymap[Pk_KP_8 & 0xFF] = SDLK_KP8; MISC_keymap[Pk_KP_9 & 0xFF] = SDLK_KP9; MISC_keymap[Pk_KP_Decimal & 0xFF] = SDLK_KP_PERIOD; MISC_keymap[Pk_KP_Divide & 0xFF] = SDLK_KP_DIVIDE; MISC_keymap[Pk_KP_Multiply & 0xFF] = SDLK_KP_MULTIPLY; MISC_keymap[Pk_KP_Subtract & 0xFF] = SDLK_KP_MINUS; MISC_keymap[Pk_KP_Add & 0xFF] = SDLK_KP_PLUS; MISC_keymap[Pk_KP_Enter & 0xFF] = SDLK_KP_ENTER; MISC_keymap[Pk_KP_Equal & 0xFF] = SDLK_KP_EQUALS; MISC_keymap[Pk_Up & 0xFF] = SDLK_UP; MISC_keymap[Pk_Down & 0xFF] = SDLK_DOWN; MISC_keymap[Pk_Right & 0xFF] = SDLK_RIGHT; MISC_keymap[Pk_Left & 0xFF] = SDLK_LEFT; MISC_keymap[Pk_Insert & 0xFF] = SDLK_INSERT; MISC_keymap[Pk_Home & 0xFF] = SDLK_HOME; MISC_keymap[Pk_End & 0xFF] = SDLK_END; MISC_keymap[Pk_Pg_Up & 0xFF] = SDLK_PAGEUP; MISC_keymap[Pk_Pg_Down & 0xFF] = SDLK_PAGEDOWN; MISC_keymap[Pk_F1 & 0xFF] = SDLK_F1; MISC_keymap[Pk_F2 & 0xFF] = SDLK_F2; MISC_keymap[Pk_F3 & 0xFF] = SDLK_F3; MISC_keymap[Pk_F4 & 0xFF] = SDLK_F4; MISC_keymap[Pk_F5 & 0xFF] = SDLK_F5; MISC_keymap[Pk_F6 & 0xFF] = SDLK_F6; MISC_keymap[Pk_F7 & 0xFF] = SDLK_F7; MISC_keymap[Pk_F8 & 0xFF] = SDLK_F8; MISC_keymap[Pk_F9 & 0xFF] = SDLK_F9; MISC_keymap[Pk_F10 & 0xFF] = SDLK_F10; MISC_keymap[Pk_F11 & 0xFF] = SDLK_F11; MISC_keymap[Pk_F12 & 0xFF] = SDLK_F12; MISC_keymap[Pk_F13 & 0xFF] = SDLK_F13; MISC_keymap[Pk_F14 & 0xFF] = SDLK_F14; MISC_keymap[Pk_F15 & 0xFF] = SDLK_F15; MISC_keymap[Pk_Num_Lock & 0xFF] = SDLK_NUMLOCK; MISC_keymap[Pk_Caps_Lock & 0xFF] = SDLK_CAPSLOCK; MISC_keymap[Pk_Scroll_Lock & 0xFF] = SDLK_SCROLLOCK; MISC_keymap[Pk_Shift_R & 0xFF] = SDLK_RSHIFT; MISC_keymap[Pk_Shift_L & 0xFF] = SDLK_LSHIFT; MISC_keymap[Pk_Control_R & 0xFF] = SDLK_RCTRL; MISC_keymap[Pk_Control_L & 0xFF] = SDLK_LCTRL; MISC_keymap[Pk_Alt_R & 0xFF] = SDLK_RALT; MISC_keymap[Pk_Alt_L & 0xFF] = SDLK_LALT; MISC_keymap[Pk_Meta_R & 0xFF] = SDLK_RMETA; MISC_keymap[Pk_Meta_L & 0xFF] = SDLK_LMETA; MISC_keymap[Pk_Super_L & 0xFF] = SDLK_LSUPER; MISC_keymap[Pk_Super_R & 0xFF] = SDLK_RSUPER; MISC_keymap[Pk_Mode_switch & 0xFF] = SDLK_MODE; /* "Alt Gr" key */ MISC_keymap[Pk_Help & 0xFF] = SDLK_HELP; MISC_keymap[Pk_Print & 0xFF] = SDLK_PRINT; MISC_keymap[Pk_Break & 0xFF] = SDLK_BREAK; MISC_keymap[Pk_Menu & 0xFF] = SDLK_MENU; /* Windows "Menu" key */ MISC_keymap[Pk_Hyper_R & 0xFF] = SDLK_RSUPER; /* Right "Windows" */ /* Left "Windows" key, but it can't be catched by application */ MISC_keymap[Pk_Hyper_L & 0xFF] = SDLK_LSUPER; } static unsigned long cap; SDL_keysym * ph_TranslateKey (PhKeyEvent_t * key, SDL_keysym * keysym) { /* 'sym' is set to the value of the key with modifiers applied to it. This member is valid only if Pk_KF_Sym_Valid is set in the key_flags. We will assume it is valid. */ /* FIXME: This needs to check whether the cap & scancode is valid */ cap = key->key_cap; switch (cap >> 8) { case 0x00: /* Latin 1 */ case 0x01: /* Latin 2 */ case 0x02: /* Latin 3 */ case 0x03: /* Latin 4 */ case 0x04: /* Katakana */ case 0x05: /* Arabic */ case 0x06: /* Cyrillic */ case 0x07: /* Greek */ case 0x08: /* Technical */ case 0x0A: /* Publishing */ case 0x0C: /* Hebrew */ case 0x0D: /* Thai */ keysym->sym = (SDLKey) (cap & 0xFF); /* Map capital letter syms to lowercase */ if ((keysym->sym >= 'A') && (keysym->sym <= 'Z')) keysym->sym += ('a' - 'A'); break; case 0xF0: keysym->sym = MISC_keymap[cap & 0xFF]; break; default: keysym->sym = SDLK_UNKNOWN; break; } keysym->scancode = key->key_scan; keysym->unicode = 0; if (SDL_TranslateUNICODE) { char utf8[MB_CUR_MAX]; int utf8len; wchar_t unicode; switch (keysym->scancode) { /* Esc key */ case 0x01: keysym->unicode = 27; break; /* BackSpace key */ case 0x0E: keysym->unicode = 127; break; /* Enter key */ case 0x1C: keysym->unicode = 10; break; default: utf8len = PhKeyToMb (utf8, key); if (utf8len > 0) { utf8len = mbtowc (&unicode, utf8, utf8len); if (utf8len > 0) { keysym->unicode = unicode; } } break; } } return (keysym); } void ph_InitOSKeymap (_THIS) { ph_InitKeymap (); } /* vi: set ts=4 sw=4 expandtab: */