diff --git a/CMakeLists.txt b/CMakeLists.txt index 77e288b62..22b8af192 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -446,6 +446,8 @@ set(IME_LIB src/core/libraries/ime/error_dialog.cpp src/core/libraries/ime/ime_dialog.h src/core/libraries/ime/ime_ui.cpp src/core/libraries/ime/ime_ui.h + src/core/libraries/ime/ime_keyboard_layouts.cpp + src/core/libraries/ime/ime_keyboard_layouts.h src/core/libraries/ime/ime_keyboard_ui.cpp src/core/libraries/ime/ime_keyboard_ui.h src/core/libraries/ime/ime.cpp diff --git a/src/core/libraries/ime/ime_dialog_ui.cpp b/src/core/libraries/ime/ime_dialog_ui.cpp index bd41488ae..3c576059d 100644 --- a/src/core/libraries/ime/ime_dialog_ui.cpp +++ b/src/core/libraries/ime/ime_dialog_ui.cpp @@ -351,8 +351,15 @@ void ImeDialogUi::DrawKeyboard() { has_logged = true; } + bool done_pressed = false; + DrawVirtualKeyboard(state->current_text.begin(), state->max_text_length * 4, - &state->input_changed, kb_mode, shift_enabled); + &state->input_changed, kb_mode, shift_enabled, &done_pressed); + + if (done_pressed) { + *status = OrbisImeDialogStatus::Finished; + result->endstatus = OrbisImeDialogEndStatus::Ok; + } } int ImeDialogUi::InputTextCallback(ImGuiInputTextCallbackData* data) { diff --git a/src/core/libraries/ime/ime_keyboard_layouts.cpp b/src/core/libraries/ime/ime_keyboard_layouts.cpp new file mode 100644 index 000000000..a6e4548ea --- /dev/null +++ b/src/core/libraries/ime/ime_keyboard_layouts.cpp @@ -0,0 +1,237 @@ +// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "ime_keyboard_layouts.h" + +const std::vector kUppercaseLayout = { + // Row 1 + {0, 0, 1, 1, "1", "", KeyType::Text}, + {0, 1, 1, 1, "2", "", KeyType::Text}, + {0, 2, 1, 1, "3", "", KeyType::Text}, + {0, 3, 1, 1, "4", "", KeyType::Text}, + {0, 4, 1, 1, "5", "", KeyType::Text}, + {0, 5, 1, 1, "6", "", KeyType::Text}, + {0, 6, 1, 1, "7", "", KeyType::Text}, + {0, 7, 1, 1, "8", "", KeyType::Text}, + {0, 8, 1, 1, "9", "", KeyType::Text}, + {0, 9, 1, 1, "0", "", KeyType::Text}, + + // Row 2 + {1, 0, 1, 1, "Q", "", KeyType::Text}, + {1, 1, 1, 1, "W", "", KeyType::Text}, + {1, 2, 1, 1, "E", "", KeyType::Text}, + {1, 3, 1, 1, "R", "", KeyType::Text}, + {1, 4, 1, 1, "T", "", KeyType::Text}, + {1, 5, 1, 1, "Y", "", KeyType::Text}, + {1, 6, 1, 1, "U", "", KeyType::Text}, + {1, 7, 1, 1, "I", "", KeyType::Text}, + {1, 8, 1, 1, "O", "", KeyType::Text}, + {1, 9, 1, 1, "P", "", KeyType::Text}, + + // Row 3 + {2, 0, 1, 1, "A", "", KeyType::Text}, + {2, 1, 1, 1, "S", "", KeyType::Text}, + {2, 2, 1, 1, "D", "", KeyType::Text}, + {2, 3, 1, 1, "F", "", KeyType::Text}, + {2, 4, 1, 1, "G", "", KeyType::Text}, + {2, 5, 1, 1, "H", "", KeyType::Text}, + {2, 6, 1, 1, "J", "", KeyType::Text}, + {2, 7, 1, 1, "K", "", KeyType::Text}, + {2, 8, 1, 1, "L", "", KeyType::Text}, + {2, 9, 1, 1, "\"", "", KeyType::Text}, + + // Row 4 + {3, 0, 1, 1, "Z", "", KeyType::Text}, + {3, 1, 1, 1, "X", "", KeyType::Text}, + {3, 2, 1, 1, "C", "", KeyType::Text}, + {3, 3, 1, 1, "V", "", KeyType::Text}, + {3, 4, 1, 1, "B", "", KeyType::Text}, + {3, 5, 1, 1, "N", "", KeyType::Text}, + {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 + {4, 0, 1, 1, "SF", "L2", KeyType::Shift}, //{4, 0, 1, 1, "⇧", "L2", KeyType::Shift}, + {4, 1, 1, 1, "@#:", "L2+TRI", KeyType::SymbolsLayout}, + {4, 2, 1, 1, "à", "L3", KeyType::UnknownFunction}, + {4, 3, 4, 1, "Space", "TRI", KeyType::Space}, //{4, 3, 4, 1, "Space", "△", KeyType::Space}, + //{4, 4, 4, 1, "Space", "△", KeyType::Space}, + //{4, 5, 4, 1, "Space", "△", KeyType::Space}, + //{4, 6, 4, 1, "Space", "△", KeyType::Space}, + {4, 7, 1, 1, "", "", KeyType::Disabled}, + {4, 8, 2, 1, "DEL", "SQR", KeyType::Backspace}, //{4, 8, 2, 1, "⌫", "▢", KeyType::Backspace}, + //{4, 9, 2, 1, "⌫", "▢", KeyType::Backspace}, + + // Row 6 + {5, 0, 1, 1, "UP", "", KeyType::CursorUp}, //{5, 0, 1, 1, "▲", "", KeyType::CursorUp}, + {5, 1, 1, 1, "DN", "", KeyType::CursorDown}, //{5, 1, 1, 1, "▼", "", KeyType::CursorDown}, + {5, 2, 1, 1, "LT", "L1", KeyType::CursorLeft}, //{5, 2, 1, 1, "◀", "L1", KeyType::CursorLeft}, + {5, 3, 1, 1, "RT", "R1", + KeyType::CursorRight}, //{5, 3, 1, 1, "▶", "R1", KeyType::CursorRight}, + {5, 4, 1, 1, "KB", "", + KeyType::ToggleKeyboard}, //{5, 4, 1, 1, "⌨", "", KeyType::ToggleKeyboard}, + {5, 5, 1, 1, "...", "", KeyType::MoreOptions}, //{5, 5, 1, 1, "…", "", KeyType::MoreOptions}, + {5, 6, 1, 1, "CR", "R1", + KeyType::ControllerAction}, //{5, 6, 1, 1, "🎮⊕", "R1", KeyType::ControllerAction}, + {5, 7, 1, 1, "", "", KeyType::Disabled}, + {5, 8, 2, 1, "Done", "R2", KeyType::Done}, + //{5, 9, 2, 1, "Done", "R2", KeyType::Done}, +}; + +const std::vector kLowercaseLayout = { + // Row 1 + {0, 0, 1, 1, "1", "", KeyType::Text}, + {0, 1, 1, 1, "2", "", KeyType::Text}, + {0, 2, 1, 1, "3", "", KeyType::Text}, + {0, 3, 1, 1, "4", "", KeyType::Text}, + {0, 4, 1, 1, "5", "", KeyType::Text}, + {0, 5, 1, 1, "6", "", KeyType::Text}, + {0, 6, 1, 1, "7", "", KeyType::Text}, + {0, 7, 1, 1, "8", "", KeyType::Text}, + {0, 8, 1, 1, "9", "", KeyType::Text}, + {0, 9, 1, 1, "0", "", KeyType::Text}, + + // Row 2 + {1, 0, 1, 1, "q", "", KeyType::Text}, + {1, 1, 1, 1, "w", "", KeyType::Text}, + {1, 2, 1, 1, "e", "", KeyType::Text}, + {1, 3, 1, 1, "r", "", KeyType::Text}, + {1, 4, 1, 1, "t", "", KeyType::Text}, + {1, 5, 1, 1, "y", "", KeyType::Text}, + {1, 6, 1, 1, "u", "", KeyType::Text}, + {1, 7, 1, 1, "i", "", KeyType::Text}, + {1, 8, 1, 1, "o", "", KeyType::Text}, + {1, 9, 1, 1, "p", "", KeyType::Text}, + + // Row 3 + {2, 0, 1, 1, "a", "", KeyType::Text}, + {2, 1, 1, 1, "s", "", KeyType::Text}, + {2, 2, 1, 1, "d", "", KeyType::Text}, + {2, 3, 1, 1, "f", "", KeyType::Text}, + {2, 4, 1, 1, "g", "", KeyType::Text}, + {2, 5, 1, 1, "h", "", KeyType::Text}, + {2, 6, 1, 1, "j", "", KeyType::Text}, + {2, 7, 1, 1, "k", "", KeyType::Text}, + {2, 8, 1, 1, "l", "", KeyType::Text}, + {2, 9, 1, 1, "-", "", KeyType::Text}, + + // Row 4 + {3, 0, 1, 1, "z", "", KeyType::Text}, + {3, 1, 1, 1, "x", "", KeyType::Text}, + {3, 2, 1, 1, "c", "", KeyType::Text}, + {3, 3, 1, 1, "v", "", KeyType::Text}, + {3, 4, 1, 1, "b", "", KeyType::Text}, + {3, 5, 1, 1, "n", "", KeyType::Text}, + {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 + {4, 0, 1, 1, "SF", "L2", KeyType::Shift}, //{4, 0, 1, 1, "⇧", "L2", KeyType::Shift}, + {4, 1, 1, 1, "@#:", "L2+TRI", + KeyType::SymbolsLayout}, //{4, 1, 1, 1, "@#:", "L2+△", KeyType::Symbols}, + {4, 2, 1, 1, "à", "L3", KeyType::UnknownFunction}, + {4, 3, 4, 1, "Space", "TRI", KeyType::Space}, //{4, 3, 4, 1, "Space", "△", KeyType::Space}, + //{4, 4, 4, 1, "Space", "△", KeyType::Space}, + //{4, 5, 4, 1, "Space", "△", KeyType::Space}, + //{4, 6, 4, 1, "Space", "△", KeyType::Space}, + {4, 7, 1, 1, "", "", KeyType::Disabled}, + {4, 8, 2, 1, "DEL", "SQR", KeyType::Backspace}, //{4, 8, 2, 1, "⌫", "▢", KeyType::Backspace}, + //{4, 8, 2, 1, "⌫", "▢", KeyType::Backspace}, + + // Row 6 + {5, 0, 1, 1, "UP", "", KeyType::CursorUp}, // {5, 0, 1, 1, "▲", "", KeyType::CursorUp}, + {5, 1, 1, 1, "DN", "", KeyType::CursorDown}, //{5, 1, 1, 1, "▼", "", KeyType::CursorDown}, + {5, 2, 1, 1, "LT", "L1", KeyType::CursorLeft}, //{5, 2, 1, 1, "◀", "L1", KeyType::CursorLeft}, + {5, 3, 1, 1, "RT", "R1", + KeyType::CursorRight}, //{5, 3, 1, 1, "▶", "R1", KeyType::CursorRight}, + {5, 4, 1, 1, "KB", "", + KeyType::ToggleKeyboard}, //{5, 4, 1, 1, "⌨", "", KeyType::ToggleKeyboard}, + {5, 5, 1, 1, "...", "", KeyType::MoreOptions}, //{5, 5, 1, 1, "…", "", KeyType::MoreOptions}, + {5, 6, 1, 1, "CR", "R1", + KeyType::ControllerAction}, //{5, 6, 1, 1, "🎮⊕", "R1", KeyType::ControllerAction}, + {5, 7, 1, 1, "", "", KeyType::Disabled}, + {5, 8, 2, 1, "Done", "R2", KeyType::Done}, + //{5, 9, 2, 1, "Done", "R2", KeyType::Done}, +}; + +const std::vector kSymbols1Layout = { + // 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::UnknownFunction}, // Next symbols page (SYM2) + + // 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::UnknownFunction}, // Next symbols page (SYM2) + + // Row 5 + {4, 0, 1, 1, "", "", KeyType::Disabled}, + {4, 1, 1, 1, "ABC", "L2+TRI", + KeyType::TextLayout}, //{4, 1, 1, 1, "ABC", "L2+△", KeyType::Symbols}, + {4, 2, 1, 1, "", "", KeyType::Disabled}, + {4, 3, 4, 1, "Space", "TRI", KeyType::Space}, //{4, 3, 4, 1, "Space", "△", KeyType::Space}, + //{4, 4, 4, 1, "Space", "△", KeyType::Space}, + //{4, 5, 4, 1, "Space", "△", KeyType::Space}, + //{4, 6, 4, 1, "Space", "△", KeyType::Space}, + {4, 7, 1, 1, "", "", KeyType::Disabled}, + {4, 8, 2, 1, "DEL", "SQR", KeyType::Backspace}, //{4, 8, 2, 1, "⌫", "▢", KeyType::Backspace}, + //{4, 9, 2, 1, "⌫", "▢", KeyType::Backspace}, + + // Row 6 + {5, 0, 1, 1, "UP", "", KeyType::CursorUp}, // {5, 0, 1, 1, "▲", "", KeyType::CursorUp}, + {5, 1, 1, 1, "DN", "", KeyType::CursorDown}, //{5, 1, 1, 1, "▼", "", KeyType::CursorDown}, + {5, 2, 1, 1, "LT", "L1", KeyType::CursorLeft}, //{5, 2, 1, 1, "◀", "L1", KeyType::CursorLeft}, + {5, 3, 1, 1, "RT", "R1", + KeyType::CursorRight}, //{5, 3, 1, 1, "▶", "R1", KeyType::CursorRight}, + {5, 4, 1, 1, "KB", "", + KeyType::ToggleKeyboard}, //{5, 4, 1, 1, "⌨", "", KeyType::ToggleKeyboard}, + {5, 5, 1, 1, "...", "", KeyType::MoreOptions}, //{5, 5, 1, 1, "…", "", KeyType::MoreOptions}, + {5, 6, 1, 1, "CR", "R1", + KeyType::ControllerAction}, //{5, 6, 1, 1, "🎮⊕", "R1", KeyType::ControllerAction}, + {5, 7, 1, 1, "", "", KeyType::Disabled}, + {5, 8, 2, 1, "Done", "R2", KeyType::Done}, + //{5, 9, 2, 1, "Done", "R2", KeyType::Done}, +}; diff --git a/src/core/libraries/ime/ime_keyboard_layouts.h b/src/core/libraries/ime/ime_keyboard_layouts.h new file mode 100644 index 000000000..0f51509c6 --- /dev/null +++ b/src/core/libraries/ime/ime_keyboard_layouts.h @@ -0,0 +1,41 @@ +// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include +#include + +enum class KeyType { + Text, // Inserts character(s) into input buffer + Backspace, // Deletes last character + Space, // Adds space + Enter, // Submits input + Shift, // Toggle uppercase/lowercase + SymbolsLayout, // Switch to symbols layout + TextLayout, // Switch to text layout + Done, // Finish and close keyboard + CursorLeft, + CursorRight, + CursorUp, + CursorDown, + ToggleKeyboard, // Toggles keyboard layout + MoreOptions, // "..." button + ControllerAction, // e.g. R3 🎮⊕ + Disabled, // Filler or placeholder + UnknownFunction, // now same as disabled +}; + +struct Key { + int row; + int col; + int colspan = 1; + int rowspan = 1; + std::string label; + std::string controller_hint; + KeyType type = KeyType::Text; // default to Text input +}; + +extern const std::vector kUppercaseLayout; +extern const std::vector kLowercaseLayout; +extern const std::vector kSymbols1Layout; diff --git a/src/core/libraries/ime/ime_keyboard_ui.cpp b/src/core/libraries/ime/ime_keyboard_ui.cpp index bbf2435ed..6322eb2f7 100644 --- a/src/core/libraries/ime/ime_keyboard_ui.cpp +++ b/src/core/libraries/ime/ime_keyboard_ui.cpp @@ -1,96 +1,134 @@ // SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later -#include #include -#include #include +#include "ime_keyboard_layouts.h" #include "ime_keyboard_ui.h" +using namespace ImGui; + void DrawVirtualKeyboard(char* buffer, std::size_t buffer_capacity, bool* input_changed, - KeyboardMode& kb_mode, bool& shift_enabled) { - const char* row1_letters = "QWERTYUIOP"; - const char* row2_letters = "ASDFGHJKL"; - const char* row3_letters = "ZXCVBNM"; + KeyboardMode& kb_mode, bool& shift_enabled, bool* done_pressed) { + const std::vector* layout = nullptr; - const char* row1_symbols = "1234567890"; - const char* row2_symbols = "!@#$%^&*()"; - const char* row3_symbols = "-_=+[]{}"; + if (kb_mode == KeyboardMode::Symbols) { + layout = &kSymbols1Layout; + } else { + layout = shift_enabled ? &kUppercaseLayout : &kLowercaseLayout; + } - auto draw_row = [&](const char* row, float offset_x) { - ImGui::SetCursorPosX(offset_x); - for (int i = 0; row[i] != '\0'; ++i) { - char ch = shift_enabled ? row[i] : static_cast(tolower(row[i])); - std::string key(1, ch); - if (ImGui::Button(key.c_str(), ImVec2(35, 35))) { - size_t len = std::strlen(buffer); - if (len + 1 < buffer_capacity) { - buffer[len] = ch; - buffer[len + 1] = '\0'; - if (input_changed) { - *input_changed = true; + RenderKeyboardLayout(*layout, buffer, buffer_capacity, input_changed, kb_mode, shift_enabled, + done_pressed); +} + +void RenderKeyboardLayout(const std::vector& layout, char* buffer, std::size_t buffer_capacity, + bool* input_changed, KeyboardMode& kb_mode, bool& shift_enabled, + bool* done_pressed) { + // Define desired total layout size (in pixels) + const float layout_width = 485.0f; + const float layout_height = 200.0f; + const float cell_spacing = 4.0f; + const float hint_padding = 2.0f; + + // Find max rows and columns + int max_col = 0; + int max_row = 0; + for (const Key& key : layout) { + max_col = std::max(max_col, key.col + static_cast(key.colspan)); + max_row = std::max(max_row, key.row + static_cast(key.rowspan)); + } + + // Calculate cell size dynamically + const float cell_width = (layout_width - (max_col - 1) * cell_spacing) / max_col; + const float cell_height = (layout_height - (max_row - 1) * cell_spacing) / max_row; + + const ImVec2 origin = ImGui::GetCursorScreenPos(); + ImDrawList* draw_list = ImGui::GetWindowDrawList(); + + for (const Key& key : layout) { + float x = origin.x + key.col * (cell_width + cell_spacing); + float y = origin.y + key.row * (cell_height + cell_spacing); + + ImVec2 pos(x, y); + ImVec2 size(key.colspan * cell_width + (key.colspan - 1) * cell_spacing, + key.rowspan * cell_height + (key.rowspan - 1) * cell_spacing); + + std::string button_id = + key.label.empty() ? "##empty_" + std::to_string(key.row) + "_" + std::to_string(key.col) + : key.label; + + ImGui::SetCursorScreenPos(pos); + + if (ImGui::Button(button_id.c_str(), size)) { + switch (key.type) { + 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; } } - } - ImGui::SameLine(); - } - ImGui::NewLine(); - }; - - // SHIFT status label - if (shift_enabled) { - ImGui::SetCursorPosX(20.0f); - ImGui::TextColored(ImVec4(0.2f, 0.6f, 1.0f, 1.0f), "SHIFT ENABLED"); - } - - draw_row(kb_mode == KeyboardMode::Letters ? row1_letters : row1_symbols, 20.0f); - draw_row(kb_mode == KeyboardMode::Letters ? row2_letters : row2_symbols, 35.0f); - draw_row(kb_mode == KeyboardMode::Letters ? row3_letters : row3_symbols, 80.0f); - - ImGui::SetCursorPosX(20.0f); - - bool highlight = shift_enabled; - if (highlight) { - ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0.2f, 0.6f, 1.0f, 1.0f)); - } - - if (ImGui::Button("SHIFT", ImVec2(75, 35))) { - shift_enabled = !shift_enabled; - } - - if (highlight) { - ImGui::PopStyleColor(); - } - - ImGui::SameLine(); - - if (ImGui::Button("SPACE", ImVec2(100, 35))) { - size_t len = std::strlen(buffer); - if (len + 1 < buffer_capacity) { - buffer[len] = ' '; - buffer[len + 1] = '\0'; - if (input_changed) { - *input_changed = true; + break; + case KeyType::Backspace: + if (buffer[0] != '\0') { + size_t len = std::strlen(buffer); + buffer[len - 1] = '\0'; + 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::SymbolsLayout: + kb_mode = KeyboardMode::Symbols; + break; + case KeyType::TextLayout: + kb_mode = KeyboardMode::Letters; + break; + case KeyType::ToggleKeyboard: + kb_mode = (kb_mode == KeyboardMode::Letters) ? KeyboardMode::Symbols + : KeyboardMode::Letters; + break; + default: + break; } } - } - ImGui::SameLine(); + // Controller hint + if (!key.controller_hint.empty()) { + float original_font_size = ImGui::GetFontSize(); + float small_font_size = original_font_size * 0.5f; - if (ImGui::Button("DELETE", ImVec2(75, 35))) { - size_t len = std::strlen(buffer); - if (len > 0) { - buffer[len - 1] = '\0'; - if (input_changed) { - *input_changed = true; - } + 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::SameLine(); - - if (ImGui::Button(kb_mode == KeyboardMode::Letters ? "123" : "ABC", ImVec2(60, 35))) { - kb_mode = - (kb_mode == KeyboardMode::Letters) ? KeyboardMode::Symbols : KeyboardMode::Letters; - } } diff --git a/src/core/libraries/ime/ime_keyboard_ui.h b/src/core/libraries/ime/ime_keyboard_ui.h index 0a5393bcc..19be74a9d 100644 --- a/src/core/libraries/ime/ime_keyboard_ui.h +++ b/src/core/libraries/ime/ime_keyboard_ui.h @@ -1,9 +1,23 @@ +// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + #pragma once #include "common/cstring.h" #include "common/types.h" +#include "core/libraries/ime/ime_dialog.h" +#include "core/libraries/ime/ime_keyboard_layouts.h" enum class KeyboardMode { Letters, Symbols }; +// Renders the virtual keyboard and modifies buffer if a key is pressed. +// Flags: +// - `input_changed`: set to true if the text buffer changes +// - `done_pressed`: set to true if the Done/Enter key was pressed void DrawVirtualKeyboard(char* buffer, std::size_t buffer_capacity, bool* input_changed, - KeyboardMode& kb_mode, bool& shift_enabled); + KeyboardMode& kb_mode, bool& shift_enabled, bool* done_pressed); + +// Renders a specific keyboard layout and processes key events. +void RenderKeyboardLayout(const std::vector& layout, char* buffer, std::size_t buffer_capacity, + bool* input_changed, KeyboardMode& kb_mode, bool& shift_enabled, + bool* done_pressed); diff --git a/src/core/libraries/ime/ime_ui.cpp b/src/core/libraries/ime/ime_ui.cpp index 43bbf6a85..0ba2dc433 100644 --- a/src/core/libraries/ime/ime_ui.cpp +++ b/src/core/libraries/ime/ime_ui.cpp @@ -195,12 +195,19 @@ void ImeUi::DrawKeyboard() { static bool has_logged = false; if (!has_logged) { - LOG_INFO(Lib_ImeDialog, "Virtual keyboard used from Ime"); + LOG_INFO(Lib_Ime, "Virtual keyboard used from ImeUi"); has_logged = true; } - DrawVirtualKeyboard(state->current_text.begin(), ime_param->maxTextLength * 4, nullptr, kb_mode, - shift_enabled); + 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 (done_pressed) { + state->SendEnterEvent(); // Submit action + } } int ImeUi::InputTextCallback(ImGuiInputTextCallbackData* data) {