mirror of
https://github.com/RPCS3/rpcs3.git
synced 2025-07-05 06:21:26 +12:00
329 lines
8.1 KiB
C++
329 lines
8.1 KiB
C++
#include "stdafx.h"
|
|
#include "overlays.h"
|
|
#include "../GSRender.h"
|
|
|
|
static auto s_ascii_lowering_map = []()
|
|
{
|
|
std::unordered_map<u32, u8> _map;
|
|
|
|
// Fullwidth block (FF00-FF5E)
|
|
for (u32 u = 0xFF01, c = 0x21; u <= 0xFF5E; ++u, ++c)
|
|
{
|
|
_map[u] = u8(c);
|
|
}
|
|
|
|
// Em and En space variations (General Punctuation)
|
|
for (u32 u = 0x2000; u <= 0x200A; ++u)
|
|
{
|
|
_map[u] = u8(' ');
|
|
}
|
|
|
|
// Misc space variations
|
|
_map[0x202F] = u8(0xA0); // narrow NBSP
|
|
_map[0x205F] = u8(' '); // medium mathematical space
|
|
_map[0x3164] = u8(' '); // hangul filler
|
|
|
|
// Ideographic (CJK punctuation)
|
|
_map[0x3000] = u8(' '); // space
|
|
_map[0x3001] = u8(','); // comma
|
|
_map[0x3002] = u8('.'); // fullstop
|
|
_map[0x3003] = u8('"'); // ditto
|
|
_map[0x3007] = u8('0'); // wide zero
|
|
_map[0x3008] = u8('<'); // left angle brace
|
|
_map[0x3009] = u8('>'); // right angle brace
|
|
_map[0x300A] = u8(0xAB); // double left angle brace
|
|
_map[0x300B] = u8(0xBB); // double right angle brace
|
|
_map[0x300C] = u8('['); // the following are all slight variations on the angular brace
|
|
_map[0x300D] = u8(']');
|
|
_map[0x300E] = u8('[');
|
|
_map[0x300F] = u8(']');
|
|
_map[0x3010] = u8('[');
|
|
_map[0x3011] = u8(']');
|
|
_map[0x3014] = u8('[');
|
|
_map[0x3015] = u8(']');
|
|
_map[0x3016] = u8('[');
|
|
_map[0x3017] = u8(']');
|
|
_map[0x3018] = u8('[');
|
|
_map[0x3019] = u8(']');
|
|
_map[0x301A] = u8('[');
|
|
_map[0x301B] = u8(']');
|
|
_map[0x301C] = u8('~'); // wave dash (inverted tilde)
|
|
_map[0x301D] = u8('"'); // reverse double prime quotation
|
|
_map[0x301E] = u8('"'); // double prime quotation
|
|
_map[0x301F] = u8('"'); // low double prime quotation
|
|
_map[0x3031] = u8('<'); // vertical kana repeat mark
|
|
|
|
return _map;
|
|
}();
|
|
|
|
std::string utf8_to_ascii8(const std::string& utf8_string)
|
|
{
|
|
std::vector<u8> out;
|
|
out.reserve(utf8_string.length() + 1);
|
|
|
|
const auto end = utf8_string.length();
|
|
for (u32 index = 0; index < end; ++index)
|
|
{
|
|
const auto code = (u8)utf8_string[index];
|
|
if (code <= 0x7F)
|
|
{
|
|
out.push_back(code);
|
|
continue;
|
|
}
|
|
|
|
const auto extra_bytes = (code <= 0xDF) ? 1u : (code <= 0xEF) ? 2u : 3u;
|
|
if ((index + extra_bytes) > end)
|
|
{
|
|
// Malformed string, abort
|
|
LOG_ERROR(GENERAL, "Failed to decode supossedly malformed utf8 string '%s'", utf8_string);
|
|
break;
|
|
}
|
|
|
|
u32 u_code = 0;
|
|
switch (extra_bytes)
|
|
{
|
|
case 1:
|
|
// 11 bits, 6 + 5
|
|
u_code = (u32(code & 0x1F) << 6) | u32(utf8_string[index + 1] & 0x3F);
|
|
break;
|
|
case 2:
|
|
// 16 bits, 6 + 6 + 4
|
|
u_code = (u32(code & 0xF) << 12) | (u32(utf8_string[index + 1] & 0x3F) << 6) | u32(utf8_string[index + 2] & 0x3F);
|
|
break;
|
|
case 3:
|
|
// 21 bits, 6 + 6 + 6 + 3
|
|
u_code = (u32(code & 0x7) << 18) | (u32(utf8_string[index + 1] & 0x3F) << 12) | (u32(utf8_string[index + 2] & 0x3F) << 6) | u32(utf8_string[index + 3] & 0x3F);
|
|
break;
|
|
default:
|
|
fmt::throw_exception("Unreachable" HERE);
|
|
}
|
|
|
|
index += extra_bytes;
|
|
|
|
if (u_code <= 0xFF)
|
|
{
|
|
// Latin-1 supplement block
|
|
out.push_back(u8(u_code));
|
|
continue;
|
|
}
|
|
|
|
auto replace = s_ascii_lowering_map.find(u_code);
|
|
if (replace == s_ascii_lowering_map.end())
|
|
{
|
|
out.push_back('#');
|
|
continue;
|
|
}
|
|
|
|
out.push_back(replace->second);
|
|
}
|
|
|
|
out.push_back(0);
|
|
return { reinterpret_cast<char*>(out.data()) };
|
|
}
|
|
|
|
std::string utf16_to_ascii8(const std::u16string& utf16_string)
|
|
{
|
|
// Strip extended codes, map to '#' instead (placeholder)
|
|
std::vector<u8> out;
|
|
out.reserve(utf16_string.length() + 1);
|
|
|
|
for (const auto& code : utf16_string)
|
|
{
|
|
out.push_back(code > 0xFF ? '#': (u8)code);
|
|
}
|
|
|
|
out.push_back(0);
|
|
return { reinterpret_cast<char*>(out.data()) };
|
|
}
|
|
|
|
std::u16string ascii8_to_utf16(const std::string& ascii_string)
|
|
{
|
|
std::vector<char16_t> out;
|
|
out.reserve(ascii_string.length() + 1);
|
|
|
|
for (const auto& code : ascii_string)
|
|
{
|
|
out.push_back(code > 0xFF ? '#' : (char16_t)code);
|
|
}
|
|
|
|
out.push_back(0);
|
|
return { out.data() };
|
|
}
|
|
|
|
namespace rsx
|
|
{
|
|
namespace overlays
|
|
{
|
|
// Singleton instance declaration
|
|
fontmgr* fontmgr::m_instance = nullptr;
|
|
|
|
s32 user_interface::run_input_loop()
|
|
{
|
|
std::array<std::chrono::steady_clock::time_point, CELL_PAD_MAX_PORT_NUM> timestamp;
|
|
timestamp.fill(std::chrono::steady_clock::now());
|
|
|
|
std::array<std::array<bool, pad_button::pad_button_max_enum>, CELL_PAD_MAX_PORT_NUM> button_state;
|
|
for (auto& state : button_state)
|
|
{
|
|
state.fill(true);
|
|
}
|
|
|
|
input_timer.Start();
|
|
|
|
pad::SetIntercepted(true);
|
|
|
|
while (!exit)
|
|
{
|
|
if (Emu.IsStopped())
|
|
return selection_code::canceled;
|
|
|
|
std::this_thread::sleep_for(1ms);
|
|
|
|
std::lock_guard lock(pad::g_pad_mutex);
|
|
|
|
const auto handler = pad::get_current_handler();
|
|
|
|
const PadInfo& rinfo = handler->GetInfo();
|
|
|
|
if (Emu.IsPaused() || !rinfo.now_connect)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
int pad_index = -1;
|
|
for (const auto &pad : handler->GetPads())
|
|
{
|
|
if (++pad_index >= CELL_PAD_MAX_PORT_NUM)
|
|
{
|
|
LOG_FATAL(RSX, "The native overlay cannot handle more than 7 pads! Current number of pads: %d", pad_index + 1);
|
|
continue;
|
|
}
|
|
|
|
for (auto &button : pad->m_buttons)
|
|
{
|
|
u8 button_id = 255;
|
|
if (button.m_offset == CELL_PAD_BTN_OFFSET_DIGITAL1)
|
|
{
|
|
switch (button.m_outKeyCode)
|
|
{
|
|
case CELL_PAD_CTRL_LEFT:
|
|
button_id = pad_button::dpad_left;
|
|
break;
|
|
case CELL_PAD_CTRL_RIGHT:
|
|
button_id = pad_button::dpad_right;
|
|
break;
|
|
case CELL_PAD_CTRL_DOWN:
|
|
button_id = pad_button::dpad_down;
|
|
break;
|
|
case CELL_PAD_CTRL_UP:
|
|
button_id = pad_button::dpad_up;
|
|
break;
|
|
case CELL_PAD_CTRL_SELECT:
|
|
button_id = pad_button::select;
|
|
break;
|
|
case CELL_PAD_CTRL_START:
|
|
button_id = pad_button::start;
|
|
break;
|
|
}
|
|
}
|
|
else if (button.m_offset == CELL_PAD_BTN_OFFSET_DIGITAL2)
|
|
{
|
|
switch (button.m_outKeyCode)
|
|
{
|
|
case CELL_PAD_CTRL_TRIANGLE:
|
|
button_id = pad_button::triangle;
|
|
break;
|
|
case CELL_PAD_CTRL_CIRCLE:
|
|
button_id = g_cfg.sys.enter_button_assignment == enter_button_assign::circle ? pad_button::cross : pad_button::circle;
|
|
break;
|
|
case CELL_PAD_CTRL_SQUARE:
|
|
button_id = pad_button::square;
|
|
break;
|
|
case CELL_PAD_CTRL_CROSS:
|
|
button_id = g_cfg.sys.enter_button_assignment == enter_button_assign::circle ? pad_button::circle : pad_button::cross;
|
|
break;
|
|
case CELL_PAD_CTRL_L1:
|
|
button_id = pad_button::L1;
|
|
break;
|
|
case CELL_PAD_CTRL_R1:
|
|
button_id = pad_button::R1;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (button_id < 255)
|
|
{
|
|
if (button.m_pressed)
|
|
{
|
|
if (button_id < 4) // d-pad button
|
|
{
|
|
if (!button_state[pad_index][button_id] || input_timer.GetMsSince(timestamp[pad_index]) > 200)
|
|
{
|
|
// d-pad button was not pressed, or was pressed more than 200ms ago
|
|
timestamp[pad_index] = std::chrono::steady_clock::now();
|
|
on_button_pressed(static_cast<pad_button>(button_id));
|
|
}
|
|
}
|
|
else if (!button_state[pad_index][button_id])
|
|
{
|
|
// button was not pressed
|
|
on_button_pressed(static_cast<pad_button>(button_id));
|
|
}
|
|
}
|
|
|
|
button_state[pad_index][button_id] = button.m_pressed;
|
|
}
|
|
|
|
if (button.m_flush)
|
|
{
|
|
button.m_pressed = false;
|
|
button.m_flush = false;
|
|
button.m_value = 0;
|
|
}
|
|
|
|
if (exit)
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
refresh();
|
|
}
|
|
|
|
// Unreachable
|
|
return 0;
|
|
}
|
|
|
|
void user_interface::close()
|
|
{
|
|
// Force unload
|
|
exit = true;
|
|
if (auto manager = fxm::get<display_manager>())
|
|
{
|
|
if (auto dlg = manager->get<rsx::overlays::message_dialog>())
|
|
{
|
|
if (dlg->progress_bar_count())
|
|
Emu.GetCallbacks().handle_taskbar_progress(0, 1);
|
|
}
|
|
|
|
manager->remove(uid);
|
|
}
|
|
|
|
pad::SetIntercepted(false);
|
|
|
|
if (on_close)
|
|
on_close(return_code);
|
|
}
|
|
|
|
void overlay::refresh()
|
|
{
|
|
if (auto rsxthr = rsx::get_current_renderer())
|
|
{
|
|
const auto now = get_system_time() - 1000000;
|
|
if ((now - rsxthr->last_flip_time) > min_refresh_duration_us)
|
|
{
|
|
rsxthr->async_flip_requested |= rsx::thread::flip_request::native_ui;
|
|
}
|
|
}
|
|
}
|
|
} // namespace overlays
|
|
} // namespace rsx
|