diff options
author | John Vilk <jvilk@cs.umass.edu> | 2013-11-06 22:08:33 -0500 |
---|---|---|
committer | John Vilk <jvilk@cs.umass.edu> | 2013-11-10 02:25:17 -0500 |
commit | 39b138d4ddda29b535285bc1c5223641dcacce28 (patch) | |
tree | 84684a42f652d043e03918034f7d3b972f45d84b /tests | |
parent | d446e2b3c3b96474106b9bd47f35d901abb14f6d (diff) |
[SDL] Joystick API implementation using HTML5 Gamepad API
Works in browsers that implement the working draft of the standard (current Chrome / Firefox stable):
http://www.w3.org/TR/2012/WD-gamepad-20120529/#gamepad-interface
...and browsers that implement the editor's draft (current Firefox Nightly):
https://dvcs.w3.org/hg/gamepad/raw-file/default/gamepad.html#idl-def-Gamepad
Contains unit tests for both event types.
Diffstat (limited to 'tests')
-rw-r--r-- | tests/sdl_joystick.c | 123 | ||||
-rw-r--r-- | tests/test_browser.py | 76 |
2 files changed, 199 insertions, 0 deletions
diff --git a/tests/sdl_joystick.c b/tests/sdl_joystick.c new file mode 100644 index 00000000..7035050f --- /dev/null +++ b/tests/sdl_joystick.c @@ -0,0 +1,123 @@ +#include <stdio.h> +#include <SDL/SDL.h> +#include <SDL/SDL_ttf.h> +#include <assert.h> +#include <string.h> +#include <emscripten.h> + +int result = 1; + +void assertJoystickEvent(int expectedGamepad, int expectedType, int expectedIndex, int expectedValue) { + SDL_Event event; + while(1) { + // Loop ends either when assertion fails (we run out of events), or we find + // the event we're looking for. + assert(SDL_PollEvent(&event) == 1); + if (event.type != expectedType) { + continue; + } + switch(event.type) { + case SDL_JOYAXISMOTION: { + assert(event.jaxis.which == expectedGamepad); + assert(event.jaxis.axis == expectedIndex); + assert(event.jaxis.value == expectedValue); + break; + } + case SDL_JOYBUTTONUP: case SDL_JOYBUTTONDOWN: { + assert(event.jbutton.which == expectedGamepad); + assert(event.jbutton.button == expectedIndex); + assert(event.jbutton.state == expectedValue); + break; + } + } + // Break out of while loop. + break; + } +} + +void assertNoJoystickEvent() { + SDL_Event event; + while(SDL_PollEvent(&event)) { + switch(event.type) { + case SDL_JOYBUTTONDOWN: case SDL_JOYBUTTONUP: case SDL_JOYAXISMOTION: { + // Fail. + assert(0); + } + } + } +} + +void main_2(void* arg); + +int main() { + SDL_Init(SDL_INIT_VIDEO | SDL_INIT_JOYSTICK); + SDL_Surface *screen = SDL_SetVideoMode(600, 450, 32, SDL_HWSURFACE); + emscripten_async_call(main_2, NULL, 3000); // avoid startup delays and intermittent errors + return 0; +} + +void main_2(void* arg) { + // TODO: At the moment, we only support joystick support through polling. + emscripten_run_script("window.addNewGamepad('Pad Thai', 4, 16)"); + emscripten_run_script("window.addNewGamepad('Pad Kee Mao', 0, 4)"); + // Check that the joysticks exist properly. + assert(SDL_NumJoysticks() == 2); + assert(!SDL_JoystickOpened(0)); + assert(!SDL_JoystickOpened(1)); + SDL_Joystick* pad1 = SDL_JoystickOpen(0); + assert(SDL_JoystickOpened(0)); + assert(SDL_JoystickIndex(pad1) == 0); + assert(strncmp(SDL_JoystickName(0), "Pad Thai", 9) == 0); + assert(strncmp(SDL_JoystickName(1), "Pad Kee Mao", 12) == 0); + assert(SDL_JoystickNumAxes(pad1) == 4); + assert(SDL_JoystickNumButtons(pad1) == 16); + + // Button events. + emscripten_run_script("window.simulateGamepadButtonDown(0, 1)"); + // We didn't tell SDL to automatically update this joystick's state. + assertNoJoystickEvent(); + SDL_JoystickUpdate(); + assertJoystickEvent(0, SDL_JOYBUTTONDOWN, 1, SDL_PRESSED); + assert(SDL_JoystickGetButton(pad1, 1) == 1); + // Enable automatic updates. + SDL_JoystickEventState(SDL_ENABLE); + assert(SDL_JoystickEventState(SDL_QUERY) == SDL_ENABLE); + emscripten_run_script("window.simulateGamepadButtonUp(0, 1)"); + assertJoystickEvent(0, SDL_JOYBUTTONUP, 1, SDL_RELEASED); + assert(SDL_JoystickGetButton(pad1, 1) == 0); + // No button change: Should not result in a new event. + emscripten_run_script("window.simulateGamepadButtonUp(0, 1)"); + assertNoJoystickEvent(); + // Joystick 1 is not opened; should not result in a new event. + emscripten_run_script("window.simulateGamepadButtonDown(1, 1)"); + assertNoJoystickEvent(); + + // Joystick wiggling + emscripten_run_script("window.simulateAxisMotion(0, 0, 1)"); + assertJoystickEvent(0, SDL_JOYAXISMOTION, 0, 32767); + assert(SDL_JoystickGetAxis(pad1, 0) == 32767); + emscripten_run_script("window.simulateAxisMotion(0, 0, 0)"); + assertJoystickEvent(0, SDL_JOYAXISMOTION, 0, 0); + assert(SDL_JoystickGetAxis(pad1, 0) == 0); + emscripten_run_script("window.simulateAxisMotion(0, 1, -1)"); + assertJoystickEvent(0, SDL_JOYAXISMOTION, 1, -32768); + assert(SDL_JoystickGetAxis(pad1, 1) == -32768); + emscripten_run_script("window.simulateAxisMotion(0, 1, -1)"); + // No joystick change: Should not result in a new event. + assertNoJoystickEvent(); + // Joystick 1 is not opened; should not result in a new event. + emscripten_run_script("window.simulateAxisMotion(1, 1, -1)"); + assertNoJoystickEvent(); + + SDL_JoystickClose(pad1); + assert(!SDL_JoystickOpened(0)); + + // Joystick 0 is closed; we should not process any new gamepad events from it. + emscripten_run_script("window.simulateGamepadButtonDown(0, 1)"); + assertNoJoystickEvent(); + + // End test. + result = 2; + printf("Test passed!\n"); +} + diff --git a/tests/test_browser.py b/tests/test_browser.py index d52f109f..1900e2cf 100644 --- a/tests/test_browser.py +++ b/tests/test_browser.py @@ -874,6 +874,82 @@ keydown(100);keyup(100); // trigger the end def test_glut_wheelevents(self): self.btest('glut_wheelevents.c', '1') + def test_sdl_joystick_1(self): + # Generates events corresponding to the Working Draft of the HTML5 Gamepad API. + # http://www.w3.org/TR/2012/WD-gamepad-20120529/#gamepad-interface + open(os.path.join(self.get_dir(), 'pre.js'), 'w').write(''' + var gamepads = []; + // Spoof this function. + navigator['getGamepads'] = function() { + return gamepads; + }; + window['addNewGamepad'] = function(id, numAxes, numButtons) { + var index = gamepads.length; + gamepads.push({ + axes: new Array(numAxes), + buttons: new Array(numButtons), + id: id, + index: index + }); + var i; + for (i = 0; i < numAxes; i++) gamepads[index].axes[i] = 0; + for (i = 0; i < numButtons; i++) gamepads[index].buttons[i] = 0; + }; + window['simulateGamepadButtonDown'] = function (index, button) { + gamepads[index].buttons[button] = 1; + }; + window['simulateGamepadButtonUp'] = function (index, button) { + gamepads[index].buttons[button] = 0; + }; + window['simulateAxisMotion'] = function (index, axis, value) { + gamepads[index].axes[axis] = value; + }; + ''') + open(os.path.join(self.get_dir(), 'sdl_joystick.c'), 'w').write(self.with_report_result(open(path_from_root('tests', 'sdl_joystick.c')).read())) + + Popen([PYTHON, EMCC, os.path.join(self.get_dir(), 'sdl_joystick.c'), '-O2', '--minify', '0', '-o', 'page.html', '--pre-js', 'pre.js']).communicate() + self.run_browser('page.html', '', '/report_result?2') + + def test_sdl_joystick_2(self): + # Generates events corresponding to the Editor's Draft of the HTML5 Gamepad API. + # https://dvcs.w3.org/hg/gamepad/raw-file/default/gamepad.html#idl-def-Gamepad + open(os.path.join(self.get_dir(), 'pre.js'), 'w').write(''' + var gamepads = []; + // Spoof this function. + navigator['getGamepads'] = function() { + return gamepads; + }; + window['addNewGamepad'] = function(id, numAxes, numButtons) { + var index = gamepads.length; + gamepads.push({ + axes: new Array(numAxes), + buttons: new Array(numButtons), + id: id, + index: index + }); + var i; + for (i = 0; i < numAxes; i++) gamepads[index].axes[i] = 0; + // Buttons are objects + for (i = 0; i < numButtons; i++) gamepads[index].buttons[i] = { pressed: false, value: 0 }; + }; + // FF mutates the original objects. + window['simulateGamepadButtonDown'] = function (index, button) { + gamepads[index].buttons[button].pressed = true; + gamepads[index].buttons[button].value = 1; + }; + window['simulateGamepadButtonUp'] = function (index, button) { + gamepads[index].buttons[button].pressed = false; + gamepads[index].buttons[button].value = 0; + }; + window['simulateAxisMotion'] = function (index, axis, value) { + gamepads[index].axes[axis] = value; + }; + ''') + open(os.path.join(self.get_dir(), 'sdl_joystick.c'), 'w').write(self.with_report_result(open(path_from_root('tests', 'sdl_joystick.c')).read())) + + Popen([PYTHON, EMCC, os.path.join(self.get_dir(), 'sdl_joystick.c'), '-O2', '--minify', '0', '-o', 'page.html', '--pre-js', 'pre.js']).communicate() + self.run_browser('page.html', '', '/report_result?2') + def test_webgl_context_attributes(self): # Javascript code to check the attributes support we want to test in the WebGL implementation # (request the attribute, create a context and check its value afterwards in the context attributes). |