Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
godotengine
GitHub Repository: godotengine/godot
Path: blob/master/core/input/input.cpp
9903 views
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
#include "input.compat.inc"
33
34
#include "core/config/project_settings.h"
35
#include "core/input/default_controller_mappings.h"
36
#include "core/input/input_map.h"
37
#include "core/os/os.h"
38
39
#ifdef DEV_ENABLED
40
#include "core/os/thread.h"
41
#endif
42
43
static const char *_joy_buttons[(size_t)JoyButton::SDL_MAX] = {
44
"a",
45
"b",
46
"x",
47
"y",
48
"back",
49
"guide",
50
"start",
51
"leftstick",
52
"rightstick",
53
"leftshoulder",
54
"rightshoulder",
55
"dpup",
56
"dpdown",
57
"dpleft",
58
"dpright",
59
"misc1",
60
"paddle1",
61
"paddle2",
62
"paddle3",
63
"paddle4",
64
"touchpad",
65
};
66
67
static const char *_joy_axes[(size_t)JoyAxis::SDL_MAX] = {
68
"leftx",
69
"lefty",
70
"rightx",
71
"righty",
72
"lefttrigger",
73
"righttrigger",
74
};
75
76
void (*Input::set_mouse_mode_func)(Input::MouseMode) = nullptr;
77
Input::MouseMode (*Input::get_mouse_mode_func)() = nullptr;
78
void (*Input::set_mouse_mode_override_func)(Input::MouseMode) = nullptr;
79
Input::MouseMode (*Input::get_mouse_mode_override_func)() = nullptr;
80
void (*Input::set_mouse_mode_override_enabled_func)(bool) = nullptr;
81
bool (*Input::is_mouse_mode_override_enabled_func)() = nullptr;
82
void (*Input::warp_mouse_func)(const Vector2 &p_position) = nullptr;
83
Input::CursorShape (*Input::get_current_cursor_shape_func)() = nullptr;
84
void (*Input::set_custom_mouse_cursor_func)(const Ref<Resource> &, Input::CursorShape, const Vector2 &) = nullptr;
85
86
Input *Input::get_singleton() {
87
return singleton;
88
}
89
90
void Input::set_mouse_mode(MouseMode p_mode) {
91
ERR_FAIL_INDEX(p_mode, MouseMode::MOUSE_MODE_MAX);
92
set_mouse_mode_func(p_mode);
93
}
94
95
Input::MouseMode Input::get_mouse_mode() const {
96
return get_mouse_mode_func();
97
}
98
99
void Input::set_mouse_mode_override(MouseMode p_mode) {
100
ERR_FAIL_INDEX(p_mode, MouseMode::MOUSE_MODE_MAX);
101
set_mouse_mode_override_func(p_mode);
102
}
103
104
Input::MouseMode Input::get_mouse_mode_override() const {
105
return get_mouse_mode_override_func();
106
}
107
108
void Input::set_mouse_mode_override_enabled(bool p_override_enabled) {
109
set_mouse_mode_override_enabled_func(p_override_enabled);
110
}
111
112
bool Input::is_mouse_mode_override_enabled() {
113
return is_mouse_mode_override_enabled_func();
114
}
115
116
void Input::_bind_methods() {
117
ClassDB::bind_method(D_METHOD("is_anything_pressed"), &Input::is_anything_pressed);
118
ClassDB::bind_method(D_METHOD("is_key_pressed", "keycode"), &Input::is_key_pressed);
119
ClassDB::bind_method(D_METHOD("is_physical_key_pressed", "keycode"), &Input::is_physical_key_pressed);
120
ClassDB::bind_method(D_METHOD("is_key_label_pressed", "keycode"), &Input::is_key_label_pressed);
121
ClassDB::bind_method(D_METHOD("is_mouse_button_pressed", "button"), &Input::is_mouse_button_pressed);
122
ClassDB::bind_method(D_METHOD("is_joy_button_pressed", "device", "button"), &Input::is_joy_button_pressed);
123
ClassDB::bind_method(D_METHOD("is_action_pressed", "action", "exact_match"), &Input::is_action_pressed, DEFVAL(false));
124
ClassDB::bind_method(D_METHOD("is_action_just_pressed", "action", "exact_match"), &Input::is_action_just_pressed, DEFVAL(false));
125
ClassDB::bind_method(D_METHOD("is_action_just_released", "action", "exact_match"), &Input::is_action_just_released, DEFVAL(false));
126
ClassDB::bind_method(D_METHOD("is_action_just_pressed_by_event", "action", "event", "exact_match"), &Input::is_action_just_pressed_by_event, DEFVAL(false));
127
ClassDB::bind_method(D_METHOD("is_action_just_released_by_event", "action", "event", "exact_match"), &Input::is_action_just_released_by_event, DEFVAL(false));
128
ClassDB::bind_method(D_METHOD("get_action_strength", "action", "exact_match"), &Input::get_action_strength, DEFVAL(false));
129
ClassDB::bind_method(D_METHOD("get_action_raw_strength", "action", "exact_match"), &Input::get_action_raw_strength, DEFVAL(false));
130
ClassDB::bind_method(D_METHOD("get_axis", "negative_action", "positive_action"), &Input::get_axis);
131
ClassDB::bind_method(D_METHOD("get_vector", "negative_x", "positive_x", "negative_y", "positive_y", "deadzone"), &Input::get_vector, DEFVAL(-1.0f));
132
ClassDB::bind_method(D_METHOD("add_joy_mapping", "mapping", "update_existing"), &Input::add_joy_mapping, DEFVAL(false));
133
ClassDB::bind_method(D_METHOD("remove_joy_mapping", "guid"), &Input::remove_joy_mapping);
134
ClassDB::bind_method(D_METHOD("is_joy_known", "device"), &Input::is_joy_known);
135
ClassDB::bind_method(D_METHOD("get_joy_axis", "device", "axis"), &Input::get_joy_axis);
136
ClassDB::bind_method(D_METHOD("get_joy_name", "device"), &Input::get_joy_name);
137
ClassDB::bind_method(D_METHOD("get_joy_guid", "device"), &Input::get_joy_guid);
138
ClassDB::bind_method(D_METHOD("get_joy_info", "device"), &Input::get_joy_info);
139
ClassDB::bind_method(D_METHOD("should_ignore_device", "vendor_id", "product_id"), &Input::should_ignore_device);
140
ClassDB::bind_method(D_METHOD("get_connected_joypads"), &Input::get_connected_joypads);
141
ClassDB::bind_method(D_METHOD("get_joy_vibration_strength", "device"), &Input::get_joy_vibration_strength);
142
ClassDB::bind_method(D_METHOD("get_joy_vibration_duration", "device"), &Input::get_joy_vibration_duration);
143
ClassDB::bind_method(D_METHOD("start_joy_vibration", "device", "weak_magnitude", "strong_magnitude", "duration"), &Input::start_joy_vibration, DEFVAL(0));
144
ClassDB::bind_method(D_METHOD("stop_joy_vibration", "device"), &Input::stop_joy_vibration);
145
ClassDB::bind_method(D_METHOD("vibrate_handheld", "duration_ms", "amplitude"), &Input::vibrate_handheld, DEFVAL(500), DEFVAL(-1.0));
146
ClassDB::bind_method(D_METHOD("get_gravity"), &Input::get_gravity);
147
ClassDB::bind_method(D_METHOD("get_accelerometer"), &Input::get_accelerometer);
148
ClassDB::bind_method(D_METHOD("get_magnetometer"), &Input::get_magnetometer);
149
ClassDB::bind_method(D_METHOD("get_gyroscope"), &Input::get_gyroscope);
150
ClassDB::bind_method(D_METHOD("set_gravity", "value"), &Input::set_gravity);
151
ClassDB::bind_method(D_METHOD("set_accelerometer", "value"), &Input::set_accelerometer);
152
ClassDB::bind_method(D_METHOD("set_magnetometer", "value"), &Input::set_magnetometer);
153
ClassDB::bind_method(D_METHOD("set_gyroscope", "value"), &Input::set_gyroscope);
154
ClassDB::bind_method(D_METHOD("get_last_mouse_velocity"), &Input::get_last_mouse_velocity);
155
ClassDB::bind_method(D_METHOD("get_last_mouse_screen_velocity"), &Input::get_last_mouse_screen_velocity);
156
ClassDB::bind_method(D_METHOD("get_mouse_button_mask"), &Input::get_mouse_button_mask);
157
ClassDB::bind_method(D_METHOD("set_mouse_mode", "mode"), &Input::set_mouse_mode);
158
ClassDB::bind_method(D_METHOD("get_mouse_mode"), &Input::get_mouse_mode);
159
ClassDB::bind_method(D_METHOD("warp_mouse", "position"), &Input::warp_mouse);
160
ClassDB::bind_method(D_METHOD("action_press", "action", "strength"), &Input::action_press, DEFVAL(1.f));
161
ClassDB::bind_method(D_METHOD("action_release", "action"), &Input::action_release);
162
ClassDB::bind_method(D_METHOD("set_default_cursor_shape", "shape"), &Input::set_default_cursor_shape, DEFVAL(CURSOR_ARROW));
163
ClassDB::bind_method(D_METHOD("get_current_cursor_shape"), &Input::get_current_cursor_shape);
164
ClassDB::bind_method(D_METHOD("set_custom_mouse_cursor", "image", "shape", "hotspot"), &Input::set_custom_mouse_cursor, DEFVAL(CURSOR_ARROW), DEFVAL(Vector2()));
165
ClassDB::bind_method(D_METHOD("parse_input_event", "event"), &Input::parse_input_event);
166
ClassDB::bind_method(D_METHOD("set_use_accumulated_input", "enable"), &Input::set_use_accumulated_input);
167
ClassDB::bind_method(D_METHOD("is_using_accumulated_input"), &Input::is_using_accumulated_input);
168
ClassDB::bind_method(D_METHOD("flush_buffered_events"), &Input::flush_buffered_events);
169
ClassDB::bind_method(D_METHOD("set_emulate_mouse_from_touch", "enable"), &Input::set_emulate_mouse_from_touch);
170
ClassDB::bind_method(D_METHOD("is_emulating_mouse_from_touch"), &Input::is_emulating_mouse_from_touch);
171
ClassDB::bind_method(D_METHOD("set_emulate_touch_from_mouse", "enable"), &Input::set_emulate_touch_from_mouse);
172
ClassDB::bind_method(D_METHOD("is_emulating_touch_from_mouse"), &Input::is_emulating_touch_from_mouse);
173
174
ADD_PROPERTY(PropertyInfo(Variant::INT, "mouse_mode"), "set_mouse_mode", "get_mouse_mode");
175
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_accumulated_input"), "set_use_accumulated_input", "is_using_accumulated_input");
176
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "emulate_mouse_from_touch"), "set_emulate_mouse_from_touch", "is_emulating_mouse_from_touch");
177
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "emulate_touch_from_mouse"), "set_emulate_touch_from_mouse", "is_emulating_touch_from_mouse");
178
179
BIND_ENUM_CONSTANT(MOUSE_MODE_VISIBLE);
180
BIND_ENUM_CONSTANT(MOUSE_MODE_HIDDEN);
181
BIND_ENUM_CONSTANT(MOUSE_MODE_CAPTURED);
182
BIND_ENUM_CONSTANT(MOUSE_MODE_CONFINED);
183
BIND_ENUM_CONSTANT(MOUSE_MODE_CONFINED_HIDDEN);
184
BIND_ENUM_CONSTANT(MOUSE_MODE_MAX);
185
186
BIND_ENUM_CONSTANT(CURSOR_ARROW);
187
BIND_ENUM_CONSTANT(CURSOR_IBEAM);
188
BIND_ENUM_CONSTANT(CURSOR_POINTING_HAND);
189
BIND_ENUM_CONSTANT(CURSOR_CROSS);
190
BIND_ENUM_CONSTANT(CURSOR_WAIT);
191
BIND_ENUM_CONSTANT(CURSOR_BUSY);
192
BIND_ENUM_CONSTANT(CURSOR_DRAG);
193
BIND_ENUM_CONSTANT(CURSOR_CAN_DROP);
194
BIND_ENUM_CONSTANT(CURSOR_FORBIDDEN);
195
BIND_ENUM_CONSTANT(CURSOR_VSIZE);
196
BIND_ENUM_CONSTANT(CURSOR_HSIZE);
197
BIND_ENUM_CONSTANT(CURSOR_BDIAGSIZE);
198
BIND_ENUM_CONSTANT(CURSOR_FDIAGSIZE);
199
BIND_ENUM_CONSTANT(CURSOR_MOVE);
200
BIND_ENUM_CONSTANT(CURSOR_VSPLIT);
201
BIND_ENUM_CONSTANT(CURSOR_HSPLIT);
202
BIND_ENUM_CONSTANT(CURSOR_HELP);
203
204
ADD_SIGNAL(MethodInfo("joy_connection_changed", PropertyInfo(Variant::INT, "device"), PropertyInfo(Variant::BOOL, "connected")));
205
}
206
207
#ifdef TOOLS_ENABLED
208
void Input::get_argument_options(const StringName &p_function, int p_idx, List<String> *r_options) const {
209
const String pf = p_function;
210
211
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")) ||
212
(p_idx < 2 && pf == "get_axis") ||
213
(p_idx < 4 && pf == "get_vector")) {
214
List<PropertyInfo> pinfo;
215
ProjectSettings::get_singleton()->get_property_list(&pinfo);
216
217
for (const PropertyInfo &pi : pinfo) {
218
if (!pi.name.begins_with("input/")) {
219
continue;
220
}
221
222
String name = pi.name.substr(pi.name.find_char('/') + 1);
223
r_options->push_back(name.quote());
224
}
225
}
226
Object::get_argument_options(p_function, p_idx, r_options);
227
}
228
#endif
229
230
void Input::VelocityTrack::update(const Vector2 &p_delta_p, const Vector2 &p_screen_delta_p) {
231
uint64_t tick = OS::get_singleton()->get_ticks_usec();
232
uint32_t tdiff = tick - last_tick;
233
float delta_t = tdiff / 1000000.0;
234
last_tick = tick;
235
236
if (delta_t > max_ref_frame) {
237
// First movement in a long time, reset and start again.
238
velocity = Vector2();
239
screen_velocity = Vector2();
240
accum = p_delta_p;
241
screen_accum = p_screen_delta_p;
242
accum_t = 0;
243
return;
244
}
245
246
accum += p_delta_p;
247
screen_accum += p_screen_delta_p;
248
accum_t += delta_t;
249
250
if (accum_t < min_ref_frame) {
251
// Not enough time has passed to calculate speed precisely.
252
return;
253
}
254
255
velocity = accum / accum_t;
256
screen_velocity = screen_accum / accum_t;
257
accum = Vector2();
258
screen_accum = Vector2();
259
accum_t = 0;
260
}
261
262
void Input::VelocityTrack::reset() {
263
last_tick = OS::get_singleton()->get_ticks_usec();
264
velocity = Vector2();
265
screen_velocity = Vector2();
266
accum = Vector2();
267
screen_accum = Vector2();
268
accum_t = 0;
269
}
270
271
Input::VelocityTrack::VelocityTrack() {
272
min_ref_frame = 0.1;
273
max_ref_frame = 3.0;
274
reset();
275
}
276
277
bool Input::is_anything_pressed() const {
278
_THREAD_SAFE_METHOD_
279
280
if (disable_input) {
281
return false;
282
}
283
284
if (!keys_pressed.is_empty() || !joy_buttons_pressed.is_empty() || !mouse_button_mask.is_empty()) {
285
return true;
286
}
287
288
for (const KeyValue<StringName, Input::ActionState> &E : action_states) {
289
if (E.value.cache.pressed) {
290
return true;
291
}
292
}
293
294
return false;
295
}
296
297
bool Input::is_anything_pressed_except_mouse() const {
298
_THREAD_SAFE_METHOD_
299
300
if (disable_input) {
301
return false;
302
}
303
304
if (!keys_pressed.is_empty() || !joy_buttons_pressed.is_empty()) {
305
return true;
306
}
307
308
for (const KeyValue<StringName, Input::ActionState> &E : action_states) {
309
if (E.value.cache.pressed) {
310
return true;
311
}
312
}
313
314
return false;
315
}
316
317
bool Input::is_key_pressed(Key p_keycode) const {
318
_THREAD_SAFE_METHOD_
319
320
if (disable_input) {
321
return false;
322
}
323
324
return keys_pressed.has(p_keycode);
325
}
326
327
bool Input::is_physical_key_pressed(Key p_keycode) const {
328
_THREAD_SAFE_METHOD_
329
330
if (disable_input) {
331
return false;
332
}
333
334
return physical_keys_pressed.has(p_keycode);
335
}
336
337
bool Input::is_key_label_pressed(Key p_keycode) const {
338
_THREAD_SAFE_METHOD_
339
340
if (disable_input) {
341
return false;
342
}
343
344
return key_label_pressed.has(p_keycode);
345
}
346
347
bool Input::is_mouse_button_pressed(MouseButton p_button) const {
348
_THREAD_SAFE_METHOD_
349
350
if (disable_input) {
351
return false;
352
}
353
354
return mouse_button_mask.has_flag(mouse_button_to_mask(p_button));
355
}
356
357
static JoyAxis _combine_device(JoyAxis p_value, int p_device) {
358
return JoyAxis((int)p_value | (p_device << 20));
359
}
360
361
static JoyButton _combine_device(JoyButton p_value, int p_device) {
362
return JoyButton((int)p_value | (p_device << 20));
363
}
364
365
bool Input::is_joy_button_pressed(int p_device, JoyButton p_button) const {
366
_THREAD_SAFE_METHOD_
367
368
if (disable_input) {
369
return false;
370
}
371
372
return joy_buttons_pressed.has(_combine_device(p_button, p_device));
373
}
374
375
bool Input::is_action_pressed(const StringName &p_action, bool p_exact) const {
376
ERR_FAIL_COND_V_MSG(!InputMap::get_singleton()->has_action(p_action), false, InputMap::get_singleton()->suggest_actions(p_action));
377
378
if (disable_input) {
379
return false;
380
}
381
382
HashMap<StringName, ActionState>::ConstIterator E = action_states.find(p_action);
383
if (!E) {
384
return false;
385
}
386
387
return E->value.cache.pressed && (p_exact ? E->value.exact : true);
388
}
389
390
bool Input::is_action_just_pressed(const StringName &p_action, bool p_exact) const {
391
ERR_FAIL_COND_V_MSG(!InputMap::get_singleton()->has_action(p_action), false, InputMap::get_singleton()->suggest_actions(p_action));
392
393
if (disable_input) {
394
return false;
395
}
396
397
HashMap<StringName, ActionState>::ConstIterator E = action_states.find(p_action);
398
if (!E) {
399
return false;
400
}
401
402
if (p_exact && E->value.exact == false) {
403
return false;
404
}
405
406
// Backward compatibility for legacy behavior, only return true if currently pressed.
407
bool pressed_requirement = legacy_just_pressed_behavior ? E->value.cache.pressed : true;
408
409
if (Engine::get_singleton()->is_in_physics_frame()) {
410
return pressed_requirement && E->value.pressed_physics_frame == Engine::get_singleton()->get_physics_frames();
411
} else {
412
return pressed_requirement && E->value.pressed_process_frame == Engine::get_singleton()->get_process_frames();
413
}
414
}
415
416
bool Input::is_action_just_pressed_by_event(const StringName &p_action, const Ref<InputEvent> &p_event, bool p_exact) const {
417
ERR_FAIL_COND_V_MSG(!InputMap::get_singleton()->has_action(p_action), false, InputMap::get_singleton()->suggest_actions(p_action));
418
ERR_FAIL_COND_V(p_event.is_null(), false);
419
420
if (disable_input) {
421
return false;
422
}
423
424
HashMap<StringName, ActionState>::ConstIterator E = action_states.find(p_action);
425
if (!E) {
426
return false;
427
}
428
429
if (p_exact && E->value.exact == false) {
430
return false;
431
}
432
433
if (E->value.pressed_event_id != p_event->get_instance_id()) {
434
return false;
435
}
436
437
// Backward compatibility for legacy behavior, only return true if currently pressed.
438
bool pressed_requirement = legacy_just_pressed_behavior ? E->value.cache.pressed : true;
439
440
if (Engine::get_singleton()->is_in_physics_frame()) {
441
return pressed_requirement && E->value.pressed_physics_frame == Engine::get_singleton()->get_physics_frames();
442
} else {
443
return pressed_requirement && E->value.pressed_process_frame == Engine::get_singleton()->get_process_frames();
444
}
445
}
446
447
bool Input::is_action_just_released(const StringName &p_action, bool p_exact) const {
448
ERR_FAIL_COND_V_MSG(!InputMap::get_singleton()->has_action(p_action), false, InputMap::get_singleton()->suggest_actions(p_action));
449
450
if (disable_input) {
451
return false;
452
}
453
454
HashMap<StringName, ActionState>::ConstIterator E = action_states.find(p_action);
455
if (!E) {
456
return false;
457
}
458
459
if (p_exact && E->value.exact == false) {
460
return false;
461
}
462
463
// Backward compatibility for legacy behavior, only return true if currently released.
464
bool released_requirement = legacy_just_pressed_behavior ? !E->value.cache.pressed : true;
465
466
if (Engine::get_singleton()->is_in_physics_frame()) {
467
return released_requirement && E->value.released_physics_frame == Engine::get_singleton()->get_physics_frames();
468
} else {
469
return released_requirement && E->value.released_process_frame == Engine::get_singleton()->get_process_frames();
470
}
471
}
472
473
bool Input::is_action_just_released_by_event(const StringName &p_action, const Ref<InputEvent> &p_event, bool p_exact) const {
474
ERR_FAIL_COND_V_MSG(!InputMap::get_singleton()->has_action(p_action), false, InputMap::get_singleton()->suggest_actions(p_action));
475
ERR_FAIL_COND_V(p_event.is_null(), false);
476
477
if (disable_input) {
478
return false;
479
}
480
481
HashMap<StringName, ActionState>::ConstIterator E = action_states.find(p_action);
482
if (!E) {
483
return false;
484
}
485
486
if (p_exact && E->value.exact == false) {
487
return false;
488
}
489
490
if (E->value.released_event_id != p_event->get_instance_id()) {
491
return false;
492
}
493
494
// Backward compatibility for legacy behavior, only return true if currently released.
495
bool released_requirement = legacy_just_pressed_behavior ? !E->value.cache.pressed : true;
496
497
if (Engine::get_singleton()->is_in_physics_frame()) {
498
return released_requirement && E->value.released_physics_frame == Engine::get_singleton()->get_physics_frames();
499
} else {
500
return released_requirement && E->value.released_process_frame == Engine::get_singleton()->get_process_frames();
501
}
502
}
503
504
float Input::get_action_strength(const StringName &p_action, bool p_exact) const {
505
ERR_FAIL_COND_V_MSG(!InputMap::get_singleton()->has_action(p_action), 0.0, InputMap::get_singleton()->suggest_actions(p_action));
506
507
if (disable_input) {
508
return 0.0f;
509
}
510
511
HashMap<StringName, ActionState>::ConstIterator E = action_states.find(p_action);
512
if (!E) {
513
return 0.0f;
514
}
515
516
if (p_exact && E->value.exact == false) {
517
return 0.0f;
518
}
519
520
return E->value.cache.strength;
521
}
522
523
float Input::get_action_raw_strength(const StringName &p_action, bool p_exact) const {
524
ERR_FAIL_COND_V_MSG(!InputMap::get_singleton()->has_action(p_action), 0.0, InputMap::get_singleton()->suggest_actions(p_action));
525
526
if (disable_input) {
527
return 0.0f;
528
}
529
530
HashMap<StringName, ActionState>::ConstIterator E = action_states.find(p_action);
531
if (!E) {
532
return 0.0f;
533
}
534
535
if (p_exact && E->value.exact == false) {
536
return 0.0f;
537
}
538
539
return E->value.cache.raw_strength;
540
}
541
542
float Input::get_axis(const StringName &p_negative_action, const StringName &p_positive_action) const {
543
return get_action_strength(p_positive_action) - get_action_strength(p_negative_action);
544
}
545
546
Vector2 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 {
547
Vector2 vector = Vector2(
548
get_action_raw_strength(p_positive_x) - get_action_raw_strength(p_negative_x),
549
get_action_raw_strength(p_positive_y) - get_action_raw_strength(p_negative_y));
550
551
if (p_deadzone < 0.0f) {
552
// If the deadzone isn't specified, get it from the average of the actions.
553
p_deadzone = 0.25 *
554
(InputMap::get_singleton()->action_get_deadzone(p_positive_x) +
555
InputMap::get_singleton()->action_get_deadzone(p_negative_x) +
556
InputMap::get_singleton()->action_get_deadzone(p_positive_y) +
557
InputMap::get_singleton()->action_get_deadzone(p_negative_y));
558
}
559
560
// Circular length limiting and deadzone.
561
float length = vector.length();
562
if (length <= p_deadzone) {
563
return Vector2();
564
} else if (length > 1.0f) {
565
return vector / length;
566
} else {
567
// Inverse lerp length to map (p_deadzone, 1) to (0, 1).
568
return vector * (Math::inverse_lerp(p_deadzone, 1.0f, length) / length);
569
}
570
}
571
572
float Input::get_joy_axis(int p_device, JoyAxis p_axis) const {
573
_THREAD_SAFE_METHOD_
574
575
if (disable_input) {
576
return 0;
577
}
578
579
JoyAxis c = _combine_device(p_axis, p_device);
580
if (_joy_axis.has(c)) {
581
return _joy_axis[c];
582
} else {
583
return 0;
584
}
585
}
586
587
String Input::get_joy_name(int p_idx) {
588
_THREAD_SAFE_METHOD_
589
return joy_names[p_idx].name;
590
}
591
592
Vector2 Input::get_joy_vibration_strength(int p_device) {
593
if (joy_vibration.has(p_device)) {
594
return Vector2(joy_vibration[p_device].weak_magnitude, joy_vibration[p_device].strong_magnitude);
595
} else {
596
return Vector2(0, 0);
597
}
598
}
599
600
uint64_t Input::get_joy_vibration_timestamp(int p_device) {
601
if (joy_vibration.has(p_device)) {
602
return joy_vibration[p_device].timestamp;
603
} else {
604
return 0;
605
}
606
}
607
608
float Input::get_joy_vibration_duration(int p_device) {
609
if (joy_vibration.has(p_device)) {
610
return joy_vibration[p_device].duration;
611
} else {
612
return 0.f;
613
}
614
}
615
616
static String _hex_str(uint8_t p_byte) {
617
static const char *dict = "0123456789abcdef";
618
char ret[3];
619
ret[2] = 0;
620
621
ret[0] = dict[p_byte >> 4];
622
ret[1] = dict[p_byte & 0xf];
623
624
return ret;
625
}
626
627
void Input::joy_connection_changed(int p_idx, bool p_connected, const String &p_name, const String &p_guid, const Dictionary &p_joypad_info) {
628
_THREAD_SAFE_METHOD_
629
630
// Clear the pressed status if a Joypad gets disconnected.
631
if (!p_connected) {
632
for (KeyValue<StringName, ActionState> &E : action_states) {
633
HashMap<int, ActionState::DeviceState>::Iterator it = E.value.device_states.find(p_idx);
634
if (it) {
635
E.value.device_states.remove(it);
636
_update_action_cache(E.key, E.value);
637
}
638
}
639
}
640
641
Joypad js;
642
js.name = p_connected ? p_name : "";
643
js.uid = p_connected ? p_guid : "";
644
js.info = p_connected ? p_joypad_info : Dictionary();
645
646
if (p_connected) {
647
String uidname = p_guid;
648
if (p_guid.is_empty()) {
649
int uidlen = MIN(p_name.length(), 16);
650
for (int i = 0; i < uidlen; i++) {
651
uidname = uidname + _hex_str(p_name[i]);
652
}
653
}
654
js.uid = uidname;
655
js.connected = true;
656
int mapping = fallback_mapping;
657
// Bypass the mapping system if the joypad's mapping is already handled by its driver
658
// (for example, the SDL joypad driver).
659
if (!p_joypad_info.get("mapping_handled", false)) {
660
for (int i = 0; i < map_db.size(); i++) {
661
if (js.uid == map_db[i].uid) {
662
mapping = i;
663
}
664
}
665
}
666
// We don't want this setting to be exposed to the user, because it's not very useful outside of this method.
667
js.info.erase("mapping_handled");
668
669
_set_joypad_mapping(js, mapping);
670
} else {
671
js.connected = false;
672
for (int i = 0; i < (int)JoyButton::MAX; i++) {
673
JoyButton c = _combine_device((JoyButton)i, p_idx);
674
joy_buttons_pressed.erase(c);
675
}
676
for (int i = 0; i < (int)JoyAxis::MAX; i++) {
677
set_joy_axis(p_idx, (JoyAxis)i, 0.0f);
678
}
679
}
680
joy_names[p_idx] = js;
681
682
// Ensure this signal is emitted on the main thread, as some platforms (e.g. Linux) call this from a different thread.
683
call_deferred("emit_signal", SNAME("joy_connection_changed"), p_idx, p_connected);
684
}
685
686
Vector3 Input::get_gravity() const {
687
_THREAD_SAFE_METHOD_
688
689
#if defined(DEBUG_ENABLED) && defined(ANDROID_ENABLED)
690
if (!gravity_enabled) {
691
WARN_PRINT_ONCE("`input_devices/sensors/enable_gravity` is not enabled in project settings.");
692
}
693
#endif
694
695
return gravity;
696
}
697
698
Vector3 Input::get_accelerometer() const {
699
_THREAD_SAFE_METHOD_
700
701
#if defined(DEBUG_ENABLED) && defined(ANDROID_ENABLED)
702
if (!accelerometer_enabled) {
703
WARN_PRINT_ONCE("`input_devices/sensors/enable_accelerometer` is not enabled in project settings.");
704
}
705
#endif
706
707
return accelerometer;
708
}
709
710
Vector3 Input::get_magnetometer() const {
711
_THREAD_SAFE_METHOD_
712
713
#if defined(DEBUG_ENABLED) && defined(ANDROID_ENABLED)
714
if (!magnetometer_enabled) {
715
WARN_PRINT_ONCE("`input_devices/sensors/enable_magnetometer` is not enabled in project settings.");
716
}
717
#endif
718
719
return magnetometer;
720
}
721
722
Vector3 Input::get_gyroscope() const {
723
_THREAD_SAFE_METHOD_
724
725
#if defined(DEBUG_ENABLED) && defined(ANDROID_ENABLED)
726
if (!gyroscope_enabled) {
727
WARN_PRINT_ONCE("`input_devices/sensors/enable_gyroscope` is not enabled in project settings.");
728
}
729
#endif
730
731
return gyroscope;
732
}
733
734
void Input::_parse_input_event_impl(const Ref<InputEvent> &p_event, bool p_is_emulated) {
735
// This function does the final delivery of the input event to user land.
736
// Regardless where the event came from originally, this has to happen on the main thread.
737
DEV_ASSERT(Thread::get_caller_id() == Thread::get_main_id());
738
739
// Notes on mouse-touch emulation:
740
// - Emulated mouse events are parsed, that is, re-routed to this method, so they make the same effects
741
// as true mouse events. The only difference is the situation is flagged as emulated so they are not
742
// emulated back to touch events in an endless loop.
743
// - Emulated touch events are handed right to the main loop (i.e., the SceneTree) because they don't
744
// require additional handling by this class.
745
746
Ref<InputEventKey> k = p_event;
747
if (k.is_valid() && !k->is_echo() && k->get_keycode() != Key::NONE) {
748
if (k->is_pressed()) {
749
keys_pressed.insert(k->get_keycode());
750
} else {
751
keys_pressed.erase(k->get_keycode());
752
}
753
}
754
if (k.is_valid() && !k->is_echo() && k->get_physical_keycode() != Key::NONE) {
755
if (k->is_pressed()) {
756
physical_keys_pressed.insert(k->get_physical_keycode());
757
} else {
758
physical_keys_pressed.erase(k->get_physical_keycode());
759
}
760
}
761
if (k.is_valid() && !k->is_echo() && k->get_key_label() != Key::NONE) {
762
if (k->is_pressed()) {
763
key_label_pressed.insert(k->get_key_label());
764
} else {
765
key_label_pressed.erase(k->get_key_label());
766
}
767
}
768
769
Ref<InputEventMouseButton> mb = p_event;
770
771
if (mb.is_valid()) {
772
if (mb->is_pressed()) {
773
mouse_button_mask.set_flag(mouse_button_to_mask(mb->get_button_index()));
774
} else {
775
mouse_button_mask.clear_flag(mouse_button_to_mask(mb->get_button_index()));
776
}
777
778
Point2 pos = mb->get_global_position();
779
if (mouse_pos != pos) {
780
set_mouse_position(pos);
781
}
782
783
if (event_dispatch_function && emulate_touch_from_mouse && !p_is_emulated && mb->get_button_index() == MouseButton::LEFT) {
784
Ref<InputEventScreenTouch> touch_event;
785
touch_event.instantiate();
786
touch_event->set_pressed(mb->is_pressed());
787
touch_event->set_canceled(mb->is_canceled());
788
touch_event->set_position(mb->get_position());
789
touch_event->set_double_tap(mb->is_double_click());
790
touch_event->set_device(InputEvent::DEVICE_ID_EMULATION);
791
_THREAD_SAFE_UNLOCK_
792
event_dispatch_function(touch_event);
793
_THREAD_SAFE_LOCK_
794
}
795
}
796
797
Ref<InputEventMouseMotion> mm = p_event;
798
799
if (mm.is_valid()) {
800
Point2 position = mm->get_global_position();
801
if (mouse_pos != position) {
802
set_mouse_position(position);
803
}
804
Vector2 relative = mm->get_relative();
805
Vector2 screen_relative = mm->get_relative_screen_position();
806
mouse_velocity_track.update(relative, screen_relative);
807
808
if (event_dispatch_function && emulate_touch_from_mouse && !p_is_emulated && mm->get_button_mask().has_flag(MouseButtonMask::LEFT)) {
809
Ref<InputEventScreenDrag> drag_event;
810
drag_event.instantiate();
811
812
drag_event->set_position(position);
813
drag_event->set_relative(relative);
814
drag_event->set_relative_screen_position(screen_relative);
815
drag_event->set_tilt(mm->get_tilt());
816
drag_event->set_pen_inverted(mm->get_pen_inverted());
817
drag_event->set_pressure(mm->get_pressure());
818
drag_event->set_velocity(get_last_mouse_velocity());
819
drag_event->set_screen_velocity(get_last_mouse_screen_velocity());
820
drag_event->set_device(InputEvent::DEVICE_ID_EMULATION);
821
822
_THREAD_SAFE_UNLOCK_
823
event_dispatch_function(drag_event);
824
_THREAD_SAFE_LOCK_
825
}
826
}
827
828
Ref<InputEventScreenTouch> st = p_event;
829
830
if (st.is_valid()) {
831
if (st->is_pressed()) {
832
VelocityTrack &track = touch_velocity_track[st->get_index()];
833
track.reset();
834
} else {
835
// Since a pointer index may not occur again (OSs may or may not reuse them),
836
// imperatively remove it from the map to keep no fossil entries in it
837
touch_velocity_track.erase(st->get_index());
838
}
839
840
if (emulate_mouse_from_touch) {
841
bool translate = false;
842
if (st->is_pressed()) {
843
if (mouse_from_touch_index == -1) {
844
translate = true;
845
mouse_from_touch_index = st->get_index();
846
}
847
} else {
848
if (st->get_index() == mouse_from_touch_index) {
849
translate = true;
850
mouse_from_touch_index = -1;
851
}
852
}
853
854
if (translate) {
855
Ref<InputEventMouseButton> button_event;
856
button_event.instantiate();
857
858
button_event->set_device(InputEvent::DEVICE_ID_EMULATION);
859
button_event->set_position(st->get_position());
860
button_event->set_global_position(st->get_position());
861
button_event->set_pressed(st->is_pressed());
862
button_event->set_canceled(st->is_canceled());
863
button_event->set_button_index(MouseButton::LEFT);
864
button_event->set_double_click(st->is_double_tap());
865
button_event->set_window_id(st->get_window_id());
866
867
BitField<MouseButtonMask> ev_bm = mouse_button_mask;
868
if (st->is_pressed()) {
869
ev_bm.set_flag(MouseButtonMask::LEFT);
870
} else {
871
ev_bm.clear_flag(MouseButtonMask::LEFT);
872
}
873
button_event->set_button_mask(ev_bm);
874
875
_parse_input_event_impl(button_event, true);
876
}
877
}
878
}
879
880
Ref<InputEventScreenDrag> sd = p_event;
881
882
if (sd.is_valid()) {
883
VelocityTrack &track = touch_velocity_track[sd->get_index()];
884
track.update(sd->get_relative(), sd->get_relative_screen_position());
885
sd->set_velocity(track.velocity);
886
sd->set_screen_velocity(track.screen_velocity);
887
888
if (emulate_mouse_from_touch && sd->get_index() == mouse_from_touch_index) {
889
Ref<InputEventMouseMotion> motion_event;
890
motion_event.instantiate();
891
892
motion_event->set_device(InputEvent::DEVICE_ID_EMULATION);
893
motion_event->set_tilt(sd->get_tilt());
894
motion_event->set_pen_inverted(sd->get_pen_inverted());
895
motion_event->set_pressure(sd->get_pressure());
896
motion_event->set_position(sd->get_position());
897
motion_event->set_global_position(sd->get_position());
898
motion_event->set_relative(sd->get_relative());
899
motion_event->set_relative_screen_position(sd->get_relative_screen_position());
900
motion_event->set_velocity(sd->get_velocity());
901
motion_event->set_screen_velocity(sd->get_screen_velocity());
902
motion_event->set_button_mask(mouse_button_mask);
903
motion_event->set_window_id(sd->get_window_id());
904
905
_parse_input_event_impl(motion_event, true);
906
}
907
}
908
909
Ref<InputEventJoypadButton> jb = p_event;
910
911
if (jb.is_valid()) {
912
JoyButton c = _combine_device(jb->get_button_index(), jb->get_device());
913
914
if (jb->is_pressed()) {
915
joy_buttons_pressed.insert(c);
916
} else {
917
joy_buttons_pressed.erase(c);
918
}
919
}
920
921
Ref<InputEventJoypadMotion> jm = p_event;
922
923
if (jm.is_valid()) {
924
set_joy_axis(jm->get_device(), jm->get_axis(), jm->get_axis_value());
925
}
926
927
Ref<InputEventGesture> ge = p_event;
928
929
if (ge.is_valid()) {
930
if (event_dispatch_function) {
931
_THREAD_SAFE_UNLOCK_
932
event_dispatch_function(ge);
933
_THREAD_SAFE_LOCK_
934
}
935
}
936
937
for (const KeyValue<StringName, InputMap::Action> &E : InputMap::get_singleton()->get_action_map()) {
938
const int event_index = InputMap::get_singleton()->event_get_index(p_event, E.key);
939
if (event_index == -1) {
940
continue;
941
}
942
ERR_FAIL_COND_MSG(event_index >= (int)MAX_EVENT, vformat("Input singleton does not support more than %d events assigned to an action.", MAX_EVENT));
943
944
int device_id = p_event->get_device();
945
bool is_pressed = p_event->is_action_pressed(E.key, true);
946
ActionState &action_state = action_states[E.key];
947
948
// Update the action's per-device state.
949
ActionState::DeviceState &device_state = action_state.device_states[device_id];
950
device_state.pressed[event_index] = is_pressed;
951
device_state.strength[event_index] = p_event->get_action_strength(E.key);
952
device_state.raw_strength[event_index] = p_event->get_action_raw_strength(E.key);
953
954
// Update the action's global state and cache.
955
if (!is_pressed) {
956
action_state.api_pressed = false; // Always release the event from action_press() method.
957
action_state.api_strength = 0.0;
958
}
959
action_state.exact = InputMap::get_singleton()->event_is_action(p_event, E.key, true);
960
961
bool was_pressed = action_state.cache.pressed;
962
_update_action_cache(E.key, action_state);
963
// As input may come in part way through a physics tick, the earliest we can react to it is the next physics tick.
964
if (action_state.cache.pressed && !was_pressed) {
965
action_state.pressed_event_id = p_event->get_instance_id();
966
action_state.pressed_physics_frame = Engine::get_singleton()->get_physics_frames() + 1;
967
action_state.pressed_process_frame = Engine::get_singleton()->get_process_frames();
968
}
969
if (!action_state.cache.pressed && was_pressed) {
970
action_state.released_event_id = p_event->get_instance_id();
971
action_state.released_physics_frame = Engine::get_singleton()->get_physics_frames() + 1;
972
action_state.released_process_frame = Engine::get_singleton()->get_process_frames();
973
}
974
}
975
976
if (event_dispatch_function) {
977
_THREAD_SAFE_UNLOCK_
978
event_dispatch_function(p_event);
979
_THREAD_SAFE_LOCK_
980
}
981
}
982
983
void Input::set_joy_axis(int p_device, JoyAxis p_axis, float p_value) {
984
_THREAD_SAFE_METHOD_
985
JoyAxis c = _combine_device(p_axis, p_device);
986
_joy_axis[c] = p_value;
987
}
988
989
void Input::start_joy_vibration(int p_device, float p_weak_magnitude, float p_strong_magnitude, float p_duration) {
990
_THREAD_SAFE_METHOD_
991
if (p_weak_magnitude < 0.f || p_weak_magnitude > 1.f || p_strong_magnitude < 0.f || p_strong_magnitude > 1.f) {
992
return;
993
}
994
VibrationInfo vibration;
995
vibration.weak_magnitude = p_weak_magnitude;
996
vibration.strong_magnitude = p_strong_magnitude;
997
vibration.duration = p_duration;
998
vibration.timestamp = OS::get_singleton()->get_ticks_usec();
999
joy_vibration[p_device] = vibration;
1000
}
1001
1002
void Input::stop_joy_vibration(int p_device) {
1003
_THREAD_SAFE_METHOD_
1004
VibrationInfo vibration;
1005
vibration.weak_magnitude = 0;
1006
vibration.strong_magnitude = 0;
1007
vibration.duration = 0;
1008
vibration.timestamp = OS::get_singleton()->get_ticks_usec();
1009
joy_vibration[p_device] = vibration;
1010
}
1011
1012
void Input::vibrate_handheld(int p_duration_ms, float p_amplitude) {
1013
OS::get_singleton()->vibrate_handheld(p_duration_ms, p_amplitude);
1014
}
1015
1016
void Input::set_gravity(const Vector3 &p_gravity) {
1017
_THREAD_SAFE_METHOD_
1018
1019
gravity = p_gravity;
1020
}
1021
1022
void Input::set_accelerometer(const Vector3 &p_accel) {
1023
_THREAD_SAFE_METHOD_
1024
1025
accelerometer = p_accel;
1026
}
1027
1028
void Input::set_magnetometer(const Vector3 &p_magnetometer) {
1029
_THREAD_SAFE_METHOD_
1030
1031
magnetometer = p_magnetometer;
1032
}
1033
1034
void Input::set_gyroscope(const Vector3 &p_gyroscope) {
1035
_THREAD_SAFE_METHOD_
1036
1037
gyroscope = p_gyroscope;
1038
}
1039
1040
void Input::set_mouse_position(const Point2 &p_posf) {
1041
mouse_pos = p_posf;
1042
}
1043
1044
Point2 Input::get_mouse_position() const {
1045
return mouse_pos;
1046
}
1047
1048
Point2 Input::get_last_mouse_velocity() {
1049
mouse_velocity_track.update(Vector2(), Vector2());
1050
return mouse_velocity_track.velocity;
1051
}
1052
1053
Point2 Input::get_last_mouse_screen_velocity() {
1054
mouse_velocity_track.update(Vector2(), Vector2());
1055
return mouse_velocity_track.screen_velocity;
1056
}
1057
1058
BitField<MouseButtonMask> Input::get_mouse_button_mask() const {
1059
return mouse_button_mask; // do not trust OS implementation, should remove it - OS::get_singleton()->get_mouse_button_state();
1060
}
1061
1062
void Input::warp_mouse(const Vector2 &p_position) {
1063
warp_mouse_func(p_position);
1064
}
1065
1066
Point2 Input::warp_mouse_motion(const Ref<InputEventMouseMotion> &p_motion, const Rect2 &p_rect) {
1067
// The relative distance reported for the next event after a warp is in the boundaries of the
1068
// size of the rect on that axis, but it may be greater, in which case there's no problem as fmod()
1069
// will warp it, but if the pointer has moved in the opposite direction between the pointer relocation
1070
// and the subsequent event, the reported relative distance will be less than the size of the rect
1071
// and thus fmod() will be disabled for handling the situation.
1072
// And due to this mouse warping mechanism being stateless, we need to apply some heuristics to
1073
// detect the warp: if the relative distance is greater than the half of the size of the relevant rect
1074
// (checked per each axis), it will be considered as the consequence of a former pointer warp.
1075
1076
const Point2 rel_sign(p_motion->get_relative().x >= 0.0f ? 1 : -1, p_motion->get_relative().y >= 0.0 ? 1 : -1);
1077
const Size2 warp_margin = p_rect.size * 0.5f;
1078
const Point2 rel_warped(
1079
Math::fmod(p_motion->get_relative().x + rel_sign.x * warp_margin.x, p_rect.size.x) - rel_sign.x * warp_margin.x,
1080
Math::fmod(p_motion->get_relative().y + rel_sign.y * warp_margin.y, p_rect.size.y) - rel_sign.y * warp_margin.y);
1081
1082
const Point2 pos_local = p_motion->get_global_position() - p_rect.position;
1083
const Point2 pos_warped(Math::fposmod(pos_local.x, p_rect.size.x), Math::fposmod(pos_local.y, p_rect.size.y));
1084
if (pos_warped != pos_local) {
1085
warp_mouse(pos_warped + p_rect.position);
1086
}
1087
1088
return rel_warped;
1089
}
1090
1091
void Input::action_press(const StringName &p_action, float p_strength) {
1092
ERR_FAIL_COND_MSG(!InputMap::get_singleton()->has_action(p_action), InputMap::get_singleton()->suggest_actions(p_action));
1093
1094
// Create or retrieve existing action.
1095
ActionState &action_state = action_states[p_action];
1096
1097
// As input may come in part way through a physics tick, the earliest we can react to it is the next physics tick.
1098
if (!action_state.cache.pressed) {
1099
action_state.pressed_event_id = ObjectID();
1100
action_state.pressed_physics_frame = Engine::get_singleton()->get_physics_frames() + 1;
1101
action_state.pressed_process_frame = Engine::get_singleton()->get_process_frames();
1102
}
1103
action_state.exact = true;
1104
action_state.api_pressed = true;
1105
action_state.api_strength = CLAMP(p_strength, 0.0f, 1.0f);
1106
_update_action_cache(p_action, action_state);
1107
}
1108
1109
void Input::action_release(const StringName &p_action) {
1110
ERR_FAIL_COND_MSG(!InputMap::get_singleton()->has_action(p_action), InputMap::get_singleton()->suggest_actions(p_action));
1111
1112
// Create or retrieve existing action.
1113
ActionState &action_state = action_states[p_action];
1114
action_state.cache.pressed = false;
1115
action_state.cache.strength = 0.0;
1116
action_state.cache.raw_strength = 0.0;
1117
// As input may come in part way through a physics tick, the earliest we can react to it is the next physics tick.
1118
action_state.released_event_id = ObjectID();
1119
action_state.released_physics_frame = Engine::get_singleton()->get_physics_frames() + 1;
1120
action_state.released_process_frame = Engine::get_singleton()->get_process_frames();
1121
action_state.device_states.clear();
1122
action_state.exact = true;
1123
action_state.api_pressed = false;
1124
action_state.api_strength = 0.0;
1125
}
1126
1127
void Input::set_emulate_touch_from_mouse(bool p_emulate) {
1128
emulate_touch_from_mouse = p_emulate;
1129
}
1130
1131
bool Input::is_emulating_touch_from_mouse() const {
1132
return emulate_touch_from_mouse;
1133
}
1134
1135
// Calling this whenever the game window is focused helps unsticking the "touch mouse"
1136
// if the OS or its abstraction class hasn't properly reported that touch pointers raised
1137
void Input::ensure_touch_mouse_raised() {
1138
_THREAD_SAFE_METHOD_
1139
if (mouse_from_touch_index != -1) {
1140
mouse_from_touch_index = -1;
1141
1142
Ref<InputEventMouseButton> button_event;
1143
button_event.instantiate();
1144
1145
button_event->set_device(InputEvent::DEVICE_ID_EMULATION);
1146
button_event->set_position(mouse_pos);
1147
button_event->set_global_position(mouse_pos);
1148
button_event->set_pressed(false);
1149
button_event->set_button_index(MouseButton::LEFT);
1150
BitField<MouseButtonMask> ev_bm = mouse_button_mask;
1151
ev_bm.clear_flag(MouseButtonMask::LEFT);
1152
button_event->set_button_mask(ev_bm);
1153
1154
_parse_input_event_impl(button_event, true);
1155
}
1156
}
1157
1158
void Input::set_emulate_mouse_from_touch(bool p_emulate) {
1159
emulate_mouse_from_touch = p_emulate;
1160
}
1161
1162
bool Input::is_emulating_mouse_from_touch() const {
1163
return emulate_mouse_from_touch;
1164
}
1165
1166
Input::CursorShape Input::get_default_cursor_shape() const {
1167
return default_shape;
1168
}
1169
1170
void Input::set_default_cursor_shape(CursorShape p_shape) {
1171
if (default_shape == p_shape) {
1172
return;
1173
}
1174
1175
default_shape = p_shape;
1176
// The default shape is set in Viewport::_gui_input_event. To instantly
1177
// see the shape in the viewport we need to trigger a mouse motion event.
1178
Ref<InputEventMouseMotion> mm;
1179
mm.instantiate();
1180
mm->set_position(mouse_pos);
1181
mm->set_global_position(mouse_pos);
1182
mm->set_device(InputEvent::DEVICE_ID_INTERNAL);
1183
parse_input_event(mm);
1184
}
1185
1186
Input::CursorShape Input::get_current_cursor_shape() const {
1187
return get_current_cursor_shape_func();
1188
}
1189
1190
void Input::set_custom_mouse_cursor(const Ref<Resource> &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot) {
1191
if (Engine::get_singleton()->is_editor_hint()) {
1192
return;
1193
}
1194
1195
ERR_FAIL_INDEX(p_shape, CursorShape::CURSOR_MAX);
1196
1197
set_custom_mouse_cursor_func(p_cursor, p_shape, p_hotspot);
1198
}
1199
1200
void Input::parse_input_event(const Ref<InputEvent> &p_event) {
1201
_THREAD_SAFE_METHOD_
1202
1203
ERR_FAIL_COND(p_event.is_null());
1204
1205
#ifdef DEBUG_ENABLED
1206
uint64_t curr_frame = Engine::get_singleton()->get_process_frames();
1207
if (curr_frame != last_parsed_frame) {
1208
frame_parsed_events.clear();
1209
last_parsed_frame = curr_frame;
1210
frame_parsed_events.insert(p_event);
1211
} else if (frame_parsed_events.has(p_event)) {
1212
// It would be technically safe to send the same event in cases such as:
1213
// - After an explicit flush.
1214
// - In platforms using buffering when agile flushing is enabled, after one of the mid-frame flushes.
1215
// - If platform doesn't use buffering and event accumulation is disabled.
1216
// - If platform doesn't use buffering and the event type is not accumulable.
1217
// However, it wouldn't be reasonable to ask users to remember the full ruleset and be aware at all times
1218
// of the possibilities of the target platform, project settings and engine internals, which may change
1219
// without prior notice.
1220
// Therefore, the guideline is, "don't send the same event object more than once per frame".
1221
WARN_PRINT_ONCE(
1222
"An input event object is being parsed more than once in the same frame, which is unsafe.\n"
1223
"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"
1224
"You can call duplicate() on the event to get a new instance with identical values.");
1225
} else {
1226
frame_parsed_events.insert(p_event);
1227
}
1228
#endif
1229
1230
if (use_accumulated_input) {
1231
if (buffered_events.is_empty() || !buffered_events.back()->get()->accumulate(p_event)) {
1232
buffered_events.push_back(p_event);
1233
}
1234
} else if (agile_input_event_flushing) {
1235
buffered_events.push_back(p_event);
1236
} else {
1237
_parse_input_event_impl(p_event, false);
1238
}
1239
}
1240
1241
#ifdef DEBUG_ENABLED
1242
void Input::flush_frame_parsed_events() {
1243
_THREAD_SAFE_METHOD_
1244
1245
frame_parsed_events.clear();
1246
}
1247
#endif
1248
1249
void Input::flush_buffered_events() {
1250
_THREAD_SAFE_METHOD_
1251
1252
while (buffered_events.front()) {
1253
// The final delivery of the input event involves releasing the lock.
1254
// While the lock is released, another thread may lock it and add new events to the back.
1255
// Therefore, we get each event and pop it while we still have the lock,
1256
// to ensure the list is in a consistent state.
1257
List<Ref<InputEvent>>::Element *E = buffered_events.front();
1258
Ref<InputEvent> e = E->get();
1259
buffered_events.pop_front();
1260
1261
_parse_input_event_impl(e, false);
1262
}
1263
}
1264
1265
bool Input::is_agile_input_event_flushing() {
1266
return agile_input_event_flushing;
1267
}
1268
1269
void Input::set_agile_input_event_flushing(bool p_enable) {
1270
agile_input_event_flushing = p_enable;
1271
}
1272
1273
void Input::set_use_accumulated_input(bool p_enable) {
1274
use_accumulated_input = p_enable;
1275
}
1276
1277
bool Input::is_using_accumulated_input() {
1278
return use_accumulated_input;
1279
}
1280
1281
void Input::release_pressed_events() {
1282
flush_buffered_events(); // this is needed to release actions strengths
1283
1284
keys_pressed.clear();
1285
physical_keys_pressed.clear();
1286
key_label_pressed.clear();
1287
joy_buttons_pressed.clear();
1288
_joy_axis.clear();
1289
1290
for (KeyValue<StringName, Input::ActionState> &E : action_states) {
1291
if (E.value.cache.pressed) {
1292
action_release(E.key);
1293
}
1294
}
1295
}
1296
1297
void Input::set_event_dispatch_function(EventDispatchFunc p_function) {
1298
event_dispatch_function = p_function;
1299
}
1300
1301
void Input::joy_button(int p_device, JoyButton p_button, bool p_pressed) {
1302
_THREAD_SAFE_METHOD_;
1303
Joypad &joy = joy_names[p_device];
1304
ERR_FAIL_INDEX((int)p_button, (int)JoyButton::MAX);
1305
1306
if (joy.last_buttons[(size_t)p_button] == p_pressed) {
1307
return;
1308
}
1309
joy.last_buttons[(size_t)p_button] = p_pressed;
1310
if (joy.mapping == -1) {
1311
_button_event(p_device, p_button, p_pressed);
1312
return;
1313
}
1314
1315
JoyEvent map = _get_mapped_button_event(map_db[joy.mapping], p_button);
1316
1317
if (map.type == TYPE_BUTTON) {
1318
_button_event(p_device, (JoyButton)map.index, p_pressed);
1319
return;
1320
}
1321
1322
if (map.type == TYPE_AXIS) {
1323
_axis_event(p_device, (JoyAxis)map.index, p_pressed ? map.value : 0.0);
1324
}
1325
// no event?
1326
}
1327
1328
void Input::joy_axis(int p_device, JoyAxis p_axis, float p_value) {
1329
_THREAD_SAFE_METHOD_;
1330
1331
ERR_FAIL_INDEX((int)p_axis, (int)JoyAxis::MAX);
1332
1333
Joypad &joy = joy_names[p_device];
1334
1335
if (joy.last_axis[(size_t)p_axis] == p_value) {
1336
return;
1337
}
1338
1339
joy.last_axis[(size_t)p_axis] = p_value;
1340
1341
if (joy.mapping == -1) {
1342
_axis_event(p_device, p_axis, p_value);
1343
return;
1344
}
1345
1346
JoyAxisRange range;
1347
JoyEvent map = _get_mapped_axis_event(map_db[joy.mapping], p_axis, p_value, range);
1348
1349
if (map.type == TYPE_BUTTON) {
1350
bool pressed = map.value > 0.5;
1351
if (pressed != joy_buttons_pressed.has(_combine_device((JoyButton)map.index, p_device))) {
1352
_button_event(p_device, (JoyButton)map.index, pressed);
1353
}
1354
1355
// Ensure opposite D-Pad button is also released.
1356
switch ((JoyButton)map.index) {
1357
case JoyButton::DPAD_UP:
1358
if (joy_buttons_pressed.has(_combine_device(JoyButton::DPAD_DOWN, p_device))) {
1359
_button_event(p_device, JoyButton::DPAD_DOWN, false);
1360
}
1361
break;
1362
case JoyButton::DPAD_DOWN:
1363
if (joy_buttons_pressed.has(_combine_device(JoyButton::DPAD_UP, p_device))) {
1364
_button_event(p_device, JoyButton::DPAD_UP, false);
1365
}
1366
break;
1367
case JoyButton::DPAD_LEFT:
1368
if (joy_buttons_pressed.has(_combine_device(JoyButton::DPAD_RIGHT, p_device))) {
1369
_button_event(p_device, JoyButton::DPAD_RIGHT, false);
1370
}
1371
break;
1372
case JoyButton::DPAD_RIGHT:
1373
if (joy_buttons_pressed.has(_combine_device(JoyButton::DPAD_LEFT, p_device))) {
1374
_button_event(p_device, JoyButton::DPAD_LEFT, false);
1375
}
1376
break;
1377
default:
1378
// Nothing to do.
1379
break;
1380
}
1381
return;
1382
}
1383
1384
if (map.type == TYPE_AXIS) {
1385
JoyAxis axis = JoyAxis(map.index);
1386
float value = map.value;
1387
if (range == FULL_AXIS && (axis == JoyAxis::TRIGGER_LEFT || axis == JoyAxis::TRIGGER_RIGHT)) {
1388
// Convert to a value between 0.0f and 1.0f.
1389
value = 0.5f + value / 2.0f;
1390
}
1391
_axis_event(p_device, axis, value);
1392
return;
1393
}
1394
}
1395
1396
void Input::joy_hat(int p_device, BitField<HatMask> p_val) {
1397
_THREAD_SAFE_METHOD_;
1398
const Joypad &joy = joy_names[p_device];
1399
1400
JoyEvent map[(size_t)HatDir::MAX];
1401
1402
map[(size_t)HatDir::UP].type = TYPE_BUTTON;
1403
map[(size_t)HatDir::UP].index = (int)JoyButton::DPAD_UP;
1404
map[(size_t)HatDir::UP].value = 0;
1405
1406
map[(size_t)HatDir::RIGHT].type = TYPE_BUTTON;
1407
map[(size_t)HatDir::RIGHT].index = (int)JoyButton::DPAD_RIGHT;
1408
map[(size_t)HatDir::RIGHT].value = 0;
1409
1410
map[(size_t)HatDir::DOWN].type = TYPE_BUTTON;
1411
map[(size_t)HatDir::DOWN].index = (int)JoyButton::DPAD_DOWN;
1412
map[(size_t)HatDir::DOWN].value = 0;
1413
1414
map[(size_t)HatDir::LEFT].type = TYPE_BUTTON;
1415
map[(size_t)HatDir::LEFT].index = (int)JoyButton::DPAD_LEFT;
1416
map[(size_t)HatDir::LEFT].value = 0;
1417
1418
if (joy.mapping != -1) {
1419
_get_mapped_hat_events(map_db[joy.mapping], (HatDir)0, map);
1420
}
1421
1422
int cur_val = joy_names[p_device].hat_current;
1423
1424
for (int hat_direction = 0, hat_mask = 1; hat_direction < (int)HatDir::MAX; hat_direction++, hat_mask <<= 1) {
1425
if (((int)p_val & hat_mask) != (cur_val & hat_mask)) {
1426
if (map[hat_direction].type == TYPE_BUTTON) {
1427
_button_event(p_device, (JoyButton)map[hat_direction].index, (int)p_val & hat_mask);
1428
}
1429
if (map[hat_direction].type == TYPE_AXIS) {
1430
_axis_event(p_device, (JoyAxis)map[hat_direction].index, ((int)p_val & hat_mask) ? map[hat_direction].value : 0.0);
1431
}
1432
}
1433
}
1434
1435
joy_names[p_device].hat_current = (int)p_val;
1436
}
1437
1438
void Input::_button_event(int p_device, JoyButton p_index, bool p_pressed) {
1439
Ref<InputEventJoypadButton> ievent;
1440
ievent.instantiate();
1441
ievent->set_device(p_device);
1442
ievent->set_button_index(p_index);
1443
ievent->set_pressed(p_pressed);
1444
1445
parse_input_event(ievent);
1446
}
1447
1448
void Input::_axis_event(int p_device, JoyAxis p_axis, float p_value) {
1449
Ref<InputEventJoypadMotion> ievent;
1450
ievent.instantiate();
1451
ievent->set_device(p_device);
1452
ievent->set_axis(p_axis);
1453
ievent->set_axis_value(p_value);
1454
1455
parse_input_event(ievent);
1456
}
1457
1458
void Input::_update_action_cache(const StringName &p_action_name, ActionState &r_action_state) {
1459
// Update the action cache, computed from the per-device and per-event states.
1460
r_action_state.cache.pressed = false;
1461
r_action_state.cache.strength = 0.0;
1462
r_action_state.cache.raw_strength = 0.0;
1463
1464
int max_event = InputMap::get_singleton()->action_get_events(p_action_name)->size() + 1; // +1 comes from InputEventAction.
1465
for (const KeyValue<int, ActionState::DeviceState> &kv : r_action_state.device_states) {
1466
const ActionState::DeviceState &device_state = kv.value;
1467
for (int i = 0; i < max_event; i++) {
1468
r_action_state.cache.pressed = r_action_state.cache.pressed || device_state.pressed[i];
1469
r_action_state.cache.strength = MAX(r_action_state.cache.strength, device_state.strength[i]);
1470
r_action_state.cache.raw_strength = MAX(r_action_state.cache.raw_strength, device_state.raw_strength[i]);
1471
}
1472
}
1473
1474
if (r_action_state.api_pressed) {
1475
r_action_state.cache.pressed = true;
1476
r_action_state.cache.strength = MAX(r_action_state.cache.strength, r_action_state.api_strength);
1477
r_action_state.cache.raw_strength = MAX(r_action_state.cache.raw_strength, r_action_state.api_strength); // Use the strength as raw_strength for API-pressed states.
1478
}
1479
}
1480
1481
Input::JoyEvent Input::_get_mapped_button_event(const JoyDeviceMapping &mapping, JoyButton p_button) {
1482
JoyEvent event;
1483
1484
for (int i = 0; i < mapping.bindings.size(); i++) {
1485
const JoyBinding binding = mapping.bindings[i];
1486
if (binding.inputType == TYPE_BUTTON && binding.input.button == p_button) {
1487
event.type = binding.outputType;
1488
switch (binding.outputType) {
1489
case TYPE_BUTTON:
1490
event.index = (int)binding.output.button;
1491
return event;
1492
case TYPE_AXIS:
1493
event.index = (int)binding.output.axis.axis;
1494
switch (binding.output.axis.range) {
1495
case POSITIVE_HALF_AXIS:
1496
event.value = 1;
1497
break;
1498
case NEGATIVE_HALF_AXIS:
1499
event.value = -1;
1500
break;
1501
case FULL_AXIS:
1502
// It doesn't make sense for a button to map to a full axis,
1503
// but keeping as a default for a trigger with a positive half-axis.
1504
event.value = 1;
1505
break;
1506
}
1507
return event;
1508
default:
1509
ERR_PRINT_ONCE("Joypad button mapping error.");
1510
}
1511
}
1512
}
1513
return event;
1514
}
1515
1516
Input::JoyEvent Input::_get_mapped_axis_event(const JoyDeviceMapping &mapping, JoyAxis p_axis, float p_value, JoyAxisRange &r_range) {
1517
JoyEvent event;
1518
1519
for (int i = 0; i < mapping.bindings.size(); i++) {
1520
const JoyBinding binding = mapping.bindings[i];
1521
if (binding.inputType == TYPE_AXIS && binding.input.axis.axis == p_axis) {
1522
float value = p_value;
1523
if (binding.input.axis.invert) {
1524
value = -value;
1525
}
1526
if (binding.input.axis.range == FULL_AXIS ||
1527
(binding.input.axis.range == POSITIVE_HALF_AXIS && value >= 0) ||
1528
(binding.input.axis.range == NEGATIVE_HALF_AXIS && value < 0)) {
1529
event.type = binding.outputType;
1530
float shifted_positive_value = 0;
1531
switch (binding.input.axis.range) {
1532
case POSITIVE_HALF_AXIS:
1533
shifted_positive_value = value;
1534
break;
1535
case NEGATIVE_HALF_AXIS:
1536
shifted_positive_value = value + 1;
1537
break;
1538
case FULL_AXIS:
1539
shifted_positive_value = (value + 1) / 2;
1540
break;
1541
}
1542
switch (binding.outputType) {
1543
case TYPE_BUTTON:
1544
event.index = (int)binding.output.button;
1545
switch (binding.input.axis.range) {
1546
case POSITIVE_HALF_AXIS:
1547
event.value = shifted_positive_value;
1548
break;
1549
case NEGATIVE_HALF_AXIS:
1550
event.value = 1 - shifted_positive_value;
1551
break;
1552
case FULL_AXIS:
1553
// It doesn't make sense for a full axis to map to a button,
1554
// but keeping as a default for a trigger with a positive half-axis.
1555
event.value = (shifted_positive_value * 2) - 1;
1556
break;
1557
}
1558
return event;
1559
case TYPE_AXIS:
1560
event.index = (int)binding.output.axis.axis;
1561
event.value = value;
1562
r_range = binding.output.axis.range;
1563
if (binding.output.axis.range != binding.input.axis.range) {
1564
switch (binding.output.axis.range) {
1565
case POSITIVE_HALF_AXIS:
1566
event.value = shifted_positive_value;
1567
break;
1568
case NEGATIVE_HALF_AXIS:
1569
event.value = shifted_positive_value - 1;
1570
break;
1571
case FULL_AXIS:
1572
event.value = (shifted_positive_value * 2) - 1;
1573
break;
1574
}
1575
}
1576
return event;
1577
default:
1578
ERR_PRINT_ONCE("Joypad axis mapping error.");
1579
}
1580
}
1581
}
1582
}
1583
return event;
1584
}
1585
1586
void Input::_get_mapped_hat_events(const JoyDeviceMapping &mapping, HatDir p_hat, JoyEvent r_events[(size_t)HatDir::MAX]) {
1587
for (int i = 0; i < mapping.bindings.size(); i++) {
1588
const JoyBinding binding = mapping.bindings[i];
1589
if (binding.inputType == TYPE_HAT && binding.input.hat.hat == p_hat) {
1590
HatDir hat_direction;
1591
switch (binding.input.hat.hat_mask) {
1592
case HatMask::UP:
1593
hat_direction = HatDir::UP;
1594
break;
1595
case HatMask::RIGHT:
1596
hat_direction = HatDir::RIGHT;
1597
break;
1598
case HatMask::DOWN:
1599
hat_direction = HatDir::DOWN;
1600
break;
1601
case HatMask::LEFT:
1602
hat_direction = HatDir::LEFT;
1603
break;
1604
default:
1605
ERR_PRINT_ONCE("Joypad button mapping error.");
1606
continue;
1607
}
1608
1609
r_events[(size_t)hat_direction].type = binding.outputType;
1610
switch (binding.outputType) {
1611
case TYPE_BUTTON:
1612
r_events[(size_t)hat_direction].index = (int)binding.output.button;
1613
break;
1614
case TYPE_AXIS:
1615
r_events[(size_t)hat_direction].index = (int)binding.output.axis.axis;
1616
switch (binding.output.axis.range) {
1617
case POSITIVE_HALF_AXIS:
1618
r_events[(size_t)hat_direction].value = 1;
1619
break;
1620
case NEGATIVE_HALF_AXIS:
1621
r_events[(size_t)hat_direction].value = -1;
1622
break;
1623
case FULL_AXIS:
1624
// It doesn't make sense for a hat direction to map to a full axis,
1625
// but keeping as a default for a trigger with a positive half-axis.
1626
r_events[(size_t)hat_direction].value = 1;
1627
break;
1628
}
1629
break;
1630
default:
1631
ERR_PRINT_ONCE("Joypad button mapping error.");
1632
}
1633
}
1634
}
1635
}
1636
1637
JoyButton Input::_get_output_button(const String &output) {
1638
for (int i = 0; i < (int)JoyButton::SDL_MAX; i++) {
1639
if (output == _joy_buttons[i]) {
1640
return JoyButton(i);
1641
}
1642
}
1643
return JoyButton::INVALID;
1644
}
1645
1646
JoyAxis Input::_get_output_axis(const String &output) {
1647
for (int i = 0; i < (int)JoyAxis::SDL_MAX; i++) {
1648
if (output == _joy_axes[i]) {
1649
return JoyAxis(i);
1650
}
1651
}
1652
return JoyAxis::INVALID;
1653
}
1654
1655
void Input::parse_mapping(const String &p_mapping) {
1656
_THREAD_SAFE_METHOD_;
1657
JoyDeviceMapping mapping;
1658
1659
Vector<String> entry = p_mapping.split(",");
1660
if (entry.size() < 2) {
1661
return;
1662
}
1663
1664
mapping.uid = entry[0];
1665
mapping.name = entry[1];
1666
1667
int idx = 1;
1668
while (++idx < entry.size()) {
1669
if (entry[idx].is_empty()) {
1670
continue;
1671
}
1672
1673
String output = entry[idx].get_slicec(':', 0).remove_char(' ');
1674
String input = entry[idx].get_slicec(':', 1).remove_char(' ');
1675
if (output.length() < 1 || input.length() < 2) {
1676
continue;
1677
}
1678
1679
if (output == "platform" || output == "hint") {
1680
continue;
1681
}
1682
1683
JoyAxisRange output_range = FULL_AXIS;
1684
if (output[0] == '+' || output[0] == '-') {
1685
ERR_CONTINUE_MSG(output.length() < 2,
1686
vformat("Invalid output entry \"%s\" in mapping:\n%s", entry[idx], p_mapping));
1687
if (output[0] == '+') {
1688
output_range = POSITIVE_HALF_AXIS;
1689
} else if (output[0] == '-') {
1690
output_range = NEGATIVE_HALF_AXIS;
1691
}
1692
output = output.substr(1);
1693
}
1694
1695
JoyAxisRange input_range = FULL_AXIS;
1696
if (input[0] == '+') {
1697
input_range = POSITIVE_HALF_AXIS;
1698
input = input.substr(1);
1699
} else if (input[0] == '-') {
1700
input_range = NEGATIVE_HALF_AXIS;
1701
input = input.substr(1);
1702
}
1703
bool invert_axis = false;
1704
if (input[input.length() - 1] == '~') {
1705
invert_axis = true;
1706
input = input.left(input.length() - 1);
1707
}
1708
1709
JoyButton output_button = _get_output_button(output);
1710
JoyAxis output_axis = _get_output_axis(output);
1711
if (output_button == JoyButton::INVALID && output_axis == JoyAxis::INVALID) {
1712
print_verbose(vformat("Unrecognized output string \"%s\" in mapping:\n%s", output, p_mapping));
1713
continue;
1714
}
1715
ERR_CONTINUE_MSG(output_button != JoyButton::INVALID && output_axis != JoyAxis::INVALID,
1716
vformat("Output string \"%s\" matched both button and axis in mapping:\n%s", output, p_mapping));
1717
1718
JoyBinding binding;
1719
if (output_button != JoyButton::INVALID) {
1720
binding.outputType = TYPE_BUTTON;
1721
binding.output.button = output_button;
1722
} else if (output_axis != JoyAxis::INVALID) {
1723
binding.outputType = TYPE_AXIS;
1724
binding.output.axis.axis = output_axis;
1725
binding.output.axis.range = output_range;
1726
}
1727
1728
switch (input[0]) {
1729
case 'b':
1730
binding.inputType = TYPE_BUTTON;
1731
binding.input.button = (JoyButton)input.substr(1).to_int();
1732
break;
1733
case 'a':
1734
binding.inputType = TYPE_AXIS;
1735
binding.input.axis.axis = (JoyAxis)input.substr(1).to_int();
1736
binding.input.axis.range = input_range;
1737
binding.input.axis.invert = invert_axis;
1738
break;
1739
case 'h':
1740
ERR_CONTINUE_MSG(input.length() != 4 || input[2] != '.',
1741
vformat("Invalid had input \"%s\" in mapping:\n%s", input, p_mapping));
1742
binding.inputType = TYPE_HAT;
1743
binding.input.hat.hat = (HatDir)input.substr(1, 1).to_int();
1744
binding.input.hat.hat_mask = static_cast<HatMask>(input.substr(3).to_int());
1745
break;
1746
default:
1747
ERR_CONTINUE_MSG(true, vformat("Unrecognized input string \"%s\" in mapping:\n%s", input, p_mapping));
1748
}
1749
1750
mapping.bindings.push_back(binding);
1751
}
1752
1753
map_db.push_back(mapping);
1754
}
1755
1756
void Input::add_joy_mapping(const String &p_mapping, bool p_update_existing) {
1757
parse_mapping(p_mapping);
1758
if (p_update_existing) {
1759
Vector<String> entry = p_mapping.split(",");
1760
const String &uid = entry[0];
1761
for (KeyValue<int, Joypad> &E : joy_names) {
1762
Joypad &joy = E.value;
1763
if (joy.uid == uid) {
1764
_set_joypad_mapping(joy, map_db.size() - 1);
1765
}
1766
}
1767
}
1768
}
1769
1770
void Input::remove_joy_mapping(const String &p_guid) {
1771
// One GUID can exist multiple times in `map_db`, and
1772
// `add_joy_mapping` can choose not to update the existing mapping,
1773
// so the indices can be all over the place. Therefore we need to remember them.
1774
Vector<int> removed_idx;
1775
int min_removed_idx = -1;
1776
int max_removed_idx = -1;
1777
int fallback_mapping_offset = 0;
1778
1779
for (int i = map_db.size() - 1; i >= 0; i--) {
1780
if (p_guid == map_db[i].uid) {
1781
map_db.remove_at(i);
1782
1783
if (max_removed_idx == -1) {
1784
max_removed_idx = i;
1785
}
1786
min_removed_idx = i;
1787
removed_idx.push_back(i);
1788
1789
if (i < fallback_mapping) {
1790
fallback_mapping_offset++;
1791
} else if (i == fallback_mapping) {
1792
fallback_mapping = -1;
1793
WARN_PRINT_ONCE(vformat("Removed fallback joypad input mapping \"%s\". This could lead to joypads not working as intended.", p_guid));
1794
}
1795
}
1796
}
1797
1798
if (min_removed_idx == -1) {
1799
return; // Nothing removed.
1800
}
1801
1802
if (fallback_mapping > 0) {
1803
// Fix the shifted index.
1804
fallback_mapping -= fallback_mapping_offset;
1805
}
1806
1807
int removed_idx_size = removed_idx.size();
1808
1809
// Update joypad mapping references: some
1810
// * should use the fallback_mapping (if set; if not, they get unmapped), or
1811
// * need their mapping reference fixed, because the deletion(s) offset them.
1812
for (KeyValue<int, Joypad> &E : joy_names) {
1813
Joypad &joy = E.value;
1814
if (joy.mapping < min_removed_idx) {
1815
continue; // Not affected.
1816
}
1817
1818
if (joy.mapping > max_removed_idx) {
1819
_set_joypad_mapping(joy, joy.mapping - removed_idx_size);
1820
continue; // Simple offset fix.
1821
}
1822
1823
// removed_idx is in reverse order (ie. high to low), because the first loop is in reverse order.
1824
for (int i = 0; i < removed_idx.size(); i++) {
1825
if (removed_idx[i] == joy.mapping) {
1826
// Set to fallback_mapping, if defined, else unmap the joypad.
1827
// Currently, the fallback_mapping is only set internally, and only for Android.
1828
_set_joypad_mapping(joy, fallback_mapping);
1829
break;
1830
}
1831
if (removed_idx[i] < joy.mapping) {
1832
// Complex offset fix:
1833
// This mapping was shifted by `(removed_idx_size - i)` deletions.
1834
_set_joypad_mapping(joy, joy.mapping - (removed_idx_size - i));
1835
break;
1836
}
1837
}
1838
}
1839
}
1840
1841
void Input::_set_joypad_mapping(Joypad &p_js, int p_map_index) {
1842
if (p_map_index != fallback_mapping && p_map_index >= 0 && p_map_index < map_db.size() && p_js.uid != "__XINPUT_DEVICE__") {
1843
// Prefer the joypad name defined in the mapping.
1844
// Exceptions:
1845
// * On Windows for XInput devices the mapping would change the joypad's name to a collective name.
1846
// * A fallback mapping is not allowed to override the joypad's name.
1847
p_js.name = map_db[p_map_index].name;
1848
}
1849
p_js.mapping = p_map_index;
1850
}
1851
1852
void Input::set_fallback_mapping(const String &p_guid) {
1853
for (int i = 0; i < map_db.size(); i++) {
1854
if (map_db[i].uid == p_guid) {
1855
fallback_mapping = i;
1856
return;
1857
}
1858
}
1859
}
1860
1861
//platforms that use the remapping system can override and call to these ones
1862
bool Input::is_joy_known(int p_device) {
1863
if (joy_names.has(p_device)) {
1864
int mapping = joy_names[p_device].mapping;
1865
if (mapping != -1 && mapping != fallback_mapping) {
1866
return true;
1867
}
1868
}
1869
return false;
1870
}
1871
1872
String Input::get_joy_guid(int p_device) const {
1873
ERR_FAIL_COND_V(!joy_names.has(p_device), "");
1874
return joy_names[p_device].uid;
1875
}
1876
1877
Dictionary Input::get_joy_info(int p_device) const {
1878
ERR_FAIL_COND_V(!joy_names.has(p_device), Dictionary());
1879
return joy_names[p_device].info;
1880
}
1881
1882
bool Input::should_ignore_device(int p_vendor_id, int p_product_id) const {
1883
uint32_t full_id = (((uint32_t)p_vendor_id) << 16) | ((uint16_t)p_product_id);
1884
return ignored_device_ids.has(full_id);
1885
}
1886
1887
TypedArray<int> Input::get_connected_joypads() {
1888
TypedArray<int> ret;
1889
HashMap<int, Joypad>::Iterator elem = joy_names.begin();
1890
while (elem) {
1891
if (elem->value.connected) {
1892
ret.push_back(elem->key);
1893
}
1894
++elem;
1895
}
1896
return ret;
1897
}
1898
1899
int Input::get_unused_joy_id() {
1900
for (int i = 0; i < JOYPADS_MAX; i++) {
1901
if (!joy_names.has(i) || !joy_names[i].connected) {
1902
return i;
1903
}
1904
}
1905
return -1;
1906
}
1907
1908
void Input::set_disable_input(bool p_disable) {
1909
disable_input = p_disable;
1910
}
1911
1912
bool Input::is_input_disabled() const {
1913
return disable_input;
1914
}
1915
1916
Input::Input() {
1917
singleton = this;
1918
1919
// Parse default mappings.
1920
{
1921
int i = 0;
1922
while (DefaultControllerMappings::mappings[i]) {
1923
parse_mapping(DefaultControllerMappings::mappings[i++]);
1924
}
1925
}
1926
1927
// If defined, parse SDL_GAMECONTROLLERCONFIG for possible new mappings/overrides.
1928
String env_mapping = OS::get_singleton()->get_environment("SDL_GAMECONTROLLERCONFIG");
1929
if (!env_mapping.is_empty()) {
1930
Vector<String> entries = env_mapping.split("\n");
1931
for (int i = 0; i < entries.size(); i++) {
1932
if (entries[i].is_empty()) {
1933
continue;
1934
}
1935
parse_mapping(entries[i]);
1936
}
1937
}
1938
1939
String env_ignore_devices = OS::get_singleton()->get_environment("SDL_GAMECONTROLLER_IGNORE_DEVICES");
1940
if (!env_ignore_devices.is_empty()) {
1941
Vector<String> entries = env_ignore_devices.split(",");
1942
for (int i = 0; i < entries.size(); i++) {
1943
Vector<String> vid_pid = entries[i].split("/");
1944
1945
if (vid_pid.size() < 2) {
1946
continue;
1947
}
1948
1949
print_verbose(vformat("Device Ignored -- Vendor: %s Product: %s", vid_pid[0], vid_pid[1]));
1950
const uint16_t vid_unswapped = vid_pid[0].hex_to_int();
1951
const uint16_t pid_unswapped = vid_pid[1].hex_to_int();
1952
const uint16_t vid = BSWAP16(vid_unswapped);
1953
const uint16_t pid = BSWAP16(pid_unswapped);
1954
1955
uint32_t full_id = (((uint32_t)vid) << 16) | ((uint16_t)pid);
1956
ignored_device_ids.insert(full_id);
1957
}
1958
}
1959
1960
legacy_just_pressed_behavior = GLOBAL_DEF("input_devices/compatibility/legacy_just_pressed_behavior", false);
1961
if (Engine::get_singleton()->is_editor_hint()) {
1962
// Always use standard behavior in the editor.
1963
legacy_just_pressed_behavior = false;
1964
}
1965
1966
accelerometer_enabled = GLOBAL_DEF_RST_BASIC("input_devices/sensors/enable_accelerometer", false);
1967
gravity_enabled = GLOBAL_DEF_RST_BASIC("input_devices/sensors/enable_gravity", false);
1968
gyroscope_enabled = GLOBAL_DEF_RST_BASIC("input_devices/sensors/enable_gyroscope", false);
1969
magnetometer_enabled = GLOBAL_DEF_RST_BASIC("input_devices/sensors/enable_magnetometer", false);
1970
}
1971
1972
Input::~Input() {
1973
singleton = nullptr;
1974
}
1975
1976
//////////////////////////////////////////////////////////
1977
1978