mirror of
https://github.com/bsnes-emu/bsnes.git
synced 2025-08-06 21:06:29 +02:00
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:
@@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
namespace Emulator {
|
namespace Emulator {
|
||||||
static const char Name[] = "higan";
|
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 Author[] = "byuu";
|
||||||
static const char License[] = "GPLv3";
|
static const char License[] = "GPLv3";
|
||||||
static const char Website[] = "http://byuu.org/";
|
static const char Website[] = "http://byuu.org/";
|
||||||
|
@@ -31,7 +31,7 @@ struct Interface {
|
|||||||
string name;
|
string name;
|
||||||
struct Input {
|
struct Input {
|
||||||
unsigned id;
|
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;
|
string name;
|
||||||
unsigned guid;
|
unsigned guid;
|
||||||
};
|
};
|
||||||
|
@@ -139,7 +139,7 @@ Interface::Interface() {
|
|||||||
device.input.append({ 7, 0, "Down" });
|
device.input.append({ 7, 0, "Down" });
|
||||||
device.input.append({ 8, 0, "R" });
|
device.input.append({ 8, 0, "R" });
|
||||||
device.input.append({ 9, 0, "L" });
|
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};
|
device.order = {6, 7, 5, 4, 1, 0, 9, 8, 2, 3, 10};
|
||||||
this->device.append(device);
|
this->device.append(device);
|
||||||
}
|
}
|
||||||
|
117
nall/hid.hpp
Normal file
117
nall/hid.hpp
Normal file
@@ -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/group.hpp>
|
||||||
#include <nall/gzip.hpp>
|
#include <nall/gzip.hpp>
|
||||||
#include <nall/hashset.hpp>
|
#include <nall/hashset.hpp>
|
||||||
|
#include <nall/hid.hpp>
|
||||||
#include <nall/http.hpp>
|
#include <nall/http.hpp>
|
||||||
#include <nall/image.hpp>
|
#include <nall/image.hpp>
|
||||||
#include <nall/inflate.hpp>
|
#include <nall/inflate.hpp>
|
||||||
|
@@ -21,6 +21,7 @@ namespace Math {
|
|||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
#include <endian.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
|
@@ -19,8 +19,7 @@ using namespace nall;
|
|||||||
/* Video */
|
/* Video */
|
||||||
|
|
||||||
#define DeclareVideo(Name) \
|
#define DeclareVideo(Name) \
|
||||||
class Video##Name : public Video { \
|
struct Video##Name : Video { \
|
||||||
public: \
|
|
||||||
bool cap(const string& name) { return p.cap(name); } \
|
bool cap(const string& name) { return p.cap(name); } \
|
||||||
any get(const string& name) { return p.get(name); } \
|
any get(const string& name) { return p.get(name); } \
|
||||||
bool set(const string& name, const any& value) { return p.set(name, value); } \
|
bool set(const string& name, const any& value) { return p.set(name, value); } \
|
||||||
@@ -79,8 +78,7 @@ using namespace nall;
|
|||||||
/* Audio */
|
/* Audio */
|
||||||
|
|
||||||
#define DeclareAudio(Name) \
|
#define DeclareAudio(Name) \
|
||||||
class Audio##Name : public Audio { \
|
struct Audio##Name : Audio { \
|
||||||
public: \
|
|
||||||
bool cap(const string& name) { return p.cap(name); } \
|
bool cap(const string& name) { return p.cap(name); } \
|
||||||
any get(const string& name) { return p.get(name); } \
|
any get(const string& name) { return p.get(name); } \
|
||||||
bool set(const string& name, const any& value) { return p.set(name, value); } \
|
bool set(const string& name, const any& value) { return p.set(name, value); } \
|
||||||
@@ -132,8 +130,7 @@ using namespace nall;
|
|||||||
/* Input */
|
/* Input */
|
||||||
|
|
||||||
#define DeclareInput(Name) \
|
#define DeclareInput(Name) \
|
||||||
class Input##Name : public Input { \
|
struct Input##Name : Input { \
|
||||||
public: \
|
|
||||||
bool cap(const string& name) { return p.cap(name); } \
|
bool cap(const string& name) { return p.cap(name); } \
|
||||||
any get(const string& name) { return p.get(name); } \
|
any get(const string& name) { return p.get(name); } \
|
||||||
bool set(const string& name, const any& value) { return p.set(name, value); } \
|
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 unacquire() { return p.unacquire(); } \
|
||||||
bool acquired() { return p.acquired(); } \
|
bool acquired() { return p.acquired(); } \
|
||||||
\
|
\
|
||||||
|
vector<HID::Device*> poll() { return p.poll(); } \
|
||||||
bool poll(int16_t* table) { return p.poll(table); } \
|
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(); } \
|
bool init() { return p.init(); } \
|
||||||
void term() { p.term(); } \
|
void term() { p.term(); } \
|
||||||
\
|
\
|
||||||
@@ -174,6 +172,6 @@ using namespace nall;
|
|||||||
#include <ruby/input/udev.cpp>
|
#include <ruby/input/udev.cpp>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef INPUT_X
|
#ifdef INPUT_XLIB
|
||||||
#include <ruby/input/x.cpp>
|
#include <ruby/input/xlib.cpp>
|
||||||
#endif
|
#endif
|
||||||
|
@@ -13,8 +13,9 @@ struct Input {
|
|||||||
virtual bool unacquire() { return false; }
|
virtual bool unacquire() { return false; }
|
||||||
virtual bool acquired() { return false; }
|
virtual bool acquired() { return false; }
|
||||||
|
|
||||||
|
virtual nall::vector<nall::HID::Device*> poll() { return {}; }
|
||||||
virtual bool poll(int16_t* table) { return false; }
|
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 bool init() { return true; }
|
||||||
virtual void term() {}
|
virtual void term() {}
|
||||||
|
|
||||||
|
66
ruby/input/joypad/sdl.cpp
Normal file
66
ruby/input/joypad/sdl.cpp
Normal file
@@ -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 {
|
namespace ruby {
|
||||||
|
|
||||||
struct InputJoypadUdev {
|
struct InputJoypadUdev {
|
||||||
@@ -21,9 +24,13 @@ struct InputJoypadUdev {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct Joystick {
|
struct Joystick {
|
||||||
string path;
|
HID::Joypad hid;
|
||||||
dev_t device = 0;
|
|
||||||
int fd = -1;
|
int fd = -1;
|
||||||
|
dev_t device = 0;
|
||||||
|
string deviceName;
|
||||||
|
string devicePath;
|
||||||
|
|
||||||
uint8_t evbit[(EV_MAX + 7) / 8] = {0};
|
uint8_t evbit[(EV_MAX + 7) / 8] = {0};
|
||||||
uint8_t keybit[(KEY_MAX + 7) / 8] = {0};
|
uint8_t keybit[(KEY_MAX + 7) / 8] = {0};
|
||||||
uint8_t absbit[(ABS_MAX + 7) / 8] = {0};
|
uint8_t absbit[(ABS_MAX + 7) / 8] = {0};
|
||||||
@@ -45,6 +52,48 @@ struct InputJoypadUdev {
|
|||||||
};
|
};
|
||||||
vector<Joystick> joysticks;
|
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) {
|
bool poll(int16_t* table) {
|
||||||
unsigned i = 0;
|
unsigned i = 0;
|
||||||
for(auto& js : joysticks) {
|
for(auto& js : joysticks) {
|
||||||
@@ -121,18 +170,18 @@ struct InputJoypadUdev {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void rumble(unsigned id, bool enable) {
|
void rumble(uint64_t id, bool enable) {
|
||||||
if(id >= joysticks.size()) return;
|
for(auto& js : joysticks) {
|
||||||
|
if(js.hid.id != id) continue;
|
||||||
|
if(js.hid.rumble == false) continue;
|
||||||
|
|
||||||
Joystick& js = joysticks[id];
|
input_event play;
|
||||||
if(js.rumble == false) return;
|
memset(&play, 0, sizeof(input_event));
|
||||||
|
play.type = EV_FF;
|
||||||
input_event play;
|
play.code = js.effectID;
|
||||||
memset(&play, 0, sizeof(input_event));
|
play.value = enable;
|
||||||
play.type = EV_FF;
|
write(js.fd, &play, sizeof(input_event));
|
||||||
play.code = js.effectID;
|
}
|
||||||
play.value = enable;
|
|
||||||
write(js.fd, &play, sizeof(input_event));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool init() {
|
bool init() {
|
||||||
@@ -167,15 +216,15 @@ struct InputJoypadUdev {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void createJoystick(udev_device* device, const char* path) {
|
void createJoystick(udev_device* device, const char* devicePath) {
|
||||||
Joystick js;
|
Joystick js;
|
||||||
js.path = path;
|
js.devicePath = devicePath;
|
||||||
|
|
||||||
struct stat st;
|
struct stat st;
|
||||||
if(stat(path, &st) < 0) return;
|
if(stat(devicePath, &st) < 0) return;
|
||||||
js.device = st.st_rdev;
|
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;
|
if(js.fd < 0) return;
|
||||||
|
|
||||||
uint8_t evbit[(EV_MAX + 7) / 8] = {0};
|
uint8_t evbit[(EV_MAX + 7) / 8] = {0};
|
||||||
@@ -199,6 +248,7 @@ private:
|
|||||||
if(js.vendorID == udev_device_get_sysattr_value(root, "idVendor")
|
if(js.vendorID == udev_device_get_sysattr_value(root, "idVendor")
|
||||||
&& js.productID == udev_device_get_sysattr_value(root, "idProduct")
|
&& 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.manufacturer = udev_device_get_sysattr_value(root, "manufacturer");
|
||||||
js.product = udev_device_get_sysattr_value(root, "product");
|
js.product = udev_device_get_sysattr_value(root, "product");
|
||||||
js.serial = udev_device_get_sysattr_value(root, "serial");
|
js.serial = udev_device_get_sysattr_value(root, "serial");
|
||||||
@@ -244,11 +294,24 @@ private:
|
|||||||
js.effectID = effect.id;
|
js.effectID = effect.id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
createJoystickHID(js);
|
||||||
joysticks.append(js);
|
joysticks.append(js);
|
||||||
}
|
}
|
||||||
|
|
||||||
#undef testBit
|
#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>
|
#include <xinput.h>
|
||||||
|
|
||||||
namespace ruby {
|
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 {
|
namespace ruby {
|
||||||
|
|
||||||
struct InputKeyboardXlib {
|
struct InputKeyboardXlib {
|
||||||
|
HID::Keyboard hid;
|
||||||
|
|
||||||
Display* display = nullptr;
|
Display* display = nullptr;
|
||||||
uint8_t scancode[256] = {0};
|
uint8_t scancode[256] = {0};
|
||||||
|
|
||||||
|
struct Key {
|
||||||
|
string name;
|
||||||
|
unsigned keysym;
|
||||||
|
unsigned keycode;
|
||||||
|
};
|
||||||
|
vector<Key> keys;
|
||||||
|
|
||||||
enum XScancode : unsigned {
|
enum XScancode : unsigned {
|
||||||
Escape, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12,
|
Escape, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12,
|
||||||
ScrollLock, Pause, Tilde,
|
ScrollLock, Pause, Tilde,
|
||||||
@@ -18,8 +30,28 @@ struct InputKeyboardXlib {
|
|||||||
Up, Down, Left, Right,
|
Up, Down, Left, Right,
|
||||||
Tab, Return, Spacebar, Menu,
|
Tab, Return, Spacebar, Menu,
|
||||||
LeftShift, RightShift, LeftControl, RightControl, LeftAlt, RightAlt, LeftSuper, RightSuper,
|
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) {
|
bool poll(int16_t* table) {
|
||||||
char state[32];
|
char state[32];
|
||||||
XQueryKeymap(display, state);
|
XQueryKeymap(display, state);
|
||||||
@@ -146,6 +178,127 @@ struct InputKeyboardXlib {
|
|||||||
bool init() {
|
bool init() {
|
||||||
display = XOpenDisplay(0);
|
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)
|
#define assign(x, y) scancode[x] = XKeysymToKeycode(display, y)
|
||||||
assign(Escape, XK_Escape);
|
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 {
|
namespace ruby {
|
||||||
|
|
||||||
struct InputMouseXlib {
|
struct InputMouseXlib {
|
||||||
|
HID::Mouse hid;
|
||||||
|
|
||||||
uintptr_t handle = 0;
|
uintptr_t handle = 0;
|
||||||
|
|
||||||
Display* display = nullptr;
|
Display* display = nullptr;
|
||||||
@@ -51,6 +56,52 @@ struct InputMouseXlib {
|
|||||||
return ms.acquired;
|
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) {
|
bool poll(int16_t* table) {
|
||||||
Window rootReturn;
|
Window rootReturn;
|
||||||
Window childReturn;
|
Window childReturn;
|
||||||
@@ -115,6 +166,17 @@ struct InputMouseXlib {
|
|||||||
ms.relativeX = 0;
|
ms.relativeX = 0;
|
||||||
ms.relativeY = 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;
|
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 <SDL/SDL.h>
|
||||||
#include <sys/ipc.h>
|
#include <sys/ipc.h>
|
||||||
#include <sys/shm.h>
|
#include <sys/shm.h>
|
||||||
|
|
||||||
|
#include "keyboard/xlib.cpp"
|
||||||
|
#include "mouse/xlib.cpp"
|
||||||
|
#include "joypad/sdl.cpp"
|
||||||
|
|
||||||
namespace ruby {
|
namespace ruby {
|
||||||
|
|
||||||
struct pInputSDL {
|
struct pInputSDL {
|
||||||
#include "xlibkeys.hpp"
|
InputKeyboardXlib xlibKeyboard;
|
||||||
|
InputMouseXlib xlibMouse;
|
||||||
|
InputJoypadSDL sdl;
|
||||||
|
|
||||||
struct {
|
struct Settings {
|
||||||
Display* display;
|
uintptr_t handle = 0;
|
||||||
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;
|
} settings;
|
||||||
|
|
||||||
bool cap(const string& name) {
|
bool cap(const string& name) {
|
||||||
@@ -57,117 +40,21 @@ struct pInputSDL {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool acquire() {
|
bool acquire() {
|
||||||
if(acquired()) return true;
|
return xlibMouse.acquire();
|
||||||
|
|
||||||
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() {
|
bool unacquire() {
|
||||||
if(acquired()) {
|
return xlibMouse.unacquire();
|
||||||
//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() {
|
bool acquired() {
|
||||||
return device.mouseacquired;
|
return xlibMouse.acquired();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool poll(int16_t* table) {
|
bool poll(int16_t* table) {
|
||||||
memset(table, 0, Scancode::Limit * sizeof(int16_t));
|
xlibKeyboard.poll(table);
|
||||||
|
xlibMouse.poll(table);
|
||||||
//========
|
sdl.poll(table);
|
||||||
//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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -175,56 +62,16 @@ struct pInputSDL {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool init() {
|
bool init() {
|
||||||
SDL_InitSubSystem(SDL_INIT_JOYSTICK);
|
if(xlibKeyboard.init() == false) return false;
|
||||||
SDL_JoystickEventState(SDL_IGNORE);
|
if(xlibMouse.init(settings.handle) == false) return false;
|
||||||
|
if(sdl.init() == false) return false;
|
||||||
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);
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void term() {
|
void term() {
|
||||||
unacquire();
|
xlibKeyboard.term();
|
||||||
XFreeCursor(device.display, device.InvisibleCursor);
|
xlibMouse.term();
|
||||||
|
sdl.term();
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -57,13 +57,22 @@ struct pInputUdev {
|
|||||||
return xlibMouse.acquired();
|
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) {
|
bool poll(int16_t* table) {
|
||||||
xlibKeyboard.poll(table);
|
xlibKeyboard.poll(table);
|
||||||
xlibMouse.poll(table);
|
xlibMouse.poll(table);
|
||||||
udev.poll(table);
|
udev.poll(table);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void rumble(unsigned id, bool enable) {
|
void rumble(uint64_t id, bool enable) {
|
||||||
udev.rumble(id, 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)
|
|
||||||
|
|
||||||
}
|
|
75
ruby/input/xlib.cpp
Normal file
75
ruby/input/xlib.cpp
Normal file
@@ -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();
|
else if(!strcmp(driver, "SDL")) p = new InputSDL();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef INPUT_X
|
#ifdef INPUT_XLIB
|
||||||
else if(!strcmp(driver, "X-Windows")) p = new InputX();
|
else if(!strcmp(driver, "Xlib")) p = new InputXlib();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
else p = new Input();
|
else p = new Input();
|
||||||
@@ -415,8 +415,8 @@ const char* InputInterface::optimalDriver() {
|
|||||||
return "udev";
|
return "udev";
|
||||||
#elif defined(INPUT_SDL)
|
#elif defined(INPUT_SDL)
|
||||||
return "SDL";
|
return "SDL";
|
||||||
#elif defined(INPUT_X)
|
#elif defined(INPUT_XLIB)
|
||||||
return "X-Windows";
|
return "Xlib";
|
||||||
|
|
||||||
#else
|
#else
|
||||||
return "None";
|
return "None";
|
||||||
@@ -436,8 +436,8 @@ const char* InputInterface::safestDriver() {
|
|||||||
return "udev";
|
return "udev";
|
||||||
#elif defined(INPUT_SDL)
|
#elif defined(INPUT_SDL)
|
||||||
return "SDL";
|
return "SDL";
|
||||||
#elif defined(INPUT_X)
|
#elif defined(INPUT_XLIB)
|
||||||
return "X-Windows";
|
return "Xlib";
|
||||||
|
|
||||||
#else
|
#else
|
||||||
return "none";
|
return "none";
|
||||||
@@ -473,8 +473,8 @@ const char* InputInterface::availableDrivers() {
|
|||||||
"SDL;"
|
"SDL;"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(INPUT_X)
|
#if defined(INPUT_XLIB)
|
||||||
"X-Windows;"
|
"Xlib;"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
"None";
|
"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::acquire() { return p ? p->acquire() : false; }
|
||||||
bool InputInterface::unacquire() { return p ? p->unacquire() : false; }
|
bool InputInterface::unacquire() { return p ? p->unacquire() : false; }
|
||||||
bool InputInterface::acquired() { return p ? p->acquired() : 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; }
|
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() : p(nullptr) {}
|
||||||
InputInterface::~InputInterface() { term(); }
|
InputInterface::~InputInterface() { term(); }
|
||||||
|
|
||||||
|
@@ -63,6 +63,8 @@ private:
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct InputInterface {
|
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 = "");
|
void driver(const char* driver = "");
|
||||||
const char* optimalDriver();
|
const char* optimalDriver();
|
||||||
const char* safestDriver();
|
const char* safestDriver();
|
||||||
@@ -78,8 +80,9 @@ struct InputInterface {
|
|||||||
bool unacquire();
|
bool unacquire();
|
||||||
bool acquired();
|
bool acquired();
|
||||||
|
|
||||||
|
nall::vector<nall::HID::Device*> poll();
|
||||||
bool poll(int16_t* table);
|
bool poll(int16_t* table);
|
||||||
void rumble(unsigned id, bool enable);
|
void rumble(uint64_t id, bool enable);
|
||||||
|
|
||||||
InputInterface();
|
InputInterface();
|
||||||
~InputInterface();
|
~InputInterface();
|
||||||
|
@@ -25,7 +25,7 @@ else ifeq ($(platform),macosx)
|
|||||||
else ifeq ($(platform),linux)
|
else ifeq ($(platform),linux)
|
||||||
ruby := video.glx video.xv video.xshm video.sdl
|
ruby := video.glx video.xv video.xshm video.sdl
|
||||||
ruby += audio.alsa audio.openal audio.oss audio.pulseaudio audio.pulseaudiosimple audio.ao
|
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)
|
else ifeq ($(platform),bsd)
|
||||||
ruby := video.glx
|
ruby := video.glx
|
||||||
ruby += audio.openal audio.oss
|
ruby += audio.openal audio.oss
|
||||||
|
@@ -2,7 +2,7 @@ void InputManager::appendHotkeys() {
|
|||||||
{
|
{
|
||||||
auto hotkey = new HotkeyInput;
|
auto hotkey = new HotkeyInput;
|
||||||
hotkey->name = "Toggle Fullscreen Mode";
|
hotkey->name = "Toggle Fullscreen Mode";
|
||||||
hotkey->mapping = "KB0::F11";
|
hotkey->mapping = "1/Button/F11";
|
||||||
|
|
||||||
hotkey->press = [] {
|
hotkey->press = [] {
|
||||||
utility->toggleFullScreen();
|
utility->toggleFullScreen();
|
||||||
|
@@ -1,82 +1,82 @@
|
|||||||
#include "../ethos.hpp"
|
#include "../ethos.hpp"
|
||||||
#include "hotkeys.cpp"
|
#include "hotkeys.cpp"
|
||||||
InputManager* inputManager = nullptr;
|
InputManager* inputManager = nullptr;
|
||||||
|
HID::Null hidNull;
|
||||||
|
|
||||||
void AbstractInput::bind() {
|
void AbstractInput::bind() {
|
||||||
inputList.reset();
|
inputList.reset();
|
||||||
lstring list = mapping.split(",");
|
lstring list = mapping.split(",");
|
||||||
|
|
||||||
for(auto& mapping : list) {
|
for(auto& mapping : list) {
|
||||||
Input::Type type;
|
lstring values = mapping.split("/");
|
||||||
if(mapping.endsWith(".Up")) type = Input::Type::HatUp;
|
if(values.size() == 1) continue; //skip "None" mapping
|
||||||
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;
|
|
||||||
|
|
||||||
if(type == Input::Type::Rumble) {
|
uint64_t id = hex(values[0]);
|
||||||
unsigned joypad = mapping[2] - '0';
|
string group = values(1, "");
|
||||||
inputList.append({type, joypad});
|
string input = values(2, "");
|
||||||
} else {
|
string qualifier = values(3, "");
|
||||||
string decode = mapping;
|
|
||||||
if(auto position = decode.find(".")) decode.resize(position());
|
Input item;
|
||||||
unsigned scancode = Scancode::decode(decode);
|
for(auto device : inputManager->devices) {
|
||||||
inputList.append({type, scancode});
|
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) {
|
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"
|
if(mapping.empty() || mapping == "None") mapping = encode; //remove "None"
|
||||||
else mapping.append(",", encode); //add to existing mapping list
|
else mapping.append(",", encode); //add to existing mapping list
|
||||||
bind();
|
bind();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
AbstractInput::AbstractInput() : state(false) {
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
//
|
||||||
|
|
||||||
bool DigitalInput::bind(unsigned scancode, int16_t value) {
|
bool DigitalInput::bind(HID::Device& device, unsigned group, unsigned input, int16_t oldValue, int16_t newValue) {
|
||||||
using nall::Keyboard;
|
if(device.isNull() || (device.isKeyboard() && device.group[group].input[input].name == "Escape")) {
|
||||||
using nall::Mouse;
|
|
||||||
|
|
||||||
if(scancode == Scancode::None || scancode == keyboard(0)[Keyboard::Escape]) {
|
|
||||||
inputList.reset();
|
inputList.reset();
|
||||||
mapping = "None";
|
mapping = "None";
|
||||||
return true;
|
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((device.isKeyboard() && group == HID::Keyboard::GroupID::Button)
|
||||||
if(value == 0) return false;
|
|| (device.isMouse() && group == HID::Mouse::GroupID::Button)
|
||||||
return append(encode);
|
|| (device.isJoypad() && group == HID::Joypad::GroupID::Button)
|
||||||
|
) {
|
||||||
|
if(newValue != 0) return append(encode);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(Mouse::isAnyButton(scancode)) {
|
if((device.isJoypad() && group == HID::Joypad::GroupID::Axis)
|
||||||
if(value == 0) return false;
|
|| (device.isJoypad() && group == HID::Joypad::GroupID::Hat)
|
||||||
return append(encode);
|
) {
|
||||||
}
|
if(newValue < -16384) return append({encode, "/Lo"});
|
||||||
|
if(newValue > +16384) return append({encode, "/Hi"});
|
||||||
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); }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
@@ -84,20 +84,24 @@ bool DigitalInput::bind(unsigned scancode, int16_t value) {
|
|||||||
|
|
||||||
int16_t DigitalInput::poll() {
|
int16_t DigitalInput::poll() {
|
||||||
if(program->focused() == false) return 0;
|
if(program->focused() == false) return 0;
|
||||||
|
if(inputList.size() == 0) return 0;
|
||||||
bool result = logic;
|
bool result = logic;
|
||||||
|
|
||||||
for(auto& item : inputList) {
|
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;
|
bool output = logic;
|
||||||
switch(item.type) {
|
if((device.isKeyboard() && item.group == HID::Keyboard::GroupID::Button)
|
||||||
case Input::Type::Button: output = value; break;
|
|| (device.isMouse() && item.group == HID::Mouse::GroupID::Button)
|
||||||
case Input::Type::MouseButton: output = value & input.acquired(); break;
|
|| (device.isJoypad() && item.group == HID::Joypad::GroupID::Button)
|
||||||
case Input::Type::HatUp: output = value & Joypad::HatUp; break;
|
) {
|
||||||
case Input::Type::HatDown: output = value & Joypad::HatDown; break;
|
output = value;
|
||||||
case Input::Type::HatLeft: output = value & Joypad::HatLeft; break;
|
}
|
||||||
case Input::Type::HatRight: output = value & Joypad::HatRight; break;
|
if((device.isJoypad() && item.group == HID::Joypad::GroupID::Axis)
|
||||||
case Input::Type::AxisLo: output = value < -16384; break;
|
|| (device.isJoypad() && item.group == HID::Joypad::GroupID::Hat)
|
||||||
case Input::Type::AxisHi: output = value > +16384; break;
|
) {
|
||||||
|
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 == 0) result |= output;
|
||||||
if(logic == 1) result &= output;
|
if(logic == 1) result &= output;
|
||||||
@@ -108,34 +112,37 @@ int16_t DigitalInput::poll() {
|
|||||||
|
|
||||||
//
|
//
|
||||||
|
|
||||||
bool RelativeInput::bind(unsigned scancode, int16_t value) {
|
bool RelativeInput::bind(HID::Device& device, unsigned group, unsigned input, int16_t oldValue, int16_t newValue) {
|
||||||
using nall::Keyboard;
|
if(device.isNull() || (device.isKeyboard() && device.group[group].input[input].name == "Escape")) {
|
||||||
using nall::Mouse;
|
|
||||||
|
|
||||||
if(scancode == Scancode::None || scancode == keyboard(0)[Keyboard::Escape]) {
|
|
||||||
inputList.reset();
|
inputList.reset();
|
||||||
mapping = "None";
|
mapping = "None";
|
||||||
return true;
|
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((device.isMouse() && group == HID::Mouse::GroupID::Axis)
|
||||||
if(Joypad::isAnyAxis(scancode)) return append(encode);
|
|| (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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
int16_t RelativeInput::poll() {
|
int16_t RelativeInput::poll() {
|
||||||
if(program->focused() == false) return 0;
|
if(program->focused() == false) return 0;
|
||||||
|
if(inputList.size() == 0) return 0;
|
||||||
int16_t result = 0;
|
int16_t result = 0;
|
||||||
|
|
||||||
for(auto& item : inputList) {
|
for(auto& item : inputList) {
|
||||||
int16_t value = inputManager->poll(item.scancode);
|
HID::Device& device = *(item.device);
|
||||||
switch(item.type) {
|
int16_t value = device.group[item.group].input[item.input].value;
|
||||||
case Input::Type::MouseAxis: value = input.acquired() ? value : 0; break;
|
if(device.isJoypad() && item.group == HID::Joypad::GroupID::Axis) value >>= 8;
|
||||||
case Input::Type::Axis: value = value; break;
|
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;
|
result += value;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -144,105 +151,28 @@ int16_t RelativeInput::poll() {
|
|||||||
|
|
||||||
//
|
//
|
||||||
|
|
||||||
bool AbsoluteInput::bind(unsigned scancode, int16_t value) {
|
bool RumbleInput::bind(HID::Device& device, unsigned group, unsigned input, int16_t oldValue, int16_t newValue) {
|
||||||
using nall::Keyboard;
|
if(device.isNull() || (device.isKeyboard() && device.group[group].input[input].name == "Escape")) {
|
||||||
using nall::Mouse;
|
|
||||||
|
|
||||||
if(scancode == Scancode::None || scancode == keyboard(0)[Keyboard::Escape]) {
|
|
||||||
inputList.reset();
|
inputList.reset();
|
||||||
mapping = "None";
|
mapping = "None";
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
string encode = Scancode::encode(scancode);
|
string encode = {hex(device.id), "/Rumble"};
|
||||||
|
|
||||||
if(Mouse::isAnyAxis(scancode)) {
|
if(device.isJoypad() && group == HID::Joypad::GroupID::Button) {
|
||||||
//only one input can be assigned for absolute positioning
|
if(newValue != 0) return append(encode);
|
||||||
inputList.reset();
|
|
||||||
mapping = encode;
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
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) {
|
void RumbleInput::rumble(bool enable) {
|
||||||
if(program->focused() == false) return;
|
if(program->focused() == false) return;
|
||||||
|
if(inputList.size() == 0) return;
|
||||||
|
|
||||||
for(auto& item : inputList) {
|
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() {
|
void InputManager::bind() {
|
||||||
for(auto& input : inputMap) input->bind();
|
for(auto& input : inputMap) input->bind();
|
||||||
for(auto& input : hotkeyMap) input->bind();
|
for(auto& input : hotkeyMap) input->bind();
|
||||||
}
|
}
|
||||||
|
|
||||||
void InputManager::poll() {
|
void InputManager::poll() {
|
||||||
using nall::Keyboard;
|
auto devices = input.poll();
|
||||||
|
bool changed = devices.size() != this->devices.size();
|
||||||
activeScancode = !activeScancode;
|
if(changed == false) {
|
||||||
if(input.poll(scancode[activeScancode]) == false) return;
|
for(unsigned n = 0; n < devices.size(); n++) {
|
||||||
|
changed = devices[n] != this->devices[n];
|
||||||
for(unsigned n = 0; n < Scancode::Limit; n++) {
|
if(changed) break;
|
||||||
if(scancode[0][n] != scancode[1][n]) {
|
|
||||||
if(settings->focused()) {
|
|
||||||
inputSettings->inputEvent(n, scancode[activeScancode][n]);
|
|
||||||
hotkeySettings->inputEvent(n, scancode[activeScancode][n]);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if(changed == true) {
|
||||||
|
this->devices = devices;
|
||||||
|
bind();
|
||||||
|
}
|
||||||
|
|
||||||
if(presentation->focused()) pollHotkeys();
|
if(presentation->focused()) pollHotkeys();
|
||||||
}
|
}
|
||||||
|
|
||||||
int16_t InputManager::poll(unsigned scancode) {
|
|
||||||
return this->scancode[activeScancode][scancode];
|
|
||||||
}
|
|
||||||
|
|
||||||
void InputManager::saveConfiguration() {
|
void InputManager::saveConfiguration() {
|
||||||
config.save(program->path("input.bml"));
|
config.save(program->path("input.bml"));
|
||||||
}
|
}
|
||||||
|
|
||||||
InputManager::InputManager() {
|
InputManager::InputManager() {
|
||||||
inputManager = this;
|
inputManager = this;
|
||||||
scancode[0] = new int16_t[Scancode::Limit]();
|
|
||||||
scancode[1] = new int16_t[Scancode::Limit]();
|
|
||||||
activeScancode = 0;
|
|
||||||
bootstrap();
|
bootstrap();
|
||||||
}
|
|
||||||
|
|
||||||
InputManager::~InputManager() {
|
input.onChange = {&InputManager::onChange, this};
|
||||||
delete[] scancode[0];
|
|
||||||
delete[] scancode[1];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void InputManager::bootstrap() {
|
void InputManager::bootstrap() {
|
||||||
@@ -316,8 +249,7 @@ void InputManager::bootstrap() {
|
|||||||
AbstractInput* abstract = nullptr;
|
AbstractInput* abstract = nullptr;
|
||||||
if(input.type == 0) abstract = new DigitalInput;
|
if(input.type == 0) abstract = new DigitalInput;
|
||||||
if(input.type == 1) abstract = new RelativeInput;
|
if(input.type == 1) abstract = new RelativeInput;
|
||||||
if(input.type == 2) abstract = new AbsoluteInput;
|
if(input.type == 2) abstract = new RumbleInput;
|
||||||
if(input.type == 3) abstract = new RumbleInput;
|
|
||||||
if(abstract == nullptr) continue;
|
if(abstract == nullptr) continue;
|
||||||
|
|
||||||
abstract->name = string{input.name}.replace(" ", "");
|
abstract->name = string{input.name}.replace(" ", "");
|
||||||
|
@@ -1,45 +1,42 @@
|
|||||||
|
extern HID::Null hidNull;
|
||||||
|
|
||||||
struct AbstractInput {
|
struct AbstractInput {
|
||||||
string name;
|
string name;
|
||||||
string mapping;
|
string mapping;
|
||||||
bool logic; //0 = OR, 1 = AND
|
bool logic = 0; //0 = OR, 1 = AND
|
||||||
bool state;
|
bool state = 0;
|
||||||
|
|
||||||
struct Input {
|
struct Input {
|
||||||
enum class Type : unsigned { Button, MouseButton, MouseAxis, HatUp, HatDown, HatLeft, HatRight, Axis, AxisLo, AxisHi, Rumble } type;
|
HID::Device* device = nullptr;
|
||||||
unsigned scancode;
|
uint64_t id = 0;
|
||||||
|
unsigned group = 0;
|
||||||
|
unsigned input = 0;
|
||||||
|
enum class Qualifier : unsigned { None, Lo, Hi } qualifier;
|
||||||
};
|
};
|
||||||
vector<Input> inputList;
|
vector<Input> inputList;
|
||||||
|
|
||||||
void bind();
|
void bind();
|
||||||
bool append(string mapping);
|
bool append(string mapping);
|
||||||
virtual bool bind(unsigned scancode, int16_t value) = 0;
|
virtual bool bind(HID::Device& device, unsigned group, unsigned input, int16_t oldValue, int16_t newValue) { return false; }
|
||||||
virtual int16_t poll() = 0;
|
virtual int16_t poll() { return 0; }
|
||||||
virtual void rumble(bool enable) {}
|
virtual void rumble(bool enable) {}
|
||||||
AbstractInput();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct DigitalInput : AbstractInput {
|
struct DigitalInput : AbstractInput {
|
||||||
using AbstractInput::bind;
|
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();
|
int16_t poll();
|
||||||
};
|
};
|
||||||
|
|
||||||
struct RelativeInput : AbstractInput {
|
struct RelativeInput : AbstractInput {
|
||||||
using AbstractInput::bind;
|
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 AbsoluteInput : AbstractInput {
|
|
||||||
using AbstractInput::bind;
|
|
||||||
bool bind(unsigned scancode, int16_t value);
|
|
||||||
int16_t poll();
|
int16_t poll();
|
||||||
};
|
};
|
||||||
|
|
||||||
struct RumbleInput : AbstractInput {
|
struct RumbleInput : AbstractInput {
|
||||||
using AbstractInput::bind;
|
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();
|
|
||||||
void rumble(bool enable);
|
void rumble(bool enable);
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -50,18 +47,17 @@ struct HotkeyInput : DigitalInput {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct InputManager {
|
struct InputManager {
|
||||||
|
vector<HID::Device*> devices;
|
||||||
vector<AbstractInput*> inputMap;
|
vector<AbstractInput*> inputMap;
|
||||||
vector<HotkeyInput*> hotkeyMap;
|
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 bind();
|
||||||
void poll();
|
void poll();
|
||||||
int16_t poll(unsigned scancode);
|
|
||||||
void saveConfiguration();
|
void saveConfiguration();
|
||||||
void bootstrap();
|
void bootstrap();
|
||||||
InputManager();
|
InputManager();
|
||||||
~InputManager();
|
|
||||||
|
|
||||||
//hotkeys.cpp
|
//hotkeys.cpp
|
||||||
void appendHotkeys();
|
void appendHotkeys();
|
||||||
|
@@ -26,8 +26,6 @@ void HotkeySettings::refresh() {
|
|||||||
unsigned index = 0;
|
unsigned index = 0;
|
||||||
for(auto& hotkey : inputManager->hotkeyMap) {
|
for(auto& hotkey : inputManager->hotkeyMap) {
|
||||||
string mapping = hotkey->mapping;
|
string mapping = hotkey->mapping;
|
||||||
mapping.replace("KB0::", "");
|
|
||||||
mapping.replace("MS0::", "Mouse::");
|
|
||||||
mapping.replace(",", " and ");
|
mapping.replace(",", " and ");
|
||||||
inputList.setText(index++, {hotkey->name, mapping});
|
inputList.setText(index++, {hotkey->name, mapping});
|
||||||
}
|
}
|
||||||
@@ -36,7 +34,7 @@ void HotkeySettings::refresh() {
|
|||||||
|
|
||||||
void HotkeySettings::eraseInput() {
|
void HotkeySettings::eraseInput() {
|
||||||
activeInput = inputManager->hotkeyMap[inputList.selection()];
|
activeInput = inputManager->hotkeyMap[inputList.selection()];
|
||||||
inputEvent(Scancode::None, 1);
|
inputEvent(hidNull, 0, 0, 0, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void HotkeySettings::assignInput() {
|
void HotkeySettings::assignInput() {
|
||||||
@@ -47,14 +45,11 @@ void HotkeySettings::assignInput() {
|
|||||||
setEnabled(false);
|
setEnabled(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void HotkeySettings::inputEvent(unsigned scancode, int16_t value) {
|
void HotkeySettings::inputEvent(HID::Device& device, unsigned group, unsigned input, int16_t oldValue, int16_t newValue) {
|
||||||
using nall::Mouse;
|
|
||||||
|
|
||||||
if(activeInput == nullptr) return;
|
if(activeInput == nullptr) return;
|
||||||
if(value != 1) return;
|
if(device.isMouse()) return;
|
||||||
if(Mouse::isAnyButton(scancode) || Mouse::isAnyAxis(scancode)) return;
|
if(device.isJoypad() && group == HID::Joypad::GroupID::Axis) return;
|
||||||
if(Joypad::isAnyAxis(scancode)) return;
|
if(activeInput->bind(device, group, input, oldValue, newValue) == false) return;
|
||||||
if(activeInput->bind(scancode, value) == false) return;
|
|
||||||
|
|
||||||
activeInput = nullptr;
|
activeInput = nullptr;
|
||||||
settings->setStatusText("");
|
settings->setStatusText("");
|
||||||
|
@@ -8,7 +8,7 @@ struct HotkeySettings : SettingsLayout {
|
|||||||
void refresh();
|
void refresh();
|
||||||
void eraseInput();
|
void eraseInput();
|
||||||
void assignInput();
|
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();
|
HotkeySettings();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@@ -69,8 +69,7 @@ void InputSettings::synchronize() {
|
|||||||
assign[2].setVisible(true);
|
assign[2].setVisible(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(dynamic_cast<RelativeInput*>(selectedInput)
|
if(dynamic_cast<RelativeInput*>(selectedInput)) {
|
||||||
|| dynamic_cast<AbsoluteInput*>(selectedInput)) {
|
|
||||||
assign[0].setText("Mouse X-axis");
|
assign[0].setText("Mouse X-axis");
|
||||||
assign[1].setText("Mouse Y-axis");
|
assign[1].setText("Mouse Y-axis");
|
||||||
assign[0].setVisible(true);
|
assign[0].setVisible(true);
|
||||||
@@ -123,8 +122,6 @@ void InputSettings::inputChanged() {
|
|||||||
auto& input = activeDevice().input[number];
|
auto& input = activeDevice().input[number];
|
||||||
auto abstract = inputManager->inputMap(input.guid);
|
auto abstract = inputManager->inputMap(input.guid);
|
||||||
string mapping = abstract->mapping;
|
string mapping = abstract->mapping;
|
||||||
mapping.replace("KB0::", "");
|
|
||||||
mapping.replace("MS0::", "Mouse::");
|
|
||||||
mapping.replace(",", " or ");
|
mapping.replace(",", " or ");
|
||||||
inputList.setText(index++, {input.name, mapping});
|
inputList.setText(index++, {input.name, mapping});
|
||||||
}
|
}
|
||||||
@@ -138,7 +135,7 @@ void InputSettings::resetInput() {
|
|||||||
unsigned length = device.input.size();
|
unsigned length = device.input.size();
|
||||||
for(unsigned n = 0; n < length; n++) {
|
for(unsigned n = 0; n < length; n++) {
|
||||||
activeInput = inputManager->inputMap[device.input[n].guid];
|
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()];
|
unsigned number = activeDevice().order[inputList.selection()];
|
||||||
auto& input = activeDevice().input[number];
|
auto& input = activeDevice().input[number];
|
||||||
activeInput = inputManager->inputMap[input.guid];
|
activeInput = inputManager->inputMap[input.guid];
|
||||||
inputEvent(Scancode::None, 1);
|
inputEvent(hidNull, 0, 0, 0, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void InputSettings::assignInput() {
|
void InputSettings::assignInput() {
|
||||||
@@ -165,20 +162,22 @@ void InputSettings::assignMouseInput(unsigned n) {
|
|||||||
activeInput = inputManager->inputMap[input.guid];
|
activeInput = inputManager->inputMap[input.guid];
|
||||||
|
|
||||||
if(dynamic_cast<DigitalInput*>(activeInput)) {
|
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)
|
if(dynamic_cast<RelativeInput*>(activeInput)) {
|
||||||
|| dynamic_cast<AbsoluteInput*>(activeInput)) {
|
if(auto hidMouse = inputManager->findMouse()) {
|
||||||
return inputEvent(mouse(0).axis(n), 1, true);
|
return inputEvent(*hidMouse, HID::Mouse::GroupID::Axis, n, 0, +32767, true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void InputSettings::inputEvent(unsigned scancode, int16_t value, bool allowMouseInput) {
|
void InputSettings::inputEvent(HID::Device& device, unsigned group, unsigned input, int16_t oldValue, int16_t newValue, bool allowMouseInput) {
|
||||||
using nall::Mouse;
|
|
||||||
if(activeInput == nullptr) return;
|
if(activeInput == nullptr) return;
|
||||||
if(allowMouseInput == false && (Mouse::isAnyButton(scancode) || Mouse::isAnyAxis(scancode))) return;
|
if(allowMouseInput == false && device.isMouse()) return;
|
||||||
if(activeInput->bind(scancode, value) == false) return;
|
if(activeInput->bind(device, group, input, oldValue, newValue) == false) return;
|
||||||
|
|
||||||
activeInput = nullptr;
|
activeInput = nullptr;
|
||||||
inputChanged();
|
inputChanged();
|
||||||
|
@@ -28,7 +28,7 @@ struct InputSettings : SettingsLayout {
|
|||||||
void eraseInput();
|
void eraseInput();
|
||||||
void assignInput();
|
void assignInput();
|
||||||
void assignMouseInput(unsigned n);
|
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();
|
InputSettings();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
Reference in New Issue
Block a user