ares-openbsd/desktop-ui/input/input.cpp

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);
}