From 747d2032e604a31967b3372a252868440ecb8d7d Mon Sep 17 00:00:00 2001 From: TheBrokenRail Date: Sat, 19 Jun 2021 19:07:09 -0400 Subject: [PATCH] Fix Mouse Cursor Bugs --- VERSION | 2 +- docs/CHANGELOG.md | 3 + libreborn/include/libreborn/minecraft.h | 17 +++++ media-layer/core/src/media.c | 93 ++++++++++++++++++------- mods/CMakeLists.txt | 7 +- mods/src/compat/compat.c | 7 ++ mods/src/compat/egl.c | 18 ++--- mods/src/init/init.c | 1 + mods/src/init/init.h | 1 + mods/src/options/README.md | 1 - mods/src/options/options.c | 22 +----- mods/src/touch/README.md | 2 + mods/src/touch/touch.c | 54 ++++++++++++++ 13 files changed, 170 insertions(+), 58 deletions(-) create mode 100644 mods/src/touch/README.md create mode 100644 mods/src/touch/touch.c diff --git a/VERSION b/VERSION index 38f77a65b..e9307ca57 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -2.0.1 +2.0.2 diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index 839eab068..ef49956b9 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -1,5 +1,8 @@ # Changelog +**2.0.2** +* Fix Mouse Cursor Bugs + **2.0.1** * Fix Blank Screen On Twister OS diff --git a/libreborn/include/libreborn/minecraft.h b/libreborn/include/libreborn/minecraft.h index cc96e0175..57e1811fa 100644 --- a/libreborn/include/libreborn/minecraft.h +++ b/libreborn/include/libreborn/minecraft.h @@ -12,6 +12,9 @@ typedef uint32_t bool; // Globals +typedef void (*renderCursor_t)(float x, float y, unsigned char *minecraft); +static renderCursor_t renderCursor = (renderCursor_t) 0x480c4; + static char **default_path = (char **) 0xe264; // /.minecraft/ static char **default_username = (char **) 0x18fd4; // StevePi @@ -120,6 +123,20 @@ static uint32_t Minecraft_command_server_property_offset = 0xcc0; // CommandServ static uint32_t Minecraft_screen_property_offset = 0xc10; // Screen * static uint32_t Minecraft_gui_property_offset = 0x198; // Gui +// GameRenderer + +typedef void (*GameRenderer_render_t)(unsigned char *game_renderer, float param_1); +static GameRenderer_render_t GameRenderer_render = (GameRenderer_render_t) 0x4a338; + +static uint32_t GameRenderer_minecraft_property_offset = 0x4; // Minecraft * + +// Mouse + +typedef int (*Mouse_get_t)(); + +static Mouse_get_t Mouse_getX = (Mouse_get_t) 0x1385c; +static Mouse_get_t Mouse_getY = (Mouse_get_t) 0x1386c; + // CommandServer static uint32_t CommandServer_minecraft_property_offset = 0x18; // Minecraft * diff --git a/media-layer/core/src/media.c b/media-layer/core/src/media.c index e4e93d8e1..b31ae699f 100644 --- a/media-layer/core/src/media.c +++ b/media-layer/core/src/media.c @@ -280,39 +280,82 @@ void media_cleanup() { #endif // #ifndef MCPI_SERVER_MODE } -#ifdef MCPI_SERVER_MODE -static SDL_GrabMode fake_grab_mode = SDL_GRAB_OFF; -#endif // #ifdef MCPI_SERVER_MODE +// Store Cursor State +static int cursor_grabbed = 0; +static int cursor_visible = 1; + +// Update GLFW Cursor State (Client Only) +#ifndef MCPI_SERVER_MODE +static void update_glfw_cursor() { + // Store Old Mode + int old_mode = glfwGetInputMode(glfw_window, GLFW_CURSOR); + + // Handle Cursor Visibility + int new_mode; + if (!cursor_visible) { + if (cursor_grabbed) { + new_mode = GLFW_CURSOR_DISABLED; + } else { + new_mode = GLFW_CURSOR_HIDDEN; + } + } else { + new_mode = GLFW_CURSOR_NORMAL; + } + if (new_mode != old_mode) { + // Set New Mode + glfwSetInputMode(glfw_window, GLFW_CURSOR, new_mode); + + // Handle Cursor Lock/Unlock + if ((new_mode == GLFW_CURSOR_DISABLED && old_mode != GLFW_CURSOR_DISABLED) || (new_mode != GLFW_CURSOR_DISABLED && old_mode == GLFW_CURSOR_DISABLED)) { + // Use Raw Mouse Motion (GLFW 3.3+ Only) +#ifdef GLFW_RAW_MOUSE_MOTION + glfwSetInputMode(glfw_window, GLFW_RAW_MOUSE_MOTION, new_mode == GLFW_CURSOR_DISABLED ? GLFW_TRUE : GLFW_FALSE); +#endif + // Reset Last Mouse Position + ignore_relative_mouse = 1; + } + } +} +#endif // Fix SDL Cursor Visibility/Grabbing SDL_GrabMode SDL_WM_GrabInput(SDL_GrabMode mode) { -#ifdef MCPI_SERVER_MODE - // Don't Grab Input In Server Mode - if (mode != SDL_GRAB_QUERY) { - fake_grab_mode = mode; + if (mode == SDL_GRAB_QUERY) { + // Query + return cursor_grabbed ? SDL_GRAB_ON : SDL_GRAB_OFF; + } else if (mode == SDL_GRAB_ON) { + // Store State + cursor_grabbed = 1; + } else if (mode == SDL_GRAB_OFF) { + // Store State + cursor_grabbed = 0; } - return fake_grab_mode; -#else // #ifdef MCPI_SERVER_MODE - if (mode != SDL_GRAB_QUERY && mode != SDL_WM_GrabInput(SDL_GRAB_QUERY)) { - glfwSetInputMode(glfw_window, GLFW_CURSOR, mode == SDL_GRAB_OFF ? GLFW_CURSOR_NORMAL : GLFW_CURSOR_DISABLED); -#if GLFW_VERSION_MAJOR > 3 || (GLFW_VERSION_MAJOR == 3 && GLFW_VERSION_MINOR >= 3) - glfwSetInputMode(glfw_window, GLFW_RAW_MOUSE_MOTION, mode == SDL_GRAB_OFF ? GLFW_FALSE : GLFW_TRUE); -#endif // #if GLFW_VERSION_MAJOR > 3 || (GLFW_VERSION_MAJOR == 3 && GLFW_VERSION_MINOR >= 3) - - // Reset Last Mouse Position - ignore_relative_mouse = 1; - } - return mode == SDL_GRAB_QUERY ? (glfwGetInputMode(glfw_window, GLFW_CURSOR) == GLFW_CURSOR_NORMAL ? SDL_GRAB_OFF : SDL_GRAB_ON) : mode; -#endif // #ifdef MCPI_SERVER_MODE + // Update Cursor GLFW State (Client Only) +#ifndef MCPI_SERVER_MODE + update_glfw_cursor(); +#endif + // Return + return mode; } // Stub SDL Cursor Visibility int SDL_ShowCursor(int toggle) { -#ifdef MCPI_SERVER_MODE - return toggle == SDL_QUERY ? (fake_grab_mode == SDL_GRAB_OFF ? SDL_ENABLE : SDL_DISABLE) : toggle; -#else // #ifdef MCPI_SERVER_MODE - return toggle == SDL_QUERY ? (glfwGetInputMode(glfw_window, GLFW_CURSOR) == GLFW_CURSOR_NORMAL ? SDL_ENABLE : SDL_DISABLE) : toggle; -#endif // #ifdef MCPI_SERVER_MODE + if (toggle == SDL_QUERY) { + // Query + return cursor_visible ? SDL_ENABLE : SDL_DISABLE; + } else if (toggle == SDL_ENABLE) { + // Store State + cursor_visible = 1; + } else if (toggle == SDL_DISABLE) { + // Store State + cursor_visible = 0; + } + // Update Cursor GLFW State (Client Only) +#ifndef MCPI_SERVER_MODE + update_glfw_cursor(); +#endif + // Return + return toggle; } // Get Framebuffer Size diff --git a/mods/CMakeLists.txt b/mods/CMakeLists.txt index 11ee05365..47acfcbc9 100644 --- a/mods/CMakeLists.txt +++ b/mods/CMakeLists.txt @@ -35,6 +35,9 @@ target_link_libraries(misc reborn feature util) add_library(options SHARED src/options/options.c) target_link_libraries(options reborn feature) +add_library(touch SHARED src/touch/touch.c) +target_link_libraries(touch reborn feature) + add_library(override SHARED src/override/override.c) target_link_libraries(override reborn dl home) @@ -51,13 +54,13 @@ add_library(test SHARED src/test/test.c) target_link_libraries(test reborn home) add_library(init SHARED src/init/init.c) -target_link_libraries(init compat game_mode camera input misc options textures chat home test) +target_link_libraries(init compat game_mode camera input misc options touch textures chat home test) if(MCPI_SERVER_MODE) target_link_libraries(init server) endif() ## Install Mods -install(TARGETS init compat readdir feature override game_mode camera input misc options textures chat home test DESTINATION "${MCPI_INSTALL_DIR}/mods") +install(TARGETS init compat readdir feature override game_mode camera input misc options touch textures chat home test DESTINATION "${MCPI_INSTALL_DIR}/mods") if(MCPI_SERVER_MODE) install(TARGETS server DESTINATION "${MCPI_INSTALL_DIR}/mods") endif() diff --git a/mods/src/compat/compat.c b/mods/src/compat/compat.c index c2fa4831c..0cd9a2aec 100644 --- a/mods/src/compat/compat.c +++ b/mods/src/compat/compat.c @@ -12,6 +12,13 @@ #include "../init/init.h" #include "compat.h" +// Mouse Cursor Is Always Invisible In Vanilla MCPI +// Because In Vanilla MCPI, The GPU Overlay Covered The Normal Mouse Cursor +HOOK(SDL_ShowCursor, int, (int toggle)) { + ensure_SDL_ShowCursor(); + return (*real_SDL_ShowCursor)(toggle == SDL_QUERY ? SDL_QUERY : SDL_DISABLE); +} + // Intercept SDL Events HOOK(SDL_PollEvent, int, (SDL_Event *event)) { // In Server Mode, Exit Requests Are Handled In src/server/server.cpp diff --git a/mods/src/compat/egl.c b/mods/src/compat/egl.c index ae77b259f..6cb545986 100644 --- a/mods/src/compat/egl.c +++ b/mods/src/compat/egl.c @@ -4,17 +4,17 @@ #include // Functions That Have Their Return Values Used -static EGLSurface eglCreateWindowSurface_overwrite(__attribute__((unused)) EGLDisplay display, __attribute__((unused)) EGLConfig config, __attribute__((unused)) NativeWindowType native_window, __attribute__((unused)) EGLint const *attrib_list) { +static EGLSurface eglCreateWindowSurface_injection(__attribute__((unused)) EGLDisplay display, __attribute__((unused)) EGLConfig config, __attribute__((unused)) NativeWindowType native_window, __attribute__((unused)) EGLint const *attrib_list) { return 0; } -static EGLDisplay eglGetDisplay_overwrite(__attribute__((unused)) NativeDisplayType native_display) { +static EGLDisplay eglGetDisplay_injection(__attribute__((unused)) NativeDisplayType native_display) { return 0; } -static EGLContext eglCreateContext_overwrite(__attribute__((unused)) EGLDisplay display, __attribute__((unused)) EGLConfig config, __attribute__((unused)) EGLContext share_context, __attribute__((unused)) EGLint const *attrib_list) { +static EGLContext eglCreateContext_injection(__attribute__((unused)) EGLDisplay display, __attribute__((unused)) EGLConfig config, __attribute__((unused)) EGLContext share_context, __attribute__((unused)) EGLint const *attrib_list) { return 0; } // Call media_swap_buffers() -static EGLBoolean eglSwapBuffers_overwrite(__attribute__((unused)) EGLDisplay display, __attribute__((unused)) EGLSurface surface) { +static EGLBoolean eglSwapBuffers_injection(__attribute__((unused)) EGLDisplay display, __attribute__((unused)) EGLSurface surface) { media_swap_buffers(); return EGL_TRUE; } @@ -25,15 +25,15 @@ __attribute__((constructor)) static void patch_egl_calls() { unsigned char nop_patch[4] = {0x00, 0xf0, 0x20, 0xe3}; // "nop" patch((void *) 0x1250c, nop_patch); // eglTerminate patch((void *) 0x12580, nop_patch); // eglBindAPI - overwrite_call((void *) 0x12638, (void *) eglCreateWindowSurface_overwrite); // eglCreateWindowSurface + overwrite_call((void *) 0x12638, (void *) eglCreateWindowSurface_injection); // eglCreateWindowSurface patch((void *) 0x12578, nop_patch); // eglChooseConfig patch((void *) 0x1255c, nop_patch); // eglInitialize patch((void *) 0x124f0, nop_patch); // eglMakeCurrent #1 patch((void *) 0x12654, nop_patch); // eglMakeCurrent #2 - overwrite_call((void *) 0x124dc, (void *) eglSwapBuffers_overwrite); // eglSwapBuffers #1 - overwrite_call((void *) 0x14b6c, (void *) eglSwapBuffers_overwrite); // eglSwapBuffers #2 - overwrite_call((void *) 0x1254c, (void *) eglGetDisplay_overwrite); // eglGetDisplay + overwrite_call((void *) 0x124dc, (void *) eglSwapBuffers_injection); // eglSwapBuffers #1 + overwrite_call((void *) 0x14b6c, (void *) eglSwapBuffers_injection); // eglSwapBuffers #2 + overwrite_call((void *) 0x1254c, (void *) eglGetDisplay_injection); // eglGetDisplay patch((void *) 0x124fc, nop_patch); // eglDestroySurface #1 patch((void *) 0x12504, nop_patch); // eglDestroySurface #2 - overwrite_call((void *) 0x12594, (void *) eglCreateContext_overwrite); // eglCreateContext + overwrite_call((void *) 0x12594, (void *) eglCreateContext_injection); // eglCreateContext } diff --git a/mods/src/init/init.c b/mods/src/init/init.c index 03c459fb5..9e07d9f50 100644 --- a/mods/src/init/init.c +++ b/mods/src/init/init.c @@ -11,6 +11,7 @@ __attribute__((constructor)) static void init() { init_misc(); init_camera(); init_options(); + init_touch(); init_textures(); init_chat(); init_home(); diff --git a/mods/src/init/init.h b/mods/src/init/init.h index 3dd76e1fe..0dc1bee6c 100644 --- a/mods/src/init/init.h +++ b/mods/src/init/init.h @@ -14,6 +14,7 @@ void init_input(); void init_misc(); void init_camera(); void init_options(); +void init_touch(); void init_textures(); void init_chat(); void init_home(); diff --git a/mods/src/options/README.md b/mods/src/options/README.md index 2ee55b3c4..4222c38d7 100644 --- a/mods/src/options/README.md +++ b/mods/src/options/README.md @@ -3,7 +3,6 @@ This mod allows various options to be configured, including: - Mob Spawning - The Render Distance - The Username -- Touch GUI - Peaceful Mode - 3D Anaglyph - Autojump diff --git a/mods/src/options/options.c b/mods/src/options/options.c index 23cfa56dd..af1d6e76f 100644 --- a/mods/src/options/options.c +++ b/mods/src/options/options.c @@ -68,21 +68,8 @@ static void Minecraft_init_injection(unsigned char *this) { *(int32_t *) (options + Options_render_distance_property_offset) = render_distance; } -// Enable Touch GUI -static int32_t Minecraft_isTouchscreen_injection(__attribute__((unused)) unsigned char *minecraft) { - return 1; -} - +// Init void init_options() { - int touch_gui = feature_has("Touch GUI"); - if (touch_gui) { - // Main UI - overwrite((void *) Minecraft_isTouchscreen, Minecraft_isTouchscreen_injection); - // Force Correct Toolbar Size - unsigned char toolbar_patch[4] = {0x01, 0x00, 0x50, 0xe3}; // "cmp r0, #0x1" - patch((void *) 0x257b0, toolbar_patch); - } - mob_spawning = feature_has("Mob Spawning"); // Set Mob Spawning overwrite((void *) LevelData_getSpawnMobs, LevelData_getSpawnMobs_injection); @@ -125,15 +112,10 @@ void init_options() { patch((void *) 0xa6628, display_nametags_patch); } - // Show Block Outlines - int block_outlines = feature_has("Show Block Outlines"); - unsigned char outline_patch[4] = {block_outlines ? !touch_gui : touch_gui, 0x00, 0x50, 0xe3}; // "cmp r0, #0x1" or "cmp r0, #0x0" - patch((void *) 0x4a210, outline_patch); - smooth_lighting = feature_has("Smooth Lighting"); if (smooth_lighting) { // Enable Smooth Lighting unsigned char smooth_lighting_patch[4] = {0x01, 0x00, 0x53, 0xe3}; // "cmp r3, #0x1" patch((void *) 0x59ea4, smooth_lighting_patch); } -} \ No newline at end of file +} diff --git a/mods/src/touch/README.md b/mods/src/touch/README.md new file mode 100644 index 000000000..69403e162 --- /dev/null +++ b/mods/src/touch/README.md @@ -0,0 +1,2 @@ +# ``touch`` Mod +This mod allows the hidden touch GUI to be activated. diff --git a/mods/src/touch/touch.c b/mods/src/touch/touch.c new file mode 100644 index 000000000..ac59c353e --- /dev/null +++ b/mods/src/touch/touch.c @@ -0,0 +1,54 @@ +#include + +#include "../feature/feature.h" +#include "../init/init.h" + +#include + +// Enable Touch GUI +static int32_t Minecraft_isTouchscreen_injection(__attribute__((unused)) unsigned char *minecraft) { + return 1; +} + +// Custom Cursor Rendering +// The Default Behavior For Touch GUI Is To Only Render The Cursor When The Mouse Is Clicking, This Fixes That +static void GameRenderer_render_injection(unsigned char *game_renderer, float param_1) { + // Call Real Method + (*GameRenderer_render)(game_renderer, param_1); + + // Render Cursor + unsigned char *minecraft = *(unsigned char **) (game_renderer + GameRenderer_minecraft_property_offset); + unsigned char *current_screen = *(unsigned char **) (minecraft + Minecraft_screen_property_offset); + // Check If Cursor Should Render + if (current_screen != NULL) { + // Get X And Y + float x = (*Mouse_getX)() * (*InvGuiScale); + float y = (*Mouse_getY)() * (*InvGuiScale); + // Render + (*renderCursor)(x, y, minecraft); + } +} + +// Init +void init_touch() { + int touch_gui = feature_has("Touch GUI"); + if (touch_gui) { + // Main UI + overwrite((void *) Minecraft_isTouchscreen, Minecraft_isTouchscreen_injection); + + // Disable Normal Cursor Rendering + unsigned char disable_cursor_patch[4] = {0x00, 0xf0, 0x20, 0xe3}; // "nop" + patch((void *) 0x4a6c0, disable_cursor_patch); + // Add Custom Cursor Rendering + overwrite_calls((void *) GameRenderer_render, (void *) GameRenderer_render_injection); + } + + // Force Correct Toolbar Size + unsigned char toolbar_patch[4] = {0x01, 0x00, 0x50, 0xe3}; // "cmp r0, #0x1" + patch((void *) 0x257b0, toolbar_patch); + + // Show Block Outlines + int block_outlines = feature_has("Show Block Outlines"); + unsigned char outline_patch[4] = {block_outlines ? !touch_gui : touch_gui, 0x00, 0x50, 0xe3}; // "cmp r0, #0x1" or "cmp r0, #0x0" + patch((void *) 0x4a210, outline_patch); +}