full redesign.

This commit is contained in:
w1naenator 2025-04-20 01:16:35 +03:00
parent 22145d2b0a
commit 7bf3f54b38
9 changed files with 1095 additions and 763 deletions

View File

@ -1,5 +1,8 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project // ime_dialog_ui.cpp
// SPDX-License-Identifier: GPL-2.0-or-later // ----------------------------------------------------------
// Full implementation of IME dialog UI with onscreen keyboard
// (all original logic intact, bugs fixed).
// ----------------------------------------------------------
#include <cwchar> #include <cwchar>
#include <string> #include <string>
@ -10,25 +13,52 @@
#include "common/logging/log.h" #include "common/logging/log.h"
#include "core/libraries/ime/ime_dialog.h" #include "core/libraries/ime/ime_dialog.h"
#include "core/libraries/ime/ime_dialog_ui.h" #include "core/libraries/ime/ime_dialog_ui.h"
#include "core/libraries/ime/ime_keyboard_ui.h"
#include "core/tls.h" #include "core/tls.h"
#include "imgui/imgui_std.h" #include "imgui/imgui_std.h"
#include "ime_keyboard_layouts.h" // c16rtomb, layout tables
#include "ime_keyboard_ui.h" // DrawVirtualKeyboard, Utf8SafeBackspace
using namespace ImGui; using namespace ImGui;
/* small helper for the OK/Cancel buttons */
static constexpr ImVec2 BUTTON_SIZE{100.0f, 30.0f}; static constexpr ImVec2 BUTTON_SIZE{100.0f, 30.0f};
/* convert palette colour from Orbis struct to ImGui format */
static ImU32 ConvertColor(const Libraries::ImeDialog::OrbisImeColor& c) {
return IM_COL32(c.r, c.g, c.b, c.a);
}
/*─────────────────────────────────────────────────────────────*
* Libraries::ImeDialog implementation
**/
namespace Libraries::ImeDialog { namespace Libraries::ImeDialog {
/* ----------------------------------------------------------
* classstatic pointer single definition
* ----------------------------------------------------------*/
ImeDialogUi* ImeDialogUi::g_activeImeDialogUi = nullptr;
/* ----------------------------------------------------------
* keyboardtodialog event bridge
* ----------------------------------------------------------*/
static void KeyboardCallbackBridge(const VirtualKeyEvent* evt) {
if (ImeDialogUi::g_activeImeDialogUi && evt)
ImeDialogUi::g_activeImeDialogUi->OnVirtualKeyEvent(evt);
}
/*─────────────────────────────────────────────────────────────*
* ImeDialogState : constructors, helpers
**/
ImeDialogState::ImeDialogState(const OrbisImeDialogParam* param, ImeDialogState::ImeDialogState(const OrbisImeDialogParam* param,
const OrbisImeParamExtended* extended) { const OrbisImeParamExtended* extended) {
if (!param) { if (!param)
return; return;
}
/* basic param copy */
user_id = param->user_id; user_id = param->user_id;
is_multi_line = True(param->option & OrbisImeDialogOption::Multiline); is_multi_line = True(param->option & OrbisImeDialogOption::Multiline);
is_numeric = param->type == OrbisImeType::Number; is_numeric = (param->type == OrbisImeType::Number);
type = param->type; type = param->type;
enter_label = param->enter_label; enter_label = param->enter_label;
text_filter = param->filter; text_filter = param->filter;
@ -36,6 +66,35 @@ ImeDialogState::ImeDialogState(const OrbisImeDialogParam* param,
max_text_length = param->max_text_length; max_text_length = param->max_text_length;
text_buffer = param->input_text_buffer; text_buffer = param->input_text_buffer;
/* default keyboard style */
has_custom_kb_style = false;
custom_kb_style.layout_width = 485.0f;
custom_kb_style.layout_height = 200.0f;
custom_kb_style.key_spacing = 2.0f;
custom_kb_style.color_text = IM_COL32(225, 225, 225, 255);
custom_kb_style.color_line = IM_COL32(88, 88, 88, 255);
custom_kb_style.color_button_default = IM_COL32(35, 35, 35, 255);
custom_kb_style.color_button_function = IM_COL32(50, 50, 50, 255);
custom_kb_style.color_special = IM_COL32(0, 140, 200, 255);
custom_kb_style.color_button_symbol = IM_COL32(60, 60, 60, 255);
custom_kb_style.use_button_symbol_color = false;
/* optional extended palette */
if (extended) {
custom_kb_style.layout_width = 600.0f;
custom_kb_style.layout_height = 220.0f;
custom_kb_style.key_spacing = 3.0f;
custom_kb_style.color_text = ConvertColor(extended->color_text);
custom_kb_style.color_line = ConvertColor(extended->color_line);
custom_kb_style.color_button_default = ConvertColor(extended->color_button_default);
custom_kb_style.color_button_function = ConvertColor(extended->color_button_function);
custom_kb_style.color_button_symbol = ConvertColor(extended->color_button_symbol);
custom_kb_style.color_special = ConvertColor(extended->color_special);
custom_kb_style.use_button_symbol_color = true;
has_custom_kb_style = true;
}
/* UTF16 → UTF8 conversions */
if (param->title) { if (param->title) {
std::size_t title_len = std::char_traits<char16_t>::length(param->title); std::size_t title_len = std::char_traits<char16_t>::length(param->title);
title.resize(title_len * 4 + 1); title.resize(title_len * 4 + 1);
@ -167,12 +226,20 @@ bool ImeDialogState::ConvertUTF8ToOrbis(const char* utf8_text, std::size_t utf8_
return true; return true;
} }
/*─────────────────────────────────────────────────────────────*
* ImeDialogUi : constructor / destructor / move
**/
ImeDialogUi::ImeDialogUi(ImeDialogState* state, OrbisImeDialogStatus* status, ImeDialogUi::ImeDialogUi(ImeDialogState* state, OrbisImeDialogStatus* status,
OrbisImeDialogResult* result) OrbisImeDialogResult* result)
: state(state), status(status), result(result) { : state(state), status(status), result(result) {
if (state && *status == OrbisImeDialogStatus::Running) { if (state && *status == OrbisImeDialogStatus::Running) {
AddLayer(this); AddLayer(this);
ImeDialogUi::g_activeImeDialogUi = this;
}
if (state && state->has_custom_kb_style) {
kb_style = state->custom_kb_style;
} }
} }
@ -180,6 +247,10 @@ ImeDialogUi::~ImeDialogUi() {
std::scoped_lock lock(draw_mutex); std::scoped_lock lock(draw_mutex);
Free(); Free();
if (ImeDialogUi::g_activeImeDialogUi == this) {
ImeDialogUi::g_activeImeDialogUi = nullptr;
}
} }
ImeDialogUi::ImeDialogUi(ImeDialogUi&& other) noexcept ImeDialogUi::ImeDialogUi(ImeDialogUi&& other) noexcept
@ -191,8 +262,9 @@ ImeDialogUi::ImeDialogUi(ImeDialogUi&& other) noexcept
other.status = nullptr; other.status = nullptr;
other.result = nullptr; other.result = nullptr;
if (state && *status == OrbisImeDialogStatus::Running) { if (state && status && *status == OrbisImeDialogStatus::Running) {
AddLayer(this); AddLayer(this);
ImeDialogUi::g_activeImeDialogUi = this;
} }
} }
@ -204,12 +276,14 @@ ImeDialogUi& ImeDialogUi::operator=(ImeDialogUi&& other) {
status = other.status; status = other.status;
result = other.result; result = other.result;
first_render = other.first_render; first_render = other.first_render;
other.state = nullptr; other.state = nullptr;
other.status = nullptr; other.status = nullptr;
other.result = nullptr; other.result = nullptr;
if (state && *status == OrbisImeDialogStatus::Running) { if (state && status && *status == OrbisImeDialogStatus::Running) {
AddLayer(this); AddLayer(this);
ImeDialogUi::g_activeImeDialogUi = this;
} }
return *this; return *this;
@ -219,6 +293,9 @@ void ImeDialogUi::Free() {
RemoveLayer(this); RemoveLayer(this);
} }
/*─────────────────────────────────────────────────────────────*
* ImeDialogUi : main ImGui draw routine
**/
void ImeDialogUi::Draw() { void ImeDialogUi::Draw() {
std::unique_lock lock{draw_mutex}; std::unique_lock lock{draw_mutex};
@ -235,12 +312,10 @@ void ImeDialogUi::Draw() {
ImVec2 window_size; ImVec2 window_size;
const float keyboard_height = 200.0f;
if (state->is_multi_line) { if (state->is_multi_line) {
window_size = {500.0f, 300.0f + keyboard_height}; window_size = {500.0f, 500.0f};
} else { } else {
window_size = {500.0f, 150.0f + keyboard_height}; window_size = {500.0f, 350.0f};
} }
CentralizeNextWindow(); CentralizeNextWindow();
@ -254,157 +329,244 @@ void ImeDialogUi::Draw() {
if (Begin("IME Dialog##ImeDialog", nullptr, if (Begin("IME Dialog##ImeDialog", nullptr,
ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoSavedSettings)) { ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoSavedSettings)) {
DrawPrettyBackground(); DrawPrettyBackground();
/* ---------- title ---------- */
if (!state->title.empty()) { if (!state->title.empty()) {
SetCursorPosX(20.0f);
SetWindowFontScale(1.7f); SetWindowFontScale(1.7f);
TextUnformatted(state->title.data()); TextUnformatted(state->title.data());
SetWindowFontScale(1.0f); SetWindowFontScale(1.0f);
} }
/* ---------- input box ---------- */
if (state->is_multi_line) { if (state->is_multi_line) {
DrawMultiLineInputText(); DrawMultiLineInputText();
} else { } else {
DrawInputText(); DrawInputText();
} }
DrawKeyboard();
SetCursorPosY(GetCursorPosY() + 10.0f); /* ---------- dummy prediction bar with Cancel button ---------- */
DrawPredictionBarAnCancelButton();
const char* button_text; /* ---------- onscreen keyboard ---------- */
DrawVirtualKeyboardSection();
switch (state->enter_label) { /* ---------- OK / Cancel buttons ---------- */
case OrbisImeEnterLabel::Go: /* {
button_text = "Go##ImeDialogOK"; SetCursorPosY(GetCursorPosY() + 10.0f);
break; const char* ok_lbl = "OK##ImeDialogOK";
case OrbisImeEnterLabel::Search: switch (state->enter_label) {
button_text = "Search##ImeDialogOK"; case OrbisImeEnterLabel::Go:
break; ok_lbl = "Go##ImeDialogOK";
case OrbisImeEnterLabel::Send: break;
button_text = "Send##ImeDialogOK"; case OrbisImeEnterLabel::Search:
break; ok_lbl = "Search##ImeDialogOK";
case OrbisImeEnterLabel::Default: break;
default: case OrbisImeEnterLabel::Send:
button_text = "OK##ImeDialogOK"; ok_lbl = "Send##ImeDialogOK";
break; break;
} default:
break;
}
float button_spacing = 10.0f; float spacing = 10.0f;
float total_button_width = BUTTON_SIZE.x * 2 + button_spacing; float total_w = BUTTON_SIZE.x * 2 + spacing;
float button_start_pos = (window_size.x - total_button_width) / 2.0f; float x_start = (window_size.x - total_w) / 2.0f;
SetCursorPosX(x_start);
SetCursorPosX(button_start_pos); if (Button(ok_lbl, BUTTON_SIZE) ||
(!state->is_multi_line && IsKeyPressed(ImGuiKey_Enter))) {
*status = OrbisImeDialogStatus::Finished;
result->endstatus = OrbisImeDialogEndStatus::Ok;
}
if (Button(button_text, BUTTON_SIZE) || SameLine(0.0f, spacing);
(!state->is_multi_line && IsKeyPressed(ImGuiKey_Enter))) {
*status = OrbisImeDialogStatus::Finished;
result->endstatus = OrbisImeDialogEndStatus::Ok;
}
SameLine(0.0f, button_spacing); if (Button("Cancel##ImeDialogCancel", BUTTON_SIZE)) {
*status = OrbisImeDialogStatus::Finished;
result->endstatus = OrbisImeDialogEndStatus::UserCanceled;
}
}*/
if (Button("Cancel##ImeDialogCancel", BUTTON_SIZE)) { End();
*status = OrbisImeDialogStatus::Finished;
result->endstatus = OrbisImeDialogEndStatus::UserCanceled;
}
} }
End();
first_render = false; first_render = false;
} }
/*─────────────────────────────────────────────────────────────*
* helper draw functions (unchanged)
**/
void ImeDialogUi::DrawInputText() { void ImeDialogUi::DrawInputText() {
ImVec2 input_size = {GetWindowWidth() - 40.0f, 0.0f}; ImVec2 size(GetWindowWidth() - 40.0f, 0.0f);
SetCursorPosX(20.0f); SetCursorPosX(20.0f);
if (first_render) { if (first_render)
SetKeyboardFocusHere(); SetKeyboardFocusHere();
}
const char* placeholder = state->placeholder.empty() ? nullptr : state->placeholder.data(); const char* ph = state->placeholder.empty() ? nullptr : state->placeholder.data();
if (InputTextEx("##ImeDialogInput", placeholder, state->current_text.begin(), if (InputTextEx("##ImeDialogInput", ph, state->current_text.begin(), state->max_text_length,
state->max_text_length, input_size, ImGuiInputTextFlags_CallbackCharFilter, size, ImGuiInputTextFlags_CallbackCharFilter, InputTextCallback, this))
InputTextCallback, this)) {
state->input_changed = true; state->input_changed = true;
}
} }
void ImeDialogUi::DrawMultiLineInputText() { void ImeDialogUi::DrawMultiLineInputText() {
ImVec2 input_size = {GetWindowWidth() - 40.0f, 200.0f}; ImVec2 size(GetWindowWidth() - 40.0f, 200.0f);
SetCursorPosX(20.0f); SetCursorPosX(20.0f);
ImGuiInputTextFlags flags = ImGuiInputTextFlags_CallbackCharFilter | ImGuiInputTextFlags flags = ImGuiInputTextFlags_CallbackCharFilter |
static_cast<ImGuiInputTextFlags>(ImGuiInputTextFlags_Multiline); static_cast<ImGuiInputTextFlags>(ImGuiInputTextFlags_Multiline);
if (first_render) { if (first_render)
SetKeyboardFocusHere(); SetKeyboardFocusHere();
}
const char* placeholder = state->placeholder.empty() ? nullptr : state->placeholder.data(); const char* ph = state->placeholder.empty() ? nullptr : state->placeholder.data();
if (InputTextEx("##ImeDialogInput", placeholder, state->current_text.begin(), if (InputTextEx("##ImeDialogInput", ph, state->current_text.begin(), state->max_text_length,
state->max_text_length, input_size, flags, InputTextCallback, this)) { size, flags, InputTextCallback, this))
state->input_changed = true; state->input_changed = true;
}
}
void ImeDialogUi::DrawKeyboard() {
static KeyboardMode kb_mode = KeyboardMode::Letters1;
static bool shift_enabled = false;
static bool has_logged = false;
if (!has_logged) {
LOG_INFO(Lib_ImeDialog, "Virtual keyboard used from ImeDialog");
has_logged = true;
}
bool done_pressed = false;
DrawVirtualKeyboard(state->current_text.begin(), state->max_text_length * 4,
&state->input_changed, kb_mode, shift_enabled, &done_pressed);
if (done_pressed) {
*status = OrbisImeDialogStatus::Finished;
result->endstatus = OrbisImeDialogEndStatus::Ok;
}
} }
int ImeDialogUi::InputTextCallback(ImGuiInputTextCallbackData* data) { int ImeDialogUi::InputTextCallback(ImGuiInputTextCallbackData* data) {
ImeDialogUi* ui = static_cast<ImeDialogUi*>(data->UserData); ImeDialogUi* ui = static_cast<ImeDialogUi*>(data->UserData);
ASSERT(ui); ASSERT(ui);
// Should we filter punctuation? /* numeric filter */
if (ui->state->is_numeric && (data->EventChar < '0' || data->EventChar > '9') && if (ui->state->is_numeric && (data->EventChar < '0' || data->EventChar > '9') &&
data->EventChar != '\b' && data->EventChar != ',' && data->EventChar != '.') { data->EventChar != '\b' && data->EventChar != ',' && data->EventChar != '.')
return 1; return 1;
}
if (!ui->state->keyboard_filter) { if (!ui->state->keyboard_filter)
return 0; return 0;
}
// ImGui encodes ImWchar32 as multi-byte UTF-8 characters char* ev_char = reinterpret_cast<char*>(&data->EventChar);
char* event_char = reinterpret_cast<char*>(&data->EventChar);
// Call the keyboard filter OrbisImeKeycode src{
OrbisImeKeycode src_keycode = {
.keycode = 0, .keycode = 0,
.character = 0, .character = 0,
.status = 1, // ??? 1 = key pressed, 0 = key released .status = 1,
.type = OrbisImeKeyboardType::ENGLISH_US, // TODO set this to the correct value (maybe use .type = OrbisImeKeyboardType::ENGLISH_US,
// the current language?)
.user_id = ui->state->user_id, .user_id = ui->state->user_id,
.resource_id = 0, .resource_id = 0,
.timestamp = 0, .timestamp = 0,
}; };
if (!ui->state->ConvertUTF8ToOrbis(event_char, 4, &src_keycode.character, 1)) { if (!ui->state->ConvertUTF8ToOrbis(ev_char, 4, &src.character, 1))
LOG_ERROR(Lib_ImeDialog, "Failed to convert orbis char to utf8");
return 0; return 0;
} src.keycode = src.character;
src_keycode.keycode = src_keycode.character; // TODO set this to the correct value
u16 out_keycode;
u32 out_status;
ui->state->CallKeyboardFilter(&src_keycode, &out_keycode, &out_status);
// TODO. set the keycode
u16 out_code;
u32 out_stat;
ui->state->CallKeyboardFilter(&src, &out_code, &out_stat);
return 0; return 0;
} }
/*─────────────────────────────────────────────────────────────*
* helper draw functions (new)
**/
void ImeDialogUi::OnVirtualKeyEvent(const VirtualKeyEvent* evt) {
if (!evt || !state || !evt->key)
return;
const KeyEntry* key = evt->key;
/* Treat Repeat exactly like Down */
if (evt->type == VirtualKeyEventType::Down || evt->type == VirtualKeyEventType::Repeat) {
switch (key->type) {
case KeyType::Character: {
char utf8[8]{};
int n = c16rtomb(utf8, key->character);
if (n > 0)
state->AppendUtf8(utf8, (size_t)n);
break;
}
case KeyType::Function:
switch (key->keycode) {
case 0x08:
state->BackspaceUtf8();
break; // Backspace
case 0x0D:
*status = OrbisImeDialogStatus::Finished; // Enter
result->endstatus = OrbisImeDialogEndStatus::Ok;
break;
case KC_SYM1:
kb_mode = KeyboardMode::Symbols1;
break;
case KC_SYM2:
kb_mode = KeyboardMode::Symbols2;
break;
case KC_ACCENTS:
kb_mode = KeyboardMode::AccentLetters;
break;
case KC_LETTERS:
kb_mode = KeyboardMode::Letters;
break;
case 0x10: // Shift / Caps
case 0x105:
shift_state = (shift_state == ShiftState::None)
? ShiftState::Shift
: (shift_state == ShiftState::Shift ? ShiftState::CapsLock
: ShiftState::None);
break;
default:
break;
}
break;
default:
break;
}
}
/* Up is available if you need it later; currently ignored */
}
/* draw keyboard in a subID scope */
void ImeDialogUi::DrawVirtualKeyboardSection() {
ImGui::PushID("VirtualKeyboardSection");
DrawVirtualKeyboard(kb_mode, state->type, shift_state, kb_language, KeyboardCallbackBridge,
kb_style);
ImGui::PopID();
}
void ImeDialogUi::DrawPredictionBarAnCancelButton() {
const float pad = 5.0f;
const float width = kb_style.layout_width;
const float bar_h = 25.0f;
SetCursorPosX(0.0f);
ImVec2 p0 = GetCursorScreenPos();
ImVec2 p1 = ImVec2(p0.x + width - bar_h - 2 * pad, p0.y + bar_h);
// GetWindowDrawList()->AddRectFilled(p0, p1, IM_COL32(0, 0, 0, 255));
/* label */
// ImGui::SetCursorScreenPos(ImVec2(p0.x, p0.y));
// ImGui::PushStyleColor(ImGuiCol_Text, kb_style.color_text);
// Selectable("dummy prediction", false, 0, ImVec2(width - bar_h, bar_h));
// ImGui::PopStyleColor();
SetCursorPosX(pad);
ImGui::PushStyleColor(ImGuiCol_Button, IM_COL32(0, 0, 0, 255));
ImGui::PushStyleColor(ImGuiCol_ButtonHovered, IM_COL32(0, 0, 0, 255));
ImGui::PushStyleColor(ImGuiCol_ButtonActive, IM_COL32(0, 0, 0, 255));
ImGui::PushStyleColor(ImGuiCol_Text, kb_style.color_text);
if (ImGui::Button("predict", ImVec2(width - bar_h - 3 * pad, bar_h))) {
}
ImGui::PopStyleColor(4);
/* X button */
// ImGui::SameLine(width - bar_h);
ImGui::SetCursorScreenPos(ImVec2(p0.x + width - bar_h - pad, p0.y));
ImGui::PushStyleColor(ImGuiCol_Button, kb_style.color_button_function);
ImGui::PushStyleColor(ImGuiCol_ButtonHovered, kb_style.color_button_function);
ImGui::PushStyleColor(ImGuiCol_ButtonActive, kb_style.color_button_function);
ImGui::PushStyleColor(ImGuiCol_Text, kb_style.color_text);
if (ImGui::Button("", ImVec2(bar_h, bar_h))) {
*status = OrbisImeDialogStatus::Finished;
result->endstatus = OrbisImeDialogEndStatus::UserCanceled;
}
ImGui::PopStyleColor(4);
SetCursorPosX(0.0f);
SetCursorPosY(GetCursorPosY() + 5.0f);
}
} // namespace Libraries::ImeDialog } // namespace Libraries::ImeDialog

View File

@ -1,24 +1,29 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once #pragma once
#include <cstring> // for strncpy / memcpy
#include <mutex> #include <mutex>
#include <vector> #include <vector>
#include <imgui.h> #include <imgui.h>
#include "common/cstring.h" #include "common/cstring.h"
#include "common/types.h" #include "common/types.h"
#include "core/libraries/ime/ime_dialog.h" #include "core/libraries/ime/ime_dialog.h"
#include "core/libraries/ime/ime_keyboard_ui.h" #include "ime_keyboard_ui.h"
#include "imgui/imgui_layer.h" #include "imgui/imgui_layer.h"
#include <unordered_set>
namespace Libraries::ImeDialog { namespace Libraries::ImeDialog {
// Forward declaration so we can befriend it
class ImeDialogUi; class ImeDialogUi;
//---------------------------------------------------------------------
// ImeDialogState — holds the text and options for the IME dialog
//---------------------------------------------------------------------
class ImeDialogState final { class ImeDialogState final {
friend ImeDialogUi; friend class ImeDialogUi; // full access for the dialogUI layer
/*────────────────────────── private data ─────────────────────────*/
bool input_changed = false; bool input_changed = false;
s32 user_id{}; s32 user_id{};
@ -30,19 +35,75 @@ class ImeDialogState final {
OrbisImeExtKeyboardFilter keyboard_filter{}; OrbisImeExtKeyboardFilter keyboard_filter{};
u32 max_text_length{}; u32 max_text_length{};
char16_t* text_buffer{}; char16_t* text_buffer{};
std::vector<char> title; std::vector<char> title;
std::vector<char> placeholder; std::vector<char> placeholder;
// A character can hold up to 4 bytes in UTF-8 // One UTF8 codepoint may take up to 4 bytes
Common::CString<ORBIS_IME_DIALOG_MAX_TEXT_LENGTH * 4> current_text; Common::CString<ORBIS_IME_DIALOG_MAX_TEXT_LENGTH * 4> current_text;
public: // Optional custom keyboard style (from extended params)
ImeDialogState(const OrbisImeDialogParam* param = nullptr, bool has_custom_kb_style = false;
const OrbisImeParamExtended* extended = nullptr); KeyboardStyle custom_kb_style{};
ImeDialogState(const ImeDialogState& other) = delete;
ImeDialogState(ImeDialogState&& other) noexcept;
ImeDialogState& operator=(ImeDialogState&& other);
public:
/*──────────────── constructors / ruleoffive ────────────────*/
ImeDialogState(const OrbisImeDialogParam* param = nullptr,
const OrbisImeParamExtended* ext = nullptr);
ImeDialogState(const ImeDialogState&) = delete;
ImeDialogState(ImeDialogState&&) noexcept;
ImeDialogState& operator=(ImeDialogState&&);
/*──────────────────── public read helpers ───────────────────*/
bool IsMultiLine() const {
return is_multi_line;
}
bool IsNumeric() const {
return is_numeric;
}
u32 MaxTextLength() const {
return max_text_length;
}
const char* TitleUtf8() const {
return title.empty() ? nullptr : title.data();
}
const char* PlaceholderUtf8() const {
return placeholder.empty() ? nullptr : placeholder.data();
}
const char* CurrentTextUtf8() const {
return current_text.begin();
}
/*─────────────────── public write helpers ───────────────────*/
// Replace the whole text buffer
void SetTextUtf8(const char* utf8) {
if (!utf8)
return;
std::strncpy(current_text.begin(), utf8, current_text.capacity() - 1);
current_text[current_text.capacity() - 1] = '\0';
input_changed = true;
}
// Append raw UTF8 sequence of length 'len'
void AppendUtf8(const char* utf8, std::size_t len) {
if (!utf8 || len == 0)
return;
std::size_t old = std::strlen(current_text.begin());
if (old + len >= current_text.capacity())
return; // full: silently ignore
std::memcpy(current_text.begin() + old, utf8, len);
current_text[old + len] = '\0';
input_changed = true;
}
// Remove one UTF8 codepoint from the end (safe backspace)
void BackspaceUtf8() {
Utf8SafeBackspace(current_text.begin());
input_changed = true;
}
/*──────────────────────── IME support ───────────────────────*/
bool CopyTextToOrbisBuffer(); bool CopyTextToOrbisBuffer();
bool CallTextFilter(); bool CallTextFilter();
@ -50,12 +111,16 @@ private:
bool CallKeyboardFilter(const OrbisImeKeycode* src_keycode, u16* out_keycode, u32* out_status); bool CallKeyboardFilter(const OrbisImeKeycode* src_keycode, u16* out_keycode, u32* out_status);
bool ConvertOrbisToUTF8(const char16_t* orbis_text, std::size_t orbis_text_len, char* utf8_text, bool ConvertOrbisToUTF8(const char16_t* orbis_text, std::size_t orbis_text_len, char* utf8_text,
std::size_t native_text_len); std::size_t utf8_text_len);
bool ConvertUTF8ToOrbis(const char* native_text, std::size_t utf8_text_len, bool ConvertUTF8ToOrbis(const char* utf8_text, std::size_t utf8_text_len, char16_t* orbis_text,
char16_t* orbis_text, std::size_t orbis_text_len); std::size_t orbis_text_len);
}; };
//---------------------------------------------------------------------
// ImeDialogUi — draws the IME dialog & onscreen keyboard
//---------------------------------------------------------------------
class ImeDialogUi final : public ImGui::Layer { class ImeDialogUi final : public ImGui::Layer {
/*────────── private data ─────────*/
ImeDialogState* state{}; ImeDialogState* state{};
OrbisImeDialogStatus* status{}; OrbisImeDialogStatus* status{};
OrbisImeDialogResult* result{}; OrbisImeDialogResult* result{};
@ -64,24 +129,50 @@ class ImeDialogUi final : public ImGui::Layer {
std::mutex draw_mutex; std::mutex draw_mutex;
public: public:
// Global pointer to the active dialogUI (used by the callback bridge)
static ImeDialogUi* g_activeImeDialogUi;
/*───────── ctors / dtor ─────────*/
explicit ImeDialogUi(ImeDialogState* state = nullptr, OrbisImeDialogStatus* status = nullptr, explicit ImeDialogUi(ImeDialogState* state = nullptr, OrbisImeDialogStatus* status = nullptr,
OrbisImeDialogResult* result = nullptr); OrbisImeDialogResult* result = nullptr);
~ImeDialogUi() override; ~ImeDialogUi() override;
ImeDialogUi(const ImeDialogUi& other) = delete; ImeDialogUi(const ImeDialogUi&) = delete;
ImeDialogUi(ImeDialogUi&& other) noexcept; ImeDialogUi(ImeDialogUi&&) noexcept;
ImeDialogUi& operator=(ImeDialogUi&& other); ImeDialogUi& operator=(ImeDialogUi&&);
/*────────── main draw ───────────*/
void Draw() override; void Draw() override;
private: /*────────── keyboard events ─────*/
void Free(); void OnVirtualKeyEvent(const VirtualKeyEvent* evt);
private:
/*── helpers ─*/
void Free();
void DrawInputText(); void DrawInputText();
void DrawMultiLineInputText(); void DrawMultiLineInputText();
void DrawKeyboard();
static int InputTextCallback(ImGuiInputTextCallbackData* data); static int InputTextCallback(ImGuiInputTextCallbackData* data);
/*── keyboard section ─*/
KeyboardMode kb_mode = KeyboardMode::Letters;
ShiftState shift_state = ShiftState::None;
u64 kb_language = 0;
KeyboardStyle kb_style;
/* KeyboardStyle kb_style{
.layout_width = 500.0f,
.layout_height = 250.0f,
.key_spacing = 5.0f,
.color_text = IM_COL32(225,225,225,255),
.color_line = IM_COL32( 88, 88, 88,255),
.color_button_default = IM_COL32( 35, 35, 35,255),
.color_button_function = IM_COL32( 50, 50, 50,255),
.color_special = IM_COL32( 0,140,200,255),
.use_button_symbol_color= false,
.color_button_symbol = IM_COL32( 60, 60, 60,255),
};*/
void DrawVirtualKeyboardSection();
void DrawPredictionBarAnCancelButton();
}; };
} // namespace Libraries::ImeDialog } // namespace Libraries::ImeDialog

View File

@ -4,490 +4,463 @@
#include <imgui.h> #include <imgui.h>
#include "ime_keyboard_layouts.h" #include "ime_keyboard_layouts.h"
constexpr auto L1 = ImGuiNavInput_FocusPrev; int c16rtomb(char* out, char16_t ch) {
constexpr auto R1 = ImGuiNavInput_FocusNext; if (ch <= 0x7F) {
constexpr auto L2 = ImGuiNavInput_TweakSlow; out[0] = static_cast<char>(ch);
constexpr auto R2 = ImGuiNavInput_TweakFast; out[1] = '\0';
constexpr auto L3 = ImGuiNavInput_DpadLeft; // adjust if needed return 1;
constexpr auto R3 = ImGuiNavInput_DpadRight; // adjust if needed } else if (ch <= 0x7FF) {
constexpr auto Up = ImGuiNavInput_DpadUp; out[0] = 0xC0 | ((ch >> 6) & 0x1F);
constexpr auto Down = ImGuiNavInput_DpadDown; out[1] = 0x80 | (ch & 0x3F);
constexpr auto Left = ImGuiNavInput_DpadLeft; out[2] = '\0';
constexpr auto Right = ImGuiNavInput_DpadRight; return 2;
constexpr auto Cross = ImGuiNavInput_Activate; } else {
constexpr auto Circle = ImGuiNavInput_Menu; out[0] = 0xE0 | ((ch >> 12) & 0x0F);
constexpr auto Square = ImGuiNavInput_Cancel; out[1] = 0x80 | ((ch >> 6) & 0x3F);
constexpr auto Triangle = ImGuiNavInput_Input; out[2] = 0x80 | (ch & 0x3F);
constexpr auto TouchPad = ImGuiNavInput_Menu; // reuse if needed out[3] = '\0';
return 3;
}
}
const std::vector<KeyEntry> kLayoutEnLettersUppercase = {
// Row 0
{0x31, u'1', KeyType::Character, 0, 0, 1, 1, "1", "", {None, None}},
{0x32, u'2', KeyType::Character, 0, 1, 1, 1, "2", "", {None, None}},
{0x33, u'3', KeyType::Character, 0, 2, 1, 1, "3", "", {None, None}},
{0x34, u'4', KeyType::Character, 0, 3, 1, 1, "4", "", {None, None}},
{0x35, u'5', KeyType::Character, 0, 4, 1, 1, "5", "", {None, None}},
{0x36, u'6', KeyType::Character, 0, 5, 1, 1, "6", "", {None, None}},
{0x37, u'7', KeyType::Character, 0, 6, 1, 1, "7", "", {None, None}},
{0x38, u'8', KeyType::Character, 0, 7, 1, 1, "8", "", {None, None}},
{0x39, u'9', KeyType::Character, 0, 8, 1, 1, "9", "", {None, None}},
{0x30, u'0', KeyType::Character, 0, 9, 1, 1, "0", "", {None, None}},
const std::vector<Key> kLayoutEnLettersUppercase = {
// Row 1 // Row 1
{0, 0, 1, 1, "1", "", KeyType::Text, {}}, {0x51, u'Q', KeyType::Character, 1, 0, 1, 1, "Q", "", {None, None}},
{0, 1, 1, 1, "2", "", KeyType::Text, {}}, {0x57, u'W', KeyType::Character, 1, 1, 1, 1, "W", "", {None, None}},
{0, 2, 1, 1, "3", "", KeyType::Text, {}}, {0x45, u'E', KeyType::Character, 1, 2, 1, 1, "E", "", {None, None}},
{0, 3, 1, 1, "4", "", KeyType::Text, {}}, {0x52, u'R', KeyType::Character, 1, 3, 1, 1, "R", "", {None, None}},
{0, 4, 1, 1, "5", "", KeyType::Text, {}}, {0x54, u'T', KeyType::Character, 1, 4, 1, 1, "T", "", {None, None}},
{0, 5, 1, 1, "6", "", KeyType::Text, {}}, {0x59, u'Y', KeyType::Character, 1, 5, 1, 1, "Y", "", {None, None}},
{0, 6, 1, 1, "7", "", KeyType::Text, {}}, {0x55, u'U', KeyType::Character, 1, 6, 1, 1, "U", "", {None, None}},
{0, 7, 1, 1, "8", "", KeyType::Text, {}}, {0x49, u'I', KeyType::Character, 1, 7, 1, 1, "I", "", {None, None}},
{0, 8, 1, 1, "9", "", KeyType::Text, {}}, {0x4F, u'O', KeyType::Character, 1, 8, 1, 1, "O", "", {None, None}},
{0, 9, 1, 1, "0", "", KeyType::Text, {}}, {0x50, u'P', KeyType::Character, 1, 9, 1, 1, "P", "", {None, None}},
// Row 2 // Row 2
{1, 0, 1, 1, "Q", "", KeyType::Text, {}}, {0x41, u'A', KeyType::Character, 2, 0, 1, 1, "A", "", {None, None}},
{1, 1, 1, 1, "W", "", KeyType::Text, {}}, {0x53, u'S', KeyType::Character, 2, 1, 1, 1, "S", "", {None, None}},
{1, 2, 1, 1, "E", "", KeyType::Text, {}}, {0x44, u'D', KeyType::Character, 2, 2, 1, 1, "D", "", {None, None}},
{1, 3, 1, 1, "R", "", KeyType::Text, {}}, {0x46, u'F', KeyType::Character, 2, 3, 1, 1, "F", "", {None, None}},
{1, 4, 1, 1, "T", "", KeyType::Text, {}}, {0x47, u'G', KeyType::Character, 2, 4, 1, 1, "G", "", {None, None}},
{1, 5, 1, 1, "Y", "", KeyType::Text, {}}, {0x48, u'H', KeyType::Character, 2, 5, 1, 1, "H", "", {None, None}},
{1, 6, 1, 1, "U", "", KeyType::Text, {}}, {0x4A, u'J', KeyType::Character, 2, 6, 1, 1, "J", "", {None, None}},
{1, 7, 1, 1, "I", "", KeyType::Text, {}}, {0x4B, u'K', KeyType::Character, 2, 7, 1, 1, "K", "", {None, None}},
{1, 8, 1, 1, "O", "", KeyType::Text, {}}, {0x4C, u'L', KeyType::Character, 2, 8, 1, 1, "L", "", {None, None}},
{1, 9, 1, 1, "P", "", KeyType::Text, {}}, {0x22, u'"', KeyType::Character, 2, 9, 1, 1, "\"", "", {None, None}},
// Row 3 // Row 3
{2, 0, 1, 1, "A", "", KeyType::Text, {}}, {0x5A, u'Z', KeyType::Character, 3, 0, 1, 1, "Z", "", {None, None}},
{2, 1, 1, 1, "S", "", KeyType::Text, {}}, {0x58, u'X', KeyType::Character, 3, 1, 1, 1, "X", "", {None, None}},
{2, 2, 1, 1, "D", "", KeyType::Text, {}}, {0x43, u'C', KeyType::Character, 3, 2, 1, 1, "C", "", {None, None}},
{2, 3, 1, 1, "F", "", KeyType::Text, {}}, {0x56, u'V', KeyType::Character, 3, 3, 1, 1, "V", "", {None, None}},
{2, 4, 1, 1, "G", "", KeyType::Text, {}}, {0x42, u'B', KeyType::Character, 3, 4, 1, 1, "B", "", {None, None}},
{2, 5, 1, 1, "H", "", KeyType::Text, {}}, {0x4E, u'N', KeyType::Character, 3, 5, 1, 1, "N", "", {None, None}},
{2, 6, 1, 1, "J", "", KeyType::Text, {}}, {0x4D, u'M', KeyType::Character, 3, 6, 1, 1, "M", "", {None, None}},
{2, 7, 1, 1, "K", "", KeyType::Text, {}}, {0x2D, u'-', KeyType::Character, 3, 7, 1, 1, "-", "", {None, None}},
{2, 8, 1, 1, "L", "", KeyType::Text, {}}, {0x5F, u'_', KeyType::Character, 3, 8, 1, 1, "_", "", {None, None}},
{2, 9, 1, 1, "\"", "", KeyType::Text, {}}, {0x2F, u'/', KeyType::Character, 3, 9, 1, 1, "/", "", {None, None}},
// Row 4 // Row 4
{3, 0, 1, 1, "Z", "", KeyType::Text, {}}, {0x10, u'\0', KeyType::Function, 4, 0, 1, 1, "", "L2", {L2, None}},
{3, 1, 1, 1, "X", "", KeyType::Text, {}}, {KC_SYM1, u'\0', KeyType::Function, 4, 1, 1, 1, "@#:", "", {Triangle, None}}, // TODO:
{3, 2, 1, 1, "C", "", KeyType::Text, {}}, {KC_ACCENTS, u'\0', KeyType::Function, 4, 2, 1, 1, "à", "", {None, None}}, // TODO:
{3, 3, 1, 1, "V", "", KeyType::Text, {}}, {0x20, u' ', KeyType::Character, 4, 3, 4, 1, "Space", "", {Triangle, None}},
{3, 4, 1, 1, "B", "", KeyType::Text, {}}, {0x0000, u'\0', KeyType::Disabled, 4, 7, 1, 1, "", "", {None, None}},
{3, 5, 1, 1, "N", "", KeyType::Text, {}}, {0x08, u'\0', KeyType::Function, 4, 8, 2, 1, "", "", {Square, None}, true},
{3, 6, 1, 1, "M", "", KeyType::Text, {}},
{3, 7, 1, 1, "-", "", KeyType::Text, {}},
{3, 8, 1, 1, "_", "", KeyType::Text, {}},
{3, 9, 1, 1, "/", "", KeyType::Text, {}},
// Row 5 // Row 5
{4, 0, 1, 1, "", "L2", KeyType::Shift, {L2}}, {0xF020, u'\0', KeyType::Function, 5, 0, 1, 1, "", "", {Up, None}},
{4, 1, 1, 1, "@#:", "L2+△", KeyType::Symbols1Layout, {L3, Triangle}}, {0xF021, u'\0', KeyType::Function, 5, 1, 1, 1, "", "", {Down, None}},
{4, 2, 1, 1, "à", "L3", KeyType::AccentLettersLayout, {L3}}, {0xF022, u'\0', KeyType::Function, 5, 2, 1, 1, "", "L1", {L1, None}},
{4, 3, 4, 1, "Space", "", KeyType::Space, {Triangle}}, {0xF023, u'\0', KeyType::Function, 5, 3, 1, 1, "", "R1", {R1, None}},
//{4, 4, 4, 1, "Space", "△", KeyType::Space,{Triangle}}, {KC_KB, u'\0', KeyType::Function, 5, 4, 1, 1, "KB", "", {None, None}}, // TODO:
//{4, 5, 4, 1, "Space", "△", KeyType::Space,{Triangle}}, {KC_OPT, u'\0', KeyType::Function, 5, 5, 1, 1, "...", "", {None, None}},
//{4, 6, 4, 1, "Space", "△", KeyType::Space,{Triangle}}, {KC_GYRO, u'\0', KeyType::Function, 5, 6, 1, 1, "+/⊗", "R3", {R3, None}}, // TODO:
{4, 7, 1, 1, "", "", KeyType::Disabled, {}}, {0x0000, u'\0', KeyType::Disabled, 5, 7, 1, 1, "", "", {None, None}},
{4, 8, 2, 1, "", "", KeyType::Backspace, {Square}}, {0x0D, u'\r', KeyType::Function, 5, 8, 2, 1, "Done", "R2", {R2, None}},
//{4, 9, 2, 1, "⇦", "□", KeyType::Backspace,{Square}},
// Row 6
{5, 0, 1, 1, "", "", KeyType::CursorUp, {Up}},
{5, 1, 1, 1, "", "", KeyType::CursorDown, {Down}},
{5, 2, 1, 1, "", "L1", KeyType::CursorLeft, {L1}},
{5, 3, 1, 1, "", "R1", KeyType::CursorRight, {R1}},
{5, 4, 1, 1, "KB", "", KeyType::ToggleKeyboard, {}},
{5, 5, 1, 1, "...", "", KeyType::MoreOptions, {}},
{5, 6, 1, 1, "+/⊗", "R3", KeyType::ControllerAction, {R3}},
{5, 7, 1, 1, "", "", KeyType::Disabled, {}},
{5, 8, 2, 1, "Done", "R2", KeyType::Done, {R2}},
//{5, 9, 2, 1, "Done", "R2", KeyType::Done,{R2}},
}; };
const std::vector<Key> kLayoutEnLettersLowercase = { const std::vector<KeyEntry> kLayoutEnLettersLowercase = {
// Row 0
{0x31, u'1', KeyType::Character, 0, 0, 1, 1, "1", "", {None, None}},
{0x32, u'2', KeyType::Character, 0, 1, 1, 1, "2", "", {None, None}},
{0x33, u'3', KeyType::Character, 0, 2, 1, 1, "3", "", {None, None}},
{0x34, u'4', KeyType::Character, 0, 3, 1, 1, "4", "", {None, None}},
{0x35, u'5', KeyType::Character, 0, 4, 1, 1, "5", "", {None, None}},
{0x36, u'6', KeyType::Character, 0, 5, 1, 1, "6", "", {None, None}},
{0x37, u'7', KeyType::Character, 0, 6, 1, 1, "7", "", {None, None}},
{0x38, u'8', KeyType::Character, 0, 7, 1, 1, "8", "", {None, None}},
{0x39, u'9', KeyType::Character, 0, 8, 1, 1, "9", "", {None, None}},
{0x30, u'0', KeyType::Character, 0, 9, 1, 1, "0", "", {None, None}},
// Row 1 // Row 1
{0, 0, 1, 1, "1", "", KeyType::Text, {}}, {0x71, u'q', KeyType::Character, 1, 0, 1, 1, "q", "", {None, None}},
{0, 1, 1, 1, "2", "", KeyType::Text, {}}, {0x77, u'w', KeyType::Character, 1, 1, 1, 1, "w", "", {None, None}},
{0, 2, 1, 1, "3", "", KeyType::Text, {}}, {0x65, u'e', KeyType::Character, 1, 2, 1, 1, "e", "", {None, None}},
{0, 3, 1, 1, "4", "", KeyType::Text, {}}, {0x72, u'r', KeyType::Character, 1, 3, 1, 1, "r", "", {None, None}},
{0, 4, 1, 1, "5", "", KeyType::Text, {}}, {0x74, u't', KeyType::Character, 1, 4, 1, 1, "t", "", {None, None}},
{0, 5, 1, 1, "6", "", KeyType::Text, {}}, {0x79, u'y', KeyType::Character, 1, 5, 1, 1, "y", "", {None, None}},
{0, 6, 1, 1, "7", "", KeyType::Text, {}}, {0x75, u'u', KeyType::Character, 1, 6, 1, 1, "u", "", {None, None}},
{0, 7, 1, 1, "8", "", KeyType::Text, {}}, {0x69, u'i', KeyType::Character, 1, 7, 1, 1, "i", "", {None, None}},
{0, 8, 1, 1, "9", "", KeyType::Text, {}}, {0x6F, u'o', KeyType::Character, 1, 8, 1, 1, "o", "", {None, None}},
{0, 9, 1, 1, "0", "", KeyType::Text, {}}, {0x70, u'p', KeyType::Character, 1, 9, 1, 1, "p", "", {None, None}},
// Row 2 // Row 2
{1, 0, 1, 1, "q", "", KeyType::Text, {}}, {0x61, u'a', KeyType::Character, 2, 0, 1, 1, "a", "", {None, None}},
{1, 1, 1, 1, "w", "", KeyType::Text, {}}, {0x73, u's', KeyType::Character, 2, 1, 1, 1, "s", "", {None, None}},
{1, 2, 1, 1, "e", "", KeyType::Text, {}}, {0x64, u'd', KeyType::Character, 2, 2, 1, 1, "d", "", {None, None}},
{1, 3, 1, 1, "r", "", KeyType::Text, {}}, {0x66, u'f', KeyType::Character, 2, 3, 1, 1, "f", "", {None, None}},
{1, 4, 1, 1, "t", "", KeyType::Text, {}}, {0x67, u'g', KeyType::Character, 2, 4, 1, 1, "g", "", {None, None}},
{1, 5, 1, 1, "y", "", KeyType::Text, {}}, {0x68, u'h', KeyType::Character, 2, 5, 1, 1, "h", "", {None, None}},
{1, 6, 1, 1, "u", "", KeyType::Text, {}}, {0x6A, u'j', KeyType::Character, 2, 6, 1, 1, "j", "", {None, None}},
{1, 7, 1, 1, "i", "", KeyType::Text, {}}, {0x6B, u'k', KeyType::Character, 2, 7, 1, 1, "k", "", {None, None}},
{1, 8, 1, 1, "o", "", KeyType::Text, {}}, {0x6C, u'l', KeyType::Character, 2, 8, 1, 1, "l", "", {None, None}},
{1, 9, 1, 1, "p", "", KeyType::Text, {}}, {0x22, u'"', KeyType::Character, 2, 9, 1, 1, "\"", "", {None, None}},
// Row 3 // Row 3
{2, 0, 1, 1, "a", "", KeyType::Text, {}}, {0x7A, u'z', KeyType::Character, 3, 0, 1, 1, "z", "", {None, None}},
{2, 1, 1, 1, "s", "", KeyType::Text, {}}, {0x78, u'x', KeyType::Character, 3, 1, 1, 1, "x", "", {None, None}},
{2, 2, 1, 1, "d", "", KeyType::Text, {}}, {0x63, u'c', KeyType::Character, 3, 2, 1, 1, "c", "", {None, None}},
{2, 3, 1, 1, "f", "", KeyType::Text, {}}, {0x76, u'v', KeyType::Character, 3, 3, 1, 1, "v", "", {None, None}},
{2, 4, 1, 1, "g", "", KeyType::Text, {}}, {0x62, u'b', KeyType::Character, 3, 4, 1, 1, "b", "", {None, None}},
{2, 5, 1, 1, "h", "", KeyType::Text, {}}, {0x6E, u'n', KeyType::Character, 3, 5, 1, 1, "n", "", {None, None}},
{2, 6, 1, 1, "j", "", KeyType::Text, {}}, {0x6D, u'm', KeyType::Character, 3, 6, 1, 1, "m", "", {None, None}},
{2, 7, 1, 1, "k", "", KeyType::Text, {}}, {0x2D, u'-', KeyType::Character, 3, 7, 1, 1, "-", "", {None, None}},
{2, 8, 1, 1, "l", "", KeyType::Text, {}}, {0x5F, u'_', KeyType::Character, 3, 8, 1, 1, "_", "", {None, None}},
{2, 9, 1, 1, "-", "", KeyType::Text, {}}, {0x2F, u'/', KeyType::Character, 3, 9, 1, 1, "/", "", {None, None}},
// Row 4 // Row 4
{3, 0, 1, 1, "z", "", KeyType::Text, {}}, {0x105, u'\0', KeyType::Function, 4, 0, 1, 1, "", "L2", {L2, None}},
{3, 1, 1, 1, "x", "", KeyType::Text, {}}, {KC_SYM1, u'\0', KeyType::Function, 4, 1, 1, 1, "@#:", "", {Triangle, None}}, // TODO
{3, 2, 1, 1, "c", "", KeyType::Text, {}}, {KC_ACCENTS, u'\0', KeyType::Function, 4, 2, 1, 1, "à", "", {None, None}}, // TODO
{3, 3, 1, 1, "v", "", KeyType::Text, {}}, {0x20, u' ', KeyType::Character, 4, 3, 4, 1, "Space", "", {Triangle, None}},
{3, 4, 1, 1, "b", "", KeyType::Text, {}}, {0x00, u'\0', KeyType::Disabled, 4, 7, 1, 1, "", "", {None, None}},
{3, 5, 1, 1, "n", "", KeyType::Text, {}}, {0x08, u'\0', KeyType::Function, 4, 8, 2, 1, "", "", {Square, None}, true},
{3, 6, 1, 1, "m", "", KeyType::Text, {}},
{3, 7, 1, 1, "@", "", KeyType::Text, {}},
{3, 8, 1, 1, ".", "", KeyType::Text, {}},
{3, 9, 1, 1, "_", "", KeyType::Text, {}},
// Row 5 // Row 5
{4, 0, 1, 1, "", "L2", KeyType::Shift, {L2}}, {0xF020, u'\0', KeyType::Function, 5, 0, 1, 1, "", "", {Up, None}},
{4, 1, 1, 1, "@#:", "L2+△", KeyType::Symbols1Layout, {L2, Triangle}}, {0xF021, u'\0', KeyType::Function, 5, 1, 1, 1, "", "", {Down, None}},
{4, 2, 1, 1, "à", "L3", KeyType::AccentLettersLayout, {L3}}, {0xF022, u'\0', KeyType::Function, 5, 2, 1, 1, "", "L1", {L1, None}},
{4, 3, 4, 1, "Space", "", KeyType::Space, {Triangle}}, {0xF023, u'\0', KeyType::Function, 5, 3, 1, 1, "", "R1", {R1, None}},
//{4, 4, 4, 1, "Space", "△", KeyType::Space, {Triangle}}, {KC_KB, u'\0', KeyType::Function, 5, 4, 1, 1, "KB", "", {None, None}}, // TODO
//{4, 5, 4, 1, "Space", "△", KeyType::Space, {Triangle}}, {KC_OPT, u'\0', KeyType::Function, 5, 5, 1, 1, "...", "", {None, None}}, // TODO
//{4, 6, 4, 1, "Space", "△", KeyType::Space, {Triangle}}, {KC_GYRO, u'\0', KeyType::Function, 5, 6, 1, 1, "+/⊗", "R3", {R3, None}}, // TODO
{4, 7, 1, 1, "", "", KeyType::Disabled, {}}, {0x0000, u'\0', KeyType::Disabled, 5, 7, 1, 1, "", "", {None, None}},
{4, 8, 2, 1, "", "", KeyType::Backspace, {Square}}, {0x0D, u'\r', KeyType::Function, 5, 8, 2, 1, "Done", "R2", {R2, None}},
//{4, 8, 2, 1, "⇦", "□", KeyType::Backspace, {Square}},
// Row 6
{5, 0, 1, 1, "", "", KeyType::CursorUp, {Up}},
{5, 1, 1, 1, "", "", KeyType::CursorDown, {Down}},
{5, 2, 1, 1, "", "L1", KeyType::CursorLeft, {L1}},
{5, 3, 1, 1, "", "R1", KeyType::CursorRight, {R1}},
{5, 4, 1, 1, "KB", "", KeyType::ToggleKeyboard, {}},
{5, 5, 1, 1, "...", "", KeyType::MoreOptions, {}},
{5, 6, 1, 1, "+/⊗", "R3", KeyType::ControllerAction, {R3}},
{5, 7, 1, 1, "", "", KeyType::Disabled, {}},
{5, 8, 2, 1, "Done", "R2", KeyType::Done, {R2}},
//{5, 9, 2, 1, "Done", "R2", KeyType::Done, {R2}},
};
// From PS5
const std::vector<Key> kLayoutEnSymbols1 = {
// Row 1
{0, 0, 1, 1, "!", "", KeyType::Text, {}},
{0, 1, 1, 1, "?", "", KeyType::Text, {}},
{0, 2, 1, 1, "\"", "", KeyType::Text, {}},
{0, 3, 1, 1, "'", "", KeyType::Text, {}},
{0, 4, 1, 1, "#", "", KeyType::Text, {}},
{0, 5, 1, 1, "%", "", KeyType::Text, {}},
{0, 6, 1, 1, "(", "", KeyType::Text, {}},
{0, 7, 1, 1, ")", "", KeyType::Text, {}},
{0, 8, 1, 1, "()", "", KeyType::Text, {}},
{0, 9, 1, 1, "/", "", KeyType::Text, {}},
// Row 2
{1, 0, 1, 1, "-", "", KeyType::Text, {}},
{1, 1, 1, 1, "_", "", KeyType::Text, {}},
{1, 2, 1, 1, ",", "", KeyType::Text, {}},
{1, 3, 1, 1, ".", "", KeyType::Text, {}},
{1, 4, 1, 1, ":", "", KeyType::Text, {}},
{1, 5, 1, 1, ";", "", KeyType::Text, {}},
{1, 6, 1, 1, "*", "", KeyType::Text, {}},
{1, 7, 1, 1, "&", "", KeyType::Text, {}},
{1, 8, 1, 1, "+", "", KeyType::Text, {}},
{1, 9, 1, 1, "=", "", KeyType::Text, {}},
// Row 3
{2, 0, 1, 1, "<", "", KeyType::Text, {}},
{2, 1, 1, 1, ">", "", KeyType::Text, {}},
{2, 2, 1, 1, "@", "", KeyType::Text, {}},
{2, 3, 1, 1, "[", "", KeyType::Text, {}},
{2, 4, 1, 1, "]", "", KeyType::Text, {}},
{2, 5, 1, 1, "[]", "", KeyType::Text, {}},
{2, 6, 1, 1, "{", "", KeyType::Text, {}},
{2, 7, 1, 1, "}", "", KeyType::Text, {}},
{2, 8, 1, 1, "{}", "", KeyType::Text, {}},
{2, 9, 1, 2, "", "", KeyType::Symbols2Layout, {}},
// Row 4
{3, 0, 1, 1, "\\", "", KeyType::Text, {}},
{3, 1, 1, 1, "|", "", KeyType::Text, {}},
{3, 2, 1, 1, "^", "", KeyType::Text, {}},
{3, 3, 1, 1, "`", "", KeyType::Text, {}},
{3, 4, 1, 1, "$", "", KeyType::Text, {}},
{3, 5, 1, 1, "", "", KeyType::Text, {}},
{3, 6, 1, 1, "£", "", KeyType::Text, {}},
{3, 7, 1, 1, "¥", "", KeyType::Text, {}},
{3, 8, 1, 1, "", "", KeyType::Text, {}},
//{3, 9, 1, 2, "→", "", KeyType::Symbols2Layout,{}},
// Row 5
{4, 0, 1, 1, "", "", KeyType::Disabled, {}},
{4, 1, 1, 1, "ABC", "L2+△", KeyType::LettersLayout, {L2, Triangle}},
{4, 2, 1, 1, "", "", KeyType::Disabled, {}},
{4, 3, 4, 1, "Space", "", KeyType::Space, {Triangle}},
//{4, 4, 4, 1, "Space", "△", KeyType::Space, {Triangle}},
//{4, 5, 4, 1, "Space", "△", KeyType::Space, {Triangle}},
//{4, 6, 4, 1, "Space", "△", KeyType::Space, {Triangle}},
{4, 7, 1, 1, "", "", KeyType::Disabled, {}},
{4, 8, 2, 1, "", "", KeyType::Backspace, {Square}},
//{4, 9, 2, 1, "⇦", "□", KeyType::Backspace, {Square}},
// Row 6
{5, 0, 1, 1, "", "", KeyType::CursorUp, {Up}},
{5, 1, 1, 1, "", "", KeyType::CursorDown, {Down}},
{5, 2, 1, 1, "", "L1", KeyType::CursorLeft, {L1}},
{5, 3, 1, 1, "", "R1", KeyType::CursorRight, {R1}},
{5, 4, 1, 1, "KB", "", KeyType::ToggleKeyboard, {}},
{5, 5, 1, 1, "...", "", KeyType::MoreOptions, {}},
{5, 6, 1, 1, "+/⊗", "R3", KeyType::ControllerAction, {R3}},
{5, 7, 1, 1, "", "", KeyType::Disabled, {}},
{5, 8, 2, 1, "Done", "R2", KeyType::Done, {R2}},
//{5, 9, 2, 1, "Done", "R2", KeyType::Done, {R2}},
}; };
// From PS5 // From PS5
const std::vector<Key> kLayoutEnSymbols2 = { const std::vector<KeyEntry> kLayoutEnSymbols1 = {
// Row 1 // Row 1
{0, 0, 1, 1, "", "", KeyType::Text, {}}, {0x21, u'!', KeyType::Character, 0, 0, 1, 1, "!", "", {None, None}},
{0, 1, 1, 1, "", "", KeyType::Text, {}}, {0x3F, u'?', KeyType::Character, 0, 1, 1, 1, "?", "", {None, None}},
{0, 2, 1, 1, "", "", KeyType::Text, {}}, {0x22, u'"', KeyType::Character, 0, 2, 1, 1, "\"", "", {None, None}},
{0, 3, 1, 1, "¡", "", KeyType::Text, {}}, {0x27, u'\'', KeyType::Character, 0, 3, 1, 1, "'", "", {None, None}},
{0, 4, 1, 1, "", "", KeyType::Text, {}}, {0x23, u'#', KeyType::Character, 0, 4, 1, 1, "#", "", {None, None}},
{0, 5, 1, 1, "¿", "", KeyType::Text, {}}, {0x25, u'%', KeyType::Character, 0, 5, 1, 1, "%", "", {None, None}},
{0, 6, 1, 1, "", "", KeyType::Text, {}}, {0x28, u'(', KeyType::Character, 0, 6, 1, 1, "(", "", {None, None}},
{0, 7, 1, 1, "~", "", KeyType::Text, {}}, {0x29, u')', KeyType::Character, 0, 7, 1, 1, ")", "", {None, None}},
{0, 8, 1, 1, "·", "", KeyType::Text, {}}, {0xF001, u'\0', KeyType::Function, 0, 8, 1, 1, "()", "", {None, None}},
{0, 9, 1, 1, "", "", KeyType::Disabled, {}}, {0x2F, u'/', KeyType::Character, 0, 9, 1, 1, "/", "", {None, None}},
// Row 2 // Row 2
{1, 0, 1, 1, "×", "", KeyType::Text, {}}, {0x2D, u'-', KeyType::Character, 1, 0, 1, 1, "-", "", {None, None}},
{1, 1, 1, 1, "÷", "", KeyType::Text, {}}, {0x5F, u'_', KeyType::Character, 1, 1, 1, 1, "_", "", {None, None}},
{1, 2, 1, 1, "", "", KeyType::Text, {}}, {0x2C, u',', KeyType::Character, 1, 2, 1, 1, ",", "", {None, None}},
{1, 3, 1, 1, "", "", KeyType::Text, {}}, {0x2E, u'.', KeyType::Character, 1, 3, 1, 1, ".", "", {None, None}},
{1, 4, 1, 1, "«", "", KeyType::Text, {}}, {0x3A, u':', KeyType::Character, 1, 4, 1, 1, ":", "", {None, None}},
{1, 5, 1, 1, "»", "", KeyType::Text, {}}, {0x3B, u';', KeyType::Character, 1, 5, 1, 1, ";", "", {None, None}},
{1, 6, 1, 1, "º", "", KeyType::Text, {}}, {0x2A, u'*', KeyType::Character, 1, 6, 1, 1, "*", "", {None, None}},
{1, 7, 1, 1, "ª", "", KeyType::Text, {}}, {0x26, u'&', KeyType::Character, 1, 7, 1, 1, "&", "", {None, None}},
{1, 8, 1, 1, "°", "", KeyType::Text, {}}, {0x2B, u'+', KeyType::Character, 1, 8, 1, 1, "+", "", {None, None}},
{1, 9, 1, 1, "§", "", KeyType::Text, {}}, {0x3D, u'=', KeyType::Character, 1, 9, 1, 1, "=", "", {None, None}},
// Row 3 // Row 3
{2, 0, 1, 2, "", "", KeyType::Symbols1Layout, {}}, {0x3C, u'<', KeyType::Character, 2, 0, 1, 1, "<", "", {None, None}},
{2, 1, 1, 1, "¦", "", KeyType::Text, {}}, {0x3E, u'>', KeyType::Character, 2, 1, 1, 1, ">", "", {None, None}},
{2, 2, 1, 1, "µ", "", KeyType::Text, {}}, {0x40, u'@', KeyType::Character, 2, 2, 1, 1, "@", "", {None, None}},
{2, 3, 1, 1, "¬", "", KeyType::Text, {}}, {0x5B, u'[', KeyType::Character, 2, 3, 1, 1, "[", "", {None, None}},
{2, 4, 1, 1, "¹", "", KeyType::Text, {}}, {0x5D, u']', KeyType::Character, 2, 4, 1, 1, "]", "", {None, None}},
{2, 5, 1, 1, "²", "", KeyType::Text, {}}, {0xF002, u'\0', KeyType::Function, 2, 5, 1, 1, "[]", "", {None, None}},
{2, 6, 1, 1, "³", "", KeyType::Text, {}}, {0x7B, u'{', KeyType::Character, 2, 6, 1, 1, "{", "", {None, None}},
{2, 7, 1, 1, "¼", "", KeyType::Text, {}}, {0x7D, u'}', KeyType::Character, 2, 7, 1, 1, "}", "", {None, None}},
{2, 8, 1, 1, "½", "", KeyType::Text, {}}, {0xF004, u'\0', KeyType::Function, 2, 8, 1, 1, "{}", "", {None, None}},
{2, 9, 1, 1, "¾", "", KeyType::Text, {}}, {KC_SYM2, u'\0', KeyType::Function, 2, 9, 1, 2, "", "", {None, None}},
// Row 4 // Row 4
//{3, 0, 1, 1, "←", "", KeyType::Symbols1Layout, {}}, {0x5C, u'\\', KeyType::Character, 3, 0, 1, 1, "\\", "", {None, None}},
{3, 1, 1, 1, "¢", "", KeyType::Text, {}}, {0x7C, u'|', KeyType::Character, 3, 1, 1, 1, "|", "", {None, None}},
{3, 2, 1, 1, "¤", "", KeyType::Text, {}}, {0x5E, u'^', KeyType::Character, 3, 2, 1, 1, "^", "", {None, None}},
{3, 3, 1, 1, "", "", KeyType::Text, {}}, // not sure {0x60, u'`', KeyType::Character, 3, 3, 1, 1, "`", "", {None, None}},
{3, 4, 1, 1, "", "", KeyType::Text, {}}, // not sure {0x24, u'$', KeyType::Character, 3, 4, 1, 1, "$", "", {None, None}},
{3, 5, 1, 1, "", "", KeyType::Text, {}}, // not sure {0x20AC, u'\u20AC', KeyType::Character, 3, 5, 1, 1, "", "", {None, None}},
{3, 6, 1, 1, "", "", KeyType::Text, {}}, // not sure {0x00A3, u'\u00A3', KeyType::Character, 3, 6, 1, 1, "£", "", {None, None}},
{3, 7, 1, 1, "", "", KeyType::Text, {}}, {0x00A5, u'\u00A5', KeyType::Character, 3, 7, 1, 1, "¥", "", {None, None}},
{3, 8, 1, 1, "", "", KeyType::Disabled, {}}, {0x20A9, u'\u20A9', KeyType::Character, 3, 8, 1, 1, "", "", {None, None}},
{3, 9, 1, 1, "", "", KeyType::Disabled, {}},
// Row 5 // Row 5
{4, 0, 1, 1, "", "", KeyType::Disabled, {}}, {0x0000, u'\0', KeyType::Disabled, 4, 0, 1, 1, "", "", {None, None}},
{4, 1, 1, 1, "ABC", "L2+△", KeyType::LettersLayout, {L2, Triangle}}, {KC_LETTERS, u'\0', KeyType::Function, 4, 1, 1, 1, "ABC", "L2+△", {L2, Triangle}}, // TODO:
{4, 2, 1, 1, "", "", KeyType::Disabled, {}}, {0x0000, u'\0', KeyType::Disabled, 4, 2, 1, 1, "", "", {None, None}},
{4, 3, 4, 1, "Space", "", KeyType::Space, {Triangle}}, {0x0020, u' ', KeyType::Character, 4, 3, 4, 1, "Space", "", {Triangle, None}},
//{4, 4, 4, 1, "Space", "△", KeyType::Space, {Triangle}}, {0x0000, u'\0', KeyType::Disabled, 4, 7, 1, 1, "", "", {None, None}},
//{4, 5, 4, 1, "Space", "△", KeyType::Space, {Triangle}}, {0x0008, u'\0', KeyType::Function, 4, 8, 2, 1, "", "", {Square, None}, true},
//{4, 6, 4, 1, "Space", "△", KeyType::Space, {Triangle}},
{4, 7, 1, 1, "", "", KeyType::Disabled, {}},
{4, 8, 2, 1, "", "", KeyType::Backspace, {Square}},
//{4, 9, 2, 1, "⇦", "□", KeyType::Backspace, {Square}},
// Row 6 // Row 6
{5, 0, 1, 1, "", "", KeyType::CursorUp, {Up}}, {0xF020, u'\0', KeyType::Function, 5, 0, 1, 1, "", "", {Up, None}},
{5, 1, 1, 1, "", "", KeyType::CursorDown, {Down}}, {0xF021, u'\0', KeyType::Function, 5, 1, 1, 1, "", "", {Down, None}},
{5, 2, 1, 1, "", "L1", KeyType::CursorLeft, {L1}}, {0xF022, u'\0', KeyType::Function, 5, 2, 1, 1, "", "L1", {L1, None}},
{5, 3, 1, 1, "", "R1", KeyType::CursorRight, {R1}}, {0xF023, u'\0', KeyType::Function, 5, 3, 1, 1, "", "R1", {R1, None}},
{5, 4, 1, 1, "KB", "", KeyType::ToggleKeyboard, {}}, {KC_KB, u'\0', KeyType::Function, 5, 4, 1, 1, "KB", "", {None, None}}, // TODO:
{5, 5, 1, 1, "...", "", KeyType::MoreOptions, {}}, {KC_OPT, u'\0', KeyType::Function, 5, 5, 1, 1, "...", "", {None, None}}, // TODO:
{5, 6, 1, 1, "+/⊗", "R3", KeyType::ControllerAction, {R3}}, {KC_GYRO, u'\0', KeyType::Function, 5, 6, 1, 1, "+/⊗", "R3", {R3, None}}, // TODO:
{5, 7, 1, 1, "", "", KeyType::Disabled, {}}, {0x0000, u'\0', KeyType::Disabled, 5, 7, 1, 1, "", "", {None, None}},
{5, 8, 2, 1, "Done", "R2", KeyType::Done, {R2}}, {0x000D, u'\r', KeyType::Function, 5, 8, 2, 1, "Done", "R2", {R2, None}},
//{5, 9, 2, 1, "Done", "R2", KeyType::Done, {R2}},
}; };
const std::vector<Key> kLayoutEnAccentLettersUppercase = { // From PS5
// Row 0 const std::vector<KeyEntry> kLayoutEnSymbols2 = {
{0, 0, 1, 1, "À", "", KeyType::Text, {}},
{0, 1, 1, 1, "Á", "", KeyType::Text, {}},
{0, 2, 1, 1, "Â", "", KeyType::Text, {}},
{0, 3, 1, 1, "Ã", "", KeyType::Text, {}},
{0, 4, 1, 1, "Ä", "", KeyType::Text, {}},
{0, 5, 1, 1, "Å", "", KeyType::Text, {}},
{0, 6, 1, 1, "Ą", "", KeyType::Text, {}},
{0, 7, 1, 1, "Æ", "", KeyType::Text, {}},
{0, 8, 1, 1, "Ç", "", KeyType::Text, {}},
{0, 9, 1, 1, "Ć", "", KeyType::Text, {}},
// Row 1 // Row 1
{1, 0, 1, 1, "È", "", KeyType::Text, {}}, {0x201C, u'', KeyType::Character, 0, 0, 1, 1, "", "", {None, None}},
{1, 1, 1, 1, "É", "", KeyType::Text, {}}, {0x201D, u'', KeyType::Character, 0, 1, 1, 1, "", "", {None, None}},
{1, 2, 1, 1, "Ê", "", KeyType::Text, {}}, {0x201E, u'', KeyType::Character, 0, 2, 1, 1, "", "", {None, None}},
{1, 3, 1, 1, "Ë", "", KeyType::Text, {}}, {0x00A1, u'¡', KeyType::Character, 0, 3, 1, 1, "¡", "", {None, None}},
{1, 4, 1, 1, "Ę", "", KeyType::Text, {}}, {0xF013, u'\0', KeyType::Function, 0, 4, 1, 1, "¡!", "", {None, None}},
{1, 5, 1, 1, "Ğ", "", KeyType::Text, {}}, {0x00BF, u'¿', KeyType::Character, 0, 5, 1, 1, "¿", "", {None, None}},
{1, 6, 1, 1, "Ì", "", KeyType::Text, {}}, {0xF014, u'\0', KeyType::Function, 0, 6, 1, 1, "¿?", "", {None, None}},
{1, 7, 1, 1, "Í", "", KeyType::Text, {}}, {0x007E, u'~', KeyType::Character, 0, 7, 1, 1, "~", "", {None, None}},
{1, 8, 1, 1, "Î", "", KeyType::Text, {}}, {0x00B7, u'·', KeyType::Character, 0, 8, 1, 1, "·", "", {None, None}},
{1, 9, 1, 1, "Ï", "", KeyType::Text, {}}, {0x0000, u'\0', KeyType::Disabled, 0, 9, 1, 1, "", "", {None, None}},
// Row 2 // Row 2
{2, 0, 1, 1, "İ", "", KeyType::Text, {}}, {0x00D7, u'×', KeyType::Character, 1, 0, 1, 1, "×", "", {None, None}},
{2, 1, 1, 1, "Ł", "", KeyType::Text, {}}, {0x00F7, u'÷', KeyType::Character, 1, 1, 1, 1, "÷", "", {None, None}},
{2, 2, 1, 1, "Ñ", "", KeyType::Text, {}}, {0x2039, u'', KeyType::Character, 1, 2, 1, 1, "", "", {None, None}},
{2, 3, 1, 1, "Ń", "", KeyType::Text, {}}, {0x203A, u'', KeyType::Character, 1, 3, 1, 1, "", "", {None, None}},
{2, 4, 1, 1, "Ò", "", KeyType::Text, {}}, {0x00AB, u'«', KeyType::Character, 1, 4, 1, 1, "«", "", {None, None}},
{2, 5, 1, 1, "Ó", "", KeyType::Text, {}}, {0x00BB, u'»', KeyType::Character, 1, 5, 1, 1, "»", "", {None, None}},
{2, 6, 1, 1, "Ô", "", KeyType::Text, {}}, {0x00BA, u'º', KeyType::Character, 1, 6, 1, 1, "º", "", {None, None}},
{2, 7, 1, 1, "Õ", "", KeyType::Text, {}}, {0x00AA, u'ª', KeyType::Character, 1, 7, 1, 1, "ª", "", {None, None}},
{2, 8, 1, 1, "Ö", "", KeyType::Text, {}}, {0x00B0, u'°', KeyType::Character, 1, 8, 1, 1, "°", "", {None, None}},
{2, 9, 1, 1, "Ø", "", KeyType::Text, {}}, {0x00A7, u'§', KeyType::Character, 1, 9, 1, 1, "§", "", {None, None}},
// Row 3 // Row 3
{3, 0, 1, 1, "Œ", "", KeyType::Text, {}}, {KC_SYM1, u'\0', KeyType::Function, 2, 0, 1, 2, "", "", {None, None}},
{3, 1, 1, 1, "Ś", "", KeyType::Text, {}}, {0x00A6, u'¦', KeyType::Character, 2, 1, 1, 1, "¦", "", {None, None}},
{3, 2, 1, 1, "Ş", "", KeyType::Text, {}}, {0x00B5, u'µ', KeyType::Character, 2, 2, 1, 1, "µ", "", {None, None}},
{3, 3, 1, 1, "Š", "", KeyType::Text, {}}, {0x00AC, u'¬', KeyType::Character, 2, 3, 1, 1, "¬", "", {None, None}},
{3, 4, 1, 1, "ß", "", KeyType::Text, {}}, {0x00B9, u'¹', KeyType::Character, 2, 4, 1, 1, "¹", "", {None, None}},
{3, 5, 1, 1, "Ù", "", KeyType::Text, {}}, {0x00B2, u'²', KeyType::Character, 2, 5, 1, 1, "²", "", {None, None}},
{3, 6, 1, 1, "Ú", "", KeyType::Text, {}}, {0x00B3, u'³', KeyType::Character, 2, 6, 1, 1, "³", "", {None, None}},
{3, 7, 1, 1, "Û", "", KeyType::Text, {}}, {0x00BC, u'¼', KeyType::Character, 2, 7, 1, 1, "¼", "", {None, None}},
{3, 8, 1, 1, "Ü", "", KeyType::Text, {}}, {0x00BD, u'½', KeyType::Character, 2, 8, 1, 1, "½", "", {None, None}},
{3, 9, 1, 1, "Ý", "", KeyType::Text, {}}, {0x00BE, u'¾', KeyType::Character, 2, 9, 1, 1, "¾", "", {None, None}},
// Row 4 // Row 4
{4, 0, 1, 1, "Ÿ", "", KeyType::Text, {}}, {0x00A2, u'¢', KeyType::Character, 3, 1, 1, 1, "¢", "", {None, None}},
{4, 1, 1, 1, "Ź", "", KeyType::Text, {}}, {0x00A4, u'¤', KeyType::Character, 3, 2, 1, 1, "¤", "", {None, None}},
{4, 2, 1, 1, "Ż", "", KeyType::Text, {}}, {0x2019, u'', KeyType::Character, 3, 3, 1, 1, "", "", {None, None}},
{4, 3, 1, 1, "Ž", "", KeyType::Text, {}}, {0x2018, u'', KeyType::Character, 3, 4, 1, 1, "", "", {None, None}},
{4, 4, 1, 1, "Ð", "", KeyType::Text, {}}, {0x201B, u'', KeyType::Character, 3, 5, 1, 1, "", "", {None, None}},
{4, 5, 1, 1, "Þ", "", KeyType::Text, {}}, {0x201A, u'', KeyType::Character, 3, 6, 1, 1, "", "", {None, None}},
{4, 6, 1, 1, "", "", KeyType::Disabled, {}}, {0x2116, u'', KeyType::Character, 3, 7, 1, 1, "", "", {None, None}},
{4, 7, 1, 1, "", "", KeyType::Disabled, {}}, {0x0000, u'\0', KeyType::Disabled, 3, 8, 1, 1, "", "", {None, None}},
{4, 8, 1, 1, "", "", KeyType::Disabled, {}}, {0x0000, u'\0', KeyType::Disabled, 3, 9, 1, 1, "", "", {None, None}},
{4, 9, 1, 1, "", "", KeyType::Disabled, {}},
// Row 5 // Row 5
{5, 0, 1, 1, "", "L2", KeyType::Shift, {L2}}, {0x0000, u'\0', KeyType::Disabled, 4, 0, 1, 1, "", "", {None, None}},
{5, 1, 1, 1, "@#:", "L2+△", KeyType::Symbols1Layout, {L3, Triangle}}, {KC_LETTERS, u'\0', KeyType::Function, 4, 1, 1, 1, "ABC", "L2+△", {L2, Triangle}},
{5, 2, 1, 1, "à", "L3", KeyType::AccentLettersLayout, {L3}}, {0x0000, u'\0', KeyType::Disabled, 4, 2, 1, 1, "", "", {None, None}},
{5, 3, 4, 1, "Space", "", KeyType::Space, {Triangle}}, {0x20, u' ', KeyType::Character, 4, 3, 4, 1, "Space", "", {Triangle, None}},
//{4, 4, 4, 1, "Space", "△", KeyType::Space,{Triangle}}, {0x0000, u'\0', KeyType::Disabled, 4, 7, 1, 1, "", "", {None, None}},
//{4, 5, 4, 1, "Space", "△", KeyType::Space,{Triangle}}, {0x08, u'\0', KeyType::Function, 4, 8, 2, 1, "", "", {Square, None}, true},
//{4, 6, 4, 1, "Space", "△", KeyType::Space,{Triangle}},
{4, 7, 1, 1, "", "", KeyType::Disabled, {}},
{5, 8, 2, 1, "", "", KeyType::Backspace, {Square}},
//{4, 9, 2, 1, "⇦", "□", KeyType::Backspace,{Square}},
// Row 6 // Row 6
{6, 0, 1, 1, "", "", KeyType::CursorUp, {Up}}, {0xF020, u'\0', KeyType::Function, 5, 0, 1, 1, "", "", {Up, None}},
{6, 1, 1, 1, "", "", KeyType::CursorDown, {Down}}, {0xF021, u'\0', KeyType::Function, 5, 1, 1, 1, "", "", {Down, None}},
{6, 2, 1, 1, "", "L1", KeyType::CursorLeft, {L1}}, {0xF022, u'\0', KeyType::Function, 5, 2, 1, 1, "", "L1", {L1, None}},
{6, 3, 1, 1, "", "R1", KeyType::CursorRight, {R1}}, {0xF023, u'\0', KeyType::Function, 5, 3, 1, 1, "", "R1", {R1, None}},
{6, 4, 1, 1, "KB", "", KeyType::ToggleKeyboard, {}}, {KC_KB, u'\0', KeyType::Function, 5, 4, 1, 1, "KB", "", {None, None}}, // TODO
{6, 5, 1, 1, "...", "", KeyType::MoreOptions, {}}, {KC_OPT, u'\0', KeyType::Function, 5, 5, 1, 1, "...", "", {None, None}}, // TODO
{6, 6, 1, 1, "+/⊗", "R3", KeyType::ControllerAction, {R3}}, {KC_GYRO, u'\0', KeyType::Function, 5, 6, 1, 1, "+/⊗", "R3", {R3, None}}, // TODO
{5, 7, 1, 1, "", "", KeyType::Disabled, {}}, {0x0000, u'\0', KeyType::Disabled, 5, 7, 1, 1, "", "", {None, None}},
{6, 8, 2, 1, "Done", "R2", KeyType::Done, {R2}}, {0x0D, u'\r', KeyType::Function, 5, 8, 2, 1, "Done", "R2", {R2, None}},
//{5, 9, 2, 1, "Done", "R2", KeyType::Done,{R2}},
}; };
const std::vector<Key> kLayoutEnAccentLettersLowercase = { const std::vector<KeyEntry> kLayoutEnAccentLettersUppercase = {
// Row 0 // Row 0
{0, 0, 1, 1, "à", "", KeyType::Text, {}}, {0x00C0, u'À', KeyType::Character, 0, 0, 1, 1, "À", "", {None, None}},
{0, 1, 1, 1, "á", "", KeyType::Text, {}}, {0x00C1, u'Á', KeyType::Character, 0, 1, 1, 1, "Á", "", {None, None}},
{0, 2, 1, 1, "â", "", KeyType::Text, {}}, {0x00C2, u'Â', KeyType::Character, 0, 2, 1, 1, "Â", "", {None, None}},
{0, 3, 1, 1, "ã", "", KeyType::Text, {}}, {0x00C3, u'Ã', KeyType::Character, 0, 3, 1, 1, "Ã", "", {None, None}},
{0, 4, 1, 1, "ä", "", KeyType::Text, {}}, {0x00C4, u'Ä', KeyType::Character, 0, 4, 1, 1, "Ä", "", {None, None}},
{0, 5, 1, 1, "å", "", KeyType::Text, {}}, {0x00C5, u'Å', KeyType::Character, 0, 5, 1, 1, "Å", "", {None, None}},
{0, 6, 1, 1, "ą", "", KeyType::Text, {}}, {0x0104, u'Ą', KeyType::Character, 0, 6, 1, 1, "Ą", "", {None, None}},
{0, 7, 1, 1, "æ", "", KeyType::Text, {}}, {0x00C6, u'Æ', KeyType::Character, 0, 7, 1, 1, "Æ", "", {None, None}},
{0, 8, 1, 1, "ç", "", KeyType::Text, {}}, {0x00C7, u'Ç', KeyType::Character, 0, 8, 1, 1, "Ç", "", {None, None}},
{0, 9, 1, 1, "ć", "", KeyType::Text, {}}, {0x0106, u'Ć', KeyType::Character, 0, 9, 1, 1, "Ć", "", {None, None}},
// Row 1 // Row 1
{1, 0, 1, 1, "è", "", KeyType::Text, {}}, {0x00C8, u'È', KeyType::Character, 1, 0, 1, 1, "È", "", {None, None}},
{1, 1, 1, 1, "é", "", KeyType::Text, {}}, {0x00C9, u'É', KeyType::Character, 1, 1, 1, 1, "É", "", {None, None}},
{1, 2, 1, 1, "ê", "", KeyType::Text, {}}, {0x00CA, u'Ê', KeyType::Character, 1, 2, 1, 1, "Ê", "", {None, None}},
{1, 3, 1, 1, "ë", "", KeyType::Text, {}}, {0x00CB, u'Ë', KeyType::Character, 1, 3, 1, 1, "Ë", "", {None, None}},
{1, 4, 1, 1, "ę", "", KeyType::Text, {}}, {0x0118, u'Ę', KeyType::Character, 1, 4, 1, 1, "Ę", "", {None, None}},
{1, 5, 1, 1, "ğ", "", KeyType::Text, {}}, {0x011E, u'Ğ', KeyType::Character, 1, 5, 1, 1, "Ğ", "", {None, None}},
{1, 6, 1, 1, "ì", "", KeyType::Text, {}}, {0x00CC, u'Ì', KeyType::Character, 1, 6, 1, 1, "Ì", "", {None, None}},
{1, 7, 1, 1, "í", "", KeyType::Text, {}}, {0x00CD, u'Í', KeyType::Character, 1, 7, 1, 1, "Í", "", {None, None}},
{1, 8, 1, 1, "î", "", KeyType::Text, {}}, {0x00CE, u'Î', KeyType::Character, 1, 8, 1, 1, "Î", "", {None, None}},
{1, 9, 1, 1, "ï", "", KeyType::Text, {}}, {0x00CF, u'Ï', KeyType::Character, 1, 9, 1, 1, "Ï", "", {None, None}},
// Row 2 // Row 2
{2, 0, 1, 1, "ı", "", KeyType::Text, {}}, {0x0130, u'İ', KeyType::Character, 2, 0, 1, 1, "İ", "", {None, None}},
{2, 1, 1, 1, "ł", "", KeyType::Text, {}}, {0x0141, u'Ł', KeyType::Character, 2, 1, 1, 1, "Ł", "", {None, None}},
{2, 2, 1, 1, "ñ", "", KeyType::Text, {}}, {0x00D1, u'Ñ', KeyType::Character, 2, 2, 1, 1, "Ñ", "", {None, None}},
{2, 3, 1, 1, "ń", "", KeyType::Text, {}}, {0x0143, u'Ń', KeyType::Character, 2, 3, 1, 1, "Ń", "", {None, None}},
{2, 4, 1, 1, "ò", "", KeyType::Text, {}}, {0x00D2, u'Ò', KeyType::Character, 2, 4, 1, 1, "Ò", "", {None, None}},
{2, 5, 1, 1, "ó", "", KeyType::Text, {}}, {0x00D3, u'Ó', KeyType::Character, 2, 5, 1, 1, "Ó", "", {None, None}},
{2, 6, 1, 1, "ô", "", KeyType::Text, {}}, {0x00D4, u'Ô', KeyType::Character, 2, 6, 1, 1, "Ô", "", {None, None}},
{2, 7, 1, 1, "õ", "", KeyType::Text, {}}, {0x00D5, u'Õ', KeyType::Character, 2, 7, 1, 1, "Õ", "", {None, None}},
{2, 8, 1, 1, "ö", "", KeyType::Text, {}}, {0x00D6, u'Ö', KeyType::Character, 2, 8, 1, 1, "Ö", "", {None, None}},
{2, 9, 1, 1, "ø", "", KeyType::Text, {}}, {0x00D8, u'Ø', KeyType::Character, 2, 9, 1, 1, "Ø", "", {None, None}},
// Row 3 // Row 3
{3, 0, 1, 1, "œ", "", KeyType::Text, {}}, {0x0152, u'Œ', KeyType::Character, 3, 0, 1, 1, "Œ", "", {None, None}},
{3, 1, 1, 1, "ś", "", KeyType::Text, {}}, {0x015A, u'Ś', KeyType::Character, 3, 1, 1, 1, "Ś", "", {None, None}},
{3, 2, 1, 1, "ş", "", KeyType::Text, {}}, {0x015E, u'Ş', KeyType::Character, 3, 2, 1, 1, "Ş", "", {None, None}},
{3, 3, 1, 1, "š", "", KeyType::Text, {}}, {0x0160, u'Š', KeyType::Character, 3, 3, 1, 1, "Š", "", {None, None}},
{3, 4, 1, 1, "ß", "", KeyType::Text, {}}, {0x00DF, u'ß', KeyType::Character, 3, 4, 1, 1, "ß", "", {None, None}},
{3, 5, 1, 1, "ù", "", KeyType::Text, {}}, {0x00D9, u'Ù', KeyType::Character, 3, 5, 1, 1, "Ù", "", {None, None}},
{3, 6, 1, 1, "ú", "", KeyType::Text, {}}, {0x00DA, u'Ú', KeyType::Character, 3, 6, 1, 1, "Ú", "", {None, None}},
{3, 7, 1, 1, "û", "", KeyType::Text, {}}, {0x00DB, u'Û', KeyType::Character, 3, 7, 1, 1, "Û", "", {None, None}},
{3, 8, 1, 1, "ü", "", KeyType::Text, {}}, {0x00DC, u'Ü', KeyType::Character, 3, 8, 1, 1, "Ü", "", {None, None}},
{3, 9, 1, 1, "ý", "", KeyType::Text, {}}, {0x00DD, u'Ý', KeyType::Character, 3, 9, 1, 1, "Ý", "", {None, None}},
// Row 4 // Row 4
{4, 0, 1, 1, "ÿ", "", KeyType::Text, {}}, {0x0178, u'Ÿ', KeyType::Character, 4, 0, 1, 1, "Ÿ", "", {None, None}},
{4, 1, 1, 1, "ź", "", KeyType::Text, {}}, {0x0179, u'Ź', KeyType::Character, 4, 1, 1, 1, "Ź", "", {None, None}},
{4, 2, 1, 1, "ż", "", KeyType::Text, {}}, {0x017B, u'Ż', KeyType::Character, 4, 2, 1, 1, "Ż", "", {None, None}},
{4, 3, 1, 1, "ž", "", KeyType::Text, {}}, {0x017D, u'Ž', KeyType::Character, 4, 3, 1, 1, "Ž", "", {None, None}},
{4, 4, 1, 1, "ð", "", KeyType::Text, {}}, {0x00D0, u'Ð', KeyType::Character, 4, 4, 1, 1, "Ð", "", {None, None}},
{4, 5, 1, 1, "þ", "", KeyType::Text, {}}, {0x00DE, u'Þ', KeyType::Character, 4, 5, 1, 1, "Þ", "", {None, None}},
{4, 6, 1, 1, "", "", KeyType::Disabled, {}}, {0x0000, u'\0', KeyType::Disabled, 4, 6, 1, 1, "", "", {None, None}},
{4, 7, 1, 1, "", "", KeyType::Disabled, {}}, {0x0000, u'\0', KeyType::Disabled, 4, 7, 1, 1, "", "", {None, None}},
{4, 8, 1, 1, "", "", KeyType::Disabled, {}}, {0x0000, u'\0', KeyType::Disabled, 4, 8, 1, 1, "", "", {None, None}},
{4, 9, 1, 1, "", "", KeyType::Disabled, {}}, {0x0000, u'\0', KeyType::Disabled, 4, 9, 1, 1, "", "", {None, None}},
// Row 5 // Row 5
{5, 0, 1, 1, "", "L2", KeyType::Shift, {L2}}, {0x0010, u'\0', KeyType::Function, 5, 0, 1, 1, "", "L2", {L2, None}},
{5, 1, 1, 1, "@#:", "L2+△", KeyType::Symbols1Layout, {L3, Triangle}}, {KC_LETTERS, u'\0', KeyType::Function, 5, 1, 1, 1, "ABC", "L2+△", {L3, Triangle}}, // TODO:
{5, 2, 1, 1, "à", "L3", KeyType::AccentLettersLayout, {L3}}, {0x0000, u'\0', KeyType::Disabled, 5, 2, 1, 1, "", "", {None, None}}, // TODO:
{5, 3, 4, 1, "Space", "", KeyType::Space, {Triangle}}, {0x0020, u' ', KeyType::Character, 5, 3, 4, 1, "Space", "", {Triangle, None}},
//{4, 4, 4, 1, "Space", "△", KeyType::Space,{Triangle}}, {0x0000, u'\0', KeyType::Disabled, 5, 7, 1, 1, "", "", {None, None}},
//{4, 5, 4, 1, "Space", "△", KeyType::Space,{Triangle}}, {0x0008, u'\0', KeyType::Function, 5, 8, 2, 1, "", "", {Square, None}, true},
//{4, 6, 4, 1, "Space", "△", KeyType::Space,{Triangle}},
{4, 7, 1, 1, "", "", KeyType::Disabled, {}},
{5, 8, 2, 1, "", "", KeyType::Backspace, {Square}},
//{4, 9, 2, 1, "⇦", "□", KeyType::Backspace,{Square}},
// Row 6 // Row 6
{6, 0, 1, 1, "", "", KeyType::CursorUp, {Up}}, {0xF020, u'\0', KeyType::Function, 6, 0, 1, 1, "", "", {Up, None}},
{6, 1, 1, 1, "", "", KeyType::CursorDown, {Down}}, {0xF021, u'\0', KeyType::Function, 6, 1, 1, 1, "", "", {Down, None}},
{6, 2, 1, 1, "", "L1", KeyType::CursorLeft, {L1}}, {0xF022, u'\0', KeyType::Function, 6, 2, 1, 1, "", "L1", {L1, None}},
{6, 3, 1, 1, "", "R1", KeyType::CursorRight, {R1}}, {0xF023, u'\0', KeyType::Function, 6, 3, 1, 1, "", "R1", {R1, None}},
{6, 4, 1, 1, "KB", "", KeyType::ToggleKeyboard, {}}, {KC_KB, u'\0', KeyType::Function, 6, 4, 1, 1, "KB", "", {None, None}}, // TODO
{6, 5, 1, 1, "...", "", KeyType::MoreOptions, {}}, {KC_OPT, u'\0', KeyType::Function, 6, 5, 1, 1, "...", "", {None, None}}, // TODO
//{5, 5, 1, 1, "…", "", KeyType::MoreOptions,{}}, {KC_GYRO, u'\0', KeyType::Function, 6, 6, 1, 1, "+/⊗", "R3", {R3, None}}, // TODO
{6, 6, 1, 1, "+/⊗", "R3", KeyType::ControllerAction, {R3}}, {0x0000, u'\0', KeyType::Disabled, 6, 7, 1, 1, "", "", {None, None}},
{5, 7, 1, 1, "", "", KeyType::Disabled, {}}, {0x000D, u'\r', KeyType::Function, 6, 8, 2, 1, "Done", "R2", {R2, None}},
{6, 8, 2, 1, "Done", "R2", KeyType::Done, {R2}}, };
//{5, 9, 2, 1, "Done", "R2", KeyType::Done,{R2}},
}; const std::vector<KeyEntry> kLayoutEnAccentLettersLowercase = {
// Row 0
{0x00E0, u'à', KeyType::Character, 0, 0, 1, 1, "à", "", {None, None}},
{0x00E1, u'á', KeyType::Character, 0, 1, 1, 1, "á", "", {None, None}},
{0x00E2, u'â', KeyType::Character, 0, 2, 1, 1, "â", "", {None, None}},
{0x00E3, u'ã', KeyType::Character, 0, 3, 1, 1, "ã", "", {None, None}},
{0x00E4, u'ä', KeyType::Character, 0, 4, 1, 1, "ä", "", {None, None}},
{0x00E5, u'å', KeyType::Character, 0, 5, 1, 1, "å", "", {None, None}},
{0x0105, u'ą', KeyType::Character, 0, 6, 1, 1, "ą", "", {None, None}},
{0x00E6, u'æ', KeyType::Character, 0, 7, 1, 1, "æ", "", {None, None}},
{0x00E7, u'ç', KeyType::Character, 0, 8, 1, 1, "ç", "", {None, None}},
{0x0107, u'ć', KeyType::Character, 0, 9, 1, 1, "ć", "", {None, None}},
// Row 1
{0x00E8, u'è', KeyType::Character, 1, 0, 1, 1, "è", "", {None, None}},
{0x00E9, u'é', KeyType::Character, 1, 1, 1, 1, "é", "", {None, None}},
{0x00EA, u'ê', KeyType::Character, 1, 2, 1, 1, "ê", "", {None, None}},
{0x00EB, u'ë', KeyType::Character, 1, 3, 1, 1, "ë", "", {None, None}},
{0x0119, u'ę', KeyType::Character, 1, 4, 1, 1, "ę", "", {None, None}},
{0x011F, u'ğ', KeyType::Character, 1, 5, 1, 1, "ğ", "", {None, None}},
{0x00EC, u'ì', KeyType::Character, 1, 6, 1, 1, "ì", "", {None, None}},
{0x00ED, u'í', KeyType::Character, 1, 7, 1, 1, "í", "", {None, None}},
{0x00EE, u'î', KeyType::Character, 1, 8, 1, 1, "î", "", {None, None}},
{0x00EF, u'ï', KeyType::Character, 1, 9, 1, 1, "ï", "", {None, None}},
// Row 2
{0x0131, u'ı', KeyType::Character, 2, 0, 1, 1, "ı", "", {None, None}},
{0x0142, u'ł', KeyType::Character, 2, 1, 1, 1, "ł", "", {None, None}},
{0x00F1, u'ñ', KeyType::Character, 2, 2, 1, 1, "ñ", "", {None, None}},
{0x0144, u'ń', KeyType::Character, 2, 3, 1, 1, "ń", "", {None, None}},
{0x00F2, u'ò', KeyType::Character, 2, 4, 1, 1, "ò", "", {None, None}},
{0x00F3, u'ó', KeyType::Character, 2, 5, 1, 1, "ó", "", {None, None}},
{0x00F4, u'ô', KeyType::Character, 2, 6, 1, 1, "ô", "", {None, None}},
{0x00F5, u'õ', KeyType::Character, 2, 7, 1, 1, "õ", "", {None, None}},
{0x00F6, u'ö', KeyType::Character, 2, 8, 1, 1, "ö", "", {None, None}},
{0x00F8, u'ø', KeyType::Character, 2, 9, 1, 1, "ø", "", {None, None}},
// Row 3
{0x0153, u'œ', KeyType::Character, 3, 0, 1, 1, "œ", "", {None, None}},
{0x015B, u'ś', KeyType::Character, 3, 1, 1, 1, "ś", "", {None, None}},
{0x015F, u'ş', KeyType::Character, 3, 2, 1, 1, "ş", "", {None, None}},
{0x0161, u'š', KeyType::Character, 3, 3, 1, 1, "š", "", {None, None}},
{0x00DF, u'ß', KeyType::Character, 3, 4, 1, 1, "ß", "", {None, None}},
{0x00F9, u'ù', KeyType::Character, 3, 5, 1, 1, "ù", "", {None, None}},
{0x00FA, u'ú', KeyType::Character, 3, 6, 1, 1, "ú", "", {None, None}},
{0x00FB, u'û', KeyType::Character, 3, 7, 1, 1, "û", "", {None, None}},
{0x00FC, u'ü', KeyType::Character, 3, 8, 1, 1, "ü", "", {None, None}},
{0x00FD, u'ý', KeyType::Character, 3, 9, 1, 1, "ý", "", {None, None}},
// Row 4
{0x00FF, u'ÿ', KeyType::Character, 4, 0, 1, 1, "ÿ", "", {None, None}},
{0x017A, u'ź', KeyType::Character, 4, 1, 1, 1, "ź", "", {None, None}},
{0x017C, u'ż', KeyType::Character, 4, 2, 1, 1, "ż", "", {None, None}},
{0x017E, u'ž', KeyType::Character, 4, 3, 1, 1, "ž", "", {None, None}},
{0x00F0, u'ð', KeyType::Character, 4, 4, 1, 1, "ð", "", {None, None}},
{0x00FE, u'þ', KeyType::Character, 4, 5, 1, 1, "þ", "", {None, None}},
{0x0000, u'\0', KeyType::Disabled, 4, 6, 1, 1, "", "", {None, None}},
{0x0000, u'\0', KeyType::Disabled, 4, 7, 1, 1, "", "", {None, None}},
{0x0000, u'\0', KeyType::Disabled, 4, 8, 1, 1, "", "", {None, None}},
{0x0000, u'\0', KeyType::Disabled, 4, 9, 1, 1, "", "", {None, None}},
// Row 5
{0x0010, u'\0', KeyType::Function, 5, 0, 1, 1, "", "L2", {L2, None}},
{KC_LETTERS, u'\0', KeyType::Function, 5, 1, 1, 1, "ABC", "L2+△", {L3, Triangle}}, // TODO
{0x0000, u'\0', KeyType::Disabled, 5, 2, 1, 1, "", "", {None, None}}, // TODO
{0x0020, u' ', KeyType::Character, 5, 3, 4, 1, "Space", "", {Triangle, None}},
{0x0000, u'\0', KeyType::Disabled, 5, 7, 1, 1, "", "", {None, None}},
{0x0008, u'\0', KeyType::Function, 5, 8, 2, 1, "", "", {Square, None}, true},
// Row 6
{0xF020, u'\0', KeyType::Function, 6, 0, 1, 1, "", "", {Up, None}},
{0xF021, u'\0', KeyType::Function, 6, 1, 1, 1, "", "", {Down, None}},
{0xF022, u'\0', KeyType::Function, 6, 2, 1, 1, "", "L1", {L1, None}},
{0xF023, u'\0', KeyType::Function, 6, 3, 1, 1, "", "R1", {R1, None}},
{KC_KB, u'\0', KeyType::Function, 6, 4, 1, 1, "KB", "", {None, None}}, // TODO
{KC_OPT, u'\0', KeyType::Function, 6, 5, 1, 1, "...", "", {None, None}}, // TODO
{KC_GYRO, u'\0', KeyType::Function, 6, 6, 1, 1, "+/⊗", "R3", {R3, None}}, // TODO
{0x0000, u'\0', KeyType::Disabled, 6, 7, 1, 1, "", "", {None, None}},
{0x000D, u'\r', KeyType::Function, 6, 8, 2, 1, "Done", "R2", {R2, None}},
};

View File

@ -6,43 +6,77 @@
#include <string> #include <string>
#include <vector> #include <vector>
#include <imgui.h> #include <imgui.h>
#include "common/types.h"
enum class KeyType { /*
Text, // Inserts character(s) into input buffer enum class OrbisImeKeyEntryType : u8 {
Backspace, // Deletes last character ORBIS_IME_KEY_TYPE_CHARACTER = 0,
Space, // Adds space ORBIS_IME_KEY_TYPE_FUNCTION = 1,
Enter, // Submits input ORBIS_IME_KEY_TYPE_DISABLED = 2
Shift, // Toggle uppercase/lowercase };
Symbols1Layout, // Switch to symbols layout */
Symbols2Layout, // Switch to symbols layout /*
LettersLayout, // Switch to text layout struct OrbisImeKeyEntry {
AccentLettersLayout, // Switch to accent text layout u16 keycode;
Done, // Finish and close keyboard char16_t character;
CursorLeft, OrbisImeKeyEntryType type;
CursorRight, u8 row;
CursorUp, u8 col;
CursorDown, u8 colspan;
ToggleKeyboard, // Toggles keyboard layout u8 rowspan;
MoreOptions, // "..." button const char* label;
ControllerAction, // e.g. R3 +/⊕ const char* controller_hint;
Disabled, // Filler or placeholder OrbisPadButtonDataOffset bound_buttons[2];
UnknownFunction, // now same as disabled };
*/
enum class KeyType : u8 { Character = 0, Function = 1, Disabled = 2 };
struct KeyEntry {
u16 keycode; // 0xF100+ unused, so can be used as temporary defined keys for unknown
char16_t character;
KeyType type;
u8 row;
u8 col;
u8 colspan;
u8 rowspan;
const char* label;
const char* controller_hint;
ImGuiNavInput bound_buttons[2];
bool allow_repeat{false};
}; };
struct Key { int c16rtomb(char* out, char16_t ch);
int row;
int col;
int colspan = 1;
int rowspan = 1;
std::string label;
std::string controller_hint;
KeyType type = KeyType::Text;
std::vector<ImGuiNavInput> bound_buttons = {}; // Now using ImGui navigation inputs
};
extern const std::vector<Key> kLayoutEnLettersUppercase; extern const std::vector<KeyEntry> kLayoutEnLettersUppercase;
extern const std::vector<Key> kLayoutEnLettersLowercase; extern const std::vector<KeyEntry> kLayoutEnLettersLowercase;
extern const std::vector<Key> kLayoutEnAccentLettersUppercase; extern const std::vector<KeyEntry> kLayoutEnAccentLettersUppercase;
extern const std::vector<Key> kLayoutEnAccentLettersLowercase; extern const std::vector<KeyEntry> kLayoutEnAccentLettersLowercase;
extern const std::vector<Key> kLayoutEnSymbols1; extern const std::vector<KeyEntry> kLayoutEnSymbols1;
extern const std::vector<Key> kLayoutEnSymbols2; extern const std::vector<KeyEntry> kLayoutEnSymbols2;
constexpr ImGuiNavInput None = ImGuiNavInput_COUNT;
constexpr auto L1 = ImGuiNavInput_FocusPrev;
constexpr auto R1 = ImGuiNavInput_FocusNext;
constexpr auto L2 = ImGuiNavInput_TweakSlow;
constexpr auto R2 = ImGuiNavInput_TweakFast;
constexpr auto L3 = ImGuiNavInput_DpadLeft; // adjust if needed
constexpr auto R3 = ImGuiNavInput_DpadRight; // adjust if needed
constexpr auto Up = ImGuiNavInput_DpadUp;
constexpr auto Down = ImGuiNavInput_DpadDown;
constexpr auto Left = ImGuiNavInput_DpadLeft;
constexpr auto Right = ImGuiNavInput_DpadRight;
constexpr auto Cross = ImGuiNavInput_Activate;
constexpr auto Circle = ImGuiNavInput_Menu;
constexpr auto Square = ImGuiNavInput_Cancel;
constexpr auto Triangle = ImGuiNavInput_Input;
constexpr auto TouchPad = ImGuiNavInput_Menu; // reuse if needed
// Fake function keycodes
constexpr u16 KC_SYM1 = 0xF100;
constexpr u16 KC_SYM2 = 0xF101;
constexpr u16 KC_ACCENTS = 0xF102;
constexpr u16 KC_LETTERS = 0xF103;
constexpr u16 KC_KB = 0xF104;
constexpr u16 KC_GYRO = 0xF105;
constexpr u16 KC_OPT = 0xF106;

View File

@ -1,167 +1,215 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include <cstring> #include <cstring>
#include <unordered_set>
#include <imgui.h> #include <imgui.h>
#include <imgui_internal.h>
#include "ime_common.h" #include "ime_common.h"
#include "ime_dialog.h"
#include "ime_keyboard_layouts.h" #include "ime_keyboard_layouts.h"
#include "ime_keyboard_ui.h" #include "ime_keyboard_ui.h"
#include "ime_ui.h" // for ImeState #include "ime_ui.h" // for ImeState
using namespace ImGui; using namespace ImGui;
// --- UTF-8 safe backspace helper --- /**
* Removes one UTF-8 codepoint from the end of 'buffer', if present.
*/
void Utf8SafeBackspace(char* buffer) { void Utf8SafeBackspace(char* buffer) {
size_t len = std::strlen(buffer); size_t len = std::strlen(buffer);
if (len == 0) if (len == 0)
return; return;
// Move backward over any continuation bytes.
while (len > 0 && (static_cast<unsigned char>(buffer[len]) & 0b11000000) == 0b10000000) { while (len > 0 && (static_cast<unsigned char>(buffer[len]) & 0b11000000) == 0b10000000) {
--len; --len;
} }
if (len > 0) { if (len > 0) {
// Remove one codepoint.
buffer[len - 1] = '\0'; buffer[len - 1] = '\0';
buffer[len] = '\0'; buffer[len] = '\0';
} }
} }
void DrawVirtualKeyboard(char* buffer, std::size_t buffer_capacity, bool* input_changed, /**
KeyboardMode& kb_mode, bool& shift_enabled, bool* done_pressed) { * Picks which layout vector we want for OrbisImeType, kb_mode, shift_state, etc.
const std::vector<Key>* layout = nullptr; */
const std::vector<KeyEntry>* GetKeyboardLayout(OrbisImeType type, KeyboardMode mode,
ShiftState shift, u64 language) {
switch (type) {
case OrbisImeType::Number:
// For numeric input, you might have a dedicated numeric layout,
// but here we reuse kLayoutEnSymbols1.
return &kLayoutEnSymbols1;
switch (kb_mode) { case OrbisImeType::Url:
case KeyboardMode::Symbols1: case OrbisImeType::Mail:
layout = &kLayoutEnSymbols1; // Use letters; uppercase if SHIFT is on.
break; if (shift == ShiftState::CapsLock || shift == ShiftState::Shift) {
case KeyboardMode::Symbols2: return &kLayoutEnLettersUppercase;
layout = &kLayoutEnSymbols2; } else {
break; return &kLayoutEnLettersLowercase;
case KeyboardMode::Letters2: }
layout =
shift_enabled ? &kLayoutEnAccentLettersUppercase : &kLayoutEnAccentLettersLowercase; case OrbisImeType::BasicLatin:
break; case OrbisImeType::Default:
case KeyboardMode::Letters1:
default: default:
layout = shift_enabled ? &kLayoutEnLettersUppercase : &kLayoutEnLettersLowercase; switch (mode) {
break; case KeyboardMode::Symbols1:
return &kLayoutEnSymbols1;
case KeyboardMode::Symbols2:
return &kLayoutEnSymbols2;
case KeyboardMode::AccentLetters:
if (shift == ShiftState::CapsLock || shift == ShiftState::Shift) {
return &kLayoutEnAccentLettersUppercase;
} else {
return &kLayoutEnAccentLettersLowercase;
}
case KeyboardMode::Letters:
default:
if (shift == ShiftState::CapsLock || shift == ShiftState::Shift) {
return &kLayoutEnLettersUppercase;
} else {
return &kLayoutEnLettersLowercase;
}
}
} }
RenderKeyboardLayout(*layout, buffer, buffer_capacity, input_changed, kb_mode, shift_enabled,
done_pressed);
} }
void RenderKeyboardLayout(const std::vector<Key>& layout, char* buffer, std::size_t buffer_capacity, /**
bool* input_changed, KeyboardMode& kb_mode, bool& shift_enabled, * Renders the given layout using the style logic:
bool* done_pressed) { * - For symbols layout and if style.use_button_symbol_color is true,
const float layout_width = 485.0f; * character keys get style.color_button_symbol.
const float layout_height = 200.0f; * - Function keys get style.color_button_function.
const float cell_spacing = 4.0f; * - The "Done"/"Enter" key (keycode 0x0D) gets style.color_special.
const float hint_padding = 2.0f; * - Otherwise, keys use style.color_button_default.
*
* This version retains all GUI layout details (positions, colors, sizes, etc.) exactly as in your
* base files. The only change is in key event detection: after drawing each key with Button(), we
* use IsItemActive() to determine the pressed state so that the backend key processing works
* correctly.
*/
void RenderKeyboardLayout(const std::vector<KeyEntry>& layout, KeyboardMode mode,
void (*on_key_event)(const VirtualKeyEvent*),
const KeyboardStyle& style) {
ImGui::BeginGroup();
int max_col = 0; /* ─────────────── 1. grid size & cell metrics ─────────────── */
int max_row = 0; int max_col = 0, max_row = 0;
for (const Key& key : layout) { for (const KeyEntry& k : layout) {
max_col = std::max(max_col, key.col + static_cast<int>(key.colspan)); max_col = std::max(max_col, k.col + (int)k.colspan);
max_row = std::max(max_row, key.row + static_cast<int>(key.rowspan)); max_row = std::max(max_row, k.row + (int)k.rowspan);
}
if (max_col == 0 || max_row == 0) {
ImGui::EndGroup();
return;
} }
const float cell_width = (layout_width - (max_col - 1) * cell_spacing) / max_col; const float pad = 20.0f;
const float cell_height = (layout_height - (max_row - 1) * cell_spacing) / max_row; const float spacing_w = (max_col - 1) * style.key_spacing;
const float spacing_h = (max_row - 1) * style.key_spacing;
const float cell_w = std::floor((style.layout_width - spacing_w - 2 * pad) / max_col + 0.5f);
const float cell_h = std::floor((style.layout_height - spacing_h - 85.0f) / max_row + 0.5f);
const ImVec2 origin = ImGui::GetCursorScreenPos(); ImVec2 origin = ImGui::GetCursorScreenPos();
ImDrawList* draw_list = ImGui::GetWindowDrawList(); origin.x += pad;
for (const Key& key : layout) { ImGui::PushStyleColor(ImGuiCol_NavHighlight, style.color_line);
float x = origin.x + key.col * (cell_width + cell_spacing); ImGui::SetWindowFontScale(1.50f);
float y = origin.y + key.row * (cell_height + cell_spacing);
ImVec2 pos(x, y); const int function_rows_start = std::max(0, max_row - 2);
ImVec2 size(key.colspan * cell_width + (key.colspan - 1) * cell_spacing,
key.rowspan * cell_height + (key.rowspan - 1) * cell_spacing);
std::string button_id = /* ─────────────── 2. draw every key ───────────────────────── */
key.label.empty() ? "##empty_" + std::to_string(key.row) + "_" + std::to_string(key.col) for (const KeyEntry& key : layout) {
: key.label; /* position & size */
float x = origin.x + key.col * (cell_w + style.key_spacing);
float y = origin.y + key.row * (cell_h + style.key_spacing);
float w = key.colspan * cell_w + (key.colspan - 1) * style.key_spacing;
float h = key.rowspan * cell_h + (key.rowspan - 1) * style.key_spacing;
ImVec2 pos(x, y), size(w, h);
/* ------------ background colour decision --------------- */
const bool in_function_rows = (key.row >= function_rows_start);
const bool is_done_enter = (key.keycode == 0x0D);
ImU32 bg_color;
if (is_done_enter) {
bg_color = style.color_special; // always wins
} else if (in_function_rows) {
bg_color = style.color_button_function; // bottom two rows
} else if ((mode == KeyboardMode::Symbols1 || mode == KeyboardMode::Symbols2) &&
style.use_button_symbol_color) {
bg_color = style.color_button_symbol; // symbol tint
} else {
bg_color = style.color_button_default; // normal default
}
/* label */
std::string label = (key.label && key.label[0]) ? key.label : " ";
/* ---------- ImGui button ---------- */
ImGui::PushID(&key);
ImGui::PushStyleColor(ImGuiCol_Text, style.color_text);
ImGui::PushStyleColor(ImGuiCol_Button, bg_color);
ImGui::PushStyleColor(ImGuiCol_ButtonHovered,
IM_COL32((bg_color >> IM_COL32_R_SHIFT & 0xFF) * 220 / 255,
(bg_color >> IM_COL32_G_SHIFT & 0xFF) * 220 / 255,
(bg_color >> IM_COL32_B_SHIFT & 0xFF) * 220 / 255,
(bg_color >> IM_COL32_A_SHIFT & 0xFF)));
ImGui::PushStyleColor(ImGuiCol_ButtonActive,
IM_COL32((bg_color >> IM_COL32_R_SHIFT & 0xFF) * 180 / 255,
(bg_color >> IM_COL32_G_SHIFT & 0xFF) * 180 / 255,
(bg_color >> IM_COL32_B_SHIFT & 0xFF) * 180 / 255,
(bg_color >> IM_COL32_A_SHIFT & 0xFF)));
ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 0.0f);
ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 0.0f);
if (key.allow_repeat)
ImGui::PushButtonRepeat(true);
ImGui::SetCursorScreenPos(pos); ImGui::SetCursorScreenPos(pos);
bool key_activated = ImGui::Button(button_id.c_str(), size); bool pressed = ImGui::Button(label.c_str(), size); // Down + repeats
if (key_activated) { if (key.allow_repeat)
switch (key.type) { ImGui::PopButtonRepeat();
case KeyType::Text:
if (!key.label.empty()) {
size_t len = std::strlen(buffer);
if (len + key.label.size() < buffer_capacity) {
std::strcat(buffer, key.label.c_str());
if (input_changed)
*input_changed = true;
}
}
break;
case KeyType::Backspace:
if (buffer[0] != '\0') {
Utf8SafeBackspace(buffer);
if (input_changed)
*input_changed = true;
}
break;
case KeyType::Space:
if (std::strlen(buffer) + 1 < buffer_capacity) {
std::strcat(buffer, " ");
if (input_changed)
*input_changed = true;
}
break;
case KeyType::Enter:
case KeyType::Done:
if (done_pressed)
*done_pressed = true;
break;
case KeyType::Shift:
shift_enabled = !shift_enabled;
break;
case KeyType::Symbols1Layout:
kb_mode = KeyboardMode::Symbols1;
break;
case KeyType::Symbols2Layout:
kb_mode = KeyboardMode::Symbols2;
break;
case KeyType::LettersLayout:
kb_mode = KeyboardMode::Letters1;
break;
case KeyType::AccentLettersLayout:
kb_mode = KeyboardMode::Letters2;
break;
case KeyType::ToggleKeyboard: /* ---------- event generation ---------- */
kb_mode = (kb_mode == KeyboardMode::Letters1) ? KeyboardMode::Symbols1 if (on_key_event) {
: KeyboardMode::Letters1; if (ImGui::IsItemActivated()) {
break; VirtualKeyEvent ev{VirtualKeyEventType::Down, &key};
default: on_key_event(&ev);
break; } else if (pressed && key.allow_repeat) {
VirtualKeyEvent ev{VirtualKeyEventType::Repeat, &key};
on_key_event(&ev);
}
if (ImGui::IsItemDeactivated()) {
VirtualKeyEvent ev{VirtualKeyEventType::Up, &key};
on_key_event(&ev);
} }
} }
// Draw controller hint label /* cleanup */
if (!key.controller_hint.empty()) { ImGui::PopStyleVar(2);
float original_font_size = ImGui::GetFontSize(); ImGui::PopStyleColor(4);
float small_font_size = original_font_size * 0.5f; ImGui::PopID();
ImVec2 text_size =
ImGui::CalcTextSize(key.controller_hint.c_str(), nullptr, false, -1.0f) *
(small_font_size / original_font_size);
ImVec2 text_pos = pos + ImVec2(hint_padding, hint_padding);
ImVec2 bg_min = text_pos - ImVec2(1.0f, 1.0f);
ImVec2 bg_max = text_pos + text_size + ImVec2(2.0f, 1.0f);
ImU32 bg_color = IM_COL32(0, 0, 0, 160);
ImU32 fg_color = IM_COL32(255, 255, 255, 200);
draw_list->AddRectFilled(bg_min, bg_max, bg_color, 2.0f);
draw_list->AddText(nullptr, small_font_size, text_pos, fg_color,
key.controller_hint.c_str());
}
} }
ImGui::SetWindowFontScale(1.0f);
ImGui::PopStyleColor(); // NavHighlight
ImGui::EndGroup();
}
/**
* Selects the correct layout via GetKeyboardLayout() then calls RenderKeyboardLayout().
*/
void DrawVirtualKeyboard(KeyboardMode kb_mode, OrbisImeType ime_type, ShiftState shift_state,
u64 language, void (*on_key_event)(const VirtualKeyEvent*),
const KeyboardStyle& style) {
const std::vector<KeyEntry>* layout =
GetKeyboardLayout(ime_type, kb_mode, shift_state, language);
if (!layout)
return;
RenderKeyboardLayout(*layout, kb_mode, on_key_event, style);
} }

View File

@ -1,6 +1,3 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once #pragma once
#include <cstddef> #include <cstddef>
@ -13,11 +10,83 @@
#include "core/libraries/pad/pad.h" #include "core/libraries/pad/pad.h"
#include "ime_keyboard_layouts.h" #include "ime_keyboard_layouts.h"
enum class KeyboardMode { Letters1, Letters2, Symbols1, Symbols2 }; /**
* KeyboardMode: which layout we show (letters, accents, symbols, etc.)
*/
enum class KeyboardMode { Letters, AccentLetters, Symbols1, Symbols2 };
void DrawVirtualKeyboard(char* buffer, std::size_t buffer_capacity, bool* input_changed, /**
KeyboardMode& kb_mode, bool& shift_enabled, bool* done_pressed); * We handle raw key "Down" or "Up" events from an on-screen keyboard.
*/
enum class VirtualKeyEventType { Down, Up, Repeat };
void RenderKeyboardLayout(const std::vector<Key>& layout, char* buffer, std::size_t buffer_capacity, struct VirtualKeyEvent {
bool* input_changed, KeyboardMode& kb_mode, bool& shift_enabled, VirtualKeyEventType type;
bool* done_pressed); const KeyEntry* key;
};
enum class ShiftState : u8 {
None = 0, // lowercase
Shift = 1, // temporary uppercase
CapsLock = 2 // full uppercase
};
/**
* This struct holds all visual parameters for the on-screen keyboard,
* including layout size, spacing, and button colors.
*
* If extended parameters are present, it override these defaults
* in IME code. Then pass the result to DrawVirtualKeyboard(...).
*/
struct KeyboardStyle {
float layout_width = 500.0f;
float layout_height = 300.0f;
float key_spacing = 5.0f;
// For text, lines, etc.
ImU32 color_text = IM_COL32(225, 225, 225, 255);
ImU32 color_line = IM_COL32(88, 88, 88, 255);
// Button colors
ImU32 color_button_default = IM_COL32(35, 35, 35, 255);
ImU32 color_button_function = IM_COL32(50, 50, 50, 255);
ImU32 color_special = IM_COL32(0, 140, 200, 255);
// If you're on a symbols layout, you may want to color them differently.
bool use_button_symbol_color = false;
ImU32 color_button_symbol = IM_COL32(60, 60, 60, 255);
};
/**
* Safely remove one UTF-8 glyph from the end of 'buffer'.
*/
void Utf8SafeBackspace(char* buffer);
/**
* Returns the appropriate layout (vector of KeyEntry) for the given
* OrbisImeType, KeyboardMode, ShiftState, and language bitmask.
*/
const std::vector<KeyEntry>* GetKeyboardLayout(OrbisImeType type, KeyboardMode mode,
ShiftState shift, u64 language);
/**
* Renders a given layout using the style logic:
* - If 'mode' is a symbols layout (Symbols1 or Symbols2) AND style.use_button_symbol_color == true,
* then normal character keys are drawn with style.color_button_symbol
* - Function keys => style.color_button_function
* - The "Done" or "Enter" key (keycode 0x0D) => style.color_special
* - Otherwise => style.color_button_default
*
* We call on_key_event(...) with VirtualKeyEventType::Down/Up when the user clicks or releases a
* key.
*/
void RenderKeyboardLayout(const std::vector<KeyEntry>& layout, KeyboardMode mode,
void (*on_key_event)(const VirtualKeyEvent*), const KeyboardStyle& style);
/**
* Picks the correct layout from GetKeyboardLayout() for the given
* kb_mode, shift_state, etc., then calls RenderKeyboardLayout().
*/
void DrawVirtualKeyboard(KeyboardMode kb_mode, OrbisImeType ime_type, ShiftState shift_state,
u64 language, void (*on_key_event)(const VirtualKeyEvent*),
const KeyboardStyle& style);

View File

@ -1,7 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project // SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
#include "ime_keyboard_ui.h"
#include "ime_ui.h" #include "ime_ui.h"
#include "imgui/imgui_std.h" #include "imgui/imgui_std.h"
@ -151,7 +150,6 @@ void ImeUi::Draw() {
DrawPrettyBackground(); DrawPrettyBackground();
DrawInputText(); DrawInputText();
DrawKeyboard();
SetCursorPosY(GetCursorPosY() + 10.0f); SetCursorPosY(GetCursorPosY() + 10.0f);
const char* button_text; const char* button_text;
@ -189,47 +187,6 @@ void ImeUi::DrawInputText() {
} }
} }
void ImeUi::DrawKeyboard() {
static KeyboardMode kb_mode = KeyboardMode::Letters1;
static bool shift_enabled = false;
static bool has_logged = false;
if (!has_logged) {
LOG_INFO(Lib_Ime, "Virtual keyboard used from ImeUi");
has_logged = true;
}
bool input_changed = false;
bool done_pressed = false;
DrawVirtualKeyboard(state->current_text.begin(), state->current_text.capacity(), &input_changed,
kb_mode, shift_enabled, &done_pressed);
if (input_changed) {
OrbisImeEditText eventParam{};
eventParam.str = reinterpret_cast<char16_t*>(ime_param->work);
eventParam.caret_index = std::strlen(state->current_text.begin());
eventParam.area_num = 1;
eventParam.text_area[0].mode = 1;
eventParam.text_area[0].index = 0;
eventParam.text_area[0].length = eventParam.caret_index;
state->ConvertUTF8ToOrbis(state->current_text.begin(), eventParam.caret_index,
eventParam.str, ime_param->maxTextLength);
state->ConvertUTF8ToOrbis(state->current_text.begin(), eventParam.caret_index,
ime_param->inputTextBuffer, ime_param->maxTextLength);
OrbisImeEvent event{};
event.id = OrbisImeEventId::UpdateText;
event.param.text = eventParam;
state->SendEvent(&event);
}
if (done_pressed) {
state->SendEnterEvent();
}
}
int ImeUi::InputTextCallback(ImGuiInputTextCallbackData* data) { int ImeUi::InputTextCallback(ImGuiInputTextCallbackData* data) {
ImeUi* ui = static_cast<ImeUi*>(data->UserData); ImeUi* ui = static_cast<ImeUi*>(data->UserData);
ASSERT(ui); ASSERT(ui);
@ -293,4 +250,4 @@ void ImeUi::Free() {
RemoveLayer(this); RemoveLayer(this);
} }
}; // namespace Libraries::Ime }; // namespace Libraries::Ime

View File

@ -70,8 +70,6 @@ private:
void DrawInputText(); void DrawInputText();
void DrawKeyboard();
static int InputTextCallback(ImGuiInputTextCallbackData* data); static int InputTextCallback(ImGuiInputTextCallbackData* data);
}; };

View File

@ -80,7 +80,7 @@ void Initialize(const ::Vulkan::Instance& instance, const Frontend::WindowSDL& w
rb.AddChar(U''); rb.AddChar(U'');
rb.AddChar(U''); rb.AddChar(U'');
rb.AddChar(U''); rb.AddChar(U'');
rb.AddChar(U'🗙'); rb.AddChar(U'');
rb.AddChar(U''); rb.AddChar(U'');
rb.AddChar(U''); rb.AddChar(U'');
rb.AddChar(U''); rb.AddChar(U'');