Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

add joystick support

  • Loading branch information...
commit eb8058a1163c2bb037adfff51f94830d70d8aba8 1 parent fc39196
@smcameron authored
Showing with 465 additions and 2 deletions.
  1. +5 −2 Makefile
  2. +37 −0 compat.h
  3. +324 −0 joystick.c
  4. +60 −0 joystick.h
  5. +39 −0 laser-lander.c
View
7 Makefile
@@ -1,14 +1,17 @@
all: laser-lander
+joystick.o: joystick.c joystick.h compat.h
+ $(CC) -g -c joystick.c
+
snis_font.o: my_point.h snis_font.c snis_font.h
$(CC) -g -c snis_font.c
snis_typeface.o: snis_typeface.h snis_typeface.c snis_font.h
$(CC) -g -c snis_typeface.c
-laser-lander: laser-lander.c snis_font.o snis_typeface.o
- $(CC) -g -L. -o laser-lander laser-lander.c -lopenlase snis_font.o snis_typeface.o
+laser-lander: laser-lander.c snis_font.o snis_typeface.o joystick.o
+ $(CC) -g -L. -o laser-lander laser-lander.c -lopenlase snis_font.o snis_typeface.o joystick.o
clean:
rm -fr laser-lander *.o
View
37 compat.h
@@ -0,0 +1,37 @@
+#ifndef COMPAT_H
+#define COMPAT_H
+
+#ifdef __WIN32__
+
+/* Windows variants of various things */
+
+#define JOYSTICK_DEV_OPEN_FLAGS O_RDONLY
+#define srandom srand
+#define random rand
+
+/* End of Windows variants of various things */
+
+#else
+#ifdef __linux__
+
+/* Linux variants of various things */
+
+#define JOYSTICK_DEV_OPEN_FLAGS O_RDONLY | O_NONBLOCK
+#define HAS_LINUX_JOYSTICK_INTERFACE 1
+#define O_BINARY 0
+
+/* End of Linux variants of various things */
+
+#else
+
+/* Generic variants of various things */
+
+#define JOYSTICK_DEV_OPEN_FLAGS O_RDONLY | O_NONBLOCK
+#define O_BINARY 0
+
+/* End of generic variants of various things */
+
+#endif /* __linux__ */
+#endif /* __WIN32__ */
+#endif /* COMPAT_H */
+
View
324 joystick.c
@@ -0,0 +1,324 @@
+/*
+ (C) Copyright 2007,2008, Stephen M. Cameron.
+
+ This file is part of wordwarvi.
+
+ wordwarvi is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ wordwarvi 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with wordwarvi; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+ */
+
+#include "compat.h"
+#include "joystick.h"
+
+#ifdef __WIN32__
+
+#define DIRECTINPUT_VERSION 0x0800
+#include <dinput.h>
+
+/* window handle */
+#include <gdk/gdkwin32.h>
+
+/* joystick axes limits */
+#define MIN_AXIS -32767
+#define MAX_AXIS 32767
+
+/* direct input interface */
+LPDIRECTINPUT8 dinput = NULL;
+
+/* joystick interface */
+LPDIRECTINPUTDEVICE8 joystick = NULL;
+
+/* device enumeration context */
+struct DEVINFO
+{
+ GUID productGuid;
+ GUID deviceID;
+ const CHAR *vendor;
+};
+
+/* device enumeration callback */
+BOOL CALLBACK EnumDevCallback(const DIDEVICEINSTANCE *dev, VOID *ctx)
+{
+ /* take the first joystick we get */
+ if (GET_DIDEVICE_TYPE(dev->dwDevType) == DI8DEVTYPE_JOYSTICK ||
+ GET_DIDEVICE_TYPE(dev->dwDevType) == DI8DEVTYPE_GAMEPAD)
+ {
+ struct DEVINFO *info = (struct DEVINFO *)ctx;
+ info->productGuid = dev->guidProduct;
+ info->deviceID = dev->guidInstance;
+ info->vendor = dev->tszInstanceName;
+ return DIENUM_STOP;
+ }
+ return DIENUM_CONTINUE;
+}
+
+/* device objects enumeration callback */
+BOOL CALLBACK EnumObjectsCallback(const DIDEVICEOBJECTINSTANCE *devobj, VOID *ctx)
+{
+ /* set DIPROP_RANGE for the axis in order to scale min/max values */
+ if (devobj->dwType & DIDFT_AXIS)
+ {
+ HRESULT hr;
+ DIPROPRANGE dipr;
+
+ dipr.diph.dwSize = sizeof(DIPROPRANGE);
+ dipr.diph.dwHeaderSize = sizeof(DIPROPHEADER);
+ dipr.diph.dwHow = DIPH_BYID;
+ dipr.diph.dwObj = devobj->dwType;
+ dipr.lMin = MIN_AXIS;
+ dipr.lMax = MAX_AXIS;
+
+ hr = IDirectInputDevice_SetProperty(joystick, DIPROP_RANGE, &dipr.diph);
+ if (FAILED(hr))
+ return DIENUM_STOP;
+ }
+ return DIENUM_CONTINUE;
+}
+
+int open_joystick(char *joystick_device, GdkWindow *window)
+{
+ HINSTANCE hi = 0;
+ HRESULT hr = 0;
+ HWND hwin = 0;
+ struct DEVINFO devinfo = {0};
+
+ /* create interface */
+ hi = GetModuleHandle(NULL);
+ hr = DirectInput8Create(hi, DIRECTINPUT_VERSION, &IID_IDirectInput8, (VOID**)&dinput, NULL);
+ if (FAILED(hr))
+ return -1;
+
+ /* look for a joystick */
+ hr = IDirectInput8_EnumDevices(dinput, DI8DEVCLASS_GAMECTRL, EnumDevCallback, &devinfo, DIEDFL_ATTACHEDONLY);
+ if(FAILED(hr))
+ return -1;
+
+ /* obtain joystick interface */
+ hr = IDirectInput8_CreateDevice(dinput, &devinfo.deviceID, &joystick, NULL);
+ if(FAILED(hr))
+ return -1;
+
+ /* set data format to "simple joystick" */
+ hr = IDirectInputDevice2_SetDataFormat(joystick, &c_dfDIJoystick2);
+ if(FAILED(hr))
+ return -1;
+
+ /* set the cooperative level */
+#ifdef __WIN32__
+ hwin = GDK_WINDOW_HWND(window);
+#endif
+ hr = IDirectInputDevice2_SetCooperativeLevel(joystick, hwin, DISCL_EXCLUSIVE | DISCL_FOREGROUND);
+ if(FAILED(hr))
+ return -1;
+
+ /* enumerate axes, buttons, povs */
+ hr = IDirectInputDevice2_EnumObjects(joystick, EnumObjectsCallback, NULL, DIDFT_ALL);
+ if(FAILED(hr))
+ return -1;
+
+ return 0;
+}
+
+int read_joystick_event(struct js_event *jse)
+{
+ /* not implemented */
+ return 0;
+}
+
+void set_joystick_y_axis(int axis)
+{
+ /* fixme: add axis selection */
+}
+
+void set_joystick_x_axis(int axis)
+{
+ /* fixme: add axis selection */
+}
+
+void close_joystick()
+{
+ if(joystick) {
+ IDirectInputDevice2_Unacquire(joystick);
+ joystick = NULL;
+ }
+
+ if (dinput) {
+ IDirectInput8_Release(dinput);
+ dinput = NULL;
+ }
+}
+
+int get_joystick_status(struct wwvi_js_event *wjse)
+{
+ HRESULT hr;
+ DIJOYSTATE2 js;
+ int i;
+
+ if (!joystick || !wjse)
+ return -1;
+
+ /* poll the device to read the current state */
+ hr = IDirectInputDevice2_Poll(joystick);
+ if (FAILED(hr)) {
+ /* input stream has been interrupted, re-acquire and try again */
+ hr = IDirectInputDevice2_Acquire(joystick);
+ while(hr == DIERR_INPUTLOST)
+ hr = IDirectInputDevice2_Acquire(joystick);
+
+ /* other errors may occur when the app is minimized
+ or in the process of switching, so just try again later */
+ if (FAILED(hr))
+ return -1;
+
+ /* try to poll again */
+ hr = IDirectInputDevice2_Poll(joystick);
+ if (FAILED(hr))
+ return -1;
+ }
+
+ /* get the device state */
+ hr = IDirectInputDevice2_GetDeviceState(joystick, sizeof(DIJOYSTATE2), &js);
+ if(FAILED(hr))
+ return -1;
+
+ /* write out state */
+ wjse->stick_x = js.lX;
+ wjse->stick_y = js.lY;
+ for (i = 0; i < 11; ++i) {
+ wjse->button[i] = (js.rgbButtons[i] & 0x80) ? 1 : 0;
+ }
+
+ return 0;
+}
+
+#else
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+
+static int joystick_fd = -1;
+
+/* These are sensible on Logitech Dual Action Rumble and xbox360 controller. */
+static int joystick_x_axis = 0;
+static int joystick_y_axis = 1;
+
+int open_joystick(char *joystick_device, __attribute__((unused)) void *window)
+{
+ if (joystick_device == NULL)
+ joystick_device = JOYSTICK_DEVNAME;
+ joystick_fd = open(joystick_device, JOYSTICK_DEV_OPEN_FLAGS);
+ if (joystick_fd < 0)
+ return joystick_fd;
+
+ /* maybe ioctls to interrogate features here? */
+
+ return joystick_fd;
+}
+
+int read_joystick_event(struct js_event *jse)
+{
+ int bytes;
+
+ bytes = read(joystick_fd, jse, sizeof(*jse));
+
+ if (bytes == -1)
+ return 0;
+
+ if (bytes == sizeof(*jse))
+ return 1;
+
+ printf("Unexpected bytes from joystick:%d\n", bytes);
+
+ return -1;
+}
+
+void close_joystick()
+{
+ close(joystick_fd);
+}
+
+int get_joystick_status(struct wwvi_js_event *wjse)
+{
+ int rc;
+ struct js_event jse;
+ if (joystick_fd < 0)
+ return -1;
+
+ /* memset(wjse, 0, sizeof(*wjse)); */
+ while ((rc = read_joystick_event(&jse) == 1)) {
+ jse.type &= ~JS_EVENT_INIT; /* ignore synthetic events */
+ if (jse.type == JS_EVENT_AXIS) {
+ if (jse.number == joystick_x_axis)
+ wjse->stick_x = jse.value;
+ if (jse.number == joystick_y_axis)
+ wjse->stick_y = jse.value;
+ } else if (jse.type == JS_EVENT_BUTTON) {
+ if (jse.number < 11) {
+ switch (jse.value) {
+ case 0:
+ case 1: wjse->button[jse.number] = jse.value;
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ }
+ /* printf("%d\n", wjse->stick1_y); */
+ return 0;
+}
+
+void set_joystick_y_axis(int axis)
+{
+ joystick_y_axis = axis;
+}
+
+void set_joystick_x_axis(int axis)
+{
+ joystick_x_axis = axis;
+}
+
+#endif /* __WIN32__ */
+
+#if 0
+/* a little test program */
+int main(int argc, char *argv[])
+{
+ int fd, rc;
+ int done = 0;
+
+ struct js_event jse;
+
+ fd = open_joystick();
+ if (fd < 0) {
+ printf("open failed.\n");
+ exit(1);
+ }
+
+ while (!done) {
+ rc = read_joystick_event(&jse);
+ usleep(1000);
+ if (rc == 1) {
+ printf("Event: time %8u, value %8hd, type: %3u, axis/button: %u\n",
+ jse.time, jse.value, jse.type, jse.number);
+ }
+ }
+}
+#endif
View
60 joystick.h
@@ -0,0 +1,60 @@
+/*
+ (C) Copyright 2007,2008, Stephen M. Cameron.
+
+ This file is part of wordwarvi.
+
+ wordwarvi is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ wordwarvi 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with wordwarvi; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+ */
+#ifndef __JOYSTICK_H__
+#define __JOYSTICK_H__
+
+#include <stdio.h>
+#ifdef __WIN32__
+#include <gdk/gdktypes.h>
+#endif
+
+#define JOYSTICK_DEVNAME "/dev/input/js0"
+
+#define JS_EVENT_BUTTON 0x01 /* button pressed/released */
+#define JS_EVENT_AXIS 0x02 /* joystick moved */
+#define JS_EVENT_INIT 0x80 /* initial state of device */
+
+
+struct js_event {
+ unsigned int time; /* event timestamp in milliseconds */
+ short value; /* value */
+ unsigned char type; /* event type */
+ unsigned char number; /* axis/button number */
+};
+
+struct wwvi_js_event {
+ int button[11];
+ int stick_x;
+ int stick_y;
+};
+
+#ifdef __WIN32__
+extern int open_joystick(char *joystick_device, GdkWindow *window);
+#else
+extern int open_joystick(char *joystick_device, void *window);
+#endif
+extern int read_joystick_event(struct js_event *jse);
+extern void set_joystick_y_axis(int axis);
+extern void set_joystick_x_axis(int axis);
+extern void close_joystick();
+extern int get_joystick_status(struct wwvi_js_event *wjse);
+
+#endif
View
39 laser-lander.c
@@ -5,6 +5,7 @@
#include "snis_font.h"
#include "snis_typeface.h"
+#include "joystick.h"
#include "libol.h"
#define XDIM (1000.0)
@@ -12,6 +13,9 @@
#define XSCALE (1.0 / (XDIM / 2.0))
#define YSCALE (-1.0 / (YDIM / 2.0))
+#define JOYSTICK_DEVICE "/dev/input/js0"
+static int joystick_fd = -1;
+
struct object;
typedef void (*move_function)(struct object *o, float time);
@@ -162,22 +166,57 @@ static void attract_mode(void)
draw_title_screen();
}
+static void deal_with_joystick(void)
+{
+ static struct wwvi_js_event jse;
+ int *xaxis, *yaxis, rc, i;
+
+ if (joystick_fd < 0)
+ return;
+
+ xaxis = &jse.stick_x;
+ yaxis = &jse.stick_y;
+
+ memset(&jse.button[0], 0, sizeof(jse.button[0]*10));
+ rc = get_joystick_status(&jse);
+ if (rc != 0)
+ return;
+
+#define JOYSTICK_SENSITIVITY 5000
+#define XJOYSTICK_THRESHOLD 20000
+
+ /* check joystick buttons */
+
+ for (i = 0; i < 11; i++) {
+ if (jse.button[i] == 1) {
+ attract_mode_active = 0;
+ }
+ }
+}
+
int main(int argc, char *argv[])
{
float elapsed_time = 0.0;
+ joystick_fd = open_joystick(JOYSTICK_DEVICE, NULL);
+ if (joystick_fd < 0)
+ printf("No joystick...");
+
snis_typefaces_init();
if (setup_openlase())
return -1;
while(1) {
+ deal_with_joystick();
draw_objs();
attract_mode();
openlase_renderframe(&elapsed_time);
move_objs(elapsed_time);
}
olShutdown();
+ if (joystick_fd >= 0)
+ close_joystick();
return 0;
}
Please sign in to comment.
Something went wrong with that request. Please try again.