diff --git a/Makefile b/Makefile index d8312d4..2bbe6cb 100644 --- a/Makefile +++ b/Makefile @@ -33,7 +33,8 @@ include $(DEVKITPRO)/libnx/switch_rules TARGET := JKSV BUILD := build SOURCES := source source/appstates source/config source/curl source/data source/fs \ - source/logging source/remote source/strings source/sys source/tasks source/ui + source/keyboard source/logging source/remote source/strings source/sys \ + source/tasks source/ui DATA := data INCLUDES := include ./Libraries/FsLib/Switch/FsLib/include ./Libraries/SDLLib/SDL/include EXEFS_SRC := exefs_src diff --git a/include/keyboard/Dictionary.hpp b/include/keyboard/Dictionary.hpp new file mode 100644 index 0000000..715e36f --- /dev/null +++ b/include/keyboard/Dictionary.hpp @@ -0,0 +1,45 @@ +#pragma once +#include +#include +#include +#include + +namespace keyboard +{ + class Dictionary final + { + public: + /// @brief Length of the words. + static constexpr size_t WORD_LENGTH = 0x19; + + // clang-format off + struct Word + { + /// @brief Need to confirm, but I'm pretty sure this is what the system uses to predict? + char16_t predict[WORD_LENGTH]{}; + + /// @brief This is the actual word. + char16_t word[WORD_LENGTH]{}; + }; + // clang-format on + + /// @brief Default constructor. + Dictionary() = default; + + /// @brief Constructs a new dictionary using the list passed. + Dictionary(std::initializer_list wordList); + + /// @brief Adds the list to the internal list. + void add_list(std::initializer_list wordList); + + /// @brief Returns the number of words in the internal list. + size_t get_count() const noexcept; + + /// @brief Returns the pointer to the internal word vector data. + const Dictionary::Word *get_words() const noexcept; + + private: + /// @brief Vector of words. + std::vector m_words{}; + }; +} \ No newline at end of file diff --git a/include/keyboard.hpp b/include/keyboard/keyboard.hpp similarity index 72% rename from include/keyboard.hpp rename to include/keyboard/keyboard.hpp index da79338..e1e5938 100644 --- a/include/keyboard.hpp +++ b/include/keyboard/keyboard.hpp @@ -1,4 +1,7 @@ #pragma once +#include "keyboard/Dictionary.hpp" + +#include #include #include @@ -10,10 +13,12 @@ namespace keyboard /// @param header The header of the keyboard. /// @param stringOut Pointer to buffer to write to. /// @param stringLength Size of the buffer to write too. + /// @param dictionary Optional. Dictionary/words. /// @return True if input was successful and valid. False if it wasn't. bool get_input(SwkbdType keyboardType, std::string_view defaultText, std::string_view header, char *stringOut, - size_t stringLength); + size_t stringLength, + std::optional> dictionary = std::nullopt); } // namespace keyboard diff --git a/source/appstates/BackupMenuState.cpp b/source/appstates/BackupMenuState.cpp index 2d0c415..bee932b 100644 --- a/source/appstates/BackupMenuState.cpp +++ b/source/appstates/BackupMenuState.cpp @@ -10,7 +10,7 @@ #include "fslib.hpp" #include "graphics/colors.hpp" #include "input.hpp" -#include "keyboard.hpp" +#include "keyboard/keyboard.hpp" #include "sdl.hpp" #include "strings/strings.hpp" #include "stringutil.hpp" @@ -274,8 +274,19 @@ void BackupMenuState::name_and_create_backup() std::snprintf(name, SIZE_NAME_LENGTH, "%s - %s", nickname, date.c_str()); } + // Doing thing like this so the strings don't linger. + keyboard::Dictionary dictionary{}; + { + const std::string dateA = stringutil::get_date_string(); + const std::string dateB = stringutil::get_date_string(stringutil::DateFormat::YearDayMonth); + const std::string user = m_user->get_path_safe_nickname(); + + dictionary.add_list({dateA, dateB, user, ".zip"}); + } + const char *keyboardHeader = strings::get_by_name(strings::names::KEYBOARD, 0); - const bool named = autoNamed || keyboard::get_input(SwkbdType_QWERTY, name, keyboardHeader, name, SIZE_NAME_LENGTH); + const bool named = + autoNamed || keyboard::get_input(SwkbdType_QWERTY, name, keyboardHeader, name, SIZE_NAME_LENGTH, dictionary); if (!named) { return; } m_dataStruct->killTask = true; // Need to make sure these kill the task. diff --git a/source/appstates/ExtrasMenuState.cpp b/source/appstates/ExtrasMenuState.cpp index ad04f34..9333a74 100644 --- a/source/appstates/ExtrasMenuState.cpp +++ b/source/appstates/ExtrasMenuState.cpp @@ -6,7 +6,7 @@ #include "error.hpp" #include "graphics/colors.hpp" #include "input.hpp" -#include "keyboard.hpp" +#include "keyboard/keyboard.hpp" #include "strings/strings.hpp" #include "ui/PopMessageManager.hpp" diff --git a/source/appstates/FileOptionState.cpp b/source/appstates/FileOptionState.cpp index 393ca18..de6ebd0 100644 --- a/source/appstates/FileOptionState.cpp +++ b/source/appstates/FileOptionState.cpp @@ -9,7 +9,7 @@ #include "fs/fs.hpp" #include "fslib.hpp" #include "input.hpp" -#include "keyboard.hpp" +#include "keyboard/keyboard.hpp" #include "logging/logger.hpp" #include "mathutil.hpp" #include "strings/strings.hpp" diff --git a/source/appstates/SaveCreateState.cpp b/source/appstates/SaveCreateState.cpp index d514ce9..c2fc051 100644 --- a/source/appstates/SaveCreateState.cpp +++ b/source/appstates/SaveCreateState.cpp @@ -6,7 +6,7 @@ #include "error.hpp" #include "fs/fs.hpp" #include "input.hpp" -#include "keyboard.hpp" +#include "keyboard/keyboard.hpp" #include "logging/logger.hpp" #include "strings/strings.hpp" #include "stringutil.hpp" diff --git a/source/appstates/SettingsState.cpp b/source/appstates/SettingsState.cpp index 7933f10..bd690ff 100644 --- a/source/appstates/SettingsState.cpp +++ b/source/appstates/SettingsState.cpp @@ -10,7 +10,7 @@ #include "fslib.hpp" #include "graphics/colors.hpp" #include "input.hpp" -#include "keyboard.hpp" +#include "keyboard/keyboard.hpp" #include "logging/logger.hpp" #include "strings/strings.hpp" #include "stringutil.hpp" diff --git a/source/appstates/TitleOptionState.cpp b/source/appstates/TitleOptionState.cpp index 389338c..dff39ef 100644 --- a/source/appstates/TitleOptionState.cpp +++ b/source/appstates/TitleOptionState.cpp @@ -11,7 +11,7 @@ #include "fslib.hpp" #include "graphics/colors.hpp" #include "input.hpp" -#include "keyboard.hpp" +#include "keyboard/keyboard.hpp" #include "logging/logger.hpp" #include "remote/remote.hpp" #include "strings/strings.hpp" diff --git a/source/keyboard.cpp b/source/keyboard.cpp deleted file mode 100644 index 65da88b..0000000 --- a/source/keyboard.cpp +++ /dev/null @@ -1,36 +0,0 @@ -#include "keyboard.hpp" - -#include "error.hpp" - -#include - -bool keyboard::get_input(SwkbdType keyboardType, - std::string_view defaultText, - std::string_view header, - char *stringOut, - size_t stringLength) -{ - SwkbdConfig keyboard{}; - - const bool createError = error::libnx(swkbdCreate(&keyboard, 0)); - if (createError) { return false; } - - swkbdConfigSetBlurBackground(&keyboard, true); - swkbdConfigSetInitialText(&keyboard, defaultText.data()); - swkbdConfigSetHeaderText(&keyboard, header.data()); - swkbdConfigSetGuideText(&keyboard, header.data()); - swkbdConfigSetType(&keyboard, keyboardType); - swkbdConfigSetStringLenMax(&keyboard, stringLength); - swkbdConfigSetKeySetDisableBitmask(&keyboard, SwkbdKeyDisableBitmask_Backslash); - - const bool swkbdError = error::libnx(swkbdShow(&keyboard, stringOut, stringLength)); - const bool empty = std::char_traits::length(stringOut) == 0; - if (swkbdError || empty) - { - swkbdClose(&keyboard); - return false; - } - - swkbdClose(&keyboard); - return true; -} diff --git a/source/keyboard/Dictionary.cpp b/source/keyboard/Dictionary.cpp new file mode 100644 index 0000000..05a709a --- /dev/null +++ b/source/keyboard/Dictionary.cpp @@ -0,0 +1,37 @@ +#include "keyboard/Dictionary.hpp" + +#include "logging/logger.hpp" + +// ---- Construction ---- + +keyboard::Dictionary::Dictionary(std::initializer_list wordList) { Dictionary::add_list(wordList); } + +// ---- Public functions ---- + +void keyboard::Dictionary::add_list(std::initializer_list wordList) +{ + // Loop through the list. + for (const std::string_view word : wordList) + { + // New word + Dictionary::Word newWord{}; + + // This is cleaner and easier to read. libnx expects uint16 instead of char16 + uint16_t *predict = reinterpret_cast(newWord.predict); + uint16_t *dictWord = reinterpret_cast(newWord.word); + + // Same here. + const uint8_t *inData = reinterpret_cast(word.data()); + + // The words are UTF-16. We need to convert them. + utf8_to_utf16(predict, inData, Dictionary::WORD_LENGTH); + utf8_to_utf16(dictWord, inData, Dictionary::WORD_LENGTH); + + // Push the word to the vector. + m_words.push_back(newWord); + } +} + +size_t keyboard::Dictionary::get_count() const noexcept { return m_words.size(); } + +const keyboard::Dictionary::Word *keyboard::Dictionary::get_words() const noexcept { return m_words.data(); } \ No newline at end of file diff --git a/source/keyboard/keyboard.cpp b/source/keyboard/keyboard.cpp new file mode 100644 index 0000000..85230b1 --- /dev/null +++ b/source/keyboard/keyboard.cpp @@ -0,0 +1,62 @@ +#include "keyboard/keyboard.hpp" + +#include "error.hpp" + +#include + +bool keyboard::get_input(SwkbdType keyboardType, + std::string_view defaultText, + std::string_view header, + char *stringOut, + size_t stringLength, + std::optional> dictionary) +{ + // Swkbd config. + SwkbdConfig keyboard{}; + + // Cache instead of repeated calls. + const bool hasDictionary = dictionary.has_value(); + + // This changes whether or not we're passed a dictionary here. + bool createError{}; + if (hasDictionary) + { + // Getting this out of the optional looks confusing... + const size_t wordCount = dictionary->get().get_count(); + createError = error::libnx(swkbdCreate(&keyboard, wordCount)); + } + else { createError = error::libnx(swkbdCreate(&keyboard, 0)); } + + // Just return false if we can't init the keyboard. + if (createError) { return false; } + + // Standard swkbd init. + swkbdConfigSetBlurBackground(&keyboard, true); + swkbdConfigSetInitialText(&keyboard, defaultText.data()); + swkbdConfigSetHeaderText(&keyboard, header.data()); + swkbdConfigSetGuideText(&keyboard, header.data()); + swkbdConfigSetType(&keyboard, keyboardType); + swkbdConfigSetStringLenMax(&keyboard, stringLength); + swkbdConfigSetKeySetDisableBitmask(&keyboard, SwkbdKeyDisableBitmask_Backslash); + + // Add the dictionary if one was passed. + if (hasDictionary) + { + // These are easier to read and work with. + const SwkbdDictWord *words = reinterpret_cast(dictionary->get().get_words()); + const size_t wordCount = dictionary->get().get_count(); + + swkbdConfigSetDictionary(&keyboard, words, wordCount); + } + + const bool swkbdError = error::libnx(swkbdShow(&keyboard, stringOut, stringLength)); + const bool empty = std::char_traits::length(stringOut) == 0; + if (swkbdError || empty) + { + swkbdClose(&keyboard); + return false; + } + + swkbdClose(&keyboard); + return true; +} diff --git a/source/tasks/titleoptions.cpp b/source/tasks/titleoptions.cpp index 53a8d89..d4d2980 100644 --- a/source/tasks/titleoptions.cpp +++ b/source/tasks/titleoptions.cpp @@ -4,7 +4,7 @@ #include "data/data.hpp" #include "error.hpp" #include "fs/fs.hpp" -#include "keyboard.hpp" +#include "keyboard/keyboard.hpp" #include "logging/logger.hpp" #include "remote/remote.hpp" #include "strings/strings.hpp"