aboutsummaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
authorJohn Vilk <jvilk@cs.umass.edu>2013-11-06 22:08:33 -0500
committerJohn Vilk <jvilk@cs.umass.edu>2013-11-10 02:25:17 -0500
commit39b138d4ddda29b535285bc1c5223641dcacce28 (patch)
tree84684a42f652d043e03918034f7d3b972f45d84b /tests
parentd446e2b3c3b96474106b9bd47f35d901abb14f6d (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.c123
-rw-r--r--tests/test_browser.py76
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).