508 行
14 KiB
C++
508 行
14 KiB
C++
#include "../desktop-ui.hpp"
|
|
#include "hotkeys.cpp"
|
|
|
|
VirtualPort virtualPorts[5];
|
|
InputManager inputManager;
|
|
|
|
auto InputMapping::bind() -> void {
|
|
for(auto& binding : bindings) binding = {};
|
|
|
|
for(u32 index : range(BindingLimit)) {
|
|
auto& assignment = assignments[index];
|
|
auto& binding = bindings[index];
|
|
|
|
auto token = assignment.split("/");
|
|
if(token.size() < 3) continue; //ignore invalid mappings
|
|
|
|
binding.deviceID = token[0].natural();
|
|
binding.groupID = token[1].natural();
|
|
binding.inputID = token[2].natural();
|
|
binding.qualifier = Qualifier::None;
|
|
if(token(3) == "Lo") binding.qualifier = Qualifier::Lo;
|
|
if(token(3) == "Hi") binding.qualifier = Qualifier::Hi;
|
|
if(token(3) == "Rumble") binding.qualifier = Qualifier::Rumble;
|
|
|
|
for(auto& device : inputManager.devices) {
|
|
if(binding.deviceID == device->id()) {
|
|
binding.device = device;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
auto InputMapping::bind(u32 binding, string assignment) -> void {
|
|
if(binding >= BindingLimit) return;
|
|
assignments[binding] = assignment;
|
|
bind();
|
|
}
|
|
|
|
auto InputMapping::unbind() -> void {
|
|
for(u32 binding : range(BindingLimit)) unbind(binding);
|
|
}
|
|
|
|
auto InputMapping::unbind(u32 binding) -> void {
|
|
if(binding >= BindingLimit) return;
|
|
bindings[binding] = {};
|
|
assignments[binding] = {};
|
|
}
|
|
|
|
auto InputMapping::Binding::icon() -> multiFactorImage {
|
|
if(!device && deviceID) return Icon::Device::Joypad;
|
|
if(!device) return {};
|
|
if(device->isKeyboard()) return Icon::Device::Keyboard;
|
|
if(device->isMouse()) return Icon::Device::Mouse;
|
|
if(device->isJoypad()) return Icon::Device::Joypad;
|
|
return {};
|
|
}
|
|
|
|
auto InputMapping::Binding::text() -> string {
|
|
if(!device && deviceID) return "(disconnected)";
|
|
if(!device) return {};
|
|
if(groupID >= device->size()) return {};
|
|
if(inputID >= device->group(groupID).size()) return {};
|
|
|
|
if(device->isKeyboard()) {
|
|
return device->group(groupID).input(inputID).name();
|
|
}
|
|
|
|
if(device->isMouse()) {
|
|
return device->group(groupID).input(inputID).name();
|
|
}
|
|
|
|
if(device->isJoypad()) {
|
|
string name{Hash::CRC16(string{device->id()}).digest().upcase()};
|
|
if(device->vendorID() == 0x045e && device->productID() == 0x028e) {
|
|
name = {"Xbox360{", 1 + device->pathID(), "}"};
|
|
} else {
|
|
name.append(" ", device->group(groupID).name());
|
|
}
|
|
name.append(" ", device->group(groupID).input(inputID).name());
|
|
if(qualifier == Qualifier::Lo) name.append(".Lo");
|
|
if(qualifier == Qualifier::Hi) name.append(".Hi");
|
|
if(qualifier == Qualifier::Rumble) name.append(".Rumble");
|
|
return name;
|
|
}
|
|
|
|
return {};
|
|
}
|
|
|
|
//
|
|
|
|
auto InputDigital::bind(u32 binding, shared_pointer<HID::Device> device, u32 groupID, u32 inputID, s16 oldValue, s16 newValue) -> bool {
|
|
string assignment = {"0x", hex(device->id()), "/", groupID, "/", inputID};
|
|
|
|
if(device->isNull()) {
|
|
return unbind(binding), true;
|
|
}
|
|
|
|
if(device->isKeyboard() && device->group(groupID).input(inputID).name() == "Escape") {
|
|
return unbind(binding), true;
|
|
}
|
|
|
|
if(device->isKeyboard() && oldValue == 0 && newValue != 0) {
|
|
return bind(binding, assignment), true;
|
|
}
|
|
|
|
if(device->isMouse() && oldValue == 0 && newValue != 0) {
|
|
return bind(binding, assignment), true;
|
|
}
|
|
|
|
if(device->isJoypad() && groupID == HID::Joypad::GroupID::Button && oldValue == 0 && newValue != 0) {
|
|
return bind(binding, assignment), true;
|
|
}
|
|
|
|
if(device->isJoypad() && groupID != HID::Joypad::GroupID::Button
|
|
&& oldValue >= -16384 && newValue < -16384
|
|
) {
|
|
return bind(binding, {assignment, "/Lo"}), true;
|
|
}
|
|
|
|
if(device->isJoypad() && groupID != HID::Joypad::GroupID::Button
|
|
&& oldValue <= +16384 && newValue > +16384
|
|
) {
|
|
return bind(binding, {assignment, "/Hi"}), true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
auto InputDigital::value() -> s16 {
|
|
s16 result = 0;
|
|
|
|
for(auto& binding : bindings) {
|
|
if(!binding.device) continue; //unbound
|
|
|
|
auto& device = binding.device;
|
|
auto& groupID = binding.groupID;
|
|
auto& inputID = binding.inputID;
|
|
auto& qualifier = binding.qualifier;
|
|
if (device->isKeyboard() && program.keyboardCaptured) continue;
|
|
s16 value = device->group(groupID).input(inputID).value();
|
|
s16 output = 0;
|
|
|
|
if(device->isKeyboard() && groupID == HID::Keyboard::GroupID::Button) {
|
|
output = value != 0;
|
|
}
|
|
|
|
if(device->isMouse() && groupID == HID::Mouse::GroupID::Button && ruby::input.acquired()) {
|
|
output = value != 0;
|
|
}
|
|
|
|
if(device->isJoypad() && groupID == HID::Joypad::GroupID::Button) {
|
|
output = value != 0;
|
|
}
|
|
|
|
if(device->isJoypad() && groupID != HID::Joypad::GroupID::Button) {
|
|
if(qualifier == Qualifier::Lo) output = value < -16384;
|
|
if(qualifier == Qualifier::Hi) output = value > +16384;
|
|
}
|
|
|
|
result |= output;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
auto InputDigital::pressed() -> bool {
|
|
return value() != 0;
|
|
}
|
|
|
|
|
|
auto InputHotkey::value() -> s16 {
|
|
s16 result = 0;
|
|
|
|
for(auto& binding : bindings) {
|
|
if(!binding.device) continue; //unbound
|
|
|
|
auto& device = binding.device;
|
|
auto& groupID = binding.groupID;
|
|
auto& inputID = binding.inputID;
|
|
auto& qualifier = binding.qualifier;
|
|
|
|
s16 value = device->group(groupID).input(inputID).value();
|
|
s16 output = 0;
|
|
|
|
if(device->isKeyboard() && groupID == HID::Keyboard::GroupID::Button) {
|
|
output = value != 0;
|
|
}
|
|
|
|
if(device->isMouse() && groupID == HID::Mouse::GroupID::Button && ruby::input.acquired()) {
|
|
output = value != 0;
|
|
}
|
|
|
|
if(device->isJoypad() && groupID == HID::Joypad::GroupID::Button) {
|
|
output = value != 0;
|
|
}
|
|
|
|
if(device->isJoypad() && groupID != HID::Joypad::GroupID::Button) {
|
|
if(qualifier == Qualifier::Lo) output = value < -16384;
|
|
if(qualifier == Qualifier::Hi) output = value > +16384;
|
|
}
|
|
|
|
result |= output;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
|
|
//
|
|
|
|
auto InputAnalog::bind(u32 binding, shared_pointer<HID::Device> device, u32 groupID, u32 inputID, s16 oldValue, s16 newValue) -> bool {
|
|
string assignment = {"0x", hex(device->id()), "/", groupID, "/", inputID};
|
|
|
|
if(device->isNull()) {
|
|
return unbind(binding), true;
|
|
}
|
|
|
|
if(device->isKeyboard() && device->group(groupID).input(inputID).name() == "Escape") {
|
|
return unbind(binding), true;
|
|
}
|
|
|
|
if(device->isKeyboard() && oldValue == 0 && newValue != 0) {
|
|
return bind(binding, assignment), true;
|
|
}
|
|
|
|
if(device->isJoypad() && groupID == HID::Joypad::GroupID::Button && oldValue == 0 && newValue != 0) {
|
|
return bind(binding, assignment), true;
|
|
}
|
|
|
|
if(device->isJoypad() && groupID != HID::Joypad::GroupID::Button
|
|
&& oldValue >= -16384 && newValue < -16384
|
|
) {
|
|
return bind(binding, {assignment, "/Lo"}), true;
|
|
}
|
|
|
|
if(device->isJoypad() && groupID != HID::Joypad::GroupID::Button
|
|
&& oldValue <= +16384 && newValue > +16384
|
|
) {
|
|
return bind(binding, {assignment, "/Hi"}), true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
auto InputAnalog::value() -> s16 {
|
|
s32 result = 0;
|
|
|
|
for(auto& binding : bindings) {
|
|
if(!binding.device) continue; //unbound
|
|
|
|
auto& device = binding.device;
|
|
auto& groupID = binding.groupID;
|
|
auto& inputID = binding.inputID;
|
|
auto& qualifier = binding.qualifier;
|
|
if (device->isKeyboard() && program.keyboardCaptured) continue;
|
|
s16 value = device->group(groupID).input(inputID).value();
|
|
|
|
if(device->isKeyboard() && groupID == HID::Keyboard::GroupID::Button) {
|
|
result += value != 0 ? 32767 : 0;
|
|
}
|
|
|
|
if(device->isJoypad() && groupID == HID::Joypad::GroupID::Button) {
|
|
result += value != 0 ? 32767 : 0;
|
|
}
|
|
|
|
if(device->isJoypad() && groupID != HID::Joypad::GroupID::Button) {
|
|
if(qualifier == Qualifier::Lo && value < 0) result += abs(value);
|
|
if(qualifier == Qualifier::Hi && value > 0) result += abs(value);
|
|
}
|
|
}
|
|
|
|
return sclamp<16>(result);
|
|
}
|
|
|
|
auto InputAnalog::pressed() -> bool {
|
|
return value() > 16384;
|
|
}
|
|
|
|
//
|
|
|
|
auto InputAbsolute::bind(u32 binding, shared_pointer<HID::Device> device, u32 groupID, u32 inputID, s16 oldValue, s16 newValue) -> bool {
|
|
string assignment = {"0x", hex(device->id()), "/", groupID, "/", inputID};
|
|
|
|
if(device->isNull()) {
|
|
return unbind(binding), true;
|
|
}
|
|
|
|
if(device->isKeyboard() && device->group(groupID).input(inputID).name() == "Escape") {
|
|
return unbind(binding), true;
|
|
}
|
|
|
|
if(device->isMouse() && groupID == HID::Mouse::GroupID::Axis) {
|
|
return bind(binding, assignment), true;
|
|
}
|
|
|
|
if(device->isJoypad() && groupID == HID::Joypad::GroupID::Axis
|
|
&& oldValue >= -16384 && newValue < -16384
|
|
) {
|
|
return bind(binding, assignment), true;
|
|
}
|
|
|
|
if(device->isJoypad() && groupID == HID::Joypad::GroupID::Axis
|
|
&& oldValue <= +16384 && newValue > +16384
|
|
) {
|
|
return bind(binding, assignment), true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
auto InputAbsolute::value() -> s16 {
|
|
s32 result = 0;
|
|
|
|
for(auto& binding : bindings) {
|
|
if(!binding.device) continue; //unbound
|
|
|
|
auto& device = binding.device;
|
|
auto& groupID = binding.groupID;
|
|
auto& inputID = binding.inputID;
|
|
auto& qualifier = binding.qualifier;
|
|
if (device->isKeyboard() && program.keyboardCaptured) continue;
|
|
s16 value = device->group(groupID).input(inputID).value();
|
|
|
|
if(device->isMouse() && groupID == HID::Joypad::GroupID::Axis && ruby::input.acquired()) {
|
|
result += value;
|
|
}
|
|
|
|
if(device->isJoypad() && groupID == HID::Joypad::GroupID::Axis) {
|
|
result += value;
|
|
}
|
|
}
|
|
|
|
return sclamp<16>(result);
|
|
}
|
|
|
|
//
|
|
|
|
auto InputRelative::bind(u32 binding, shared_pointer<HID::Device> device, u32 groupID, u32 inputID, s16 oldValue, s16 newValue) -> bool {
|
|
string assignment = {"0x", hex(device->id()), "/", groupID, "/", inputID};
|
|
|
|
if(device->isNull()) {
|
|
return unbind(binding), true;
|
|
}
|
|
|
|
if(device->isKeyboard() && device->group(groupID).input(inputID).name() == "Escape") {
|
|
return unbind(binding), true;
|
|
}
|
|
|
|
if(device->isMouse() && groupID == HID::Mouse::GroupID::Axis) {
|
|
return bind(binding, assignment), true;
|
|
}
|
|
|
|
if(device->isJoypad() && groupID == HID::Joypad::GroupID::Axis
|
|
&& oldValue >= -16384 && newValue < -16384
|
|
) {
|
|
return bind(binding, assignment), true;
|
|
}
|
|
|
|
if(device->isJoypad() && groupID == HID::Joypad::GroupID::Axis
|
|
&& oldValue <= +16384 && newValue > +16384
|
|
) {
|
|
return bind(binding, assignment), true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
auto InputRelative::value() -> s16 {
|
|
s32 result = 0;
|
|
|
|
for(auto& binding : bindings) {
|
|
if(!binding.device) continue; //unbound
|
|
|
|
auto& device = binding.device;
|
|
auto& groupID = binding.groupID;
|
|
auto& inputID = binding.inputID;
|
|
auto& qualifier = binding.qualifier;
|
|
if (device->isKeyboard() && program.keyboardCaptured) continue;
|
|
s16 value = device->group(groupID).input(inputID).value();
|
|
|
|
if(device->isMouse() && groupID == HID::Joypad::GroupID::Axis && ruby::input.acquired()) {
|
|
result += value;
|
|
}
|
|
|
|
if(device->isJoypad() && groupID == HID::Joypad::GroupID::Axis) {
|
|
result += value;
|
|
}
|
|
}
|
|
|
|
return sclamp<16>(result);
|
|
}
|
|
|
|
//
|
|
|
|
auto InputRumble::bind(u32 binding, shared_pointer<HID::Device> device, u32 groupID, u32 inputID, s16 oldValue, s16 newValue) -> bool {
|
|
string assignment = {"0x", hex(device->id()), "/", groupID, "/", inputID};
|
|
|
|
if(device->isNull()) {
|
|
return unbind(binding), true;
|
|
}
|
|
|
|
if(device->isKeyboard() && device->group(groupID).input(inputID).name() == "Escape") {
|
|
return unbind(binding), true;
|
|
}
|
|
|
|
if(device->isJoypad() && groupID == HID::Joypad::GroupID::Button && oldValue == 0 && newValue == 1) {
|
|
return bind(binding, assignment), true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
auto InputRumble::value() -> s16 {
|
|
return 0;
|
|
}
|
|
|
|
auto InputRumble::rumble(u16 strong, u16 weak) -> void {
|
|
for(auto& binding : bindings) {
|
|
if(!binding.device) continue;
|
|
ruby::input.rumble(binding.deviceID, strong, weak);
|
|
}
|
|
}
|
|
|
|
//
|
|
|
|
VirtualPad::VirtualPad() {
|
|
InputDevice::name = "Virtual Gamepad";
|
|
InputDevice::digital("Pad Up", up);
|
|
InputDevice::digital("Pad Down", down);
|
|
InputDevice::digital("Pad Left", left);
|
|
InputDevice::digital("Pad Right", right);
|
|
InputDevice::digital("Select", select);
|
|
InputDevice::digital("Start", start);
|
|
InputDevice::digital("A (South)", south);
|
|
InputDevice::digital("B (East)", east);
|
|
InputDevice::digital("X (West)", west);
|
|
InputDevice::digital("Y (North)", north);
|
|
InputDevice::digital("L-Bumper", l_bumper);
|
|
InputDevice::digital("R-Bumper", r_bumper);
|
|
InputDevice::digital("L-Trigger", l_trigger);
|
|
InputDevice::digital("R-Trigger", r_trigger);
|
|
InputDevice::digital("L-Stick (Click)", lstick_click);
|
|
InputDevice::digital("R-Stick (Click)", rstick_click);
|
|
InputDevice::analog ("L-Up", lstick_up);
|
|
InputDevice::analog ("L-Down", lstick_down);
|
|
InputDevice::analog ("L-Left", lstick_left);
|
|
InputDevice::analog ("L-Right", lstick_right);
|
|
InputDevice::analog ("R-Up", rstick_up);
|
|
InputDevice::analog ("R-Down", rstick_down);
|
|
InputDevice::analog ("R-Left", rstick_left);
|
|
InputDevice::analog ("R-Right", rstick_right);
|
|
InputDevice::rumble ("Rumble", rumble);
|
|
}
|
|
|
|
//
|
|
|
|
VirtualMouse::VirtualMouse() {
|
|
InputDevice::name = "Mouse";
|
|
InputDevice::relative("X", x);
|
|
InputDevice::relative("Y", y);
|
|
InputDevice::digital ("Left", left);
|
|
InputDevice::digital ("Middle", middle);
|
|
InputDevice::digital ("Right", right);
|
|
InputDevice::digital ("Extra", extra);
|
|
}
|
|
|
|
//
|
|
|
|
auto InputManager::create() -> void {
|
|
createHotkeys();
|
|
}
|
|
|
|
auto InputManager::bind() -> void {
|
|
for(auto& port : virtualPorts) {
|
|
for(auto& input : port.pad.inputs) input.mapping->bind();
|
|
for(auto& input : port.mouse.inputs) input.mapping->bind();
|
|
}
|
|
for(auto& mapping : hotkeys) mapping.bind();
|
|
}
|
|
|
|
auto InputManager::poll(bool force) -> void {
|
|
//polling actual hardware is very time-consuming; skip call if poll was called too recently
|
|
auto thisPoll = chrono::millisecond();
|
|
if(thisPoll - lastPoll < pollFrequency && !force) return;
|
|
lastPoll = thisPoll;
|
|
|
|
auto devices = ruby::input.poll();
|
|
bool changed = devices.size() != this->devices.size();
|
|
if(!changed) {
|
|
for(u32 index : range(devices.size())) {
|
|
changed = devices[index] != this->devices[index];
|
|
if(changed) break;
|
|
}
|
|
}
|
|
if(changed) {
|
|
this->devices = devices;
|
|
bind();
|
|
inputSettings.refresh();
|
|
hotkeySettings.refresh();
|
|
}
|
|
}
|
|
|
|
auto InputManager::eventInput(shared_pointer<HID::Device> device, u32 groupID, u32 inputID, s16 oldValue, s16 newValue) -> void {
|
|
inputSettings.eventInput(device, groupID, inputID, oldValue, newValue);
|
|
hotkeySettings.eventInput(device, groupID, inputID, oldValue, newValue);
|
|
}
|