mirror of
https://github.com/RPCS3/rpcs3.git
synced 2024-11-22 10:42:36 +01:00
cellOskDialog: implement KeyboardEventHookCallback
This commit is contained in:
parent
0ff293707a
commit
71f8280c5e
@ -3,6 +3,7 @@
|
|||||||
#include "Emu/system_config.h"
|
#include "Emu/system_config.h"
|
||||||
#include "Emu/Cell/PPUModule.h"
|
#include "Emu/Cell/PPUModule.h"
|
||||||
#include "Emu/Io/interception.h"
|
#include "Emu/Io/interception.h"
|
||||||
|
#include "Emu/Io/Keyboard.h"
|
||||||
#include "Emu/RSX/Overlays/overlay_osk.h"
|
#include "Emu/RSX/Overlays/overlay_osk.h"
|
||||||
#include "Emu/IdManager.h"
|
#include "Emu/IdManager.h"
|
||||||
|
|
||||||
@ -91,6 +92,7 @@ struct osk_info
|
|||||||
atomic_t<vm::ptr<cellOskDialogConfirmWordFilterCallback>> osk_confirm_callback{};
|
atomic_t<vm::ptr<cellOskDialogConfirmWordFilterCallback>> osk_confirm_callback{};
|
||||||
atomic_t<vm::ptr<cellOskDialogForceFinishCallback>> osk_force_finish_callback{};
|
atomic_t<vm::ptr<cellOskDialogForceFinishCallback>> osk_force_finish_callback{};
|
||||||
atomic_t<vm::ptr<cellOskDialogHardwareKeyboardEventHookCallback>> osk_hardware_keyboard_event_hook_callback{};
|
atomic_t<vm::ptr<cellOskDialogHardwareKeyboardEventHookCallback>> osk_hardware_keyboard_event_hook_callback{};
|
||||||
|
atomic_t<u16> hook_event_mode{0};
|
||||||
|
|
||||||
stx::init_mutex init;
|
stx::init_mutex init;
|
||||||
|
|
||||||
@ -123,6 +125,7 @@ struct osk_info
|
|||||||
osk_confirm_callback.store({});
|
osk_confirm_callback.store({});
|
||||||
osk_force_finish_callback.store({});
|
osk_force_finish_callback.store({});
|
||||||
osk_hardware_keyboard_event_hook_callback.store({});
|
osk_hardware_keyboard_event_hook_callback.store({});
|
||||||
|
hook_event_mode.store(0);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -340,12 +343,155 @@ error_code cellOskDialogLoadAsync(u32 container, vm::ptr<CellOskDialogParam> dia
|
|||||||
input::SetIntercepted(false);
|
input::SetIntercepted(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
if (info.osk_continuous_mode == CELL_OSKDIALOG_CONTINUOUS_MODE_HIDE)
|
// Set key callback
|
||||||
|
osk->on_osk_key_input_entered = [wptr = std::weak_ptr<OskDialogBase>(osk)](CellOskDialogKeyMessage key_message)
|
||||||
{
|
{
|
||||||
info.last_dialog_state = CELL_SYSUTIL_OSKDIALOG_LOADED;
|
const auto osk = wptr.lock();
|
||||||
sysutil_send_system_cmd(CELL_SYSUTIL_OSKDIALOG_LOADED, 0);
|
auto& info = g_fxo->get<osk_info>();
|
||||||
return CELL_OK;
|
bool is_kook_key = false;
|
||||||
}
|
|
||||||
|
switch (key_message.keycode)
|
||||||
|
{
|
||||||
|
case CELL_KEYC_NO_EVENT:
|
||||||
|
{
|
||||||
|
// Any shift/alt/ctrl key
|
||||||
|
is_kook_key = key_message.mkey > 0 && (info.hook_event_mode & CELL_OSKDIALOG_EVENT_HOOK_TYPE_ONLY_MODIFIER);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case CELL_KEYC_E_ROLLOVER:
|
||||||
|
case CELL_KEYC_E_POSTFAIL:
|
||||||
|
case CELL_KEYC_E_UNDEF:
|
||||||
|
case CELL_KEYC_ESCAPE:
|
||||||
|
case CELL_KEYC_106_KANJI:
|
||||||
|
case CELL_KEYC_CAPS_LOCK:
|
||||||
|
case CELL_KEYC_F1:
|
||||||
|
case CELL_KEYC_F2:
|
||||||
|
case CELL_KEYC_F3:
|
||||||
|
case CELL_KEYC_F4:
|
||||||
|
case CELL_KEYC_F5:
|
||||||
|
case CELL_KEYC_F6:
|
||||||
|
case CELL_KEYC_F7:
|
||||||
|
case CELL_KEYC_F8:
|
||||||
|
case CELL_KEYC_F9:
|
||||||
|
case CELL_KEYC_F10:
|
||||||
|
case CELL_KEYC_F11:
|
||||||
|
case CELL_KEYC_F12:
|
||||||
|
case CELL_KEYC_PRINTSCREEN:
|
||||||
|
case CELL_KEYC_SCROLL_LOCK:
|
||||||
|
case CELL_KEYC_PAUSE:
|
||||||
|
case CELL_KEYC_INSERT:
|
||||||
|
case CELL_KEYC_HOME:
|
||||||
|
case CELL_KEYC_PAGE_UP:
|
||||||
|
case CELL_KEYC_DELETE:
|
||||||
|
case CELL_KEYC_END:
|
||||||
|
case CELL_KEYC_PAGE_DOWN:
|
||||||
|
case CELL_KEYC_RIGHT_ARROW:
|
||||||
|
case CELL_KEYC_LEFT_ARROW:
|
||||||
|
case CELL_KEYC_DOWN_ARROW:
|
||||||
|
case CELL_KEYC_UP_ARROW:
|
||||||
|
case CELL_KEYC_NUM_LOCK:
|
||||||
|
case CELL_KEYC_APPLICATION:
|
||||||
|
case CELL_KEYC_KANA:
|
||||||
|
case CELL_KEYC_HENKAN:
|
||||||
|
case CELL_KEYC_MUHENKAN:
|
||||||
|
{
|
||||||
|
// Any function key or other special key like Delete
|
||||||
|
is_kook_key = (info.hook_event_mode & CELL_OSKDIALOG_EVENT_HOOK_TYPE_FUNCTION_KEY);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
// Any regular ascii key
|
||||||
|
is_kook_key = (info.hook_event_mode & CELL_OSKDIALOG_EVENT_HOOK_TYPE_ASCII_KEY);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!is_kook_key)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (auto ccb = info.osk_hardware_keyboard_event_hook_callback.load())
|
||||||
|
{
|
||||||
|
constexpr u32 max_size = 101;
|
||||||
|
std::vector<u16> string_to_send(max_size, 0);
|
||||||
|
atomic_t<bool> done = false;
|
||||||
|
|
||||||
|
for (u32 i = 0; i < max_size - 1; i++)
|
||||||
|
{
|
||||||
|
string_to_send[i] = osk->osk_text[i];
|
||||||
|
if (osk->osk_text[i] == 0) break;
|
||||||
|
}
|
||||||
|
|
||||||
|
sysutil_register_cb([&](ppu_thread& cb_ppu) -> s32
|
||||||
|
{
|
||||||
|
vm::var<CellOskDialogKeyMessage> keyMessage(key_message);
|
||||||
|
vm::var<u32> action(CELL_OSKDIALOG_CHANGE_NO_EVENT);
|
||||||
|
vm::var<u16[], vm::page_allocator<>> pActionInfo(max_size, string_to_send.data());
|
||||||
|
|
||||||
|
const bool return_value = ccb(cb_ppu, keyMessage, action, pActionInfo.begin());
|
||||||
|
cellOskDialog.warning("osk_hardware_keyboard_event_hook_callback: return_value=%d, action=%d)", return_value, action.get_ptr() ? static_cast<u32>(*action) : 0);
|
||||||
|
|
||||||
|
if (return_value)
|
||||||
|
{
|
||||||
|
ensure(action);
|
||||||
|
ensure(pActionInfo);
|
||||||
|
|
||||||
|
switch (*action)
|
||||||
|
{
|
||||||
|
case CELL_OSKDIALOG_CHANGE_NO_EVENT:
|
||||||
|
case CELL_OSKDIALOG_CHANGE_EVENT_CANCEL:
|
||||||
|
{
|
||||||
|
// Do nothing
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case CELL_OSKDIALOG_CHANGE_WORDS_INPUT:
|
||||||
|
{
|
||||||
|
// Set unconfirmed string and reset unconfirmed string
|
||||||
|
for (u32 i = 0; i < max_size; i++)
|
||||||
|
{
|
||||||
|
osk->osk_text[i] = pActionInfo.begin()[i];
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case CELL_OSKDIALOG_CHANGE_WORDS_INSERT:
|
||||||
|
{
|
||||||
|
// Set confirmed string and reset unconfirmed string
|
||||||
|
for (u32 i = 0; i < max_size; i++)
|
||||||
|
{
|
||||||
|
info.valid_text[i] = pActionInfo.begin()[i];
|
||||||
|
osk->osk_text[i] = 0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case CELL_OSKDIALOG_CHANGE_WORDS_REPLACE_ALL:
|
||||||
|
{
|
||||||
|
// Set confirmed string and reset all strings
|
||||||
|
for (u32 i = 0; i < max_size; i++)
|
||||||
|
{
|
||||||
|
info.valid_text[i] = pActionInfo.begin()[i];
|
||||||
|
osk->osk_text[i] = 0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
cellOskDialog.error("osk_hardware_keyboard_event_hook_callback returned invalid action (%d)", *action);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
done = true;
|
||||||
|
return 0;
|
||||||
|
});
|
||||||
|
|
||||||
|
// wait for callback
|
||||||
|
while (!done && !Emu.IsStopped())
|
||||||
|
{
|
||||||
|
std::this_thread::yield();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// Set device mask and event lock
|
// Set device mask and event lock
|
||||||
osk->ignore_input_events = info.lock_ext_input.load();
|
osk->ignore_input_events = info.lock_ext_input.load();
|
||||||
@ -358,6 +504,13 @@ error_code cellOskDialogLoadAsync(u32 container, vm::ptr<CellOskDialogParam> dia
|
|||||||
|
|
||||||
input::SetIntercepted(osk->pad_input_enabled, osk->keyboard_input_enabled, osk->mouse_input_enabled);
|
input::SetIntercepted(osk->pad_input_enabled, osk->keyboard_input_enabled, osk->mouse_input_enabled);
|
||||||
|
|
||||||
|
if (info.osk_continuous_mode == CELL_OSKDIALOG_CONTINUOUS_MODE_HIDE)
|
||||||
|
{
|
||||||
|
info.last_dialog_state = CELL_SYSUTIL_OSKDIALOG_LOADED;
|
||||||
|
sysutil_send_system_cmd(CELL_SYSUTIL_OSKDIALOG_LOADED, 0);
|
||||||
|
return CELL_OK;
|
||||||
|
}
|
||||||
|
|
||||||
Emu.CallFromMainThread([=, &result]()
|
Emu.CallFromMainThread([=, &result]()
|
||||||
{
|
{
|
||||||
osk->Create(get_localized_string(localized_string_id::CELL_OSK_DIALOG_TITLE), message, osk->osk_text, maxLength, prohibitFlgs, allowOskPanelFlg, firstViewPanel);
|
osk->Create(get_localized_string(localized_string_id::CELL_OSK_DIALOG_TITLE), message, osk->osk_text, maxLength, prohibitFlgs, allowOskPanelFlg, firstViewPanel);
|
||||||
@ -713,25 +866,7 @@ error_code register_keyboard_event_hook_callback(u16 hookEventMode, vm::ptr<cell
|
|||||||
}
|
}
|
||||||
|
|
||||||
g_fxo->get<osk_info>().osk_hardware_keyboard_event_hook_callback = pCallback;
|
g_fxo->get<osk_info>().osk_hardware_keyboard_event_hook_callback = pCallback;
|
||||||
|
g_fxo->get<osk_info>().hook_event_mode = hookEventMode;
|
||||||
// TODO: use callback
|
|
||||||
// 1. Check if the callback needs to be called. This depends on the pressed key and on the OR of the hookEventMode parameter:
|
|
||||||
// CELL_OSKDIALOG_EVENT_HOOK_TYPE_FUNCTION_KEY: Any function keys + other special keys like Delete
|
|
||||||
// CELL_OSKDIALOG_EVENT_HOOK_TYPE_ASCII_KEY: Any regular ascii key
|
|
||||||
// CELL_OSKDIALOG_EVENT_HOOK_TYPE_ONLY_MODIFIER: Any shift/alt/ctrl key
|
|
||||||
// 2. When a hardware key is pressed, call osk_hardware_keyboard_event_hook_callback with the following params:
|
|
||||||
// keyMessage: our info about the current key press (and release?)
|
|
||||||
// action: an out pointer. The game will set this value and we will have to react to it
|
|
||||||
// pActionInfo: the currently unconfirmed string. max 100 characters + '\0' character. This should be the valid_text member of osk_info.
|
|
||||||
// 3. Check return value:
|
|
||||||
// false: do nothing
|
|
||||||
// true: go to the next step
|
|
||||||
// 4. Check 'action' pointer value. React accordingly:
|
|
||||||
// CELL_OSKDIALOG_CHANGE_NO_EVENT: do nothing
|
|
||||||
// CELL_OSKDIALOG_CHANGE_EVENT_CANCEL: cancel input
|
|
||||||
// CELL_OSKDIALOG_CHANGE_WORDS_INPUT: change unconfirmed string and delete unconfirmed string
|
|
||||||
// CELL_OSKDIALOG_CHANGE_WORDS_INSERT: change "confirmed string to insert" and delete unconfirmed string
|
|
||||||
// CELL_OSKDIALOG_CHANGE_WORDS_REPLACE_ALL: change "confirmed string to insert" and delete ALL strings
|
|
||||||
|
|
||||||
return CELL_OK;
|
return CELL_OK;
|
||||||
}
|
}
|
||||||
|
@ -262,7 +262,7 @@ public:
|
|||||||
virtual ~OskDialogBase();
|
virtual ~OskDialogBase();
|
||||||
|
|
||||||
std::function<void(s32 status)> on_osk_close;
|
std::function<void(s32 status)> on_osk_close;
|
||||||
std::function<void()> on_osk_input_entered;
|
std::function<void(CellOskDialogKeyMessage key_message)> on_osk_key_input_entered;
|
||||||
|
|
||||||
atomic_t<OskDialogState> state{ OskDialogState::Unloaded };
|
atomic_t<OskDialogState> state{ OskDialogState::Unloaded };
|
||||||
atomic_t<bool> pad_input_enabled{ true }; // Determines if the OSK consumes the device's events.
|
atomic_t<bool> pad_input_enabled{ true }; // Determines if the OSK consumes the device's events.
|
||||||
|
@ -651,6 +651,7 @@ namespace rsx
|
|||||||
const std::string out_key_string = utf16_to_ascii8(utf16_string);
|
const std::string out_key_string = utf16_to_ascii8(utf16_string);
|
||||||
|
|
||||||
// Find matching key in the OSK
|
// Find matching key in the OSK
|
||||||
|
bool found_key = false;
|
||||||
for (const cell& current_cell : m_grid)
|
for (const cell& current_cell : m_grid)
|
||||||
{
|
{
|
||||||
// TODO: maybe just ignore the current charset and check all outputs
|
// TODO: maybe just ignore the current charset and check all outputs
|
||||||
@ -669,30 +670,46 @@ namespace rsx
|
|||||||
{
|
{
|
||||||
on_default_callback(str);
|
on_default_callback(str);
|
||||||
}
|
}
|
||||||
return;
|
|
||||||
|
found_key = true;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (found_key)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle special input
|
// Handle special input
|
||||||
if (!out_key_string.empty())
|
if (!found_key && !out_key_string.empty())
|
||||||
{
|
{
|
||||||
switch (out_key_string[0])
|
switch (out_key_string[0])
|
||||||
{
|
{
|
||||||
case ' ':
|
case ' ':
|
||||||
on_space(u32_string);
|
on_space(u32_string);
|
||||||
return;
|
break;
|
||||||
case '\b':
|
case '\b':
|
||||||
on_backspace(u32_string);
|
on_backspace(u32_string);
|
||||||
return;
|
break;
|
||||||
case '\n':
|
case '\n':
|
||||||
on_enter(u32_string);
|
on_enter(u32_string);
|
||||||
return;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (on_osk_key_input_entered)
|
||||||
|
{
|
||||||
|
CellOskDialogKeyMessage key_message{};
|
||||||
|
key_message.led = led;
|
||||||
|
key_message.mkey = mkey;
|
||||||
|
key_message.keycode = key_code;
|
||||||
|
on_osk_key_input_entered(key_message);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void osk_dialog::on_text_changed()
|
void osk_dialog::on_text_changed()
|
||||||
@ -701,11 +718,6 @@ namespace rsx
|
|||||||
const auto length = (ws.length() + 1) * sizeof(char16_t);
|
const auto length = (ws.length() + 1) * sizeof(char16_t);
|
||||||
memcpy(osk_text, ws.c_str(), length);
|
memcpy(osk_text, ws.c_str(), length);
|
||||||
|
|
||||||
if (on_osk_input_entered)
|
|
||||||
{
|
|
||||||
on_osk_input_entered();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Muted contrast for placeholder text
|
// Muted contrast for placeholder text
|
||||||
m_preview.fore_color.a = m_preview.value.empty() ? 0.5f : 1.f;
|
m_preview.fore_color.a = m_preview.value.empty() ? 0.5f : 1.f;
|
||||||
|
|
||||||
|
@ -77,7 +77,7 @@ void osk_dialog_frame::Create(const std::string& title, const std::u16string& me
|
|||||||
{
|
{
|
||||||
input_count_label->setText(QString("%1/%2").arg(text.length()).arg(charlimit));
|
input_count_label->setText(QString("%1/%2").arg(text.length()).arg(charlimit));
|
||||||
SetOskText(text);
|
SetOskText(text);
|
||||||
on_osk_input_entered();
|
// if (on_osk_key_input_entered) on_osk_key_input_entered({}); // Not applicable
|
||||||
});
|
});
|
||||||
connect(input, &QLineEdit::returnPressed, m_dialog, &QDialog::accept);
|
connect(input, &QLineEdit::returnPressed, m_dialog, &QDialog::accept);
|
||||||
|
|
||||||
@ -141,7 +141,7 @@ void osk_dialog_frame::Create(const std::string& title, const std::u16string& me
|
|||||||
|
|
||||||
input_count_label->setText(QString("%1/%2").arg(text.length()).arg(charlimit));
|
input_count_label->setText(QString("%1/%2").arg(text.length()).arg(charlimit));
|
||||||
SetOskText(text);
|
SetOskText(text);
|
||||||
on_osk_input_entered();
|
// if (on_osk_key_input_entered) on_osk_key_input_entered({}); // Not applicable
|
||||||
});
|
});
|
||||||
|
|
||||||
inputLayout->addWidget(input);
|
inputLayout->addWidget(input);
|
||||||
|
Loading…
Reference in New Issue
Block a user