2018-03-22 03:07:11 +01:00
|
|
|
// Copyright 2018 Citra Emulator Project
|
|
|
|
// Licensed under GPLv2 or any later version
|
|
|
|
// Refer to the license.txt file included.
|
|
|
|
|
2018-06-20 14:01:50 +02:00
|
|
|
#include <algorithm>
|
|
|
|
#include <cctype>
|
2018-06-20 06:01:54 +02:00
|
|
|
#include "common/assert.h"
|
|
|
|
#include "common/logging/log.h"
|
2018-06-20 14:01:50 +02:00
|
|
|
#include "core/core.h"
|
2018-06-20 06:01:54 +02:00
|
|
|
#include "core/frontend/applets/swkbd.h"
|
2018-03-22 03:07:11 +01:00
|
|
|
|
|
|
|
namespace Frontend {
|
|
|
|
|
2018-06-20 14:01:50 +02:00
|
|
|
ValidationError SoftwareKeyboard::ValidateFilters(const std::string& input) const {
|
2018-03-22 03:07:11 +01:00
|
|
|
if (config.filters.prevent_digit) {
|
2018-06-20 06:01:54 +02:00
|
|
|
if (std::any_of(input.begin(), input.end(),
|
|
|
|
[](unsigned char c) { return std::isdigit(c); })) {
|
2018-03-22 03:07:11 +01:00
|
|
|
return ValidationError::DigitNotAllowed;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (config.filters.prevent_at) {
|
|
|
|
if (input.find('@') != std::string::npos) {
|
|
|
|
return ValidationError::AtSignNotAllowed;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (config.filters.prevent_percent) {
|
|
|
|
if (input.find('%') != std::string::npos) {
|
|
|
|
return ValidationError::PercentNotAllowed;
|
|
|
|
}
|
|
|
|
}
|
2018-06-20 06:01:54 +02:00
|
|
|
if (config.filters.prevent_backslash) {
|
2018-03-22 03:07:11 +01:00
|
|
|
if (input.find('\\') != std::string::npos) {
|
|
|
|
return ValidationError::BackslashNotAllowed;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (config.filters.prevent_profanity) {
|
|
|
|
// TODO: check the profanity filter
|
|
|
|
LOG_INFO(Frontend, "App requested swkbd profanity filter, but its not implemented.");
|
|
|
|
}
|
|
|
|
if (config.filters.enable_callback) {
|
|
|
|
// TODO: check the callback
|
|
|
|
LOG_INFO(Frontend, "App requested a swkbd callback, but its not implemented.");
|
|
|
|
}
|
2018-06-20 06:01:54 +02:00
|
|
|
return ValidationError::None;
|
2018-03-22 03:07:11 +01:00
|
|
|
}
|
|
|
|
|
2018-06-20 14:01:50 +02:00
|
|
|
ValidationError SoftwareKeyboard::ValidateInput(const std::string& input) const {
|
2018-03-22 03:07:11 +01:00
|
|
|
ValidationError error;
|
|
|
|
if ((error = ValidateFilters(input)) != ValidationError::None) {
|
|
|
|
return error;
|
|
|
|
}
|
|
|
|
|
|
|
|
// TODO(jroweboy): Is max_text_length inclusive or exclusive?
|
|
|
|
if (input.size() > config.max_text_length) {
|
|
|
|
return ValidationError::MaxLengthExceeded;
|
|
|
|
}
|
|
|
|
|
2018-06-20 14:01:50 +02:00
|
|
|
bool is_blank =
|
|
|
|
std::all_of(input.begin(), input.end(), [](unsigned char c) { return std::isspace(c); });
|
|
|
|
bool is_empty = input.empty();
|
2018-06-20 06:01:54 +02:00
|
|
|
switch (config.accept_mode) {
|
2018-03-22 03:07:11 +01:00
|
|
|
case AcceptedInput::FixedLength:
|
|
|
|
if (input.size() != config.max_text_length) {
|
|
|
|
return ValidationError::FixedLengthRequired;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case AcceptedInput::NotEmptyAndNotBlank:
|
2018-06-20 14:01:50 +02:00
|
|
|
if (is_blank) {
|
2018-03-22 03:07:11 +01:00
|
|
|
return ValidationError::BlankInputNotAllowed;
|
|
|
|
}
|
2018-06-20 14:01:50 +02:00
|
|
|
if (is_empty) {
|
2018-03-22 03:07:11 +01:00
|
|
|
return ValidationError::EmptyInputNotAllowed;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case AcceptedInput::NotBlank:
|
2018-06-20 14:01:50 +02:00
|
|
|
if (is_blank) {
|
2018-03-22 03:07:11 +01:00
|
|
|
return ValidationError::BlankInputNotAllowed;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case AcceptedInput::NotEmpty:
|
2018-06-20 14:01:50 +02:00
|
|
|
if (is_empty) {
|
2018-03-22 03:07:11 +01:00
|
|
|
return ValidationError::EmptyInputNotAllowed;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case AcceptedInput::Anything:
|
|
|
|
return ValidationError::None;
|
|
|
|
default:
|
|
|
|
// TODO(jroweboy): What does hardware do in this case?
|
2018-06-20 14:01:50 +02:00
|
|
|
LOG_CRITICAL(Frontend, "Application requested unknown validation method. Method: {}",
|
|
|
|
static_cast<u32>(config.accept_mode));
|
2018-03-22 03:07:11 +01:00
|
|
|
UNREACHABLE();
|
|
|
|
}
|
|
|
|
|
|
|
|
return ValidationError::None;
|
2018-06-20 06:01:54 +02:00
|
|
|
}
|
2018-03-22 03:07:11 +01:00
|
|
|
|
2018-06-20 14:01:50 +02:00
|
|
|
ValidationError SoftwareKeyboard::ValidateButton(u8 button) const {
|
2018-03-22 03:07:11 +01:00
|
|
|
switch (config.button_config) {
|
|
|
|
case ButtonConfig::None:
|
|
|
|
return ValidationError::None;
|
|
|
|
case ButtonConfig::Single:
|
|
|
|
if (button != 0) {
|
|
|
|
return ValidationError::ButtonOutOfRange;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case ButtonConfig::Dual:
|
|
|
|
if (button > 1) {
|
|
|
|
return ValidationError::ButtonOutOfRange;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case ButtonConfig::Triple:
|
|
|
|
if (button > 2) {
|
|
|
|
return ValidationError::ButtonOutOfRange;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
UNREACHABLE();
|
|
|
|
}
|
|
|
|
return ValidationError::None;
|
|
|
|
}
|
|
|
|
|
2018-06-20 06:01:54 +02:00
|
|
|
ValidationError SoftwareKeyboard::Finalize(const std::string& text, u8 button) {
|
2018-03-22 03:07:11 +01:00
|
|
|
ValidationError error;
|
2018-06-20 06:01:54 +02:00
|
|
|
if ((error = ValidateInput(text)) != ValidationError::None) {
|
2018-03-22 03:07:11 +01:00
|
|
|
return error;
|
|
|
|
}
|
2018-06-20 06:01:54 +02:00
|
|
|
if ((error = ValidateButton(button)) != ValidationError::None) {
|
2018-03-22 03:07:11 +01:00
|
|
|
return error;
|
|
|
|
}
|
|
|
|
data = {text, button};
|
2018-06-20 14:01:50 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void DefaultCitraKeyboard::Setup(const Frontend::KeyboardConfig* config) {
|
|
|
|
SoftwareKeyboard::Setup(config);
|
|
|
|
switch (this->config.button_config) {
|
|
|
|
case ButtonConfig::None:
|
|
|
|
case ButtonConfig::Single:
|
|
|
|
Finalize("Citra", 0);
|
|
|
|
break;
|
|
|
|
case ButtonConfig::Dual:
|
|
|
|
Finalize("Citra", 1);
|
|
|
|
break;
|
|
|
|
case ButtonConfig::Triple:
|
|
|
|
Finalize("Citra", 2);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
UNREACHABLE();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void RegisterSoftwareKeyboard(std::shared_ptr<SoftwareKeyboard> applet) {
|
|
|
|
Core::System::GetInstance().RegisterSoftwareKeyboard(applet);
|
|
|
|
}
|
|
|
|
|
|
|
|
std::shared_ptr<SoftwareKeyboard> GetRegisteredSoftwareKeyboard() {
|
|
|
|
return Core::System::GetInstance().GetSoftwareKeyboard();
|
2018-03-22 03:07:11 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
} // namespace Frontend
|