mirror of
https://github.com/citra-emu/citra.git
synced 2024-11-25 22:20:14 +00:00
Stdin software keyboard implementation
A simple stdin swkbd for the purpose of adding several missing features from the existing implementation. Allows users to type into the console for text input, runs several of the validation checks, and returns the correct result codes.
This commit is contained in:
parent
9dc43d3720
commit
da07fdc93c
@ -2,7 +2,11 @@
|
|||||||
// Licensed under GPLv2 or any later version
|
// Licensed under GPLv2 or any later version
|
||||||
// Refer to the license.txt file included.
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <cctype>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
#include <functional>
|
||||||
|
#include <iostream>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include "common/assert.h"
|
#include "common/assert.h"
|
||||||
#include "common/logging/log.h"
|
#include "common/logging/log.h"
|
||||||
@ -21,6 +25,10 @@
|
|||||||
namespace HLE {
|
namespace HLE {
|
||||||
namespace Applets {
|
namespace Applets {
|
||||||
|
|
||||||
|
const static std::array<std::string, 1> swkbd_default_1_button = {"Ok"};
|
||||||
|
const static std::array<std::string, 2> swkbd_default_2_button = {"Cancel", "Ok"};
|
||||||
|
const static std::array<std::string, 3> swkbd_default_3_button = {"Cancel", "I Forgot", "Ok"};
|
||||||
|
|
||||||
ResultCode SoftwareKeyboard::ReceiveParameter(Service::APT::MessageParameter const& parameter) {
|
ResultCode SoftwareKeyboard::ReceiveParameter(Service::APT::MessageParameter const& parameter) {
|
||||||
if (parameter.signal != static_cast<u32>(Service::APT::SignalType::Request)) {
|
if (parameter.signal != static_cast<u32>(Service::APT::SignalType::Request)) {
|
||||||
LOG_ERROR(Service_APT, "unsupported signal %u", parameter.signal);
|
LOG_ERROR(Service_APT, "unsupported signal %u", parameter.signal);
|
||||||
@ -42,7 +50,7 @@ ResultCode SoftwareKeyboard::ReceiveParameter(Service::APT::MessageParameter con
|
|||||||
heap_memory = std::make_shared<std::vector<u8>>(capture_info.size);
|
heap_memory = std::make_shared<std::vector<u8>>(capture_info.size);
|
||||||
// Create a SharedMemory that directly points to this heap block.
|
// Create a SharedMemory that directly points to this heap block.
|
||||||
framebuffer_memory = Kernel::SharedMemory::CreateForApplet(
|
framebuffer_memory = Kernel::SharedMemory::CreateForApplet(
|
||||||
heap_memory, 0, heap_memory->size(), MemoryPermission::ReadWrite,
|
heap_memory, 0, static_cast<u32>(heap_memory->size()), MemoryPermission::ReadWrite,
|
||||||
MemoryPermission::ReadWrite, "SoftwareKeyboard Memory");
|
MemoryPermission::ReadWrite, "SoftwareKeyboard Memory");
|
||||||
|
|
||||||
// Send the response message with the newly created SharedMemory
|
// Send the response message with the newly created SharedMemory
|
||||||
@ -74,18 +82,192 @@ ResultCode SoftwareKeyboard::StartImpl(Service::APT::AppletStartupParameter cons
|
|||||||
return RESULT_SUCCESS;
|
return RESULT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool ValidateFilters(const u32 filters, const std::string& input) {
|
||||||
|
bool valid = true;
|
||||||
|
bool local_filter = true;
|
||||||
|
if ((filters & SWKBDFILTER_DIGITS) == SWKBDFILTER_DIGITS) {
|
||||||
|
valid &= local_filter =
|
||||||
|
std::all_of(input.begin(), input.end(), [](const char c) { return !std::isdigit(c); });
|
||||||
|
if (!local_filter) {
|
||||||
|
std::cout << "Input must not contain any digits" << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ((filters & SWKBDFILTER_AT) == SWKBDFILTER_AT) {
|
||||||
|
valid &= local_filter = input.find("@") == std::string::npos;
|
||||||
|
if (!local_filter) {
|
||||||
|
std::cout << "Input must not contain the @ symbol" << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ((filters & SWKBDFILTER_PERCENT) == SWKBDFILTER_PERCENT) {
|
||||||
|
valid &= local_filter = input.find("%") == std::string::npos;
|
||||||
|
if (!local_filter) {
|
||||||
|
std::cout << "Input must not contain the % symbol" << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ((filters & SWKBDFILTER_BACKSLASH) == SWKBDFILTER_BACKSLASH) {
|
||||||
|
valid &= local_filter = input.find("\\") == std::string::npos;
|
||||||
|
if (!local_filter) {
|
||||||
|
std::cout << "Input must not contain the \\ symbol" << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ((filters & SWKBDFILTER_PROFANITY) == SWKBDFILTER_PROFANITY) {
|
||||||
|
// TODO: check the profanity filter
|
||||||
|
LOG_WARNING(Service_APT, "App requested profanity filter, but its not implemented.");
|
||||||
|
}
|
||||||
|
if ((filters & SWKBDFILTER_CALLBACK) == SWKBDFILTER_CALLBACK) {
|
||||||
|
// TODO: check the callback
|
||||||
|
LOG_WARNING(Service_APT, "App requested a callback check, but its not implemented.");
|
||||||
|
}
|
||||||
|
return valid;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool ValidateInput(const SoftwareKeyboardConfig& config, const std::string input) {
|
||||||
|
// TODO(jroweboy): Is max_text_length inclusive or exclusive?
|
||||||
|
if (input.size() > config.max_text_length) {
|
||||||
|
std::cout << Common::StringFromFormat("Input is longer than the maximum length. Max: %u",
|
||||||
|
config.max_text_length)
|
||||||
|
<< std::endl;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// return early if the text is filtered
|
||||||
|
if (config.filter_flags && !ValidateFilters(config.filter_flags, input)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool valid;
|
||||||
|
switch (config.valid_input) {
|
||||||
|
case SwkbdValidInput::FIXEDLEN:
|
||||||
|
valid = input.size() == config.max_text_length;
|
||||||
|
if (!valid) {
|
||||||
|
std::cout << Common::StringFromFormat("Input must be exactly %u characters.",
|
||||||
|
config.max_text_length)
|
||||||
|
<< std::endl;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case SwkbdValidInput::NOTEMPTY_NOTBLANK:
|
||||||
|
case SwkbdValidInput::NOTBLANK:
|
||||||
|
valid =
|
||||||
|
std::any_of(input.begin(), input.end(), [](const char c) { return !std::isspace(c); });
|
||||||
|
if (!valid) {
|
||||||
|
std::cout << "Input must not be blank." << std::endl;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case SwkbdValidInput::NOTEMPTY:
|
||||||
|
valid = input.empty();
|
||||||
|
if (!valid) {
|
||||||
|
std::cout << "Input must not be empty." << std::endl;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case SwkbdValidInput::ANYTHING:
|
||||||
|
valid = true;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
// TODO(jroweboy): What does hardware do in this case?
|
||||||
|
LOG_CRITICAL(Service_APT, "Application requested unknown validation method. Method: %u",
|
||||||
|
static_cast<u32>(config.valid_input));
|
||||||
|
UNREACHABLE();
|
||||||
|
}
|
||||||
|
|
||||||
|
return valid;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool ValidateButton(u32 num_buttons, const std::string& input) {
|
||||||
|
// check that the input is a valid number
|
||||||
|
bool valid = false;
|
||||||
|
try {
|
||||||
|
u32 num = std::stoul(input);
|
||||||
|
valid = num <= num_buttons;
|
||||||
|
if (!valid) {
|
||||||
|
std::cout << Common::StringFromFormat("Please choose a number between 0 and %u",
|
||||||
|
num_buttons)
|
||||||
|
<< std::endl;
|
||||||
|
}
|
||||||
|
} catch (const std::invalid_argument& e) {
|
||||||
|
(void)e;
|
||||||
|
std::cout << "Unable to parse input as a number." << std::endl;
|
||||||
|
} catch (const std::out_of_range& e) {
|
||||||
|
(void)e;
|
||||||
|
std::cout << "Input number is not valid." << std::endl;
|
||||||
|
}
|
||||||
|
return valid;
|
||||||
|
}
|
||||||
|
|
||||||
void SoftwareKeyboard::Update() {
|
void SoftwareKeyboard::Update() {
|
||||||
// TODO(Subv): Handle input using the touch events from the HID module
|
// TODO(Subv): Handle input using the touch events from the HID module
|
||||||
|
// Until then, just read input from the terminal
|
||||||
|
std::string input;
|
||||||
|
std::cout << "SOFTWARE KEYBOARD" << std::endl;
|
||||||
|
// Display hint text
|
||||||
|
std::u16string hint(reinterpret_cast<char16_t*>(config.hint_text));
|
||||||
|
if (!hint.empty()) {
|
||||||
|
std::cout << "Hint text: " << Common::UTF16ToUTF8(hint) << std::endl;
|
||||||
|
}
|
||||||
|
do {
|
||||||
|
std::cout << "Enter the text you will send to the application:" << std::endl;
|
||||||
|
std::getline(std::cin, input);
|
||||||
|
} while (!ValidateInput(config, input));
|
||||||
|
|
||||||
// TODO(Subv): Remove this hardcoded text
|
std::string option_text;
|
||||||
std::u16string text = Common::UTF8ToUTF16("Citra");
|
// convert all of the button texts into something we can output
|
||||||
memcpy(text_memory->GetPointer(), text.c_str(), text.length() * sizeof(char16_t));
|
// num_buttons is in the range of 0-2 so use <= instead of <
|
||||||
|
u32 num_buttons = static_cast<u32>(config.num_buttons_m1);
|
||||||
|
for (u32 i = 0; i <= num_buttons; ++i) {
|
||||||
|
std::string final_text;
|
||||||
|
// apps are allowed to set custom text to display on the button
|
||||||
|
std::u16string custom_button_text(reinterpret_cast<char16_t*>(config.button_text[i]));
|
||||||
|
if (custom_button_text.empty()) {
|
||||||
|
// Use the system default text for that button
|
||||||
|
if (num_buttons == 0) {
|
||||||
|
final_text = swkbd_default_1_button[i];
|
||||||
|
} else if (num_buttons == 1) {
|
||||||
|
final_text = swkbd_default_2_button[i];
|
||||||
|
} else {
|
||||||
|
final_text = swkbd_default_3_button[i];
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
final_text = Common::UTF16ToUTF8(custom_button_text);
|
||||||
|
}
|
||||||
|
option_text += Common::StringFromFormat("\t(%u) %s\t", i, final_text);
|
||||||
|
}
|
||||||
|
std::string option;
|
||||||
|
do {
|
||||||
|
std::cout << "\nPlease type the number of the button you will press: \n"
|
||||||
|
<< option_text << std::endl;
|
||||||
|
std::getline(std::cin, option);
|
||||||
|
} while (!ValidateButton(static_cast<u32>(config.num_buttons_m1), option));
|
||||||
|
|
||||||
// TODO(Subv): Ask for input and write it to the shared memory
|
s32 button = std::stol(option);
|
||||||
// TODO(Subv): Find out what are the possible values for the return code,
|
switch (config.num_buttons_m1) {
|
||||||
// some games seem to check for a hardcoded 2
|
case SwkbdButtonConfig::SINGLE_BUTTON:
|
||||||
config.return_code = 2;
|
config.return_code = SwkbdResult::D0_CLICK;
|
||||||
config.text_length = 6;
|
break;
|
||||||
|
case SwkbdButtonConfig::DUAL_BUTTON:
|
||||||
|
if (button == 0) {
|
||||||
|
config.return_code = SwkbdResult::D1_CLICK0;
|
||||||
|
} else {
|
||||||
|
config.return_code = SwkbdResult::D1_CLICK1;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case SwkbdButtonConfig::TRIPLE_BUTTON:
|
||||||
|
if (button == 0) {
|
||||||
|
config.return_code = SwkbdResult::D2_CLICK0;
|
||||||
|
} else if (button == 1) {
|
||||||
|
config.return_code = SwkbdResult::D2_CLICK1;
|
||||||
|
} else {
|
||||||
|
config.return_code = SwkbdResult::D2_CLICK2;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
// TODO: what does the hardware do
|
||||||
|
LOG_WARNING(Service_APT, "Unknown option for num_buttons_m1: %u",
|
||||||
|
static_cast<u32>(config.num_buttons_m1));
|
||||||
|
config.return_code = SwkbdResult::NONE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::u16string utf16_input = Common::UTF8ToUTF16(input);
|
||||||
|
memcpy(text_memory->GetPointer(), utf16_input.c_str(), utf16_input.length() * sizeof(char16_t));
|
||||||
|
config.text_length = static_cast<u16>(utf16_input.size());
|
||||||
config.text_offset = 0;
|
config.text_offset = 0;
|
||||||
|
|
||||||
// TODO(Subv): We're finalizing the applet immediately after it's started,
|
// TODO(Subv): We're finalizing the applet immediately after it's started,
|
||||||
|
@ -15,33 +15,153 @@
|
|||||||
namespace HLE {
|
namespace HLE {
|
||||||
namespace Applets {
|
namespace Applets {
|
||||||
|
|
||||||
|
/// Maximum number of buttons that can be in the keyboard.
|
||||||
|
#define SWKBD_MAX_BUTTON 3
|
||||||
|
/// Maximum button text length, in UTF-16 code units.
|
||||||
|
#define SWKBD_MAX_BUTTON_TEXT_LEN 16
|
||||||
|
/// Maximum hint text length, in UTF-16 code units.
|
||||||
|
#define SWKBD_MAX_HINT_TEXT_LEN 64
|
||||||
|
/// Maximum filter callback error message length, in UTF-16 code units.
|
||||||
|
#define SWKBD_MAX_CALLBACK_MSG_LEN 256
|
||||||
|
|
||||||
|
/// Keyboard types
|
||||||
|
enum class SwkbdType : u32 {
|
||||||
|
NORMAL = 0, ///< Normal keyboard with several pages (QWERTY/accents/symbol/mobile)
|
||||||
|
QWERTY, ///< QWERTY keyboard only.
|
||||||
|
NUMPAD, ///< Number pad.
|
||||||
|
WESTERN, ///< On JPN systems, a text keyboard without Japanese input capabilities,
|
||||||
|
/// otherwise same as SWKBD_TYPE_NORMAL.
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Keyboard dialog buttons.
|
||||||
|
enum class SwkbdButtonConfig : u32 {
|
||||||
|
SINGLE_BUTTON = 0, ///< Ok button
|
||||||
|
DUAL_BUTTON, ///< Cancel | Ok buttons
|
||||||
|
TRIPLE_BUTTON, ///< Cancel | I Forgot | Ok buttons
|
||||||
|
NO_BUTTON, ///< No button (returned by swkbdInputText in special cases)
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Accepted input types.
|
||||||
|
enum class SwkbdValidInput : u32 {
|
||||||
|
ANYTHING = 0, ///< All inputs are accepted.
|
||||||
|
NOTEMPTY, ///< Empty inputs are not accepted.
|
||||||
|
NOTEMPTY_NOTBLANK, ///< Empty or blank inputs (consisting solely of whitespace) are not
|
||||||
|
/// accepted.
|
||||||
|
NOTBLANK, ///< Blank inputs (consisting solely of whitespace) are not accepted, but empty
|
||||||
|
/// inputs are.
|
||||||
|
FIXEDLEN, ///< The input must have a fixed length (specified by maxTextLength in
|
||||||
|
/// swkbdInit).
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Keyboard password modes.
|
||||||
|
enum class SwkbdPasswordMode : u32 {
|
||||||
|
NONE = 0, ///< Characters are not concealed.
|
||||||
|
HIDE, ///< Characters are concealed immediately.
|
||||||
|
HIDE_DELAY, ///< Characters are concealed a second after they've been typed.
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Keyboard input filtering flags.
|
||||||
|
enum SwkbdFilter {
|
||||||
|
SWKBDFILTER_DIGITS =
|
||||||
|
1, ///< Disallow the use of more than a certain number of digits (0 or more)
|
||||||
|
SWKBDFILTER_AT = 1 << 1, ///< Disallow the use of the @ sign.
|
||||||
|
SWKBDFILTER_PERCENT = 1 << 2, ///< Disallow the use of the % sign.
|
||||||
|
SWKBDFILTER_BACKSLASH = 1 << 3, ///< Disallow the use of the \ sign.
|
||||||
|
SWKBDFILTER_PROFANITY = 1 << 4, ///< Disallow profanity using Nintendo's profanity filter.
|
||||||
|
SWKBDFILTER_CALLBACK = 1 << 5, ///< Use a callback in order to check the input.
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Keyboard features.
|
||||||
|
enum SwkbdFeatures {
|
||||||
|
SWKBDFEATURES_PARENTAL = 1, ///< Parental PIN mode.
|
||||||
|
SWKBDFEATURES_DARKEN_TOP_SCREEN = 1 << 1, ///< Darken the top screen when the keyboard is shown.
|
||||||
|
SWKBDFEATURES_PREDICTIVE_INPUT =
|
||||||
|
1 << 2, ///< Enable predictive input (necessary for Kanji input in JPN systems).
|
||||||
|
SWKBDFEATURES_MULTILINE = 1 << 3, ///< Enable multiline input.
|
||||||
|
SWKBDFEATURES_FIXED_WIDTH = 1 << 4, ///< Enable fixed-width mode.
|
||||||
|
SWKBDFEATURES_ALLOW_HOME = 1 << 5, ///< Allow the usage of the HOME button.
|
||||||
|
SWKBDFEATURES_ALLOW_RESET = 1 << 6, ///< Allow the usage of a software-reset combination.
|
||||||
|
SWKBDFEATURES_ALLOW_POWER = 1 << 7, ///< Allow the usage of the POWER button.
|
||||||
|
SWKBDFEATURES_DEFAULT_QWERTY = 1
|
||||||
|
<< 9, ///< Default to the QWERTY page when the keyboard is shown.
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Keyboard filter callback return values.
|
||||||
|
enum class SwkbdCallbackResult : u32 {
|
||||||
|
OK = 0, ///< Specifies that the input is valid.
|
||||||
|
CLOSE, ///< Displays an error message, then closes the keyboard.
|
||||||
|
CONTINUE, ///< Displays an error message and continues displaying the keyboard.
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Keyboard return values.
|
||||||
|
enum class SwkbdResult : s32 {
|
||||||
|
NONE = -1, ///< Dummy/unused.
|
||||||
|
INVALID_INPUT = -2, ///< Invalid parameters to swkbd.
|
||||||
|
OUTOFMEM = -3, ///< Out of memory.
|
||||||
|
|
||||||
|
D0_CLICK = 0, ///< The button was clicked in 1-button dialogs.
|
||||||
|
D1_CLICK0, ///< The left button was clicked in 2-button dialogs.
|
||||||
|
D1_CLICK1, ///< The right button was clicked in 2-button dialogs.
|
||||||
|
D2_CLICK0, ///< The left button was clicked in 3-button dialogs.
|
||||||
|
D2_CLICK1, ///< The middle button was clicked in 3-button dialogs.
|
||||||
|
D2_CLICK2, ///< The right button was clicked in 3-button dialogs.
|
||||||
|
|
||||||
|
HOMEPRESSED = 10, ///< The HOME button was pressed.
|
||||||
|
RESETPRESSED, ///< The soft-reset key combination was pressed.
|
||||||
|
POWERPRESSED, ///< The POWER button was pressed.
|
||||||
|
|
||||||
|
PARENTAL_OK = 20, ///< The parental PIN was verified successfully.
|
||||||
|
PARENTAL_FAIL, ///< The parental PIN was incorrect.
|
||||||
|
|
||||||
|
BANNED_INPUT = 30, ///< The filter callback returned SWKBD_CALLBACK_CLOSE.
|
||||||
|
};
|
||||||
|
|
||||||
struct SoftwareKeyboardConfig {
|
struct SoftwareKeyboardConfig {
|
||||||
INSERT_PADDING_WORDS(0x8);
|
SwkbdType type;
|
||||||
|
SwkbdButtonConfig num_buttons_m1;
|
||||||
|
SwkbdValidInput valid_input;
|
||||||
|
SwkbdPasswordMode password_mode;
|
||||||
|
s32 is_parental_screen;
|
||||||
|
s32 darken_top_screen;
|
||||||
|
u32 filter_flags;
|
||||||
|
u32 save_state_flags;
|
||||||
u16 max_text_length; ///< Maximum length of the input text
|
u16 max_text_length; ///< Maximum length of the input text
|
||||||
|
u16 dict_word_count;
|
||||||
|
u16 max_digits;
|
||||||
|
u16 button_text[SWKBD_MAX_BUTTON][SWKBD_MAX_BUTTON_TEXT_LEN + 1];
|
||||||
|
u16 numpad_keys[2];
|
||||||
|
u16 hint_text[SWKBD_MAX_HINT_TEXT_LEN + 1]; ///< Text to display when asking the user for input
|
||||||
|
bool predictive_input;
|
||||||
|
bool multiline;
|
||||||
|
bool fixed_width;
|
||||||
|
bool allow_home;
|
||||||
|
bool allow_reset;
|
||||||
|
bool allow_power;
|
||||||
|
bool unknown; // XX: what is this supposed to do? "communicateWithOtherRegions"
|
||||||
|
bool default_qwerty;
|
||||||
|
bool button_submits_text[4];
|
||||||
|
u16 language; // XX: not working? supposedly 0 = use system language, CFG_Language+1 = pick
|
||||||
|
// language
|
||||||
|
|
||||||
INSERT_PADDING_BYTES(0x6E);
|
u32 initial_text_offset; ///< Offset of the default text in the output SharedMemory
|
||||||
|
u32 dict_offset;
|
||||||
char16_t display_text[65]; ///< Text to display when asking the user for input
|
u32 initial_status_offset;
|
||||||
|
u32 initial_learning_offset;
|
||||||
INSERT_PADDING_BYTES(0xE);
|
|
||||||
|
|
||||||
u32 default_text_offset; ///< Offset of the default text in the output SharedMemory
|
|
||||||
|
|
||||||
INSERT_PADDING_WORDS(0x3);
|
|
||||||
|
|
||||||
u32 shared_memory_size; ///< Size of the SharedMemory
|
u32 shared_memory_size; ///< Size of the SharedMemory
|
||||||
|
u32 version;
|
||||||
|
|
||||||
INSERT_PADDING_WORDS(0x1);
|
SwkbdResult return_code;
|
||||||
|
|
||||||
u32 return_code; ///< Return code of the SoftwareKeyboard, usually 2, other values are unknown
|
u32 status_offset;
|
||||||
|
u32 learning_offset;
|
||||||
INSERT_PADDING_WORDS(0x2);
|
|
||||||
|
|
||||||
u32 text_offset; ///< Offset in the SharedMemory where the output text starts
|
u32 text_offset; ///< Offset in the SharedMemory where the output text starts
|
||||||
u16 text_length; ///< Length in characters of the output text
|
u16 text_length; ///< Length in characters of the output text
|
||||||
|
|
||||||
INSERT_PADDING_BYTES(0x2B6);
|
int callback_result;
|
||||||
|
u16 callback_msg[SWKBD_MAX_CALLBACK_MSG_LEN + 1];
|
||||||
|
bool skip_at_check;
|
||||||
|
INSERT_PADDING_BYTES(0xAB);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -40,8 +40,12 @@ static ScreencapPostPermission screen_capture_post_permission;
|
|||||||
/// Parameter data to be returned in the next call to Glance/ReceiveParameter
|
/// Parameter data to be returned in the next call to Glance/ReceiveParameter
|
||||||
static MessageParameter next_parameter;
|
static MessageParameter next_parameter;
|
||||||
|
|
||||||
|
/// stores the state for CancelParameter
|
||||||
|
static bool cancelled = false;
|
||||||
|
|
||||||
void SendParameter(const MessageParameter& parameter) {
|
void SendParameter(const MessageParameter& parameter) {
|
||||||
next_parameter = parameter;
|
next_parameter = parameter;
|
||||||
|
cancelled = false;
|
||||||
// Signal the event to let the application know that a new parameter is ready to be read
|
// Signal the event to let the application know that a new parameter is ready to be read
|
||||||
parameter_event->Signal();
|
parameter_event->Signal();
|
||||||
}
|
}
|
||||||
@ -208,6 +212,11 @@ void ReceiveParameter(Service::Interface* self) {
|
|||||||
u32 buffer_size = cmd_buff[2];
|
u32 buffer_size = cmd_buff[2];
|
||||||
VAddr buffer = cmd_buff[0x104 >> 2];
|
VAddr buffer = cmd_buff[0x104 >> 2];
|
||||||
|
|
||||||
|
if (cancelled) {
|
||||||
|
cmd_buff[1] = -1;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
cmd_buff[1] = RESULT_SUCCESS.raw; // No error
|
cmd_buff[1] = RESULT_SUCCESS.raw; // No error
|
||||||
cmd_buff[2] = next_parameter.sender_id;
|
cmd_buff[2] = next_parameter.sender_id;
|
||||||
cmd_buff[3] = next_parameter.signal; // Signal type
|
cmd_buff[3] = next_parameter.signal; // Signal type
|
||||||
@ -230,6 +239,11 @@ void GlanceParameter(Service::Interface* self) {
|
|||||||
u32 buffer_size = cmd_buff[2];
|
u32 buffer_size = cmd_buff[2];
|
||||||
VAddr buffer = cmd_buff[0x104 >> 2];
|
VAddr buffer = cmd_buff[0x104 >> 2];
|
||||||
|
|
||||||
|
if (cancelled) {
|
||||||
|
cmd_buff[1] = -1;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
cmd_buff[1] = RESULT_SUCCESS.raw; // No error
|
cmd_buff[1] = RESULT_SUCCESS.raw; // No error
|
||||||
cmd_buff[2] = next_parameter.sender_id;
|
cmd_buff[2] = next_parameter.sender_id;
|
||||||
cmd_buff[3] = next_parameter.signal; // Signal type
|
cmd_buff[3] = next_parameter.signal; // Signal type
|
||||||
@ -254,6 +268,8 @@ void CancelParameter(Service::Interface* self) {
|
|||||||
u32 flag2 = cmd_buff[3];
|
u32 flag2 = cmd_buff[3];
|
||||||
u32 app_id = cmd_buff[4];
|
u32 app_id = cmd_buff[4];
|
||||||
|
|
||||||
|
cancelled = true;
|
||||||
|
|
||||||
cmd_buff[1] = RESULT_SUCCESS.raw; // No error
|
cmd_buff[1] = RESULT_SUCCESS.raw; // No error
|
||||||
cmd_buff[2] = 1; // Set to Success
|
cmd_buff[2] = 1; // Set to Success
|
||||||
|
|
||||||
@ -493,6 +509,13 @@ void CheckNew3DS(Service::Interface* self) {
|
|||||||
LOG_WARNING(Service_APT, "(STUBBED) called");
|
LOG_WARNING(Service_APT, "(STUBBED) called");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ReplySleepQuery(Service::Interface* self) {
|
||||||
|
u32* cmd_buff = Kernel::GetCommandBuffer();
|
||||||
|
|
||||||
|
cmd_buff[1] = RESULT_SUCCESS.raw;
|
||||||
|
LOG_WARNING(Service_APT, "(STUBBED) ReplySleepQuery called");
|
||||||
|
}
|
||||||
|
|
||||||
void Init() {
|
void Init() {
|
||||||
AddService(new APT_A_Interface);
|
AddService(new APT_A_Interface);
|
||||||
AddService(new APT_S_Interface);
|
AddService(new APT_S_Interface);
|
||||||
|
@ -461,6 +461,13 @@ void CheckNew3DSApp(Service::Interface* self);
|
|||||||
*/
|
*/
|
||||||
void CheckNew3DS(Service::Interface* self);
|
void CheckNew3DS(Service::Interface* self);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* APT::ReplySleepQuery service function
|
||||||
|
* Outputs:
|
||||||
|
* 1: Result code
|
||||||
|
*/
|
||||||
|
void ReplySleepQuery(Service::Interface* self);
|
||||||
|
|
||||||
/// Initialize the APT service
|
/// Initialize the APT service
|
||||||
void Init();
|
void Init();
|
||||||
|
|
||||||
|
@ -20,10 +20,10 @@ const Interface::FunctionInfo FunctionTable[] = {
|
|||||||
{0x00090040, nullptr, "IsRegistered"},
|
{0x00090040, nullptr, "IsRegistered"},
|
||||||
{0x000A0040, nullptr, "GetAttribute"},
|
{0x000A0040, nullptr, "GetAttribute"},
|
||||||
{0x000B0040, InquireNotification, "InquireNotification"},
|
{0x000B0040, InquireNotification, "InquireNotification"},
|
||||||
{0x000C0104, nullptr, "SendParameter"},
|
{0x000C0104, SendParameter, "SendParameter"},
|
||||||
{0x000D0080, ReceiveParameter, "ReceiveParameter"},
|
{0x000D0080, ReceiveParameter, "ReceiveParameter"},
|
||||||
{0x000E0080, GlanceParameter, "GlanceParameter"},
|
{0x000E0080, GlanceParameter, "GlanceParameter"},
|
||||||
{0x000F0100, nullptr, "CancelParameter"},
|
{0x000F0100, CancelParameter, "CancelParameter"},
|
||||||
{0x001000C2, nullptr, "DebugFunc"},
|
{0x001000C2, nullptr, "DebugFunc"},
|
||||||
{0x001100C0, nullptr, "MapProgramIdForDebug"},
|
{0x001100C0, nullptr, "MapProgramIdForDebug"},
|
||||||
{0x00120040, nullptr, "SetHomeMenuAppletIdForDebug"},
|
{0x00120040, nullptr, "SetHomeMenuAppletIdForDebug"},
|
||||||
@ -38,7 +38,7 @@ const Interface::FunctionInfo FunctionTable[] = {
|
|||||||
{0x001B00C4, nullptr, "StartApplication"},
|
{0x001B00C4, nullptr, "StartApplication"},
|
||||||
{0x001C0000, nullptr, "WakeupApplication"},
|
{0x001C0000, nullptr, "WakeupApplication"},
|
||||||
{0x001D0000, nullptr, "CancelApplication"},
|
{0x001D0000, nullptr, "CancelApplication"},
|
||||||
{0x001E0084, nullptr, "StartLibraryApplet"},
|
{0x001E0084, StartLibraryApplet, "StartLibraryApplet"},
|
||||||
{0x001F0084, nullptr, "StartSystemApplet"},
|
{0x001F0084, nullptr, "StartSystemApplet"},
|
||||||
{0x00200044, nullptr, "StartNewestHomeMenu"},
|
{0x00200044, nullptr, "StartNewestHomeMenu"},
|
||||||
{0x00210000, nullptr, "OrderToCloseApplication"},
|
{0x00210000, nullptr, "OrderToCloseApplication"},
|
||||||
@ -70,7 +70,7 @@ const Interface::FunctionInfo FunctionTable[] = {
|
|||||||
{0x003B0040, nullptr, "CancelLibraryApplet"},
|
{0x003B0040, nullptr, "CancelLibraryApplet"},
|
||||||
{0x003C0042, nullptr, "SendDspSleep"},
|
{0x003C0042, nullptr, "SendDspSleep"},
|
||||||
{0x003D0042, nullptr, "SendDspWakeUp"},
|
{0x003D0042, nullptr, "SendDspWakeUp"},
|
||||||
{0x003E0080, nullptr, "ReplySleepQuery"},
|
{0x003E0080, ReplySleepQuery, "ReplySleepQuery"},
|
||||||
{0x003F0040, nullptr, "ReplySleepNotificationComplete"},
|
{0x003F0040, nullptr, "ReplySleepNotificationComplete"},
|
||||||
{0x00400042, nullptr, "SendCaptureBufferInfo"},
|
{0x00400042, nullptr, "SendCaptureBufferInfo"},
|
||||||
{0x00410040, nullptr, "ReceiveCaptureBufferInfo"},
|
{0x00410040, nullptr, "ReceiveCaptureBufferInfo"},
|
||||||
|
Loading…
Reference in New Issue
Block a user