First version split into asnes and bsnes.

This commit is contained in:
Tim Allen
2010-08-09 23:28:56 +10:00
commit 165f1e74b5
698 changed files with 145483 additions and 0 deletions

157
ruby/input/carbon.cpp Executable file
View File

@@ -0,0 +1,157 @@
namespace ruby {
class pInputCarbon {
public:
bool cap(const string& name) {
return false;
}
any get(const string& name) {
return false;
}
bool set(const string& name, const any& value) {
return false;
}
bool acquire() { return false; }
bool unacquire() { return false; }
bool acquired() { return false; }
bool poll(int16_t *table) {
memset(table, 0, Scancode::Limit * sizeof(int16_t));
KeyMap keys;
GetKeys(keys);
uint8_t *keymap = (uint8_t*)keys;
#define map(id, name) table[keyboard(0)[name]] = (bool)(keymap[id >> 3] & (1 << (id & 7)))
map(0x35, Keyboard::Escape);
map(0x7a, Keyboard::F1);
map(0x78, Keyboard::F2);
map(0x63, Keyboard::F3);
map(0x76, Keyboard::F4);
map(0x60, Keyboard::F5);
map(0x61, Keyboard::F6);
map(0x62, Keyboard::F7);
map(0x64, Keyboard::F8);
map(0x65, Keyboard::F9);
map(0x6d, Keyboard::F10);
map(0x67, Keyboard::F11);
//map(0x??, Keyboard::F12);
map(0x69, Keyboard::PrintScreen);
//map(0x??, Keyboard::ScrollLock);
map(0x71, Keyboard::Pause);
map(0x32, Keyboard::Tilde);
map(0x12, Keyboard::Num1);
map(0x13, Keyboard::Num2);
map(0x14, Keyboard::Num3);
map(0x15, Keyboard::Num4);
map(0x17, Keyboard::Num5);
map(0x16, Keyboard::Num6);
map(0x1a, Keyboard::Num7);
map(0x1c, Keyboard::Num8);
map(0x19, Keyboard::Num9);
map(0x1d, Keyboard::Num0);
map(0x1b, Keyboard::Dash);
map(0x18, Keyboard::Equal);
map(0x33, Keyboard::Backspace);
map(0x72, Keyboard::Insert);
map(0x75, Keyboard::Delete);
map(0x73, Keyboard::Home);
map(0x77, Keyboard::End);
map(0x74, Keyboard::PageUp);
map(0x79, Keyboard::PageDown);
map(0x00, Keyboard::A);
map(0x0b, Keyboard::B);
map(0x08, Keyboard::C);
map(0x02, Keyboard::D);
map(0x0e, Keyboard::E);
map(0x03, Keyboard::F);
map(0x05, Keyboard::G);
map(0x04, Keyboard::H);
map(0x22, Keyboard::I);
map(0x26, Keyboard::J);
map(0x28, Keyboard::K);
map(0x25, Keyboard::L);
map(0x2e, Keyboard::M);
map(0x2d, Keyboard::N);
map(0x1f, Keyboard::O);
map(0x23, Keyboard::P);
map(0x0c, Keyboard::Q);
map(0x0f, Keyboard::R);
map(0x01, Keyboard::S);
map(0x11, Keyboard::T);
map(0x20, Keyboard::U);
map(0x09, Keyboard::V);
map(0x0d, Keyboard::W);
map(0x07, Keyboard::X);
map(0x10, Keyboard::Y);
map(0x06, Keyboard::Z);
map(0x21, Keyboard::LeftBracket);
map(0x1e, Keyboard::RightBracket);
map(0x2a, Keyboard::Backslash);
map(0x29, Keyboard::Semicolon);
map(0x27, Keyboard::Apostrophe);
map(0x2b, Keyboard::Comma);
map(0x2f, Keyboard::Period);
map(0x2c, Keyboard::Slash);
map(0x53, Keyboard::Keypad1);
map(0x54, Keyboard::Keypad2);
map(0x55, Keyboard::Keypad3);
map(0x56, Keyboard::Keypad4);
map(0x57, Keyboard::Keypad5);
map(0x58, Keyboard::Keypad6);
map(0x59, Keyboard::Keypad7);
map(0x5b, Keyboard::Keypad8);
map(0x5c, Keyboard::Keypad9);
map(0x52, Keyboard::Keypad0);
//map(0x??, Keyboard::Point);
map(0x4c, Keyboard::Enter);
map(0x45, Keyboard::Add);
map(0x4e, Keyboard::Subtract);
map(0x43, Keyboard::Multiply);
map(0x4b, Keyboard::Divide);
map(0x47, Keyboard::NumLock);
//map(0x39, Keyboard::CapsLock);
map(0x7e, Keyboard::Up);
map(0x7d, Keyboard::Down);
map(0x7b, Keyboard::Left);
map(0x7c, Keyboard::Right);
map(0x30, Keyboard::Tab);
map(0x24, Keyboard::Return);
map(0x31, Keyboard::Spacebar);
//map(0x??, Keyboard::Menu);
map(0x38, Keyboard::Shift);
map(0x3b, Keyboard::Control);
map(0x3a, Keyboard::Alt);
map(0x37, Keyboard::Super);
#undef map
return true;
}
bool init() {
return true;
}
void term() {
}
};
DeclareInput(Carbon)
};

387
ruby/input/directinput.cpp Executable file
View File

@@ -0,0 +1,387 @@
#define DIRECTINPUT_VERSION 0x0800
#include <dinput.h>
namespace ruby {
static BOOL CALLBACK DI_EnumJoypadsCallback(const DIDEVICEINSTANCE*, void*);
static BOOL CALLBACK DI_EnumJoypadAxesCallback(const DIDEVICEOBJECTINSTANCE*, void*);
using namespace nall;
class pInputDI {
public:
struct {
LPDIRECTINPUT8 context;
LPDIRECTINPUTDEVICE8 keyboard;
LPDIRECTINPUTDEVICE8 mouse;
LPDIRECTINPUTDEVICE8 gamepad[Joypad::Count];
bool mouseacquired;
} device;
struct {
HWND handle;
} settings;
bool cap(const string& name) {
if(name == Input::Handle) return true;
if(name == Input::KeyboardSupport) return true;
if(name == Input::MouseSupport) return true;
if(name == Input::JoypadSupport) return true;
return false;
}
any get(const string& name) {
if(name == Input::Handle) return (uintptr_t)settings.handle;
return false;
}
bool set(const string& name, const any& value) {
if(name == Input::Handle) {
settings.handle = (HWND)any_cast<uintptr_t>(value);
return true;
}
return false;
}
bool poll(int16_t *table) {
memset(table, 0, Scancode::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);
}
}
#define key(id) table[keyboard(0)[id]]
key(Keyboard::Escape) = (bool)(state[0x01] & 0x80);
key(Keyboard::F1 ) = (bool)(state[0x3b] & 0x80);
key(Keyboard::F2 ) = (bool)(state[0x3c] & 0x80);
key(Keyboard::F3 ) = (bool)(state[0x3d] & 0x80);
key(Keyboard::F4 ) = (bool)(state[0x3e] & 0x80);
key(Keyboard::F5 ) = (bool)(state[0x3f] & 0x80);
key(Keyboard::F6 ) = (bool)(state[0x40] & 0x80);
key(Keyboard::F7 ) = (bool)(state[0x41] & 0x80);
key(Keyboard::F8 ) = (bool)(state[0x42] & 0x80);
key(Keyboard::F9 ) = (bool)(state[0x43] & 0x80);
key(Keyboard::F10 ) = (bool)(state[0x44] & 0x80);
key(Keyboard::F11 ) = (bool)(state[0x57] & 0x80);
key(Keyboard::F12 ) = (bool)(state[0x58] & 0x80);
key(Keyboard::PrintScreen) = (bool)(state[0xb7] & 0x80);
key(Keyboard::ScrollLock ) = (bool)(state[0x46] & 0x80);
key(Keyboard::Pause ) = (bool)(state[0xc5] & 0x80);
key(Keyboard::Tilde ) = (bool)(state[0x29] & 0x80);
key(Keyboard::Num1) = (bool)(state[0x02] & 0x80);
key(Keyboard::Num2) = (bool)(state[0x03] & 0x80);
key(Keyboard::Num3) = (bool)(state[0x04] & 0x80);
key(Keyboard::Num4) = (bool)(state[0x05] & 0x80);
key(Keyboard::Num5) = (bool)(state[0x06] & 0x80);
key(Keyboard::Num6) = (bool)(state[0x07] & 0x80);
key(Keyboard::Num7) = (bool)(state[0x08] & 0x80);
key(Keyboard::Num8) = (bool)(state[0x09] & 0x80);
key(Keyboard::Num9) = (bool)(state[0x0a] & 0x80);
key(Keyboard::Num0) = (bool)(state[0x0b] & 0x80);
key(Keyboard::Dash ) = (bool)(state[0x0c] & 0x80);
key(Keyboard::Equal ) = (bool)(state[0x0d] & 0x80);
key(Keyboard::Backspace) = (bool)(state[0x0e] & 0x80);
key(Keyboard::Insert ) = (bool)(state[0xd2] & 0x80);
key(Keyboard::Delete ) = (bool)(state[0xd3] & 0x80);
key(Keyboard::Home ) = (bool)(state[0xc7] & 0x80);
key(Keyboard::End ) = (bool)(state[0xcf] & 0x80);
key(Keyboard::PageUp ) = (bool)(state[0xc9] & 0x80);
key(Keyboard::PageDown) = (bool)(state[0xd1] & 0x80);
key(Keyboard::A) = (bool)(state[0x1e] & 0x80);
key(Keyboard::B) = (bool)(state[0x30] & 0x80);
key(Keyboard::C) = (bool)(state[0x2e] & 0x80);
key(Keyboard::D) = (bool)(state[0x20] & 0x80);
key(Keyboard::E) = (bool)(state[0x12] & 0x80);
key(Keyboard::F) = (bool)(state[0x21] & 0x80);
key(Keyboard::G) = (bool)(state[0x22] & 0x80);
key(Keyboard::H) = (bool)(state[0x23] & 0x80);
key(Keyboard::I) = (bool)(state[0x17] & 0x80);
key(Keyboard::J) = (bool)(state[0x24] & 0x80);
key(Keyboard::K) = (bool)(state[0x25] & 0x80);
key(Keyboard::L) = (bool)(state[0x26] & 0x80);
key(Keyboard::M) = (bool)(state[0x32] & 0x80);
key(Keyboard::N) = (bool)(state[0x31] & 0x80);
key(Keyboard::O) = (bool)(state[0x18] & 0x80);
key(Keyboard::P) = (bool)(state[0x19] & 0x80);
key(Keyboard::Q) = (bool)(state[0x10] & 0x80);
key(Keyboard::R) = (bool)(state[0x13] & 0x80);
key(Keyboard::S) = (bool)(state[0x1f] & 0x80);
key(Keyboard::T) = (bool)(state[0x14] & 0x80);
key(Keyboard::U) = (bool)(state[0x16] & 0x80);
key(Keyboard::V) = (bool)(state[0x2f] & 0x80);
key(Keyboard::W) = (bool)(state[0x11] & 0x80);
key(Keyboard::X) = (bool)(state[0x2d] & 0x80);
key(Keyboard::Y) = (bool)(state[0x15] & 0x80);
key(Keyboard::Z) = (bool)(state[0x2c] & 0x80);
key(Keyboard::LeftBracket ) = (bool)(state[0x1a] & 0x80);
key(Keyboard::RightBracket) = (bool)(state[0x1b] & 0x80);
key(Keyboard::Backslash ) = (bool)(state[0x2b] & 0x80);
key(Keyboard::Semicolon ) = (bool)(state[0x27] & 0x80);
key(Keyboard::Apostrophe ) = (bool)(state[0x28] & 0x80);
key(Keyboard::Comma ) = (bool)(state[0x33] & 0x80);
key(Keyboard::Period ) = (bool)(state[0x34] & 0x80);
key(Keyboard::Slash ) = (bool)(state[0x35] & 0x80);
key(Keyboard::Keypad0) = (bool)(state[0x4f] & 0x80);
key(Keyboard::Keypad1) = (bool)(state[0x50] & 0x80);
key(Keyboard::Keypad2) = (bool)(state[0x51] & 0x80);
key(Keyboard::Keypad3) = (bool)(state[0x4b] & 0x80);
key(Keyboard::Keypad4) = (bool)(state[0x4c] & 0x80);
key(Keyboard::Keypad5) = (bool)(state[0x4d] & 0x80);
key(Keyboard::Keypad6) = (bool)(state[0x47] & 0x80);
key(Keyboard::Keypad7) = (bool)(state[0x48] & 0x80);
key(Keyboard::Keypad8) = (bool)(state[0x49] & 0x80);
key(Keyboard::Keypad9) = (bool)(state[0x52] & 0x80);
key(Keyboard::Point ) = (bool)(state[0x53] & 0x80);
key(Keyboard::Add ) = (bool)(state[0x4e] & 0x80);
key(Keyboard::Subtract) = (bool)(state[0x4a] & 0x80);
key(Keyboard::Multiply) = (bool)(state[0x37] & 0x80);
key(Keyboard::Divide ) = (bool)(state[0xb5] & 0x80);
key(Keyboard::Enter ) = (bool)(state[0x9c] & 0x80);
key(Keyboard::NumLock ) = (bool)(state[0x45] & 0x80);
key(Keyboard::CapsLock) = (bool)(state[0x3a] & 0x80);
key(Keyboard::Up ) = (bool)(state[0xc8] & 0x80);
key(Keyboard::Down ) = (bool)(state[0xd0] & 0x80);
key(Keyboard::Left ) = (bool)(state[0xcb] & 0x80);
key(Keyboard::Right) = (bool)(state[0xcd] & 0x80);
key(Keyboard::Tab ) = (bool)(state[0x0f] & 0x80);
key(Keyboard::Return ) = (bool)(state[0x1c] & 0x80);
key(Keyboard::Spacebar) = (bool)(state[0x39] & 0x80);
key(Keyboard::Menu ) = (bool)(state[0xdd] & 0x80);
key(Keyboard::Shift ) = (bool)(state[0x2a] & 0x80) || (bool)(state[0x36] & 0x80);
key(Keyboard::Control) = (bool)(state[0x1d] & 0x80) || (bool)(state[0x9d] & 0x80);
key(Keyboard::Alt ) = (bool)(state[0x38] & 0x80) || (bool)(state[0xb8] & 0x80);
key(Keyboard::Super ) = (bool)(state[0xdb] & 0x80) || (bool)(state[0xdc] & 0x80);
#undef key
}
//=====
//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).axis(0)] = state.lX;
table[mouse(0).axis(1)] = state.lY;
table[mouse(0).axis(2)] = 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;
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[joypad(i).hat(n)] |= Joypad::HatUp;
if(pov >= 4500 && pov <= 13500) table[joypad(i).hat(n)] |= Joypad::HatRight;
if(pov >= 13500 && pov <= 22500) table[joypad(i).hat(n)] |= Joypad::HatDown;
if(pov >= 22500 && pov <= 31500) table[joypad(i).hat(n)] |= Joypad::HatLeft;
}
}
//axes
table[joypad(i).axis(0)] = state.lX;
table[joypad(i).axis(1)] = state.lY;
table[joypad(i).axis(2)] = state.lZ;
table[joypad(i).axis(3)] = state.lRx;
table[joypad(i).axis(4)] = state.lRy;
table[joypad(i).axis(5)] = state.lRz;
//buttons
for(unsigned n = 0; n < min((unsigned)Joypad::Buttons, 128); n++) {
table[joypad(i).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() {
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);
}
DeclareInput(DI)
};

797
ruby/input/rawinput.cpp Executable file
View File

@@ -0,0 +1,797 @@
//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 {
static DWORD WINAPI RawInputThreadProc(void*);
static 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[nall::Keyboard::Size];
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, nall::Keyboard::Escape)
map(0x003b, 0, nall::Keyboard::F1)
map(0x003c, 0, nall::Keyboard::F2)
map(0x003d, 0, nall::Keyboard::F3)
map(0x003e, 0, nall::Keyboard::F4)
map(0x003f, 0, nall::Keyboard::F5)
map(0x0040, 0, nall::Keyboard::F6)
map(0x0041, 0, nall::Keyboard::F7)
map(0x0042, 0, nall::Keyboard::F8)
map(0x0043, 0, nall::Keyboard::F9)
map(0x0044, 0, nall::Keyboard::F10)
map(0x0057, 0, nall::Keyboard::F11)
map(0x0058, 0, nall::Keyboard::F12)
map(0x0037, 2, nall::Keyboard::PrintScreen)
map(0x0046, 0, nall::Keyboard::ScrollLock)
map(0x001d, 4, nall::Keyboard::Pause)
map(0x0029, 0, nall::Keyboard::Tilde)
map(0x0002, 0, nall::Keyboard::Num1)
map(0x0003, 0, nall::Keyboard::Num2)
map(0x0004, 0, nall::Keyboard::Num3)
map(0x0005, 0, nall::Keyboard::Num4)
map(0x0006, 0, nall::Keyboard::Num5)
map(0x0007, 0, nall::Keyboard::Num6)
map(0x0008, 0, nall::Keyboard::Num7)
map(0x0009, 0, nall::Keyboard::Num8)
map(0x000a, 0, nall::Keyboard::Num9)
map(0x000b, 0, nall::Keyboard::Num0)
map(0x000c, 0, nall::Keyboard::Dash)
map(0x000d, 0, nall::Keyboard::Equal)
map(0x000e, 0, nall::Keyboard::Backspace)
map(0x0052, 2, nall::Keyboard::Insert)
map(0x0053, 2, nall::Keyboard::Delete)
map(0x0047, 2, nall::Keyboard::Home)
map(0x004f, 2, nall::Keyboard::End)
map(0x0049, 2, nall::Keyboard::PageUp)
map(0x0051, 2, nall::Keyboard::PageDown)
map(0x001e, 0, nall::Keyboard::A)
map(0x0030, 0, nall::Keyboard::B)
map(0x002e, 0, nall::Keyboard::C)
map(0x0020, 0, nall::Keyboard::D)
map(0x0012, 0, nall::Keyboard::E)
map(0x0021, 0, nall::Keyboard::F)
map(0x0022, 0, nall::Keyboard::G)
map(0x0023, 0, nall::Keyboard::H)
map(0x0017, 0, nall::Keyboard::I)
map(0x0024, 0, nall::Keyboard::J)
map(0x0025, 0, nall::Keyboard::K)
map(0x0026, 0, nall::Keyboard::L)
map(0x0032, 0, nall::Keyboard::M)
map(0x0031, 0, nall::Keyboard::N)
map(0x0018, 0, nall::Keyboard::O)
map(0x0019, 0, nall::Keyboard::P)
map(0x0010, 0, nall::Keyboard::Q)
map(0x0013, 0, nall::Keyboard::R)
map(0x001f, 0, nall::Keyboard::S)
map(0x0014, 0, nall::Keyboard::T)
map(0x0016, 0, nall::Keyboard::U)
map(0x002f, 0, nall::Keyboard::V)
map(0x0011, 0, nall::Keyboard::W)
map(0x002d, 0, nall::Keyboard::X)
map(0x0015, 0, nall::Keyboard::Y)
map(0x002c, 0, nall::Keyboard::Z)
map(0x001a, 0, nall::Keyboard::LeftBracket)
map(0x001b, 0, nall::Keyboard::RightBracket)
map(0x002b, 0, nall::Keyboard::Backslash)
map(0x0027, 0, nall::Keyboard::Semicolon)
map(0x0028, 0, nall::Keyboard::Apostrophe)
map(0x0033, 0, nall::Keyboard::Comma)
map(0x0034, 0, nall::Keyboard::Period)
map(0x0035, 0, nall::Keyboard::Slash)
map(0x004f, 0, nall::Keyboard::Keypad1)
map(0x0050, 0, nall::Keyboard::Keypad2)
map(0x0051, 0, nall::Keyboard::Keypad3)
map(0x004b, 0, nall::Keyboard::Keypad4)
map(0x004c, 0, nall::Keyboard::Keypad5)
map(0x004d, 0, nall::Keyboard::Keypad6)
map(0x0047, 0, nall::Keyboard::Keypad7)
map(0x0048, 0, nall::Keyboard::Keypad8)
map(0x0049, 0, nall::Keyboard::Keypad9)
map(0x0052, 0, nall::Keyboard::Keypad0)
map(0x0053, 0, nall::Keyboard::Point)
map(0x001c, 2, nall::Keyboard::Enter)
map(0x004e, 0, nall::Keyboard::Add)
map(0x004a, 0, nall::Keyboard::Subtract)
map(0x0037, 0, nall::Keyboard::Multiply)
map(0x0035, 2, nall::Keyboard::Divide)
map(0x0045, 0, nall::Keyboard::NumLock)
map(0x003a, 0, nall::Keyboard::CapsLock)
//Pause signals 0x1d:4 + 0x45:0, whereas NumLock signals only 0x45:0.
//this makes it impractical to detect both Pause+NumLock independently.
//workaround: always detect Pause; detect NumLock only when Pause is released.
if(state[nall::Keyboard::Pause]) state[nall::Keyboard::NumLock] = false;
map(0x0048, 2, nall::Keyboard::Up)
map(0x0050, 2, nall::Keyboard::Down)
map(0x004b, 2, nall::Keyboard::Left)
map(0x004d, 2, nall::Keyboard::Right)
map(0x000f, 0, nall::Keyboard::Tab)
map(0x001c, 0, nall::Keyboard::Return)
map(0x0039, 0, nall::Keyboard::Spacebar)
map(0x005d, 2, nall::Keyboard::Menu)
//merge left and right modifiers to one ID
if(code == 0x002a && flags == 0) state[nall::Keyboard::Shift] = 1; //left shift
if(code == 0x002a && flags == 1) state[nall::Keyboard::Shift] = 0;
if(code == 0x0036 && flags == 0) state[nall::Keyboard::Shift] = 1; //right shift
if(code == 0x0036 && flags == 1) state[nall::Keyboard::Shift] = 0;
if(code == 0x001d && flags == 0) state[nall::Keyboard::Control] = 1; //left control
if(code == 0x001d && flags == 1) state[nall::Keyboard::Control] = 0;
if(code == 0x001d && flags == 2) state[nall::Keyboard::Control] = 1; //right control
if(code == 0x001d && flags == 3) state[nall::Keyboard::Control] = 0;
if(code == 0x0038 && flags == 0) state[nall::Keyboard::Alt] = 1; //left alt
if(code == 0x0038 && flags == 1) state[nall::Keyboard::Alt] = 0;
if(code == 0x0038 && flags == 2) state[nall::Keyboard::Alt] = 1; //right alt
if(code == 0x0038 && flags == 3) state[nall::Keyboard::Alt] = 0;
if(code == 0x005b && flags == 2) state[nall::Keyboard::Super] = 1; //left super
if(code == 0x005b && flags == 3) state[nall::Keyboard::Super] = 0;
if(code == 0x005c && flags == 2) state[nall::Keyboard::Super] = 1; //right super
if(code == 0x005c && flags == 3) state[nall::Keyboard::Super] = 0;
#undef map
}
Keyboard() {
for(unsigned i = 0; i < nall::Keyboard::Size; 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;
};
linear_vector<Keyboard> lkeyboard;
linear_vector<Mouse> lmouse;
linear_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:
HMODULE libxinput;
DWORD WINAPI (*pXInputGetState)(DWORD, XINPUT_STATE*);
struct Gamepad {
unsigned id;
int16_t hat;
int16_t axis[6];
bool button[10];
void poll(XINPUT_STATE &state) {
hat = Joypad::HatCenter;
if(state.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_UP ) hat |= Joypad::HatUp;
if(state.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_RIGHT) hat |= Joypad::HatRight;
if(state.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_DOWN ) hat |= Joypad::HatDown;
if(state.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_LEFT ) hat |= Joypad::HatLeft;
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::HatCenter;
for(unsigned n = 0; n < 6; n++) axis[n] = 0;
for(unsigned n = 0; n < 10; n++) button[n] = false;
}
};
linear_vector<Gamepad> lgamepad;
void poll() {
if(!pXInputGetState) return;
for(unsigned i = 0; i < lgamepad.size(); i++) {
XINPUT_STATE state;
DWORD result = pXInputGetState(lgamepad[i].id, &state);
if(result == ERROR_SUCCESS) lgamepad[i].poll(state);
}
}
void init() {
if(!pXInputGetState) return;
//XInput only supports up to four controllers
for(unsigned i = 0; i <= 3; i++) {
XINPUT_STATE state;
DWORD result = pXInputGetState(i, &state);
if(result == ERROR_SUCCESS) {
//valid controller detected, add to gamepad list
unsigned n = lgamepad.size();
lgamepad[n].id = i;
}
}
}
XInput() : pXInputGetState(0) {
//bind xinput1 dynamically, as it does not ship with Windows Vista or below
libxinput = LoadLibraryA("xinput1_3.dll");
if(!libxinput) libxinput = LoadLibraryA("xinput1_2.dll");
if(!libxinput) libxinput = LoadLibraryA("xinput1_1.dll");
if(!libxinput) return;
pXInputGetState = (DWORD WINAPI (*)(DWORD, XINPUT_STATE*))GetProcAddress(libxinput, "XInputGetState");
}
~XInput() {
if(libxinput) FreeLibrary(libxinput);
}
};
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::HatCenter;
//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::HatUp;
if(pov >= 4500 && pov <= 13500) hat[n] |= Joypad::HatRight;
if(pov >= 13500 && pov <= 22500) hat[n] |= Joypad::HatDown;
if(pov >= 22500 && pov <= 31500) hat[n] |= Joypad::HatLeft;
}
//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::HatCenter;
for(unsigned n = 0; n < 6; n++) axis[n] = 0;
for(unsigned n = 0; n < 128; n++) button[n] = false;
}
};
linear_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:
XInput xinput;
DirectInput dinput;
bool acquire_mouse;
bool cursor_visible;
struct {
HWND handle;
} settings;
bool cap(const string& name) {
if(name == Input::Handle) return true;
if(name == Input::KeyboardSupport) return true;
if(name == Input::MouseSupport) return true;
if(name == Input::JoypadSupport) return true;
return false;
}
any get(const string& name) {
if(name == Input::Handle) return (uintptr_t)settings.handle;
return false;
}
bool set(const string& name, const any& value) {
if(name == Input::Handle) {
settings.handle = (HWND)any_cast<uintptr_t>(value);
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, Scancode::Limit * sizeof(int16_t));
WaitForSingleObject(rawinput.mutex, INFINITE);
//=========
//Keyboards
//=========
for(unsigned i = 0; i < min(rawinput.lkeyboard.size(), (unsigned)Keyboard::Count); i++) {
for(unsigned n = 0; n < nall::Keyboard::Size; n++) {
table[keyboard(i).key(n)] = rawinput.lkeyboard[i].state[n];
}
}
//====
//Mice
//====
for(unsigned i = 0; i < min(rawinput.lmouse.size(), (unsigned)Mouse::Count); i++) {
table[mouse(i).axis(0)] = rawinput.lmouse[i].xDistance;
table[mouse(i).axis(1)] = rawinput.lmouse[i].yDistance;
table[mouse(i).axis(2)] = rawinput.lmouse[i].zDistance;
for(unsigned n = 0; n < min(5U, (unsigned)Mouse::Buttons); n++) {
table[mouse(i).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;
table[joypad(i).hat(0)] = xinput.lgamepad[i].hat;
for(unsigned axis = 0; axis < min(6U, (unsigned)Joypad::Axes); axis++) {
table[joypad(i).axis(axis)] = xinput.lgamepad[i].axis[axis];
}
for(unsigned button = 0; button < min(10U, (unsigned)Joypad::Buttons); button++) {
table[joypad(i).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;
for(unsigned hat = 0; hat < min(4U, (unsigned)Joypad::Hats); hat++) {
table[joypad(i).hat(hat)] = dinput.lgamepad[i].hat[hat];
}
for(unsigned axis = 0; axis < min(6U, (unsigned)Joypad::Axes); axis++) {
table[joypad(i).axis(axis)] = dinput.lgamepad[i].axis[axis];
}
for(unsigned button = 0; button < min(128U, (unsigned)Joypad::Buttons); button++) {
table[joypad(i).button(button)] = dinput.lgamepad[i].button[button];
}
}
return true;
}
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() {
}
};
DeclareInput(Raw)
};

230
ruby/input/sdl.cpp Executable file
View File

@@ -0,0 +1,230 @@
//================
//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>
namespace ruby {
struct pInputSDL {
#include "xlibkeys.hpp"
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(const string& name) {
if(name == Input::Handle) return true;
if(name == Input::KeyboardSupport) return true;
if(name == Input::MouseSupport) return true;
if(name == Input::JoypadSupport) return true;
return false;
}
any get(const string& name) {
if(name == Input::Handle) return (uintptr_t)settings.handle;
return false;
}
bool set(const string& name, const any &value) {
if(name == Input::Handle) {
settings.handle = any_cast<uintptr_t>(value);
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, Scancode::Limit * sizeof(int16_t));
//========
//Keyboard
//========
x_poll(table);
//=====
//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).axis(0)] = (int16_t)(root_x_return - device.screenwidth / 2);
table[mouse(0).axis(1)] = (int16_t)(root_y_return - device.screenheight / 2);
if(table[mouse(0).axis(0)] != 0 || table[mouse(0).axis(1)] != 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).axis(0)] = (int16_t)(root_x_return - device.relativex);
table[mouse(0).axis(1)] = (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;
//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[joypad(i).hat(hat)] |= Joypad::HatUp;
if(state & SDL_HAT_RIGHT) table[joypad(i).hat(hat)] |= Joypad::HatRight;
if(state & SDL_HAT_DOWN ) table[joypad(i).hat(hat)] |= Joypad::HatDown;
if(state & SDL_HAT_LEFT ) table[joypad(i).hat(hat)] |= Joypad::HatLeft;
}
//axes
unsigned axes = min((unsigned)Joypad::Axes, SDL_JoystickNumAxes(device.gamepad[i]));
for(unsigned axis = 0; axis < axes; axis++) {
table[joypad(i).axis(axis)] = (int16_t)SDL_JoystickGetAxis(device.gamepad[i], axis);
}
//buttons
for(unsigned button = 0; button < Joypad::Buttons; button++) {
table[joypad(i).button(button)] = (bool)SDL_JoystickGetButton(device.gamepad[i], button);
}
}
return true;
}
bool init() {
x_init();
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);
XCloseDisplay(device.display);
}
pInputSDL() {
for(unsigned i = 0; i < Joypad::Count; i++) device.gamepad[i] = 0;
settings.handle = 0;
}
};
DeclareInput(SDL)
};

50
ruby/input/x.cpp Executable file
View File

@@ -0,0 +1,50 @@
#include <sys/ipc.h>
#include <sys/shm.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/Xatom.h>
namespace ruby {
class pInputX {
public:
Display *display;
#include "xlibkeys.hpp"
bool cap(const string& name) {
if(name == Input::KeyboardSupport) return true;
return false;
}
any get(const string& name) {
return false;
}
bool set(const string& name, const any &value) {
return false;
}
bool acquire() { return false; }
bool unacquire() { return false; }
bool acquired() { return false; }
bool poll(int16_t *table) {
memset(table, 0, Scancode::Limit * sizeof(int16_t));
x_poll(table);
return true;
}
bool init() {
x_init();
display = XOpenDisplay(0);
return true;
}
void term() {
XCloseDisplay(display);
}
};
DeclareInput(X)
};

264
ruby/input/xlibkeys.hpp Executable file
View File

@@ -0,0 +1,264 @@
uint8_t scancode[256];
enum XScancode {
Escape, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12,
ScrollLock, Pause, Tilde,
Num1, Num2, Num3, Num4, Num5, Num6, Num7, Num8, Num9, Num0,
Dash, Equal, Backspace,
Insert, Delete, Home, End, PageUp, PageDown,
A, B, C, D, E, F, G, H, I, J, K, L, M,
N, O, P, Q, R, S, T, U, V, W, X, Y, Z,
LeftBracket, RightBracket, Backslash, Semicolon, Apostrophe, Comma, Period, Slash,
Keypad1, Keypad2, Keypad3, Keypad4, Keypad5, Keypad6, Keypad7, Keypad8, Keypad9, Keypad0,
Point, Enter, Add, Subtract, Multiply, Divide,
Up, Down, Left, Right,
Tab, Return, Spacebar, Menu,
LeftShift, RightShift, LeftControl, RightControl, LeftAlt, RightAlt, LeftSuper, RightSuper,
};
void x_poll(int16_t *table) {
char state[32];
Display *display = XOpenDisplay(0);
XQueryKeymap(display, state);
XCloseDisplay(display);
#define key(id) table[keyboard(0)[id]]
#define pressed(id) (bool)(state[scancode[id] >> 3] & (1 << (scancode[id] & 7)))
key(Keyboard::Escape) = pressed(Escape);
key(Keyboard::F1) = pressed(F1);
key(Keyboard::F2) = pressed(F2);
key(Keyboard::F3) = pressed(F3);
key(Keyboard::F4) = pressed(F4);
key(Keyboard::F5) = pressed(F5);
key(Keyboard::F6) = pressed(F6);
key(Keyboard::F7) = pressed(F7);
key(Keyboard::F8) = pressed(F8);
key(Keyboard::F9) = pressed(F9);
key(Keyboard::F10) = pressed(F10);
key(Keyboard::F11) = pressed(F11);
key(Keyboard::F12) = pressed(F12);
key(Keyboard::ScrollLock) = pressed(ScrollLock);
key(Keyboard::Pause) = pressed(Pause);
key(Keyboard::Tilde) = pressed(Tilde);
key(Keyboard::Num1) = pressed(Num1);
key(Keyboard::Num2) = pressed(Num2);
key(Keyboard::Num3) = pressed(Num3);
key(Keyboard::Num4) = pressed(Num4);
key(Keyboard::Num5) = pressed(Num5);
key(Keyboard::Num6) = pressed(Num6);
key(Keyboard::Num7) = pressed(Num7);
key(Keyboard::Num8) = pressed(Num8);
key(Keyboard::Num9) = pressed(Num9);
key(Keyboard::Num0) = pressed(Num0);
key(Keyboard::Dash) = pressed(Dash);
key(Keyboard::Equal) = pressed(Equal);
key(Keyboard::Backspace) = pressed(Backspace);
key(Keyboard::Insert) = pressed(Insert);
key(Keyboard::Delete) = pressed(Delete);
key(Keyboard::Home) = pressed(Home);
key(Keyboard::End) = pressed(End);
key(Keyboard::PageUp) = pressed(PageUp);
key(Keyboard::PageDown) = pressed(PageDown);
key(Keyboard::A) = pressed(A);
key(Keyboard::B) = pressed(B);
key(Keyboard::C) = pressed(C);
key(Keyboard::D) = pressed(D);
key(Keyboard::E) = pressed(E);
key(Keyboard::F) = pressed(F);
key(Keyboard::G) = pressed(G);
key(Keyboard::H) = pressed(H);
key(Keyboard::I) = pressed(I);
key(Keyboard::J) = pressed(J);
key(Keyboard::K) = pressed(K);
key(Keyboard::L) = pressed(L);
key(Keyboard::M) = pressed(M);
key(Keyboard::N) = pressed(N);
key(Keyboard::O) = pressed(O);
key(Keyboard::P) = pressed(P);
key(Keyboard::Q) = pressed(Q);
key(Keyboard::R) = pressed(R);
key(Keyboard::S) = pressed(S);
key(Keyboard::T) = pressed(T);
key(Keyboard::U) = pressed(U);
key(Keyboard::V) = pressed(V);
key(Keyboard::W) = pressed(W);
key(Keyboard::X) = pressed(X);
key(Keyboard::Y) = pressed(Y);
key(Keyboard::Z) = pressed(Z);
key(Keyboard::LeftBracket) = pressed(LeftBracket);
key(Keyboard::RightBracket) = pressed(RightBracket);
key(Keyboard::Backslash) = pressed(Backslash);
key(Keyboard::Semicolon) = pressed(Semicolon);
key(Keyboard::Apostrophe) = pressed(Apostrophe);
key(Keyboard::Comma) = pressed(Comma);
key(Keyboard::Period) = pressed(Period);
key(Keyboard::Slash) = pressed(Slash);
key(Keyboard::Keypad1) = pressed(Keypad1);
key(Keyboard::Keypad2) = pressed(Keypad2);
key(Keyboard::Keypad3) = pressed(Keypad3);
key(Keyboard::Keypad4) = pressed(Keypad4);
key(Keyboard::Keypad5) = pressed(Keypad5);
key(Keyboard::Keypad6) = pressed(Keypad6);
key(Keyboard::Keypad7) = pressed(Keypad7);
key(Keyboard::Keypad8) = pressed(Keypad8);
key(Keyboard::Keypad9) = pressed(Keypad9);
key(Keyboard::Keypad0) = pressed(Keypad0);
key(Keyboard::Point) = pressed(Point);
key(Keyboard::Enter) = pressed(Enter);
key(Keyboard::Add) = pressed(Add);
key(Keyboard::Subtract) = pressed(Subtract);
key(Keyboard::Multiply) = pressed(Multiply);
key(Keyboard::Divide) = pressed(Divide);
key(Keyboard::Up) = pressed(Up);
key(Keyboard::Down) = pressed(Down);
key(Keyboard::Left) = pressed(Left);
key(Keyboard::Right) = pressed(Right);
key(Keyboard::Tab) = pressed(Tab);
key(Keyboard::Return) = pressed(Return);
key(Keyboard::Spacebar) = pressed(Spacebar);
key(Keyboard::Menu) = pressed(Menu);
key(Keyboard::Shift) = pressed(LeftShift) || pressed(RightShift);
key(Keyboard::Control) = pressed(LeftControl) || pressed(RightControl);
key(Keyboard::Alt) = pressed(LeftAlt) || pressed(RightAlt);
key(Keyboard::Super) = pressed(LeftSuper) || pressed(RightSuper);
#undef key
#undef pressed
}
void x_init() {
Display *display = XOpenDisplay(0);
memset(&scancode, 0, sizeof scancode);
#define assign(x, y) scancode[x] = XKeysymToKeycode(display, y)
assign(Escape, XK_Escape);
assign(F1, XK_F1);
assign(F2, XK_F2);
assign(F3, XK_F3);
assign(F4, XK_F4);
assign(F5, XK_F5);
assign(F6, XK_F6);
assign(F7, XK_F7);
assign(F8, XK_F8);
assign(F9, XK_F9);
assign(F10, XK_F10);
assign(F11, XK_F11);
assign(F12, XK_F12);
assign(ScrollLock, XK_Scroll_Lock);
assign(Pause, XK_Pause);
assign(Tilde, XK_asciitilde);
assign(Num0, XK_0);
assign(Num1, XK_1);
assign(Num2, XK_2);
assign(Num3, XK_3);
assign(Num4, XK_4);
assign(Num5, XK_5);
assign(Num6, XK_6);
assign(Num7, XK_7);
assign(Num8, XK_8);
assign(Num9, XK_9);
assign(Dash, XK_minus);
assign(Equal, XK_equal);
assign(Backspace, XK_BackSpace);
assign(Insert, XK_Insert);
assign(Delete, XK_Delete);
assign(Home, XK_Home);
assign(End, XK_End);
assign(PageUp, XK_Prior);
assign(PageDown, XK_Next);
assign(A, XK_A);
assign(B, XK_B);
assign(C, XK_C);
assign(D, XK_D);
assign(E, XK_E);
assign(F, XK_F);
assign(G, XK_G);
assign(H, XK_H);
assign(I, XK_I);
assign(J, XK_J);
assign(K, XK_K);
assign(L, XK_L);
assign(M, XK_M);
assign(N, XK_N);
assign(O, XK_O);
assign(P, XK_P);
assign(Q, XK_Q);
assign(R, XK_R);
assign(S, XK_S);
assign(T, XK_T);
assign(U, XK_U);
assign(V, XK_V);
assign(W, XK_W);
assign(X, XK_X);
assign(Y, XK_Y);
assign(Z, XK_Z);
assign(LeftBracket, XK_bracketleft);
assign(RightBracket, XK_bracketright);
assign(Backslash, XK_backslash);
assign(Semicolon, XK_semicolon);
assign(Apostrophe, XK_apostrophe);
assign(Comma, XK_comma);
assign(Period, XK_period);
assign(Slash, XK_slash);
assign(Keypad0, XK_KP_0);
assign(Keypad1, XK_KP_1);
assign(Keypad2, XK_KP_2);
assign(Keypad3, XK_KP_3);
assign(Keypad4, XK_KP_4);
assign(Keypad5, XK_KP_5);
assign(Keypad6, XK_KP_6);
assign(Keypad7, XK_KP_7);
assign(Keypad8, XK_KP_8);
assign(Keypad9, XK_KP_9);
assign(Add, XK_KP_Add);
assign(Subtract, XK_KP_Subtract);
assign(Multiply, XK_KP_Multiply);
assign(Divide, XK_KP_Divide);
assign(Enter, XK_KP_Enter);
assign(Up, XK_Up);
assign(Down, XK_Down);
assign(Left, XK_Left);
assign(Right, XK_Right);
assign(Tab, XK_Tab);
assign(Return, XK_Return);
assign(Spacebar, XK_space);
assign(LeftControl, XK_Control_L);
assign(RightControl, XK_Control_R);
assign(LeftAlt, XK_Alt_L);
assign(RightAlt, XK_Alt_R);
assign(LeftShift, XK_Shift_L);
assign(RightShift, XK_Shift_R);
assign(LeftSuper, XK_Super_L);
assign(RightSuper, XK_Super_R);
assign(Menu, XK_Menu);
#undef assign
XCloseDisplay(display);
}