touch: Add touchpad support.

- Allow double touch in pc with using touchpad of DS/4.
- Add draw touchpad cursor when is used.
- Add config for allow disable show this cursor per game.
This commit is contained in:
Zangetsu38 2023-09-08 19:15:06 +02:00 committed by Zangetsu
parent 32344c2a25
commit b8ae624f73
11 changed files with 123 additions and 11 deletions

View File

@ -95,6 +95,7 @@ enum PerfomanceOverleyPosition {
code(bool, "discord-rich-presence", true, discord_rich_presence) \
code(bool, "wait-for-debugger", false, wait_for_debugger) \
code(bool, "color-surface-debug", false, color_surface_debug) \
code(bool, "show-touchpad-cursor", true, show_touchpad_cursor) \
code(bool, "performance-overlay", false, performance_overlay) \
code(int, "perfomance-overlay-detail", static_cast<int>(MINIMUM), performance_overlay_detail) \
code(int, "perfomance-overlay-position", static_cast<int>(TOP_LEFT), performance_overlay_position) \

View File

@ -180,6 +180,7 @@ public:
bool v_sync = true;
int anisotropic_filtering = 1;
bool stretch_the_display_area = false;
bool show_touchpad_cursor = true;
int psn_status = SCE_NP_SERVICE_STATE_UNKNOWN;
};

View File

@ -51,5 +51,5 @@ add_library(
target_include_directories(gui PUBLIC include ${CMAKE_SOURCE_DIR}/vita3k)
target_link_libraries(gui PUBLIC app compat config dialog emuenv https ime imgui glutil lang regmgr np)
target_link_libraries(gui PRIVATE audio ctrl kernel miniz psvpfsparser pugixml::pugixml stb renderer packages sdl2 vkutil host::dialog)
target_link_libraries(gui PRIVATE audio ctrl kernel miniz psvpfsparser pugixml::pugixml stb renderer packages sdl2 touch vkutil host::dialog)
target_link_libraries(gui PUBLIC tracy)

View File

@ -124,6 +124,7 @@ void draw_reinstall_dialog(GenericDialogState *status, GuiState &gui, EmuEnvStat
void draw_pre_compiling_shaders_progress(GuiState &gui, EmuEnvState &emuenv, const uint32_t &total);
void draw_shaders_count_compiled(GuiState &gui, EmuEnvState &emuenv);
void draw_trophies_unlocked(GuiState &gui, EmuEnvState &emuenv);
void draw_touchpad_cursor(EmuEnvState &emuenv);
void draw_perf_overlay(GuiState &gui, EmuEnvState &emuenv);
ImTextureID load_image(GuiState &gui, const char *data, const std::uint32_t size);

View File

@ -32,6 +32,7 @@
#include <lang/functions.h>
#include <packages/sfo.h>
#include <regmgr/functions.h>
#include <touch/functions.h>
#include <util/fs.h>
#include <util/log.h>
#include <util/string_utils.h>
@ -738,6 +739,23 @@ void draw_end(GuiState &gui, SDL_Window *window) {
ImGui_ImplSdl_RenderDrawData(gui.imgui_state.get());
}
void draw_touchpad_cursor(EmuEnvState &emuenv) {
SceTouchPortType port;
const auto touchpad_fingers_pos = get_touchpad_fingers_pos(port);
if (touchpad_fingers_pos.empty())
return;
const ImVec2 RES_SCALE(emuenv.viewport_size.x / emuenv.res_width_dpi_scale, emuenv.viewport_size.y / emuenv.res_height_dpi_scale);
const ImVec2 SCALE(RES_SCALE.x * emuenv.dpi_scale, RES_SCALE.y * emuenv.dpi_scale);
const auto color = (port == SCE_TOUCH_PORT_FRONT) ? IM_COL32(0.f, 102.f, 204.f, 255.f) : IM_COL32(255.f, 0.f, 0.f, 255.f);
for (const auto &pos : touchpad_fingers_pos) {
auto x = emuenv.viewport_pos.x + (pos.x * emuenv.viewport_size.x);
auto y = emuenv.viewport_pos.y + (pos.y * emuenv.viewport_size.y);
ImGui::GetForegroundDrawList()->AddCircle(ImVec2(x, y), 20.f * SCALE.x, color, 0, 4.f * SCALE.x);
}
}
void draw_vita_area(GuiState &gui, EmuEnvState &emuenv) {
if (gui.vita_area.start_screen)
draw_start_screen(gui, emuenv);

View File

@ -180,6 +180,7 @@ static bool get_custom_config(GuiState &gui, EmuEnvState &emuenv, const std::str
if (!config_child.child("emulator").empty()) {
const auto emulator_child = config_child.child("emulator");
config.ngs_enable = emulator_child.attribute("enable-ngs").as_bool();
config.show_touchpad_cursor = emulator_child.attribute("show-touchpad-cursor").as_bool();
}
// Load Network Config
@ -227,6 +228,7 @@ void init_config(GuiState &gui, EmuEnvState &emuenv, const std::string &app_path
config.anisotropic_filtering = emuenv.cfg.anisotropic_filtering;
config.pstv_mode = emuenv.cfg.pstv_mode;
config.ngs_enable = emuenv.cfg.ngs_enable;
config.show_touchpad_cursor = emuenv.cfg.show_touchpad_cursor;
config.psn_status = emuenv.cfg.psn_status;
}
get_modules_list(gui, emuenv);
@ -292,6 +294,7 @@ static void save_config(GuiState &gui, EmuEnvState &emuenv) {
// Emulator
auto emulator_child = config_child.append_child("emulator");
emulator_child.append_attribute("enable-ngs") = config.ngs_enable;
emulator_child.append_attribute("show-touchpad-cursor") = config.show_touchpad_cursor;
// Network
auto network_child = config_child.append_child("network");
@ -312,6 +315,7 @@ static void save_config(GuiState &gui, EmuEnvState &emuenv) {
emuenv.cfg.v_sync = config.v_sync;
emuenv.cfg.anisotropic_filtering = config.anisotropic_filtering;
emuenv.cfg.ngs_enable = config.ngs_enable;
emuenv.cfg.show_touchpad_cursor = config.show_touchpad_cursor;
emuenv.cfg.psn_status = config.psn_status;
}
@ -369,6 +373,7 @@ void set_config(GuiState &gui, EmuEnvState &emuenv, const std::string &app_path)
emuenv.cfg.current_config.v_sync = emuenv.cfg.v_sync;
emuenv.cfg.current_config.anisotropic_filtering = emuenv.cfg.anisotropic_filtering;
emuenv.cfg.current_config.ngs_enable = emuenv.cfg.ngs_enable;
emuenv.cfg.current_config.show_touchpad_cursor = emuenv.cfg.show_touchpad_cursor;
emuenv.cfg.current_config.psn_status = emuenv.cfg.psn_status;
}
@ -764,6 +769,10 @@ void draw_settings_dialog(GuiState &gui, EmuEnvState &emuenv) {
if (ImGui::IsItemHovered())
ImGui::SetTooltip("Uncheck the box to disable the display of the compile shaders dialog.");
ImGui::Spacing();
ImGui::Checkbox("Show Touchpad Cursor", &config.show_touchpad_cursor);
if (ImGui::IsItemHovered())
ImGui::SetTooltip("Uncheck the box to disable showing the touchpad cursor on-screen.");
ImGui::SameLine();
ImGui::Checkbox("Log Compatibility Warnings", &emuenv.cfg.log_compat_warn);
if (ImGui::IsItemHovered())
ImGui::SetTooltip("Check the box to log issues related to the app compatibility database.");

View File

@ -714,6 +714,9 @@ bool handle_events(EmuEnvState &emuenv, GuiState &gui) {
break;
case SDL_CONTROLLERBUTTONDOWN:
if (!emuenv.kernel.is_threads_paused() && (event.cbutton.button == SDL_CONTROLLER_BUTTON_TOUCHPAD))
toggle_touchscreen();
if (ImGui::GetIO().WantTextInput)
continue;
@ -759,18 +762,18 @@ bool handle_events(EmuEnvState &emuenv, GuiState &gui) {
}
break;
case SDL_CONTROLLERTOUCHPADDOWN:
case SDL_CONTROLLERTOUCHPADMOTION:
case SDL_CONTROLLERTOUCHPADUP:
handle_touchpad_event(event.ctouchpad);
break;
case SDL_WINDOWEVENT:
handle_window_event(emuenv, event.window);
break;
case SDL_FINGERDOWN:
handle_touch_event(event.tfinger);
break;
case SDL_FINGERMOTION:
handle_touch_event(event.tfinger);
break;
case SDL_FINGERUP:
handle_touch_event(event.tfinger);
break;

View File

@ -432,6 +432,9 @@ int main(int argc, char *argv[]) {
if (emuenv.cfg.performance_overlay && !emuenv.kernel.is_threads_paused() && (emuenv.common_dialog.status != SCE_COMMON_DIALOG_STATUS_RUNNING))
gui::draw_perf_overlay(gui, emuenv);
if (emuenv.cfg.current_config.show_touchpad_cursor && !emuenv.kernel.is_threads_paused())
gui::draw_touchpad_cursor(emuenv);
if (emuenv.display.imgui_render) {
gui::draw_ui(gui, emuenv);
}

View File

@ -3,6 +3,8 @@
#include <emuenv/state.h>
#include <touch/touch.h>
std::vector<SceFVector2> get_touchpad_fingers_pos(SceTouchPortType &port);
int handle_touchpad_event(SDL_ControllerTouchpadEvent &touchpad);
void touch_vsync_update(const EmuEnvState &emuenv);
int handle_touch_event(SDL_TouchFingerEvent &finger);
int toggle_touchscreen();

View File

@ -21,6 +21,7 @@
#define SCE_TOUCH_MAX_REPORT 8
struct SDL_ControllerTouchpadEvent;
struct SDL_TouchFingerEvent;
enum SceTouchSamplingState {

View File

@ -30,11 +30,12 @@
constexpr int MAX_TOUCH_BUFFER_SAVED = 64;
static SceTouchData touch_buffers[MAX_TOUCH_BUFFER_SAVED][2];
int touch_buffer_idx = 0;
static int touch_buffer_idx = 0;
static bool is_touchpad = false;
static SDL_TouchFingerEvent finger_buffer[8];
static SDL_ControllerTouchpadEvent touchpad_buffer[8];
static uint8_t finger_count = 0;
static auto touchscreen_port = SCE_TOUCH_PORT_FRONT;
static SceTouchPortType touchscreen_port = SCE_TOUCH_PORT_FRONT;
static bool is_touched[2] = { false, false };
// Used for mouse support
static int curr_touch_id[2] = { 0, 0 };
@ -67,12 +68,33 @@ static SceTouchData recover_touch_events(const EmuEnvState &emuenv) {
return touch_data;
}
static SceTouchData recover_touchpad_events(const EmuEnvState &emuenv) {
SceTouchData touch_data;
touch_data.status = 0;
for (uint8_t i = 0; i < finger_count; i++) {
touch_data.report[i].id = static_cast<uint8_t>(touchpad_buffer[i].which);
touch_data.report[i].force = forceTouchEnabled[touchscreen_port] ? 128 : 0;
touch_data.report[i].x = static_cast<uint16_t>(touchpad_buffer[i].x * 1920);
if (touchscreen_port == SCE_TOUCH_PORT_FRONT) {
touch_data.report[i].y = static_cast<uint16_t>(touchpad_buffer[i].y * 1088);
} else {
touch_data.report[i].y = static_cast<uint16_t>(108 + touchpad_buffer[i].y * 781);
}
}
touch_data.reportNum = finger_count;
return touch_data;
}
void touch_vsync_update(const EmuEnvState &emuenv) {
std::chrono::time_point<std::chrono::steady_clock> ts = std::chrono::steady_clock::now();
uint64_t timestamp = std::chrono::duration_cast<std::chrono::microseconds>(ts.time_since_epoch()).count();
if (finger_count > 0) {
SceTouchData touch_data = recover_touch_events(emuenv);
SceTouchData touch_data = is_touchpad ? recover_touchpad_events(emuenv) : recover_touch_events(emuenv);
touch_data.timeStamp = timestamp;
SceTouchData *buffers = touch_buffers[(touch_buffer_idx + 1) % MAX_TOUCH_BUFFER_SAVED];
@ -189,6 +211,57 @@ int handle_touch_event(SDL_TouchFingerEvent &finger) {
return 0;
}
int handle_touchpad_event(SDL_ControllerTouchpadEvent &touchpad) {
switch (touchpad.type) {
case SDL_CONTROLLERTOUCHPADDOWN:
if (finger_count >= 8) // best we can do is clean everything
finger_count = 0;
touchpad_buffer[finger_count] = touchpad;
touchpad_buffer[finger_count].which = next_touch_id;
next_touch_id = (next_touch_id + 1) % 128;
finger_count++;
break;
case SDL_CONTROLLERTOUCHPADUP:
for (uint32_t i = 0; i < finger_count; i++) {
if (touchpad.finger == touchpad_buffer[i].finger) {
if (i < (finger_count - 1))
touchpad_buffer[i] = touchpad_buffer[i + 1];
}
}
if (finger_count > 0)
finger_count--;
break;
case SDL_CONTROLLERTOUCHPADMOTION:
for (int i = 0; i < finger_count; i++) {
if (touchpad.finger == touchpad_buffer[i].finger) {
const auto touch_id = touchpad_buffer[i].which;
touchpad_buffer[i] = touchpad;
touchpad_buffer[i].which = touch_id;
}
}
break;
}
is_touchpad = finger_count > 0;
return 0;
}
std::vector<SceFVector2> get_touchpad_fingers_pos(SceTouchPortType &port) {
if (!is_touchpad)
return {};
std::vector<SceFVector2> touchpad_fingers_pos;
for (int i = 0; i < finger_count; i++) {
touchpad_fingers_pos.push_back({ touchpad_buffer[i].x, touchpad_buffer[i].y });
}
port = touchscreen_port;
return touchpad_fingers_pos;
}
int toggle_touchscreen() {
if (touchscreen_port == SCE_TOUCH_PORT_FRONT) {
touchscreen_port = SCE_TOUCH_PORT_BACK;