summaryrefslogtreecommitdiff
path: root/src/core/hid/emulated_devices.cpp
diff options
context:
space:
mode:
authorGravatar german772021-09-20 19:43:16 -0500
committerGravatar Narr the Reg2021-11-24 20:30:23 -0600
commitc3f54ff2329d79bdbb273678b5123cf0b1cd090c (patch)
tree671542346e2f692b2cef8dc4da6ccdb0b9e21dc2 /src/core/hid/emulated_devices.cpp
parentyuzu_cmd: Use new input (diff)
downloadyuzu-c3f54ff2329d79bdbb273678b5123cf0b1cd090c.tar.gz
yuzu-c3f54ff2329d79bdbb273678b5123cf0b1cd090c.tar.xz
yuzu-c3f54ff2329d79bdbb273678b5123cf0b1cd090c.zip
core/hid: Add emulated controllers
Diffstat (limited to 'src/core/hid/emulated_devices.cpp')
-rw-r--r--src/core/hid/emulated_devices.cpp349
1 files changed, 349 insertions, 0 deletions
diff --git a/src/core/hid/emulated_devices.cpp b/src/core/hid/emulated_devices.cpp
new file mode 100644
index 000000000..3caf90714
--- /dev/null
+++ b/src/core/hid/emulated_devices.cpp
@@ -0,0 +1,349 @@
1// Copyright 2021 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included
4
5#include <fmt/format.h>
6
7#include "core/hid/emulated_devices.h"
8#include "core/hid/input_converter.h"
9
10namespace Core::HID {
11
12EmulatedDevices::EmulatedDevices() {}
13
14EmulatedDevices::~EmulatedDevices() = default;
15
16void EmulatedDevices::ReloadFromSettings() {
17 const auto& mouse = Settings::values.mouse_buttons;
18
19 for (std::size_t index = 0; index < mouse.size(); ++index) {
20 mouse_button_params[index] = Common::ParamPackage(mouse[index]);
21 }
22 ReloadInput();
23}
24
25void EmulatedDevices::ReloadInput() {
26 std::transform(mouse_button_params.begin() + Settings::NativeMouseButton::MOUSE_HID_BEGIN,
27 mouse_button_params.begin() + Settings::NativeMouseButton::MOUSE_HID_END,
28 mouse_button_devices.begin(), Input::CreateDevice<Input::InputDevice>);
29
30 std::transform(Settings::values.keyboard_keys.begin(), Settings::values.keyboard_keys.end(),
31 keyboard_devices.begin(), Input::CreateDeviceFromString<Input::InputDevice>);
32
33 std::transform(Settings::values.keyboard_mods.begin(), Settings::values.keyboard_mods.end(),
34 keyboard_modifier_devices.begin(),
35 Input::CreateDeviceFromString<Input::InputDevice>);
36
37 for (std::size_t index = 0; index < mouse_button_devices.size(); ++index) {
38 if (!mouse_button_devices[index]) {
39 continue;
40 }
41 Input::InputCallback button_callback{
42 [this, index](Input::CallbackStatus callback) { SetMouseButton(callback, index); }};
43 mouse_button_devices[index]->SetCallback(button_callback);
44 }
45
46 for (std::size_t index = 0; index < keyboard_devices.size(); ++index) {
47 if (!keyboard_devices[index]) {
48 continue;
49 }
50 Input::InputCallback button_callback{
51 [this, index](Input::CallbackStatus callback) { SetKeyboardButton(callback, index); }};
52 keyboard_devices[index]->SetCallback(button_callback);
53 }
54
55 for (std::size_t index = 0; index < keyboard_modifier_devices.size(); ++index) {
56 if (!keyboard_modifier_devices[index]) {
57 continue;
58 }
59 Input::InputCallback button_callback{[this, index](Input::CallbackStatus callback) {
60 SetKeyboardModifier(callback, index);
61 }};
62 keyboard_modifier_devices[index]->SetCallback(button_callback);
63 }
64}
65
66void EmulatedDevices::UnloadInput() {
67 for (auto& button : mouse_button_devices) {
68 button.reset();
69 }
70 for (auto& button : keyboard_devices) {
71 button.reset();
72 }
73 for (auto& button : keyboard_modifier_devices) {
74 button.reset();
75 }
76}
77
78void EmulatedDevices::EnableConfiguration() {
79 is_configuring = true;
80 SaveCurrentConfig();
81}
82
83void EmulatedDevices::DisableConfiguration() {
84 is_configuring = false;
85}
86
87bool EmulatedDevices::IsConfiguring() const {
88 return is_configuring;
89}
90
91void EmulatedDevices::SaveCurrentConfig() {
92 if (!is_configuring) {
93 return;
94 }
95
96 auto& mouse = Settings::values.mouse_buttons;
97
98 for (std::size_t index = 0; index < mouse.size(); ++index) {
99 mouse[index] = mouse_button_params[index].Serialize();
100 }
101}
102
103void EmulatedDevices::RestoreConfig() {
104 if (!is_configuring) {
105 return;
106 }
107 ReloadFromSettings();
108}
109
110Common::ParamPackage EmulatedDevices::GetMouseButtonParam(std::size_t index) const {
111 if (index >= mouse_button_params.size()) {
112 return {};
113 }
114 return mouse_button_params[index];
115}
116
117void EmulatedDevices::SetButtonParam(std::size_t index, Common::ParamPackage param) {
118 if (index >= mouse_button_params.size()) {
119 return;
120 }
121 mouse_button_params[index] = param;
122 ReloadInput();
123}
124
125void EmulatedDevices::SetKeyboardButton(Input::CallbackStatus callback, std::size_t index) {
126 if (index >= device_status.keyboard_values.size()) {
127 return;
128 }
129 std::lock_guard lock{mutex};
130 bool value_changed = false;
131 const auto new_status = TransformToButton(callback);
132 auto& current_status = device_status.keyboard_values[index];
133 current_status.toggle = new_status.toggle;
134
135 // Update button status with current
136 if (!current_status.toggle) {
137 current_status.locked = false;
138 if (current_status.value != new_status.value) {
139 current_status.value = new_status.value;
140 value_changed = true;
141 }
142 } else {
143 // Toggle button and lock status
144 if (new_status.value && !current_status.locked) {
145 current_status.locked = true;
146 current_status.value = !current_status.value;
147 value_changed = true;
148 }
149
150 // Unlock button ready for next press
151 if (!new_status.value && current_status.locked) {
152 current_status.locked = false;
153 }
154 }
155
156 if (!value_changed) {
157 return;
158 }
159
160 if (is_configuring) {
161 TriggerOnChange(DeviceTriggerType::Keyboard);
162 return;
163 }
164
165 // TODO(german77): Do this properly
166 // switch (index) {
167 // case Settings::NativeKeyboard::A:
168 // interface_status.keyboard_state.a.Assign(current_status.value);
169 // break;
170 // ....
171 //}
172
173 TriggerOnChange(DeviceTriggerType::Keyboard);
174}
175
176void EmulatedDevices::SetKeyboardModifier(Input::CallbackStatus callback, std::size_t index) {
177 if (index >= device_status.keyboard_moddifier_values.size()) {
178 return;
179 }
180 std::lock_guard lock{mutex};
181 bool value_changed = false;
182 const auto new_status = TransformToButton(callback);
183 auto& current_status = device_status.keyboard_moddifier_values[index];
184 current_status.toggle = new_status.toggle;
185
186 // Update button status with current
187 if (!current_status.toggle) {
188 current_status.locked = false;
189 if (current_status.value != new_status.value) {
190 current_status.value = new_status.value;
191 value_changed = true;
192 }
193 } else {
194 // Toggle button and lock status
195 if (new_status.value && !current_status.locked) {
196 current_status.locked = true;
197 current_status.value = !current_status.value;
198 value_changed = true;
199 }
200
201 // Unlock button ready for next press
202 if (!new_status.value && current_status.locked) {
203 current_status.locked = false;
204 }
205 }
206
207 if (!value_changed) {
208 return;
209 }
210
211 if (is_configuring) {
212 TriggerOnChange(DeviceTriggerType::KeyboardModdifier);
213 return;
214 }
215
216 switch (index) {
217 case Settings::NativeKeyboard::LeftControl:
218 case Settings::NativeKeyboard::RightControl:
219 device_status.keyboard_moddifier_state.control.Assign(current_status.value);
220 break;
221 case Settings::NativeKeyboard::LeftShift:
222 case Settings::NativeKeyboard::RightShift:
223 device_status.keyboard_moddifier_state.shift.Assign(current_status.value);
224 break;
225 case Settings::NativeKeyboard::LeftAlt:
226 device_status.keyboard_moddifier_state.left_alt.Assign(current_status.value);
227 break;
228 case Settings::NativeKeyboard::RightAlt:
229 device_status.keyboard_moddifier_state.right_alt.Assign(current_status.value);
230 break;
231 case Settings::NativeKeyboard::CapsLock:
232 device_status.keyboard_moddifier_state.caps_lock.Assign(current_status.value);
233 break;
234 case Settings::NativeKeyboard::ScrollLock:
235 device_status.keyboard_moddifier_state.scroll_lock.Assign(current_status.value);
236 break;
237 case Settings::NativeKeyboard::NumLock:
238 device_status.keyboard_moddifier_state.num_lock.Assign(current_status.value);
239 break;
240 }
241
242 TriggerOnChange(DeviceTriggerType::KeyboardModdifier);
243}
244
245void EmulatedDevices::SetMouseButton(Input::CallbackStatus callback, std::size_t index) {
246 if (index >= device_status.mouse_button_values.size()) {
247 return;
248 }
249 std::lock_guard lock{mutex};
250 bool value_changed = false;
251 const auto new_status = TransformToButton(callback);
252 auto& current_status = device_status.mouse_button_values[index];
253 current_status.toggle = new_status.toggle;
254
255 // Update button status with current
256 if (!current_status.toggle) {
257 current_status.locked = false;
258 if (current_status.value != new_status.value) {
259 current_status.value = new_status.value;
260 value_changed = true;
261 }
262 } else {
263 // Toggle button and lock status
264 if (new_status.value && !current_status.locked) {
265 current_status.locked = true;
266 current_status.value = !current_status.value;
267 value_changed = true;
268 }
269
270 // Unlock button ready for next press
271 if (!new_status.value && current_status.locked) {
272 current_status.locked = false;
273 }
274 }
275
276 if (!value_changed) {
277 return;
278 }
279
280 if (is_configuring) {
281 TriggerOnChange(DeviceTriggerType::Mouse);
282 return;
283 }
284
285 switch (index) {
286 case Settings::NativeMouseButton::Left:
287 device_status.mouse_button_state.left.Assign(current_status.value);
288 break;
289 case Settings::NativeMouseButton::Right:
290 device_status.mouse_button_state.right.Assign(current_status.value);
291 break;
292 case Settings::NativeMouseButton::Middle:
293 device_status.mouse_button_state.middle.Assign(current_status.value);
294 break;
295 case Settings::NativeMouseButton::Forward:
296 device_status.mouse_button_state.forward.Assign(current_status.value);
297 break;
298 case Settings::NativeMouseButton::Back:
299 device_status.mouse_button_state.back.Assign(current_status.value);
300 break;
301 }
302
303 TriggerOnChange(DeviceTriggerType::Mouse);
304}
305
306MouseButtonValues EmulatedDevices::GetMouseButtonsValues() const {
307 return device_status.mouse_button_values;
308}
309
310KeyboardKey EmulatedDevices::GetKeyboard() const {
311 return device_status.keyboard_state;
312}
313
314KeyboardModifier EmulatedDevices::GetKeyboardModifier() const {
315 return device_status.keyboard_moddifier_state;
316}
317
318MouseButton EmulatedDevices::GetMouseButtons() const {
319 return device_status.mouse_button_state;
320}
321
322MousePosition EmulatedDevices::GetMousePosition() const {
323 return device_status.mouse_position_state;
324}
325
326void EmulatedDevices::TriggerOnChange(DeviceTriggerType type) {
327 for (const std::pair<int, InterfaceUpdateCallback> poller_pair : callback_list) {
328 const InterfaceUpdateCallback& poller = poller_pair.second;
329 if (poller.on_change) {
330 poller.on_change(type);
331 }
332 }
333}
334
335int EmulatedDevices::SetCallback(InterfaceUpdateCallback update_callback) {
336 std::lock_guard lock{mutex};
337 callback_list.insert_or_assign(last_callback_key, update_callback);
338 return last_callback_key++;
339}
340
341void EmulatedDevices::DeleteCallback(int key) {
342 std::lock_guard lock{mutex};
343 if (!callback_list.contains(key)) {
344 LOG_ERROR(Input, "Tried to delete non-existent callback {}", key);
345 return;
346 }
347 callback_list.erase(key);
348}
349} // namespace Core::HID