Welcome, Guest. Please login or register.
Did you miss your activation email?

Login with username, password and session length

 
Advanced search

880026 Posts in 33018 Topics- by 24385 Members - Latest Member: jhewitt

May 25, 2013, 03:04:45 PM
TIGSource ForumsDeveloperTechnical (Moderators: Glaiel-Gamer, ThemsAllTook)Simple cross-platform gamepad library
Pages: [1]
Print
Author Topic: Simple cross-platform gamepad library  (Read 3218 times)
ThemsAllTook
Moderator
Level 8
******


Alex Diener


View Profile WWW
« on: January 25, 2010, 05:38:23 AM »

Hello all,

I've been working on a library for Mac OS X, Windows, and Linux that provides a clean, easy-to-use API for reading input from USB game controllers, to be released as an open source project under the zlib/libpng license. I've built a simple test harness that shows all connected gamepads and the state of their controls. It looks like this:



If any of you have a gamepad, joystick, or other game controller and can spare a minute, could you please try out the test app and let me know how it handles your hardware? Here are builds for each platform:

http://sacredsoftware.net/temp/GamepadTestHarness_macosx.zip <- Mac
http://sacredsoftware.net/temp/GamepadTestHarness_windows.zip <- Windows
http://sacredsoftware.net/temp/GamepadTestHarness_linux.zip <- Linux

I have some minor dependency issues to work out before I can make the library itself available, but if you're interested, here's what the API looks like:

Code:
#ifndef __GAMEPAD_H__
#define __GAMEPAD_H__

#include <stdbool.h>
#include "utilities/EventDispatcher.h"

// eventData -> struct Gamepad_device
#define GAMEPAD_EVENT_DEVICE_ATTACHED "GAMEPAD_EVENT_DEVICE_ATTACHED" // Only dispatched when Gamepad_init or Gamepad_detectDevices is called
#define GAMEPAD_EVENT_DEVICE_REMOVED  "GAMEPAD_EVENT_DEVICE_REMOVED" // Can be dispatched at any time

// eventData -> struct Gamepad_buttonEvent
#define GAMEPAD_EVENT_BUTTON_DOWN     "GAMEPAD_EVENT_BUTTON_DOWN" // Only dispatched when Gamepad_processEvents is called
#define GAMEPAD_EVENT_BUTTON_UP       "GAMEPAD_EVENT_BUTTON_UP" // Only dispatched when Gamepad_processEvents is called

// eventData -> struct Gamepad_axisEvent
#define GAMEPAD_EVENT_AXIS_MOVED      "GAMEPAD_EVENT_AXIS_MOVED" // Only dispatched when Gamepad_processEvents is called

struct Gamepad_buttonEvent {
// Device that generated the event
struct Gamepad_device * device;

// Relative time of the event, in seconds. Does not necessarily correspond to values returned from Shell_getCurrentTime().
double timestamp;

// Button being pushed or released
unsigned int buttonID;

// True if button is down
bool down;
};

struct Gamepad_axisEvent {
// Device that generated the event
struct Gamepad_device * device;

// Relative time of the event, in seconds. Does not necessarily correspond to values returned from Shell_getCurrentTime().
double timestamp;

// Axis being moved
unsigned int axisID;

// Axis position value, in the range [-1..1]
float value;
};

struct Gamepad_device {
// Unique device identifier for application session. If a device is removed and subsequently reattached during the same application session, it will have a new deviceID.
unsigned int deviceID;

// Human-readable device name
const char * description;

// USB vendor/product IDs as returned by the driver. Can be used to determine the particular model of device represented.
int vendorID;
int productID;

// Number of axis elements belonging to the device
unsigned int numAxes;

// Number of button elements belonging to the device
unsigned int numButtons;

// Array[numAxes] of values representing the current state of each axis, in the range [-1..1]
float * axisStates;

// Array[numButtons] of values representing the current state of each button
bool * buttonStates;

// Broadcasts GAMEPAD_EVENT_BUTTON_DOWN, GAMEPAD_EVENT_BUTTON_UP, and GAMEPAD_EVENT_AXIS_MOVED
EventDispatcher * eventDispatcher;

// Platform-specific device data storage; don't mess with it
void * privateData;
};

/* Initializes gamepad library and detects initial devices. Call this before any other Gamepad_*()
   function, EXCEPT Gamepad_eventDispatcher(). In order to get receive GAMEPAD_EVENT_DEVICE_ATTACHED
   events from devices detected in Gamepad_init(), you must register handlers for those events before
   calling Gamepad_init(). */
void Gamepad_init();

/* Tears down all data structures created by the gamepad library and releases any memory that was
   allocated. It is not necessary to call this function at application termination. */
void Gamepad_shutdown();

/* EventDispatcher used by gamepad library to broadcast GAMEPAD_EVENT_DEVICE_ATTACHED and
   GAMEPAD_EVENT_DEVICE_REMOVED events. */
EventDispatcher * Gamepad_eventDispatcher();

/* Returns the number of currently attached gamepad devices. */
unsigned int Gamepad_numDevices();

/* Returns the specified Gamepad_device struct, or NULL if deviceIndex is out of bounds. */
struct Gamepad_device * Gamepad_deviceAtIndex(unsigned int deviceIndex);

/* Polls for any devices that have been attached since the last call to Gamepad_detectDevices() or
   Gamepad_init(). If any new devices are found, a GAMEPAD_EVENT_DEVICE_ATTACHED event will be
   broadcast via Gamepad_eventDispatcher() for each one. */
void Gamepad_detectDevices();

/* Reads pending input from all attached devices and broadcasts GAMEPAD_EVENT_BUTTON_DOWN,
   GAMEPAD_EVENT_BUTTON_UP, and GAMEPAD_EVENT_AXIS_MOVED events through the eventDispatcher of the
   device that generated the event. */
void Gamepad_processEvents();

#endif

EDIT: Libraries available: Source, Pre-built binaries
« Last Edit: January 31, 2010, 04:35:23 PM by ThemsAllTook » Logged
deadeye
First Manbaby Home
Level 10
*



View Profile
« Reply #1 on: January 25, 2010, 05:58:57 AM »

Tried the windows version with my Logitech Dual Action.  Works fine, all buttons and axis...es... light up normally.  Your buttons are numbered 0 - 11, and the ones on my controller are numbered 1 - 12, but I'm sure that's of no consequence.

Don't know what kind of hardware info you need, but here:
Windows XP SP2,  Athlon 64 Dual Core 4200+ 2.21GHz, 2G Ram
Logged

tweet tweet @j_younger
Draknek
Level 5
*****


"Alan Hazelden" for short

msn@draknek.org
View Profile WWW Email
« Reply #2 on: January 25, 2010, 06:42:24 AM »

Tried the Linux version with an Xbox 360 controller and it worked. The axis ordering is maybe a bit weird (left x, left y, left trigger, right x, right y, right trigger), but that has nothing to do with your library.
Logged

Ivan
Owl Country
Level 10
*


alright, let's see what we can see

Valaam0
View Profile
« Reply #3 on: January 25, 2010, 10:14:12 AM »

Wow, this looks great!! I'm gonna see if i can roll it up into my engine. I'll let you know how it works with my gamepads
Logged

http://polycode.org/ - Free, cross-platform, open-source engine.
Alex May
...is probably drunk right now.
Level 10
*


hen hao wan


View Profile WWW Email
« Reply #4 on: January 25, 2010, 10:27:50 AM »

Great idea.

One thing you could do is detect certain types of commonly-used controllers and have defines or enumerations for their buttons, so that apps could use those in a switch against the controller type.
Logged

ThemsAllTook
Moderator
Level 8
******


Alex Diener


View Profile WWW
« Reply #5 on: January 25, 2010, 10:43:28 AM »

Cool, glad to hear it's working so far!

Great idea.

One thing you could do is detect certain types of commonly-used controllers and have defines or enumerations for their buttons, so that apps could use those in a switch against the controller type.

Yep, I'm definitely thinking about ways to do this nicely... Once I get the low-level parts of this library working well enough (which looks like it might be already), I'd like to build a higher-level device-aware API on top of it. The hope is that the high-level API would be able to consistently tell you which button is which, tell you their names, know the physical layout for displaying configuration screens, etc. This sounds like it might require a large data collection effort to build up a reasonable database of device behaviors, so I'm still thinking about the logistics of that... If I can get it going, though, I feel like this database could be a great asset to the game development community.
Logged
iamwhosiam
Level 0
***


View Profile WWW Email
« Reply #6 on: January 25, 2010, 05:05:03 PM »

don't know if your still wondering but the 360 controller works on windows!

perfectly!

I was just wondering how I would do this a couple days ago. Can't wait for this one!
Logged
mcc
Level 10
*****


glitch


View Profile WWW Email
« Reply #7 on: January 25, 2010, 09:36:51 PM »

What would be the difference between this and SDL joystick input?
Logged

My projects:<br />Games: Jumpman Retro-futuristic platforming iJumpman iPhone version Drumcircle PC+smartphone music toy<br />More: RUN HELLO
ThemsAllTook
Moderator
Level 8
******


Alex Diener


View Profile WWW
« Reply #8 on: January 26, 2010, 07:01:34 AM »

What would be the difference between this and SDL joystick input?

The two main reasons I wrote this instead of using SDL_joystick:
  • SDL is licensed under GPL, which I find too restrictive. I prefer permissive licenses like zlib/libpng.
  • SDL_joystick doesn't look like it can be used standalone. You have to pull in all of SDL to use it.

If you're already using SDL or if the above two things don't bug you, it'll probably work just as well. I actually used SDL joystick code as a reference/sanity check for a lot of what I did here, so it ends up being reasonably similar.
Logged
ThemsAllTook
Moderator
Level 8
******


Alex Diener


View Profile WWW
« Reply #9 on: January 28, 2010, 06:54:33 PM »

I think I've finally managed to get this into a releasable state.

Source
Pre-built binaries

Have fun! Please let me know if I've overlooked anything, or if you find bugs, have suggestions for improvements, etc.
Logged
d3sphil
Level 0
**


View Profile Email
« Reply #10 on: February 06, 2010, 09:22:35 PM »

this looks sweet =).
I typically use SDL, but the SDL_joystick doesn't support any type of attach/detach stuff.
From running your example and looking at the code it seems this library can do that stuff,
so I will most likely use this over anything else. Detecting when a gamepad is connected or disconnected
is like super important in my opinion =).

Thanks!
Logged
Mikademus
Level 10
*****


The Magical Owl


View Profile
« Reply #11 on: February 07, 2010, 05:58:29 AM »

The two main reasons I wrote this instead of using SDL_joystick:
  • SDL is licensed under GPL, which I find too restrictive. I prefer permissive licenses like zlib/libpng.
  • SDL_joystick doesn't look like it can be used standalone. You have to pull in all of SDL to use it.

I agree with your second point, the less external dependencies I have to include the happier I am! But SDL is not GPL, it is LGPL.

Still, I really love your effort and I will absolutely try your library!  Kiss
Logged

\\\"There\\\'s a tendency among the press to attribute the creation of a game to a single person,\\\" says Warren Spector, creator of Thief and Deus Ex. --IGN<br />My compilation of game engines for indies
ThemsAllTook
Moderator
Level 8
******


Alex Diener


View Profile WWW
« Reply #12 on: February 08, 2010, 10:06:01 AM »

Cool, thanks guys. I've done a test integration of this library into one of my own games to experience any integration pains myself. Here's the stuff I'm working on fixing:

  • The 1.1.0 release posted above was accidentally built with some debug code left in. The effect this will has is that hat switches on some joysticks will give erroneous inputs on Mac OS X.
  • I'm tracking down a crash that occurs when I remove a device and plug it back in while running the game, which for some reason works correctly in the test harness. No idea yet what's different about the two cases.
  • Axis inputs are a huge pain to manage. The game I'm integrating this with is wired to read keyboard inputs for each of the four directions. In order to determine the equivalent of "key down" and "key up" for each direction, I have to keep the last value of each mapped axis around and compare it with new values that are coming in, and do some fudging and thresholding to make sure it feels stable. I'd like to add an abstracted API that will ease this somewhat (while still allowing you to read raw axis inputs if desired, of course).
  • Mapping buttons/axes to game controls and saving those settings between game sessions is a big can of worms, to say the least... There's a lot of complex logic I still need to work out conceptually. Thinking about having multiple gamepads of the same type attached (indistinguishable to my library other than the order in which they were attached), remembering mappings for each gamepad type, what to do when more than one gamepad that has mappings is plugged in... It's a bit of a nightmare, really. Hopefully I'll be able to come up with a nice solution that the API can support. A lot of this will be on the individual application, but I want to consolidate the logic in the library as much as makes sense.

All of the above is still ignoring the additional layer I was talking about that would be aware of physical device layouts and characteristics. Lots to still do here!
Logged
Matt Thorson
Level 7
**


c'est la vie


View Profile WWW Email
« Reply #13 on: February 09, 2010, 08:33:52 PM »

I'm on Windows 7 with an XB360 controller and it works perfectly Smiley
Logged

Pages: [1]
Print
Jump to:  

Theme orange-lt created by panic