2015-03-02 09:13:28 +00:00
|
|
|
#include "../tomoko.hpp"
|
2015-04-13 11:16:33 +00:00
|
|
|
#include "hotkeys.cpp"
|
2015-03-02 09:13:28 +00:00
|
|
|
InputManager* inputManager = nullptr;
|
|
|
|
|
|
|
|
auto InputMapping::bind() -> void {
|
|
|
|
auto token = assignment.split("/");
|
2015-05-23 05:29:18 +00:00
|
|
|
if(token.size() < 3) return unbind();
|
2015-12-21 09:16:47 +00:00
|
|
|
uint64 id = token[0].natural();
|
|
|
|
uint group = token[1].natural();
|
|
|
|
uint input = token[2].natural();
|
2015-05-23 05:29:18 +00:00
|
|
|
string qualifier = token(3, "None");
|
2015-03-02 09:13:28 +00:00
|
|
|
|
|
|
|
for(auto& device : inputManager->devices) {
|
2015-05-24 09:44:28 +00:00
|
|
|
if(id != device->id()) continue;
|
2015-03-02 09:13:28 +00:00
|
|
|
|
|
|
|
this->device = device;
|
|
|
|
this->group = group;
|
|
|
|
this->input = input;
|
2015-05-23 05:29:18 +00:00
|
|
|
this->qualifier = Qualifier::None;
|
|
|
|
if(qualifier == "Lo") this->qualifier = Qualifier::Lo;
|
|
|
|
if(qualifier == "Hi") this->qualifier = Qualifier::Hi;
|
|
|
|
if(qualifier == "Rumble") this->qualifier = Qualifier::Rumble;
|
2015-03-02 09:13:28 +00:00
|
|
|
break;
|
|
|
|
}
|
2015-11-16 08:38:05 +00:00
|
|
|
|
|
|
|
settings[path].setValue(assignment);
|
2015-03-02 09:13:28 +00:00
|
|
|
}
|
|
|
|
|
2015-12-21 09:16:47 +00:00
|
|
|
auto InputMapping::bind(shared_pointer<HID::Device> device, uint group, uint input, int16 oldValue, int16 newValue) -> bool {
|
2015-05-24 09:44:28 +00:00
|
|
|
if(device->isNull() || (device->isKeyboard() && device->group(group).input(input).name() == "Escape")) {
|
2015-05-23 05:29:18 +00:00
|
|
|
return unbind(), true;
|
|
|
|
}
|
|
|
|
|
2015-05-24 09:44:28 +00:00
|
|
|
string encoding = {"0x", hex(device->id()), "/", group, "/", input};
|
2015-05-23 05:29:18 +00:00
|
|
|
|
|
|
|
if(isDigital()) {
|
2015-05-24 09:44:28 +00:00
|
|
|
if((device->isKeyboard() && group == HID::Keyboard::GroupID::Button)
|
|
|
|
|| (device->isMouse() && group == HID::Mouse::GroupID::Button)
|
|
|
|
|| (device->isJoypad() && group == HID::Joypad::GroupID::Button)) {
|
2015-05-23 05:29:18 +00:00
|
|
|
if(newValue) {
|
|
|
|
this->assignment = encoding;
|
|
|
|
return bind(), true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-05-24 09:44:28 +00:00
|
|
|
if((device->isJoypad() && group == HID::Joypad::GroupID::Axis)
|
2015-08-24 09:42:11 +00:00
|
|
|
|| (device->isJoypad() && group == HID::Joypad::GroupID::Hat)
|
|
|
|
|| (device->isJoypad() && group == HID::Joypad::GroupID::Trigger)) {
|
|
|
|
if(newValue < -16384 && group != HID::Joypad::GroupID::Trigger) { //triggers are always hi
|
2015-05-23 05:29:18 +00:00
|
|
|
this->assignment = {encoding, "/Lo"};
|
|
|
|
return bind(), true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(newValue > +16384) {
|
|
|
|
this->assignment = {encoding, "/Hi"};
|
|
|
|
return bind(), true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if(isAnalog()) {
|
2015-05-24 09:44:28 +00:00
|
|
|
if((device->isMouse() && group == HID::Mouse::GroupID::Axis)
|
|
|
|
|| (device->isJoypad() && group == HID::Joypad::GroupID::Axis)
|
|
|
|
|| (device->isJoypad() && group == HID::Joypad::GroupID::Hat)) {
|
2015-05-23 05:29:18 +00:00
|
|
|
if(newValue < -16384 || newValue > +16384) {
|
|
|
|
this->assignment = encoding;
|
|
|
|
return bind(), true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
Update to v094r13 release.
byuu says:
This version polishes up the input dialogue (reset, erase, disable
button when item not focused, split device ID from mapping name), adds
color emulation toggle, and add dummy menu items for remaining features
(to be filled in later.)
Also, it now compiles cleanly on Windows with GTK.
I didn't test with TDM-GCC-32, because for god knows what reason, the
32-bit version ships with headers from Windows 95 OSR2 only. So I built
with TDM-GCC-64 with arch=x86.
And uh, apparently, moving or resizing a window causes a Visual C++
runtime exception in the GTK+ DLLs. This doesn't happen with trance or
renshuu built with TDM-GCC-32. So, yeah, like I said, don't use -m32.
2015-03-07 10:21:47 +00:00
|
|
|
|
2015-05-23 05:29:18 +00:00
|
|
|
if(isRumble()) {
|
2015-05-24 09:44:28 +00:00
|
|
|
if(device->isJoypad() && group == HID::Joypad::GroupID::Button) {
|
2015-05-23 05:29:18 +00:00
|
|
|
if(newValue) {
|
2015-08-24 09:42:11 +00:00
|
|
|
this->assignment = {encoding, "/Rumble"};
|
2015-05-23 05:29:18 +00:00
|
|
|
return bind(), true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
2015-03-02 09:13:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
auto InputMapping::poll() -> int16 {
|
2015-05-23 05:29:18 +00:00
|
|
|
if(!device) return 0;
|
2015-05-24 09:44:28 +00:00
|
|
|
auto value = device->group(group).input(input).value();
|
2015-05-23 05:29:18 +00:00
|
|
|
|
|
|
|
if(isDigital()) {
|
|
|
|
if(device->isKeyboard() && group == HID::Keyboard::GroupID::Button) return value != 0;
|
|
|
|
if(device->isMouse() && group == HID::Mouse::GroupID::Button) return value != 0;
|
|
|
|
if(device->isJoypad() && group == HID::Joypad::GroupID::Button) return value != 0;
|
|
|
|
if((device->isJoypad() && group == HID::Joypad::GroupID::Axis)
|
2015-08-24 09:42:11 +00:00
|
|
|
|| (device->isJoypad() && group == HID::Joypad::GroupID::Hat)
|
|
|
|
|| (device->isJoypad() && group == HID::Joypad::GroupID::Trigger)) {
|
2015-05-23 05:29:18 +00:00
|
|
|
if(qualifier == Qualifier::Lo) return value < -16384;
|
|
|
|
if(qualifier == Qualifier::Hi) return value > +16384;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if(isAnalog()) {
|
|
|
|
if(device->isMouse() && group == HID::Mouse::GroupID::Axis) return value;
|
|
|
|
if(device->isJoypad() && group == HID::Joypad::GroupID::Axis) return value >> 8;
|
|
|
|
if(device->isJoypad() && group == HID::Joypad::GroupID::Hat) return value < 0 ? -1 : value > 0 ? +1 : 0;
|
|
|
|
}
|
|
|
|
|
2015-03-02 09:13:28 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-08-24 09:42:11 +00:00
|
|
|
auto InputMapping::rumble(bool enable) -> void {
|
|
|
|
if(!device) return;
|
|
|
|
::input->rumble(device->id(), enable);
|
|
|
|
}
|
|
|
|
|
Update to v094r13 release.
byuu says:
This version polishes up the input dialogue (reset, erase, disable
button when item not focused, split device ID from mapping name), adds
color emulation toggle, and add dummy menu items for remaining features
(to be filled in later.)
Also, it now compiles cleanly on Windows with GTK.
I didn't test with TDM-GCC-32, because for god knows what reason, the
32-bit version ships with headers from Windows 95 OSR2 only. So I built
with TDM-GCC-64 with arch=x86.
And uh, apparently, moving or resizing a window causes a Visual C++
runtime exception in the GTK+ DLLs. This doesn't happen with trance or
renshuu built with TDM-GCC-32. So, yeah, like I said, don't use -m32.
2015-03-07 10:21:47 +00:00
|
|
|
auto InputMapping::unbind() -> void {
|
2015-11-16 08:38:05 +00:00
|
|
|
assignment = "None";
|
|
|
|
device = nullptr;
|
|
|
|
group = 0;
|
|
|
|
input = 0;
|
|
|
|
qualifier = Qualifier::None;
|
|
|
|
settings[path].setValue(assignment);
|
2015-05-23 05:29:18 +00:00
|
|
|
}
|
|
|
|
|
2015-05-24 09:44:28 +00:00
|
|
|
auto InputMapping::assignmentName() -> string {
|
2015-05-23 05:29:18 +00:00
|
|
|
if(!device) return "None";
|
|
|
|
string path;
|
2015-05-24 09:44:28 +00:00
|
|
|
path.append(device->name());
|
|
|
|
path.append(".", device->group(group).name());
|
|
|
|
path.append(".", device->group(group).input(input).name());
|
2015-05-23 05:29:18 +00:00
|
|
|
if(qualifier == Qualifier::Lo) path.append(".Lo");
|
|
|
|
if(qualifier == Qualifier::Hi) path.append(".Hi");
|
|
|
|
if(qualifier == Qualifier::Rumble) path.append(".Rumble");
|
|
|
|
return path;
|
|
|
|
}
|
|
|
|
|
2015-05-24 09:44:28 +00:00
|
|
|
auto InputMapping::deviceName() -> string {
|
2015-05-23 05:29:18 +00:00
|
|
|
if(!device) return "";
|
2015-05-24 09:44:28 +00:00
|
|
|
return hex(device->id());
|
Update to v094r13 release.
byuu says:
This version polishes up the input dialogue (reset, erase, disable
button when item not focused, split device ID from mapping name), adds
color emulation toggle, and add dummy menu items for remaining features
(to be filled in later.)
Also, it now compiles cleanly on Windows with GTK.
I didn't test with TDM-GCC-32, because for god knows what reason, the
32-bit version ships with headers from Windows 95 OSR2 only. So I built
with TDM-GCC-64 with arch=x86.
And uh, apparently, moving or resizing a window causes a Visual C++
runtime exception in the GTK+ DLLs. This doesn't happen with trance or
renshuu built with TDM-GCC-32. So, yeah, like I said, don't use -m32.
2015-03-07 10:21:47 +00:00
|
|
|
}
|
|
|
|
|
2015-03-02 09:13:28 +00:00
|
|
|
//
|
|
|
|
|
|
|
|
InputManager::InputManager() {
|
|
|
|
inputManager = this;
|
|
|
|
|
|
|
|
for(auto& emulator : program->emulators) {
|
|
|
|
emulators.append(InputEmulator());
|
|
|
|
auto& inputEmulator = emulators.last();
|
|
|
|
inputEmulator.name = emulator->information.name;
|
|
|
|
|
|
|
|
for(auto& port : emulator->port) {
|
|
|
|
inputEmulator.ports.append(InputPort());
|
|
|
|
auto& inputPort = inputEmulator.ports.last();
|
|
|
|
inputPort.name = port.name;
|
|
|
|
for(auto& device : port.device) {
|
|
|
|
inputPort.devices.append(InputDevice());
|
|
|
|
auto& inputDevice = inputPort.devices.last();
|
|
|
|
inputDevice.name = device.name;
|
|
|
|
for(auto number : device.order) {
|
|
|
|
auto& input = device.input[number];
|
|
|
|
inputDevice.mappings.append(new InputMapping());
|
|
|
|
auto& inputMapping = inputDevice.mappings.last();
|
|
|
|
inputMapping->name = input.name;
|
|
|
|
inputMapping->link = &input;
|
2015-11-16 08:38:05 +00:00
|
|
|
input.guid = (uintptr)inputMapping;
|
2015-03-02 09:13:28 +00:00
|
|
|
|
2015-11-16 08:38:05 +00:00
|
|
|
inputMapping->path = string{inputEmulator.name, "/", inputPort.name, "/", inputDevice.name, "/", inputMapping->name}.replace(" ", "");
|
|
|
|
inputMapping->assignment = settings(inputMapping->path).text();
|
|
|
|
inputMapping->bind();
|
2015-03-02 09:13:28 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-04-13 11:16:33 +00:00
|
|
|
appendHotkeys();
|
2015-03-02 09:13:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
auto InputManager::bind() -> void {
|
|
|
|
for(auto& emulator : emulators) {
|
|
|
|
for(auto& port : emulator.ports) {
|
|
|
|
for(auto& device : port.devices) {
|
|
|
|
for(auto& mapping : device.mappings) {
|
|
|
|
mapping->bind();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2015-04-13 11:16:33 +00:00
|
|
|
|
|
|
|
for(auto& hotkey : hotkeys) {
|
|
|
|
hotkey->bind();
|
|
|
|
}
|
2015-03-02 09:13:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
auto InputManager::poll() -> void {
|
2015-06-20 05:44:05 +00:00
|
|
|
auto devices = input->poll();
|
2015-03-02 09:13:28 +00:00
|
|
|
bool changed = devices.size() != this->devices.size();
|
|
|
|
if(changed == false) {
|
|
|
|
for(auto n : range(devices)) {
|
|
|
|
changed = devices[n] != this->devices[n];
|
|
|
|
if(changed) break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if(changed == true) {
|
|
|
|
this->devices = devices;
|
|
|
|
bind();
|
|
|
|
}
|
2015-04-13 11:16:33 +00:00
|
|
|
|
|
|
|
if(presentation && presentation->focused()) pollHotkeys();
|
2015-03-02 09:13:28 +00:00
|
|
|
}
|
|
|
|
|
2015-12-21 09:16:47 +00:00
|
|
|
auto InputManager::onChange(shared_pointer<HID::Device> device, uint group, uint input, int16 oldValue, int16 newValue) -> void {
|
2015-03-02 09:13:28 +00:00
|
|
|
if(settingsManager->focused()) {
|
|
|
|
settingsManager->input.inputEvent(device, group, input, oldValue, newValue);
|
2015-04-13 11:16:33 +00:00
|
|
|
settingsManager->hotkeys.inputEvent(device, group, input, oldValue, newValue);
|
2015-03-02 09:13:28 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
auto InputManager::quit() -> void {
|
2015-04-13 11:16:33 +00:00
|
|
|
emulators.reset();
|
|
|
|
hotkeys.reset();
|
2015-03-02 09:13:28 +00:00
|
|
|
}
|
2015-05-23 05:29:18 +00:00
|
|
|
|
2015-05-24 09:44:28 +00:00
|
|
|
auto InputManager::findMouse() -> shared_pointer<HID::Device> {
|
|
|
|
for(auto& device : devices) {
|
2015-05-23 05:29:18 +00:00
|
|
|
if(device->isMouse()) return device;
|
|
|
|
}
|
2015-05-24 09:44:28 +00:00
|
|
|
return {};
|
2015-05-23 05:29:18 +00:00
|
|
|
}
|