Skip to content

Commit

Permalink
* Add joystick support for Windows.
Browse files Browse the repository at this point in the history
This patch is contributed by Sergej Forat
(with some very very minor modifications by Stephen Cameron.)
  • Loading branch information
smcameron committed Oct 24, 2012
1 parent 8bd37c3 commit 8962916
Show file tree
Hide file tree
Showing 4 changed files with 208 additions and 15 deletions.
193 changes: 189 additions & 4 deletions joystick.c
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,193 @@
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>
Expand All @@ -26,16 +213,13 @@
#include <stdlib.h>
#include <string.h>

#include "compat.h"
#include "joystick.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)
int open_joystick(char *joystick_device, __attribute__((unused)) void *window)
{
if (joystick_device == NULL)
joystick_device = JOYSTICK_DEVNAME;
Expand Down Expand Up @@ -111,6 +295,7 @@ void set_joystick_x_axis(int axis)
joystick_x_axis = axis;
}

#endif /* __WIN32__ */

#if 0
/* a little test program */
Expand Down
14 changes: 11 additions & 3 deletions joystick.h
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/*
/*
(C) Copyright 2007,2008, Stephen M. Cameron.
This file is part of wordwarvi.
Expand All @@ -18,10 +18,14 @@
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <stdio.h>
#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 */
Expand All @@ -42,7 +46,11 @@ struct wwvi_js_event {
int stick_y;
};

extern int open_joystick(char *joystick_device);
#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);
Expand Down
12 changes: 6 additions & 6 deletions wordwarvi.c
Original file line number Diff line number Diff line change
Expand Up @@ -13960,12 +13960,6 @@ int main(int argc, char *argv[])
set_joystick_x_axis(game_state.x_joystick_axis);
set_joystick_y_axis(game_state.y_joystick_axis);

jsfd = open_joystick(joystick_device);
if (jsfd < 0) {
printf("No joystick...\n");
} else
check_for_screensaver();

#ifdef WITHAUDIOSUPPORT
if (nomusic)
wwviaudio_set_nomusic();
Expand Down Expand Up @@ -14104,6 +14098,12 @@ int main(int argc, char *argv[])

inhibit_screensaver(window);

jsfd = open_joystick(joystick_device, window->window);
if (jsfd < 0) {
printf("No joystick...\n");
} else
check_for_screensaver();

gc = gdk_gc_new(GTK_WIDGET(main_da)->window);
gdk_gc_set_foreground(gc, &huex[BLUE]);
gdk_gc_set_foreground(gc, &huex[WHITE]);
Expand Down
4 changes: 2 additions & 2 deletions wordwarvi.cbp
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
<Build>
<Target title="Debug">
<Option output="wordwarvi_d" prefix_auto="1" extension_auto="1" />
<Option working_dir="" />
<Option object_output="obj/Debug/" />
<Option type="1" />
<Option compiler="gcc" />
Expand All @@ -18,7 +17,6 @@
</Target>
<Target title="Release">
<Option output="wordwarvi" prefix_auto="1" extension_auto="1" />
<Option working_dir="" />
<Option object_output="obj/Release/" />
<Option type="1" />
<Option compiler="gcc" />
Expand Down Expand Up @@ -53,6 +51,8 @@
<Add library="portaudio_x86" />
<Add library="libvorbisfile-3" />
<Add library="ws2_32" />
<Add library="dinput8" />
<Add library="dxguid" />
<Add directory="win32/bin" />
</Linker>
<ExtraCommands>
Expand Down

0 comments on commit 8962916

Please sign in to comment.