From a855d6202536ff28e5aae4f22a0f31d8f5b325d0 Mon Sep 17 00:00:00 2001 From: Franklin Wei Date: Sat, 21 Jan 2017 15:18:31 -0500 Subject: Port of Duke Nukem 3D This ports Fabien Sanglard's Chocolate Duke to run on a version of SDL for Rockbox. Change-Id: I8f2c4c78af19de10c1633ed7bb7a997b43256dd9 --- .../sdl/src/video/maccommon/SDL_macevents.c | 746 +++++++++++++++++++++ 1 file changed, 746 insertions(+) create mode 100644 apps/plugins/sdl/src/video/maccommon/SDL_macevents.c (limited to 'apps/plugins/sdl/src/video/maccommon/SDL_macevents.c') diff --git a/apps/plugins/sdl/src/video/maccommon/SDL_macevents.c b/apps/plugins/sdl/src/video/maccommon/SDL_macevents.c new file mode 100644 index 0000000000..6e3fef2d60 --- /dev/null +++ b/apps/plugins/sdl/src/video/maccommon/SDL_macevents.c @@ -0,0 +1,746 @@ +/* + SDL - Simple DirectMedia Layer + Copyright (C) 1997-2012 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" + +#include + +#if defined(__APPLE__) && defined(__MACH__) +#include +#elif TARGET_API_MAC_CARBON && (UNIVERSAL_INTERFACES_VERSION > 0x0335) +#include +#else +#include +#include +#include +#include +#include +#endif + +#include "SDL_events.h" +#include "SDL_video.h" +#include "SDL_syswm.h" +#include "../../events/SDL_events_c.h" +#include "../../events/SDL_sysevents.h" +#include "../SDL_cursor_c.h" +#include "SDL_macevents_c.h" +#include "SDL_mackeys.h" +#include "SDL_macmouse_c.h" + +/* Define this to be able to collapse SDL windows. +#define USE_APPEARANCE_MANAGER + */ + +/* Macintosh resource constants */ +#define mApple 128 /* Apple menu resource */ +#define iAbout 1 /* About menu item */ + +/* Functions to handle the About menu */ +static void Mac_DoAppleMenu(_THIS, long item); + +/* The translation table from a macintosh key scancode to a SDL keysym */ +static SDLKey MAC_keymap[256]; +static SDL_keysym *TranslateKey(int scancode, int modifiers, + SDL_keysym *keysym, int pressed); + +/* Handle activation and deactivation -- returns whether an event was posted */ +static int Mac_HandleActivate(int activate) +{ + if ( activate ) { + /* Show the current SDL application cursor */ + SDL_SetCursor(NULL); + + /* put our mask back case it changed during context switch */ + SetEventMask(everyEvent & ~autoKeyMask); + } else { +#if TARGET_API_MAC_CARBON + { Cursor cursor; + SetCursor(GetQDGlobalsArrow(&cursor)); + } +#else + SetCursor(&theQD->arrow); +#endif + if ( ! Mac_cursor_showing ) { + ShowCursor(); + Mac_cursor_showing = 1; + } + } + return(SDL_PrivateAppActive(activate, SDL_APPINPUTFOCUS)); +} + +static void myGlobalToLocal(_THIS, Point *pt) +{ + if ( SDL_VideoSurface && !(SDL_VideoSurface->flags&SDL_FULLSCREEN) ) { + GrafPtr saveport; + GetPort(&saveport); +#if TARGET_API_MAC_CARBON + SetPort(GetWindowPort(SDL_Window)); +#else + SetPort(SDL_Window); +#endif + GlobalToLocal(pt); + SetPort(saveport); + } +} + +/* The main MacOS event handler */ +static int Mac_HandleEvents(_THIS, int wait4it) +{ + static int mouse_button = 1; + int i; + EventRecord event; + +#if TARGET_API_MAC_CARBON + /* There's no GetOSEvent() in the Carbon API. *sigh* */ +#define cooperative_multitasking 1 +#else + int cooperative_multitasking; + /* If we're running fullscreen, we can hog the MacOS events, + otherwise we had better play nicely with the other apps. + */ + if ( this->screen && (this->screen->flags & SDL_FULLSCREEN) ) { + cooperative_multitasking = 0; + } else { + cooperative_multitasking = 1; + } +#endif + + /* If we call WaitNextEvent(), MacOS will check other processes + * and allow them to run, and perform other high-level processing. + */ + if ( cooperative_multitasking || wait4it ) { + UInt32 wait_time; + + /* Are we polling or not? */ + if ( wait4it ) { + wait_time = 2147483647; + } else { + wait_time = 0; + } + WaitNextEvent(everyEvent, &event, wait_time, nil); + } else { +#if ! TARGET_API_MAC_CARBON + GetOSEvent(everyEvent, &event); +#endif + } + +#if TARGET_API_MAC_CARBON + /* for some reason, event.where isn't set ? */ + GetGlobalMouse ( &event.where ); +#endif + + /* Check for mouse motion */ + if ( (event.where.h != last_where.h) || + (event.where.v != last_where.v) ) { + Point pt; + pt = last_where = event.where; + myGlobalToLocal(this, &pt); + SDL_PrivateMouseMotion(0, 0, pt.h, pt.v); + } + + /* Check the current state of the keyboard */ + if ( SDL_GetAppState() & SDL_APPINPUTFOCUS ) { + KeyMap keys; + const Uint32 *keysptr = (Uint32 *) &keys; + const Uint32 *last_keysptr = (Uint32 *) &last_keys; + + /* Check for special non-event keys */ + if ( event.modifiers != last_mods ) { + static struct { + EventModifiers mask; + SDLKey key; + } mods[] = { + { alphaLock, SDLK_CAPSLOCK }, +#if 0 /* These are handled below in the GetKeys() code */ + { cmdKey, SDLK_LMETA }, + { shiftKey, SDLK_LSHIFT }, + { rightShiftKey, SDLK_RSHIFT }, + { optionKey, SDLK_LALT }, + { rightOptionKey, SDLK_RALT }, + { controlKey, SDLK_LCTRL }, + { rightControlKey, SDLK_RCTRL }, +#endif /* 0 */ + { 0, 0 } + }; + SDL_keysym keysym; + Uint8 mode; + EventModifiers mod, mask; + + + /* Set up the keyboard event */ + keysym.scancode = 0; + keysym.sym = SDLK_UNKNOWN; + keysym.mod = KMOD_NONE; + keysym.unicode = 0; + + /* See what has changed, and generate events */ + mod = event.modifiers; + for ( i=0; mods[i].mask; ++i ) { + mask = mods[i].mask; + if ( (mod&mask) != (last_mods&mask) ) { + keysym.sym = mods[i].key; + if ( (mod&mask) || + (mods[i].key == SDLK_CAPSLOCK) ) { + mode = SDL_PRESSED; + } else { + mode = SDL_RELEASED; + } + SDL_PrivateKeyboard(mode, &keysym); + } + } + + /* Save state for next time */ + last_mods = mod; + } + + /* Check for normal event keys, but we have to scan the + actual keyboard state because on Mac OS X a keydown event + is immediately followed by a keyup event. + */ + GetKeys(keys); + if ( (keysptr[0] != last_keysptr[0]) || + (keysptr[1] != last_keysptr[1]) || + (keysptr[2] != last_keysptr[2]) || + (keysptr[3] != last_keysptr[3]) ) { + SDL_keysym keysym; + int old_bit, new_bit; + +#ifdef DEBUG_KEYBOARD + fprintf(sterr, "New keys: 0x%x 0x%x 0x%x 0x%x\n", + new_keys[0], new_keys[1], + new_keys[2], new_keys[3]); +#endif + for ( i=0; i<128; ++i ) { + old_bit = (((Uint8 *)last_keys)[i/8]>>(i%8)) & 0x01; + new_bit = (((Uint8 *)keys)[i/8]>>(i%8)) & 0x01; + if ( old_bit != new_bit ) { + /* Post the keyboard event */ +#ifdef DEBUG_KEYBOARD + fprintf(stderr,"Scancode: 0x%2.2X\n",i); +#endif + SDL_PrivateKeyboard(new_bit, + TranslateKey(i, event.modifiers, + &keysym, new_bit)); + } + } + + /* Save state for next time */ + last_keys[0] = keys[0]; + last_keys[1] = keys[1]; + last_keys[2] = keys[2]; + last_keys[3] = keys[3]; + } + } + + /* Handle normal events */ + switch (event.what) { + case mouseDown: { + WindowRef win; + short area; + + area = FindWindow(event.where, &win); + /* Support switching between the SIOUX console + and SDL_Window by clicking in the window. + */ + if ( win && (win != FrontWindow()) ) { + SelectWindow(win); + } + switch (area) { + case inMenuBar: /* Only the apple menu exists */ + Mac_DoAppleMenu(this, MenuSelect(event.where)); + HiliteMenu(0); + break; + case inDrag: +#if TARGET_API_MAC_CARBON + DragWindow(win, event.where, NULL); +#else + DragWindow(win, event.where, &theQD->screenBits.bounds); +#endif + break; + case inGoAway: + if ( TrackGoAway(win, event.where) ) { + SDL_PrivateQuit(); + } + break; + case inContent: + myGlobalToLocal(this, &event.where); + /* Treat command-click as right mouse button */ + if ( event.modifiers & optionKey ) { + mouse_button = 2; + } else if ( event.modifiers & cmdKey ) { + mouse_button = 3; + } else { + mouse_button = 1; + } + SDL_PrivateMouseButton(SDL_PRESSED, + mouse_button, event.where.h, event.where.v); + break; + case inGrow: { + int newSize; + + /* Don't allow resize if video mode isn't resizable */ + if ( ! SDL_PublicSurface || + ! (SDL_PublicSurface->flags & SDL_RESIZABLE) ) { + break; + } +#if TARGET_API_MAC_CARBON + newSize = GrowWindow(win, event.where, NULL); +#else + newSize = GrowWindow(win, event.where, &theQD->screenBits.bounds); +#endif + if ( newSize ) { +#if !TARGET_API_MAC_CARBON + EraseRect ( &theQD->screenBits.bounds ); +#endif + SizeWindow ( win, LoWord (newSize), HiWord (newSize), 1 ); + SDL_PrivateResize ( LoWord (newSize), HiWord (newSize) ); + } + } break; + case inZoomIn: + case inZoomOut: + if ( TrackBox (win, event.where, area )) { + Rect rect; +#if !TARGET_API_MAC_CARBON + EraseRect ( &theQD->screenBits.bounds ); +#endif + ZoomWindow ( win, area, 0); + if ( area == inZoomIn ) { + GetWindowUserState(SDL_Window, &rect); + } else { + GetWindowStandardState(SDL_Window, &rect); + } + SDL_PrivateResize (rect.right-rect.left, + rect.bottom-rect.top); + } + break; +#if TARGET_API_MAC_CARBON + case inCollapseBox: + if ( TrackBox (win, event.where, area )) { + if ( IsWindowCollapsable(win) ) { + CollapseWindow (win, !IsWindowCollapsed(win)); + /* There should be something done like in inGrow case, but... */ + } + } + break; +#endif /* TARGET_API_MAC_CARBON */ + case inSysWindow: +#if TARGET_API_MAC_CARBON + /* Never happens in Carbon? */ +#else + SystemClick(&event, win); +#endif + break; + default: + break; + } + } + break; + case mouseUp: { + myGlobalToLocal(this, &event.where); + /* Release the mouse button we simulated in the last press. + The drawback of this methos is we cannot press more than + one button. However, this doesn't matter, since there is + only a single logical mouse button, even if you have a + multi-button mouse, this doesn't matter at all. + */ + SDL_PrivateMouseButton(SDL_RELEASED, + mouse_button, event.where.h, event.where.v); + } + break; +#if 0 /* Handled above the switch statement */ + case keyDown: { + SDL_keysym keysym; + + SDL_PrivateKeyboard(SDL_PRESSED, + TranslateKey((event.message&keyCodeMask)>>8 + event.modifiers, &keysym, 1)); + } + break; + case keyUp: { + SDL_keysym keysym; + + SDL_PrivateKeyboard(SDL_RELEASED, + TranslateKey((event.message&keyCodeMask)>>8 + event.modifiers, &keysym, 0)); + } + break; +#endif + case updateEvt: { + BeginUpdate(SDL_Window); + #if SDL_VIDEO_OPENGL + if (SDL_VideoSurface->flags & SDL_OPENGL) + SDL_GL_SwapBuffers(); + else + #endif + if ( (SDL_VideoSurface->flags & SDL_HWSURFACE) == + SDL_SWSURFACE ) { + SDL_UpdateRect(SDL_VideoSurface, 0, 0, 0, 0); + } + EndUpdate(SDL_Window); + } + /* If this was an update event for the SIOUX console, we return 0 + in order to stop an endless series of updates being triggered. + */ + if ( (WindowRef) event.message != SDL_Window ) { + return 0; + } + break; + case activateEvt: { + Mac_HandleActivate(!!(event.modifiers & activeFlag)); + } + break; + case diskEvt: { +#if TARGET_API_MAC_CARBON + /* What are we supposed to do? */; +#else + if ( ((event.message>>16)&0xFFFF) != noErr ) { + Point spot; + SetPt(&spot, 0x0070, 0x0050); + DIBadMount(spot, event.message); + } +#endif + } + break; + case osEvt: { + switch ((event.message>>24) & 0xFF) { +#if 0 /* Handled above the switch statement */ + case mouseMovedMessage: { + myGlobalToLocal(this, &event.where); + SDL_PrivateMouseMotion(0, 0, + event.where.h, event.where.v); + } + break; +#endif /* 0 */ + case suspendResumeMessage: { + Mac_HandleActivate(!!(event.message & resumeFlag)); + } + break; + } + } + break; + default: { + ; + } + break; + } + return (event.what != nullEvent); +} + + +void Mac_PumpEvents(_THIS) +{ + /* Process pending MacOS events */ + while ( Mac_HandleEvents(this, 0) ) { + /* Loop and check again */; + } +} + +void Mac_InitOSKeymap(_THIS) +{ + const void *KCHRPtr; + UInt32 state; + UInt32 value; + int i; + int world = SDLK_WORLD_0; + + /* Map the MAC keysyms */ + for ( i=0; ikeysym map. However, it will not + * work very well on international keyboard. Hence we now query MacOS + * for its own keymap to adjust our own mapping table. However, this is + * bascially only useful for ascii char keys. This is also the reason + * why we keep the static table, too. + */ + + /* Get a pointer to the systems cached KCHR */ + KCHRPtr = (void *)GetScriptManagerVariable(smKCHRCache); + if (KCHRPtr) + { + /* Loop over all 127 possible scan codes */ + for (i = 0; i < 0x7F; i++) + { + /* We pretend a clean start to begin with (i.e. no dead keys active */ + state = 0; + + /* Now translate the key code to a key value */ + value = KeyTranslate(KCHRPtr, i, &state) & 0xff; + + /* If the state become 0, it was a dead key. We need to translate again, + passing in the new state, to get the actual key value */ + if (state != 0) + value = KeyTranslate(KCHRPtr, i, &state) & 0xff; + + /* Now we should have an ascii value, or 0. Try to figure out to which SDL symbol it maps */ + if (value >= 128) /* Some non-ASCII char, map it to SDLK_WORLD_* */ + MAC_keymap[i] = world++; + else if (value >= 32) /* non-control ASCII char */ + MAC_keymap[i] = value; + } + } + + /* The keypad codes are re-setup here, because the loop above cannot + * distinguish between a key on the keypad and a regular key. We maybe + * could get around this problem in another fashion: NSEvent's flags + * include a "NSNumericPadKeyMask" bit; we could check that and modify + * the symbol we return on the fly. However, this flag seems to exhibit + * some weird behaviour related to the num lock key + */ + MAC_keymap[MK_KP0] = SDLK_KP0; + MAC_keymap[MK_KP1] = SDLK_KP1; + MAC_keymap[MK_KP2] = SDLK_KP2; + MAC_keymap[MK_KP3] = SDLK_KP3; + MAC_keymap[MK_KP4] = SDLK_KP4; + MAC_keymap[MK_KP5] = SDLK_KP5; + MAC_keymap[MK_KP6] = SDLK_KP6; + MAC_keymap[MK_KP7] = SDLK_KP7; + MAC_keymap[MK_KP8] = SDLK_KP8; + MAC_keymap[MK_KP9] = SDLK_KP9; + MAC_keymap[MK_KP_MINUS] = SDLK_KP_MINUS; + MAC_keymap[MK_KP_PLUS] = SDLK_KP_PLUS; + MAC_keymap[MK_KP_PERIOD] = SDLK_KP_PERIOD; + MAC_keymap[MK_KP_EQUALS] = SDLK_KP_EQUALS; + MAC_keymap[MK_KP_DIVIDE] = SDLK_KP_DIVIDE; + MAC_keymap[MK_KP_MULTIPLY] = SDLK_KP_MULTIPLY; + MAC_keymap[MK_KP_ENTER] = SDLK_KP_ENTER; +} + +static SDL_keysym *TranslateKey(int scancode, int modifiers, + SDL_keysym *keysym, int pressed) +{ + /* Set the keysym information */ + keysym->scancode = scancode; + keysym->sym = MAC_keymap[keysym->scancode]; + keysym->mod = KMOD_NONE; + keysym->unicode = 0; + if ( pressed && SDL_TranslateUNICODE ) { + static unsigned long state = 0; + static Ptr keymap = nil; + Ptr new_keymap; + + /* Get the current keyboard map resource */ + new_keymap = (Ptr)GetScriptManagerVariable(smKCHRCache); + if ( new_keymap != keymap ) { + keymap = new_keymap; + state = 0; + } + keysym->unicode = KeyTranslate(keymap, + keysym->scancode|modifiers, &state) & 0xFFFF; + } + return(keysym); +} + +void Mac_InitEvents(_THIS) +{ + /* Create apple menu bar */ + apple_menu = GetMenu(mApple); + if ( apple_menu != nil ) { + AppendResMenu(apple_menu, 'DRVR'); + InsertMenu(apple_menu, 0); + } + DrawMenuBar(); + + /* Get rid of spurious events at startup */ + FlushEvents(everyEvent, 0); + + /* Allow every event but keyrepeat */ + SetEventMask(everyEvent & ~autoKeyMask); +} + +void Mac_QuitEvents(_THIS) +{ + ClearMenuBar(); + if ( apple_menu != nil ) { + ReleaseResource((char **)apple_menu); + } + + /* Clean up pending events */ + FlushEvents(everyEvent, 0); +} + +static void Mac_DoAppleMenu(_THIS, long choice) +{ +#if !TARGET_API_MAC_CARBON /* No Apple menu in OS X */ + short menu, item; + + item = (choice&0xFFFF); + choice >>= 16; + menu = (choice&0xFFFF); + + switch (menu) { + case mApple: { + switch (item) { + case iAbout: { + /* Run the about box */; + } + break; + default: { + Str255 name; + + GetMenuItemText(apple_menu, item, name); + OpenDeskAcc(name); + } + break; + } + } + break; + default: { + /* Ignore other menus */; + } + } +#endif /* !TARGET_API_MAC_CARBON */ +} + +#if !TARGET_API_MAC_CARBON +/* Since we don't initialize QuickDraw, we need to get a pointer to qd */ +struct QDGlobals *theQD = NULL; +#endif + +/* Exported to the macmain code */ +void SDL_InitQuickDraw(struct QDGlobals *the_qd) +{ +#if !TARGET_API_MAC_CARBON + theQD = the_qd; +#endif +} -- cgit v1.2.3