Win32 joystick support

This commit is contained in:
Ilari Liusvaara 2012-04-07 00:24:07 +03:00
parent d6d749581f
commit 518ac9e0ad
4 changed files with 243 additions and 1 deletions

View file

@ -1,4 +1,4 @@
PLATFORMS=dummy evdev portaudio sdl wxwidgets
PLATFORMS=dummy evdev portaudio sdl wxwidgets win32mm
ALLOBJECT=__all__.$(OBJECT_SUFFIX)
ALLFLAGS=__all__.ldflags
PLATFORMS_OBJS=$(patsubst %,%/$(ALLOBJECT),$(PLATFORMS))
@ -14,6 +14,9 @@ dummy/$(ALLOBJECT): forcelook
evdev/$(ALLOBJECT): forcelook
$(MAKE) -C evdev
win32mm/$(ALLOBJECT): forcelook
$(MAKE) -C win32mm
portaudio/$(ALLOBJECT): forcelook
$(MAKE) -C portaudio
@ -29,6 +32,7 @@ wxwidgets/$(ALLOBJECT): forcelook
precheck:
$(MAKE) -C dummy precheck
$(MAKE) -C evdev precheck
$(MAKE) -C win32mm precheck
$(MAKE) -C portaudio precheck
$(MAKE) -C sdl precheck
$(MAKE) -C wxwidgets precheck
@ -37,6 +41,7 @@ clean:
rm -f *.$(OBJECT_SUFFIX) *.ldflags
$(MAKE) -C dummy clean
$(MAKE) -C evdev clean
$(MAKE) -C win32mm clean
$(MAKE) -C portaudio clean
$(MAKE) -C sdl clean
$(MAKE) -C wxwidgets clean

View file

@ -0,0 +1,20 @@
ifeq ($(JOYSTICK), WIN32MM)
OBJECTS=$(patsubst %.cpp,%.$(OBJECT_SUFFIX),$(wildcard *.cpp))
else
OBJECTS=dummy.$(OBJECT_SUFFIX)
endif
.PRECIOUS: %.$(OBJECT_SUFFIX)
__all__.$(OBJECT_SUFFIX): $(OBJECTS)
$(REALLD) -r -o $@ $^
touch __all__.ldflags
%.$(OBJECT_SUFFIX): %.cpp
$(REALCC) -c -o $@ $< -I../../../include $(CFLAGS)
precheck:
@true
clean:
rm -f *.$(OBJECT_SUFFIX) *.ldflags

View file

@ -0,0 +1 @@
char SYMBOL_5825392786327896327896798437692738969832786;

View file

@ -0,0 +1,216 @@
#include "core/command.hpp"
#include "core/framerate.hpp"
#include "core/keymapper.hpp"
#include "core/window.hpp"
#include "library/minmax.hpp"
#include "library/string.hpp"
#include <windows.h>
#include <mmsystem.h>
#include <regstr.h>
#include <cstdlib>
#include <string>
#include <sstream>
#include <iostream>
#include <stdexcept>
#include <sys/time.h>
#include <unistd.h>
namespace
{
std::set<keygroup*> keygroups;
std::map<std::pair<unsigned, unsigned>, keygroup*> buttons;
std::map<std::pair<unsigned, unsigned>, keygroup*> axes;
std::map<unsigned, keygroup*> hats;
std::map<std::pair<unsigned, unsigned>, short> lbuttons;
std::map<std::pair<unsigned, unsigned>, short> laxes;
std::map<unsigned, short> lhats;
std::set<unsigned> joysticks;
std::map<unsigned, JOYCAPS> capabilities;
volatile bool quit_signaled;
volatile bool quit_ack;
void create_hat(unsigned i)
{
std::string n = (stringfmt() << "joystick" << i << "hat").str();
keygroup* k = new keygroup(n, keygroup::KT_HAT);
hats[i] = k;
}
void create_button(unsigned i, unsigned j)
{
std::string n = (stringfmt() << "joystick" << i << "button" << j).str();
keygroup* k = new keygroup(n, keygroup::KT_KEY);
buttons[std::make_pair(i, j)] = k;
}
void create_axis(unsigned i, unsigned j, unsigned min, unsigned max)
{
std::string n = (stringfmt() << "joystick" << i << "axis" << j).str();
keygroup* k;
k = new keygroup(n, keygroup::KT_AXIS_PAIR);
axes[std::make_pair(i, j)] = k;
}
void read_axis(unsigned i, unsigned j, unsigned pos, unsigned pmin, unsigned pmax)
{
auto key = std::make_pair(i, j);
if(!axes.count(key))
return;
short cpos;
double _pos = pos;
double _pmin = pmin;
double _pmax = pmax;
_pos = 65535 * (_pos - _pmin) / (_pmax - _pmin) - 32768;
if(_pos < -32768)
cpos = -32768;
else if(_pos > 32767)
cpos = 32767;
else
cpos = _pos;
if(laxes[key] != cpos) {
platform::queue(keypress(modifier_set(), *axes[key], cpos));
laxes[key] = cpos;
}
}
void init_joysticks()
{
unsigned max_joysticks = joyGetNumDevs();
if(!max_joysticks)
return; //No joystick support.
for(unsigned i = 0; i < max_joysticks; i++) {
JOYINFOEX info;
JOYCAPS caps;
info.dwSize = sizeof(info);
info.dwFlags = JOY_RETURNALL;
if(joyGetPosEx(i, &info) != JOYERR_NOERROR)
continue; //Not usable.
if(joyGetDevCaps(i, &caps, sizeof(caps)) != JOYERR_NOERROR)
continue; //Not usable.
joysticks.insert(i);
capabilities[i] = caps;
messages << "Joystick #" << i << ": " << caps.szPname << " (by '" << caps.szOEMVxD << "')"
<< std::endl;
if(caps.wCaps & JOYCAPS_HASPOV)
create_hat(i);
for(unsigned j = 0; j < caps.wNumButtons && j < 32; j++)
create_button(i, j);
unsigned axcount = 2;
create_axis(i, 0, caps.wXmin, caps.wXmax);
create_axis(i, 1, caps.wYmin, caps.wYmax);
if(caps.wCaps & JOYCAPS_HASZ) {
create_axis(i, 2, caps.wZmin, caps.wZmax);
axcount++;
}
if(caps.wCaps & JOYCAPS_HASR) {
create_axis(i, 3, caps.wRmin, caps.wRmax);
axcount++;
}
if(caps.wCaps & JOYCAPS_HASU) {
create_axis(i, 4, caps.wUmin, caps.wUmax);
axcount++;
}
if(caps.wCaps & JOYCAPS_HASV) {
create_axis(i, 5, caps.wVmin, caps.wVmax);
axcount++;
}
if(caps.wCaps & JOYCAPS_HASPOV)
messages << "1 hat, ";
messages << axcount << " axes, " << min((int)caps.wNumButtons, 32) << " buttons" << std::endl;
}
}
void quit_joysticks()
{
for(auto i : keygroups)
delete i;
buttons.clear();
axes.clear();
hats.clear();
keygroups.clear();
joysticks.clear();
capabilities.clear();
}
void poll_joysticks()
{
modifier_set mod;
for(auto i : capabilities) {
unsigned jnum = i.first;
JOYINFOEX info;
JOYCAPS caps = capabilities[jnum];
info.dwSize = sizeof(info);
info.dwFlags = JOY_RETURNALL;
if(joyGetPosEx(jnum, &info) != JOYERR_NOERROR)
continue; //Not usable.
if(caps.wCaps & JOYCAPS_HASPOV) {
//Read POV hat.
short m = 0;
int pov = info.dwPOV;
if((pov >= 0 && pov <= 6000) || (pov >= 30000 && pov <= 36000))
m |= 1;
if(pov >= 3000 && pov <= 15000)
m |= 2;
if(pov >= 12000 && pov <= 24000)
m |= 4;
if(pov >= 21000 && pov <= 33000)
m |= 8;
if(lhats[jnum] != m) {
platform::queue(keypress(modifier_set(), *hats[jnum], m));
lhats[jnum] = m;
}
}
for(unsigned j = 0; j < caps.wMaxButtons; j++) {
//Read buttons
auto key = std::make_pair(jnum, j);
short x = (info.dwButtons >> j) & 1;
if(buttons.count(key) && lbuttons[key] != x) {
platform::queue(keypress(modifier_set(), *buttons[key], x));
lbuttons[key] = x;
}
}
read_axis(jnum, 0, info.dwXpos, caps.wXmin, caps.wXmax);
read_axis(jnum, 1, info.dwYpos, caps.wYmin, caps.wYmax);
if(caps.wCaps & JOYCAPS_HASZ)
read_axis(jnum, 2, info.dwZpos, caps.wZmin, caps.wZmax);
if(caps.wCaps & JOYCAPS_HASR)
read_axis(jnum, 3, info.dwRpos, caps.wRmin, caps.wRmax);
if(caps.wCaps & JOYCAPS_HASU)
read_axis(jnum, 4, info.dwUpos, caps.wUmin, caps.wUmax);
if(caps.wCaps & JOYCAPS_HASV)
read_axis(jnum, 5, info.dwVpos, caps.wVmin, caps.wVmax);
}
}
}
void joystick_plugin::init() throw()
{
init_joysticks();
quit_ack = quit_signaled = false;
}
void joystick_plugin::quit() throw()
{
quit_signaled = true;
while(!quit_ack);
quit_joysticks();
}
#define POLL_WAIT 20000
void joystick_plugin::thread_fn() throw()
{
while(!quit_signaled) {
poll_joysticks();
usleep(POLL_WAIT);
}
quit_ack = true;
}
void joystick_plugin::signal() throw()
{
quit_signaled = true;
}
const char* joystick_plugin::name = "Win32mm joystick plugin";