1/**************************************************************************/
2/* input.cpp */
3/**************************************************************************/
4/* This file is part of: */
5/* GODOT ENGINE */
6/* https://godotengine.org */
7/**************************************************************************/
8/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
9/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
10/* */
11/* Permission is hereby granted, free of charge, to any person obtaining */
12/* a copy of this software and associated documentation files (the */
13/* "Software"), to deal in the Software without restriction, including */
14/* without limitation the rights to use, copy, modify, merge, publish, */
15/* distribute, sublicense, and/or sell copies of the Software, and to */
16/* permit persons to whom the Software is furnished to do so, subject to */
17/* the following conditions: */
18/* */
19/* The above copyright notice and this permission notice shall be */
20/* included in all copies or substantial portions of the Software. */
21/* */
22/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
23/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
24/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
25/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
26/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
27/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
28/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
29/**************************************************************************/
30
31#include "input.h"
32
33#include "core/config/project_settings.h"
34#include "core/input/default_controller_mappings.h"
35#include "core/input/input_map.h"
36#include "core/os/os.h"
37
38#ifdef DEV_ENABLED
39#include "core/os/thread.h"
40#endif
41
42static const char *_joy_buttons[(size_t)JoyButton::SDL_MAX] = {
43 "a",
44 "b",
45 "x",
46 "y",
47 "back",
48 "guide",
49 "start",
50 "leftstick",
51 "rightstick",
52 "leftshoulder",
53 "rightshoulder",
54 "dpup",
55 "dpdown",
56 "dpleft",
57 "dpright",
58 "misc1",
59 "paddle1",
60 "paddle2",
61 "paddle3",
62 "paddle4",
63 "touchpad",
64};
65
66static const char *_joy_axes[(size_t)JoyAxis::SDL_MAX] = {
67 "leftx",
68 "lefty",
69 "rightx",
70 "righty",
71 "lefttrigger",
72 "righttrigger",
73};
74
75Input *Input::singleton = nullptr;
76
77void (*Input::set_mouse_mode_func)(Input::MouseMode) = nullptr;
78Input::MouseMode (*Input::get_mouse_mode_func)() = nullptr;
79void (*Input::warp_mouse_func)(const Vector2 &p_position) = nullptr;
80Input::CursorShape (*Input::get_current_cursor_shape_func)() = nullptr;
81void (*Input::set_custom_mouse_cursor_func)(const Ref<Resource> &, Input::CursorShape, const Vector2 &) = nullptr;
82
83Input *Input::get_singleton() {
84 return singleton;
85}
86
87void Input::set_mouse_mode(MouseMode p_mode) {
88 ERR_FAIL_INDEX((int)p_mode, 5);
89 set_mouse_mode_func(p_mode);
90}
91
92Input::MouseMode Input::get_mouse_mode() const {
93 return get_mouse_mode_func();
94}
95
96void Input::_bind_methods() {
97 ClassDB::bind_method(D_METHOD("is_anything_pressed"), &Input::is_anything_pressed);
98 ClassDB::bind_method(D_METHOD("is_key_pressed", "keycode"), &Input::is_key_pressed);
99 ClassDB::bind_method(D_METHOD("is_physical_key_pressed", "keycode"), &Input::is_physical_key_pressed);
100 ClassDB::bind_method(D_METHOD("is_key_label_pressed", "keycode"), &Input::is_key_label_pressed);
101 ClassDB::bind_method(D_METHOD("is_mouse_button_pressed", "button"), &Input::is_mouse_button_pressed);
102 ClassDB::bind_method(D_METHOD("is_joy_button_pressed", "device", "button"), &Input::is_joy_button_pressed);
103 ClassDB::bind_method(D_METHOD("is_action_pressed", "action", "exact_match"), &Input::is_action_pressed, DEFVAL(false));
104 ClassDB::bind_method(D_METHOD("is_action_just_pressed", "action", "exact_match"), &Input::is_action_just_pressed, DEFVAL(false));
105 ClassDB::bind_method(D_METHOD("is_action_just_released", "action", "exact_match"), &Input::is_action_just_released, DEFVAL(false));
106 ClassDB::bind_method(D_METHOD("get_action_strength", "action", "exact_match"), &Input::get_action_strength, DEFVAL(false));
107 ClassDB::bind_method(D_METHOD("get_action_raw_strength", "action", "exact_match"), &Input::get_action_raw_strength, DEFVAL(false));
108 ClassDB::bind_method(D_METHOD("get_axis", "negative_action", "positive_action"), &Input::get_axis);
109 ClassDB::bind_method(D_METHOD("get_vector", "negative_x", "positive_x", "negative_y", "positive_y", "deadzone"), &Input::get_vector, DEFVAL(-1.0f));
110 ClassDB::bind_method(D_METHOD("add_joy_mapping", "mapping", "update_existing"), &Input::add_joy_mapping, DEFVAL(false));
111 ClassDB::bind_method(D_METHOD("remove_joy_mapping", "guid"), &Input::remove_joy_mapping);
112 ClassDB::bind_method(D_METHOD("is_joy_known", "device"), &Input::is_joy_known);
113 ClassDB::bind_method(D_METHOD("get_joy_axis", "device", "axis"), &Input::get_joy_axis);
114 ClassDB::bind_method(D_METHOD("get_joy_name", "device"), &Input::get_joy_name);
115 ClassDB::bind_method(D_METHOD("get_joy_guid", "device"), &Input::get_joy_guid);
116 ClassDB::bind_method(D_METHOD("get_joy_info", "device"), &Input::get_joy_info);
117 ClassDB::bind_method(D_METHOD("should_ignore_device", "vendor_id", "product_id"), &Input::should_ignore_device);
118 ClassDB::bind_method(D_METHOD("get_connected_joypads"), &Input::get_connected_joypads);
119 ClassDB::bind_method(D_METHOD("get_joy_vibration_strength", "device"), &Input::get_joy_vibration_strength);
120 ClassDB::bind_method(D_METHOD("get_joy_vibration_duration", "device"), &Input::get_joy_vibration_duration);
121 ClassDB::bind_method(D_METHOD("start_joy_vibration", "device", "weak_magnitude", "strong_magnitude", "duration"), &Input::start_joy_vibration, DEFVAL(0));
122 ClassDB::bind_method(D_METHOD("stop_joy_vibration", "device"), &Input::stop_joy_vibration);
123 ClassDB::bind_method(D_METHOD("vibrate_handheld", "duration_ms"), &Input::vibrate_handheld, DEFVAL(500));
124 ClassDB::bind_method(D_METHOD("get_gravity"), &Input::get_gravity);
125 ClassDB::bind_method(D_METHOD("get_accelerometer"), &Input::get_accelerometer);
126 ClassDB::bind_method(D_METHOD("get_magnetometer"), &Input::get_magnetometer);
127 ClassDB::bind_method(D_METHOD("get_gyroscope"), &Input::get_gyroscope);
128 ClassDB::bind_method(D_METHOD("set_gravity", "value"), &Input::set_gravity);
129 ClassDB::bind_method(D_METHOD("set_accelerometer", "value"), &Input::set_accelerometer);
130 ClassDB::bind_method(D_METHOD("set_magnetometer", "value"), &Input::set_magnetometer);
131 ClassDB::bind_method(D_METHOD("set_gyroscope", "value"), &Input::set_gyroscope);
132 ClassDB::bind_method(D_METHOD("get_last_mouse_velocity"), &Input::get_last_mouse_velocity);
133 ClassDB::bind_method(D_METHOD("get_mouse_button_mask"), &Input::get_mouse_button_mask);
134 ClassDB::bind_method(D_METHOD("set_mouse_mode", "mode"), &Input::set_mouse_mode);
135 ClassDB::bind_method(D_METHOD("get_mouse_mode"), &Input::get_mouse_mode);
136 ClassDB::bind_method(D_METHOD("warp_mouse", "position"), &Input::warp_mouse);
137 ClassDB::bind_method(D_METHOD("action_press", "action", "strength"), &Input::action_press, DEFVAL(1.f));
138 ClassDB::bind_method(D_METHOD("action_release", "action"), &Input::action_release);
139 ClassDB::bind_method(D_METHOD("set_default_cursor_shape", "shape"), &Input::set_default_cursor_shape, DEFVAL(CURSOR_ARROW));
140 ClassDB::bind_method(D_METHOD("get_current_cursor_shape"), &Input::get_current_cursor_shape);
141 ClassDB::bind_method(D_METHOD("set_custom_mouse_cursor", "image", "shape", "hotspot"), &Input::set_custom_mouse_cursor, DEFVAL(CURSOR_ARROW), DEFVAL(Vector2()));
142 ClassDB::bind_method(D_METHOD("parse_input_event", "event"), &Input::parse_input_event);
143 ClassDB::bind_method(D_METHOD("set_use_accumulated_input", "enable"), &Input::set_use_accumulated_input);
144 ClassDB::bind_method(D_METHOD("is_using_accumulated_input"), &Input::is_using_accumulated_input);
145 ClassDB::bind_method(D_METHOD("flush_buffered_events"), &Input::flush_buffered_events);
146
147 ADD_PROPERTY(PropertyInfo(Variant::INT, "mouse_mode"), "set_mouse_mode", "get_mouse_mode");
148 ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_accumulated_input"), "set_use_accumulated_input", "is_using_accumulated_input");
149
150 BIND_ENUM_CONSTANT(MOUSE_MODE_VISIBLE);
151 BIND_ENUM_CONSTANT(MOUSE_MODE_HIDDEN);
152 BIND_ENUM_CONSTANT(MOUSE_MODE_CAPTURED);
153 BIND_ENUM_CONSTANT(MOUSE_MODE_CONFINED);
154 BIND_ENUM_CONSTANT(MOUSE_MODE_CONFINED_HIDDEN);
155
156 BIND_ENUM_CONSTANT(CURSOR_ARROW);
157 BIND_ENUM_CONSTANT(CURSOR_IBEAM);
158 BIND_ENUM_CONSTANT(CURSOR_POINTING_HAND);
159 BIND_ENUM_CONSTANT(CURSOR_CROSS);
160 BIND_ENUM_CONSTANT(CURSOR_WAIT);
161 BIND_ENUM_CONSTANT(CURSOR_BUSY);
162 BIND_ENUM_CONSTANT(CURSOR_DRAG);
163 BIND_ENUM_CONSTANT(CURSOR_CAN_DROP);
164 BIND_ENUM_CONSTANT(CURSOR_FORBIDDEN);
165 BIND_ENUM_CONSTANT(CURSOR_VSIZE);
166 BIND_ENUM_CONSTANT(CURSOR_HSIZE);
167 BIND_ENUM_CONSTANT(CURSOR_BDIAGSIZE);
168 BIND_ENUM_CONSTANT(CURSOR_FDIAGSIZE);
169 BIND_ENUM_CONSTANT(CURSOR_MOVE);
170 BIND_ENUM_CONSTANT(CURSOR_VSPLIT);
171 BIND_ENUM_CONSTANT(CURSOR_HSPLIT);
172 BIND_ENUM_CONSTANT(CURSOR_HELP);
173
174 ADD_SIGNAL(MethodInfo("joy_connection_changed", PropertyInfo(Variant::INT, "device"), PropertyInfo(Variant::BOOL, "connected")));
175}
176
177void Input::get_argument_options(const StringName &p_function, int p_idx, List<String> *r_options) const {
178 String pf = p_function;
179
180 if ((p_idx == 0 && (pf == "is_action_pressed" || pf == "action_press" || pf == "action_release" || pf == "is_action_just_pressed" || pf == "is_action_just_released" || pf == "get_action_strength" || pf == "get_action_raw_strength")) ||
181 (p_idx < 2 && pf == "get_axis") ||
182 (p_idx < 4 && pf == "get_vector")) {
183 List<PropertyInfo> pinfo;
184 ProjectSettings::get_singleton()->get_property_list(&pinfo);
185
186 for (const PropertyInfo &pi : pinfo) {
187 if (!pi.name.begins_with("input/")) {
188 continue;
189 }
190
191 String name = pi.name.substr(pi.name.find("/") + 1, pi.name.length());
192 r_options->push_back(name.quote());
193 }
194 }
195}
196
197void Input::VelocityTrack::update(const Vector2 &p_delta_p) {
198 uint64_t tick = OS::get_singleton()->get_ticks_usec();
199 uint32_t tdiff = tick - last_tick;
200 float delta_t = tdiff / 1000000.0;
201 last_tick = tick;
202
203 if (delta_t > max_ref_frame) {
204 // First movement in a long time, reset and start again.
205 velocity = Vector2();
206 accum = p_delta_p;
207 accum_t = 0;
208 return;
209 }
210
211 accum += p_delta_p;
212 accum_t += delta_t;
213
214 if (accum_t < min_ref_frame) {
215 // Not enough time has passed to calculate speed precisely.
216 return;
217 }
218
219 velocity = accum / accum_t;
220 accum = Vector2();
221 accum_t = 0;
222}
223
224void Input::VelocityTrack::reset() {
225 last_tick = OS::get_singleton()->get_ticks_usec();
226 velocity = Vector2();
227 accum = Vector2();
228 accum_t = 0;
229}
230
231Input::VelocityTrack::VelocityTrack() {
232 min_ref_frame = 0.1;
233 max_ref_frame = 3.0;
234 reset();
235}
236
237bool Input::is_anything_pressed() const {
238 _THREAD_SAFE_METHOD_
239
240 if (!keys_pressed.is_empty() || !joy_buttons_pressed.is_empty() || !mouse_button_mask.is_empty()) {
241 return true;
242 }
243
244 for (const KeyValue<StringName, Input::Action> &E : action_state) {
245 if (E.value.pressed) {
246 return true;
247 }
248 }
249
250 return false;
251}
252
253bool Input::is_key_pressed(Key p_keycode) const {
254 _THREAD_SAFE_METHOD_
255 return keys_pressed.has(p_keycode);
256}
257
258bool Input::is_physical_key_pressed(Key p_keycode) const {
259 _THREAD_SAFE_METHOD_
260 return physical_keys_pressed.has(p_keycode);
261}
262
263bool Input::is_key_label_pressed(Key p_keycode) const {
264 _THREAD_SAFE_METHOD_
265 return key_label_pressed.has(p_keycode);
266}
267
268bool Input::is_mouse_button_pressed(MouseButton p_button) const {
269 _THREAD_SAFE_METHOD_
270 return mouse_button_mask.has_flag(mouse_button_to_mask(p_button));
271}
272
273static JoyAxis _combine_device(JoyAxis p_value, int p_device) {
274 return JoyAxis((int)p_value | (p_device << 20));
275}
276
277static JoyButton _combine_device(JoyButton p_value, int p_device) {
278 return JoyButton((int)p_value | (p_device << 20));
279}
280
281bool Input::is_joy_button_pressed(int p_device, JoyButton p_button) const {
282 _THREAD_SAFE_METHOD_
283 return joy_buttons_pressed.has(_combine_device(p_button, p_device));
284}
285
286bool Input::is_action_pressed(const StringName &p_action, bool p_exact) const {
287 ERR_FAIL_COND_V_MSG(!InputMap::get_singleton()->has_action(p_action), false, InputMap::get_singleton()->suggest_actions(p_action));
288 return action_state.has(p_action) && action_state[p_action].pressed > 0 && (p_exact ? action_state[p_action].exact : true);
289}
290
291bool Input::is_action_just_pressed(const StringName &p_action, bool p_exact) const {
292 ERR_FAIL_COND_V_MSG(!InputMap::get_singleton()->has_action(p_action), false, InputMap::get_singleton()->suggest_actions(p_action));
293 HashMap<StringName, Action>::ConstIterator E = action_state.find(p_action);
294 if (!E) {
295 return false;
296 }
297
298 if (p_exact && E->value.exact == false) {
299 return false;
300 }
301
302 // Backward compatibility for legacy behavior, only return true if currently pressed.
303 bool pressed_requirement = legacy_just_pressed_behavior ? E->value.pressed : true;
304
305 if (Engine::get_singleton()->is_in_physics_frame()) {
306 return pressed_requirement && E->value.pressed_physics_frame == Engine::get_singleton()->get_physics_frames();
307 } else {
308 return pressed_requirement && E->value.pressed_process_frame == Engine::get_singleton()->get_process_frames();
309 }
310}
311
312bool Input::is_action_just_released(const StringName &p_action, bool p_exact) const {
313 ERR_FAIL_COND_V_MSG(!InputMap::get_singleton()->has_action(p_action), false, InputMap::get_singleton()->suggest_actions(p_action));
314 HashMap<StringName, Action>::ConstIterator E = action_state.find(p_action);
315 if (!E) {
316 return false;
317 }
318
319 if (p_exact && E->value.exact == false) {
320 return false;
321 }
322
323 // Backward compatibility for legacy behavior, only return true if currently released.
324 bool released_requirement = legacy_just_pressed_behavior ? !E->value.pressed : true;
325
326 if (Engine::get_singleton()->is_in_physics_frame()) {
327 return released_requirement && E->value.released_physics_frame == Engine::get_singleton()->get_physics_frames();
328 } else {
329 return released_requirement && E->value.released_process_frame == Engine::get_singleton()->get_process_frames();
330 }
331}
332
333float Input::get_action_strength(const StringName &p_action, bool p_exact) const {
334 ERR_FAIL_COND_V_MSG(!InputMap::get_singleton()->has_action(p_action), 0.0, InputMap::get_singleton()->suggest_actions(p_action));
335 HashMap<StringName, Action>::ConstIterator E = action_state.find(p_action);
336 if (!E) {
337 return 0.0f;
338 }
339
340 if (p_exact && E->value.exact == false) {
341 return 0.0f;
342 }
343
344 return E->value.strength;
345}
346
347float Input::get_action_raw_strength(const StringName &p_action, bool p_exact) const {
348 ERR_FAIL_COND_V_MSG(!InputMap::get_singleton()->has_action(p_action), 0.0, InputMap::get_singleton()->suggest_actions(p_action));
349 HashMap<StringName, Action>::ConstIterator E = action_state.find(p_action);
350 if (!E) {
351 return 0.0f;
352 }
353
354 if (p_exact && E->value.exact == false) {
355 return 0.0f;
356 }
357
358 return E->value.raw_strength;
359}
360
361float Input::get_axis(const StringName &p_negative_action, const StringName &p_positive_action) const {
362 return get_action_strength(p_positive_action) - get_action_strength(p_negative_action);
363}
364
365Vector2 Input::get_vector(const StringName &p_negative_x, const StringName &p_positive_x, const StringName &p_negative_y, const StringName &p_positive_y, float p_deadzone) const {
366 Vector2 vector = Vector2(
367 get_action_raw_strength(p_positive_x) - get_action_raw_strength(p_negative_x),
368 get_action_raw_strength(p_positive_y) - get_action_raw_strength(p_negative_y));
369
370 if (p_deadzone < 0.0f) {
371 // If the deadzone isn't specified, get it from the average of the actions.
372 p_deadzone = 0.25 *
373 (InputMap::get_singleton()->action_get_deadzone(p_positive_x) +
374 InputMap::get_singleton()->action_get_deadzone(p_negative_x) +
375 InputMap::get_singleton()->action_get_deadzone(p_positive_y) +
376 InputMap::get_singleton()->action_get_deadzone(p_negative_y));
377 }
378
379 // Circular length limiting and deadzone.
380 float length = vector.length();
381 if (length <= p_deadzone) {
382 return Vector2();
383 } else if (length > 1.0f) {
384 return vector / length;
385 } else {
386 // Inverse lerp length to map (p_deadzone, 1) to (0, 1).
387 return vector * (Math::inverse_lerp(p_deadzone, 1.0f, length) / length);
388 }
389}
390
391float Input::get_joy_axis(int p_device, JoyAxis p_axis) const {
392 _THREAD_SAFE_METHOD_
393 JoyAxis c = _combine_device(p_axis, p_device);
394 if (_joy_axis.has(c)) {
395 return _joy_axis[c];
396 } else {
397 return 0;
398 }
399}
400
401String Input::get_joy_name(int p_idx) {
402 _THREAD_SAFE_METHOD_
403 return joy_names[p_idx].name;
404}
405
406Vector2 Input::get_joy_vibration_strength(int p_device) {
407 if (joy_vibration.has(p_device)) {
408 return Vector2(joy_vibration[p_device].weak_magnitude, joy_vibration[p_device].strong_magnitude);
409 } else {
410 return Vector2(0, 0);
411 }
412}
413
414uint64_t Input::get_joy_vibration_timestamp(int p_device) {
415 if (joy_vibration.has(p_device)) {
416 return joy_vibration[p_device].timestamp;
417 } else {
418 return 0;
419 }
420}
421
422float Input::get_joy_vibration_duration(int p_device) {
423 if (joy_vibration.has(p_device)) {
424 return joy_vibration[p_device].duration;
425 } else {
426 return 0.f;
427 }
428}
429
430static String _hex_str(uint8_t p_byte) {
431 static const char *dict = "0123456789abcdef";
432 char ret[3];
433 ret[2] = 0;
434
435 ret[0] = dict[p_byte >> 4];
436 ret[1] = dict[p_byte & 0xf];
437
438 return ret;
439}
440
441void Input::joy_connection_changed(int p_idx, bool p_connected, String p_name, String p_guid, Dictionary p_joypad_info) {
442 _THREAD_SAFE_METHOD_
443 Joypad js;
444 js.name = p_connected ? p_name : "";
445 js.uid = p_connected ? p_guid : "";
446 js.info = p_connected ? p_joypad_info : Dictionary();
447
448 if (p_connected) {
449 String uidname = p_guid;
450 if (p_guid.is_empty()) {
451 int uidlen = MIN(p_name.length(), 16);
452 for (int i = 0; i < uidlen; i++) {
453 uidname = uidname + _hex_str(p_name[i]);
454 }
455 }
456 js.uid = uidname;
457 js.connected = true;
458 int mapping = fallback_mapping;
459 for (int i = 0; i < map_db.size(); i++) {
460 if (js.uid == map_db[i].uid) {
461 mapping = i;
462 js.name = map_db[i].name;
463 }
464 }
465 js.mapping = mapping;
466 } else {
467 js.connected = false;
468 for (int i = 0; i < (int)JoyButton::MAX; i++) {
469 JoyButton c = _combine_device((JoyButton)i, p_idx);
470 joy_buttons_pressed.erase(c);
471 }
472 for (int i = 0; i < (int)JoyAxis::MAX; i++) {
473 set_joy_axis(p_idx, (JoyAxis)i, 0.0f);
474 }
475 }
476 joy_names[p_idx] = js;
477
478 // Ensure this signal is emitted on the main thread, as some platforms (e.g. Linux) call this from a different thread.
479 call_deferred("emit_signal", SNAME("joy_connection_changed"), p_idx, p_connected);
480}
481
482Vector3 Input::get_gravity() const {
483 _THREAD_SAFE_METHOD_
484 return gravity;
485}
486
487Vector3 Input::get_accelerometer() const {
488 _THREAD_SAFE_METHOD_
489 return accelerometer;
490}
491
492Vector3 Input::get_magnetometer() const {
493 _THREAD_SAFE_METHOD_
494 return magnetometer;
495}
496
497Vector3 Input::get_gyroscope() const {
498 _THREAD_SAFE_METHOD_
499 return gyroscope;
500}
501
502void Input::_parse_input_event_impl(const Ref<InputEvent> &p_event, bool p_is_emulated) {
503 // This function does the final delivery of the input event to user land.
504 // Regardless where the event came from originally, this has to happen on the main thread.
505 DEV_ASSERT(Thread::get_caller_id() == Thread::get_main_id());
506
507 // Notes on mouse-touch emulation:
508 // - Emulated mouse events are parsed, that is, re-routed to this method, so they make the same effects
509 // as true mouse events. The only difference is the situation is flagged as emulated so they are not
510 // emulated back to touch events in an endless loop.
511 // - Emulated touch events are handed right to the main loop (i.e., the SceneTree) because they don't
512 // require additional handling by this class.
513
514 Ref<InputEventKey> k = p_event;
515 if (k.is_valid() && !k->is_echo() && k->get_keycode() != Key::NONE) {
516 if (k->is_pressed()) {
517 keys_pressed.insert(k->get_keycode());
518 } else {
519 keys_pressed.erase(k->get_keycode());
520 }
521 }
522 if (k.is_valid() && !k->is_echo() && k->get_physical_keycode() != Key::NONE) {
523 if (k->is_pressed()) {
524 physical_keys_pressed.insert(k->get_physical_keycode());
525 } else {
526 physical_keys_pressed.erase(k->get_physical_keycode());
527 }
528 }
529 if (k.is_valid() && !k->is_echo() && k->get_key_label() != Key::NONE) {
530 if (k->is_pressed()) {
531 key_label_pressed.insert(k->get_key_label());
532 } else {
533 key_label_pressed.erase(k->get_key_label());
534 }
535 }
536
537 Ref<InputEventMouseButton> mb = p_event;
538
539 if (mb.is_valid()) {
540 if (mb->is_pressed()) {
541 mouse_button_mask.set_flag(mouse_button_to_mask(mb->get_button_index()));
542 } else {
543 mouse_button_mask.clear_flag(mouse_button_to_mask(mb->get_button_index()));
544 }
545
546 Point2 pos = mb->get_global_position();
547 if (mouse_pos != pos) {
548 set_mouse_position(pos);
549 }
550
551 if (event_dispatch_function && emulate_touch_from_mouse && !p_is_emulated && mb->get_button_index() == MouseButton::LEFT) {
552 Ref<InputEventScreenTouch> touch_event;
553 touch_event.instantiate();
554 touch_event->set_pressed(mb->is_pressed());
555 touch_event->set_canceled(mb->is_canceled());
556 touch_event->set_position(mb->get_position());
557 touch_event->set_double_tap(mb->is_double_click());
558 touch_event->set_device(InputEvent::DEVICE_ID_EMULATION);
559 _THREAD_SAFE_UNLOCK_
560 event_dispatch_function(touch_event);
561 _THREAD_SAFE_LOCK_
562 }
563 }
564
565 Ref<InputEventMouseMotion> mm = p_event;
566
567 if (mm.is_valid()) {
568 Point2 position = mm->get_global_position();
569 if (mouse_pos != position) {
570 set_mouse_position(position);
571 }
572 Vector2 relative = mm->get_relative();
573 mouse_velocity_track.update(relative);
574
575 if (event_dispatch_function && emulate_touch_from_mouse && !p_is_emulated && mm->get_button_mask().has_flag(MouseButtonMask::LEFT)) {
576 Ref<InputEventScreenDrag> drag_event;
577 drag_event.instantiate();
578
579 drag_event->set_position(position);
580 drag_event->set_relative(relative);
581 drag_event->set_tilt(mm->get_tilt());
582 drag_event->set_pen_inverted(mm->get_pen_inverted());
583 drag_event->set_pressure(mm->get_pressure());
584 drag_event->set_velocity(get_last_mouse_velocity());
585 drag_event->set_device(InputEvent::DEVICE_ID_EMULATION);
586
587 _THREAD_SAFE_UNLOCK_
588 event_dispatch_function(drag_event);
589 _THREAD_SAFE_LOCK_
590 }
591 }
592
593 Ref<InputEventScreenTouch> st = p_event;
594
595 if (st.is_valid()) {
596 if (st->is_pressed()) {
597 VelocityTrack &track = touch_velocity_track[st->get_index()];
598 track.reset();
599 } else {
600 // Since a pointer index may not occur again (OSs may or may not reuse them),
601 // imperatively remove it from the map to keep no fossil entries in it
602 touch_velocity_track.erase(st->get_index());
603 }
604
605 if (emulate_mouse_from_touch) {
606 bool translate = false;
607 if (st->is_pressed()) {
608 if (mouse_from_touch_index == -1) {
609 translate = true;
610 mouse_from_touch_index = st->get_index();
611 }
612 } else {
613 if (st->get_index() == mouse_from_touch_index) {
614 translate = true;
615 mouse_from_touch_index = -1;
616 }
617 }
618
619 if (translate) {
620 Ref<InputEventMouseButton> button_event;
621 button_event.instantiate();
622
623 button_event->set_device(InputEvent::DEVICE_ID_EMULATION);
624 button_event->set_position(st->get_position());
625 button_event->set_global_position(st->get_position());
626 button_event->set_pressed(st->is_pressed());
627 button_event->set_canceled(st->is_canceled());
628 button_event->set_button_index(MouseButton::LEFT);
629 button_event->set_double_click(st->is_double_tap());
630
631 BitField<MouseButtonMask> ev_bm = mouse_button_mask;
632 if (st->is_pressed()) {
633 ev_bm.set_flag(MouseButtonMask::LEFT);
634 } else {
635 ev_bm.clear_flag(MouseButtonMask::LEFT);
636 }
637 button_event->set_button_mask(ev_bm);
638
639 _parse_input_event_impl(button_event, true);
640 }
641 }
642 }
643
644 Ref<InputEventScreenDrag> sd = p_event;
645
646 if (sd.is_valid()) {
647 VelocityTrack &track = touch_velocity_track[sd->get_index()];
648 track.update(sd->get_relative());
649 sd->set_velocity(track.velocity);
650
651 if (emulate_mouse_from_touch && sd->get_index() == mouse_from_touch_index) {
652 Ref<InputEventMouseMotion> motion_event;
653 motion_event.instantiate();
654
655 motion_event->set_device(InputEvent::DEVICE_ID_EMULATION);
656 motion_event->set_tilt(sd->get_tilt());
657 motion_event->set_pen_inverted(sd->get_pen_inverted());
658 motion_event->set_pressure(sd->get_pressure());
659 motion_event->set_position(sd->get_position());
660 motion_event->set_global_position(sd->get_position());
661 motion_event->set_relative(sd->get_relative());
662 motion_event->set_velocity(sd->get_velocity());
663 motion_event->set_button_mask(mouse_button_mask);
664
665 _parse_input_event_impl(motion_event, true);
666 }
667 }
668
669 Ref<InputEventJoypadButton> jb = p_event;
670
671 if (jb.is_valid()) {
672 JoyButton c = _combine_device(jb->get_button_index(), jb->get_device());
673
674 if (jb->is_pressed()) {
675 joy_buttons_pressed.insert(c);
676 } else {
677 joy_buttons_pressed.erase(c);
678 }
679 }
680
681 Ref<InputEventJoypadMotion> jm = p_event;
682
683 if (jm.is_valid()) {
684 set_joy_axis(jm->get_device(), jm->get_axis(), jm->get_axis_value());
685 }
686
687 Ref<InputEventGesture> ge = p_event;
688
689 if (ge.is_valid()) {
690 if (event_dispatch_function) {
691 _THREAD_SAFE_UNLOCK_
692 event_dispatch_function(ge);
693 _THREAD_SAFE_LOCK_
694 }
695 }
696
697 for (const KeyValue<StringName, InputMap::Action> &E : InputMap::get_singleton()->get_action_map()) {
698 if (InputMap::get_singleton()->event_is_action(p_event, E.key)) {
699 Action &action = action_state[E.key];
700 bool is_pressed = false;
701
702 if (!p_event->is_echo()) {
703 if (p_event->is_action_pressed(E.key)) {
704 if (jm.is_valid()) {
705 // If axis is already pressed, don't increase the pressed counter.
706 if (!action.axis_pressed) {
707 action.pressed++;
708 action.axis_pressed = true;
709 }
710 } else {
711 action.pressed++;
712 }
713
714 is_pressed = true;
715 if (action.pressed == 1) {
716 action.pressed_physics_frame = Engine::get_singleton()->get_physics_frames();
717 action.pressed_process_frame = Engine::get_singleton()->get_process_frames();
718 }
719 } else {
720 bool is_released = true;
721 if (jm.is_valid()) {
722 // Same as above. Don't release axis when not pressed.
723 if (action.axis_pressed) {
724 action.axis_pressed = false;
725 } else {
726 is_released = false;
727 }
728 }
729
730 if (is_released) {
731 if (action.pressed == 1) {
732 action.released_physics_frame = Engine::get_singleton()->get_physics_frames();
733 action.released_process_frame = Engine::get_singleton()->get_process_frames();
734 }
735 action.pressed = MAX(action.pressed - 1, 0);
736 }
737 }
738 action.exact = InputMap::get_singleton()->event_is_action(p_event, E.key, true);
739 }
740
741 if (is_pressed || action.pressed == 0) {
742 action.strength = p_event->get_action_strength(E.key);
743 action.raw_strength = p_event->get_action_raw_strength(E.key);
744 }
745 }
746 }
747
748 if (event_dispatch_function) {
749 _THREAD_SAFE_UNLOCK_
750 event_dispatch_function(p_event);
751 _THREAD_SAFE_LOCK_
752 }
753}
754
755void Input::set_joy_axis(int p_device, JoyAxis p_axis, float p_value) {
756 _THREAD_SAFE_METHOD_
757 JoyAxis c = _combine_device(p_axis, p_device);
758 _joy_axis[c] = p_value;
759}
760
761void Input::start_joy_vibration(int p_device, float p_weak_magnitude, float p_strong_magnitude, float p_duration) {
762 _THREAD_SAFE_METHOD_
763 if (p_weak_magnitude < 0.f || p_weak_magnitude > 1.f || p_strong_magnitude < 0.f || p_strong_magnitude > 1.f) {
764 return;
765 }
766 VibrationInfo vibration;
767 vibration.weak_magnitude = p_weak_magnitude;
768 vibration.strong_magnitude = p_strong_magnitude;
769 vibration.duration = p_duration;
770 vibration.timestamp = OS::get_singleton()->get_ticks_usec();
771 joy_vibration[p_device] = vibration;
772}
773
774void Input::stop_joy_vibration(int p_device) {
775 _THREAD_SAFE_METHOD_
776 VibrationInfo vibration;
777 vibration.weak_magnitude = 0;
778 vibration.strong_magnitude = 0;
779 vibration.duration = 0;
780 vibration.timestamp = OS::get_singleton()->get_ticks_usec();
781 joy_vibration[p_device] = vibration;
782}
783
784void Input::vibrate_handheld(int p_duration_ms) {
785 OS::get_singleton()->vibrate_handheld(p_duration_ms);
786}
787
788void Input::set_gravity(const Vector3 &p_gravity) {
789 _THREAD_SAFE_METHOD_
790
791 gravity = p_gravity;
792}
793
794void Input::set_accelerometer(const Vector3 &p_accel) {
795 _THREAD_SAFE_METHOD_
796
797 accelerometer = p_accel;
798}
799
800void Input::set_magnetometer(const Vector3 &p_magnetometer) {
801 _THREAD_SAFE_METHOD_
802
803 magnetometer = p_magnetometer;
804}
805
806void Input::set_gyroscope(const Vector3 &p_gyroscope) {
807 _THREAD_SAFE_METHOD_
808
809 gyroscope = p_gyroscope;
810}
811
812void Input::set_mouse_position(const Point2 &p_posf) {
813 mouse_pos = p_posf;
814}
815
816Point2 Input::get_mouse_position() const {
817 return mouse_pos;
818}
819
820Point2 Input::get_last_mouse_velocity() {
821 mouse_velocity_track.update(Vector2());
822 return mouse_velocity_track.velocity;
823}
824
825BitField<MouseButtonMask> Input::get_mouse_button_mask() const {
826 return mouse_button_mask; // do not trust OS implementation, should remove it - OS::get_singleton()->get_mouse_button_state();
827}
828
829void Input::warp_mouse(const Vector2 &p_position) {
830 warp_mouse_func(p_position);
831}
832
833Point2i Input::warp_mouse_motion(const Ref<InputEventMouseMotion> &p_motion, const Rect2 &p_rect) {
834 // The relative distance reported for the next event after a warp is in the boundaries of the
835 // size of the rect on that axis, but it may be greater, in which case there's no problem as fmod()
836 // will warp it, but if the pointer has moved in the opposite direction between the pointer relocation
837 // and the subsequent event, the reported relative distance will be less than the size of the rect
838 // and thus fmod() will be disabled for handling the situation.
839 // And due to this mouse warping mechanism being stateless, we need to apply some heuristics to
840 // detect the warp: if the relative distance is greater than the half of the size of the relevant rect
841 // (checked per each axis), it will be considered as the consequence of a former pointer warp.
842
843 const Point2i rel_sign(p_motion->get_relative().x >= 0.0f ? 1 : -1, p_motion->get_relative().y >= 0.0 ? 1 : -1);
844 const Size2i warp_margin = p_rect.size * 0.5f;
845 const Point2i rel_warped(
846 Math::fmod(p_motion->get_relative().x + rel_sign.x * warp_margin.x, p_rect.size.x) - rel_sign.x * warp_margin.x,
847 Math::fmod(p_motion->get_relative().y + rel_sign.y * warp_margin.y, p_rect.size.y) - rel_sign.y * warp_margin.y);
848
849 const Point2i pos_local = p_motion->get_global_position() - p_rect.position;
850 const Point2i pos_warped(Math::fposmod(pos_local.x, p_rect.size.x), Math::fposmod(pos_local.y, p_rect.size.y));
851 if (pos_warped != pos_local) {
852 warp_mouse(pos_warped + p_rect.position);
853 }
854
855 return rel_warped;
856}
857
858void Input::action_press(const StringName &p_action, float p_strength) {
859 // Create or retrieve existing action.
860 Action &action = action_state[p_action];
861
862 action.pressed++;
863 if (action.pressed == 1) {
864 action.pressed_physics_frame = Engine::get_singleton()->get_physics_frames();
865 action.pressed_process_frame = Engine::get_singleton()->get_process_frames();
866 }
867 action.strength = p_strength;
868 action.raw_strength = p_strength;
869 action.exact = true;
870}
871
872void Input::action_release(const StringName &p_action) {
873 // Create or retrieve existing action.
874 Action &action = action_state[p_action];
875
876 action.pressed--;
877 if (action.pressed == 0) {
878 action.released_physics_frame = Engine::get_singleton()->get_physics_frames();
879 action.released_process_frame = Engine::get_singleton()->get_process_frames();
880 }
881 action.strength = 0.0f;
882 action.raw_strength = 0.0f;
883 action.exact = true;
884}
885
886void Input::set_emulate_touch_from_mouse(bool p_emulate) {
887 emulate_touch_from_mouse = p_emulate;
888}
889
890bool Input::is_emulating_touch_from_mouse() const {
891 return emulate_touch_from_mouse;
892}
893
894// Calling this whenever the game window is focused helps unsticking the "touch mouse"
895// if the OS or its abstraction class hasn't properly reported that touch pointers raised
896void Input::ensure_touch_mouse_raised() {
897 _THREAD_SAFE_METHOD_
898 if (mouse_from_touch_index != -1) {
899 mouse_from_touch_index = -1;
900
901 Ref<InputEventMouseButton> button_event;
902 button_event.instantiate();
903
904 button_event->set_device(InputEvent::DEVICE_ID_EMULATION);
905 button_event->set_position(mouse_pos);
906 button_event->set_global_position(mouse_pos);
907 button_event->set_pressed(false);
908 button_event->set_button_index(MouseButton::LEFT);
909 BitField<MouseButtonMask> ev_bm = mouse_button_mask;
910 ev_bm.clear_flag(MouseButtonMask::LEFT);
911 button_event->set_button_mask(ev_bm);
912
913 _parse_input_event_impl(button_event, true);
914 }
915}
916
917void Input::set_emulate_mouse_from_touch(bool p_emulate) {
918 emulate_mouse_from_touch = p_emulate;
919}
920
921bool Input::is_emulating_mouse_from_touch() const {
922 return emulate_mouse_from_touch;
923}
924
925Input::CursorShape Input::get_default_cursor_shape() const {
926 return default_shape;
927}
928
929void Input::set_default_cursor_shape(CursorShape p_shape) {
930 if (default_shape == p_shape) {
931 return;
932 }
933
934 default_shape = p_shape;
935 // The default shape is set in Viewport::_gui_input_event. To instantly
936 // see the shape in the viewport we need to trigger a mouse motion event.
937 Ref<InputEventMouseMotion> mm;
938 mm.instantiate();
939 mm->set_position(mouse_pos);
940 mm->set_global_position(mouse_pos);
941 mm->set_device(InputEvent::DEVICE_ID_INTERNAL);
942 parse_input_event(mm);
943}
944
945Input::CursorShape Input::get_current_cursor_shape() const {
946 return get_current_cursor_shape_func();
947}
948
949void Input::set_custom_mouse_cursor(const Ref<Resource> &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot) {
950 if (Engine::get_singleton()->is_editor_hint()) {
951 return;
952 }
953
954 ERR_FAIL_INDEX(p_shape, CursorShape::CURSOR_MAX);
955
956 set_custom_mouse_cursor_func(p_cursor, p_shape, p_hotspot);
957}
958
959void Input::parse_input_event(const Ref<InputEvent> &p_event) {
960 _THREAD_SAFE_METHOD_
961
962 ERR_FAIL_COND(p_event.is_null());
963
964#ifdef DEBUG_ENABLED
965 uint64_t curr_frame = Engine::get_singleton()->get_process_frames();
966 if (curr_frame != last_parsed_frame) {
967 frame_parsed_events.clear();
968 last_parsed_frame = curr_frame;
969 frame_parsed_events.insert(p_event);
970 } else if (frame_parsed_events.has(p_event)) {
971 // It would be technically safe to send the same event in cases such as:
972 // - After an explicit flush.
973 // - In platforms using buffering when agile flushing is enabled, after one of the mid-frame flushes.
974 // - If platform doesn't use buffering and event accumulation is disabled.
975 // - If platform doesn't use buffering and the event type is not accumulable.
976 // However, it wouldn't be reasonable to ask users to remember the full ruleset and be aware at all times
977 // of the possibilities of the target platform, project settings and engine internals, which may change
978 // without prior notice.
979 // Therefore, the guideline is, "don't send the same event object more than once per frame".
980 WARN_PRINT_ONCE(
981 "An input event object is being parsed more than once in the same frame, which is unsafe.\n"
982 "If you are generating events in a script, you have to instantiate a new event instead of sending the same one more than once, unless the original one was sent on an earlier frame.\n"
983 "You can call duplicate() on the event to get a new instance with identical values.");
984 } else {
985 frame_parsed_events.insert(p_event);
986 }
987#endif
988
989 if (use_accumulated_input) {
990 if (buffered_events.is_empty() || !buffered_events.back()->get()->accumulate(p_event)) {
991 buffered_events.push_back(p_event);
992 }
993 } else if (use_input_buffering) {
994 buffered_events.push_back(p_event);
995 } else {
996 _parse_input_event_impl(p_event, false);
997 }
998}
999
1000void Input::flush_buffered_events() {
1001 _THREAD_SAFE_METHOD_
1002
1003 while (buffered_events.front()) {
1004 // The final delivery of the input event involves releasing the lock.
1005 // While the lock is released, another thread may lock it and add new events to the back.
1006 // Therefore, we get each event and pop it while we still have the lock,
1007 // to ensure the list is in a consistent state.
1008 List<Ref<InputEvent>>::Element *E = buffered_events.front();
1009 Ref<InputEvent> e = E->get();
1010 buffered_events.pop_front();
1011
1012 _parse_input_event_impl(e, false);
1013 }
1014}
1015
1016bool Input::is_using_input_buffering() {
1017 return use_input_buffering;
1018}
1019
1020void Input::set_use_input_buffering(bool p_enable) {
1021 use_input_buffering = p_enable;
1022}
1023
1024void Input::set_use_accumulated_input(bool p_enable) {
1025 use_accumulated_input = p_enable;
1026}
1027
1028bool Input::is_using_accumulated_input() {
1029 return use_accumulated_input;
1030}
1031
1032void Input::release_pressed_events() {
1033 flush_buffered_events(); // this is needed to release actions strengths
1034
1035 keys_pressed.clear();
1036 physical_keys_pressed.clear();
1037 key_label_pressed.clear();
1038 joy_buttons_pressed.clear();
1039 _joy_axis.clear();
1040
1041 for (KeyValue<StringName, Input::Action> &E : action_state) {
1042 if (E.value.pressed > 0) {
1043 // Make sure the action is really released.
1044 E.value.pressed = 1;
1045 action_release(E.key);
1046 }
1047 }
1048}
1049
1050void Input::set_event_dispatch_function(EventDispatchFunc p_function) {
1051 event_dispatch_function = p_function;
1052}
1053
1054void Input::joy_button(int p_device, JoyButton p_button, bool p_pressed) {
1055 _THREAD_SAFE_METHOD_;
1056 Joypad &joy = joy_names[p_device];
1057 ERR_FAIL_INDEX((int)p_button, (int)JoyButton::MAX);
1058
1059 if (joy.last_buttons[(size_t)p_button] == p_pressed) {
1060 return;
1061 }
1062 joy.last_buttons[(size_t)p_button] = p_pressed;
1063 if (joy.mapping == -1) {
1064 _button_event(p_device, p_button, p_pressed);
1065 return;
1066 }
1067
1068 JoyEvent map = _get_mapped_button_event(map_db[joy.mapping], p_button);
1069
1070 if (map.type == TYPE_BUTTON) {
1071 _button_event(p_device, (JoyButton)map.index, p_pressed);
1072 return;
1073 }
1074
1075 if (map.type == TYPE_AXIS) {
1076 _axis_event(p_device, (JoyAxis)map.index, p_pressed ? map.value : 0.0);
1077 }
1078 // no event?
1079}
1080
1081void Input::joy_axis(int p_device, JoyAxis p_axis, float p_value) {
1082 _THREAD_SAFE_METHOD_;
1083
1084 ERR_FAIL_INDEX((int)p_axis, (int)JoyAxis::MAX);
1085
1086 Joypad &joy = joy_names[p_device];
1087
1088 if (joy.last_axis[(size_t)p_axis] == p_value) {
1089 return;
1090 }
1091
1092 joy.last_axis[(size_t)p_axis] = p_value;
1093
1094 if (joy.mapping == -1) {
1095 _axis_event(p_device, p_axis, p_value);
1096 return;
1097 }
1098
1099 JoyEvent map = _get_mapped_axis_event(map_db[joy.mapping], p_axis, p_value);
1100
1101 if (map.type == TYPE_BUTTON) {
1102 bool pressed = map.value > 0.5;
1103 if (pressed != joy_buttons_pressed.has(_combine_device((JoyButton)map.index, p_device))) {
1104 _button_event(p_device, (JoyButton)map.index, pressed);
1105 }
1106
1107 // Ensure opposite D-Pad button is also released.
1108 switch ((JoyButton)map.index) {
1109 case JoyButton::DPAD_UP:
1110 if (joy_buttons_pressed.has(_combine_device(JoyButton::DPAD_DOWN, p_device))) {
1111 _button_event(p_device, JoyButton::DPAD_DOWN, false);
1112 }
1113 break;
1114 case JoyButton::DPAD_DOWN:
1115 if (joy_buttons_pressed.has(_combine_device(JoyButton::DPAD_UP, p_device))) {
1116 _button_event(p_device, JoyButton::DPAD_UP, false);
1117 }
1118 break;
1119 case JoyButton::DPAD_LEFT:
1120 if (joy_buttons_pressed.has(_combine_device(JoyButton::DPAD_RIGHT, p_device))) {
1121 _button_event(p_device, JoyButton::DPAD_RIGHT, false);
1122 }
1123 break;
1124 case JoyButton::DPAD_RIGHT:
1125 if (joy_buttons_pressed.has(_combine_device(JoyButton::DPAD_LEFT, p_device))) {
1126 _button_event(p_device, JoyButton::DPAD_LEFT, false);
1127 }
1128 break;
1129 default:
1130 // Nothing to do.
1131 break;
1132 }
1133 return;
1134 }
1135
1136 if (map.type == TYPE_AXIS) {
1137 JoyAxis axis = JoyAxis(map.index);
1138 float value = map.value;
1139 if (axis == JoyAxis::TRIGGER_LEFT || axis == JoyAxis::TRIGGER_RIGHT) {
1140 // Convert to a value between 0.0f and 1.0f.
1141 value = 0.5f + value / 2.0f;
1142 }
1143 _axis_event(p_device, axis, value);
1144 return;
1145 }
1146}
1147
1148void Input::joy_hat(int p_device, BitField<HatMask> p_val) {
1149 _THREAD_SAFE_METHOD_;
1150 const Joypad &joy = joy_names[p_device];
1151
1152 JoyEvent map[(size_t)HatDir::MAX];
1153
1154 map[(size_t)HatDir::UP].type = TYPE_BUTTON;
1155 map[(size_t)HatDir::UP].index = (int)JoyButton::DPAD_UP;
1156 map[(size_t)HatDir::UP].value = 0;
1157
1158 map[(size_t)HatDir::RIGHT].type = TYPE_BUTTON;
1159 map[(size_t)HatDir::RIGHT].index = (int)JoyButton::DPAD_RIGHT;
1160 map[(size_t)HatDir::RIGHT].value = 0;
1161
1162 map[(size_t)HatDir::DOWN].type = TYPE_BUTTON;
1163 map[(size_t)HatDir::DOWN].index = (int)JoyButton::DPAD_DOWN;
1164 map[(size_t)HatDir::DOWN].value = 0;
1165
1166 map[(size_t)HatDir::LEFT].type = TYPE_BUTTON;
1167 map[(size_t)HatDir::LEFT].index = (int)JoyButton::DPAD_LEFT;
1168 map[(size_t)HatDir::LEFT].value = 0;
1169
1170 if (joy.mapping != -1) {
1171 _get_mapped_hat_events(map_db[joy.mapping], (HatDir)0, map);
1172 }
1173
1174 int cur_val = joy_names[p_device].hat_current;
1175
1176 for (int hat_direction = 0, hat_mask = 1; hat_direction < (int)HatDir::MAX; hat_direction++, hat_mask <<= 1) {
1177 if (((int)p_val & hat_mask) != (cur_val & hat_mask)) {
1178 if (map[hat_direction].type == TYPE_BUTTON) {
1179 _button_event(p_device, (JoyButton)map[hat_direction].index, (int)p_val & hat_mask);
1180 }
1181 if (map[hat_direction].type == TYPE_AXIS) {
1182 _axis_event(p_device, (JoyAxis)map[hat_direction].index, ((int)p_val & hat_mask) ? map[hat_direction].value : 0.0);
1183 }
1184 }
1185 }
1186
1187 joy_names[p_device].hat_current = (int)p_val;
1188}
1189
1190void Input::_button_event(int p_device, JoyButton p_index, bool p_pressed) {
1191 Ref<InputEventJoypadButton> ievent;
1192 ievent.instantiate();
1193 ievent->set_device(p_device);
1194 ievent->set_button_index(p_index);
1195 ievent->set_pressed(p_pressed);
1196
1197 parse_input_event(ievent);
1198}
1199
1200void Input::_axis_event(int p_device, JoyAxis p_axis, float p_value) {
1201 Ref<InputEventJoypadMotion> ievent;
1202 ievent.instantiate();
1203 ievent->set_device(p_device);
1204 ievent->set_axis(p_axis);
1205 ievent->set_axis_value(p_value);
1206
1207 parse_input_event(ievent);
1208}
1209
1210Input::JoyEvent Input::_get_mapped_button_event(const JoyDeviceMapping &mapping, JoyButton p_button) {
1211 JoyEvent event;
1212
1213 for (int i = 0; i < mapping.bindings.size(); i++) {
1214 const JoyBinding binding = mapping.bindings[i];
1215 if (binding.inputType == TYPE_BUTTON && binding.input.button == p_button) {
1216 event.type = binding.outputType;
1217 switch (binding.outputType) {
1218 case TYPE_BUTTON:
1219 event.index = (int)binding.output.button;
1220 return event;
1221 case TYPE_AXIS:
1222 event.index = (int)binding.output.axis.axis;
1223 switch (binding.output.axis.range) {
1224 case POSITIVE_HALF_AXIS:
1225 event.value = 1;
1226 break;
1227 case NEGATIVE_HALF_AXIS:
1228 event.value = -1;
1229 break;
1230 case FULL_AXIS:
1231 // It doesn't make sense for a button to map to a full axis,
1232 // but keeping as a default for a trigger with a positive half-axis.
1233 event.value = 1;
1234 break;
1235 }
1236 return event;
1237 default:
1238 ERR_PRINT_ONCE("Joypad button mapping error.");
1239 }
1240 }
1241 }
1242 return event;
1243}
1244
1245Input::JoyEvent Input::_get_mapped_axis_event(const JoyDeviceMapping &mapping, JoyAxis p_axis, float p_value) {
1246 JoyEvent event;
1247
1248 for (int i = 0; i < mapping.bindings.size(); i++) {
1249 const JoyBinding binding = mapping.bindings[i];
1250 if (binding.inputType == TYPE_AXIS && binding.input.axis.axis == p_axis) {
1251 float value = p_value;
1252 if (binding.input.axis.invert) {
1253 value = -value;
1254 }
1255 if (binding.input.axis.range == FULL_AXIS ||
1256 (binding.input.axis.range == POSITIVE_HALF_AXIS && value >= 0) ||
1257 (binding.input.axis.range == NEGATIVE_HALF_AXIS && value < 0)) {
1258 event.type = binding.outputType;
1259 float shifted_positive_value = 0;
1260 switch (binding.input.axis.range) {
1261 case POSITIVE_HALF_AXIS:
1262 shifted_positive_value = value;
1263 break;
1264 case NEGATIVE_HALF_AXIS:
1265 shifted_positive_value = value + 1;
1266 break;
1267 case FULL_AXIS:
1268 shifted_positive_value = (value + 1) / 2;
1269 break;
1270 }
1271 switch (binding.outputType) {
1272 case TYPE_BUTTON:
1273 event.index = (int)binding.output.button;
1274 switch (binding.input.axis.range) {
1275 case POSITIVE_HALF_AXIS:
1276 event.value = shifted_positive_value;
1277 break;
1278 case NEGATIVE_HALF_AXIS:
1279 event.value = 1 - shifted_positive_value;
1280 break;
1281 case FULL_AXIS:
1282 // It doesn't make sense for a full axis to map to a button,
1283 // but keeping as a default for a trigger with a positive half-axis.
1284 event.value = (shifted_positive_value * 2) - 1;
1285 break;
1286 }
1287 return event;
1288 case TYPE_AXIS:
1289 event.index = (int)binding.output.axis.axis;
1290 event.value = value;
1291 if (binding.output.axis.range != binding.input.axis.range) {
1292 switch (binding.output.axis.range) {
1293 case POSITIVE_HALF_AXIS:
1294 event.value = shifted_positive_value;
1295 break;
1296 case NEGATIVE_HALF_AXIS:
1297 event.value = shifted_positive_value - 1;
1298 break;
1299 case FULL_AXIS:
1300 event.value = (shifted_positive_value * 2) - 1;
1301 break;
1302 }
1303 }
1304 return event;
1305 default:
1306 ERR_PRINT_ONCE("Joypad axis mapping error.");
1307 }
1308 }
1309 }
1310 }
1311 return event;
1312}
1313
1314void Input::_get_mapped_hat_events(const JoyDeviceMapping &mapping, HatDir p_hat, JoyEvent r_events[(size_t)HatDir::MAX]) {
1315 for (int i = 0; i < mapping.bindings.size(); i++) {
1316 const JoyBinding binding = mapping.bindings[i];
1317 if (binding.inputType == TYPE_HAT && binding.input.hat.hat == p_hat) {
1318 HatDir hat_direction;
1319 switch (binding.input.hat.hat_mask) {
1320 case HatMask::UP:
1321 hat_direction = HatDir::UP;
1322 break;
1323 case HatMask::RIGHT:
1324 hat_direction = HatDir::RIGHT;
1325 break;
1326 case HatMask::DOWN:
1327 hat_direction = HatDir::DOWN;
1328 break;
1329 case HatMask::LEFT:
1330 hat_direction = HatDir::LEFT;
1331 break;
1332 default:
1333 ERR_PRINT_ONCE("Joypad button mapping error.");
1334 continue;
1335 }
1336
1337 r_events[(size_t)hat_direction].type = binding.outputType;
1338 switch (binding.outputType) {
1339 case TYPE_BUTTON:
1340 r_events[(size_t)hat_direction].index = (int)binding.output.button;
1341 break;
1342 case TYPE_AXIS:
1343 r_events[(size_t)hat_direction].index = (int)binding.output.axis.axis;
1344 switch (binding.output.axis.range) {
1345 case POSITIVE_HALF_AXIS:
1346 r_events[(size_t)hat_direction].value = 1;
1347 break;
1348 case NEGATIVE_HALF_AXIS:
1349 r_events[(size_t)hat_direction].value = -1;
1350 break;
1351 case FULL_AXIS:
1352 // It doesn't make sense for a hat direction to map to a full axis,
1353 // but keeping as a default for a trigger with a positive half-axis.
1354 r_events[(size_t)hat_direction].value = 1;
1355 break;
1356 }
1357 break;
1358 default:
1359 ERR_PRINT_ONCE("Joypad button mapping error.");
1360 }
1361 }
1362 }
1363}
1364
1365JoyButton Input::_get_output_button(String output) {
1366 for (int i = 0; i < (int)JoyButton::SDL_MAX; i++) {
1367 if (output == _joy_buttons[i]) {
1368 return JoyButton(i);
1369 }
1370 }
1371 return JoyButton::INVALID;
1372}
1373
1374JoyAxis Input::_get_output_axis(String output) {
1375 for (int i = 0; i < (int)JoyAxis::SDL_MAX; i++) {
1376 if (output == _joy_axes[i]) {
1377 return JoyAxis(i);
1378 }
1379 }
1380 return JoyAxis::INVALID;
1381}
1382
1383void Input::parse_mapping(String p_mapping) {
1384 _THREAD_SAFE_METHOD_;
1385 JoyDeviceMapping mapping;
1386
1387 Vector<String> entry = p_mapping.split(",");
1388 if (entry.size() < 2) {
1389 return;
1390 }
1391
1392 CharString uid;
1393 uid.resize(17);
1394
1395 mapping.uid = entry[0];
1396 mapping.name = entry[1];
1397
1398 int idx = 1;
1399 while (++idx < entry.size()) {
1400 if (entry[idx].is_empty()) {
1401 continue;
1402 }
1403
1404 String output = entry[idx].get_slice(":", 0).replace(" ", "");
1405 String input = entry[idx].get_slice(":", 1).replace(" ", "");
1406 if (output.length() < 1 || input.length() < 2) {
1407 continue;
1408 }
1409
1410 if (output == "platform" || output == "hint") {
1411 continue;
1412 }
1413
1414 JoyAxisRange output_range = FULL_AXIS;
1415 if (output[0] == '+' || output[0] == '-') {
1416 ERR_CONTINUE_MSG(output.length() < 2,
1417 vformat("Invalid output entry \"%s\" in mapping:\n%s", entry[idx], p_mapping));
1418 if (output[0] == '+') {
1419 output_range = POSITIVE_HALF_AXIS;
1420 } else if (output[0] == '-') {
1421 output_range = NEGATIVE_HALF_AXIS;
1422 }
1423 output = output.substr(1);
1424 }
1425
1426 JoyAxisRange input_range = FULL_AXIS;
1427 if (input[0] == '+') {
1428 input_range = POSITIVE_HALF_AXIS;
1429 input = input.substr(1);
1430 } else if (input[0] == '-') {
1431 input_range = NEGATIVE_HALF_AXIS;
1432 input = input.substr(1);
1433 }
1434 bool invert_axis = false;
1435 if (input[input.length() - 1] == '~') {
1436 invert_axis = true;
1437 input = input.left(input.length() - 1);
1438 }
1439
1440 JoyButton output_button = _get_output_button(output);
1441 JoyAxis output_axis = _get_output_axis(output);
1442 if (output_button == JoyButton::INVALID && output_axis == JoyAxis::INVALID) {
1443 print_verbose(vformat("Unrecognized output string \"%s\" in mapping:\n%s", output, p_mapping));
1444 }
1445 ERR_CONTINUE_MSG(output_button != JoyButton::INVALID && output_axis != JoyAxis::INVALID,
1446 vformat("Output string \"%s\" matched both button and axis in mapping:\n%s", output, p_mapping));
1447
1448 JoyBinding binding;
1449 if (output_button != JoyButton::INVALID) {
1450 binding.outputType = TYPE_BUTTON;
1451 binding.output.button = output_button;
1452 } else if (output_axis != JoyAxis::INVALID) {
1453 binding.outputType = TYPE_AXIS;
1454 binding.output.axis.axis = output_axis;
1455 binding.output.axis.range = output_range;
1456 }
1457
1458 switch (input[0]) {
1459 case 'b':
1460 binding.inputType = TYPE_BUTTON;
1461 binding.input.button = (JoyButton)input.substr(1).to_int();
1462 break;
1463 case 'a':
1464 binding.inputType = TYPE_AXIS;
1465 binding.input.axis.axis = (JoyAxis)input.substr(1).to_int();
1466 binding.input.axis.range = input_range;
1467 binding.input.axis.invert = invert_axis;
1468 break;
1469 case 'h':
1470 ERR_CONTINUE_MSG(input.length() != 4 || input[2] != '.',
1471 vformat("Invalid had input \"%s\" in mapping:\n%s", input, p_mapping));
1472 binding.inputType = TYPE_HAT;
1473 binding.input.hat.hat = (HatDir)input.substr(1, 1).to_int();
1474 binding.input.hat.hat_mask = static_cast<HatMask>(input.substr(3).to_int());
1475 break;
1476 default:
1477 ERR_CONTINUE_MSG(true, vformat("Unrecognized input string \"%s\" in mapping:\n%s", input, p_mapping));
1478 }
1479
1480 mapping.bindings.push_back(binding);
1481 }
1482
1483 map_db.push_back(mapping);
1484}
1485
1486void Input::add_joy_mapping(String p_mapping, bool p_update_existing) {
1487 parse_mapping(p_mapping);
1488 if (p_update_existing) {
1489 Vector<String> entry = p_mapping.split(",");
1490 String uid = entry[0];
1491 for (KeyValue<int, Joypad> &E : joy_names) {
1492 Joypad &joy = E.value;
1493 if (joy.uid == uid) {
1494 joy.mapping = map_db.size() - 1;
1495 }
1496 }
1497 }
1498}
1499
1500void Input::remove_joy_mapping(String p_guid) {
1501 for (int i = map_db.size() - 1; i >= 0; i--) {
1502 if (p_guid == map_db[i].uid) {
1503 map_db.remove_at(i);
1504 }
1505 }
1506 for (KeyValue<int, Joypad> &E : joy_names) {
1507 Joypad &joy = E.value;
1508 if (joy.uid == p_guid) {
1509 joy.mapping = -1;
1510 }
1511 }
1512}
1513
1514void Input::set_fallback_mapping(String p_guid) {
1515 for (int i = 0; i < map_db.size(); i++) {
1516 if (map_db[i].uid == p_guid) {
1517 fallback_mapping = i;
1518 return;
1519 }
1520 }
1521}
1522
1523//platforms that use the remapping system can override and call to these ones
1524bool Input::is_joy_known(int p_device) {
1525 if (joy_names.has(p_device)) {
1526 int mapping = joy_names[p_device].mapping;
1527 if (mapping != -1 && mapping != fallback_mapping) {
1528 return true;
1529 }
1530 }
1531 return false;
1532}
1533
1534String Input::get_joy_guid(int p_device) const {
1535 ERR_FAIL_COND_V(!joy_names.has(p_device), "");
1536 return joy_names[p_device].uid;
1537}
1538
1539Dictionary Input::get_joy_info(int p_device) const {
1540 ERR_FAIL_COND_V(!joy_names.has(p_device), Dictionary());
1541 return joy_names[p_device].info;
1542}
1543
1544bool Input::should_ignore_device(int p_vendor_id, int p_product_id) const {
1545 uint32_t full_id = (((uint32_t)p_vendor_id) << 16) | ((uint16_t)p_product_id);
1546 return ignored_device_ids.has(full_id);
1547}
1548
1549TypedArray<int> Input::get_connected_joypads() {
1550 TypedArray<int> ret;
1551 HashMap<int, Joypad>::Iterator elem = joy_names.begin();
1552 while (elem) {
1553 if (elem->value.connected) {
1554 ret.push_back(elem->key);
1555 }
1556 ++elem;
1557 }
1558 return ret;
1559}
1560
1561int Input::get_unused_joy_id() {
1562 for (int i = 0; i < JOYPADS_MAX; i++) {
1563 if (!joy_names.has(i) || !joy_names[i].connected) {
1564 return i;
1565 }
1566 }
1567 return -1;
1568}
1569
1570Input::Input() {
1571 singleton = this;
1572
1573 // Parse default mappings.
1574 {
1575 int i = 0;
1576 while (DefaultControllerMappings::mappings[i]) {
1577 parse_mapping(DefaultControllerMappings::mappings[i++]);
1578 }
1579 }
1580
1581 // If defined, parse SDL_GAMECONTROLLERCONFIG for possible new mappings/overrides.
1582 String env_mapping = OS::get_singleton()->get_environment("SDL_GAMECONTROLLERCONFIG");
1583 if (!env_mapping.is_empty()) {
1584 Vector<String> entries = env_mapping.split("\n");
1585 for (int i = 0; i < entries.size(); i++) {
1586 if (entries[i].is_empty()) {
1587 continue;
1588 }
1589 parse_mapping(entries[i]);
1590 }
1591 }
1592
1593 String env_ignore_devices = OS::get_singleton()->get_environment("SDL_GAMECONTROLLER_IGNORE_DEVICES");
1594 if (!env_ignore_devices.is_empty()) {
1595 Vector<String> entries = env_ignore_devices.split(",");
1596 for (int i = 0; i < entries.size(); i++) {
1597 Vector<String> vid_pid = entries[i].split("/");
1598
1599 if (vid_pid.size() < 2) {
1600 continue;
1601 }
1602
1603 print_verbose(vformat("Device Ignored -- Vendor: %s Product: %s", vid_pid[0], vid_pid[1]));
1604 const uint16_t vid_unswapped = vid_pid[0].hex_to_int();
1605 const uint16_t pid_unswapped = vid_pid[1].hex_to_int();
1606 const uint16_t vid = BSWAP16(vid_unswapped);
1607 const uint16_t pid = BSWAP16(pid_unswapped);
1608
1609 uint32_t full_id = (((uint32_t)vid) << 16) | ((uint16_t)pid);
1610 ignored_device_ids.insert(full_id);
1611 }
1612 }
1613
1614 legacy_just_pressed_behavior = GLOBAL_DEF("input_devices/compatibility/legacy_just_pressed_behavior", false);
1615 if (Engine::get_singleton()->is_editor_hint()) {
1616 // Always use standard behavior in the editor.
1617 legacy_just_pressed_behavior = false;
1618 }
1619}
1620
1621Input::~Input() {
1622 singleton = nullptr;
1623}
1624
1625//////////////////////////////////////////////////////////
1626