mirror of https://github.com/bsnes-emu/bsnes.git
Update to v093r12 release.
byuu says: I've completely redone the ethos InputManager and ruby to work on HID::Device objects instead of one giant scancode pool. Currently only the udev driver supports the changes to ruby, so only Linux users will be able to compile and run this WIP build. The nice thing about the new system is that it's now possible to uniquely identify controllers, so if you swap out gamepads, you won't end up with it working but with all the mappings all screwed up. Since higan lets you map multiple physical inputs to one emulated input, you can now configure your keyboard and multiple gamepads to the same emulated input, and then just use whatever controller you want. Because USB gamepad makers failed to provide unique serial#s with each controller, we have to limit the mapping to specific USB ports. Otherwise, we couldn't distinguish two otherwise identical gamepads. So basically your computer USB ports act like real game console input port numbers. Which is kind of neat, I guess. And the really nice thing about the new system is that we now have the capability to support hotplugging input devices. I haven't yet added this to any drivers, but I'm definitely going to add it to udev for v094 official. Finally, with the device ID (vendor ID + product ID) exposed, we gain one last really cool feature that we may be able to develop more in the future. Say we created a joypad.bml file to include with higan. In it, we'd store the Xbox 360 controller, and pre-defined button mappings for each emulated system. So if higan detects you have an Xbox 360 controller, you can just plug it in and use it. Even better, we can clearly specify the difference between triggers and analog axes, and name each individual input. So you'd see "Xbox 360 Gamepad #1: Left Trigger" instead of higan v093's "JP0::Axis2.Hi" Note: for right now, ethos' input manager isn't filtering the device IDs to look pretty. So you're going to see a 64-bit hex value for a device ID right now instead of something like Joypad#N for now.
This commit is contained in:
parent
73be2e729c
commit
3ce1d19f7a
|
@ -3,7 +3,7 @@
|
|||
|
||||
namespace Emulator {
|
||||
static const char Name[] = "higan";
|
||||
static const char Version[] = "093.11";
|
||||
static const char Version[] = "093.12";
|
||||
static const char Author[] = "byuu";
|
||||
static const char License[] = "GPLv3";
|
||||
static const char Website[] = "http://byuu.org/";
|
||||
|
|
|
@ -31,7 +31,7 @@ struct Interface {
|
|||
string name;
|
||||
struct Input {
|
||||
unsigned id;
|
||||
unsigned type; //0 = digital, 1 = analog (relative), 2 = analog (absolute), 3 = rumble
|
||||
unsigned type; //0 = digital, 1 = analog (relative), 2 = rumble
|
||||
string name;
|
||||
unsigned guid;
|
||||
};
|
||||
|
|
|
@ -139,7 +139,7 @@ Interface::Interface() {
|
|||
device.input.append({ 7, 0, "Down" });
|
||||
device.input.append({ 8, 0, "R" });
|
||||
device.input.append({ 9, 0, "L" });
|
||||
device.input.append({10, 3, "Rumble"});
|
||||
device.input.append({10, 2, "Rumble"});
|
||||
device.order = {6, 7, 5, 4, 1, 0, 9, 8, 2, 3, 10};
|
||||
this->device.append(device);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,117 @@
|
|||
#ifndef NALL_HID_HPP
|
||||
#define NALL_HID_HPP
|
||||
|
||||
namespace nall {
|
||||
|
||||
namespace HID {
|
||||
struct Input {
|
||||
string name;
|
||||
int16_t value = 0;
|
||||
|
||||
Input() {}
|
||||
Input(const string& name) : name(name) {}
|
||||
};
|
||||
|
||||
struct Group {
|
||||
string name;
|
||||
vector<Input> input;
|
||||
|
||||
Group() {}
|
||||
Group(const string& name) : name(name) {}
|
||||
|
||||
void append(const string& name) {
|
||||
input.append({name});
|
||||
}
|
||||
|
||||
optional<unsigned> find(const string& name) {
|
||||
for(unsigned id = 0; id < input.size(); id++) {
|
||||
if(input[id].name == name) return {true, id};
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
struct Device {
|
||||
uint64_t id = 0;
|
||||
string name;
|
||||
vector<Group> group;
|
||||
|
||||
Device() {
|
||||
group.resize(4);
|
||||
}
|
||||
|
||||
uint32_t pathID() const { return (uint32_t)(id >> 32); }
|
||||
uint32_t deviceID() const { return (uint32_t)(id >> 0); }
|
||||
uint16_t vendorID() const { return (uint16_t)(id >> 16); }
|
||||
uint16_t productID() const { return (uint16_t)(id >> 0); }
|
||||
|
||||
virtual bool isNull() const { return false; }
|
||||
virtual bool isKeyboard() const { return false; }
|
||||
virtual bool isMouse() const { return false; }
|
||||
virtual bool isJoypad() const { return false; }
|
||||
|
||||
optional<unsigned> find(const string& name) {
|
||||
for(unsigned id = 0; id < group.size(); id++) {
|
||||
if(group[id].name == name) return {true, id};
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
struct Null : Device {
|
||||
Null() {
|
||||
name = "Null";
|
||||
}
|
||||
|
||||
bool isNull() const { return true; }
|
||||
};
|
||||
|
||||
struct Keyboard : Device {
|
||||
enum GroupID : unsigned { Button };
|
||||
Group& button = group[0];
|
||||
|
||||
Keyboard() {
|
||||
name = "Keyboard";
|
||||
button.name = "Button";
|
||||
}
|
||||
|
||||
bool isKeyboard() const { return true; }
|
||||
};
|
||||
|
||||
struct Mouse : Device {
|
||||
enum GroupID : unsigned { Axis, Button };
|
||||
Group& axis = group[0];
|
||||
Group& button = group[1];
|
||||
|
||||
Mouse() {
|
||||
name = "Mouse";
|
||||
axis.name = "Axis";
|
||||
button.name = "Button";
|
||||
}
|
||||
|
||||
bool isMouse() const { return true; }
|
||||
};
|
||||
|
||||
struct Joypad : Device {
|
||||
enum GroupID : unsigned { Axis, Hat, Trigger, Button };
|
||||
Group& axis = group[0];
|
||||
Group& hat = group[1];
|
||||
Group& trigger = group[2];
|
||||
Group& button = group[3];
|
||||
bool rumble = false;
|
||||
|
||||
Joypad() {
|
||||
name = "Joypad";
|
||||
axis.name = "Axis";
|
||||
hat.name = "Hat";
|
||||
trigger.name = "Trigger";
|
||||
button.name = "Button";
|
||||
}
|
||||
|
||||
bool isJoypad() const { return true; }
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
|
@ -24,6 +24,7 @@
|
|||
#include <nall/group.hpp>
|
||||
#include <nall/gzip.hpp>
|
||||
#include <nall/hashset.hpp>
|
||||
#include <nall/hid.hpp>
|
||||
#include <nall/http.hpp>
|
||||
#include <nall/image.hpp>
|
||||
#include <nall/inflate.hpp>
|
||||
|
|
|
@ -21,6 +21,7 @@ namespace Math {
|
|||
#include <utility>
|
||||
|
||||
#include <assert.h>
|
||||
#include <endian.h>
|
||||
#include <errno.h>
|
||||
#include <limits.h>
|
||||
#include <math.h>
|
||||
|
|
|
@ -19,8 +19,7 @@ using namespace nall;
|
|||
/* Video */
|
||||
|
||||
#define DeclareVideo(Name) \
|
||||
class Video##Name : public Video { \
|
||||
public: \
|
||||
struct Video##Name : Video { \
|
||||
bool cap(const string& name) { return p.cap(name); } \
|
||||
any get(const string& name) { return p.get(name); } \
|
||||
bool set(const string& name, const any& value) { return p.set(name, value); } \
|
||||
|
@ -79,8 +78,7 @@ using namespace nall;
|
|||
/* Audio */
|
||||
|
||||
#define DeclareAudio(Name) \
|
||||
class Audio##Name : public Audio { \
|
||||
public: \
|
||||
struct Audio##Name : Audio { \
|
||||
bool cap(const string& name) { return p.cap(name); } \
|
||||
any get(const string& name) { return p.get(name); } \
|
||||
bool set(const string& name, const any& value) { return p.set(name, value); } \
|
||||
|
@ -132,8 +130,7 @@ using namespace nall;
|
|||
/* Input */
|
||||
|
||||
#define DeclareInput(Name) \
|
||||
class Input##Name : public Input { \
|
||||
public: \
|
||||
struct Input##Name : Input { \
|
||||
bool cap(const string& name) { return p.cap(name); } \
|
||||
any get(const string& name) { return p.get(name); } \
|
||||
bool set(const string& name, const any& value) { return p.set(name, value); } \
|
||||
|
@ -142,8 +139,9 @@ using namespace nall;
|
|||
bool unacquire() { return p.unacquire(); } \
|
||||
bool acquired() { return p.acquired(); } \
|
||||
\
|
||||
vector<HID::Device*> poll() { return p.poll(); } \
|
||||
bool poll(int16_t* table) { return p.poll(table); } \
|
||||
void rumble(unsigned id, bool enable) { return p.rumble(id, enable); } \
|
||||
void rumble(uint64_t id, bool enable) { return p.rumble(id, enable); } \
|
||||
bool init() { return p.init(); } \
|
||||
void term() { p.term(); } \
|
||||
\
|
||||
|
@ -174,6 +172,6 @@ using namespace nall;
|
|||
#include <ruby/input/udev.cpp>
|
||||
#endif
|
||||
|
||||
#ifdef INPUT_X
|
||||
#include <ruby/input/x.cpp>
|
||||
#ifdef INPUT_XLIB
|
||||
#include <ruby/input/xlib.cpp>
|
||||
#endif
|
||||
|
|
|
@ -13,8 +13,9 @@ struct Input {
|
|||
virtual bool unacquire() { return false; }
|
||||
virtual bool acquired() { return false; }
|
||||
|
||||
virtual nall::vector<nall::HID::Device*> poll() { return {}; }
|
||||
virtual bool poll(int16_t* table) { return false; }
|
||||
virtual void rumble(unsigned id, bool enable) {}
|
||||
virtual void rumble(uint64_t id, bool enable) {}
|
||||
virtual bool init() { return true; }
|
||||
virtual void term() {}
|
||||
|
||||
|
|
|
@ -0,0 +1,66 @@
|
|||
#ifndef RUBY_INPUT_JOYPAD_SDL
|
||||
#define RUBY_INPUT_JOYPAD_SDL
|
||||
|
||||
namespace ruby {
|
||||
|
||||
struct InputJoypadSDL {
|
||||
struct Joystick {
|
||||
unsigned id = 0;
|
||||
SDL_Joystick* handle = nullptr;
|
||||
};
|
||||
vector<Joystick> joysticks;
|
||||
|
||||
bool poll(int16_t* table) {
|
||||
SDL_JoystickUpdate();
|
||||
for(auto& js : joysticks) {
|
||||
unsigned axes = min((unsigned)Joypad::Axes, SDL_JoystickNumAxes(js.handle));
|
||||
for(unsigned axis = 0; axis < axes; axis++) {
|
||||
table[joypad(js.id).axis(axis)] = (int16_t)SDL_JoystickGetAxis(js.handle, axis);
|
||||
}
|
||||
|
||||
unsigned hats = min((unsigned)Joypad::Hats, SDL_JoystickNumHats(js.handle));
|
||||
for(unsigned hat = 0; hat < hats; hat++) {
|
||||
uint8_t state = SDL_JoystickGetHat(js.handle, hat);
|
||||
int16_t value = 0;
|
||||
if(state & SDL_HAT_UP ) value |= Joypad::HatUp;
|
||||
if(state & SDL_HAT_DOWN ) value |= Joypad::HatDown;
|
||||
if(state & SDL_HAT_LEFT ) value |= Joypad::HatLeft;
|
||||
if(state & SDL_HAT_RIGHT) value |= Joypad::HatRight;
|
||||
table[joypad(js.id).hat(hat)] = value;
|
||||
}
|
||||
|
||||
//there is no SDL_JoystickNumButtons function
|
||||
for(unsigned button = 0; button < Joypad::Buttons; button++) {
|
||||
table[joypad(js.id).button(button)] = (bool)SDL_JoystickGetButton(js.handle, button);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool init() {
|
||||
SDL_InitSubSystem(SDL_INIT_JOYSTICK);
|
||||
SDL_JoystickEventState(SDL_IGNORE);
|
||||
|
||||
unsigned joystickCount = SDL_NumJoysticks();
|
||||
for(unsigned id = 0; id < joystickCount; id++) {
|
||||
Joystick joystick;
|
||||
joystick.id = id;
|
||||
joystick.handle = SDL_JoystickOpen(id);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void term() {
|
||||
for(auto& js : joysticks) {
|
||||
SDL_JoystickClose(js.handle);
|
||||
}
|
||||
joysticks.reset();
|
||||
SDL_QuitSubSystem(SDL_INIT_JOYSTICK);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
|
@ -1,3 +1,6 @@
|
|||
#ifndef RUBY_INPUT_JOYPAD_UDEV
|
||||
#define RUBY_INPUT_JOYPAD_UDEV
|
||||
|
||||
namespace ruby {
|
||||
|
||||
struct InputJoypadUdev {
|
||||
|
@ -21,9 +24,13 @@ struct InputJoypadUdev {
|
|||
};
|
||||
|
||||
struct Joystick {
|
||||
string path;
|
||||
dev_t device = 0;
|
||||
HID::Joypad hid;
|
||||
|
||||
int fd = -1;
|
||||
dev_t device = 0;
|
||||
string deviceName;
|
||||
string devicePath;
|
||||
|
||||
uint8_t evbit[(EV_MAX + 7) / 8] = {0};
|
||||
uint8_t keybit[(KEY_MAX + 7) / 8] = {0};
|
||||
uint8_t absbit[(ABS_MAX + 7) / 8] = {0};
|
||||
|
@ -45,6 +52,48 @@ struct InputJoypadUdev {
|
|||
};
|
||||
vector<Joystick> joysticks;
|
||||
|
||||
void assign(HID::Joypad& hid, unsigned groupID, unsigned inputID, int16_t value) {
|
||||
auto& group = hid.group[groupID];
|
||||
if(group.input[inputID].value == value) return;
|
||||
if(input.onChange) input.onChange(hid, groupID, inputID, group.input[inputID].value, value);
|
||||
group.input[inputID].value = value;
|
||||
}
|
||||
|
||||
void poll(vector<HID::Device*>& devices) {
|
||||
for(auto& js : joysticks) {
|
||||
input_event events[32];
|
||||
signed length = 0;
|
||||
while((length = read(js.fd, events, sizeof(events))) > 0) {
|
||||
length /= sizeof(input_event);
|
||||
for(unsigned i = 0; i < length; i++) {
|
||||
signed code = events[i].code;
|
||||
signed type = events[i].type;
|
||||
signed value = events[i].value;
|
||||
|
||||
if(type == EV_ABS) {
|
||||
if(auto input = js.axes.find({code})) {
|
||||
signed range = input().info.maximum - input().info.minimum;
|
||||
value = (value - input().info.minimum) * 65535ll / range - 32767;
|
||||
assign(js.hid, HID::Joypad::GroupID::Axis, input().id, sclamp<16>(value));
|
||||
} else if(auto input = js.hats.find({code})) {
|
||||
signed range = input().info.maximum - input().info.minimum;
|
||||
value = (value - input().info.minimum) * 65535ll / range - 32767;
|
||||
assign(js.hid, HID::Joypad::GroupID::Hat, input().id, sclamp<16>(value));
|
||||
}
|
||||
} else if(type == EV_KEY) {
|
||||
if(code >= BTN_MISC) {
|
||||
if(auto input = js.buttons.find({code})) {
|
||||
assign(js.hid, HID::Joypad::GroupID::Button, input().id, (bool)value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
devices.append(&js.hid);
|
||||
}
|
||||
}
|
||||
|
||||
bool poll(int16_t* table) {
|
||||
unsigned i = 0;
|
||||
for(auto& js : joysticks) {
|
||||
|
@ -121,18 +170,18 @@ struct InputJoypadUdev {
|
|||
return true;
|
||||
}
|
||||
|
||||
void rumble(unsigned id, bool enable) {
|
||||
if(id >= joysticks.size()) return;
|
||||
void rumble(uint64_t id, bool enable) {
|
||||
for(auto& js : joysticks) {
|
||||
if(js.hid.id != id) continue;
|
||||
if(js.hid.rumble == false) continue;
|
||||
|
||||
Joystick& js = joysticks[id];
|
||||
if(js.rumble == false) return;
|
||||
|
||||
input_event play;
|
||||
memset(&play, 0, sizeof(input_event));
|
||||
play.type = EV_FF;
|
||||
play.code = js.effectID;
|
||||
play.value = enable;
|
||||
write(js.fd, &play, sizeof(input_event));
|
||||
input_event play;
|
||||
memset(&play, 0, sizeof(input_event));
|
||||
play.type = EV_FF;
|
||||
play.code = js.effectID;
|
||||
play.value = enable;
|
||||
write(js.fd, &play, sizeof(input_event));
|
||||
}
|
||||
}
|
||||
|
||||
bool init() {
|
||||
|
@ -167,15 +216,15 @@ struct InputJoypadUdev {
|
|||
}
|
||||
|
||||
private:
|
||||
void createJoystick(udev_device* device, const char* path) {
|
||||
void createJoystick(udev_device* device, const char* devicePath) {
|
||||
Joystick js;
|
||||
js.path = path;
|
||||
js.devicePath = devicePath;
|
||||
|
||||
struct stat st;
|
||||
if(stat(path, &st) < 0) return;
|
||||
if(stat(devicePath, &st) < 0) return;
|
||||
js.device = st.st_rdev;
|
||||
|
||||
js.fd = open(path, O_RDWR | O_NONBLOCK);
|
||||
js.fd = open(devicePath, O_RDWR | O_NONBLOCK);
|
||||
if(js.fd < 0) return;
|
||||
|
||||
uint8_t evbit[(EV_MAX + 7) / 8] = {0};
|
||||
|
@ -199,6 +248,7 @@ private:
|
|||
if(js.vendorID == udev_device_get_sysattr_value(root, "idVendor")
|
||||
&& js.productID == udev_device_get_sysattr_value(root, "idProduct")
|
||||
) {
|
||||
js.deviceName = udev_device_get_devpath(root);
|
||||
js.manufacturer = udev_device_get_sysattr_value(root, "manufacturer");
|
||||
js.product = udev_device_get_sysattr_value(root, "product");
|
||||
js.serial = udev_device_get_sysattr_value(root, "serial");
|
||||
|
@ -244,11 +294,24 @@ private:
|
|||
js.effectID = effect.id;
|
||||
}
|
||||
|
||||
createJoystickHID(js);
|
||||
joysticks.append(js);
|
||||
}
|
||||
|
||||
#undef testBit
|
||||
}
|
||||
|
||||
void createJoystickHID(Joystick& js) {
|
||||
uint64_t pathID = crc32_calculate((const uint8_t*)js.deviceName.data(), js.deviceName.size());
|
||||
js.hid.id = pathID << 32 | hex(js.vendorID) << 16 | hex(js.productID) << 0;
|
||||
|
||||
for(unsigned n = 0; n < js.axes.size(); n++) js.hid.axis.append({n});
|
||||
for(unsigned n = 0; n < js.hats.size(); n++) js.hid.hat.append({n});
|
||||
for(unsigned n = 0; n < js.buttons.size(); n++) js.hid.button.append({n});
|
||||
js.hid.rumble = js.rumble;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
#ifndef RUBY_INPUT_JOYPAD_XINPUT
|
||||
#define RUBY_INPUT_JOYPAD_XINPUT
|
||||
|
||||
#include <xinput.h>
|
||||
|
||||
namespace ruby {
|
||||
|
@ -99,3 +102,5 @@ struct InputJoypadXInput {
|
|||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,9 +1,21 @@
|
|||
#ifndef RUBY_INPUT_KEYBOARD_XLIB
|
||||
#define RUBY_INPUT_KEYBOARD_XLIB
|
||||
|
||||
namespace ruby {
|
||||
|
||||
struct InputKeyboardXlib {
|
||||
HID::Keyboard hid;
|
||||
|
||||
Display* display = nullptr;
|
||||
uint8_t scancode[256] = {0};
|
||||
|
||||
struct Key {
|
||||
string name;
|
||||
unsigned keysym;
|
||||
unsigned keycode;
|
||||
};
|
||||
vector<Key> keys;
|
||||
|
||||
enum XScancode : unsigned {
|
||||
Escape, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12,
|
||||
ScrollLock, Pause, Tilde,
|
||||
|
@ -18,8 +30,28 @@ struct InputKeyboardXlib {
|
|||
Up, Down, Left, Right,
|
||||
Tab, Return, Spacebar, Menu,
|
||||
LeftShift, RightShift, LeftControl, RightControl, LeftAlt, RightAlt, LeftSuper, RightSuper,
|
||||
Limit,
|
||||
};
|
||||
|
||||
void assign(unsigned inputID, bool value) {
|
||||
auto& group = hid.group[HID::Keyboard::GroupID::Button];
|
||||
if(group.input[inputID].value == value) return;
|
||||
if(input.onChange) input.onChange(hid, HID::Keyboard::GroupID::Button, inputID, group.input[inputID].value, value);
|
||||
group.input[inputID].value = value;
|
||||
}
|
||||
|
||||
void poll(vector<HID::Device*>& devices) {
|
||||
char state[32];
|
||||
XQueryKeymap(display, state);
|
||||
|
||||
for(unsigned n = 0; n < keys.size(); n++) {
|
||||
bool value = state[keys[n].keycode >> 3] & (1 << (keys[n].keycode & 7));
|
||||
assign(n, value);
|
||||
}
|
||||
|
||||
devices.append(&hid);
|
||||
}
|
||||
|
||||
bool poll(int16_t* table) {
|
||||
char state[32];
|
||||
XQueryKeymap(display, state);
|
||||
|
@ -146,6 +178,127 @@ struct InputKeyboardXlib {
|
|||
bool init() {
|
||||
display = XOpenDisplay(0);
|
||||
|
||||
keys.append({"Escape", XK_Escape});
|
||||
|
||||
keys.append({"F1", XK_F1});
|
||||
keys.append({"F2", XK_F2});
|
||||
keys.append({"F3", XK_F3});
|
||||
keys.append({"F4", XK_F4});
|
||||
keys.append({"F5", XK_F5});
|
||||
keys.append({"F6", XK_F6});
|
||||
keys.append({"F7", XK_F7});
|
||||
keys.append({"F8", XK_F8});
|
||||
keys.append({"F9", XK_F9});
|
||||
keys.append({"F10", XK_F10});
|
||||
keys.append({"F11", XK_F11});
|
||||
keys.append({"F12", XK_F12});
|
||||
|
||||
keys.append({"ScrollLock", XK_Scroll_Lock});
|
||||
keys.append({"Pause", XK_Pause});
|
||||
|
||||
keys.append({"Tilde", XK_asciitilde});
|
||||
|
||||
keys.append({"Num0", XK_0});
|
||||
keys.append({"Num1", XK_1});
|
||||
keys.append({"Num2", XK_2});
|
||||
keys.append({"Num3", XK_3});
|
||||
keys.append({"Num4", XK_4});
|
||||
keys.append({"Num5", XK_5});
|
||||
keys.append({"Num6", XK_6});
|
||||
keys.append({"Num7", XK_7});
|
||||
keys.append({"Num8", XK_8});
|
||||
keys.append({"Num9", XK_9});
|
||||
|
||||
keys.append({"Dash", XK_minus});
|
||||
keys.append({"Equal", XK_equal});
|
||||
keys.append({"Backspace", XK_BackSpace});
|
||||
|
||||
keys.append({"Insert", XK_Insert});
|
||||
keys.append({"Delete", XK_Delete});
|
||||
keys.append({"Home", XK_Home});
|
||||
keys.append({"End", XK_End});
|
||||
keys.append({"PageUp", XK_Prior});
|
||||
keys.append({"PageDown", XK_Next});
|
||||
|
||||
keys.append({"A", XK_A});
|
||||
keys.append({"B", XK_B});
|
||||
keys.append({"C", XK_C});
|
||||
keys.append({"D", XK_D});
|
||||
keys.append({"E", XK_E});
|
||||
keys.append({"F", XK_F});
|
||||
keys.append({"G", XK_G});
|
||||
keys.append({"H", XK_H});
|
||||
keys.append({"I", XK_I});
|
||||
keys.append({"J", XK_J});
|
||||
keys.append({"K", XK_K});
|
||||
keys.append({"L", XK_L});
|
||||
keys.append({"M", XK_M});
|
||||
keys.append({"N", XK_N});
|
||||
keys.append({"O", XK_O});
|
||||
keys.append({"P", XK_P});
|
||||
keys.append({"Q", XK_Q});
|
||||
keys.append({"R", XK_R});
|
||||
keys.append({"S", XK_S});
|
||||
keys.append({"T", XK_T});
|
||||
keys.append({"U", XK_U});
|
||||
keys.append({"V", XK_V});
|
||||
keys.append({"W", XK_W});
|
||||
keys.append({"X", XK_X});
|
||||
keys.append({"Y", XK_Y});
|
||||
keys.append({"Z", XK_Z});
|
||||
|
||||
keys.append({"LeftBracket", XK_bracketleft});
|
||||
keys.append({"RightBracket", XK_bracketright});
|
||||
keys.append({"Backslash", XK_backslash});
|
||||
keys.append({"Semicolon", XK_semicolon});
|
||||
keys.append({"Apostrophe", XK_apostrophe});
|
||||
keys.append({"Comma", XK_comma});
|
||||
keys.append({"Period", XK_period});
|
||||
keys.append({"Slash", XK_slash});
|
||||
|
||||
keys.append({"Keypad0", XK_KP_0});
|
||||
keys.append({"Keypad1", XK_KP_1});
|
||||
keys.append({"Keypad2", XK_KP_2});
|
||||
keys.append({"Keypad3", XK_KP_3});
|
||||
keys.append({"Keypad4", XK_KP_4});
|
||||
keys.append({"Keypad5", XK_KP_5});
|
||||
keys.append({"Keypad6", XK_KP_6});
|
||||
keys.append({"Keypad7", XK_KP_7});
|
||||
keys.append({"Keypad8", XK_KP_8});
|
||||
keys.append({"Keypad9", XK_KP_9});
|
||||
|
||||
keys.append({"Add", XK_KP_Add});
|
||||
keys.append({"Subtract", XK_KP_Subtract});
|
||||
keys.append({"Multiply", XK_KP_Multiply});
|
||||
keys.append({"Divide", XK_KP_Divide});
|
||||
keys.append({"Enter", XK_KP_Enter});
|
||||
|
||||
keys.append({"Up", XK_Up});
|
||||
keys.append({"Down", XK_Down});
|
||||
keys.append({"Left", XK_Left});
|
||||
keys.append({"Right", XK_Right});
|
||||
|
||||
keys.append({"Tab", XK_Tab});
|
||||
keys.append({"Return", XK_Return});
|
||||
keys.append({"Spacebar", XK_space});
|
||||
|
||||
keys.append({"LeftControl", XK_Control_L});
|
||||
keys.append({"RightControl", XK_Control_R});
|
||||
keys.append({"LeftAlt", XK_Alt_L});
|
||||
keys.append({"RightAlt", XK_Alt_R});
|
||||
keys.append({"LeftShift", XK_Shift_L});
|
||||
keys.append({"RightShift", XK_Shift_R});
|
||||
keys.append({"LeftSuper", XK_Super_L});
|
||||
keys.append({"RightSuper", XK_Super_R});
|
||||
keys.append({"Menu", XK_Menu});
|
||||
|
||||
hid.id = 1;
|
||||
|
||||
for(unsigned n = 0; n < keys.size(); n++) {
|
||||
hid.button.append(keys[n].name);
|
||||
keys[n].keycode = XKeysymToKeycode(display, keys[n].keysym);
|
||||
}
|
||||
|
||||
#define assign(x, y) scancode[x] = XKeysymToKeycode(display, y)
|
||||
assign(Escape, XK_Escape);
|
||||
|
||||
|
@ -275,3 +428,5 @@ struct InputKeyboardXlib {
|
|||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,6 +1,11 @@
|
|||
#ifndef RUBY_INPUT_MOUSE_XLIB
|
||||
#define RUBY_INPUT_MOUSE_XLIB
|
||||
|
||||
namespace ruby {
|
||||
|
||||
struct InputMouseXlib {
|
||||
HID::Mouse hid;
|
||||
|
||||
uintptr_t handle = 0;
|
||||
|
||||
Display* display = nullptr;
|
||||
|
@ -51,6 +56,52 @@ struct InputMouseXlib {
|
|||
return ms.acquired;
|
||||
}
|
||||
|
||||
void assign(unsigned groupID, unsigned inputID, int16_t value) {
|
||||
auto& group = hid.group[groupID];
|
||||
if(group.input[inputID].value == value) return;
|
||||
if(input.onChange) input.onChange(hid, groupID, inputID, group.input[inputID].value, value);
|
||||
group.input[inputID].value = value;
|
||||
}
|
||||
|
||||
void poll(vector<HID::Device*>& devices) {
|
||||
Window rootReturn;
|
||||
Window childReturn;
|
||||
signed rootXReturn = 0;
|
||||
signed rootYReturn = 0;
|
||||
signed windowXReturn = 0;
|
||||
signed windowYReturn = 0;
|
||||
unsigned maskReturn = 0;
|
||||
XQueryPointer(display, handle, &rootReturn, &childReturn, &rootXReturn, &rootYReturn, &windowXReturn, &windowYReturn, &maskReturn);
|
||||
|
||||
if(acquired()) {
|
||||
XWindowAttributes attributes;
|
||||
XGetWindowAttributes(display, handle, &attributes);
|
||||
|
||||
//absolute -> relative conversion
|
||||
assign(HID::Mouse::GroupID::Axis, 0, (int16_t)(rootXReturn - screenWidth / 2));
|
||||
assign(HID::Mouse::GroupID::Axis, 1, (int16_t)(rootYReturn - screenHeight / 2));
|
||||
|
||||
if(hid.axis.input[0].value != 0 || hid.axis.input[1].value != 0) {
|
||||
//if mouse moved, re-center mouse for next poll
|
||||
XWarpPointer(display, None, rootWindow, 0, 0, 0, 0, screenWidth / 2, screenHeight / 2);
|
||||
}
|
||||
} else {
|
||||
assign(HID::Mouse::GroupID::Axis, 0, (int16_t)(rootXReturn - ms.relativeX));
|
||||
assign(HID::Mouse::GroupID::Axis, 1, (int16_t)(rootYReturn - ms.relativeY));
|
||||
|
||||
ms.relativeX = rootXReturn;
|
||||
ms.relativeY = rootYReturn;
|
||||
}
|
||||
|
||||
assign(HID::Mouse::GroupID::Button, 0, (bool)(maskReturn & Button1Mask));
|
||||
assign(HID::Mouse::GroupID::Button, 1, (bool)(maskReturn & Button2Mask));
|
||||
assign(HID::Mouse::GroupID::Button, 2, (bool)(maskReturn & Button3Mask));
|
||||
assign(HID::Mouse::GroupID::Button, 3, (bool)(maskReturn & Button4Mask));
|
||||
assign(HID::Mouse::GroupID::Button, 4, (bool)(maskReturn & Button5Mask));
|
||||
|
||||
devices.append(&hid);
|
||||
}
|
||||
|
||||
bool poll(int16_t* table) {
|
||||
Window rootReturn;
|
||||
Window childReturn;
|
||||
|
@ -115,6 +166,17 @@ struct InputMouseXlib {
|
|||
ms.relativeX = 0;
|
||||
ms.relativeY = 0;
|
||||
|
||||
hid.id = 2;
|
||||
|
||||
hid.axis.append({"X"});
|
||||
hid.axis.append({"Y"});
|
||||
|
||||
hid.button.append({"Left"});
|
||||
hid.button.append({"Middle"});
|
||||
hid.button.append({"Right"});
|
||||
hid.button.append({"Up"});
|
||||
hid.button.append({"Down"});
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -126,3 +188,5 @@ struct InputMouseXlib {
|
|||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,37 +1,20 @@
|
|||
//================
|
||||
//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 "keyboard/xlib.cpp"
|
||||
#include "mouse/xlib.cpp"
|
||||
#include "joypad/sdl.cpp"
|
||||
|
||||
namespace ruby {
|
||||
|
||||
struct pInputSDL {
|
||||
#include "xlibkeys.hpp"
|
||||
InputKeyboardXlib xlibKeyboard;
|
||||
InputMouseXlib xlibMouse;
|
||||
InputJoypadSDL sdl;
|
||||
|
||||
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;
|
||||
struct Settings {
|
||||
uintptr_t handle = 0;
|
||||
} settings;
|
||||
|
||||
bool cap(const string& name) {
|
||||
|
@ -57,117 +40,21 @@ struct pInputSDL {
|
|||
}
|
||||
|
||||
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;
|
||||
}
|
||||
return xlibMouse.acquire();
|
||||
}
|
||||
|
||||
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;
|
||||
return xlibMouse.unacquire();
|
||||
}
|
||||
|
||||
bool acquired() {
|
||||
return device.mouseacquired;
|
||||
return xlibMouse.acquired();
|
||||
}
|
||||
|
||||
bool poll(int16_t* table) {
|
||||
memset(table, 0, Scancode::Limit * sizeof(int16_t));
|
||||
|
||||
//========
|
||||
//Keyboard
|
||||
//========
|
||||
|
||||
x_poll(device.display, 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);
|
||||
}
|
||||
}
|
||||
|
||||
xlibKeyboard.poll(table);
|
||||
xlibMouse.poll(table);
|
||||
sdl.poll(table);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -175,56 +62,16 @@ struct pInputSDL {
|
|||
}
|
||||
|
||||
bool 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;
|
||||
x_init(device.display);
|
||||
|
||||
//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);
|
||||
|
||||
if(xlibKeyboard.init() == false) return false;
|
||||
if(xlibMouse.init(settings.handle) == false) return false;
|
||||
if(sdl.init() == false) return false;
|
||||
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;
|
||||
xlibKeyboard.term();
|
||||
xlibMouse.term();
|
||||
sdl.term();
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -57,13 +57,22 @@ struct pInputUdev {
|
|||
return xlibMouse.acquired();
|
||||
}
|
||||
|
||||
vector<HID::Device*> poll() {
|
||||
vector<HID::Device*> devices;
|
||||
xlibKeyboard.poll(devices);
|
||||
xlibMouse.poll(devices);
|
||||
udev.poll(devices);
|
||||
return devices;
|
||||
}
|
||||
|
||||
bool poll(int16_t* table) {
|
||||
xlibKeyboard.poll(table);
|
||||
xlibMouse.poll(table);
|
||||
udev.poll(table);
|
||||
return true;
|
||||
}
|
||||
|
||||
void rumble(unsigned id, bool enable) {
|
||||
void rumble(uint64_t id, bool enable) {
|
||||
udev.rumble(id, enable);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,53 +0,0 @@
|
|||
#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(display, table);
|
||||
return true;
|
||||
}
|
||||
|
||||
void rumble(unsigned id, bool enable) {
|
||||
}
|
||||
|
||||
bool init() {
|
||||
display = XOpenDisplay(0);
|
||||
x_init(display);
|
||||
return true;
|
||||
}
|
||||
|
||||
void term() {
|
||||
XCloseDisplay(display);
|
||||
}
|
||||
};
|
||||
|
||||
DeclareInput(X)
|
||||
|
||||
}
|
|
@ -0,0 +1,75 @@
|
|||
#include <sys/ipc.h>
|
||||
#include <sys/shm.h>
|
||||
#include <X11/Xlib.h>
|
||||
#include <X11/Xutil.h>
|
||||
#include <X11/Xatom.h>
|
||||
|
||||
#include "keyboard/xlib.cpp"
|
||||
#include "mouse/xlib.cpp"
|
||||
|
||||
namespace ruby {
|
||||
|
||||
struct pInputXlib {
|
||||
InputKeyboardXlib xlibKeyboard;
|
||||
InputMouseXlib xlibMouse;
|
||||
|
||||
struct Settings {
|
||||
uintptr_t handle = 0;
|
||||
} settings;
|
||||
|
||||
bool cap(const string& name) {
|
||||
if(name == Input::KeyboardSupport) return true;
|
||||
if(name == Input::MouseSupport) 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() {
|
||||
return xlibMouse.acquire();
|
||||
}
|
||||
|
||||
bool unacquire() {
|
||||
return xlibMouse.unacquire();
|
||||
}
|
||||
|
||||
bool acquired() {
|
||||
return xlibMouse.acquired();
|
||||
}
|
||||
|
||||
bool poll(int16_t* table) {
|
||||
xlibKeyboard.poll(table);
|
||||
xlibMouse.poll(table);
|
||||
return true;
|
||||
}
|
||||
|
||||
void rumble(unsigned id, bool enable) {
|
||||
}
|
||||
|
||||
bool init() {
|
||||
if(xlibKeyboard.init() == false) return false;
|
||||
if(xlibMouse.init(settings.handle) == false) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
void term() {
|
||||
xlibKeyboard.term();
|
||||
xlibMouse.term();
|
||||
}
|
||||
};
|
||||
|
||||
DeclareInput(Xlib)
|
||||
|
||||
}
|
|
@ -1,263 +0,0 @@
|
|||
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(Display* display, int16_t* table) {
|
||||
if(!display) return;
|
||||
|
||||
char state[32];
|
||||
XQueryKeymap(display, state);
|
||||
|
||||
#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) {
|
||||
if(!display) return;
|
||||
|
||||
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
|
||||
}
|
|
@ -395,8 +395,8 @@ void InputInterface::driver(const char* driver) {
|
|||
else if(!strcmp(driver, "SDL")) p = new InputSDL();
|
||||
#endif
|
||||
|
||||
#ifdef INPUT_X
|
||||
else if(!strcmp(driver, "X-Windows")) p = new InputX();
|
||||
#ifdef INPUT_XLIB
|
||||
else if(!strcmp(driver, "Xlib")) p = new InputXlib();
|
||||
#endif
|
||||
|
||||
else p = new Input();
|
||||
|
@ -415,8 +415,8 @@ const char* InputInterface::optimalDriver() {
|
|||
return "udev";
|
||||
#elif defined(INPUT_SDL)
|
||||
return "SDL";
|
||||
#elif defined(INPUT_X)
|
||||
return "X-Windows";
|
||||
#elif defined(INPUT_XLIB)
|
||||
return "Xlib";
|
||||
|
||||
#else
|
||||
return "None";
|
||||
|
@ -436,8 +436,8 @@ const char* InputInterface::safestDriver() {
|
|||
return "udev";
|
||||
#elif defined(INPUT_SDL)
|
||||
return "SDL";
|
||||
#elif defined(INPUT_X)
|
||||
return "X-Windows";
|
||||
#elif defined(INPUT_XLIB)
|
||||
return "Xlib";
|
||||
|
||||
#else
|
||||
return "none";
|
||||
|
@ -473,8 +473,8 @@ const char* InputInterface::availableDrivers() {
|
|||
"SDL;"
|
||||
#endif
|
||||
|
||||
#if defined(INPUT_X)
|
||||
"X-Windows;"
|
||||
#if defined(INPUT_XLIB)
|
||||
"Xlib;"
|
||||
#endif
|
||||
|
||||
"None";
|
||||
|
@ -499,8 +499,9 @@ bool InputInterface::set(const string& name, const any& value) { return p ? p->s
|
|||
bool InputInterface::acquire() { return p ? p->acquire() : false; }
|
||||
bool InputInterface::unacquire() { return p ? p->unacquire() : false; }
|
||||
bool InputInterface::acquired() { return p ? p->acquired() : false; }
|
||||
vector<HID::Device*> InputInterface::poll() { return p ? p->poll() : vector<HID::Device*>(); }
|
||||
bool InputInterface::poll(int16_t* table) { return p ? p->poll(table) : false; }
|
||||
void InputInterface::rumble(unsigned id, bool enable) { if(p) return p->rumble(id, enable); }
|
||||
void InputInterface::rumble(uint64_t id, bool enable) { if(p) return p->rumble(id, enable); }
|
||||
InputInterface::InputInterface() : p(nullptr) {}
|
||||
InputInterface::~InputInterface() { term(); }
|
||||
|
||||
|
|
|
@ -63,6 +63,8 @@ private:
|
|||
};
|
||||
|
||||
struct InputInterface {
|
||||
nall::function<void (nall::HID::Device& device, unsigned group, unsigned input, int16_t oldValue, int16_t newValue)> onChange;
|
||||
|
||||
void driver(const char* driver = "");
|
||||
const char* optimalDriver();
|
||||
const char* safestDriver();
|
||||
|
@ -78,8 +80,9 @@ struct InputInterface {
|
|||
bool unacquire();
|
||||
bool acquired();
|
||||
|
||||
nall::vector<nall::HID::Device*> poll();
|
||||
bool poll(int16_t* table);
|
||||
void rumble(unsigned id, bool enable);
|
||||
void rumble(uint64_t id, bool enable);
|
||||
|
||||
InputInterface();
|
||||
~InputInterface();
|
||||
|
|
|
@ -25,7 +25,7 @@ else ifeq ($(platform),macosx)
|
|||
else ifeq ($(platform),linux)
|
||||
ruby := video.glx video.xv video.xshm video.sdl
|
||||
ruby += audio.alsa audio.openal audio.oss audio.pulseaudio audio.pulseaudiosimple audio.ao
|
||||
ruby += input.udev input.sdl input.x
|
||||
ruby += input.udev
|
||||
else ifeq ($(platform),bsd)
|
||||
ruby := video.glx
|
||||
ruby += audio.openal audio.oss
|
||||
|
|
|
@ -2,7 +2,7 @@ void InputManager::appendHotkeys() {
|
|||
{
|
||||
auto hotkey = new HotkeyInput;
|
||||
hotkey->name = "Toggle Fullscreen Mode";
|
||||
hotkey->mapping = "KB0::F11";
|
||||
hotkey->mapping = "1/Button/F11";
|
||||
|
||||
hotkey->press = [] {
|
||||
utility->toggleFullScreen();
|
||||
|
|
|
@ -1,82 +1,82 @@
|
|||
#include "../ethos.hpp"
|
||||
#include "hotkeys.cpp"
|
||||
InputManager* inputManager = nullptr;
|
||||
HID::Null hidNull;
|
||||
|
||||
void AbstractInput::bind() {
|
||||
inputList.reset();
|
||||
lstring list = mapping.split(",");
|
||||
|
||||
for(auto& mapping : list) {
|
||||
Input::Type type;
|
||||
if(mapping.endsWith(".Up")) type = Input::Type::HatUp;
|
||||
else if(mapping.endsWith(".Down")) type = Input::Type::HatDown;
|
||||
else if(mapping.endsWith(".Left")) type = Input::Type::HatLeft;
|
||||
else if(mapping.endsWith(".Right")) type = Input::Type::HatRight;
|
||||
else if(mapping.endsWith(".Lo")) type = Input::Type::AxisLo;
|
||||
else if(mapping.endsWith(".Hi")) type = Input::Type::AxisHi;
|
||||
else if(mapping.beginsWith("JP") && mapping.find("Axis")) type = Input::Type::Axis;
|
||||
else if(mapping.beginsWith("JP") && mapping.endsWith("Rumble")) type = Input::Type::Rumble;
|
||||
else if(mapping.beginsWith("MS") && mapping.endsWith("axis")) type = Input::Type::MouseAxis;
|
||||
else if(mapping.beginsWith("MS")) type = Input::Type::MouseButton;
|
||||
else type = Input::Type::Button;
|
||||
lstring values = mapping.split("/");
|
||||
if(values.size() == 1) continue; //skip "None" mapping
|
||||
|
||||
if(type == Input::Type::Rumble) {
|
||||
unsigned joypad = mapping[2] - '0';
|
||||
inputList.append({type, joypad});
|
||||
} else {
|
||||
string decode = mapping;
|
||||
if(auto position = decode.find(".")) decode.resize(position());
|
||||
unsigned scancode = Scancode::decode(decode);
|
||||
inputList.append({type, scancode});
|
||||
uint64_t id = hex(values[0]);
|
||||
string group = values(1, "");
|
||||
string input = values(2, "");
|
||||
string qualifier = values(3, "");
|
||||
|
||||
Input item;
|
||||
for(auto device : inputManager->devices) {
|
||||
if(id != device->id) continue;
|
||||
if(group == "Rumble") {
|
||||
item.device = device;
|
||||
item.id = id;
|
||||
item.group = 0;
|
||||
item.input = 0;
|
||||
break;
|
||||
}
|
||||
if(auto groupID = device->find(group)) {
|
||||
if(auto inputID = device->group[groupID()].find(input)) {
|
||||
item.device = device;
|
||||
item.id = id;
|
||||
item.group = groupID();
|
||||
item.input = inputID();
|
||||
item.qualifier = Input::Qualifier::None;
|
||||
if(qualifier == "Lo") item.qualifier = Input::Qualifier::Lo;
|
||||
if(qualifier == "Hi") item.qualifier = Input::Qualifier::Hi;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(item.device == nullptr) continue;
|
||||
|
||||
inputList.append(item);
|
||||
}
|
||||
}
|
||||
|
||||
bool AbstractInput::append(string encode) {
|
||||
if(mapping.find(encode)) return true; //mapping already bound
|
||||
lstring mappings = mapping.split(",");
|
||||
if(mappings.find(encode)) return true; //mapping already bound
|
||||
if(mapping.empty() || mapping == "None") mapping = encode; //remove "None"
|
||||
else mapping.append(",", encode); //add to existing mapping list
|
||||
bind();
|
||||
return true;
|
||||
}
|
||||
|
||||
AbstractInput::AbstractInput() : state(false) {
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
bool DigitalInput::bind(unsigned scancode, int16_t value) {
|
||||
using nall::Keyboard;
|
||||
using nall::Mouse;
|
||||
|
||||
if(scancode == Scancode::None || scancode == keyboard(0)[Keyboard::Escape]) {
|
||||
bool DigitalInput::bind(HID::Device& device, unsigned group, unsigned input, int16_t oldValue, int16_t newValue) {
|
||||
if(device.isNull() || (device.isKeyboard() && device.group[group].input[input].name == "Escape")) {
|
||||
inputList.reset();
|
||||
mapping = "None";
|
||||
return true;
|
||||
}
|
||||
|
||||
string encode = Scancode::encode(scancode);
|
||||
string encode = {hex(device.id), "/", device.group[group].name, "/", device.group[group].input[input].name};
|
||||
|
||||
if(Keyboard::isAnyKey(scancode) || Keyboard::isAnyModifier(scancode) || Joypad::isAnyButton(scancode)) {
|
||||
if(value == 0) return false;
|
||||
return append(encode);
|
||||
if((device.isKeyboard() && group == HID::Keyboard::GroupID::Button)
|
||||
|| (device.isMouse() && group == HID::Mouse::GroupID::Button)
|
||||
|| (device.isJoypad() && group == HID::Joypad::GroupID::Button)
|
||||
) {
|
||||
if(newValue != 0) return append(encode);
|
||||
}
|
||||
|
||||
if(Mouse::isAnyButton(scancode)) {
|
||||
if(value == 0) return false;
|
||||
return append(encode);
|
||||
}
|
||||
|
||||
if(Joypad::isAnyHat(scancode)) {
|
||||
if(value & Joypad::HatUp ) { encode.append(".Up" ); return append(encode); }
|
||||
if(value & Joypad::HatDown ) { encode.append(".Down" ); return append(encode); }
|
||||
if(value & Joypad::HatLeft ) { encode.append(".Left" ); return append(encode); }
|
||||
if(value & Joypad::HatRight) { encode.append(".Right"); return append(encode); }
|
||||
}
|
||||
|
||||
if(Joypad::isAnyAxis(scancode)) {
|
||||
if(value < -12288) { encode.append(".Lo"); return append(encode); }
|
||||
if(value > +24576) { encode.append(".Hi"); return append(encode); }
|
||||
if((device.isJoypad() && group == HID::Joypad::GroupID::Axis)
|
||||
|| (device.isJoypad() && group == HID::Joypad::GroupID::Hat)
|
||||
) {
|
||||
if(newValue < -16384) return append({encode, "/Lo"});
|
||||
if(newValue > +16384) return append({encode, "/Hi"});
|
||||
}
|
||||
|
||||
return false;
|
||||
|
@ -84,20 +84,24 @@ bool DigitalInput::bind(unsigned scancode, int16_t value) {
|
|||
|
||||
int16_t DigitalInput::poll() {
|
||||
if(program->focused() == false) return 0;
|
||||
if(inputList.size() == 0) return 0;
|
||||
bool result = logic;
|
||||
|
||||
for(auto& item : inputList) {
|
||||
int16_t value = inputManager->poll(item.scancode);
|
||||
HID::Device& device = *(item.device);
|
||||
int16_t value = device.group[item.group].input[item.input].value;
|
||||
bool output = logic;
|
||||
switch(item.type) {
|
||||
case Input::Type::Button: output = value; break;
|
||||
case Input::Type::MouseButton: output = value & input.acquired(); break;
|
||||
case Input::Type::HatUp: output = value & Joypad::HatUp; break;
|
||||
case Input::Type::HatDown: output = value & Joypad::HatDown; break;
|
||||
case Input::Type::HatLeft: output = value & Joypad::HatLeft; break;
|
||||
case Input::Type::HatRight: output = value & Joypad::HatRight; break;
|
||||
case Input::Type::AxisLo: output = value < -16384; break;
|
||||
case Input::Type::AxisHi: output = value > +16384; break;
|
||||
if((device.isKeyboard() && item.group == HID::Keyboard::GroupID::Button)
|
||||
|| (device.isMouse() && item.group == HID::Mouse::GroupID::Button)
|
||||
|| (device.isJoypad() && item.group == HID::Joypad::GroupID::Button)
|
||||
) {
|
||||
output = value;
|
||||
}
|
||||
if((device.isJoypad() && item.group == HID::Joypad::GroupID::Axis)
|
||||
|| (device.isJoypad() && item.group == HID::Joypad::GroupID::Hat)
|
||||
) {
|
||||
if(item.qualifier == Input::Qualifier::Lo) output = value < -16384;
|
||||
if(item.qualifier == Input::Qualifier::Hi) output = value > +16384;
|
||||
}
|
||||
if(logic == 0) result |= output;
|
||||
if(logic == 1) result &= output;
|
||||
|
@ -108,34 +112,37 @@ int16_t DigitalInput::poll() {
|
|||
|
||||
//
|
||||
|
||||
bool RelativeInput::bind(unsigned scancode, int16_t value) {
|
||||
using nall::Keyboard;
|
||||
using nall::Mouse;
|
||||
|
||||
if(scancode == Scancode::None || scancode == keyboard(0)[Keyboard::Escape]) {
|
||||
bool RelativeInput::bind(HID::Device& device, unsigned group, unsigned input, int16_t oldValue, int16_t newValue) {
|
||||
if(device.isNull() || (device.isKeyboard() && device.group[group].input[input].name == "Escape")) {
|
||||
inputList.reset();
|
||||
mapping = "None";
|
||||
return true;
|
||||
}
|
||||
|
||||
string encode = Scancode::encode(scancode);
|
||||
string encode = {hex(device.id), "/", device.group[group].name, "/", device.group[group].input[input].name};
|
||||
|
||||
if(Mouse::isAnyAxis(scancode)) return append(encode);
|
||||
if(Joypad::isAnyAxis(scancode)) return append(encode);
|
||||
if((device.isMouse() && group == HID::Mouse::GroupID::Axis)
|
||||
|| (device.isJoypad() && group == HID::Joypad::GroupID::Axis)
|
||||
|| (device.isJoypad() && group == HID::Joypad::GroupID::Hat)
|
||||
) {
|
||||
if(newValue < -16384) return append(encode);
|
||||
if(newValue > +16384) return append(encode);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
int16_t RelativeInput::poll() {
|
||||
if(program->focused() == false) return 0;
|
||||
if(inputList.size() == 0) return 0;
|
||||
int16_t result = 0;
|
||||
|
||||
for(auto& item : inputList) {
|
||||
int16_t value = inputManager->poll(item.scancode);
|
||||
switch(item.type) {
|
||||
case Input::Type::MouseAxis: value = input.acquired() ? value : 0; break;
|
||||
case Input::Type::Axis: value = value; break;
|
||||
}
|
||||
HID::Device& device = *(item.device);
|
||||
int16_t value = device.group[item.group].input[item.input].value;
|
||||
if(device.isJoypad() && item.group == HID::Joypad::GroupID::Axis) value >>= 8;
|
||||
if(device.isJoypad() && item.group == HID::Joypad::GroupID::Hat) value = (value < 0 ? -1 : value > 0 ? + 1 : 0);
|
||||
if(device.isMouse() && input.acquired() == false) value = 0;
|
||||
result += value;
|
||||
}
|
||||
|
||||
|
@ -144,105 +151,28 @@ int16_t RelativeInput::poll() {
|
|||
|
||||
//
|
||||
|
||||
bool AbsoluteInput::bind(unsigned scancode, int16_t value) {
|
||||
using nall::Keyboard;
|
||||
using nall::Mouse;
|
||||
|
||||
if(scancode == Scancode::None || scancode == keyboard(0)[Keyboard::Escape]) {
|
||||
bool RumbleInput::bind(HID::Device& device, unsigned group, unsigned input, int16_t oldValue, int16_t newValue) {
|
||||
if(device.isNull() || (device.isKeyboard() && device.group[group].input[input].name == "Escape")) {
|
||||
inputList.reset();
|
||||
mapping = "None";
|
||||
return true;
|
||||
}
|
||||
|
||||
string encode = Scancode::encode(scancode);
|
||||
string encode = {hex(device.id), "/Rumble"};
|
||||
|
||||
if(Mouse::isAnyAxis(scancode)) {
|
||||
//only one input can be assigned for absolute positioning
|
||||
inputList.reset();
|
||||
mapping = encode;
|
||||
return true;
|
||||
if(device.isJoypad() && group == HID::Joypad::GroupID::Button) {
|
||||
if(newValue != 0) return append(encode);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
int16_t AbsoluteInput::poll() {
|
||||
if(program->focused() == false) return -32768;
|
||||
int16_t result = -32768; //offscreen value
|
||||
|
||||
using nall::Mouse;
|
||||
|
||||
Position position = phoenix::Mouse::position();
|
||||
Geometry geometry = presentation->geometry();
|
||||
|
||||
if(position.x < geometry.x
|
||||
|| position.y < geometry.y
|
||||
|| position.x >= geometry.x + geometry.width
|
||||
|| position.y >= geometry.y + geometry.height) {
|
||||
//cursor is offscreen
|
||||
position.x = -32768;
|
||||
position.y = -32768;
|
||||
} else {
|
||||
//convert from screen to viewport coordinates
|
||||
double x = position.x - geometry.x;
|
||||
double y = position.y - geometry.y;
|
||||
|
||||
//scale coordinate range to -0.5 to +0.5 (0.0 = center)
|
||||
x = x * 1.0 / geometry.width - 0.5;
|
||||
y = y * 1.0 / geometry.height - 0.5;
|
||||
|
||||
//scale coordinates to -32767 to +32767
|
||||
signed px = (signed)(x * 65535.0);
|
||||
signed py = (signed)(y * 65535.0);
|
||||
|
||||
//clamp to valid range
|
||||
position.x = max(-32767, min(+32767, px));
|
||||
position.y = max(-32767, min(+32767, py));
|
||||
}
|
||||
|
||||
for(auto& item : inputList) {
|
||||
if(item.scancode == mouse(0)[Mouse::Xaxis]) {
|
||||
result = position.x;
|
||||
}
|
||||
|
||||
if(item.scancode == mouse(0)[Mouse::Yaxis]) {
|
||||
result = position.y;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool RumbleInput::bind(unsigned scancode, int16_t value) {
|
||||
using nall::Keyboard;
|
||||
|
||||
if(scancode == Scancode::None || scancode == keyboard(0)[Keyboard::Escape]) {
|
||||
inputList.reset();
|
||||
mapping = "None";
|
||||
return true;
|
||||
}
|
||||
|
||||
string encode = Scancode::encode(scancode);
|
||||
|
||||
if(Joypad::isAnyButton(scancode)) {
|
||||
if(value == 0) return false;
|
||||
if(auto position = encode.find("::")) encode.resize(position());
|
||||
encode.append("::Rumble");
|
||||
return append(encode);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
int16_t RumbleInput::poll() {
|
||||
return false;
|
||||
}
|
||||
|
||||
void RumbleInput::rumble(bool enable) {
|
||||
if(program->focused() == false) return;
|
||||
if(inputList.size() == 0) return;
|
||||
|
||||
for(auto& item : inputList) {
|
||||
input.rumble(item.scancode, enable);
|
||||
input.rumble(item.id, enable);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -255,48 +185,51 @@ HotkeyInput::HotkeyInput() {
|
|||
|
||||
//
|
||||
|
||||
void InputManager::onChange(HID::Device& device, unsigned group, unsigned input, int16_t oldValue, int16_t newValue) {
|
||||
if(settings->focused()) {
|
||||
inputSettings->inputEvent(device, group, input, oldValue, newValue);
|
||||
hotkeySettings->inputEvent(device, group, input, oldValue, newValue);
|
||||
}
|
||||
}
|
||||
|
||||
HID::Device* InputManager::findMouse() {
|
||||
for(auto device : devices) {
|
||||
if(device->isMouse()) return device;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void InputManager::bind() {
|
||||
for(auto& input : inputMap) input->bind();
|
||||
for(auto& input : hotkeyMap) input->bind();
|
||||
}
|
||||
|
||||
void InputManager::poll() {
|
||||
using nall::Keyboard;
|
||||
|
||||
activeScancode = !activeScancode;
|
||||
if(input.poll(scancode[activeScancode]) == false) return;
|
||||
|
||||
for(unsigned n = 0; n < Scancode::Limit; n++) {
|
||||
if(scancode[0][n] != scancode[1][n]) {
|
||||
if(settings->focused()) {
|
||||
inputSettings->inputEvent(n, scancode[activeScancode][n]);
|
||||
hotkeySettings->inputEvent(n, scancode[activeScancode][n]);
|
||||
}
|
||||
auto devices = input.poll();
|
||||
bool changed = devices.size() != this->devices.size();
|
||||
if(changed == false) {
|
||||
for(unsigned n = 0; n < devices.size(); n++) {
|
||||
changed = devices[n] != this->devices[n];
|
||||
if(changed) break;
|
||||
}
|
||||
}
|
||||
if(changed == true) {
|
||||
this->devices = devices;
|
||||
bind();
|
||||
}
|
||||
|
||||
if(presentation->focused()) pollHotkeys();
|
||||
}
|
||||
|
||||
int16_t InputManager::poll(unsigned scancode) {
|
||||
return this->scancode[activeScancode][scancode];
|
||||
}
|
||||
|
||||
void InputManager::saveConfiguration() {
|
||||
config.save(program->path("input.bml"));
|
||||
}
|
||||
|
||||
InputManager::InputManager() {
|
||||
inputManager = this;
|
||||
scancode[0] = new int16_t[Scancode::Limit]();
|
||||
scancode[1] = new int16_t[Scancode::Limit]();
|
||||
activeScancode = 0;
|
||||
bootstrap();
|
||||
}
|
||||
|
||||
InputManager::~InputManager() {
|
||||
delete[] scancode[0];
|
||||
delete[] scancode[1];
|
||||
input.onChange = {&InputManager::onChange, this};
|
||||
}
|
||||
|
||||
void InputManager::bootstrap() {
|
||||
|
@ -316,8 +249,7 @@ void InputManager::bootstrap() {
|
|||
AbstractInput* abstract = nullptr;
|
||||
if(input.type == 0) abstract = new DigitalInput;
|
||||
if(input.type == 1) abstract = new RelativeInput;
|
||||
if(input.type == 2) abstract = new AbsoluteInput;
|
||||
if(input.type == 3) abstract = new RumbleInput;
|
||||
if(input.type == 2) abstract = new RumbleInput;
|
||||
if(abstract == nullptr) continue;
|
||||
|
||||
abstract->name = string{input.name}.replace(" ", "");
|
||||
|
|
|
@ -1,45 +1,42 @@
|
|||
extern HID::Null hidNull;
|
||||
|
||||
struct AbstractInput {
|
||||
string name;
|
||||
string mapping;
|
||||
bool logic; //0 = OR, 1 = AND
|
||||
bool state;
|
||||
bool logic = 0; //0 = OR, 1 = AND
|
||||
bool state = 0;
|
||||
|
||||
struct Input {
|
||||
enum class Type : unsigned { Button, MouseButton, MouseAxis, HatUp, HatDown, HatLeft, HatRight, Axis, AxisLo, AxisHi, Rumble } type;
|
||||
unsigned scancode;
|
||||
HID::Device* device = nullptr;
|
||||
uint64_t id = 0;
|
||||
unsigned group = 0;
|
||||
unsigned input = 0;
|
||||
enum class Qualifier : unsigned { None, Lo, Hi } qualifier;
|
||||
};
|
||||
vector<Input> inputList;
|
||||
|
||||
void bind();
|
||||
bool append(string mapping);
|
||||
virtual bool bind(unsigned scancode, int16_t value) = 0;
|
||||
virtual int16_t poll() = 0;
|
||||
virtual bool bind(HID::Device& device, unsigned group, unsigned input, int16_t oldValue, int16_t newValue) { return false; }
|
||||
virtual int16_t poll() { return 0; }
|
||||
virtual void rumble(bool enable) {}
|
||||
AbstractInput();
|
||||
};
|
||||
|
||||
struct DigitalInput : AbstractInput {
|
||||
using AbstractInput::bind;
|
||||
bool bind(unsigned scancode, int16_t value);
|
||||
bool bind(HID::Device& device, unsigned group, unsigned input, int16_t oldValue, int16_t newValue);
|
||||
int16_t poll();
|
||||
};
|
||||
|
||||
struct RelativeInput : AbstractInput {
|
||||
using AbstractInput::bind;
|
||||
bool bind(unsigned scancode, int16_t value);
|
||||
int16_t poll();
|
||||
};
|
||||
|
||||
struct AbsoluteInput : AbstractInput {
|
||||
using AbstractInput::bind;
|
||||
bool bind(unsigned scancode, int16_t value);
|
||||
bool bind(HID::Device& device, unsigned group, unsigned input, int16_t oldValue, int16_t newValue);
|
||||
int16_t poll();
|
||||
};
|
||||
|
||||
struct RumbleInput : AbstractInput {
|
||||
using AbstractInput::bind;
|
||||
bool bind(unsigned scancode, int16_t value);
|
||||
int16_t poll();
|
||||
bool bind(HID::Device& device, unsigned group, unsigned input, int16_t oldValue, int16_t newValue);
|
||||
void rumble(bool enable);
|
||||
};
|
||||
|
||||
|
@ -50,18 +47,17 @@ struct HotkeyInput : DigitalInput {
|
|||
};
|
||||
|
||||
struct InputManager {
|
||||
vector<HID::Device*> devices;
|
||||
vector<AbstractInput*> inputMap;
|
||||
vector<HotkeyInput*> hotkeyMap;
|
||||
int16_t* scancode[2];
|
||||
bool activeScancode;
|
||||
|
||||
void onChange(HID::Device& device, unsigned group, unsigned input, int16_t oldValue, int16_t newValue);
|
||||
HID::Device* findMouse();
|
||||
void bind();
|
||||
void poll();
|
||||
int16_t poll(unsigned scancode);
|
||||
void saveConfiguration();
|
||||
void bootstrap();
|
||||
InputManager();
|
||||
~InputManager();
|
||||
|
||||
//hotkeys.cpp
|
||||
void appendHotkeys();
|
||||
|
|
|
@ -26,8 +26,6 @@ void HotkeySettings::refresh() {
|
|||
unsigned index = 0;
|
||||
for(auto& hotkey : inputManager->hotkeyMap) {
|
||||
string mapping = hotkey->mapping;
|
||||
mapping.replace("KB0::", "");
|
||||
mapping.replace("MS0::", "Mouse::");
|
||||
mapping.replace(",", " and ");
|
||||
inputList.setText(index++, {hotkey->name, mapping});
|
||||
}
|
||||
|
@ -36,7 +34,7 @@ void HotkeySettings::refresh() {
|
|||
|
||||
void HotkeySettings::eraseInput() {
|
||||
activeInput = inputManager->hotkeyMap[inputList.selection()];
|
||||
inputEvent(Scancode::None, 1);
|
||||
inputEvent(hidNull, 0, 0, 0, 1);
|
||||
}
|
||||
|
||||
void HotkeySettings::assignInput() {
|
||||
|
@ -47,14 +45,11 @@ void HotkeySettings::assignInput() {
|
|||
setEnabled(false);
|
||||
}
|
||||
|
||||
void HotkeySettings::inputEvent(unsigned scancode, int16_t value) {
|
||||
using nall::Mouse;
|
||||
|
||||
void HotkeySettings::inputEvent(HID::Device& device, unsigned group, unsigned input, int16_t oldValue, int16_t newValue) {
|
||||
if(activeInput == nullptr) return;
|
||||
if(value != 1) return;
|
||||
if(Mouse::isAnyButton(scancode) || Mouse::isAnyAxis(scancode)) return;
|
||||
if(Joypad::isAnyAxis(scancode)) return;
|
||||
if(activeInput->bind(scancode, value) == false) return;
|
||||
if(device.isMouse()) return;
|
||||
if(device.isJoypad() && group == HID::Joypad::GroupID::Axis) return;
|
||||
if(activeInput->bind(device, group, input, oldValue, newValue) == false) return;
|
||||
|
||||
activeInput = nullptr;
|
||||
settings->setStatusText("");
|
||||
|
|
|
@ -8,7 +8,7 @@ struct HotkeySettings : SettingsLayout {
|
|||
void refresh();
|
||||
void eraseInput();
|
||||
void assignInput();
|
||||
void inputEvent(unsigned scancode, int16_t value);
|
||||
void inputEvent(HID::Device& device, unsigned group, unsigned input, int16_t oldValue, int16_t newValue);
|
||||
HotkeySettings();
|
||||
|
||||
private:
|
||||
|
|
|
@ -69,8 +69,7 @@ void InputSettings::synchronize() {
|
|||
assign[2].setVisible(true);
|
||||
}
|
||||
|
||||
if(dynamic_cast<RelativeInput*>(selectedInput)
|
||||
|| dynamic_cast<AbsoluteInput*>(selectedInput)) {
|
||||
if(dynamic_cast<RelativeInput*>(selectedInput)) {
|
||||
assign[0].setText("Mouse X-axis");
|
||||
assign[1].setText("Mouse Y-axis");
|
||||
assign[0].setVisible(true);
|
||||
|
@ -123,8 +122,6 @@ void InputSettings::inputChanged() {
|
|||
auto& input = activeDevice().input[number];
|
||||
auto abstract = inputManager->inputMap(input.guid);
|
||||
string mapping = abstract->mapping;
|
||||
mapping.replace("KB0::", "");
|
||||
mapping.replace("MS0::", "Mouse::");
|
||||
mapping.replace(",", " or ");
|
||||
inputList.setText(index++, {input.name, mapping});
|
||||
}
|
||||
|
@ -138,7 +135,7 @@ void InputSettings::resetInput() {
|
|||
unsigned length = device.input.size();
|
||||
for(unsigned n = 0; n < length; n++) {
|
||||
activeInput = inputManager->inputMap[device.input[n].guid];
|
||||
inputEvent(Scancode::None, 1);
|
||||
inputEvent(hidNull, 0, 0, 0, 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -146,7 +143,7 @@ void InputSettings::eraseInput() {
|
|||
unsigned number = activeDevice().order[inputList.selection()];
|
||||
auto& input = activeDevice().input[number];
|
||||
activeInput = inputManager->inputMap[input.guid];
|
||||
inputEvent(Scancode::None, 1);
|
||||
inputEvent(hidNull, 0, 0, 0, 1);
|
||||
}
|
||||
|
||||
void InputSettings::assignInput() {
|
||||
|
@ -165,20 +162,22 @@ void InputSettings::assignMouseInput(unsigned n) {
|
|||
activeInput = inputManager->inputMap[input.guid];
|
||||
|
||||
if(dynamic_cast<DigitalInput*>(activeInput)) {
|
||||
return inputEvent(mouse(0).button(n), 1, true);
|
||||
if(auto hidMouse = inputManager->findMouse()) {
|
||||
return inputEvent(*hidMouse, HID::Mouse::GroupID::Button, n, 0, 1, true);
|
||||
}
|
||||
}
|
||||
|
||||
if(dynamic_cast<RelativeInput*>(activeInput)
|
||||
|| dynamic_cast<AbsoluteInput*>(activeInput)) {
|
||||
return inputEvent(mouse(0).axis(n), 1, true);
|
||||
if(dynamic_cast<RelativeInput*>(activeInput)) {
|
||||
if(auto hidMouse = inputManager->findMouse()) {
|
||||
return inputEvent(*hidMouse, HID::Mouse::GroupID::Axis, n, 0, +32767, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void InputSettings::inputEvent(unsigned scancode, int16_t value, bool allowMouseInput) {
|
||||
using nall::Mouse;
|
||||
void InputSettings::inputEvent(HID::Device& device, unsigned group, unsigned input, int16_t oldValue, int16_t newValue, bool allowMouseInput) {
|
||||
if(activeInput == nullptr) return;
|
||||
if(allowMouseInput == false && (Mouse::isAnyButton(scancode) || Mouse::isAnyAxis(scancode))) return;
|
||||
if(activeInput->bind(scancode, value) == false) return;
|
||||
if(allowMouseInput == false && device.isMouse()) return;
|
||||
if(activeInput->bind(device, group, input, oldValue, newValue) == false) return;
|
||||
|
||||
activeInput = nullptr;
|
||||
inputChanged();
|
||||
|
|
|
@ -28,7 +28,7 @@ struct InputSettings : SettingsLayout {
|
|||
void eraseInput();
|
||||
void assignInput();
|
||||
void assignMouseInput(unsigned n);
|
||||
void inputEvent(unsigned scancode, int16_t value, bool allowMouseInput = false);
|
||||
void inputEvent(HID::Device& device, unsigned group, unsigned input, int16_t oldValue, int16_t newValue, bool allowMouseInput = false);
|
||||
InputSettings();
|
||||
|
||||
private:
|
||||
|
|
Loading…
Reference in New Issue