Add ios virtual controller support.
This commit is contained in:
parent
506d6e427a
commit
6e765250e3
|
@ -149,11 +149,32 @@ void Input::_bind_methods() {
|
|||
ClassDB::bind_method(D_METHOD("is_emulating_mouse_from_touch"), &Input::is_emulating_mouse_from_touch);
|
||||
ClassDB::bind_method(D_METHOD("set_emulate_touch_from_mouse", "enable"), &Input::set_emulate_touch_from_mouse);
|
||||
ClassDB::bind_method(D_METHOD("is_emulating_touch_from_mouse"), &Input::is_emulating_touch_from_mouse);
|
||||
ClassDB::bind_method(D_METHOD("set_enable_ios_virtual_control", "enable"), &Input::set_enable_ios_virtual_control);
|
||||
ClassDB::bind_method(D_METHOD("is_enable_ios_virtual_control"), &Input::is_enable_ios_virtual_control);
|
||||
ClassDB::bind_method(D_METHOD("set_enable_left_thumbstick", "enable"), &Input::set_enable_left_thumbstick);
|
||||
ClassDB::bind_method(D_METHOD("is_enable_left_thumbstick"), &Input::is_enable_left_thumbstick);
|
||||
ClassDB::bind_method(D_METHOD("set_enable_right_thumbstick", "enable"), &Input::set_enable_right_thumbstick);
|
||||
ClassDB::bind_method(D_METHOD("is_enable_right_thumbstick"), &Input::is_enable_right_thumbstick);
|
||||
ClassDB::bind_method(D_METHOD("set_enable_button_a", "enable"), &Input::set_enable_button_a);
|
||||
ClassDB::bind_method(D_METHOD("is_enable_button_a"), &Input::is_enable_button_a);
|
||||
ClassDB::bind_method(D_METHOD("set_enable_button_b", "enable"), &Input::set_enable_button_b);
|
||||
ClassDB::bind_method(D_METHOD("is_enable_button_b"), &Input::is_enable_button_b);
|
||||
ClassDB::bind_method(D_METHOD("set_enable_button_x", "enable"), &Input::set_enable_button_x);
|
||||
ClassDB::bind_method(D_METHOD("is_enable_button_x"), &Input::is_enable_button_x);
|
||||
ClassDB::bind_method(D_METHOD("set_enable_button_y", "enable"), &Input::set_enable_button_y);
|
||||
ClassDB::bind_method(D_METHOD("is_enable_button_y"), &Input::is_enable_button_y);
|
||||
|
||||
ADD_PROPERTY(PropertyInfo(Variant::INT, "mouse_mode"), "set_mouse_mode", "get_mouse_mode");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_accumulated_input"), "set_use_accumulated_input", "is_using_accumulated_input");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "emulate_mouse_from_touch"), "set_emulate_mouse_from_touch", "is_emulating_mouse_from_touch");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "emulate_touch_from_mouse"), "set_emulate_touch_from_mouse", "is_emulating_touch_from_mouse");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "enable_ios_virtual_control"), "set_enable_ios_virtual_control", "is_enable_ios_virtual_control");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "enable_left_thumbstick"), "set_enable_left_thumbstick", "is_enable_left_thumbstick");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "enable_right_thumbstick"), "set_enable_right_thumbstick", "is_enable_right_thumbstick");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "enable_button_a"), "set_enable_button_a", "is_enable_button_a");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "enable_button_b"), "set_enable_button_b", "is_enable_button_b");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "enable_button_x"), "set_enable_button_x", "is_enable_button_x");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "enable_button_y"), "set_enable_button_y", "is_enable_button_y");
|
||||
|
||||
BIND_ENUM_CONSTANT(MOUSE_MODE_VISIBLE);
|
||||
BIND_ENUM_CONSTANT(MOUSE_MODE_HIDDEN);
|
||||
|
@ -954,6 +975,62 @@ bool Input::is_emulating_touch_from_mouse() const {
|
|||
return emulate_touch_from_mouse;
|
||||
}
|
||||
|
||||
void Input::set_enable_ios_virtual_control(bool p_enable) {
|
||||
enable_ios_virtual_control = p_enable;
|
||||
}
|
||||
|
||||
bool Input::is_enable_ios_virtual_control() const {
|
||||
return enable_ios_virtual_control;
|
||||
}
|
||||
|
||||
void Input::set_enable_left_thumbstick(bool p_enable) {
|
||||
enable_left_thumbstick = p_enable;
|
||||
}
|
||||
|
||||
bool Input::is_enable_left_thumbstick() const {
|
||||
return enable_left_thumbstick;
|
||||
}
|
||||
|
||||
void Input::set_enable_right_thumbstick(bool p_enable) {
|
||||
enable_right_thumbstick = p_enable;
|
||||
}
|
||||
|
||||
bool Input::is_enable_right_thumbstick() const {
|
||||
return enable_right_thumbstick;
|
||||
}
|
||||
|
||||
void Input::set_enable_button_a(bool p_enable) {
|
||||
enable_button_a = p_enable;
|
||||
}
|
||||
|
||||
bool Input::is_enable_button_a() const {
|
||||
return enable_button_a;
|
||||
}
|
||||
|
||||
void Input::set_enable_button_b(bool p_enable) {
|
||||
enable_button_b = p_enable;
|
||||
}
|
||||
|
||||
bool Input::is_enable_button_b() const {
|
||||
return enable_button_b;
|
||||
}
|
||||
|
||||
void Input::set_enable_button_x(bool p_enable) {
|
||||
enable_button_x = p_enable;
|
||||
}
|
||||
|
||||
bool Input::is_enable_button_x() const {
|
||||
return enable_button_x;
|
||||
}
|
||||
|
||||
void Input::set_enable_button_y(bool p_enable) {
|
||||
enable_button_y = p_enable;
|
||||
}
|
||||
|
||||
bool Input::is_enable_button_y() const {
|
||||
return enable_button_y;
|
||||
}
|
||||
|
||||
// Calling this whenever the game window is focused helps unsticking the "touch mouse"
|
||||
// if the OS or its abstraction class hasn't properly reported that touch pointers raised
|
||||
void Input::ensure_touch_mouse_raised() {
|
||||
|
|
|
@ -135,6 +135,14 @@ private:
|
|||
bool agile_input_event_flushing = false;
|
||||
bool use_accumulated_input = true;
|
||||
|
||||
bool enable_ios_virtual_control = false;
|
||||
bool enable_left_thumbstick;
|
||||
bool enable_right_thumbstick;
|
||||
bool enable_button_a;
|
||||
bool enable_button_b;
|
||||
bool enable_button_x;
|
||||
bool enable_button_y;
|
||||
|
||||
int mouse_from_touch_index = -1;
|
||||
|
||||
struct VibrationInfo {
|
||||
|
@ -376,6 +384,21 @@ public:
|
|||
void set_use_accumulated_input(bool p_enable);
|
||||
bool is_using_accumulated_input();
|
||||
|
||||
void set_enable_ios_virtual_control(bool p_enable);
|
||||
bool is_enable_ios_virtual_control() const;
|
||||
void set_enable_left_thumbstick(bool p_enable);
|
||||
bool is_enable_left_thumbstick() const;
|
||||
void set_enable_right_thumbstick(bool p_enable);
|
||||
bool is_enable_right_thumbstick() const;
|
||||
void set_enable_button_a(bool p_enable);
|
||||
bool is_enable_button_a() const;
|
||||
void set_enable_button_b(bool p_enable);
|
||||
bool is_enable_button_b() const;
|
||||
void set_enable_button_x(bool p_enable);
|
||||
bool is_enable_button_x() const;
|
||||
void set_enable_button_y(bool p_enable);
|
||||
bool is_enable_button_y() const;
|
||||
|
||||
void release_pressed_events();
|
||||
|
||||
void set_event_dispatch_function(EventDispatchFunc p_function);
|
||||
|
|
|
@ -425,6 +425,20 @@
|
|||
<member name="emulate_touch_from_mouse" type="bool" setter="set_emulate_touch_from_mouse" getter="is_emulating_touch_from_mouse">
|
||||
If [code]true[/code], sends touch input events when clicking or dragging the mouse. See also [member ProjectSettings.input_devices/pointing/emulate_touch_from_mouse].
|
||||
</member>
|
||||
<member name="enable_button_a" type="bool" setter="set_enable_button_a" getter="is_enable_button_a">
|
||||
</member>
|
||||
<member name="enable_button_b" type="bool" setter="set_enable_button_b" getter="is_enable_button_b">
|
||||
</member>
|
||||
<member name="enable_button_x" type="bool" setter="set_enable_button_x" getter="is_enable_button_x">
|
||||
</member>
|
||||
<member name="enable_button_y" type="bool" setter="set_enable_button_y" getter="is_enable_button_y">
|
||||
</member>
|
||||
<member name="enable_ios_virtual_control" type="bool" setter="set_enable_ios_virtual_control" getter="is_enable_ios_virtual_control">
|
||||
</member>
|
||||
<member name="enable_left_thumbstick" type="bool" setter="set_enable_left_thumbstick" getter="is_enable_left_thumbstick">
|
||||
</member>
|
||||
<member name="enable_right_thumbstick" type="bool" setter="set_enable_right_thumbstick" getter="is_enable_right_thumbstick">
|
||||
</member>
|
||||
<member name="mouse_mode" type="int" setter="set_mouse_mode" getter="get_mouse_mode" enum="Input.MouseMode">
|
||||
Controls the mouse mode. See [enum MouseMode] for more information.
|
||||
</member>
|
||||
|
|
|
@ -1405,6 +1405,20 @@
|
|||
If [code]false[/code], no input will be lost.
|
||||
[b]Note:[/b] You should in nearly all cases prefer the [code]false[/code] setting. The legacy behavior is to enable supporting old projects that rely on the old logic, without changes to script.
|
||||
</member>
|
||||
<member name="input_devices/controllers/ios/enable_button_a" type="bool" setter="" getter="" default="true">
|
||||
</member>
|
||||
<member name="input_devices/controllers/ios/enable_button_b" type="bool" setter="" getter="" default="true">
|
||||
</member>
|
||||
<member name="input_devices/controllers/ios/enable_button_x" type="bool" setter="" getter="" default="true">
|
||||
</member>
|
||||
<member name="input_devices/controllers/ios/enable_button_y" type="bool" setter="" getter="" default="true">
|
||||
</member>
|
||||
<member name="input_devices/controllers/ios/enable_ios_virtual_control" type="bool" setter="" getter="" default="false">
|
||||
</member>
|
||||
<member name="input_devices/controllers/ios/enable_left_thumbstick" type="bool" setter="" getter="" default="true">
|
||||
</member>
|
||||
<member name="input_devices/controllers/ios/enable_right_thumbstick" type="bool" setter="" getter="" default="true">
|
||||
</member>
|
||||
<member name="input_devices/pen_tablet/driver" type="String" setter="" getter="">
|
||||
Specifies the tablet driver to use. If left empty, the default driver will be used.
|
||||
[b]Note:[/b] The driver in use can be overridden at runtime via the [code]--tablet-driver[/code] [url=$DOCS_URL/tutorials/editor/command_line_tutorial.html]command line argument[/url].
|
||||
|
|
|
@ -3191,6 +3191,13 @@ Error Main::setup2(bool p_show_boot_logo) {
|
|||
}
|
||||
|
||||
id->set_emulate_mouse_from_touch(bool(GLOBAL_DEF_BASIC("input_devices/pointing/emulate_mouse_from_touch", true)));
|
||||
id->set_enable_ios_virtual_control(bool(GLOBAL_DEF_BASIC("input_devices/controllers/ios/enable_ios_virtual_control", false)));
|
||||
id->set_enable_left_thumbstick(bool(GLOBAL_DEF_BASIC("input_devices/controllers/ios/enable_left_thumbstick", true)));
|
||||
id->set_enable_right_thumbstick(bool(GLOBAL_DEF_BASIC("input_devices/controllers/ios/enable_right_thumbstick", true)));
|
||||
id->set_enable_button_a(bool(GLOBAL_DEF_BASIC("input_devices/controllers/ios/enable_button_a", true)));
|
||||
id->set_enable_button_b(bool(GLOBAL_DEF_BASIC("input_devices/controllers/ios/enable_button_b", true)));
|
||||
id->set_enable_button_x(bool(GLOBAL_DEF_BASIC("input_devices/controllers/ios/enable_button_x", true)));
|
||||
id->set_enable_button_y(bool(GLOBAL_DEF_BASIC("input_devices/controllers/ios/enable_button_y", true)));
|
||||
}
|
||||
|
||||
OS::get_singleton()->benchmark_end_measure("Startup", "Setup Window and Boot");
|
||||
|
|
|
@ -78,6 +78,7 @@ ios_lib = [
|
|||
"keyboard_input_view.mm",
|
||||
"key_mapping_ios.mm",
|
||||
"ios_terminal_logger.mm",
|
||||
"virtual_controller.mm",
|
||||
]
|
||||
|
||||
env_ios = env.Clone()
|
||||
|
|
|
@ -184,6 +184,8 @@ void JoypadIOS::start_processing() {
|
|||
} else {
|
||||
[self addiOSJoypad:controller];
|
||||
}
|
||||
|
||||
OS_IOS::get_singleton()->controller_connected();
|
||||
}
|
||||
|
||||
- (void)controllerWasDisconnected:(NSNotification *)notification {
|
||||
|
@ -203,6 +205,8 @@ void JoypadIOS::start_processing() {
|
|||
// and remove it from our dictionary
|
||||
[self.connectedJoypads removeObjectForKey:key];
|
||||
}
|
||||
|
||||
OS_IOS::get_singleton()->controller_disconnected();
|
||||
}
|
||||
|
||||
- (GCControllerPlayerIndex)getFreePlayerIndex {
|
||||
|
|
|
@ -35,6 +35,7 @@
|
|||
|
||||
#import "ios.h"
|
||||
#import "joypad_ios.h"
|
||||
#import "virtual_controller.h"
|
||||
|
||||
#import "drivers/coreaudio/audio_driver_coreaudio.h"
|
||||
#include "drivers/unix/os_unix.h"
|
||||
|
@ -62,6 +63,8 @@ private:
|
|||
|
||||
MainLoop *main_loop = nullptr;
|
||||
|
||||
VirtualController *virtual_controller = nullptr;
|
||||
|
||||
virtual void initialize_core() override;
|
||||
virtual void initialize() override;
|
||||
|
||||
|
@ -132,6 +135,10 @@ public:
|
|||
|
||||
void on_enter_background();
|
||||
void on_exit_background();
|
||||
|
||||
void controller_connected();
|
||||
|
||||
void controller_disconnected();
|
||||
};
|
||||
|
||||
#endif // IOS_ENABLED
|
||||
|
|
|
@ -135,9 +135,16 @@ void OS_IOS::initialize_modules() {
|
|||
Engine::get_singleton()->add_singleton(Engine::Singleton("iOS", ios));
|
||||
|
||||
joypad_ios = memnew(JoypadIOS);
|
||||
|
||||
virtual_controller = memnew(VirtualController);
|
||||
}
|
||||
|
||||
void OS_IOS::deinitialize_modules() {
|
||||
if (virtual_controller) {
|
||||
virtual_controller->disconnect();
|
||||
memdelete(virtual_controller);
|
||||
}
|
||||
|
||||
if (joypad_ios) {
|
||||
memdelete(joypad_ios);
|
||||
}
|
||||
|
@ -184,6 +191,11 @@ void OS_IOS::start() {
|
|||
if (joypad_ios) {
|
||||
joypad_ios->start_processing();
|
||||
}
|
||||
|
||||
if (virtual_controller) {
|
||||
virtual_controller->initialize();
|
||||
virtual_controller->connect();
|
||||
}
|
||||
}
|
||||
|
||||
void OS_IOS::finalize() {
|
||||
|
@ -651,4 +663,16 @@ void OS_IOS::on_exit_background() {
|
|||
}
|
||||
}
|
||||
|
||||
void OS_IOS::controller_connected() {
|
||||
if (virtual_controller) {
|
||||
virtual_controller->controller_connected();
|
||||
}
|
||||
}
|
||||
|
||||
void OS_IOS::controller_disconnected() {
|
||||
if (virtual_controller) {
|
||||
virtual_controller->controller_disconnected();
|
||||
}
|
||||
}
|
||||
|
||||
#endif // IOS_ENABLED
|
||||
|
|
|
@ -0,0 +1,49 @@
|
|||
/**************************************************************************/
|
||||
/* virtual_controller.h */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#import <GameController/GameController.h>
|
||||
|
||||
class VirtualController {
|
||||
private:
|
||||
#if defined(__IPHONE_15_0)
|
||||
API_AVAILABLE(ios(15.0))
|
||||
GCVirtualController *gcv_controller;
|
||||
#endif
|
||||
|
||||
public:
|
||||
VirtualController();
|
||||
~VirtualController();
|
||||
|
||||
void initialize();
|
||||
void connect();
|
||||
void disconnect();
|
||||
void controller_connected();
|
||||
void controller_disconnected();
|
||||
};
|
|
@ -0,0 +1,115 @@
|
|||
/**************************************************************************/
|
||||
/* virtual_controller.mm */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#import "virtual_controller.h"
|
||||
#include "core/input/input.h"
|
||||
|
||||
VirtualController::VirtualController() {
|
||||
}
|
||||
|
||||
VirtualController::~VirtualController() {
|
||||
if (@available(iOS 15.0, *)) {
|
||||
gcv_controller = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void VirtualController::initialize() {
|
||||
if (@available(iOS 15.0, *)) {
|
||||
if (!gcv_controller) {
|
||||
GCVirtualControllerConfiguration *config = [[GCVirtualControllerConfiguration alloc] init];
|
||||
|
||||
NSMutableSet *elements = [[NSMutableSet alloc] init];
|
||||
|
||||
Input *input = Input::get_singleton();
|
||||
|
||||
if (input->is_enable_left_thumbstick()) {
|
||||
[elements addObject:GCInputLeftThumbstick];
|
||||
}
|
||||
if (input->is_enable_right_thumbstick()) {
|
||||
[elements addObject:GCInputRightThumbstick];
|
||||
}
|
||||
if (input->is_enable_button_a()) {
|
||||
[elements addObject:GCInputButtonA];
|
||||
}
|
||||
if (input->is_enable_button_b()) {
|
||||
[elements addObject:GCInputButtonB];
|
||||
}
|
||||
if (input->is_enable_button_x()) {
|
||||
[elements addObject:GCInputButtonX];
|
||||
}
|
||||
if (input->is_enable_button_y()) {
|
||||
[elements addObject:GCInputButtonY];
|
||||
}
|
||||
|
||||
config.elements = elements;
|
||||
gcv_controller = [[GCVirtualController alloc] initWithConfiguration:config];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void VirtualController::connect() {
|
||||
if (!Input::get_singleton()->is_enable_ios_virtual_control()) {
|
||||
return;
|
||||
}
|
||||
if (@available(iOS 15.0, *)) {
|
||||
if (GCController.controllers.count == 0 && gcv_controller != nil) {
|
||||
[gcv_controller connectWithReplyHandler:nil];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void VirtualController::disconnect() {
|
||||
if (@available(iOS 15.0, *)) {
|
||||
if (gcv_controller) {
|
||||
[gcv_controller disconnect];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void VirtualController::controller_connected() {
|
||||
if (@available(iOS 15.0, *)) {
|
||||
if (gcv_controller != nil) {
|
||||
BOOL hasPhysicalController = NO;
|
||||
for (GCController *controller in GCController.controllers) {
|
||||
if (controller != gcv_controller.controller) {
|
||||
hasPhysicalController = YES;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (hasPhysicalController) {
|
||||
disconnect();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void VirtualController::controller_disconnected() {
|
||||
connect();
|
||||
}
|
Loading…
Reference in New Issue