blob: 6704e23772d0f68cef47e28fa61a3e3b1f1757b6 [file] [log] [blame]
/*
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 <stdio.h>
#include <setjmp.h>
#include <sys/time.h>
#include <Ph.h>
#include <photon/PkKeyDef.h>
#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, &region, NULL, NULL, 0) == 0) {
region.events_sense =
(region.events_sense & ~fields) | (flags & fields);
PhRegionChange(Ph_REGION_EV_SENSE, 0, &region, 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: */