o cleanup
This commit is contained in:
403
tools/bsnes/lib/ruby/input/directinput.cpp
Executable file
403
tools/bsnes/lib/ruby/input/directinput.cpp
Executable file
@@ -0,0 +1,403 @@
|
||||
#define DIRECTINPUT_VERSION 0x0800
|
||||
#include <windows.h>
|
||||
#include <dinput.h>
|
||||
|
||||
namespace ruby {
|
||||
|
||||
#include "directinput.hpp"
|
||||
|
||||
static BOOL CALLBACK DI_EnumJoypadsCallback(const DIDEVICEINSTANCE*, void*);
|
||||
static BOOL CALLBACK DI_EnumJoypadAxesCallback(const DIDEVICEOBJECTINSTANCE*, void*);
|
||||
|
||||
using namespace nall;
|
||||
|
||||
class pInputDI {
|
||||
public:
|
||||
InputDI &self;
|
||||
|
||||
struct {
|
||||
LPDIRECTINPUT8 context;
|
||||
LPDIRECTINPUTDEVICE8 keyboard;
|
||||
LPDIRECTINPUTDEVICE8 mouse;
|
||||
LPDIRECTINPUTDEVICE8 gamepad[joypad<>::count];
|
||||
bool mouseacquired;
|
||||
} device;
|
||||
|
||||
struct {
|
||||
HWND handle;
|
||||
} settings;
|
||||
|
||||
bool cap(Input::Setting setting) {
|
||||
if(setting == Input::Handle) return true;
|
||||
if(setting == Input::KeyboardSupport) return true;
|
||||
if(setting == Input::MouseSupport) return true;
|
||||
if(setting == Input::JoypadSupport) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
uintptr_t get(Input::Setting setting) {
|
||||
if(setting == Input::Handle) return (uintptr_t)settings.handle;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool set(Input::Setting setting, uintptr_t param) {
|
||||
if(setting == Input::Handle) {
|
||||
settings.handle = (HWND)param;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool poll(int16_t *table) {
|
||||
memset(table, 0, nall::input_limit * sizeof(int16_t));
|
||||
|
||||
//========
|
||||
//Keyboard
|
||||
//========
|
||||
|
||||
if(device.keyboard) {
|
||||
uint8_t state[256];
|
||||
if(FAILED(device.keyboard->GetDeviceState(sizeof state, state))) {
|
||||
device.keyboard->Acquire();
|
||||
if(FAILED(device.keyboard->GetDeviceState(sizeof state, state))) {
|
||||
memset(state, 0, sizeof state);
|
||||
}
|
||||
}
|
||||
|
||||
table[keyboard<0>::escape] = (bool)(state[0x01] & 0x80);
|
||||
table[keyboard<0>::f1 ] = (bool)(state[0x3b] & 0x80);
|
||||
table[keyboard<0>::f2 ] = (bool)(state[0x3c] & 0x80);
|
||||
table[keyboard<0>::f3 ] = (bool)(state[0x3d] & 0x80);
|
||||
table[keyboard<0>::f4 ] = (bool)(state[0x3e] & 0x80);
|
||||
table[keyboard<0>::f5 ] = (bool)(state[0x3f] & 0x80);
|
||||
table[keyboard<0>::f6 ] = (bool)(state[0x40] & 0x80);
|
||||
table[keyboard<0>::f7 ] = (bool)(state[0x41] & 0x80);
|
||||
table[keyboard<0>::f8 ] = (bool)(state[0x42] & 0x80);
|
||||
table[keyboard<0>::f9 ] = (bool)(state[0x43] & 0x80);
|
||||
table[keyboard<0>::f10 ] = (bool)(state[0x44] & 0x80);
|
||||
table[keyboard<0>::f11 ] = (bool)(state[0x57] & 0x80);
|
||||
table[keyboard<0>::f12 ] = (bool)(state[0x58] & 0x80);
|
||||
|
||||
table[keyboard<0>::print_screen] = (bool)(state[0xb7] & 0x80);
|
||||
table[keyboard<0>::scroll_lock ] = (bool)(state[0x46] & 0x80);
|
||||
table[keyboard<0>::pause ] = (bool)(state[0xc5] & 0x80);
|
||||
table[keyboard<0>::tilde ] = (bool)(state[0x29] & 0x80);
|
||||
|
||||
table[keyboard<0>::num_1] = (bool)(state[0x02] & 0x80);
|
||||
table[keyboard<0>::num_2] = (bool)(state[0x03] & 0x80);
|
||||
table[keyboard<0>::num_3] = (bool)(state[0x04] & 0x80);
|
||||
table[keyboard<0>::num_4] = (bool)(state[0x05] & 0x80);
|
||||
table[keyboard<0>::num_5] = (bool)(state[0x06] & 0x80);
|
||||
table[keyboard<0>::num_6] = (bool)(state[0x07] & 0x80);
|
||||
table[keyboard<0>::num_7] = (bool)(state[0x08] & 0x80);
|
||||
table[keyboard<0>::num_8] = (bool)(state[0x09] & 0x80);
|
||||
table[keyboard<0>::num_9] = (bool)(state[0x0a] & 0x80);
|
||||
table[keyboard<0>::num_0] = (bool)(state[0x0b] & 0x80);
|
||||
|
||||
table[keyboard<0>::dash ] = (bool)(state[0x0c] & 0x80);
|
||||
table[keyboard<0>::equal ] = (bool)(state[0x0d] & 0x80);
|
||||
table[keyboard<0>::backspace] = (bool)(state[0x0e] & 0x80);
|
||||
|
||||
table[keyboard<0>::insert ] = (bool)(state[0xd2] & 0x80);
|
||||
table[keyboard<0>::delete_ ] = (bool)(state[0xd3] & 0x80);
|
||||
table[keyboard<0>::home ] = (bool)(state[0xc7] & 0x80);
|
||||
table[keyboard<0>::end ] = (bool)(state[0xcf] & 0x80);
|
||||
table[keyboard<0>::page_up ] = (bool)(state[0xc9] & 0x80);
|
||||
table[keyboard<0>::page_down] = (bool)(state[0xd1] & 0x80);
|
||||
|
||||
table[keyboard<0>::a] = (bool)(state[0x1e] & 0x80);
|
||||
table[keyboard<0>::b] = (bool)(state[0x30] & 0x80);
|
||||
table[keyboard<0>::c] = (bool)(state[0x2e] & 0x80);
|
||||
table[keyboard<0>::d] = (bool)(state[0x20] & 0x80);
|
||||
table[keyboard<0>::e] = (bool)(state[0x12] & 0x80);
|
||||
table[keyboard<0>::f] = (bool)(state[0x21] & 0x80);
|
||||
table[keyboard<0>::g] = (bool)(state[0x22] & 0x80);
|
||||
table[keyboard<0>::h] = (bool)(state[0x23] & 0x80);
|
||||
table[keyboard<0>::i] = (bool)(state[0x17] & 0x80);
|
||||
table[keyboard<0>::j] = (bool)(state[0x24] & 0x80);
|
||||
table[keyboard<0>::k] = (bool)(state[0x25] & 0x80);
|
||||
table[keyboard<0>::l] = (bool)(state[0x26] & 0x80);
|
||||
table[keyboard<0>::m] = (bool)(state[0x32] & 0x80);
|
||||
table[keyboard<0>::n] = (bool)(state[0x31] & 0x80);
|
||||
table[keyboard<0>::o] = (bool)(state[0x18] & 0x80);
|
||||
table[keyboard<0>::p] = (bool)(state[0x19] & 0x80);
|
||||
table[keyboard<0>::q] = (bool)(state[0x10] & 0x80);
|
||||
table[keyboard<0>::r] = (bool)(state[0x13] & 0x80);
|
||||
table[keyboard<0>::s] = (bool)(state[0x1f] & 0x80);
|
||||
table[keyboard<0>::t] = (bool)(state[0x14] & 0x80);
|
||||
table[keyboard<0>::u] = (bool)(state[0x16] & 0x80);
|
||||
table[keyboard<0>::v] = (bool)(state[0x2f] & 0x80);
|
||||
table[keyboard<0>::w] = (bool)(state[0x11] & 0x80);
|
||||
table[keyboard<0>::x] = (bool)(state[0x2d] & 0x80);
|
||||
table[keyboard<0>::y] = (bool)(state[0x15] & 0x80);
|
||||
table[keyboard<0>::z] = (bool)(state[0x2c] & 0x80);
|
||||
|
||||
table[keyboard<0>::lbracket ] = (bool)(state[0x1a] & 0x80);
|
||||
table[keyboard<0>::rbracket ] = (bool)(state[0x1b] & 0x80);
|
||||
table[keyboard<0>::backslash ] = (bool)(state[0x2b] & 0x80);
|
||||
table[keyboard<0>::semicolon ] = (bool)(state[0x27] & 0x80);
|
||||
table[keyboard<0>::apostrophe] = (bool)(state[0x28] & 0x80);
|
||||
table[keyboard<0>::comma ] = (bool)(state[0x33] & 0x80);
|
||||
table[keyboard<0>::period ] = (bool)(state[0x34] & 0x80);
|
||||
table[keyboard<0>::slash ] = (bool)(state[0x35] & 0x80);
|
||||
|
||||
table[keyboard<0>::pad_0] = (bool)(state[0x4f] & 0x80);
|
||||
table[keyboard<0>::pad_1] = (bool)(state[0x50] & 0x80);
|
||||
table[keyboard<0>::pad_2] = (bool)(state[0x51] & 0x80);
|
||||
table[keyboard<0>::pad_3] = (bool)(state[0x4b] & 0x80);
|
||||
table[keyboard<0>::pad_4] = (bool)(state[0x4c] & 0x80);
|
||||
table[keyboard<0>::pad_5] = (bool)(state[0x4d] & 0x80);
|
||||
table[keyboard<0>::pad_6] = (bool)(state[0x47] & 0x80);
|
||||
table[keyboard<0>::pad_7] = (bool)(state[0x48] & 0x80);
|
||||
table[keyboard<0>::pad_8] = (bool)(state[0x49] & 0x80);
|
||||
table[keyboard<0>::pad_9] = (bool)(state[0x52] & 0x80);
|
||||
table[keyboard<0>::point] = (bool)(state[0x53] & 0x80);
|
||||
|
||||
table[keyboard<0>::add] = (bool)(state[0x4e] & 0x80);
|
||||
table[keyboard<0>::subtract] = (bool)(state[0x4a] & 0x80);
|
||||
table[keyboard<0>::multiply] = (bool)(state[0x37] & 0x80);
|
||||
table[keyboard<0>::divide] = (bool)(state[0xb5] & 0x80);
|
||||
table[keyboard<0>::enter] = (bool)(state[0x9c] & 0x80);
|
||||
|
||||
table[keyboard<0>::num_lock ] = (bool)(state[0x45] & 0x80);
|
||||
table[keyboard<0>::caps_lock] = (bool)(state[0x3a] & 0x80);
|
||||
|
||||
table[keyboard<0>::up ] = (bool)(state[0xc8] & 0x80);
|
||||
table[keyboard<0>::down ] = (bool)(state[0xd0] & 0x80);
|
||||
table[keyboard<0>::left ] = (bool)(state[0xcb] & 0x80);
|
||||
table[keyboard<0>::right] = (bool)(state[0xcd] & 0x80);
|
||||
|
||||
table[keyboard<0>::tab ] = (bool)(state[0x0f] & 0x80);
|
||||
table[keyboard<0>::return_ ] = (bool)(state[0x1c] & 0x80);
|
||||
table[keyboard<0>::spacebar] = (bool)(state[0x39] & 0x80);
|
||||
|
||||
table[keyboard<0>::lctrl ] = (bool)(state[0x1d] & 0x80);
|
||||
table[keyboard<0>::rctrl ] = (bool)(state[0x9d] & 0x80);
|
||||
table[keyboard<0>::lalt ] = (bool)(state[0x38] & 0x80);
|
||||
table[keyboard<0>::ralt ] = (bool)(state[0xb8] & 0x80);
|
||||
table[keyboard<0>::lshift] = (bool)(state[0x2a] & 0x80);
|
||||
table[keyboard<0>::rshift] = (bool)(state[0x36] & 0x80);
|
||||
table[keyboard<0>::lsuper] = (bool)(state[0xdb] & 0x80);
|
||||
table[keyboard<0>::rsuper] = (bool)(state[0xdc] & 0x80);
|
||||
table[keyboard<0>::menu ] = (bool)(state[0xdd] & 0x80);
|
||||
}
|
||||
|
||||
//=====
|
||||
//Mouse
|
||||
//=====
|
||||
|
||||
if(device.mouse) {
|
||||
DIMOUSESTATE2 state;
|
||||
if(FAILED(device.mouse->GetDeviceState(sizeof(DIMOUSESTATE2), (void*)&state))) {
|
||||
device.mouse->Acquire();
|
||||
if(FAILED(device.mouse->GetDeviceState(sizeof(DIMOUSESTATE2), (void*)&state))) {
|
||||
memset(&state, 0, sizeof(DIMOUSESTATE2));
|
||||
}
|
||||
}
|
||||
|
||||
table[mouse<0>::x] = state.lX;
|
||||
table[mouse<0>::y] = state.lY;
|
||||
table[mouse<0>::z] = state.lZ / WHEEL_DELTA;
|
||||
for(unsigned n = 0; n < mouse<>::buttons; n++) {
|
||||
table[mouse<0>::button + n] = (bool)state.rgbButtons[n];
|
||||
}
|
||||
|
||||
//on Windows, 0 = left, 1 = right, 2 = middle
|
||||
//swap middle and right buttons for consistency with Linux
|
||||
int16_t temp = table[mouse<0>::button + 1];
|
||||
table[mouse<0>::button + 1] = table[mouse<0>::button + 2];
|
||||
table[mouse<0>::button + 2] = temp;
|
||||
}
|
||||
|
||||
//=========
|
||||
//Joypad(s)
|
||||
//=========
|
||||
|
||||
for(unsigned i = 0; i < joypad<>::count; i++) {
|
||||
if(!device.gamepad[i]) continue;
|
||||
unsigned index = joypad<>::index(i, joypad<>::none);
|
||||
|
||||
if(FAILED(device.gamepad[i]->Poll())) {
|
||||
device.gamepad[i]->Acquire();
|
||||
continue;
|
||||
}
|
||||
|
||||
DIJOYSTATE2 state;
|
||||
device.gamepad[i]->GetDeviceState(sizeof(DIJOYSTATE2), &state);
|
||||
|
||||
//POV hats
|
||||
for(unsigned n = 0; n < min((unsigned)joypad<>::hats, 4); n++) {
|
||||
//POV value is in clockwise-hundredth degree units.
|
||||
unsigned pov = state.rgdwPOV[n];
|
||||
//some drivers report a centered POV hat as -1U, others as 65535U.
|
||||
//>= 36000 will match both, as well as invalid ranges.
|
||||
if(pov < 36000) {
|
||||
if(pov >= 31500 || pov <= 4500) table[index + joypad<>::hat + n] |= joypad<>::hat_up;
|
||||
if(pov >= 4500 && pov <= 13500) table[index + joypad<>::hat + n] |= joypad<>::hat_right;
|
||||
if(pov >= 13500 && pov <= 22500) table[index + joypad<>::hat + n] |= joypad<>::hat_down;
|
||||
if(pov >= 22500 && pov <= 31500) table[index + joypad<>::hat + n] |= joypad<>::hat_left;
|
||||
}
|
||||
}
|
||||
|
||||
//axes
|
||||
table[index + joypad<>::axis + 0] = state.lX;
|
||||
table[index + joypad<>::axis + 1] = state.lY;
|
||||
table[index + joypad<>::axis + 2] = state.lZ;
|
||||
table[index + joypad<>::axis + 3] = state.lRx;
|
||||
table[index + joypad<>::axis + 4] = state.lRy;
|
||||
table[index + joypad<>::axis + 5] = state.lRz;
|
||||
|
||||
//buttons
|
||||
for(unsigned n = 0; n < min((unsigned)joypad<>::buttons, 128); n++) {
|
||||
table[index + joypad<>::button + n] = (bool)state.rgbButtons[n];
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool init_joypad(const DIDEVICEINSTANCE *instance) {
|
||||
unsigned n;
|
||||
for(n = 0; n < joypad<>::count; n++) { if(!device.gamepad[n]) break; }
|
||||
if(n >= joypad<>::count) return DIENUM_STOP;
|
||||
|
||||
if(FAILED(device.context->CreateDevice(instance->guidInstance, &device.gamepad[n], 0))) {
|
||||
return DIENUM_CONTINUE; //continue and try next gamepad
|
||||
}
|
||||
|
||||
device.gamepad[n]->SetDataFormat(&c_dfDIJoystick2);
|
||||
device.gamepad[n]->SetCooperativeLevel(settings.handle, DISCL_NONEXCLUSIVE | DISCL_BACKGROUND);
|
||||
device.gamepad[n]->EnumObjects(DI_EnumJoypadAxesCallback, (void*)this, DIDFT_ABSAXIS);
|
||||
|
||||
return DIENUM_CONTINUE;
|
||||
}
|
||||
|
||||
bool init_axis(const DIDEVICEOBJECTINSTANCE *instance) {
|
||||
signed n;
|
||||
for(n = joypad<>::count - 1; n >= 0; n--) { if(device.gamepad[n]) break; }
|
||||
if(n < 0) return DIENUM_STOP;
|
||||
|
||||
DIPROPRANGE range;
|
||||
range.diph.dwSize = sizeof(DIPROPRANGE);
|
||||
range.diph.dwHeaderSize = sizeof(DIPROPHEADER);
|
||||
range.diph.dwHow = DIPH_BYID;
|
||||
range.diph.dwObj = instance->dwType;
|
||||
range.lMin = -32768;
|
||||
range.lMax = +32767;
|
||||
device.gamepad[n]->SetProperty(DIPROP_RANGE, &range.diph);
|
||||
|
||||
return DIENUM_CONTINUE;
|
||||
}
|
||||
|
||||
bool init() {
|
||||
device.context = 0;
|
||||
device.keyboard = 0;
|
||||
device.mouse = 0;
|
||||
for(unsigned i = 0; i < joypad<>::count; i++) device.gamepad[i] = 0;
|
||||
device.mouseacquired = false;
|
||||
|
||||
DirectInput8Create(GetModuleHandle(0), 0x0800, IID_IDirectInput8, (void**)&device.context, 0);
|
||||
|
||||
device.context->CreateDevice(GUID_SysKeyboard, &device.keyboard, 0);
|
||||
device.keyboard->SetDataFormat(&c_dfDIKeyboard);
|
||||
device.keyboard->SetCooperativeLevel(settings.handle, DISCL_NONEXCLUSIVE | DISCL_BACKGROUND);
|
||||
device.keyboard->Acquire();
|
||||
|
||||
device.context->CreateDevice(GUID_SysMouse, &device.mouse, 0);
|
||||
device.mouse->SetDataFormat(&c_dfDIMouse2);
|
||||
HRESULT hr = device.mouse->SetCooperativeLevel(settings.handle, DISCL_NONEXCLUSIVE | DISCL_BACKGROUND);
|
||||
device.mouse->Acquire();
|
||||
|
||||
device.context->EnumDevices(DI8DEVCLASS_GAMECTRL, DI_EnumJoypadsCallback, (void*)this, DIEDFL_ATTACHEDONLY);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void term() {
|
||||
if(device.keyboard) {
|
||||
device.keyboard->Unacquire();
|
||||
device.keyboard->Release();
|
||||
device.keyboard = 0;
|
||||
}
|
||||
|
||||
if(device.mouse) {
|
||||
device.mouse->Unacquire();
|
||||
device.mouse->Release();
|
||||
device.mouse = 0;
|
||||
}
|
||||
|
||||
for(unsigned i = 0; i < joypad<>::count; i++) {
|
||||
if(device.gamepad[i]) {
|
||||
device.gamepad[i]->Unacquire();
|
||||
device.gamepad[i]->Release();
|
||||
device.gamepad[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if(device.context) {
|
||||
device.context->Release();
|
||||
device.context = 0;
|
||||
}
|
||||
}
|
||||
|
||||
bool acquire() {
|
||||
if(!device.mouse) return false;
|
||||
if(acquired() == false) {
|
||||
device.mouse->Unacquire();
|
||||
device.mouse->SetCooperativeLevel(settings.handle, DISCL_EXCLUSIVE | DISCL_FOREGROUND);
|
||||
device.mouse->Acquire();
|
||||
device.mouseacquired = true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool unacquire() {
|
||||
if(!device.mouse) return false;
|
||||
if(acquired() == true) {
|
||||
device.mouse->Unacquire();
|
||||
device.mouse->SetCooperativeLevel(settings.handle, DISCL_NONEXCLUSIVE | DISCL_BACKGROUND);
|
||||
device.mouse->Acquire();
|
||||
device.mouseacquired = false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool acquired() {
|
||||
return device.mouseacquired;
|
||||
}
|
||||
|
||||
pInputDI(InputDI &self_) : self(self_) {
|
||||
device.context = 0;
|
||||
device.keyboard = 0;
|
||||
device.mouse = 0;
|
||||
for(unsigned i = 0; i < joypad<>::count; i++) device.gamepad[i] = 0;
|
||||
device.mouseacquired = false;
|
||||
|
||||
settings.handle = 0;
|
||||
}
|
||||
|
||||
~pInputDI() { term(); }
|
||||
};
|
||||
|
||||
BOOL CALLBACK DI_EnumJoypadsCallback(const DIDEVICEINSTANCE *instance, void *p) {
|
||||
return ((pInputDI*)p)->init_joypad(instance);
|
||||
}
|
||||
|
||||
BOOL CALLBACK DI_EnumJoypadAxesCallback(const DIDEVICEOBJECTINSTANCE *instance, void *p) {
|
||||
return ((pInputDI*)p)->init_axis(instance);
|
||||
}
|
||||
|
||||
bool InputDI::cap(Setting setting) { return p.cap(setting); }
|
||||
uintptr_t InputDI::get(Setting setting) { return p.get(setting); }
|
||||
bool InputDI::set(Setting setting, uintptr_t param) { return p.set(setting, param); }
|
||||
bool InputDI::acquire() { return p.acquire(); }
|
||||
bool InputDI::unacquire() { return p.unacquire(); }
|
||||
bool InputDI::acquired() { return p.acquired(); }
|
||||
bool InputDI::poll(int16_t *table) { return p.poll(table); }
|
||||
bool InputDI::init() { return p.init(); }
|
||||
void InputDI::term() { p.term(); }
|
||||
InputDI::InputDI() : p(*new pInputDI(*this)) {}
|
||||
InputDI::~InputDI() { delete &p; }
|
||||
|
||||
} //namespace ruby
|
||||
22
tools/bsnes/lib/ruby/input/directinput.hpp
Executable file
22
tools/bsnes/lib/ruby/input/directinput.hpp
Executable file
@@ -0,0 +1,22 @@
|
||||
class pInputDI;
|
||||
|
||||
class InputDI : public Input {
|
||||
public:
|
||||
bool cap(Setting);
|
||||
uintptr_t get(Setting);
|
||||
bool set(Setting, uintptr_t);
|
||||
|
||||
bool acquire();
|
||||
bool unacquire();
|
||||
bool acquired();
|
||||
|
||||
bool poll(int16_t *table);
|
||||
bool init();
|
||||
void term();
|
||||
|
||||
InputDI();
|
||||
~InputDI();
|
||||
|
||||
private:
|
||||
pInputDI &p;
|
||||
};
|
||||
781
tools/bsnes/lib/ruby/input/rawinput.cpp
Executable file
781
tools/bsnes/lib/ruby/input/rawinput.cpp
Executable file
@@ -0,0 +1,781 @@
|
||||
//RawInput driver
|
||||
//author: byuu
|
||||
|
||||
//this driver utilizes RawInput (WM_INPUT) to capture keyboard and mouse input.
|
||||
//although this requires WinXP or newer, it is the only way to uniquely identify
|
||||
//and independently map multiple keyboards and mice. DirectInput merges all
|
||||
//keyboards and mice into one device per.
|
||||
//
|
||||
//as WM_INPUT lacks specific RAWINPUT structures for gamepads, giving only raw
|
||||
//data, and because DirectInput supports up to 16 joypads, DirectInput is used
|
||||
//for joypad mapping.
|
||||
//
|
||||
//further, Xbox 360 controllers are explicitly detected and supported through
|
||||
//XInput. this is because under DirectInput, the LT / RT (trigger) buttons are
|
||||
//merged into a single Z-axis -- making it impossible to detect both buttons
|
||||
//being pressed at the same time. with XInput, the state of both trigger
|
||||
//buttons can be read independently.
|
||||
//
|
||||
//so in essence, this is actually more of a hybrid driver.
|
||||
|
||||
#define DIRECTINPUT_VERSION 0x0800
|
||||
#include <dinput.h>
|
||||
#include <xinput.h>
|
||||
|
||||
namespace ruby {
|
||||
|
||||
#include "rawinput.hpp"
|
||||
|
||||
DWORD WINAPI RawInputThreadProc(void*);
|
||||
LRESULT CALLBACK RawInputWindowProc(HWND, UINT, WPARAM, LPARAM);
|
||||
|
||||
class RawInput {
|
||||
public:
|
||||
HANDLE mutex;
|
||||
HWND hwnd;
|
||||
bool initialized;
|
||||
bool ready;
|
||||
|
||||
struct Device {
|
||||
HANDLE handle;
|
||||
};
|
||||
|
||||
struct Keyboard : Device {
|
||||
bool state[keyboard<>::length];
|
||||
|
||||
void update(RAWINPUT *input) {
|
||||
unsigned code = input->data.keyboard.MakeCode;
|
||||
unsigned flags = input->data.keyboard.Flags;
|
||||
|
||||
#define map(id, flag, name) if(code == id) state[name] = (bool)(flags == flag);
|
||||
map(0x0001, 0, keyboard<>::escape)
|
||||
map(0x003b, 0, keyboard<>::f1)
|
||||
map(0x003c, 0, keyboard<>::f2)
|
||||
map(0x003d, 0, keyboard<>::f3)
|
||||
map(0x003e, 0, keyboard<>::f4)
|
||||
map(0x003f, 0, keyboard<>::f5)
|
||||
map(0x0040, 0, keyboard<>::f6)
|
||||
map(0x0041, 0, keyboard<>::f7)
|
||||
map(0x0042, 0, keyboard<>::f8)
|
||||
map(0x0043, 0, keyboard<>::f9)
|
||||
map(0x0044, 0, keyboard<>::f10)
|
||||
map(0x0057, 0, keyboard<>::f11)
|
||||
map(0x0058, 0, keyboard<>::f12)
|
||||
|
||||
map(0x0037, 2, keyboard<>::print_screen)
|
||||
map(0x0046, 0, keyboard<>::scroll_lock)
|
||||
map(0x001d, 4, keyboard<>::pause)
|
||||
map(0x0029, 0, keyboard<>::tilde)
|
||||
|
||||
map(0x0002, 0, keyboard<>::num_1)
|
||||
map(0x0003, 0, keyboard<>::num_2)
|
||||
map(0x0004, 0, keyboard<>::num_3)
|
||||
map(0x0005, 0, keyboard<>::num_4)
|
||||
map(0x0006, 0, keyboard<>::num_5)
|
||||
map(0x0007, 0, keyboard<>::num_6)
|
||||
map(0x0008, 0, keyboard<>::num_7)
|
||||
map(0x0009, 0, keyboard<>::num_8)
|
||||
map(0x000a, 0, keyboard<>::num_9)
|
||||
map(0x000b, 0, keyboard<>::num_0)
|
||||
|
||||
map(0x000c, 0, keyboard<>::dash)
|
||||
map(0x000d, 0, keyboard<>::equal)
|
||||
map(0x000e, 0, keyboard<>::backspace)
|
||||
|
||||
map(0x0052, 2, keyboard<>::insert)
|
||||
map(0x0053, 2, keyboard<>::delete_)
|
||||
map(0x0047, 2, keyboard<>::home)
|
||||
map(0x004f, 2, keyboard<>::end)
|
||||
map(0x0049, 2, keyboard<>::page_up)
|
||||
map(0x0051, 2, keyboard<>::page_down)
|
||||
|
||||
map(0x001e, 0, keyboard<>::a)
|
||||
map(0x0030, 0, keyboard<>::b)
|
||||
map(0x002e, 0, keyboard<>::c)
|
||||
map(0x0020, 0, keyboard<>::d)
|
||||
map(0x0012, 0, keyboard<>::e)
|
||||
map(0x0021, 0, keyboard<>::f)
|
||||
map(0x0022, 0, keyboard<>::g)
|
||||
map(0x0023, 0, keyboard<>::h)
|
||||
map(0x0017, 0, keyboard<>::i)
|
||||
map(0x0024, 0, keyboard<>::j)
|
||||
map(0x0025, 0, keyboard<>::k)
|
||||
map(0x0026, 0, keyboard<>::l)
|
||||
map(0x0032, 0, keyboard<>::m)
|
||||
map(0x0031, 0, keyboard<>::n)
|
||||
map(0x0018, 0, keyboard<>::o)
|
||||
map(0x0019, 0, keyboard<>::p)
|
||||
map(0x0010, 0, keyboard<>::q)
|
||||
map(0x0013, 0, keyboard<>::r)
|
||||
map(0x001f, 0, keyboard<>::s)
|
||||
map(0x0014, 0, keyboard<>::t)
|
||||
map(0x0016, 0, keyboard<>::u)
|
||||
map(0x002f, 0, keyboard<>::v)
|
||||
map(0x0011, 0, keyboard<>::w)
|
||||
map(0x002d, 0, keyboard<>::x)
|
||||
map(0x0015, 0, keyboard<>::y)
|
||||
map(0x002c, 0, keyboard<>::z)
|
||||
|
||||
map(0x001a, 0, keyboard<>::lbracket)
|
||||
map(0x001b, 0, keyboard<>::rbracket)
|
||||
map(0x002b, 0, keyboard<>::backslash)
|
||||
map(0x0027, 0, keyboard<>::semicolon)
|
||||
map(0x0028, 0, keyboard<>::apostrophe)
|
||||
map(0x0033, 0, keyboard<>::comma)
|
||||
map(0x0034, 0, keyboard<>::period)
|
||||
map(0x0035, 0, keyboard<>::slash)
|
||||
|
||||
map(0x004f, 0, keyboard<>::pad_1)
|
||||
map(0x0050, 0, keyboard<>::pad_2)
|
||||
map(0x0051, 0, keyboard<>::pad_3)
|
||||
map(0x004b, 0, keyboard<>::pad_4)
|
||||
map(0x004c, 0, keyboard<>::pad_5)
|
||||
map(0x004d, 0, keyboard<>::pad_6)
|
||||
map(0x0047, 0, keyboard<>::pad_7)
|
||||
map(0x0048, 0, keyboard<>::pad_8)
|
||||
map(0x0049, 0, keyboard<>::pad_9)
|
||||
map(0x0052, 0, keyboard<>::pad_0)
|
||||
|
||||
map(0x0053, 0, keyboard<>::point)
|
||||
map(0x001c, 2, keyboard<>::enter)
|
||||
map(0x004e, 0, keyboard<>::add)
|
||||
map(0x004a, 0, keyboard<>::subtract)
|
||||
map(0x0037, 0, keyboard<>::multiply)
|
||||
map(0x0035, 2, keyboard<>::divide)
|
||||
|
||||
map(0x0045, 0, keyboard<>::num_lock)
|
||||
map(0x003a, 0, keyboard<>::caps_lock)
|
||||
|
||||
//pause signals 0x1d:4 + 0x45:0, whereas num_lock signals only 0x45:0.
|
||||
//this makes it impractical to detect both pause+num_lock independently.
|
||||
//workaround: always detect pause; detect num_lock only when pause is released.
|
||||
if(state[keyboard<>::pause]) state[keyboard<>::num_lock] = false;
|
||||
|
||||
map(0x0048, 2, keyboard<>::up)
|
||||
map(0x0050, 2, keyboard<>::down)
|
||||
map(0x004b, 2, keyboard<>::left)
|
||||
map(0x004d, 2, keyboard<>::right)
|
||||
|
||||
map(0x000f, 0, keyboard<>::tab)
|
||||
map(0x001c, 0, keyboard<>::return_)
|
||||
map(0x0039, 0, keyboard<>::spacebar)
|
||||
|
||||
map(0x001d, 0, keyboard<>::lctrl)
|
||||
map(0x001d, 2, keyboard<>::rctrl)
|
||||
map(0x0038, 0, keyboard<>::lalt)
|
||||
map(0x0038, 2, keyboard<>::ralt)
|
||||
map(0x002a, 0, keyboard<>::lshift)
|
||||
map(0x0036, 0, keyboard<>::rshift)
|
||||
map(0x005b, 2, keyboard<>::lsuper)
|
||||
map(0x005c, 2, keyboard<>::rsuper)
|
||||
map(0x005d, 2, keyboard<>::menu)
|
||||
#undef map
|
||||
}
|
||||
|
||||
Keyboard() {
|
||||
for(unsigned i = 0; i < keyboard<>::length; i++) state[i] = false;
|
||||
}
|
||||
};
|
||||
|
||||
struct Mouse : Device {
|
||||
signed xDistance;
|
||||
signed yDistance;
|
||||
signed zDistance;
|
||||
unsigned buttonState;
|
||||
|
||||
void sync() {
|
||||
xDistance = 0;
|
||||
yDistance = 0;
|
||||
zDistance = 0;
|
||||
}
|
||||
|
||||
void update(RAWINPUT *input) {
|
||||
if((input->data.mouse.usFlags & 1) == MOUSE_MOVE_RELATIVE) {
|
||||
xDistance += input->data.mouse.lLastX;
|
||||
yDistance += input->data.mouse.lLastY;
|
||||
}
|
||||
|
||||
if(input->data.mouse.usButtonFlags & RI_MOUSE_BUTTON_1_DOWN) buttonState |= 1 << 0;
|
||||
if(input->data.mouse.usButtonFlags & RI_MOUSE_BUTTON_1_UP ) buttonState &=~ 1 << 0;
|
||||
if(input->data.mouse.usButtonFlags & RI_MOUSE_BUTTON_2_DOWN) buttonState |= 1 << 2; //swap middle and right buttons,
|
||||
if(input->data.mouse.usButtonFlags & RI_MOUSE_BUTTON_2_UP ) buttonState &=~ 1 << 2; //for consistency with Linux:
|
||||
if(input->data.mouse.usButtonFlags & RI_MOUSE_BUTTON_3_DOWN) buttonState |= 1 << 1; //left = 0, middle = 1, right = 2
|
||||
if(input->data.mouse.usButtonFlags & RI_MOUSE_BUTTON_3_UP ) buttonState &=~ 1 << 1;
|
||||
if(input->data.mouse.usButtonFlags & RI_MOUSE_BUTTON_4_DOWN) buttonState |= 1 << 3;
|
||||
if(input->data.mouse.usButtonFlags & RI_MOUSE_BUTTON_4_UP ) buttonState &=~ 1 << 3;
|
||||
if(input->data.mouse.usButtonFlags & RI_MOUSE_BUTTON_5_DOWN) buttonState |= 1 << 4;
|
||||
if(input->data.mouse.usButtonFlags & RI_MOUSE_BUTTON_5_UP ) buttonState &=~ 1 << 4;
|
||||
|
||||
if(input->data.mouse.usButtonFlags & RI_MOUSE_WHEEL) {
|
||||
zDistance += (int16_t)input->data.mouse.usButtonData;
|
||||
}
|
||||
}
|
||||
|
||||
Mouse() {
|
||||
xDistance = yDistance = zDistance = 0;
|
||||
buttonState = 0;
|
||||
}
|
||||
};
|
||||
|
||||
//keep track of gamepads for the sole purpose of distinguishing XInput devices
|
||||
//from all other devices. this is necessary, as DirectInput does not provide
|
||||
//a way to retrieve the necessary RIDI_DEVICENAME string.
|
||||
struct Gamepad : Device {
|
||||
bool isXInputDevice;
|
||||
uint16_t vendorId;
|
||||
uint16_t productId;
|
||||
};
|
||||
|
||||
vector<Keyboard> lkeyboard;
|
||||
vector<Mouse> lmouse;
|
||||
vector<Gamepad> lgamepad;
|
||||
|
||||
LRESULT window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
|
||||
if(msg == WM_INPUT) {
|
||||
unsigned size = 0;
|
||||
GetRawInputData((HRAWINPUT)lparam, RID_INPUT, NULL, &size, sizeof(RAWINPUTHEADER));
|
||||
RAWINPUT *input = new RAWINPUT[size];
|
||||
GetRawInputData((HRAWINPUT)lparam, RID_INPUT, input, &size, sizeof(RAWINPUTHEADER));
|
||||
WaitForSingleObject(mutex, INFINITE);
|
||||
|
||||
if(input->header.dwType == RIM_TYPEKEYBOARD) {
|
||||
for(unsigned i = 0; i < lkeyboard.size(); i++) {
|
||||
if(input->header.hDevice == lkeyboard[i].handle) {
|
||||
lkeyboard[i].update(input);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else if(input->header.dwType == RIM_TYPEMOUSE) {
|
||||
for(unsigned i = 0; i < lmouse.size(); i++) {
|
||||
if(input->header.hDevice == lmouse[i].handle) {
|
||||
lmouse[i].update(input);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ReleaseMutex(mutex);
|
||||
//allow propogation of WM_INPUT message
|
||||
LRESULT result = DefRawInputProc(&input, size, sizeof(RAWINPUTHEADER));
|
||||
delete[] input;
|
||||
return result;
|
||||
}
|
||||
|
||||
return DefWindowProc(hwnd, msg, wparam, lparam);
|
||||
}
|
||||
|
||||
//this is used to sort device IDs
|
||||
struct DevicePool {
|
||||
HANDLE handle;
|
||||
char name[4096];
|
||||
bool operator<(const DevicePool &pool) const { return strcmp(name, pool.name) < 0; }
|
||||
};
|
||||
|
||||
int main() {
|
||||
//create an invisible window to act as a sink, capturing all WM_INPUT messages
|
||||
WNDCLASS wc;
|
||||
wc.cbClsExtra = 0;
|
||||
wc.cbWndExtra = 0;
|
||||
wc.hbrBackground = (HBRUSH)COLOR_WINDOW;
|
||||
wc.hCursor = LoadCursor(0, IDC_ARROW);
|
||||
wc.hIcon = LoadIcon(0, IDI_APPLICATION);
|
||||
wc.hInstance = GetModuleHandle(0);
|
||||
wc.lpfnWndProc = RawInputWindowProc;
|
||||
wc.lpszClassName = "RawInputClass";
|
||||
wc.lpszMenuName = 0;
|
||||
wc.style = CS_VREDRAW | CS_HREDRAW;
|
||||
RegisterClass(&wc);
|
||||
|
||||
hwnd = CreateWindow("RawInputClass", "RawInputClass", WS_POPUP,
|
||||
0, 0, 64, 64, 0, 0, GetModuleHandle(0), 0);
|
||||
|
||||
//enumerate all HID devices
|
||||
unsigned devices = 0;
|
||||
GetRawInputDeviceList(NULL, &devices, sizeof(RAWINPUTDEVICELIST));
|
||||
RAWINPUTDEVICELIST *list = new RAWINPUTDEVICELIST[devices];
|
||||
GetRawInputDeviceList(list, &devices, sizeof(RAWINPUTDEVICELIST));
|
||||
|
||||
//sort all devices by name. this has two important properties:
|
||||
//1) it consistently orders peripherals, so mapped IDs remain constant
|
||||
//2) it sorts the virtual keyboard and mouse to the bottom of the list
|
||||
// (real devices start with \\?\HID#, virtual with \\?\Root#)
|
||||
DevicePool pool[devices];
|
||||
for(unsigned i = 0; i < devices; i++) {
|
||||
pool[i].handle = list[i].hDevice;
|
||||
unsigned size = sizeof(pool[i].name) - 1;
|
||||
GetRawInputDeviceInfo(list[i].hDevice, RIDI_DEVICENAME, &pool[i].name, &size);
|
||||
}
|
||||
nall::sort(pool, devices);
|
||||
delete[] list;
|
||||
|
||||
for(unsigned i = 0; i < devices; i++) {
|
||||
RID_DEVICE_INFO info;
|
||||
info.cbSize = sizeof(RID_DEVICE_INFO);
|
||||
|
||||
unsigned size = info.cbSize;
|
||||
GetRawInputDeviceInfo(pool[i].handle, RIDI_DEVICEINFO, &info, &size);
|
||||
|
||||
if(info.dwType == RIM_TYPEKEYBOARD) {
|
||||
unsigned n = lkeyboard.size();
|
||||
lkeyboard[n].handle = pool[i].handle;
|
||||
} else if(info.dwType == RIM_TYPEMOUSE) {
|
||||
unsigned n = lmouse.size();
|
||||
lmouse[n].handle = pool[i].handle;
|
||||
} else if(info.dwType == RIM_TYPEHID) {
|
||||
//if this is a gamepad or joystick device ...
|
||||
if(info.hid.usUsagePage == 1 && (info.hid.usUsage == 4 || info.hid.usUsage == 5)) {
|
||||
//... then cache device information for later use
|
||||
unsigned n = lgamepad.size();
|
||||
lgamepad[n].handle = pool[i].handle;
|
||||
lgamepad[n].vendorId = (uint16_t)info.hid.dwVendorId;
|
||||
lgamepad[n].productId = (uint16_t)info.hid.dwProductId;
|
||||
|
||||
//per MSDN: XInput devices have "IG_" in their device strings,
|
||||
//which is how they should be identified.
|
||||
const char *p = strstr(pool[i].name, "IG_");
|
||||
lgamepad[n].isXInputDevice = (bool)p;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
RAWINPUTDEVICE device[2];
|
||||
//capture all keyboard input
|
||||
device[0].usUsagePage = 1;
|
||||
device[0].usUsage = 6;
|
||||
device[0].dwFlags = RIDEV_INPUTSINK;
|
||||
device[0].hwndTarget = hwnd;
|
||||
//capture all mouse input
|
||||
device[1].usUsagePage = 1;
|
||||
device[1].usUsage = 2;
|
||||
device[1].dwFlags = RIDEV_INPUTSINK;
|
||||
device[1].hwndTarget = hwnd;
|
||||
RegisterRawInputDevices(device, 2, sizeof(RAWINPUTDEVICE));
|
||||
|
||||
WaitForSingleObject(mutex, INFINITE);
|
||||
ready = true;
|
||||
ReleaseMutex(mutex);
|
||||
|
||||
while(true) {
|
||||
MSG msg;
|
||||
GetMessage(&msg, hwnd, 0, 0);
|
||||
TranslateMessage(&msg);
|
||||
DispatchMessage(&msg);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
RawInput() : initialized(false), ready(false) {
|
||||
}
|
||||
};
|
||||
|
||||
static RawInput rawinput;
|
||||
|
||||
DWORD WINAPI RawInputThreadProc(void*) {
|
||||
return rawinput.main();
|
||||
}
|
||||
|
||||
LRESULT CALLBACK RawInputWindowProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
|
||||
return rawinput.window_proc(hwnd, msg, wparam, lparam);
|
||||
}
|
||||
|
||||
class XInput {
|
||||
public:
|
||||
struct Gamepad {
|
||||
unsigned id;
|
||||
|
||||
int16_t hat;
|
||||
int16_t axis[6];
|
||||
bool button[10];
|
||||
|
||||
void poll(XINPUT_STATE &state) {
|
||||
hat = joypad<>::hat_center;
|
||||
if(state.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_UP ) hat |= joypad<>::hat_up;
|
||||
if(state.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_RIGHT) hat |= joypad<>::hat_right;
|
||||
if(state.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_DOWN ) hat |= joypad<>::hat_down;
|
||||
if(state.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_LEFT ) hat |= joypad<>::hat_left;
|
||||
|
||||
axis[0] = (int16_t)state.Gamepad.sThumbLX;
|
||||
axis[1] = (int16_t)state.Gamepad.sThumbLY;
|
||||
axis[2] = (int16_t)state.Gamepad.sThumbRX;
|
||||
axis[3] = (int16_t)state.Gamepad.sThumbRY;
|
||||
|
||||
//transform left and right trigger ranges:
|
||||
//from: 0 (low, eg released) to 255 (high, eg pressed all the way down)
|
||||
//to: +32767 (low) to -32768 (high)
|
||||
uint16_t triggerX = state.Gamepad.bLeftTrigger;
|
||||
uint16_t triggerY = state.Gamepad.bRightTrigger;
|
||||
|
||||
triggerX = (triggerX << 8) | triggerX;
|
||||
triggerY = (triggerY << 8) | triggerY;
|
||||
|
||||
axis[4] = (~triggerX) - 32768;
|
||||
axis[5] = (~triggerY) - 32768;
|
||||
|
||||
button[0] = (bool)(state.Gamepad.wButtons & XINPUT_GAMEPAD_A);
|
||||
button[1] = (bool)(state.Gamepad.wButtons & XINPUT_GAMEPAD_B);
|
||||
button[2] = (bool)(state.Gamepad.wButtons & XINPUT_GAMEPAD_X);
|
||||
button[3] = (bool)(state.Gamepad.wButtons & XINPUT_GAMEPAD_Y);
|
||||
button[4] = (bool)(state.Gamepad.wButtons & XINPUT_GAMEPAD_BACK);
|
||||
button[5] = (bool)(state.Gamepad.wButtons & XINPUT_GAMEPAD_START);
|
||||
button[6] = (bool)(state.Gamepad.wButtons & XINPUT_GAMEPAD_LEFT_SHOULDER);
|
||||
button[7] = (bool)(state.Gamepad.wButtons & XINPUT_GAMEPAD_RIGHT_SHOULDER);
|
||||
button[8] = (bool)(state.Gamepad.wButtons & XINPUT_GAMEPAD_LEFT_THUMB);
|
||||
button[9] = (bool)(state.Gamepad.wButtons & XINPUT_GAMEPAD_RIGHT_THUMB);
|
||||
}
|
||||
|
||||
Gamepad() {
|
||||
hat = joypad<>::hat_center;
|
||||
for(unsigned n = 0; n < 6; n++) axis[n] = 0;
|
||||
for(unsigned n = 0; n < 10; n++) button[n] = false;
|
||||
}
|
||||
};
|
||||
|
||||
vector<Gamepad> lgamepad;
|
||||
|
||||
void poll() {
|
||||
for(unsigned i = 0; i < lgamepad.size(); i++) {
|
||||
XINPUT_STATE state;
|
||||
DWORD result = XInputGetState(lgamepad[i].id, &state);
|
||||
if(result == ERROR_SUCCESS) lgamepad[i].poll(state);
|
||||
}
|
||||
}
|
||||
|
||||
void init() {
|
||||
//XInput only supports up to four controllers
|
||||
for(unsigned i = 0; i <= 3; i++) {
|
||||
XINPUT_STATE state;
|
||||
DWORD result = XInputGetState(i, &state);
|
||||
if(result == ERROR_SUCCESS) {
|
||||
//valid controller detected, add to gamepad list
|
||||
unsigned n = lgamepad.size();
|
||||
lgamepad[n].id = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
static BOOL CALLBACK DirectInput_EnumJoypadsCallback(const DIDEVICEINSTANCE*, void*);
|
||||
static BOOL CALLBACK DirectInput_EnumJoypadAxesCallback(const DIDEVICEOBJECTINSTANCE*, void*);
|
||||
|
||||
class DirectInput {
|
||||
public:
|
||||
HWND handle;
|
||||
LPDIRECTINPUT8 context;
|
||||
struct Gamepad {
|
||||
LPDIRECTINPUTDEVICE8 handle;
|
||||
|
||||
int16_t hat[4];
|
||||
int16_t axis[6];
|
||||
bool button[128];
|
||||
|
||||
void poll(DIJOYSTATE2 &state) {
|
||||
//POV hats
|
||||
for(unsigned n = 0; n < 4; n++) {
|
||||
hat[n] = joypad<>::hat_center;
|
||||
|
||||
//POV value is in clockwise-hundredth degree units
|
||||
unsigned pov = state.rgdwPOV[n];
|
||||
|
||||
//some drivers report a centered POV hat as -1U, others as 65535U.
|
||||
//>= 36000 will match both, as well as invalid ranges.
|
||||
if(pov >= 36000) continue;
|
||||
|
||||
if(pov >= 31500 || pov <= 4500) hat[n] |= joypad<>::hat_up;
|
||||
if(pov >= 4500 && pov <= 13500) hat[n] |= joypad<>::hat_right;
|
||||
if(pov >= 13500 && pov <= 22500) hat[n] |= joypad<>::hat_down;
|
||||
if(pov >= 22500 && pov <= 31500) hat[n] |= joypad<>::hat_left;
|
||||
}
|
||||
|
||||
//axes
|
||||
axis[0] = state.lX;
|
||||
axis[1] = state.lY;
|
||||
axis[2] = state.lZ;
|
||||
axis[3] = state.lRx;
|
||||
axis[4] = state.lRy;
|
||||
axis[5] = state.lRz;
|
||||
|
||||
//buttons
|
||||
for(unsigned n = 0; n < 128; n++) {
|
||||
button[n] = (bool)state.rgbButtons[n];
|
||||
}
|
||||
}
|
||||
|
||||
Gamepad() {
|
||||
handle = 0;
|
||||
for(unsigned n = 0; n < 4; n++) hat[n] = joypad<>::hat_center;
|
||||
for(unsigned n = 0; n < 6; n++) axis[n] = 0;
|
||||
for(unsigned n = 0; n < 128; n++) button[n] = false;
|
||||
}
|
||||
};
|
||||
vector<Gamepad> lgamepad;
|
||||
|
||||
void poll() {
|
||||
for(unsigned i = 0; i < lgamepad.size(); i++) {
|
||||
if(FAILED(lgamepad[i].handle->Poll())) {
|
||||
lgamepad[i].handle->Acquire();
|
||||
continue;
|
||||
}
|
||||
|
||||
DIJOYSTATE2 state;
|
||||
lgamepad[i].handle->GetDeviceState(sizeof(DIJOYSTATE2), &state);
|
||||
lgamepad[i].poll(state);
|
||||
}
|
||||
}
|
||||
|
||||
bool init_joypad(const DIDEVICEINSTANCE *instance) {
|
||||
//if this is an XInput device, do not acquire it via DirectInput ...
|
||||
//the XInput driver above will handle said device.
|
||||
for(unsigned i = 0; i < rawinput.lgamepad.size(); i++) {
|
||||
uint32_t guid = MAKELONG(rawinput.lgamepad[i].vendorId, rawinput.lgamepad[i].productId);
|
||||
if(guid == instance->guidProduct.Data1) {
|
||||
if(rawinput.lgamepad[i].isXInputDevice == true) {
|
||||
return DIENUM_CONTINUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(FAILED(context->CreateDevice(instance->guidInstance, &device, 0))) {
|
||||
return DIENUM_CONTINUE;
|
||||
}
|
||||
|
||||
device->SetDataFormat(&c_dfDIJoystick2);
|
||||
device->SetCooperativeLevel(handle, DISCL_NONEXCLUSIVE | DISCL_BACKGROUND);
|
||||
device->EnumObjects(DirectInput_EnumJoypadAxesCallback, (void*)this, DIDFT_ABSAXIS);
|
||||
unsigned n = lgamepad.size();
|
||||
lgamepad[n].handle = device;
|
||||
return DIENUM_CONTINUE;
|
||||
}
|
||||
|
||||
bool init_axis(const DIDEVICEOBJECTINSTANCE *instance) {
|
||||
DIPROPRANGE range;
|
||||
range.diph.dwSize = sizeof(DIPROPRANGE);
|
||||
range.diph.dwHeaderSize = sizeof(DIPROPHEADER);
|
||||
range.diph.dwHow = DIPH_BYID;
|
||||
range.diph.dwObj = instance->dwType;
|
||||
range.lMin = -32768;
|
||||
range.lMax = +32767;
|
||||
device->SetProperty(DIPROP_RANGE, &range.diph);
|
||||
return DIENUM_CONTINUE;
|
||||
}
|
||||
|
||||
void init(HWND handle_) {
|
||||
handle = handle_;
|
||||
DirectInput8Create(GetModuleHandle(0), DIRECTINPUT_VERSION, IID_IDirectInput8, (void**)&context, 0);
|
||||
context->EnumDevices(DI8DEVCLASS_GAMECTRL, DirectInput_EnumJoypadsCallback, (void*)this, DIEDFL_ATTACHEDONLY);
|
||||
}
|
||||
|
||||
void term() {
|
||||
for(unsigned i = 0; i < lgamepad.size(); i++) {
|
||||
lgamepad[i].handle->Unacquire();
|
||||
lgamepad[i].handle->Release();
|
||||
}
|
||||
lgamepad.reset();
|
||||
|
||||
if(context) {
|
||||
context->Release();
|
||||
context = 0;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
LPDIRECTINPUTDEVICE8 device;
|
||||
};
|
||||
|
||||
BOOL CALLBACK DirectInput_EnumJoypadsCallback(const DIDEVICEINSTANCE *instance, void *p) {
|
||||
return ((DirectInput*)p)->init_joypad(instance);
|
||||
}
|
||||
|
||||
BOOL CALLBACK DirectInput_EnumJoypadAxesCallback(const DIDEVICEOBJECTINSTANCE *instance, void *p) {
|
||||
return ((DirectInput*)p)->init_axis(instance);
|
||||
}
|
||||
|
||||
class pInputRaw {
|
||||
public:
|
||||
InputRaw &self;
|
||||
XInput xinput;
|
||||
DirectInput dinput;
|
||||
|
||||
bool acquire_mouse;
|
||||
bool cursor_visible;
|
||||
|
||||
struct {
|
||||
HWND handle;
|
||||
} settings;
|
||||
|
||||
bool cap(Input::Setting setting) {
|
||||
if(setting == Input::Handle) return true;
|
||||
if(setting == Input::KeyboardSupport) return true;
|
||||
if(setting == Input::MouseSupport) return true;
|
||||
if(setting == Input::JoypadSupport) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
uintptr_t get(Input::Setting setting) {
|
||||
if(setting == Input::Handle) return (uintptr_t)settings.handle;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool set(Input::Setting setting, uintptr_t param) {
|
||||
if(setting == Input::Handle) {
|
||||
settings.handle = (HWND)param;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool acquire() {
|
||||
acquire_mouse = true;
|
||||
if(cursor_visible == true) {
|
||||
ShowCursor(cursor_visible = false);
|
||||
}
|
||||
return acquired();
|
||||
}
|
||||
|
||||
bool unacquire() {
|
||||
acquire_mouse = false;
|
||||
ReleaseCapture();
|
||||
ClipCursor(NULL);
|
||||
if(cursor_visible == false) {
|
||||
ShowCursor(cursor_visible = true);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool acquired() {
|
||||
if(acquire_mouse == true) {
|
||||
SetFocus(settings.handle);
|
||||
SetCapture(settings.handle);
|
||||
RECT rc;
|
||||
GetWindowRect(settings.handle, &rc);
|
||||
ClipCursor(&rc);
|
||||
}
|
||||
return GetCapture() == settings.handle;
|
||||
}
|
||||
|
||||
bool poll(int16_t *table) {
|
||||
memset(table, 0, nall::input_limit * sizeof(int16_t));
|
||||
|
||||
WaitForSingleObject(rawinput.mutex, INFINITE);
|
||||
|
||||
//=========
|
||||
//Keyboards
|
||||
//=========
|
||||
for(unsigned i = 0; i < min(rawinput.lkeyboard.size(), (unsigned)keyboard<>::count); i++) {
|
||||
unsigned index = keyboard<>::index(i, keyboard<>::none);
|
||||
|
||||
for(unsigned n = 0; n < keyboard<>::length; n++) {
|
||||
table[index + n] = rawinput.lkeyboard[i].state[n];
|
||||
}
|
||||
}
|
||||
|
||||
//====
|
||||
//Mice
|
||||
//====
|
||||
for(unsigned i = 0; i < min(rawinput.lmouse.size(), (unsigned)mouse<>::count); i++) {
|
||||
unsigned index = mouse<>::index(i, mouse<>::none);
|
||||
|
||||
table[index + mouse<>::x] = rawinput.lmouse[i].xDistance;
|
||||
table[index + mouse<>::y] = rawinput.lmouse[i].yDistance;
|
||||
table[index + mouse<>::z] = rawinput.lmouse[i].zDistance;
|
||||
|
||||
for(unsigned n = 0; n < min(5U, (unsigned)mouse<>::buttons); n++) {
|
||||
table[index + mouse<>::button + n] = (bool)(rawinput.lmouse[i].buttonState & (1 << n));
|
||||
}
|
||||
|
||||
rawinput.lmouse[i].sync();
|
||||
}
|
||||
|
||||
ReleaseMutex(rawinput.mutex);
|
||||
|
||||
unsigned joy = 0;
|
||||
|
||||
//==================
|
||||
//XInput controllers
|
||||
//==================
|
||||
xinput.poll();
|
||||
for(unsigned i = 0; i < xinput.lgamepad.size(); i++) {
|
||||
if(joy >= joypad<>::count) break;
|
||||
unsigned index = joypad<>::index(joy++, joypad<>::none);
|
||||
|
||||
table[index + joypad<>::hat + 0] = xinput.lgamepad[i].hat;
|
||||
|
||||
for(unsigned axis = 0; axis < min(6U, (unsigned)joypad<>::axes); axis++) {
|
||||
table[index + joypad<>::axis + axis] = xinput.lgamepad[i].axis[axis];
|
||||
}
|
||||
|
||||
for(unsigned button = 0; button < min(10U, (unsigned)joypad<>::buttons); button++) {
|
||||
table[index + joypad<>::button + button] = xinput.lgamepad[i].button[button];
|
||||
}
|
||||
}
|
||||
|
||||
//=======================
|
||||
//DirectInput controllers
|
||||
//=======================
|
||||
dinput.poll();
|
||||
for(unsigned i = 0; i < dinput.lgamepad.size(); i++) {
|
||||
if(joy >= joypad<>::count) break;
|
||||
unsigned index = joypad<>::index(joy++, joypad<>::none);
|
||||
|
||||
for(unsigned hat = 0; hat < min(4U, (unsigned)joypad<>::hats); hat++) {
|
||||
table[index + joypad<>::hat + hat] = dinput.lgamepad[i].hat[hat];
|
||||
}
|
||||
|
||||
for(unsigned axis = 0; axis < min(6U, (unsigned)joypad<>::axes); axis++) {
|
||||
table[index + joypad<>::axis + axis] = dinput.lgamepad[i].axis[axis];
|
||||
}
|
||||
|
||||
for(unsigned button = 0; button < min(128U, (unsigned)joypad<>::buttons); button++) {
|
||||
table[index + joypad<>::button + button] = dinput.lgamepad[i].button[button];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool init() {
|
||||
//only spawn RawInput processing thread one time
|
||||
if(rawinput.initialized == false) {
|
||||
rawinput.initialized = true;
|
||||
rawinput.mutex = CreateMutex(NULL, FALSE, NULL);
|
||||
CreateThread(NULL, 0, RawInputThreadProc, 0, 0, NULL);
|
||||
|
||||
//RawInput device calibration needs to finish before initializing DirectInput;
|
||||
//as it needs device GUIDs to distinguish XInput devices from ordinary joypads.
|
||||
bool ready = false;
|
||||
do {
|
||||
Sleep(10);
|
||||
WaitForSingleObject(rawinput.mutex, INFINITE);
|
||||
ready = rawinput.ready;
|
||||
ReleaseMutex(rawinput.mutex);
|
||||
} while(ready == false);
|
||||
}
|
||||
|
||||
xinput.init();
|
||||
dinput.init(settings.handle);
|
||||
|
||||
acquire_mouse = false;
|
||||
cursor_visible = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
void term() {
|
||||
unacquire();
|
||||
dinput.term();
|
||||
}
|
||||
|
||||
pInputRaw(InputRaw &self_) : self(self_) {
|
||||
}
|
||||
};
|
||||
|
||||
bool InputRaw::cap(Setting setting) { return p.cap(setting); }
|
||||
uintptr_t InputRaw::get(Setting setting) { return p.get(setting); }
|
||||
bool InputRaw::set(Setting setting, uintptr_t param) { return p.set(setting, param); }
|
||||
bool InputRaw::acquire() { return p.acquire(); }
|
||||
bool InputRaw::unacquire() { return p.unacquire(); }
|
||||
bool InputRaw::acquired() { return p.acquired(); }
|
||||
bool InputRaw::poll(int16_t *table) { return p.poll(table); }
|
||||
bool InputRaw::init() { return p.init(); }
|
||||
void InputRaw::term() { p.term(); }
|
||||
InputRaw::InputRaw() : p(*new pInputRaw(*this)) {}
|
||||
InputRaw::~InputRaw() { delete &p; }
|
||||
|
||||
}
|
||||
22
tools/bsnes/lib/ruby/input/rawinput.hpp
Executable file
22
tools/bsnes/lib/ruby/input/rawinput.hpp
Executable file
@@ -0,0 +1,22 @@
|
||||
class pInputRaw;
|
||||
|
||||
class InputRaw : public Input {
|
||||
public:
|
||||
bool cap(Setting);
|
||||
uintptr_t get(Setting);
|
||||
bool set(Setting, uintptr_t);
|
||||
|
||||
bool acquire();
|
||||
bool unacquire();
|
||||
bool acquired();
|
||||
|
||||
bool poll(int16_t *table);
|
||||
bool init();
|
||||
void term();
|
||||
|
||||
InputRaw();
|
||||
~InputRaw();
|
||||
|
||||
private:
|
||||
pInputRaw &p;
|
||||
};
|
||||
254
tools/bsnes/lib/ruby/input/sdl.cpp
Executable file
254
tools/bsnes/lib/ruby/input/sdl.cpp
Executable file
@@ -0,0 +1,254 @@
|
||||
//================
|
||||
//SDL input driver
|
||||
//================
|
||||
//Keyboard and mouse are controlled directly via Xlib,
|
||||
//as SDL cannot capture input from windows it does not create itself.
|
||||
//SDL is used only to handle joysticks / gamepads.
|
||||
|
||||
#include <SDL/SDL.h>
|
||||
#include <sys/ipc.h>
|
||||
#include <sys/shm.h>
|
||||
#include <X11/Xlib.h>
|
||||
#include <X11/Xutil.h>
|
||||
#include <X11/Xatom.h>
|
||||
|
||||
namespace ruby {
|
||||
|
||||
#include "sdl.hpp"
|
||||
|
||||
struct pInputSDL {
|
||||
#include "xlibkeys.hpp"
|
||||
InputSDL &self;
|
||||
|
||||
struct {
|
||||
Display *display;
|
||||
Window rootwindow;
|
||||
Cursor InvisibleCursor;
|
||||
SDL_Joystick *gamepad[joypad<>::count];
|
||||
|
||||
unsigned screenwidth, screenheight;
|
||||
unsigned relativex, relativey;
|
||||
bool mouseacquired;
|
||||
|
||||
//mouse device settings
|
||||
int accel_numerator;
|
||||
int accel_denominator;
|
||||
int threshold;
|
||||
} device;
|
||||
|
||||
struct {
|
||||
uintptr_t handle;
|
||||
} settings;
|
||||
|
||||
bool cap(Input::Setting setting) {
|
||||
if(setting == Input::Handle) return true;
|
||||
if(setting == Input::KeyboardSupport) return true;
|
||||
if(setting == Input::MouseSupport) return true;
|
||||
if(setting == Input::JoypadSupport) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
uintptr_t get(Input::Setting setting) {
|
||||
if(setting == Input::Handle) return settings.handle;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool set(Input::Setting setting, uintptr_t param) {
|
||||
if(setting == Input::Handle) {
|
||||
settings.handle = param;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool acquire() {
|
||||
if(acquired()) return true;
|
||||
|
||||
if(XGrabPointer(device.display, settings.handle, True, 0, GrabModeAsync, GrabModeAsync,
|
||||
device.rootwindow, device.InvisibleCursor, CurrentTime) == GrabSuccess) {
|
||||
//backup existing cursor acceleration settings
|
||||
XGetPointerControl(device.display, &device.accel_numerator, &device.accel_denominator, &device.threshold);
|
||||
|
||||
//disable cursor acceleration
|
||||
XChangePointerControl(device.display, True, False, 1, 1, 0);
|
||||
|
||||
//center cursor (so that first relative poll returns 0, 0 if mouse has not moved)
|
||||
XWarpPointer(device.display, None, device.rootwindow, 0, 0, 0, 0, device.screenwidth / 2, device.screenheight / 2);
|
||||
|
||||
return device.mouseacquired = true;
|
||||
} else {
|
||||
return device.mouseacquired = false;
|
||||
}
|
||||
}
|
||||
|
||||
bool unacquire() {
|
||||
if(acquired()) {
|
||||
//restore cursor acceleration and release cursor
|
||||
XChangePointerControl(device.display, True, True, device.accel_numerator, device.accel_denominator, device.threshold);
|
||||
XUngrabPointer(device.display, CurrentTime);
|
||||
device.mouseacquired = false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool acquired() {
|
||||
return device.mouseacquired;
|
||||
}
|
||||
|
||||
bool poll(int16_t *table) {
|
||||
memset(table, 0, nall::input_limit * sizeof(int16_t));
|
||||
|
||||
//========
|
||||
//Keyboard
|
||||
//========
|
||||
|
||||
char state[32];
|
||||
XQueryKeymap(device.display, state);
|
||||
|
||||
for(unsigned i = 0; i < keyboard<>::length; i++) {
|
||||
uint8_t code = keycode[i];
|
||||
if(code == 0) continue; //unmapped
|
||||
table[i] = (bool)(state[code >> 3] & (1 << (code & 7)));
|
||||
}
|
||||
|
||||
//=====
|
||||
//Mouse
|
||||
//=====
|
||||
|
||||
Window root_return, child_return;
|
||||
int root_x_return = 0, root_y_return = 0;
|
||||
int win_x_return = 0, win_y_return = 0;
|
||||
unsigned int mask_return = 0;
|
||||
XQueryPointer(device.display, settings.handle,
|
||||
&root_return, &child_return, &root_x_return, &root_y_return,
|
||||
&win_x_return, &win_y_return, &mask_return);
|
||||
|
||||
if(acquired()) {
|
||||
XWindowAttributes attributes;
|
||||
XGetWindowAttributes(device.display, settings.handle, &attributes);
|
||||
|
||||
//absolute -> relative conversion
|
||||
table[mouse<0>::x] = (int16_t)(root_x_return - device.screenwidth / 2);
|
||||
table[mouse<0>::y] = (int16_t)(root_y_return - device.screenheight / 2);
|
||||
|
||||
if(table[mouse<0>::x] != 0 || table[mouse<0>::y] != 0) {
|
||||
//if mouse movement occurred, re-center mouse for next poll
|
||||
XWarpPointer(device.display, None, device.rootwindow, 0, 0, 0, 0, device.screenwidth / 2, device.screenheight / 2);
|
||||
}
|
||||
} else {
|
||||
table[mouse<0>::x] = (int16_t)(root_x_return - device.relativex);
|
||||
table[mouse<0>::y] = (int16_t)(root_y_return - device.relativey);
|
||||
|
||||
device.relativex = root_x_return;
|
||||
device.relativey = root_y_return;
|
||||
}
|
||||
|
||||
//manual device polling is limited to only five buttons ...
|
||||
table[mouse<0>::button + 0] = (bool)(mask_return & Button1Mask);
|
||||
table[mouse<0>::button + 1] = (bool)(mask_return & Button2Mask);
|
||||
table[mouse<0>::button + 2] = (bool)(mask_return & Button3Mask);
|
||||
table[mouse<0>::button + 3] = (bool)(mask_return & Button4Mask);
|
||||
table[mouse<0>::button + 4] = (bool)(mask_return & Button5Mask);
|
||||
|
||||
//=========
|
||||
//Joypad(s)
|
||||
//=========
|
||||
|
||||
SDL_JoystickUpdate();
|
||||
for(unsigned i = 0; i < joypad<>::count; i++) {
|
||||
if(!device.gamepad[i]) continue;
|
||||
unsigned index = joypad<>::index(i, joypad<>::none);
|
||||
|
||||
//POV hats
|
||||
unsigned hats = min((unsigned)joypad<>::hats, SDL_JoystickNumHats(device.gamepad[i]));
|
||||
for(unsigned hat = 0; hat < hats; hat++) {
|
||||
uint8_t state = SDL_JoystickGetHat(device.gamepad[i], hat);
|
||||
if(state & SDL_HAT_UP ) table[index + joypad<>::hat + hat] |= joypad<>::hat_up;
|
||||
if(state & SDL_HAT_RIGHT) table[index + joypad<>::hat + hat] |= joypad<>::hat_right;
|
||||
if(state & SDL_HAT_DOWN ) table[index + joypad<>::hat + hat] |= joypad<>::hat_down;
|
||||
if(state & SDL_HAT_LEFT ) table[index + joypad<>::hat + hat] |= joypad<>::hat_left;
|
||||
}
|
||||
|
||||
//axes
|
||||
unsigned axes = min((unsigned)joypad<>::axes, SDL_JoystickNumAxes(device.gamepad[i]));
|
||||
for(unsigned axis = 0; axis < axes; axis++) {
|
||||
table[index + joypad<>::axis + axis] = (int16_t)SDL_JoystickGetAxis(device.gamepad[i], axis);
|
||||
}
|
||||
|
||||
//buttons
|
||||
for(unsigned button = 0; button < joypad<>::buttons; button++) {
|
||||
table[index + joypad<>::button + button] = (bool)SDL_JoystickGetButton(device.gamepad[i], button);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool init() {
|
||||
init_keycodes();
|
||||
SDL_InitSubSystem(SDL_INIT_JOYSTICK);
|
||||
SDL_JoystickEventState(SDL_IGNORE);
|
||||
|
||||
device.display = XOpenDisplay(0);
|
||||
device.rootwindow = DefaultRootWindow(device.display);
|
||||
XWindowAttributes attributes;
|
||||
XGetWindowAttributes(device.display, device.rootwindow, &attributes);
|
||||
device.screenwidth = attributes.width;
|
||||
device.screenheight = attributes.height;
|
||||
|
||||
//Xlib: "because XShowCursor(false) would be too easy."
|
||||
//create a fully transparent cursor named InvisibleCursor,
|
||||
//for use while acquire() / XGrabPointer() is active.
|
||||
Pixmap pixmap;
|
||||
XColor black, unused;
|
||||
static char invisible_data[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
|
||||
Colormap colormap = DefaultColormap(device.display, DefaultScreen(device.display));
|
||||
XAllocNamedColor(device.display, colormap, "black", &black, &unused);
|
||||
pixmap = XCreateBitmapFromData(device.display, settings.handle, invisible_data, 8, 8);
|
||||
device.InvisibleCursor = XCreatePixmapCursor(device.display, pixmap, pixmap, &black, &black, 0, 0);
|
||||
XFreePixmap(device.display, pixmap);
|
||||
XFreeColors(device.display, colormap, &black.pixel, 1, 0);
|
||||
|
||||
device.mouseacquired = false;
|
||||
device.relativex = 0;
|
||||
device.relativey = 0;
|
||||
|
||||
unsigned joypads = min((unsigned)joypad<>::count, SDL_NumJoysticks());
|
||||
for(unsigned i = 0; i < joypads; i++) device.gamepad[i] = SDL_JoystickOpen(i);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void term() {
|
||||
unacquire();
|
||||
XFreeCursor(device.display, device.InvisibleCursor);
|
||||
|
||||
for(unsigned i = 0; i < joypad<>::count; i++) {
|
||||
if(device.gamepad[i]) SDL_JoystickClose(device.gamepad[i]);
|
||||
device.gamepad[i] = 0;
|
||||
}
|
||||
|
||||
SDL_QuitSubSystem(SDL_INIT_JOYSTICK);
|
||||
}
|
||||
|
||||
pInputSDL(InputSDL &self_) : self(self_) {
|
||||
for(unsigned i = 0; i < joypad<>::count; i++) device.gamepad[i] = 0;
|
||||
settings.handle = 0;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
bool InputSDL::cap(Setting setting) { return p.cap(setting); }
|
||||
uintptr_t InputSDL::get(Setting setting) { return p.get(setting); }
|
||||
bool InputSDL::set(Setting setting, uintptr_t param) { return p.set(setting, param); }
|
||||
bool InputSDL::acquire() { return p.acquire(); }
|
||||
bool InputSDL::unacquire() { return p.unacquire(); }
|
||||
bool InputSDL::acquired() { return p.acquired(); }
|
||||
bool InputSDL::poll(int16_t *table) { return p.poll(table); }
|
||||
bool InputSDL::init() { return p.init(); }
|
||||
void InputSDL::term() { p.term(); }
|
||||
InputSDL::InputSDL() : p(*new pInputSDL(*this)) {}
|
||||
InputSDL::~InputSDL() { delete &p; }
|
||||
|
||||
}
|
||||
22
tools/bsnes/lib/ruby/input/sdl.hpp
Executable file
22
tools/bsnes/lib/ruby/input/sdl.hpp
Executable file
@@ -0,0 +1,22 @@
|
||||
class pInputSDL;
|
||||
|
||||
class InputSDL : public Input {
|
||||
public:
|
||||
bool cap(Setting);
|
||||
uintptr_t get(Setting);
|
||||
bool set(Setting, uintptr_t);
|
||||
|
||||
bool acquire();
|
||||
bool unacquire();
|
||||
bool acquired();
|
||||
|
||||
bool poll(int16_t *table);
|
||||
bool init();
|
||||
void term();
|
||||
|
||||
InputSDL();
|
||||
~InputSDL();
|
||||
|
||||
private:
|
||||
pInputSDL &p;
|
||||
};
|
||||
66
tools/bsnes/lib/ruby/input/x.cpp
Executable file
66
tools/bsnes/lib/ruby/input/x.cpp
Executable file
@@ -0,0 +1,66 @@
|
||||
#include <sys/ipc.h>
|
||||
#include <sys/shm.h>
|
||||
#include <X11/Xlib.h>
|
||||
#include <X11/Xutil.h>
|
||||
#include <X11/Xatom.h>
|
||||
|
||||
namespace ruby {
|
||||
|
||||
#include "x.hpp"
|
||||
|
||||
class pInputX {
|
||||
public:
|
||||
InputX &self;
|
||||
Display *display;
|
||||
#include "xlibkeys.hpp"
|
||||
|
||||
bool cap(Input::Setting setting) {
|
||||
if(setting == Input::KeyboardSupport) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
uintptr_t get(Input::Setting setting) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool set(Input::Setting setting, uintptr_t param) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool poll(int16_t *table) {
|
||||
memset(table, 0, input_limit * sizeof(int16_t));
|
||||
|
||||
char state[32];
|
||||
XQueryKeymap(display, state);
|
||||
|
||||
for(unsigned i = 0; i < keyboard<>::length; i++) {
|
||||
uint8_t code = keycode[i];
|
||||
if(code == 0) continue; //unmapped
|
||||
table[i] = (bool)(state[code >> 3] & (1 << (code & 7)));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool init() {
|
||||
init_keycodes();
|
||||
display = XOpenDisplay(0);
|
||||
return true;
|
||||
}
|
||||
|
||||
void term() {
|
||||
}
|
||||
|
||||
pInputX(InputX &self_) : self(self_) {}
|
||||
};
|
||||
|
||||
bool InputX::cap(Setting setting) { return p.cap(setting); }
|
||||
uintptr_t InputX::get(Setting setting) { return p.get(setting); }
|
||||
bool InputX::set(Setting setting, uintptr_t param) { return p.set(setting, param); }
|
||||
bool InputX::poll(int16_t *table) { return p.poll(table); }
|
||||
bool InputX::init() { return p.init(); }
|
||||
void InputX::term() { p.term(); }
|
||||
InputX::InputX() : p(*new pInputX(*this)) {}
|
||||
InputX::~InputX() { delete &p; }
|
||||
|
||||
} //namespace ruby
|
||||
18
tools/bsnes/lib/ruby/input/x.hpp
Executable file
18
tools/bsnes/lib/ruby/input/x.hpp
Executable file
@@ -0,0 +1,18 @@
|
||||
class pInputX;
|
||||
|
||||
class InputX : public Input {
|
||||
public:
|
||||
bool cap(Setting);
|
||||
uintptr_t get(Setting);
|
||||
bool set(Setting, uintptr_t);
|
||||
|
||||
bool poll(int16_t *table);
|
||||
bool init();
|
||||
void term();
|
||||
|
||||
InputX();
|
||||
~InputX();
|
||||
|
||||
private:
|
||||
pInputX &p;
|
||||
};
|
||||
138
tools/bsnes/lib/ruby/input/xlibkeys.hpp
Executable file
138
tools/bsnes/lib/ruby/input/xlibkeys.hpp
Executable file
@@ -0,0 +1,138 @@
|
||||
//shared keycode lookup table + initialization routine:
|
||||
//#include inside a class interface to use
|
||||
|
||||
//Xlib keycodes for each key can vary between platforms, so this header file
|
||||
//will lookup keycodes from static keysyms, and map them to nall/input.hpp's
|
||||
//keyboard identifiers.
|
||||
//
|
||||
//this allows input capture routine to iterate quickly over all keycodes and
|
||||
//map their states to ruby's input state table.
|
||||
|
||||
uint8_t keycode[256];
|
||||
|
||||
bool init_keycodes() {
|
||||
Display *display = XOpenDisplay(0);
|
||||
memset(&keycode, 0, sizeof keycode);
|
||||
|
||||
#define assign(x, y) keycode[x] = XKeysymToKeycode(display, y)
|
||||
assign(keyboard<0>::escape, XK_Escape);
|
||||
|
||||
assign(keyboard<0>::f1, XK_F1);
|
||||
assign(keyboard<0>::f2, XK_F2);
|
||||
assign(keyboard<0>::f3, XK_F3);
|
||||
assign(keyboard<0>::f4, XK_F4);
|
||||
assign(keyboard<0>::f5, XK_F5);
|
||||
assign(keyboard<0>::f6, XK_F6);
|
||||
assign(keyboard<0>::f7, XK_F7);
|
||||
assign(keyboard<0>::f8, XK_F8);
|
||||
assign(keyboard<0>::f9, XK_F9);
|
||||
assign(keyboard<0>::f10, XK_F10);
|
||||
assign(keyboard<0>::f11, XK_F11);
|
||||
assign(keyboard<0>::f12, XK_F12);
|
||||
|
||||
//assign(keyboard<0>::print_screen, XK_???);
|
||||
assign(keyboard<0>::scroll_lock, XK_Scroll_Lock);
|
||||
assign(keyboard<0>::pause, XK_Pause);
|
||||
|
||||
assign(keyboard<0>::tilde, XK_asciitilde);
|
||||
|
||||
assign(keyboard<0>::num_0, XK_0);
|
||||
assign(keyboard<0>::num_1, XK_1);
|
||||
assign(keyboard<0>::num_2, XK_2);
|
||||
assign(keyboard<0>::num_3, XK_3);
|
||||
assign(keyboard<0>::num_4, XK_4);
|
||||
assign(keyboard<0>::num_5, XK_5);
|
||||
assign(keyboard<0>::num_6, XK_6);
|
||||
assign(keyboard<0>::num_7, XK_7);
|
||||
assign(keyboard<0>::num_8, XK_8);
|
||||
assign(keyboard<0>::num_9, XK_9);
|
||||
|
||||
assign(keyboard<0>::dash, XK_minus);
|
||||
assign(keyboard<0>::equal, XK_equal);
|
||||
assign(keyboard<0>::backspace, XK_BackSpace);
|
||||
|
||||
assign(keyboard<0>::insert, XK_Insert);
|
||||
assign(keyboard<0>::delete_, XK_Delete);
|
||||
assign(keyboard<0>::home, XK_Home);
|
||||
assign(keyboard<0>::end, XK_End);
|
||||
assign(keyboard<0>::page_up, XK_Prior);
|
||||
assign(keyboard<0>::page_down, XK_Next);
|
||||
|
||||
assign(keyboard<0>::a, XK_A);
|
||||
assign(keyboard<0>::b, XK_B);
|
||||
assign(keyboard<0>::c, XK_C);
|
||||
assign(keyboard<0>::d, XK_D);
|
||||
assign(keyboard<0>::e, XK_E);
|
||||
assign(keyboard<0>::f, XK_F);
|
||||
assign(keyboard<0>::g, XK_G);
|
||||
assign(keyboard<0>::h, XK_H);
|
||||
assign(keyboard<0>::i, XK_I);
|
||||
assign(keyboard<0>::j, XK_J);
|
||||
assign(keyboard<0>::k, XK_K);
|
||||
assign(keyboard<0>::l, XK_L);
|
||||
assign(keyboard<0>::m, XK_M);
|
||||
assign(keyboard<0>::n, XK_N);
|
||||
assign(keyboard<0>::o, XK_O);
|
||||
assign(keyboard<0>::p, XK_P);
|
||||
assign(keyboard<0>::q, XK_Q);
|
||||
assign(keyboard<0>::r, XK_R);
|
||||
assign(keyboard<0>::s, XK_S);
|
||||
assign(keyboard<0>::t, XK_T);
|
||||
assign(keyboard<0>::u, XK_U);
|
||||
assign(keyboard<0>::v, XK_V);
|
||||
assign(keyboard<0>::w, XK_W);
|
||||
assign(keyboard<0>::x, XK_X);
|
||||
assign(keyboard<0>::y, XK_Y);
|
||||
assign(keyboard<0>::z, XK_Z);
|
||||
|
||||
assign(keyboard<0>::lbracket, XK_bracketleft);
|
||||
assign(keyboard<0>::rbracket, XK_bracketright);
|
||||
assign(keyboard<0>::backslash, XK_backslash);
|
||||
assign(keyboard<0>::semicolon, XK_semicolon);
|
||||
assign(keyboard<0>::apostrophe, XK_apostrophe);
|
||||
assign(keyboard<0>::comma, XK_comma);
|
||||
assign(keyboard<0>::period, XK_period);
|
||||
assign(keyboard<0>::slash, XK_slash);
|
||||
|
||||
assign(keyboard<0>::pad_0, XK_KP_0);
|
||||
assign(keyboard<0>::pad_1, XK_KP_1);
|
||||
assign(keyboard<0>::pad_2, XK_KP_2);
|
||||
assign(keyboard<0>::pad_3, XK_KP_3);
|
||||
assign(keyboard<0>::pad_4, XK_KP_4);
|
||||
assign(keyboard<0>::pad_5, XK_KP_5);
|
||||
assign(keyboard<0>::pad_6, XK_KP_6);
|
||||
assign(keyboard<0>::pad_7, XK_KP_7);
|
||||
assign(keyboard<0>::pad_8, XK_KP_8);
|
||||
assign(keyboard<0>::pad_9, XK_KP_9);
|
||||
|
||||
assign(keyboard<0>::add, XK_KP_Add);
|
||||
assign(keyboard<0>::subtract, XK_KP_Subtract);
|
||||
assign(keyboard<0>::multiply, XK_KP_Multiply);
|
||||
assign(keyboard<0>::divide, XK_KP_Divide);
|
||||
assign(keyboard<0>::enter, XK_KP_Enter);
|
||||
|
||||
//assign(keyboard<0>::num_lock, XK_???);
|
||||
//assign(keyboard<0>::caps_lock, XK_???);
|
||||
|
||||
assign(keyboard<0>::up, XK_Up);
|
||||
assign(keyboard<0>::down, XK_Down);
|
||||
assign(keyboard<0>::left, XK_Left);
|
||||
assign(keyboard<0>::right, XK_Right);
|
||||
|
||||
assign(keyboard<0>::tab, XK_Tab);
|
||||
assign(keyboard<0>::return_, XK_Return);
|
||||
assign(keyboard<0>::spacebar, XK_space);
|
||||
|
||||
assign(keyboard<0>::lctrl, XK_Control_L);
|
||||
assign(keyboard<0>::rctrl, XK_Control_R);
|
||||
assign(keyboard<0>::lalt, XK_Alt_L);
|
||||
assign(keyboard<0>::ralt, XK_Alt_R);
|
||||
assign(keyboard<0>::lshift, XK_Shift_L);
|
||||
assign(keyboard<0>::rshift, XK_Shift_R);
|
||||
assign(keyboard<0>::lsuper, XK_Super_L);
|
||||
assign(keyboard<0>::rsuper, XK_Super_R);
|
||||
assign(keyboard<0>::menu, XK_Menu);
|
||||
#undef assign
|
||||
|
||||
XCloseDisplay(display);
|
||||
}
|
||||
Reference in New Issue
Block a user