Skip to content

Commit 7903c5f

Browse files
committed
Add ios virtual controller support.
1 parent 1bffd6c commit 7903c5f

17 files changed

+641
-0
lines changed

core/config/project_settings.cpp

+7
Original file line numberDiff line numberDiff line change
@@ -1576,6 +1576,13 @@ ProjectSettings::ProjectSettings() {
15761576
GLOBAL_DEF_BASIC("input_devices/pointing/android/enable_long_press_as_right_click", false);
15771577
GLOBAL_DEF_BASIC("input_devices/pointing/android/enable_pan_and_scale_gestures", false);
15781578
GLOBAL_DEF_BASIC(PropertyInfo(Variant::INT, "input_devices/pointing/android/rotary_input_scroll_axis", PROPERTY_HINT_ENUM, "Horizontal,Vertical"), 1);
1579+
GLOBAL_DEF_BASIC("input_devices/virtual_controller/ios/enable_controller", false);
1580+
GLOBAL_DEF_BASIC("input_devices/virtual_controller/ios/enable_left_thumbstick", true);
1581+
GLOBAL_DEF_BASIC("input_devices/virtual_controller/ios/enable_right_thumbstick", true);
1582+
GLOBAL_DEF_BASIC("input_devices/virtual_controller/ios/enable_button_a", true);
1583+
GLOBAL_DEF_BASIC("input_devices/virtual_controller/ios/enable_button_b", true);
1584+
GLOBAL_DEF_BASIC("input_devices/virtual_controller/ios/enable_button_x", true);
1585+
GLOBAL_DEF_BASIC("input_devices/virtual_controller/ios/enable_button_y", true);
15791586

15801587
// These properties will not show up in the dialog. If you want to exclude whole groups, use add_hidden_prefix().
15811588
GLOBAL_DEF_INTERNAL("application/config/features", PackedStringArray());

core/input/input.cpp

+5
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,7 @@ void Input::_bind_methods() {
188188
ClassDB::bind_method(D_METHOD("is_emulating_mouse_from_touch"), &Input::is_emulating_mouse_from_touch);
189189
ClassDB::bind_method(D_METHOD("set_emulate_touch_from_mouse", "enable"), &Input::set_emulate_touch_from_mouse);
190190
ClassDB::bind_method(D_METHOD("is_emulating_touch_from_mouse"), &Input::is_emulating_touch_from_mouse);
191+
ClassDB::bind_method(D_METHOD("get_virtual_controller"), &Input::get_virtual_controller);
191192

192193
ADD_PROPERTY(PropertyInfo(Variant::INT, "mouse_mode"), "set_mouse_mode", "get_mouse_mode");
193194
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_accumulated_input"), "set_use_accumulated_input", "is_using_accumulated_input");
@@ -1054,6 +1055,10 @@ bool Input::is_emulating_touch_from_mouse() const {
10541055
return emulate_touch_from_mouse;
10551056
}
10561057

1058+
VirtualController *Input::get_virtual_controller() {
1059+
return OS::get_singleton()->get_virtual_controller();
1060+
}
1061+
10571062
// Calling this whenever the game window is focused helps unsticking the "touch mouse"
10581063
// if the OS or its abstraction class hasn't properly reported that touch pointers raised
10591064
void Input::ensure_touch_mouse_raised() {

core/input/input.h

+3
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
#define INPUT_H
3333

3434
#include "core/input/input_event.h"
35+
#include "core/input/virtual_controller.h"
3536
#include "core/object/object.h"
3637
#include "core/os/keyboard.h"
3738
#include "core/os/thread_safe.h"
@@ -383,6 +384,8 @@ class Input : public Object {
383384
void set_use_accumulated_input(bool p_enable);
384385
bool is_using_accumulated_input();
385386

387+
VirtualController *get_virtual_controller();
388+
386389
void release_pressed_events();
387390

388391
void set_event_dispatch_function(EventDispatchFunc p_function);

core/input/virtual_controller.cpp

+49
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
/**************************************************************************/
2+
/* virtual_controller.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 "virtual_controller.h"
32+
33+
void VirtualController::_bind_methods() {
34+
ClassDB::bind_method(D_METHOD("enable"), &VirtualController::enable);
35+
ClassDB::bind_method(D_METHOD("disable"), &VirtualController::disable);
36+
ClassDB::bind_method(D_METHOD("is_enabled"), &VirtualController::is_enabled);
37+
ClassDB::bind_method(D_METHOD("set_enabled_left_thumbstick", "enable"), &VirtualController::set_enabled_left_thumbstick);
38+
ClassDB::bind_method(D_METHOD("is_enabled_left_thumbstick"), &VirtualController::is_enabled_left_thumbstick);
39+
ClassDB::bind_method(D_METHOD("set_enabled_right_thumbstick", "enable"), &VirtualController::set_enabled_right_thumbstick);
40+
ClassDB::bind_method(D_METHOD("is_enabled_right_thumbstick"), &VirtualController::is_enabled_right_thumbstick);
41+
ClassDB::bind_method(D_METHOD("set_enabled_button_a", "enable"), &VirtualController::set_enabled_button_a);
42+
ClassDB::bind_method(D_METHOD("is_enabled_button_a"), &VirtualController::is_enabled_button_a);
43+
ClassDB::bind_method(D_METHOD("set_enabled_button_b", "enable"), &VirtualController::set_enabled_button_b);
44+
ClassDB::bind_method(D_METHOD("is_enabled_button_b"), &VirtualController::is_enabled_button_b);
45+
ClassDB::bind_method(D_METHOD("set_enabled_button_x", "enable"), &VirtualController::set_enabled_button_x);
46+
ClassDB::bind_method(D_METHOD("is_enabled_button_x"), &VirtualController::is_enabled_button_x);
47+
ClassDB::bind_method(D_METHOD("set_enabled_button_y", "enable"), &VirtualController::set_enabled_button_y);
48+
ClassDB::bind_method(D_METHOD("is_enabled_button_y"), &VirtualController::is_enabled_button_y);
49+
}

core/input/virtual_controller.h

+60
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
/**************************************************************************/
2+
/* virtual_controller.h */
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+
#ifndef VIRTUAL_CONTROLLER_H
32+
#define VIRTUAL_CONTROLLER_H
33+
34+
#include "core/object/class_db.h"
35+
36+
class VirtualController : public Object {
37+
GDCLASS(VirtualController, Object);
38+
39+
protected:
40+
static void _bind_methods();
41+
42+
public:
43+
virtual void enable() = 0;
44+
virtual void disable() = 0;
45+
virtual bool is_enabled() = 0;
46+
virtual void set_enabled_left_thumbstick(bool p_enabled) = 0;
47+
virtual bool is_enabled_left_thumbstick() = 0;
48+
virtual void set_enabled_right_thumbstick(bool p_enabled) = 0;
49+
virtual bool is_enabled_right_thumbstick() = 0;
50+
virtual void set_enabled_button_a(bool p_enabled) = 0;
51+
virtual bool is_enabled_button_a() = 0;
52+
virtual void set_enabled_button_b(bool p_enabled) = 0;
53+
virtual bool is_enabled_button_b() = 0;
54+
virtual void set_enabled_button_x(bool p_enabled) = 0;
55+
virtual bool is_enabled_button_x() = 0;
56+
virtual void set_enabled_button_y(bool p_enabled) = 0;
57+
virtual bool is_enabled_button_y() = 0;
58+
};
59+
60+
#endif // VIRTUAL_CONTROLLER_H

core/os/os.cpp

+4
Original file line numberDiff line numberDiff line change
@@ -700,6 +700,10 @@ void OS::benchmark_dump() {
700700
#endif
701701
}
702702

703+
VirtualController *OS::get_virtual_controller() const {
704+
return nullptr;
705+
}
706+
703707
OS::OS() {
704708
singleton = this;
705709

core/os/os.h

+3
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
#define OS_H
3333

3434
#include "core/config/engine.h"
35+
#include "core/input/virtual_controller.h"
3536
#include "core/io/logger.h"
3637
#include "core/io/remote_filesystem_client.h"
3738
#include "core/os/time_enums.h"
@@ -344,6 +345,8 @@ class OS {
344345
// This is invoked by the GDExtensionManager after loading GDExtensions specified by the project.
345346
virtual void load_platform_gdextensions() const {}
346347

348+
virtual VirtualController *get_virtual_controller() const;
349+
347350
OS();
348351
virtual ~OS();
349352
};

core/register_core_types.cpp

+3
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
#include "core/input/input.h"
4343
#include "core/input/input_map.h"
4444
#include "core/input/shortcut.h"
45+
#include "core/input/virtual_controller.h"
4546
#include "core/io/config_file.h"
4647
#include "core/io/dir_access.h"
4748
#include "core/io/dtls_server.h"
@@ -298,6 +299,8 @@ void register_core_types() {
298299
GDREGISTER_NATIVE_STRUCT(AudioFrame, "float left;float right");
299300
GDREGISTER_NATIVE_STRUCT(ScriptLanguageExtensionProfilingInfo, "StringName signature;uint64_t call_count;uint64_t total_time;uint64_t self_time");
300301

302+
GDREGISTER_ABSTRACT_CLASS(VirtualController);
303+
301304
worker_thread_pool = memnew(WorkerThreadPool);
302305

303306
OS::get_singleton()->benchmark_end_measure("Core", "Register Types");

doc/classes/Input.xml

+7
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,13 @@
195195
By default, the deadzone is automatically calculated from the average of the action deadzones. However, you can override the deadzone to be whatever you want (on the range of 0 to 1).
196196
</description>
197197
</method>
198+
<method name="get_virtual_controller">
199+
<return type="VirtualController" />
200+
<description>
201+
Return platform-specific virtual controller or null. (See [VirtualController])
202+
[b]Note:[/b] Currently implemented only on iOS 15.0+.
203+
</description>
204+
</method>
198205
<method name="is_action_just_pressed" qualifiers="const">
199206
<return type="bool" />
200207
<param index="0" name="action" type="StringName" />

doc/classes/ProjectSettings.xml

+22
Original file line numberDiff line numberDiff line change
@@ -1456,6 +1456,28 @@
14561456
<member name="input_devices/sensors/enable_magnetometer" type="bool" setter="" getter="" default="false">
14571457
If [code]true[/code], the magnetometer sensor is enabled and [method Input.get_magnetometer] returns valid data.
14581458
</member>
1459+
<member name="input_devices/virtual_controller/ios/enable_button_a" type="bool" setter="" getter="" default="true">
1460+
If [code]true[/code], the button "A" shows in the virtual controller.
1461+
</member>
1462+
<member name="input_devices/virtual_controller/ios/enable_button_b" type="bool" setter="" getter="" default="true">
1463+
If [code]true[/code], the button "B" shows in the virtual controller.
1464+
</member>
1465+
<member name="input_devices/virtual_controller/ios/enable_button_x" type="bool" setter="" getter="" default="true">
1466+
If [code]true[/code], the button "X" shows in the virtual controller.
1467+
</member>
1468+
<member name="input_devices/virtual_controller/ios/enable_button_y" type="bool" setter="" getter="" default="true">
1469+
If [code]true[/code], the button "Y" shows in the virtual controller.
1470+
</member>
1471+
<member name="input_devices/virtual_controller/ios/enable_controller" type="bool" setter="" getter="" default="false">
1472+
If [code]true[/code], if there are no physical controllers connected, the game shows the virtual controller.
1473+
[b]Note:[/b] Currently implemented only on iOS 15.0+.
1474+
</member>
1475+
<member name="input_devices/virtual_controller/ios/enable_left_thumbstick" type="bool" setter="" getter="" default="true">
1476+
If [code]true[/code], the left thumbstick shows in the virtual controller.
1477+
</member>
1478+
<member name="input_devices/virtual_controller/ios/enable_right_thumbstick" type="bool" setter="" getter="" default="true">
1479+
If [code]true[/code], the right thumbstick shows in the virtual controller.
1480+
</member>
14591481
<member name="internationalization/locale/fallback" type="String" setter="" getter="" default="&quot;en&quot;">
14601482
The locale to fall back to if a translation isn't available in a given language. If left empty, [code]en[/code] (English) will be used.
14611483
</member>

doc/classes/VirtualController.xml

+112
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
<?xml version="1.0" encoding="UTF-8" ?>
2+
<class name="VirtualController" inherits="Object" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
3+
<brief_description>
4+
A software emulation of a real controller that you configure specifically for your game.
5+
</brief_description>
6+
<description>
7+
Use a virtual controller to display software controls that you can customize over your game.
8+
You create a virtual controller from a configuration where you choose the input elements to display.
9+
When you connect the controller to the device, users interact with it similarly to a real controller.
10+
[b]Note:[/b] Currently implemented only on iOS 15.0+.
11+
</description>
12+
<tutorials>
13+
</tutorials>
14+
<methods>
15+
<method name="disable">
16+
<return type="void" />
17+
<description>
18+
Disconnects the virtual controller from the device and removes it from the screen.
19+
</description>
20+
</method>
21+
<method name="enable">
22+
<return type="void" />
23+
<description>
24+
If there are no physical controllers connected, connects the virtual controller to the device and displays it on the screen.
25+
</description>
26+
</method>
27+
<method name="is_enabled">
28+
<return type="bool" />
29+
<description>
30+
Returns [code]true[/code] if the virtual controller is enabled.
31+
</description>
32+
</method>
33+
<method name="is_enabled_button_a">
34+
<return type="bool" />
35+
<description>
36+
Returns [code]true[/code] if the button "A" is enabled.
37+
</description>
38+
</method>
39+
<method name="is_enabled_button_b">
40+
<return type="bool" />
41+
<description>
42+
Returns [code]true[/code] if the button "B" is enabled.
43+
</description>
44+
</method>
45+
<method name="is_enabled_button_x">
46+
<return type="bool" />
47+
<description>
48+
Returns [code]true[/code] if the button "X" is enabled.
49+
</description>
50+
</method>
51+
<method name="is_enabled_button_y">
52+
<return type="bool" />
53+
<description>
54+
Returns [code]true[/code] if the button "Y" is enabled.
55+
</description>
56+
</method>
57+
<method name="is_enabled_left_thumbstick">
58+
<return type="bool" />
59+
<description>
60+
Returns [code]true[/code] if the left thumbstick is enabled.
61+
</description>
62+
</method>
63+
<method name="is_enabled_right_thumbstick">
64+
<return type="bool" />
65+
<description>
66+
Returns [code]true[/code] if the right thumbstick is enabled.
67+
</description>
68+
</method>
69+
<method name="set_enabled_button_a">
70+
<return type="void" />
71+
<param index="0" name="enable" type="bool" />
72+
<description>
73+
Changes the visibility of a button "A" element. Default is [code]true[/code].
74+
</description>
75+
</method>
76+
<method name="set_enabled_button_b">
77+
<return type="void" />
78+
<param index="0" name="enable" type="bool" />
79+
<description>
80+
Changes the visibility of a button "B" element. Default is [code]true[/code].
81+
</description>
82+
</method>
83+
<method name="set_enabled_button_x">
84+
<return type="void" />
85+
<param index="0" name="enable" type="bool" />
86+
<description>
87+
Changes the visibility of a button "A" element. Default is [code]true[/code].
88+
</description>
89+
</method>
90+
<method name="set_enabled_button_y">
91+
<return type="void" />
92+
<param index="0" name="enable" type="bool" />
93+
<description>
94+
Changes the visibility of a button "Y" element. Default is [code]true[/code].
95+
</description>
96+
</method>
97+
<method name="set_enabled_left_thumbstick">
98+
<return type="void" />
99+
<param index="0" name="enable" type="bool" />
100+
<description>
101+
Changes the visibility of a left thumbstick element. Default is [code]true[/code].
102+
</description>
103+
</method>
104+
<method name="set_enabled_right_thumbstick">
105+
<return type="void" />
106+
<param index="0" name="enable" type="bool" />
107+
<description>
108+
Changes the visibility of a right thumbstick element. Default is [code]true[/code].
109+
</description>
110+
</method>
111+
</methods>
112+
</class>

platform/ios/SCsub

+1
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@ ios_lib = [
7878
"keyboard_input_view.mm",
7979
"key_mapping_ios.mm",
8080
"ios_terminal_logger.mm",
81+
"virtual_controller_ios.mm",
8182
]
8283

8384
env_ios = env.Clone()

platform/ios/joypad_ios.mm

+4
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,8 @@ - (void)controllerWasConnected:(NSNotification *)notification {
184184
} else {
185185
[self addiOSJoypad:controller];
186186
}
187+
188+
OS_IOS::get_singleton()->controller_connected();
187189
}
188190

189191
- (void)controllerWasDisconnected:(NSNotification *)notification {
@@ -203,6 +205,8 @@ - (void)controllerWasDisconnected:(NSNotification *)notification {
203205
// and remove it from our dictionary
204206
[self.connectedJoypads removeObjectForKey:key];
205207
}
208+
209+
OS_IOS::get_singleton()->controller_disconnected();
206210
}
207211

208212
- (GCControllerPlayerIndex)getFreePlayerIndex {

0 commit comments

Comments
 (0)