mirror of
https://github.com/shadps4-emu/shadPS4.git
synced 2025-06-12 13:43:15 +00:00
Switch remaining CRLF terminated files to LF
This commit is contained in:
parent
2c0f986c52
commit
c284cf72e1
28 changed files with 4856 additions and 4856 deletions
|
@ -1,183 +1,183 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "common/types.h"
|
||||
#include "core/libraries/rtc/rtc.h"
|
||||
|
||||
enum class OrbisImeType : u32 {
|
||||
Default = 0,
|
||||
BasicLatin = 1,
|
||||
Url = 2,
|
||||
Mail = 3,
|
||||
Number = 4,
|
||||
};
|
||||
|
||||
enum class OrbisImeHorizontalAlignment : u32 {
|
||||
Left = 0,
|
||||
Center = 1,
|
||||
Right = 2,
|
||||
};
|
||||
|
||||
enum class OrbisImeVerticalAlignment : u32 {
|
||||
Top = 0,
|
||||
Center = 1,
|
||||
Bottom = 2,
|
||||
};
|
||||
|
||||
enum class OrbisImeEnterLabel : u32 {
|
||||
Default = 0,
|
||||
Send = 1,
|
||||
Search = 2,
|
||||
Go = 3,
|
||||
};
|
||||
|
||||
enum class OrbisImeInputMethod : u32 {
|
||||
Default = 0,
|
||||
};
|
||||
|
||||
enum class OrbisImeEventId : u32 {
|
||||
Open = 0,
|
||||
UpdateText = 1,
|
||||
UpdateCaret = 2,
|
||||
PressClose = 4,
|
||||
PressEnter = 5,
|
||||
Abort = 6,
|
||||
CandidateListStart = 7,
|
||||
CandidateListEnd = 8,
|
||||
CandidateWord = 9,
|
||||
CandidateIndex = 10,
|
||||
CandidateDone = 11,
|
||||
CandidateCancel = 12,
|
||||
ChangeDevice = 14,
|
||||
ChangeInputMethodState = 18,
|
||||
|
||||
KeyboardOpen = 256,
|
||||
KeyboardKeycodeDoen = 257,
|
||||
KeyboardKeycodeUp = 258,
|
||||
KeyboardKeycodeRepeat = 259,
|
||||
KeyboardConnection = 260,
|
||||
KeyboardDisconnection = 261,
|
||||
KeyboardAbort = 262,
|
||||
};
|
||||
|
||||
enum class OrbisImeKeyboardType : u32 {
|
||||
NONE = 0,
|
||||
DANISH = 1,
|
||||
GERMAN = 2,
|
||||
GERMAN_SW = 3,
|
||||
ENGLISH_US = 4,
|
||||
ENGLISH_GB = 5,
|
||||
SPANISH = 6,
|
||||
SPANISH_LA = 7,
|
||||
FINNISH = 8,
|
||||
FRENCH = 9,
|
||||
FRENCH_BR = 10,
|
||||
FRENCH_CA = 11,
|
||||
FRENCH_SW = 12,
|
||||
ITALIAN = 13,
|
||||
DUTCH = 14,
|
||||
NORWEGIAN = 15,
|
||||
POLISH = 16,
|
||||
PORTUGUESE_BR = 17,
|
||||
PORTUGUESE_PT = 18,
|
||||
RUSSIAN = 19,
|
||||
SWEDISH = 20,
|
||||
TURKISH = 21,
|
||||
JAPANESE_ROMAN = 22,
|
||||
JAPANESE_KANA = 23,
|
||||
KOREAN = 24,
|
||||
SM_CHINESE = 25,
|
||||
TR_CHINESE_ZY = 26,
|
||||
TR_CHINESE_PY_HK = 27,
|
||||
TR_CHINESE_PY_TW = 28,
|
||||
TR_CHINESE_CG = 29,
|
||||
ARABIC_AR = 30,
|
||||
THAI = 31,
|
||||
CZECH = 32,
|
||||
GREEK = 33,
|
||||
INDONESIAN = 34,
|
||||
VIETNAMESE = 35,
|
||||
ROMANIAN = 36,
|
||||
HUNGARIAN = 37,
|
||||
};
|
||||
|
||||
enum class OrbisImeDeviceType : u32 {
|
||||
None = 0,
|
||||
Controller = 1,
|
||||
ExtKeyboard = 2,
|
||||
RemoteOsk = 3,
|
||||
};
|
||||
|
||||
struct OrbisImeRect {
|
||||
f32 x;
|
||||
f32 y;
|
||||
u32 width;
|
||||
u32 height;
|
||||
};
|
||||
|
||||
struct OrbisImeTextAreaProperty {
|
||||
u32 mode; // OrbisImeTextAreaMode
|
||||
u32 index;
|
||||
s32 length;
|
||||
};
|
||||
|
||||
struct OrbisImeEditText {
|
||||
char16_t* str;
|
||||
u32 caret_index;
|
||||
u32 area_num;
|
||||
OrbisImeTextAreaProperty text_area[4];
|
||||
};
|
||||
|
||||
struct OrbisImeKeycode {
|
||||
u16 keycode;
|
||||
char16_t character;
|
||||
u32 status;
|
||||
OrbisImeKeyboardType type;
|
||||
s32 user_id;
|
||||
u32 resource_id;
|
||||
Libraries::Rtc::OrbisRtcTick timestamp;
|
||||
};
|
||||
|
||||
struct OrbisImeKeyboardResourceIdArray {
|
||||
s32 userId;
|
||||
u32 resourceId[5];
|
||||
};
|
||||
|
||||
enum class OrbisImeCaretMovementDirection : u32 {
|
||||
Still = 0,
|
||||
Left = 1,
|
||||
Right = 2,
|
||||
Up = 3,
|
||||
Down = 4,
|
||||
Home = 5,
|
||||
End = 6,
|
||||
PageUp = 7,
|
||||
PageDown = 8,
|
||||
Top = 9,
|
||||
Bottom = 10,
|
||||
};
|
||||
|
||||
union OrbisImeEventParam {
|
||||
OrbisImeRect rect;
|
||||
OrbisImeEditText text;
|
||||
OrbisImeCaretMovementDirection caret_move;
|
||||
OrbisImeKeycode keycode;
|
||||
OrbisImeKeyboardResourceIdArray resource_id_array;
|
||||
char16_t* candidate_word;
|
||||
s32 candidate_index;
|
||||
OrbisImeDeviceType device_type;
|
||||
u32 input_method_state;
|
||||
s8 reserved[64];
|
||||
};
|
||||
|
||||
struct OrbisImeEvent {
|
||||
OrbisImeEventId id;
|
||||
OrbisImeEventParam param;
|
||||
};
|
||||
|
||||
using OrbisImeTextFilter = PS4_SYSV_ABI int (*)(char16_t* outText, u32* outTextLength,
|
||||
const char16_t* srcText, u32 srcTextLength);
|
||||
|
||||
using OrbisImeEventHandler = PS4_SYSV_ABI void (*)(void* arg, const OrbisImeEvent* e);
|
||||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "common/types.h"
|
||||
#include "core/libraries/rtc/rtc.h"
|
||||
|
||||
enum class OrbisImeType : u32 {
|
||||
Default = 0,
|
||||
BasicLatin = 1,
|
||||
Url = 2,
|
||||
Mail = 3,
|
||||
Number = 4,
|
||||
};
|
||||
|
||||
enum class OrbisImeHorizontalAlignment : u32 {
|
||||
Left = 0,
|
||||
Center = 1,
|
||||
Right = 2,
|
||||
};
|
||||
|
||||
enum class OrbisImeVerticalAlignment : u32 {
|
||||
Top = 0,
|
||||
Center = 1,
|
||||
Bottom = 2,
|
||||
};
|
||||
|
||||
enum class OrbisImeEnterLabel : u32 {
|
||||
Default = 0,
|
||||
Send = 1,
|
||||
Search = 2,
|
||||
Go = 3,
|
||||
};
|
||||
|
||||
enum class OrbisImeInputMethod : u32 {
|
||||
Default = 0,
|
||||
};
|
||||
|
||||
enum class OrbisImeEventId : u32 {
|
||||
Open = 0,
|
||||
UpdateText = 1,
|
||||
UpdateCaret = 2,
|
||||
PressClose = 4,
|
||||
PressEnter = 5,
|
||||
Abort = 6,
|
||||
CandidateListStart = 7,
|
||||
CandidateListEnd = 8,
|
||||
CandidateWord = 9,
|
||||
CandidateIndex = 10,
|
||||
CandidateDone = 11,
|
||||
CandidateCancel = 12,
|
||||
ChangeDevice = 14,
|
||||
ChangeInputMethodState = 18,
|
||||
|
||||
KeyboardOpen = 256,
|
||||
KeyboardKeycodeDoen = 257,
|
||||
KeyboardKeycodeUp = 258,
|
||||
KeyboardKeycodeRepeat = 259,
|
||||
KeyboardConnection = 260,
|
||||
KeyboardDisconnection = 261,
|
||||
KeyboardAbort = 262,
|
||||
};
|
||||
|
||||
enum class OrbisImeKeyboardType : u32 {
|
||||
NONE = 0,
|
||||
DANISH = 1,
|
||||
GERMAN = 2,
|
||||
GERMAN_SW = 3,
|
||||
ENGLISH_US = 4,
|
||||
ENGLISH_GB = 5,
|
||||
SPANISH = 6,
|
||||
SPANISH_LA = 7,
|
||||
FINNISH = 8,
|
||||
FRENCH = 9,
|
||||
FRENCH_BR = 10,
|
||||
FRENCH_CA = 11,
|
||||
FRENCH_SW = 12,
|
||||
ITALIAN = 13,
|
||||
DUTCH = 14,
|
||||
NORWEGIAN = 15,
|
||||
POLISH = 16,
|
||||
PORTUGUESE_BR = 17,
|
||||
PORTUGUESE_PT = 18,
|
||||
RUSSIAN = 19,
|
||||
SWEDISH = 20,
|
||||
TURKISH = 21,
|
||||
JAPANESE_ROMAN = 22,
|
||||
JAPANESE_KANA = 23,
|
||||
KOREAN = 24,
|
||||
SM_CHINESE = 25,
|
||||
TR_CHINESE_ZY = 26,
|
||||
TR_CHINESE_PY_HK = 27,
|
||||
TR_CHINESE_PY_TW = 28,
|
||||
TR_CHINESE_CG = 29,
|
||||
ARABIC_AR = 30,
|
||||
THAI = 31,
|
||||
CZECH = 32,
|
||||
GREEK = 33,
|
||||
INDONESIAN = 34,
|
||||
VIETNAMESE = 35,
|
||||
ROMANIAN = 36,
|
||||
HUNGARIAN = 37,
|
||||
};
|
||||
|
||||
enum class OrbisImeDeviceType : u32 {
|
||||
None = 0,
|
||||
Controller = 1,
|
||||
ExtKeyboard = 2,
|
||||
RemoteOsk = 3,
|
||||
};
|
||||
|
||||
struct OrbisImeRect {
|
||||
f32 x;
|
||||
f32 y;
|
||||
u32 width;
|
||||
u32 height;
|
||||
};
|
||||
|
||||
struct OrbisImeTextAreaProperty {
|
||||
u32 mode; // OrbisImeTextAreaMode
|
||||
u32 index;
|
||||
s32 length;
|
||||
};
|
||||
|
||||
struct OrbisImeEditText {
|
||||
char16_t* str;
|
||||
u32 caret_index;
|
||||
u32 area_num;
|
||||
OrbisImeTextAreaProperty text_area[4];
|
||||
};
|
||||
|
||||
struct OrbisImeKeycode {
|
||||
u16 keycode;
|
||||
char16_t character;
|
||||
u32 status;
|
||||
OrbisImeKeyboardType type;
|
||||
s32 user_id;
|
||||
u32 resource_id;
|
||||
Libraries::Rtc::OrbisRtcTick timestamp;
|
||||
};
|
||||
|
||||
struct OrbisImeKeyboardResourceIdArray {
|
||||
s32 userId;
|
||||
u32 resourceId[5];
|
||||
};
|
||||
|
||||
enum class OrbisImeCaretMovementDirection : u32 {
|
||||
Still = 0,
|
||||
Left = 1,
|
||||
Right = 2,
|
||||
Up = 3,
|
||||
Down = 4,
|
||||
Home = 5,
|
||||
End = 6,
|
||||
PageUp = 7,
|
||||
PageDown = 8,
|
||||
Top = 9,
|
||||
Bottom = 10,
|
||||
};
|
||||
|
||||
union OrbisImeEventParam {
|
||||
OrbisImeRect rect;
|
||||
OrbisImeEditText text;
|
||||
OrbisImeCaretMovementDirection caret_move;
|
||||
OrbisImeKeycode keycode;
|
||||
OrbisImeKeyboardResourceIdArray resource_id_array;
|
||||
char16_t* candidate_word;
|
||||
s32 candidate_index;
|
||||
OrbisImeDeviceType device_type;
|
||||
u32 input_method_state;
|
||||
s8 reserved[64];
|
||||
};
|
||||
|
||||
struct OrbisImeEvent {
|
||||
OrbisImeEventId id;
|
||||
OrbisImeEventParam param;
|
||||
};
|
||||
|
||||
using OrbisImeTextFilter = PS4_SYSV_ABI int (*)(char16_t* outText, u32* outTextLength,
|
||||
const char16_t* srcText, u32 srcTextLength);
|
||||
|
||||
using OrbisImeEventHandler = PS4_SYSV_ABI void (*)(void* arg, const OrbisImeEvent* e);
|
||||
|
|
|
@ -1,253 +1,253 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "ime_ui.h"
|
||||
#include "imgui/imgui_std.h"
|
||||
|
||||
namespace Libraries::Ime {
|
||||
|
||||
using namespace ImGui;
|
||||
|
||||
static constexpr ImVec2 BUTTON_SIZE{100.0f, 30.0f};
|
||||
|
||||
ImeState::ImeState(const OrbisImeParam* param) {
|
||||
if (!param) {
|
||||
return;
|
||||
}
|
||||
|
||||
work_buffer = param->work;
|
||||
text_buffer = param->inputTextBuffer;
|
||||
|
||||
std::size_t text_len = std::char_traits<char16_t>::length(text_buffer);
|
||||
if (!ConvertOrbisToUTF8(text_buffer, text_len, current_text.begin(),
|
||||
ORBIS_IME_MAX_TEXT_LENGTH * 4)) {
|
||||
LOG_ERROR(Lib_ImeDialog, "Failed to convert text to utf8 encoding");
|
||||
}
|
||||
}
|
||||
|
||||
ImeState::ImeState(ImeState&& other) noexcept
|
||||
: work_buffer(other.work_buffer), text_buffer(other.text_buffer),
|
||||
current_text(std::move(other.current_text)), event_queue(std::move(other.event_queue)) {
|
||||
other.text_buffer = nullptr;
|
||||
}
|
||||
|
||||
ImeState& ImeState::operator=(ImeState&& other) noexcept {
|
||||
if (this != &other) {
|
||||
work_buffer = other.work_buffer;
|
||||
text_buffer = other.text_buffer;
|
||||
current_text = std::move(other.current_text);
|
||||
event_queue = std::move(other.event_queue);
|
||||
|
||||
other.text_buffer = nullptr;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
void ImeState::SendEvent(OrbisImeEvent* event) {
|
||||
std::unique_lock lock{queue_mutex};
|
||||
event_queue.push(*event);
|
||||
}
|
||||
|
||||
void ImeState::SendEnterEvent() {
|
||||
OrbisImeEvent enterEvent{};
|
||||
enterEvent.id = OrbisImeEventId::PressEnter;
|
||||
SendEvent(&enterEvent);
|
||||
}
|
||||
|
||||
void ImeState::SendCloseEvent() {
|
||||
OrbisImeEvent closeEvent{};
|
||||
closeEvent.id = OrbisImeEventId::PressClose;
|
||||
closeEvent.param.text.str = reinterpret_cast<char16_t*>(work_buffer);
|
||||
SendEvent(&closeEvent);
|
||||
}
|
||||
|
||||
void ImeState::SetText(const char16_t* text, u32 length) {}
|
||||
|
||||
void ImeState::SetCaret(u32 position) {}
|
||||
|
||||
bool ImeState::ConvertOrbisToUTF8(const char16_t* orbis_text, std::size_t orbis_text_len,
|
||||
char* utf8_text, std::size_t utf8_text_len) {
|
||||
std::fill(utf8_text, utf8_text + utf8_text_len, '\0');
|
||||
const ImWchar* orbis_text_ptr = reinterpret_cast<const ImWchar*>(orbis_text);
|
||||
ImTextStrToUtf8(utf8_text, utf8_text_len, orbis_text_ptr, orbis_text_ptr + orbis_text_len);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ImeState::ConvertUTF8ToOrbis(const char* utf8_text, std::size_t utf8_text_len,
|
||||
char16_t* orbis_text, std::size_t orbis_text_len) {
|
||||
std::fill(orbis_text, orbis_text + orbis_text_len, u'\0');
|
||||
ImTextStrFromUtf8(reinterpret_cast<ImWchar*>(orbis_text), orbis_text_len, utf8_text, nullptr);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
ImeUi::ImeUi(ImeState* state, const OrbisImeParam* param) : state(state), ime_param(param) {
|
||||
if (param) {
|
||||
AddLayer(this);
|
||||
}
|
||||
}
|
||||
|
||||
ImeUi::~ImeUi() {
|
||||
std::scoped_lock lock(draw_mutex);
|
||||
Free();
|
||||
}
|
||||
|
||||
ImeUi& ImeUi::operator=(ImeUi&& other) {
|
||||
std::scoped_lock lock(draw_mutex, other.draw_mutex);
|
||||
Free();
|
||||
|
||||
state = other.state;
|
||||
ime_param = other.ime_param;
|
||||
first_render = other.first_render;
|
||||
other.state = nullptr;
|
||||
other.ime_param = nullptr;
|
||||
|
||||
AddLayer(this);
|
||||
return *this;
|
||||
}
|
||||
|
||||
void ImeUi::Draw() {
|
||||
std::unique_lock lock{draw_mutex};
|
||||
|
||||
if (!state) {
|
||||
return;
|
||||
}
|
||||
|
||||
const auto& ctx = *GetCurrentContext();
|
||||
const auto& io = ctx.IO;
|
||||
|
||||
// TODO: Figure out how to properly translate the positions -
|
||||
// for example, if a game wants to center the IME panel,
|
||||
// we have to translate the panel position in a way that it
|
||||
// still becomes centered, as the game normally calculates
|
||||
// the position assuming a it's running on a 1920x1080 screen,
|
||||
// whereas we are running on a 1280x720 window size (by default).
|
||||
//
|
||||
// e.g. Panel position calculation from a game:
|
||||
// param.posx = (1920 / 2) - (panelWidth / 2);
|
||||
// param.posy = (1080 / 2) - (panelHeight / 2);
|
||||
const auto size = GetIO().DisplaySize;
|
||||
f32 pos_x = (ime_param->posx / 1920.0f * (float)size.x);
|
||||
f32 pos_y = (ime_param->posy / 1080.0f * (float)size.y);
|
||||
|
||||
ImVec2 window_pos = {pos_x, pos_y};
|
||||
ImVec2 window_size = {500.0f, 100.0f};
|
||||
|
||||
// SetNextWindowPos(window_pos);
|
||||
SetNextWindowPos(ImVec2(io.DisplaySize.x * 0.5f, io.DisplaySize.y * 0.5f),
|
||||
ImGuiCond_FirstUseEver, ImVec2(0.5f, 0.5f));
|
||||
SetNextWindowSize(window_size);
|
||||
SetNextWindowCollapsed(false);
|
||||
|
||||
if (first_render || !io.NavActive) {
|
||||
SetNextWindowFocus();
|
||||
}
|
||||
|
||||
if (Begin("IME##Ime", nullptr,
|
||||
ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize |
|
||||
ImGuiWindowFlags_NoSavedSettings)) {
|
||||
DrawPrettyBackground();
|
||||
|
||||
DrawInputText();
|
||||
SetCursorPosY(GetCursorPosY() + 10.0f);
|
||||
|
||||
const char* button_text;
|
||||
button_text = "Done##ImeDone";
|
||||
|
||||
float button_spacing = 10.0f;
|
||||
float total_button_width = BUTTON_SIZE.x * 2 + button_spacing;
|
||||
float button_start_pos = (window_size.x - total_button_width) / 2.0f;
|
||||
|
||||
SetCursorPosX(button_start_pos);
|
||||
|
||||
if (Button(button_text, BUTTON_SIZE) || (IsKeyPressed(ImGuiKey_Enter))) {
|
||||
state->SendEnterEvent();
|
||||
}
|
||||
|
||||
SameLine(0.0f, button_spacing);
|
||||
|
||||
if (Button("Close##ImeClose", BUTTON_SIZE)) {
|
||||
state->SendCloseEvent();
|
||||
}
|
||||
}
|
||||
End();
|
||||
|
||||
first_render = false;
|
||||
}
|
||||
|
||||
void ImeUi::DrawInputText() {
|
||||
ImVec2 input_size = {GetWindowWidth() - 40.0f, 0.0f};
|
||||
SetCursorPosX(20.0f);
|
||||
if (first_render) {
|
||||
SetKeyboardFocusHere();
|
||||
}
|
||||
if (InputTextEx("##ImeInput", nullptr, state->current_text.begin(), ime_param->maxTextLength,
|
||||
input_size, ImGuiInputTextFlags_CallbackAlways, InputTextCallback, this)) {
|
||||
}
|
||||
}
|
||||
|
||||
int ImeUi::InputTextCallback(ImGuiInputTextCallbackData* data) {
|
||||
ImeUi* ui = static_cast<ImeUi*>(data->UserData);
|
||||
ASSERT(ui);
|
||||
|
||||
static std::string lastText;
|
||||
std::string currentText(data->Buf, data->BufTextLen);
|
||||
if (currentText != lastText) {
|
||||
OrbisImeEditText eventParam{};
|
||||
eventParam.str = reinterpret_cast<char16_t*>(ui->ime_param->work);
|
||||
eventParam.caret_index = data->CursorPos;
|
||||
eventParam.area_num = 1;
|
||||
|
||||
eventParam.text_area[0].mode = 1; // Edit mode
|
||||
eventParam.text_area[0].index = data->CursorPos;
|
||||
eventParam.text_area[0].length = data->BufTextLen;
|
||||
|
||||
if (!ui->state->ConvertUTF8ToOrbis(data->Buf, data->BufTextLen, eventParam.str,
|
||||
ui->ime_param->maxTextLength)) {
|
||||
LOG_ERROR(Lib_ImeDialog, "Failed to convert Orbis char to UTF-8");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!ui->state->ConvertUTF8ToOrbis(data->Buf, data->BufTextLen,
|
||||
ui->ime_param->inputTextBuffer,
|
||||
ui->ime_param->maxTextLength)) {
|
||||
LOG_ERROR(Lib_ImeDialog, "Failed to convert Orbis char to UTF-8");
|
||||
return 0;
|
||||
}
|
||||
|
||||
OrbisImeEvent event{};
|
||||
event.id = OrbisImeEventId::UpdateText;
|
||||
event.param.text = eventParam;
|
||||
|
||||
lastText = currentText;
|
||||
ui->state->SendEvent(&event);
|
||||
}
|
||||
|
||||
static int lastCaretPos = -1;
|
||||
if (lastCaretPos == -1) {
|
||||
lastCaretPos = data->CursorPos;
|
||||
} else if (data->CursorPos != lastCaretPos) {
|
||||
OrbisImeCaretMovementDirection caretDirection = OrbisImeCaretMovementDirection::Still;
|
||||
if (data->CursorPos < lastCaretPos) {
|
||||
caretDirection = OrbisImeCaretMovementDirection::Left;
|
||||
} else if (data->CursorPos > lastCaretPos) {
|
||||
caretDirection = OrbisImeCaretMovementDirection::Right;
|
||||
}
|
||||
|
||||
OrbisImeEvent event{};
|
||||
event.id = OrbisImeEventId::UpdateCaret;
|
||||
event.param.caret_move = caretDirection;
|
||||
|
||||
lastCaretPos = data->CursorPos;
|
||||
ui->state->SendEvent(&event);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ImeUi::Free() {
|
||||
RemoveLayer(this);
|
||||
}
|
||||
|
||||
}; // namespace Libraries::Ime
|
||||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "ime_ui.h"
|
||||
#include "imgui/imgui_std.h"
|
||||
|
||||
namespace Libraries::Ime {
|
||||
|
||||
using namespace ImGui;
|
||||
|
||||
static constexpr ImVec2 BUTTON_SIZE{100.0f, 30.0f};
|
||||
|
||||
ImeState::ImeState(const OrbisImeParam* param) {
|
||||
if (!param) {
|
||||
return;
|
||||
}
|
||||
|
||||
work_buffer = param->work;
|
||||
text_buffer = param->inputTextBuffer;
|
||||
|
||||
std::size_t text_len = std::char_traits<char16_t>::length(text_buffer);
|
||||
if (!ConvertOrbisToUTF8(text_buffer, text_len, current_text.begin(),
|
||||
ORBIS_IME_MAX_TEXT_LENGTH * 4)) {
|
||||
LOG_ERROR(Lib_ImeDialog, "Failed to convert text to utf8 encoding");
|
||||
}
|
||||
}
|
||||
|
||||
ImeState::ImeState(ImeState&& other) noexcept
|
||||
: work_buffer(other.work_buffer), text_buffer(other.text_buffer),
|
||||
current_text(std::move(other.current_text)), event_queue(std::move(other.event_queue)) {
|
||||
other.text_buffer = nullptr;
|
||||
}
|
||||
|
||||
ImeState& ImeState::operator=(ImeState&& other) noexcept {
|
||||
if (this != &other) {
|
||||
work_buffer = other.work_buffer;
|
||||
text_buffer = other.text_buffer;
|
||||
current_text = std::move(other.current_text);
|
||||
event_queue = std::move(other.event_queue);
|
||||
|
||||
other.text_buffer = nullptr;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
void ImeState::SendEvent(OrbisImeEvent* event) {
|
||||
std::unique_lock lock{queue_mutex};
|
||||
event_queue.push(*event);
|
||||
}
|
||||
|
||||
void ImeState::SendEnterEvent() {
|
||||
OrbisImeEvent enterEvent{};
|
||||
enterEvent.id = OrbisImeEventId::PressEnter;
|
||||
SendEvent(&enterEvent);
|
||||
}
|
||||
|
||||
void ImeState::SendCloseEvent() {
|
||||
OrbisImeEvent closeEvent{};
|
||||
closeEvent.id = OrbisImeEventId::PressClose;
|
||||
closeEvent.param.text.str = reinterpret_cast<char16_t*>(work_buffer);
|
||||
SendEvent(&closeEvent);
|
||||
}
|
||||
|
||||
void ImeState::SetText(const char16_t* text, u32 length) {}
|
||||
|
||||
void ImeState::SetCaret(u32 position) {}
|
||||
|
||||
bool ImeState::ConvertOrbisToUTF8(const char16_t* orbis_text, std::size_t orbis_text_len,
|
||||
char* utf8_text, std::size_t utf8_text_len) {
|
||||
std::fill(utf8_text, utf8_text + utf8_text_len, '\0');
|
||||
const ImWchar* orbis_text_ptr = reinterpret_cast<const ImWchar*>(orbis_text);
|
||||
ImTextStrToUtf8(utf8_text, utf8_text_len, orbis_text_ptr, orbis_text_ptr + orbis_text_len);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ImeState::ConvertUTF8ToOrbis(const char* utf8_text, std::size_t utf8_text_len,
|
||||
char16_t* orbis_text, std::size_t orbis_text_len) {
|
||||
std::fill(orbis_text, orbis_text + orbis_text_len, u'\0');
|
||||
ImTextStrFromUtf8(reinterpret_cast<ImWchar*>(orbis_text), orbis_text_len, utf8_text, nullptr);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
ImeUi::ImeUi(ImeState* state, const OrbisImeParam* param) : state(state), ime_param(param) {
|
||||
if (param) {
|
||||
AddLayer(this);
|
||||
}
|
||||
}
|
||||
|
||||
ImeUi::~ImeUi() {
|
||||
std::scoped_lock lock(draw_mutex);
|
||||
Free();
|
||||
}
|
||||
|
||||
ImeUi& ImeUi::operator=(ImeUi&& other) {
|
||||
std::scoped_lock lock(draw_mutex, other.draw_mutex);
|
||||
Free();
|
||||
|
||||
state = other.state;
|
||||
ime_param = other.ime_param;
|
||||
first_render = other.first_render;
|
||||
other.state = nullptr;
|
||||
other.ime_param = nullptr;
|
||||
|
||||
AddLayer(this);
|
||||
return *this;
|
||||
}
|
||||
|
||||
void ImeUi::Draw() {
|
||||
std::unique_lock lock{draw_mutex};
|
||||
|
||||
if (!state) {
|
||||
return;
|
||||
}
|
||||
|
||||
const auto& ctx = *GetCurrentContext();
|
||||
const auto& io = ctx.IO;
|
||||
|
||||
// TODO: Figure out how to properly translate the positions -
|
||||
// for example, if a game wants to center the IME panel,
|
||||
// we have to translate the panel position in a way that it
|
||||
// still becomes centered, as the game normally calculates
|
||||
// the position assuming a it's running on a 1920x1080 screen,
|
||||
// whereas we are running on a 1280x720 window size (by default).
|
||||
//
|
||||
// e.g. Panel position calculation from a game:
|
||||
// param.posx = (1920 / 2) - (panelWidth / 2);
|
||||
// param.posy = (1080 / 2) - (panelHeight / 2);
|
||||
const auto size = GetIO().DisplaySize;
|
||||
f32 pos_x = (ime_param->posx / 1920.0f * (float)size.x);
|
||||
f32 pos_y = (ime_param->posy / 1080.0f * (float)size.y);
|
||||
|
||||
ImVec2 window_pos = {pos_x, pos_y};
|
||||
ImVec2 window_size = {500.0f, 100.0f};
|
||||
|
||||
// SetNextWindowPos(window_pos);
|
||||
SetNextWindowPos(ImVec2(io.DisplaySize.x * 0.5f, io.DisplaySize.y * 0.5f),
|
||||
ImGuiCond_FirstUseEver, ImVec2(0.5f, 0.5f));
|
||||
SetNextWindowSize(window_size);
|
||||
SetNextWindowCollapsed(false);
|
||||
|
||||
if (first_render || !io.NavActive) {
|
||||
SetNextWindowFocus();
|
||||
}
|
||||
|
||||
if (Begin("IME##Ime", nullptr,
|
||||
ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize |
|
||||
ImGuiWindowFlags_NoSavedSettings)) {
|
||||
DrawPrettyBackground();
|
||||
|
||||
DrawInputText();
|
||||
SetCursorPosY(GetCursorPosY() + 10.0f);
|
||||
|
||||
const char* button_text;
|
||||
button_text = "Done##ImeDone";
|
||||
|
||||
float button_spacing = 10.0f;
|
||||
float total_button_width = BUTTON_SIZE.x * 2 + button_spacing;
|
||||
float button_start_pos = (window_size.x - total_button_width) / 2.0f;
|
||||
|
||||
SetCursorPosX(button_start_pos);
|
||||
|
||||
if (Button(button_text, BUTTON_SIZE) || (IsKeyPressed(ImGuiKey_Enter))) {
|
||||
state->SendEnterEvent();
|
||||
}
|
||||
|
||||
SameLine(0.0f, button_spacing);
|
||||
|
||||
if (Button("Close##ImeClose", BUTTON_SIZE)) {
|
||||
state->SendCloseEvent();
|
||||
}
|
||||
}
|
||||
End();
|
||||
|
||||
first_render = false;
|
||||
}
|
||||
|
||||
void ImeUi::DrawInputText() {
|
||||
ImVec2 input_size = {GetWindowWidth() - 40.0f, 0.0f};
|
||||
SetCursorPosX(20.0f);
|
||||
if (first_render) {
|
||||
SetKeyboardFocusHere();
|
||||
}
|
||||
if (InputTextEx("##ImeInput", nullptr, state->current_text.begin(), ime_param->maxTextLength,
|
||||
input_size, ImGuiInputTextFlags_CallbackAlways, InputTextCallback, this)) {
|
||||
}
|
||||
}
|
||||
|
||||
int ImeUi::InputTextCallback(ImGuiInputTextCallbackData* data) {
|
||||
ImeUi* ui = static_cast<ImeUi*>(data->UserData);
|
||||
ASSERT(ui);
|
||||
|
||||
static std::string lastText;
|
||||
std::string currentText(data->Buf, data->BufTextLen);
|
||||
if (currentText != lastText) {
|
||||
OrbisImeEditText eventParam{};
|
||||
eventParam.str = reinterpret_cast<char16_t*>(ui->ime_param->work);
|
||||
eventParam.caret_index = data->CursorPos;
|
||||
eventParam.area_num = 1;
|
||||
|
||||
eventParam.text_area[0].mode = 1; // Edit mode
|
||||
eventParam.text_area[0].index = data->CursorPos;
|
||||
eventParam.text_area[0].length = data->BufTextLen;
|
||||
|
||||
if (!ui->state->ConvertUTF8ToOrbis(data->Buf, data->BufTextLen, eventParam.str,
|
||||
ui->ime_param->maxTextLength)) {
|
||||
LOG_ERROR(Lib_ImeDialog, "Failed to convert Orbis char to UTF-8");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!ui->state->ConvertUTF8ToOrbis(data->Buf, data->BufTextLen,
|
||||
ui->ime_param->inputTextBuffer,
|
||||
ui->ime_param->maxTextLength)) {
|
||||
LOG_ERROR(Lib_ImeDialog, "Failed to convert Orbis char to UTF-8");
|
||||
return 0;
|
||||
}
|
||||
|
||||
OrbisImeEvent event{};
|
||||
event.id = OrbisImeEventId::UpdateText;
|
||||
event.param.text = eventParam;
|
||||
|
||||
lastText = currentText;
|
||||
ui->state->SendEvent(&event);
|
||||
}
|
||||
|
||||
static int lastCaretPos = -1;
|
||||
if (lastCaretPos == -1) {
|
||||
lastCaretPos = data->CursorPos;
|
||||
} else if (data->CursorPos != lastCaretPos) {
|
||||
OrbisImeCaretMovementDirection caretDirection = OrbisImeCaretMovementDirection::Still;
|
||||
if (data->CursorPos < lastCaretPos) {
|
||||
caretDirection = OrbisImeCaretMovementDirection::Left;
|
||||
} else if (data->CursorPos > lastCaretPos) {
|
||||
caretDirection = OrbisImeCaretMovementDirection::Right;
|
||||
}
|
||||
|
||||
OrbisImeEvent event{};
|
||||
event.id = OrbisImeEventId::UpdateCaret;
|
||||
event.param.caret_move = caretDirection;
|
||||
|
||||
lastCaretPos = data->CursorPos;
|
||||
ui->state->SendEvent(&event);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ImeUi::Free() {
|
||||
RemoveLayer(this);
|
||||
}
|
||||
|
||||
}; // namespace Libraries::Ime
|
||||
|
|
|
@ -1,76 +1,76 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <mutex>
|
||||
#include <imgui.h>
|
||||
#include <queue>
|
||||
#include "imgui/imgui_layer.h"
|
||||
|
||||
#include "common/cstring.h"
|
||||
#include "common/types.h"
|
||||
|
||||
#include "ime.h"
|
||||
|
||||
namespace Libraries::Ime {
|
||||
|
||||
class ImeHandler;
|
||||
class ImeUi;
|
||||
|
||||
class ImeState {
|
||||
friend class ImeHandler;
|
||||
friend class ImeUi;
|
||||
|
||||
void* work_buffer{};
|
||||
char16_t* text_buffer{};
|
||||
|
||||
// A character can hold up to 4 bytes in UTF-8
|
||||
Common::CString<ORBIS_IME_MAX_TEXT_LENGTH * 4> current_text;
|
||||
|
||||
std::queue<OrbisImeEvent> event_queue;
|
||||
std::mutex queue_mutex;
|
||||
|
||||
public:
|
||||
ImeState(const OrbisImeParam* param = nullptr);
|
||||
ImeState(ImeState&& other) noexcept;
|
||||
ImeState& operator=(ImeState&& other) noexcept;
|
||||
|
||||
void SendEvent(OrbisImeEvent* event);
|
||||
void SendEnterEvent();
|
||||
void SendCloseEvent();
|
||||
|
||||
void SetText(const char16_t* text, u32 length);
|
||||
void SetCaret(u32 position);
|
||||
|
||||
private:
|
||||
bool ConvertOrbisToUTF8(const char16_t* orbis_text, std::size_t orbis_text_len, char* utf8_text,
|
||||
std::size_t native_text_len);
|
||||
bool ConvertUTF8ToOrbis(const char* native_text, std::size_t utf8_text_len,
|
||||
char16_t* orbis_text, std::size_t orbis_text_len);
|
||||
};
|
||||
|
||||
class ImeUi : public ImGui::Layer {
|
||||
ImeState* state{};
|
||||
const OrbisImeParam* ime_param{};
|
||||
|
||||
bool first_render = true;
|
||||
std::mutex draw_mutex;
|
||||
|
||||
public:
|
||||
explicit ImeUi(ImeState* state = nullptr, const OrbisImeParam* param = nullptr);
|
||||
~ImeUi() override;
|
||||
ImeUi(const ImeUi& other) = delete;
|
||||
ImeUi& operator=(ImeUi&& other);
|
||||
|
||||
void Draw() override;
|
||||
|
||||
private:
|
||||
void Free();
|
||||
|
||||
void DrawInputText();
|
||||
|
||||
static int InputTextCallback(ImGuiInputTextCallbackData* data);
|
||||
};
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <mutex>
|
||||
#include <imgui.h>
|
||||
#include <queue>
|
||||
#include "imgui/imgui_layer.h"
|
||||
|
||||
#include "common/cstring.h"
|
||||
#include "common/types.h"
|
||||
|
||||
#include "ime.h"
|
||||
|
||||
namespace Libraries::Ime {
|
||||
|
||||
class ImeHandler;
|
||||
class ImeUi;
|
||||
|
||||
class ImeState {
|
||||
friend class ImeHandler;
|
||||
friend class ImeUi;
|
||||
|
||||
void* work_buffer{};
|
||||
char16_t* text_buffer{};
|
||||
|
||||
// A character can hold up to 4 bytes in UTF-8
|
||||
Common::CString<ORBIS_IME_MAX_TEXT_LENGTH * 4> current_text;
|
||||
|
||||
std::queue<OrbisImeEvent> event_queue;
|
||||
std::mutex queue_mutex;
|
||||
|
||||
public:
|
||||
ImeState(const OrbisImeParam* param = nullptr);
|
||||
ImeState(ImeState&& other) noexcept;
|
||||
ImeState& operator=(ImeState&& other) noexcept;
|
||||
|
||||
void SendEvent(OrbisImeEvent* event);
|
||||
void SendEnterEvent();
|
||||
void SendCloseEvent();
|
||||
|
||||
void SetText(const char16_t* text, u32 length);
|
||||
void SetCaret(u32 position);
|
||||
|
||||
private:
|
||||
bool ConvertOrbisToUTF8(const char16_t* orbis_text, std::size_t orbis_text_len, char* utf8_text,
|
||||
std::size_t native_text_len);
|
||||
bool ConvertUTF8ToOrbis(const char* native_text, std::size_t utf8_text_len,
|
||||
char16_t* orbis_text, std::size_t orbis_text_len);
|
||||
};
|
||||
|
||||
class ImeUi : public ImGui::Layer {
|
||||
ImeState* state{};
|
||||
const OrbisImeParam* ime_param{};
|
||||
|
||||
bool first_render = true;
|
||||
std::mutex draw_mutex;
|
||||
|
||||
public:
|
||||
explicit ImeUi(ImeState* state = nullptr, const OrbisImeParam* param = nullptr);
|
||||
~ImeUi() override;
|
||||
ImeUi(const ImeUi& other) = delete;
|
||||
ImeUi& operator=(ImeUi&& other);
|
||||
|
||||
void Draw() override;
|
||||
|
||||
private:
|
||||
void Free();
|
||||
|
||||
void DrawInputText();
|
||||
|
||||
static int InputTextCallback(ImGuiInputTextCallbackData* data);
|
||||
};
|
||||
|
||||
}; // namespace Libraries::Ime
|
Loading…
Add table
Add a link
Reference in a new issue