summaryrefslogtreecommitdiff
path: root/src/core/hid/emulated_devices.cpp
diff options
context:
space:
mode:
authorGravatar Feng Chen2021-12-18 13:57:14 +0800
committerGravatar GitHub2021-12-18 13:57:14 +0800
commite49184e6069a9d791d2df3c1958f5c4b1187e124 (patch)
treeb776caf722e0be0e680f67b0ad0842628162ef1c /src/core/hid/emulated_devices.cpp
parentImplement convert legacy to generic (diff)
parentMerge pull request #7570 from ameerj/favorites-expanded (diff)
downloadyuzu-e49184e6069a9d791d2df3c1958f5c4b1187e124.tar.gz
yuzu-e49184e6069a9d791d2df3c1958f5c4b1187e124.tar.xz
yuzu-e49184e6069a9d791d2df3c1958f5c4b1187e124.zip
Merge branch 'yuzu-emu:master' into convert_legacy
Diffstat (limited to 'src/core/hid/emulated_devices.cpp')
-rw-r--r--src/core/hid/emulated_devices.cpp459
1 files changed, 459 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..708480f2d
--- /dev/null
+++ b/src/core/hid/emulated_devices.cpp
@@ -0,0 +1,459 @@
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 <algorithm>
6#include <fmt/format.h>
7
8#include "core/hid/emulated_devices.h"
9#include "core/hid/input_converter.h"
10
11namespace Core::HID {
12
13EmulatedDevices::EmulatedDevices() = default;
14
15EmulatedDevices::~EmulatedDevices() = default;
16
17void EmulatedDevices::ReloadFromSettings() {
18 ReloadInput();
19}
20
21void EmulatedDevices::ReloadInput() {
22 // If you load any device here add the equivalent to the UnloadInput() function
23 std::size_t key_index = 0;
24 for (auto& mouse_device : mouse_button_devices) {
25 Common::ParamPackage mouse_params;
26 mouse_params.Set("engine", "mouse");
27 mouse_params.Set("button", static_cast<int>(key_index));
28 mouse_device = Common::Input::CreateDevice<Common::Input::InputDevice>(mouse_params);
29 key_index++;
30 }
31
32 mouse_stick_device = Common::Input::CreateDeviceFromString<Common::Input::InputDevice>(
33 "engine:mouse,axis_x:0,axis_y:1");
34
35 // First two axis are reserved for mouse position
36 key_index = 2;
37 for (auto& mouse_device : mouse_analog_devices) {
38 Common::ParamPackage mouse_params;
39 mouse_params.Set("engine", "mouse");
40 mouse_params.Set("axis", static_cast<int>(key_index));
41 mouse_device = Common::Input::CreateDevice<Common::Input::InputDevice>(mouse_params);
42 key_index++;
43 }
44
45 key_index = 0;
46 for (auto& keyboard_device : keyboard_devices) {
47 // Keyboard keys are only mapped on port 1, pad 0
48 Common::ParamPackage keyboard_params;
49 keyboard_params.Set("engine", "keyboard");
50 keyboard_params.Set("button", static_cast<int>(key_index));
51 keyboard_params.Set("port", 1);
52 keyboard_params.Set("pad", 0);
53 keyboard_device = Common::Input::CreateDevice<Common::Input::InputDevice>(keyboard_params);
54 key_index++;
55 }
56
57 key_index = 0;
58 for (auto& keyboard_device : keyboard_modifier_devices) {
59 // Keyboard moddifiers are only mapped on port 1, pad 1
60 Common::ParamPackage keyboard_params;
61 keyboard_params.Set("engine", "keyboard");
62 keyboard_params.Set("button", static_cast<int>(key_index));
63 keyboard_params.Set("port", 1);
64 keyboard_params.Set("pad", 1);
65 keyboard_device = Common::Input::CreateDevice<Common::Input::InputDevice>(keyboard_params);
66 key_index++;
67 }
68
69 for (std::size_t index = 0; index < mouse_button_devices.size(); ++index) {
70 if (!mouse_button_devices[index]) {
71 continue;
72 }
73 mouse_button_devices[index]->SetCallback({
74 .on_change =
75 [this, index](const Common::Input::CallbackStatus& callback) {
76 SetMouseButton(callback, index);
77 },
78 });
79 }
80
81 for (std::size_t index = 0; index < mouse_analog_devices.size(); ++index) {
82 if (!mouse_analog_devices[index]) {
83 continue;
84 }
85 mouse_analog_devices[index]->SetCallback({
86 .on_change =
87 [this, index](const Common::Input::CallbackStatus& callback) {
88 SetMouseAnalog(callback, index);
89 },
90 });
91 }
92
93 if (mouse_stick_device) {
94 mouse_stick_device->SetCallback({
95 .on_change =
96 [this](const Common::Input::CallbackStatus& callback) { SetMouseStick(callback); },
97 });
98 }
99
100 for (std::size_t index = 0; index < keyboard_devices.size(); ++index) {
101 if (!keyboard_devices[index]) {
102 continue;
103 }
104 keyboard_devices[index]->SetCallback({
105 .on_change =
106 [this, index](const Common::Input::CallbackStatus& callback) {
107 SetKeyboardButton(callback, index);
108 },
109 });
110 }
111
112 for (std::size_t index = 0; index < keyboard_modifier_devices.size(); ++index) {
113 if (!keyboard_modifier_devices[index]) {
114 continue;
115 }
116 keyboard_modifier_devices[index]->SetCallback({
117 .on_change =
118 [this, index](const Common::Input::CallbackStatus& callback) {
119 SetKeyboardModifier(callback, index);
120 },
121 });
122 }
123}
124
125void EmulatedDevices::UnloadInput() {
126 for (auto& button : mouse_button_devices) {
127 button.reset();
128 }
129 for (auto& analog : mouse_analog_devices) {
130 analog.reset();
131 }
132 mouse_stick_device.reset();
133 for (auto& button : keyboard_devices) {
134 button.reset();
135 }
136 for (auto& button : keyboard_modifier_devices) {
137 button.reset();
138 }
139}
140
141void EmulatedDevices::EnableConfiguration() {
142 is_configuring = true;
143 SaveCurrentConfig();
144}
145
146void EmulatedDevices::DisableConfiguration() {
147 is_configuring = false;
148}
149
150bool EmulatedDevices::IsConfiguring() const {
151 return is_configuring;
152}
153
154void EmulatedDevices::SaveCurrentConfig() {
155 if (!is_configuring) {
156 return;
157 }
158}
159
160void EmulatedDevices::RestoreConfig() {
161 if (!is_configuring) {
162 return;
163 }
164 ReloadFromSettings();
165}
166
167void EmulatedDevices::SetKeyboardButton(const Common::Input::CallbackStatus& callback,
168 std::size_t index) {
169 if (index >= device_status.keyboard_values.size()) {
170 return;
171 }
172 std::lock_guard lock{mutex};
173 bool value_changed = false;
174 const auto new_status = TransformToButton(callback);
175 auto& current_status = device_status.keyboard_values[index];
176 current_status.toggle = new_status.toggle;
177
178 // Update button status with current status
179 if (!current_status.toggle) {
180 current_status.locked = false;
181 if (current_status.value != new_status.value) {
182 current_status.value = new_status.value;
183 value_changed = true;
184 }
185 } else {
186 // Toggle button and lock status
187 if (new_status.value && !current_status.locked) {
188 current_status.locked = true;
189 current_status.value = !current_status.value;
190 value_changed = true;
191 }
192
193 // Unlock button, ready for next press
194 if (!new_status.value && current_status.locked) {
195 current_status.locked = false;
196 }
197 }
198
199 if (!value_changed) {
200 return;
201 }
202
203 if (is_configuring) {
204 TriggerOnChange(DeviceTriggerType::Keyboard);
205 return;
206 }
207
208 // Index should be converted from NativeKeyboard to KeyboardKeyIndex
209 UpdateKey(index, current_status.value);
210
211 TriggerOnChange(DeviceTriggerType::Keyboard);
212}
213
214void EmulatedDevices::UpdateKey(std::size_t key_index, bool status) {
215 constexpr std::size_t KEYS_PER_BYTE = 8;
216 auto& entry = device_status.keyboard_state.key[key_index / KEYS_PER_BYTE];
217 const u8 mask = static_cast<u8>(1 << (key_index % KEYS_PER_BYTE));
218 if (status) {
219 entry = entry | mask;
220 } else {
221 entry = static_cast<u8>(entry & ~mask);
222 }
223}
224
225void EmulatedDevices::SetKeyboardModifier(const Common::Input::CallbackStatus& callback,
226 std::size_t index) {
227 if (index >= device_status.keyboard_moddifier_values.size()) {
228 return;
229 }
230 std::lock_guard lock{mutex};
231 bool value_changed = false;
232 const auto new_status = TransformToButton(callback);
233 auto& current_status = device_status.keyboard_moddifier_values[index];
234 current_status.toggle = new_status.toggle;
235
236 // Update button status with current
237 if (!current_status.toggle) {
238 current_status.locked = false;
239 if (current_status.value != new_status.value) {
240 current_status.value = new_status.value;
241 value_changed = true;
242 }
243 } else {
244 // Toggle button and lock status
245 if (new_status.value && !current_status.locked) {
246 current_status.locked = true;
247 current_status.value = !current_status.value;
248 value_changed = true;
249 }
250
251 // Unlock button ready for next press
252 if (!new_status.value && current_status.locked) {
253 current_status.locked = false;
254 }
255 }
256
257 if (!value_changed) {
258 return;
259 }
260
261 if (is_configuring) {
262 TriggerOnChange(DeviceTriggerType::KeyboardModdifier);
263 return;
264 }
265
266 switch (index) {
267 case Settings::NativeKeyboard::LeftControl:
268 case Settings::NativeKeyboard::RightControl:
269 device_status.keyboard_moddifier_state.control.Assign(current_status.value);
270 break;
271 case Settings::NativeKeyboard::LeftShift:
272 case Settings::NativeKeyboard::RightShift:
273 device_status.keyboard_moddifier_state.shift.Assign(current_status.value);
274 break;
275 case Settings::NativeKeyboard::LeftAlt:
276 device_status.keyboard_moddifier_state.left_alt.Assign(current_status.value);
277 break;
278 case Settings::NativeKeyboard::RightAlt:
279 device_status.keyboard_moddifier_state.right_alt.Assign(current_status.value);
280 break;
281 case Settings::NativeKeyboard::CapsLock:
282 device_status.keyboard_moddifier_state.caps_lock.Assign(current_status.value);
283 break;
284 case Settings::NativeKeyboard::ScrollLock:
285 device_status.keyboard_moddifier_state.scroll_lock.Assign(current_status.value);
286 break;
287 case Settings::NativeKeyboard::NumLock:
288 device_status.keyboard_moddifier_state.num_lock.Assign(current_status.value);
289 break;
290 }
291
292 TriggerOnChange(DeviceTriggerType::KeyboardModdifier);
293}
294
295void EmulatedDevices::SetMouseButton(const Common::Input::CallbackStatus& callback,
296 std::size_t index) {
297 if (index >= device_status.mouse_button_values.size()) {
298 return;
299 }
300 std::lock_guard lock{mutex};
301 bool value_changed = false;
302 const auto new_status = TransformToButton(callback);
303 auto& current_status = device_status.mouse_button_values[index];
304 current_status.toggle = new_status.toggle;
305
306 // Update button status with current
307 if (!current_status.toggle) {
308 current_status.locked = false;
309 if (current_status.value != new_status.value) {
310 current_status.value = new_status.value;
311 value_changed = true;
312 }
313 } else {
314 // Toggle button and lock status
315 if (new_status.value && !current_status.locked) {
316 current_status.locked = true;
317 current_status.value = !current_status.value;
318 value_changed = true;
319 }
320
321 // Unlock button ready for next press
322 if (!new_status.value && current_status.locked) {
323 current_status.locked = false;
324 }
325 }
326
327 if (!value_changed) {
328 return;
329 }
330
331 if (is_configuring) {
332 TriggerOnChange(DeviceTriggerType::Mouse);
333 return;
334 }
335
336 switch (index) {
337 case Settings::NativeMouseButton::Left:
338 device_status.mouse_button_state.left.Assign(current_status.value);
339 break;
340 case Settings::NativeMouseButton::Right:
341 device_status.mouse_button_state.right.Assign(current_status.value);
342 break;
343 case Settings::NativeMouseButton::Middle:
344 device_status.mouse_button_state.middle.Assign(current_status.value);
345 break;
346 case Settings::NativeMouseButton::Forward:
347 device_status.mouse_button_state.forward.Assign(current_status.value);
348 break;
349 case Settings::NativeMouseButton::Back:
350 device_status.mouse_button_state.back.Assign(current_status.value);
351 break;
352 }
353
354 TriggerOnChange(DeviceTriggerType::Mouse);
355}
356
357void EmulatedDevices::SetMouseAnalog(const Common::Input::CallbackStatus& callback,
358 std::size_t index) {
359 if (index >= device_status.mouse_analog_values.size()) {
360 return;
361 }
362 std::lock_guard lock{mutex};
363 const auto analog_value = TransformToAnalog(callback);
364
365 device_status.mouse_analog_values[index] = analog_value;
366
367 if (is_configuring) {
368 device_status.mouse_position_state = {};
369 TriggerOnChange(DeviceTriggerType::Mouse);
370 return;
371 }
372
373 switch (index) {
374 case Settings::NativeMouseWheel::X:
375 device_status.mouse_wheel_state.x = static_cast<s32>(analog_value.value);
376 break;
377 case Settings::NativeMouseWheel::Y:
378 device_status.mouse_wheel_state.y = static_cast<s32>(analog_value.value);
379 break;
380 }
381
382 TriggerOnChange(DeviceTriggerType::Mouse);
383}
384
385void EmulatedDevices::SetMouseStick(const Common::Input::CallbackStatus& callback) {
386 std::lock_guard lock{mutex};
387 const auto touch_value = TransformToTouch(callback);
388
389 device_status.mouse_stick_value = touch_value;
390
391 if (is_configuring) {
392 device_status.mouse_position_state = {};
393 TriggerOnChange(DeviceTriggerType::Mouse);
394 return;
395 }
396
397 device_status.mouse_position_state.x = touch_value.x.value;
398 device_status.mouse_position_state.y = touch_value.y.value;
399
400 TriggerOnChange(DeviceTriggerType::Mouse);
401}
402
403KeyboardValues EmulatedDevices::GetKeyboardValues() const {
404 return device_status.keyboard_values;
405}
406
407KeyboardModifierValues EmulatedDevices::GetKeyboardModdifierValues() const {
408 return device_status.keyboard_moddifier_values;
409}
410
411MouseButtonValues EmulatedDevices::GetMouseButtonsValues() const {
412 return device_status.mouse_button_values;
413}
414
415KeyboardKey EmulatedDevices::GetKeyboard() const {
416 return device_status.keyboard_state;
417}
418
419KeyboardModifier EmulatedDevices::GetKeyboardModifier() const {
420 return device_status.keyboard_moddifier_state;
421}
422
423MouseButton EmulatedDevices::GetMouseButtons() const {
424 return device_status.mouse_button_state;
425}
426
427MousePosition EmulatedDevices::GetMousePosition() const {
428 return device_status.mouse_position_state;
429}
430
431AnalogStickState EmulatedDevices::GetMouseWheel() const {
432 return device_status.mouse_wheel_state;
433}
434
435void EmulatedDevices::TriggerOnChange(DeviceTriggerType type) {
436 for (const auto& poller_pair : callback_list) {
437 const InterfaceUpdateCallback& poller = poller_pair.second;
438 if (poller.on_change) {
439 poller.on_change(type);
440 }
441 }
442}
443
444int EmulatedDevices::SetCallback(InterfaceUpdateCallback update_callback) {
445 std::lock_guard lock{mutex};
446 callback_list.insert_or_assign(last_callback_key, std::move(update_callback));
447 return last_callback_key++;
448}
449
450void EmulatedDevices::DeleteCallback(int key) {
451 std::lock_guard lock{mutex};
452 const auto& iterator = callback_list.find(key);
453 if (iterator == callback_list.end()) {
454 LOG_ERROR(Input, "Tried to delete non-existent callback {}", key);
455 return;
456 }
457 callback_list.erase(iterator);
458}
459} // namespace Core::HID