Skip to content

Commit

Permalink
[Switch] Create Switch API for virtual keyboards
Browse files Browse the repository at this point in the history
  • Loading branch information
halotroop2288 committed Jan 26, 2024
1 parent 009e003 commit 5eff1ee
Show file tree
Hide file tree
Showing 8 changed files with 369 additions and 66 deletions.
4 changes: 4 additions & 0 deletions doc/classes/@GlobalScope.xml
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,10 @@
<member name="NavigationServer" type="NavigationServer" setter="" getter="">
The [NavigationServer] singleton.
</member>
<member name="NintendoSwitch" type="NintendoSwitch" setter="" getter="">
The [NintendoSwitch] singleton.
[b]Note:[/b] Only implemented on Nintendo Switch.
</member>
<member name="OS" type="OS" setter="" getter="">
The [OS] singleton.
</member>
Expand Down
48 changes: 48 additions & 0 deletions doc/classes/NintendoSwitch.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="NintendoSwitch" inherits="Object" version="3.5" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Singleton that adds new functions specific to Nintendo Switch's Horizon OS.
</brief_description>
<description>
The NintendoSwitch singleton is implemented only in the Nintendo Switch export. It's used to access features that are only supported by Horizon OS.
</description>
<tutorials>
</tutorials>
<methods>
<method name="show_virtual_keyboard">
<return type="void" />
<argument index="0" name="existing_text" type="String" default="&quot;&quot;" />
<argument index="1" name="type" type="int" enum="NintendoSwitch.SoftwareKeyboardType" default="0" />
<description>
Shows the virtual keyboard of the type specified.
The [code]existing_text[/code] parameter is useful for implementing your own [LineEdit] or [TextEdit], as it tells the virtual keyboard what text has already been typed.
</description>
</method>
</methods>
<constants>
<constant name="NORMAL_KEYBOARD" value="0" enum="SoftwareKeyboardType">
Normal keyboard.
</constant>
<constant name="NUMPAD_KEYBOARD" value="1" enum="SoftwareKeyboardType">
Number pad.
</constant>
<constant name="QWERTY_KEYBOARD" value="2" enum="SoftwareKeyboardType">
QWERTY (and variants) keyboard only.
</constant>
<constant name="LATIN_KEYBOARD" value="4" enum="SoftwareKeyboardType">
All Latin like languages keyboard only (without CJK keyboard).
</constant>
<constant name="SIMPLIFIED_CHINESE_KEYBOARD" value="5" enum="SoftwareKeyboardType">
Chinese Simplified keyboard only.
</constant>
<constant name="TRADITIONAL_CHINESE_KEYBOARD" value="6" enum="SoftwareKeyboardType">
Chinese Traditional keyboard only.
</constant>
<constant name="KOREAN_KEYBOARD" value="7" enum="SoftwareKeyboardType">
Korean keyboard only.
</constant>
<constant name="ALL_LANGUAGES_KEYBOARD" value="8" enum="SoftwareKeyboardType">
All language keyboards.
</constant>
</constants>
</class>
2 changes: 1 addition & 1 deletion doc/classes/OS.xml
Original file line number Diff line number Diff line change
Expand Up @@ -1019,7 +1019,7 @@
Shows the virtual keyboard if the platform has one.
The [code]existing_text[/code] parameter is useful for implementing your own [LineEdit] or [TextEdit], as it tells the virtual keyboard what text has already been typed (the virtual keyboard uses it for auto-correct and predictions).
The [code]multiline[/code] parameter needs to be set to [code]true[/code] to be able to enter multiple lines of text, as in [TextEdit].
[b]Note:[/b] This method is implemented on Android, iOS and UWP.
[b]Note:[/b] This method is implemented on Android, iOS, UWP, Nintendo Switch, and PlayStation Vita.
</description>
</method>
</methods>
Expand Down
181 changes: 181 additions & 0 deletions platform/switch/api/api.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,181 @@
/**************************************************************************/
/* api.cpp */
/**************************************************************************/
/* 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. */
/**************************************************************************/

#include "api.h"
#ifdef HORIZON_ENABLED
#include "os_switch.h"
#endif // HORIZON_ENABLED
#include "switch_singleton.h"

#include "core/engine.h"
#include "core/os/keyboard.h"

// === === ===
// === API ===
// === === ===

static NintendoSwitch *switch_eval;

void register_switch_api() {
ClassDB::register_virtual_class<NintendoSwitch>();
switch_eval = memnew(NintendoSwitch);
Engine::get_singleton()->add_singleton(Engine::Singleton("NintendoSwitch", switch_eval));
}

void unregister_switch_api() {
memdelete(switch_eval);
}

// === === === === === === === === ===
// === Nintendo Switch Singleton ===
// === === === === === === === === ===

bool g_swkbd_open = false;

NintendoSwitch *NintendoSwitch::singleton = nullptr;

NintendoSwitch *NintendoSwitch::get_singleton() {
return singleton;
}

NintendoSwitch::NintendoSwitch() {
ERR_FAIL_COND_MSG(singleton != nullptr, "NintendoSwitch singleton already exists.");
singleton = this;
#ifdef HORIZON_ENABLED
swkbdInlineCreate(&inline_keyboard);
#endif // HORIZON_ENABLED
}

void NintendoSwitch::_bind_methods() {
ClassDB::bind_method(D_METHOD("show_virtual_keyboard", "existing_text", "type"), &NintendoSwitch::show_virtual_keyboard, DEFVAL(""), DEFVAL(NORMAL_KEYBOARD));

BIND_ENUM_CONSTANT(NORMAL_KEYBOARD)
BIND_ENUM_CONSTANT(NUMPAD_KEYBOARD)
BIND_ENUM_CONSTANT(QWERTY_KEYBOARD)
BIND_ENUM_CONSTANT(LATIN_KEYBOARD)
BIND_ENUM_CONSTANT(SIMPLIFIED_CHINESE_KEYBOARD)
BIND_ENUM_CONSTANT(TRADITIONAL_CHINESE_KEYBOARD)
BIND_ENUM_CONSTANT(KOREAN_KEYBOARD)
BIND_ENUM_CONSTANT(ALL_LANGUAGES_KEYBOARD)
}

#ifdef HORIZON_ENABLED
int g_eat_string_events = 0;

u32 last_length = 0;
void keyboard_string_changed_callback(const char *str, SwkbdChangedStringArg *arg) {
// Adjusted for NUL-terminator
u32 string_length = arg->stringLen + 3;

// We get a string changed event on appear, and another one on setting text.
if (g_eat_string_events) {
last_length = string_length;
g_eat_string_events--;
return;
}

if (string_length < last_length) {
OS_Switch::get_singleton()->key(KEY_BACKSPACE, true);
} else if (string_length > 0) {
OS_Switch::get_singleton()->key(str[string_length - 1], true);
}
last_length = string_length;
}

int last_cursor = 0;
void keyboard_moved_cursor_callback(const char *str, SwkbdMovedCursorArg *arg) {
if (arg->cursorPos < last_cursor) {
OS_Switch::get_singleton()->key(KEY_LEFT, true);
} else {
OS_Switch::get_singleton()->key(KEY_RIGHT, true);
}

last_cursor = arg->cursorPos;
}

void keyboard_decided_enter_callback(const char *str, SwkbdDecidedEnterArg *arg) {
OS_Switch::get_singleton()->key(KEY_ENTER, true);

g_swkbd_open = false;
}

void keyboard_decided_cancel_callback() {
g_swkbd_open = false;
}
#endif // HORIZON_ENABLED

void NintendoSwitch::initialize_software_keyboard() {
#ifdef HORIZON_ENABLED
swkbdInlineLaunchForLibraryApplet(&inline_keyboard, SwkbdInlineMode_AppletDisplay, 0);
swkbdInlineSetChangedStringCallback(&inline_keyboard, keyboard_string_changed_callback);
swkbdInlineSetMovedCursorCallback(&inline_keyboard, keyboard_moved_cursor_callback);
swkbdInlineSetDecidedEnterCallback(&inline_keyboard, keyboard_decided_enter_callback);
swkbdInlineSetDecidedCancelCallback(&inline_keyboard, keyboard_decided_cancel_callback);
#endif // HORIZON_ENABLED
}

void NintendoSwitch::update() {
#ifdef HORIZON_ENABLED
swkbdInlineUpdate(&inline_keyboard, NULL);
#endif // HORIZON_ENABLED
}

void NintendoSwitch::show_virtual_keyboard(const String &p_existing_text, SoftwareKeyboardType p_type) {
#ifdef HORIZON_ENABLED
if (!g_swkbd_open) {
SwkbdAppearArg appear_arg;
swkbdInlineMakeAppearArg(&appear_arg, (SwkbdType)p_type);
swkbdInlineSetInputText(&inline_keyboard, p_existing_text.utf8().get_data());
swkbdInlineSetCursorPos(&inline_keyboard, p_existing_text.size() - 1);

swkbdInlineAppear(&inline_keyboard, &appear_arg);

g_eat_string_events = 2;
g_swkbd_open = true;
}
#endif // HORIZON_ENABLED
}

void NintendoSwitch::hide_virtual_keyboard() {
#ifdef HORIZON_ENABLED
swkbdInlineDisappear(&inline_keyboard);
g_swkbd_open = false;
#endif // HORIZON_ENABLED
}

bool NintendoSwitch::is_virtual_keyboard_open() {
return g_swkbd_open;
}

void NintendoSwitch::cleanup() {
#ifdef HORIZON_ENABLED
swkbdInlineClose(&inline_keyboard);
#endif // HORIZON_ENABLED
}
41 changes: 41 additions & 0 deletions platform/switch/api/api.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
/**************************************************************************/
/* api.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. */
/**************************************************************************/

#ifndef SWITCH_API_H
#define SWITCH_API_H

#ifndef MODULE_MONO_ENABLED

void register_switch_api();
void unregister_switch_api();

#endif // MODULE_MONO_ENABLED`

#endif // SWITCH_API_H
85 changes: 85 additions & 0 deletions platform/switch/api/switch_singleton.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
/**************************************************************************/
/* switch_singleton.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. */
/**************************************************************************/

#ifndef SWITCH_SINGLETON_H
#define SWITCH_SINGLETON_H

#ifndef MODULE_MONO_ENABLED

#include "core/object.h"
#include "core/variant.h"
#ifdef HORIZON_ENABLED
#include "switch_wrapper.h"
#endif // HORIZON_ENABLED

class NintendoSwitch : public Object {
GDCLASS(NintendoSwitch, Object);

public:
enum SoftwareKeyboardType {
NORMAL_KEYBOARD = 0,
NUMPAD_KEYBOARD = 1,
QWERTY_KEYBOARD = 2,
LATIN_KEYBOARD = 4,
SIMPLIFIED_CHINESE_KEYBOARD = 5,
TRADITIONAL_CHINESE_KEYBOARD = 6,
KOREAN_KEYBOARD = 7,
ALL_LANGUAGES_KEYBOARD = 8,
};

int g_eat_string_events = 0;
#ifdef HORIZON_ENABLED
SwkbdInline inline_keyboard;
#endif // HORIZON_ENABLED

protected:
static NintendoSwitch *singleton;

static void _bind_methods();

public:
static NintendoSwitch *get_singleton();

void initialize_software_keyboard();
void update();
void show_virtual_keyboard(const String &p_existing_text, SoftwareKeyboardType p_type);
void hide_virtual_keyboard();
bool is_virtual_keyboard_open();

void cleanup();

NintendoSwitch();
};

VARIANT_ENUM_CAST(NintendoSwitch::SoftwareKeyboardType);

#endif // MODULE_MONO_ENABLED

#endif // SWITCH_SINGLETON_H
Loading

0 comments on commit 5eff1ee

Please sign in to comment.