diff --git a/configure.in b/configure.in index ab0e314..c7ae13b 100644 --- a/configure.in +++ b/configure.in @@ -957,7 +957,7 @@ AC_HELP_STRING([--enable-naclvideo], [enable the nacl video driver [[default=yes AC_DEFINE(SDL_VIDEO_DRIVER_NACL) SOURCES="$SOURCES $srcdir/src/video/nacl/*.c" EXTRA_LDFLAGS="-lppapi_simple -l${NACL_CXX_LIB:-stdc++} $EXTRA_LDFLAGS" - SDL_LIBS="-Wl,-unacl_main -Wl,-undefined=PSUserMainGet -lSDLmain $SDL_LIBS -lppapi_gles2 -lcli_main -lnacl_spawn -ltar -lppapi_simple -lnacl_io -lppapi -lm -l${NACL_CXX_LIB:-stdc++}" + SDL_LIBS="-lSDLmain $SDL_LIBS -lppapi_gles2 -lcli_main -lnacl_spawn -ltar -lppapi_simple_cpp -lnacl_io -lppapi -lm -l${NACL_CXX_LIB:-stdc++} -lppapi_cpp" SDL_CFLAGS="$SDL_CFLAGS -Dmain=SDL_main" fi @@ -2449,7 +2449,7 @@ case "$host" in have_timers=yes fi CheckPTHREAD - SDLMAIN_SOURCES="$srcdir/src/main/nacl/*.c" + SDLMAIN_SOURCES="$srcdir/src/main/nacl/*.cc" ;; *-*-linux*|*-*-uclinux*|*-*-gnu*|*-*-k*bsd*-gnu|*-*-bsdi*|*-*-freebsd*|*-*-dragonfly*|*-*-netbsd*|*-*-openbsd*|*-*-sysv5*|*-*-solaris*|*-*-hpux*|*-*-irix*|*-*-aix*|*-*-osf*) case "$host" in diff --git a/src/events/SDL_keyboard.c b/src/events/SDL_keyboard.c index 5753927..da37fe6 100644 --- a/src/events/SDL_keyboard.c +++ b/src/events/SDL_keyboard.c @@ -371,6 +371,13 @@ Uint8 * SDL_GetKeyState (int *numkeys) *numkeys = SDLK_LAST; return(SDL_KeyState); } + +// private (used in naclevents.c) +void SDL_SetKeyState (SDLKey key, Uint8 state) +{ + SDL_KeyState[key] = state; +} + SDLMod SDL_GetModState (void) { return(SDL_ModState); diff --git a/src/main/nacl/SDL_nacl_main.c b/src/main/nacl/SDL_nacl_main.c deleted file mode 100644 index ef26120..0000000 --- a/src/main/nacl/SDL_nacl_main.c +++ /dev/null @@ -1,125 +0,0 @@ -/* - Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - 3. This notice may not be removed or altered from any source distribution. -*/ -#include "SDL_config.h" - -#if SDL_VIDEO_DRIVER_NACL - -/* Include the SDL main definition header */ -#include "SDL_main.h" -#include "../../SDL_trace.h" - -#include -#include -#include -#include -#include -#include -#include -#include - -extern void NACL_SetScreenResolution(int width, int height); - -static int -ProcessArgs(int argc, char** argv) { - const char* arg = getenv("SDL_TAR_EXTRACT"); - if (arg != NULL) { - const char* source; - const char* target = "/"; - char* sep; - char buf[64]; - int n; - - const char* q, *p = arg; - while (*p) { - while (*p && isspace((unsigned char)*p)) ++p; - if (!*p) break; - q = p; - while (*p && !isspace((unsigned char)*p)) ++p; - - n = sizeof(buf) - 1; - if (p - q < n) n = p - q; - strncpy(buf, q, n); - buf[n] = '\0'; - - sep = strchr(buf, ':'); - source = buf; - if (sep) { - target = sep + 1; - *sep = '\0'; - } - - SDL_log("extracting tar file '%s' -> '%s'\n", source, target); - if (nacl_startup_untar(argv[0], source, target) != 0) - return 1; - } - } - - return 0; -} - -/* This is started in a worker thread by ppapi_simple! */ -int -nacl_main(int argc, char *argv[]) -{ - SDL_TRACE("nacl_main\n"); - PSEvent* ps_event; - PP_Resource event; - struct PP_Rect rect; - int ready = 0; - const PPB_View *ppb_view = PSInterfaceView(); - - if (ProcessArgs(argc, argv) != 0) { - return 1; - } - - /* Wait for the first PSE_INSTANCE_DIDCHANGEVIEW event before starting the app */ - PSEventSetFilter(PSE_INSTANCE_DIDCHANGEVIEW); - /* Process all waiting events without blocking */ - while (!ready) { - ps_event = PSEventWaitAcquire(); - event = ps_event->as_resource; - switch(ps_event->type) { - /* From DidChangeView, contains a view resource */ - case PSE_INSTANCE_DIDCHANGEVIEW: - ppb_view->GetRect(event, &rect); - NACL_SetScreenResolution(rect.size.width, rect.size.height); - ready = 1; - break; - default: - break; - } - PSEventRelease(ps_event); - } - - /* - * Startup in /mnt/http by default so resources hosted on the webserver - * are accessible in the current working directory. - */ - if (getenv("PWD") == NULL) { - if (chdir("/mnt/http") != 0) { - SDL_log("chdir to /mnt/http failed: %s\n", strerror(errno)); - } - } - - return SDL_main(argc, argv); -} - -#endif /* SDL_VIDEO_DRIVER_NACL */ diff --git a/src/main/nacl/SDL_nacl_main.cc b/src/main/nacl/SDL_nacl_main.cc new file mode 100644 index 0000000..ee80b9a --- /dev/null +++ b/src/main/nacl/SDL_nacl_main.cc @@ -0,0 +1,129 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2014 Sam Lantinga + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ +#include "SDL_config.h" + +#if SDL_VIDEO_DRIVER_NACL + +/* Include the SDL main definition header */ +#include "SDL_main.h" +#include "../../SDL_trace.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +extern "C" void NACL_SetScreenResolution(int width, int height); + +static int +ProcessArgs(int argc, char** argv) { + const char* arg = getenv("SDL_TAR_EXTRACT"); + if (arg != NULL) { + const char* source; + const char* target = "/"; + char* sep; + char buf[64]; + int n; + + const char* q, *p = arg; + while (*p) { + while (*p && isspace((unsigned char)*p)) ++p; + if (!*p) break; + q = p; + while (*p && !isspace((unsigned char)*p)) ++p; + + n = sizeof(buf) - 1; + if (p - q < n) n = p - q; + strncpy(buf, q, n); + buf[n] = '\0'; + + sep = strchr(buf, ':'); + source = buf; + if (sep) { + target = sep + 1; + *sep = '\0'; + } + + SDL_log("extracting tar file '%s' -> '%s'\n", source, target); + if (nacl_startup_untar(argv[0], source, target) != 0) + return 1; + } + } + + return 0; +} + +#undef main + +/* This is started in a worker thread by ppapi_simple! */ +int +main(int argc, char *argv[]) +{ + SDL_TRACE("main\n"); + PSEvent* ps_event; + PP_Resource event; + struct PP_Rect rect; + int ready = 0; + const PPB_View *ppb_view = PSInterfaceView(); + + if (ProcessArgs(argc, argv) != 0) { + return 1; + } + + /* Wait for the first PSE_INSTANCE_DIDCHANGEVIEW event before starting the app */ + PSEventSetFilter(PSE_INSTANCE_DIDCHANGEVIEW); + /* Process all waiting events without blocking */ + while (!ready) { + ps_event = PSEventWaitAcquire(); + event = ps_event->as_resource; + switch(ps_event->type) { + /* From DidChangeView, contains a view resource */ + case PSE_INSTANCE_DIDCHANGEVIEW: + ppb_view->GetRect(event, &rect); + NACL_SetScreenResolution(rect.size.width, rect.size.height); + ready = 1; + break; + default: + break; + } + PSEventRelease(ps_event); + } + + mount("", /* source */ + "/persistent", /* target */ + "html5fs", /* filesystemtype */ + 0, /* mountflags */ + "type=PERSISTENT,expected_size=1048576"); /* data */ + + mount("", /* source. Use relative URL */ + "/http", /* target */ + "httpfs", /* filesystemtype */ + 0, /* mountflags */ + ""); /* data */ + + return SDL_main(argc, argv); +} + +#endif /* SDL_VIDEO_DRIVER_NACL */ diff --git a/src/video/nacl/SDL_naclevents.c b/src/video/nacl/SDL_naclevents.c index a2f7e19..a97134f 100644 --- a/src/video/nacl/SDL_naclevents.c +++ b/src/video/nacl/SDL_naclevents.c @@ -29,6 +29,7 @@ #include #include +#include #define PPAPI_KEY_CTRL 17 #define PPAPI_KEY_ALT 18 @@ -176,12 +177,85 @@ static SDLKey translateKey(uint32_t code) { } } +static SDL_bool SDL_NeedModUpdate = SDL_TRUE; + +static int Utf8ToUtf16(const Uint8 *utf8, const int utf8_length, Uint16 *utf16, const int utf16_max_length) { + + /* p moves over the output buffer. max_ptr points to the next to the last slot of the buffer. */ + Uint16 *p = utf16; + Uint16 const *const max_ptr = utf16 + utf16_max_length; + + /* end_of_input points to the last byte of input as opposed to the next to the last byte. */ + Uint8 const *const end_of_input = utf8 + utf8_length - 1; + + while (utf8 <= end_of_input) { + Uint8 const c = *utf8; + if (p >= max_ptr) { + /* No more output space. */ + return -1; + } + if (c < 0x80) { + /* One byte ASCII. */ + *p++ = c; + utf8 += 1; + } else if (c < 0xC0) { + /* Follower byte without preceeding leader bytes. */ + return -1; + } else if (c < 0xE0) { + /* Two byte sequence. We need one follower byte. */ + if (end_of_input - utf8 < 1 || (((utf8[1] ^ 0x80)) & 0xC0)) { + return -1; + } + *p++ = (Uint16)(0xCF80 + (c << 6) + utf8[1]); + utf8 += 2; + } else if (c < 0xF0) { + /* Three byte sequence. We need two follower byte. */ + if (end_of_input - utf8 < 2 || (((utf8[1] ^ 0x80) | (utf8[2] ^ 0x80)) & 0xC0)) { + return -1; + } + *p++ = (Uint16)(0xDF80 + (c << 12) + (utf8[1] << 6) + utf8[2]); + utf8 += 3; + } else if (c < 0xF8) { + int plane; + /* Four byte sequence. We need three follower bytes. */ + if (end_of_input - utf8 < 3 || (((utf8[1] ^ 0x80) | (utf8[2] ^0x80) | (utf8[3] ^ 0x80)) & 0xC0)) { + return -1; + } + plane = (-0xC8 + (c << 2) + (utf8[1] >> 4)); + if (plane == 0) { + /* This four byte sequence is an alias that + corresponds to a Unicode scalar value in BMP. + It fits in an UTF-16 encoding unit. */ + *p++ = (Uint16)(0xDF80 + (utf8[1] << 12) + (utf8[2] << 6) + utf8[3]); + } else if (plane <= 16) { + /* This is a legal four byte sequence that corresponds to a surrogate pair. */ + if (p + 1 >= max_ptr) { + /* No enough space on the output buffer for the pair. */ + return -1; + } + *p++ = (Uint16)(0xE5B8 + (c << 8) + (utf8[1] << 2) + (utf8[2] >> 4)); + *p++ = (Uint16)(0xDB80 + ((utf8[2] & 0x0F) << 6) + utf8[3]); + } else { + /* This four byte sequence is out of UTF-16 code space. */ + return -1; + } + utf8 += 4; + } else { + /* Longer sequence or unused byte. */ + return -1; + } + } + return p - utf16; +} + + void HandleInputEvent(_THIS, PP_Resource event) { static Uint8 last_scancode = 0; static int alt_down = 0; static int ctrl_down = 0; PP_InputEvent_Type type; PP_InputEvent_Modifier modifiers; + SDLMod sdl_mod; Uint8 button; Uint8 state; Uint8 gained; @@ -197,9 +271,49 @@ void HandleInputEvent(_THIS, PP_Resource event) { int sdl_wheel_clicks_y; int i; + // defining modifiers array for conversion + static const size_t modcnt = 6; + static const int ppapi_mods[modcnt] = { + PP_INPUTEVENT_MODIFIER_SHIFTKEY, + PP_INPUTEVENT_MODIFIER_CONTROLKEY, + PP_INPUTEVENT_MODIFIER_ALTKEY, + PP_INPUTEVENT_MODIFIER_METAKEY, + PP_INPUTEVENT_MODIFIER_CAPSLOCKKEY, + PP_INPUTEVENT_MODIFIER_NUMLOCKKEY + }; + static const SDLMod sdl_mods[modcnt] = { + KMOD_LSHIFT, + KMOD_LCTRL, + KMOD_LALT, + KMOD_LMETA, + KMOD_CAPS, + KMOD_NUM + }; + static const SDLKey sdl_keys[modcnt] = { + SDLK_LSHIFT, + SDLK_LCTRL, + SDLK_LALT, + SDLK_LMETA, + SDLK_CAPSLOCK, + SDLK_NUMLOCK + }; + static const SDLKey sdl_rkeys[modcnt] = { + SDLK_RSHIFT, + SDLK_RCTRL, + SDLK_RALT, + SDLK_RMETA, + SDLK_CAPSLOCK, + SDLK_NUMLOCK + }; + type = dd->ppb_input_event->GetType(event); modifiers = dd->ppb_input_event->GetModifiers(event); + // alt_down and ctrl_down correction + // needed when one of these keys were pressed outside of the module + alt_down = modifiers & PP_INPUTEVENT_MODIFIER_ALTKEY ? 1 : 0; + ctrl_down = modifiers & PP_INPUTEVENT_MODIFIER_CONTROLKEY ? 1 : 0; + switch (type) { case PP_INPUTEVENT_TYPE_MOUSEDOWN: case PP_INPUTEVENT_TYPE_MOUSEUP: @@ -216,13 +330,13 @@ void HandleInputEvent(_THIS, PP_Resource event) { sdl_wheel_clicks_y = trunc(wheel_clicks_y); button = (sdl_wheel_clicks_x > 0) ? SDL_BUTTON_X1 : SDL_BUTTON_X2; for (i = 0; i < abs(sdl_wheel_clicks_x); i++) { - SDL_PrivateMouseButton(SDL_MOUSEBUTTONDOWN, button, 0, 0); - SDL_PrivateMouseButton(SDL_MOUSEBUTTONUP, button, 0, 0); + SDL_PrivateMouseButton(SDL_PRESSED, button, 0, 0); + SDL_PrivateMouseButton(SDL_RELEASED, button, 0, 0); } button = (sdl_wheel_clicks_y > 0) ? SDL_BUTTON_WHEELUP : SDL_BUTTON_WHEELDOWN; for (i = 0; i < abs(sdl_wheel_clicks_y); i++) { - SDL_PrivateMouseButton(SDL_MOUSEBUTTONDOWN, button, 0, 0); - SDL_PrivateMouseButton(SDL_MOUSEBUTTONUP, button, 0, 0); + SDL_PrivateMouseButton(SDL_PRESSED, button, 0, 0); + SDL_PrivateMouseButton(SDL_RELEASED, button, 0, 0); } wheel_clicks_x -= sdl_wheel_clicks_x; wheel_clicks_y -= sdl_wheel_clicks_y; @@ -259,7 +373,12 @@ void HandleInputEvent(_THIS, PP_Resource event) { // It seems that SDL 1.3 is better in this regard. keysym.scancode = dd->ppb_keyboard_input_event->GetKeyCode(event); unicode_var = dd->ppb_keyboard_input_event->GetCharacterText(event); - keysym.unicode = dd->ppb_var->VarToUtf8(unicode_var, &unicode_var_len)[0]; + const Uint8 *utf8_buf = dd->ppb_var->VarToUtf8(unicode_var, &unicode_var_len); + + Uint8 utf16_buf[10]; + Utf8ToUtf16(utf8_buf, unicode_var_len, (Uint16*)&utf16_buf[0], 1); + keysym.unicode = *(Uint16*)&utf16_buf[0]; + dd->ppb_var->Release(unicode_var); keysym.sym = translateKey(keysym.scancode); @@ -318,6 +437,34 @@ void HandleInputEvent(_THIS, PP_Resource event) { state = SDL_RELEASED; last_scancode = 0; } + + if (SDL_NeedModUpdate) { + // copying keyboard modifiers from PPAPI + sdl_mod = KMOD_NONE; + for (i = 0; i < modcnt; ++i) { + if (sdl_keys[i] == keysym.sym) // if key is a modifier + continue; // then do not copy it + if (modifiers & ppapi_mods[i]) { + sdl_mod |= sdl_mods[i]; + SDL_SetKeyState(sdl_keys[i], SDL_PRESSED); + } else { + SDL_SetKeyState(sdl_keys[i], SDL_RELEASED); + } + } + SDL_SetModState(sdl_mod); + SDL_NeedModUpdate = SDL_FALSE; + } + + if (modifiers & PP_INPUTEVENT_MODIFIER_ISRIGHT) { + // convert left modifier keycode to the right one + for (i = 0; i < modcnt; ++i) { + if (keysym.sym == sdl_keys[i]) { + keysym.sym = sdl_rkeys[i]; + break; + } + } + } + keysym.mod = KMOD_NONE; SDL_TRACE("Key event: %d: %s\n", state, SDL_GetKeyName(keysym.sym)); SDL_PrivateKeyboard(state, &keysym); @@ -352,6 +499,7 @@ static void HandleEvent(_THIS, PSEvent* ps_event) { /* From DidChangeFocus, contains a PP_Bool with the current focus state. */ case PSE_INSTANCE_DIDCHANGEFOCUS: + SDL_NeedModUpdate = SDL_TRUE; break; /* When the 3D context is lost, no resource. */