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