Skip to content

Instantly share code, notes, and snippets.

@Kaloyan501
Created March 3, 2026 18:34
Show Gist options
  • Select an option

  • Save Kaloyan501/6d6abc33e84abca1432304b01a14d098 to your computer and use it in GitHub Desktop.

Select an option

Save Kaloyan501/6d6abc33e84abca1432304b01a14d098 to your computer and use it in GitHub Desktop.
Advanced Keyboard and Mouse shim for Minecraft Legacy Console Edition
#include "stdafx.h"
#include <Windows64\4JLibs\inc\4J_Input.h>
#include <Common\App_enums.h>
#include <Windows.h>
#include <iostream>
#include <atomic>
#include <chrono>
#include <vector>
#include <algorithm>
C_4JInput InputManager;
// --- MOUSE EMULATION (cursor sampling / recenter) ---
namespace MouseEmu
{
static std::atomic<int> g_dx(0);
static std::atomic<int> g_dy(0);
static float g_cached_rx = 0.0f;
static float g_cached_ry = 0.0f;
static bool g_cache_valid = false;
static DWORD g_last_poll = 0;
static bool g_was_focused = false;
static POINT g_center = {0,0};
static float g_sensitivity = 0.035f;
static float g_deadzone = 0.02f;
static float g_decayPerSecond = 16.0f;
template<typename T>
T Clamp(T val, T minVal, T maxVal)
{
if (val < minVal) return minVal;
if (val > maxVal) return maxVal;
return val;
}
static void SetupFocusState()
{
HWND hwnd = FindWindowA("MinecraftClass", NULL);
if (!hwnd) return;
RECT rc;
if (!GetClientRect(hwnd, &rc)) return;
POINT ul = { rc.left, rc.top }, lr = { rc.right, rc.bottom };
ClientToScreen(hwnd, &ul);
ClientToScreen(hwnd, &lr);
g_center.x = (ul.x + lr.x) / 2;
g_center.y = (ul.y + lr.y) / 2;
RECT clip = { ul.x, ul.y, lr.x, lr.y };
ClipCursor(&clip);
SetCursorPos(g_center.x, g_center.y);
ShowCursor(FALSE);
}
static void ClearFocusState()
{
ClipCursor(NULL);
ShowCursor(TRUE);
g_dx.store(0);
g_dy.store(0);
g_cached_rx = 0.0f;
g_cached_ry = 0.0f;
}
void NewFrame()
{
g_cache_valid = false;
bool focused = false;
HWND hwnd = FindWindowA("MinecraftClass", NULL);
if (hwnd && GetForegroundWindow() == hwnd) focused = true;
if (focused && !g_was_focused) {
SetupFocusState();
g_was_focused = true;
g_last_poll = GetTickCount();
return;
}
if (!focused && g_was_focused) {
ClearFocusState();
g_was_focused = false;
return;
}
if (focused) {
POINT p;
if (GetCursorPos(&p)) {
int dx = p.x - g_center.x;
int dy = p.y - g_center.y;
if (dx != 0 || dy != 0) {
g_dx.fetch_add(dx);
g_dy.fetch_add(dy);
SetCursorPos(g_center.x, g_center.y);
}
}
} else {
g_dx.store(0);
g_dy.store(0);
}
}
void Poll()
{
DWORD now = GetTickCount();
float dt = 1.0f / 60.0f;
if (g_last_poll != 0) {
DWORD diff = now - g_last_poll;
dt = diff / 1000.0f;
if (dt <= 0.0f) dt = 1.0f / 60.0f;
}
g_last_poll = now;
if (g_cache_valid) return;
int dx = g_dx.exchange(0);
int dy = g_dy.exchange(0);
dx = Clamp(dx, -30, 30);
dy = Clamp(dy, -30, 30);
float raw_rx = dx * g_sensitivity;
float raw_ry = -dy * g_sensitivity;
raw_rx = Clamp(raw_rx, -1.0f, 1.0f);
raw_ry = Clamp(raw_ry, -1.0f, 1.0f);
float lerpFactor = 1.0f - (float)exp(-g_decayPerSecond * dt);
g_cached_rx = g_cached_rx + (raw_rx - g_cached_rx) * lerpFactor;
g_cached_ry = g_cached_ry + (raw_ry - g_cached_ry) * lerpFactor;
//char buf[128];
//_snprintf_s(buf, sizeof(buf), _TRUNCATE, "MouseEmu: dx=%d dy=%d raw_rx=%.3f raw_ry=%.3f\n", dx, dy, raw_rx, raw_ry);
//OutputDebugStringA(buf);
g_cache_valid = true;
}
float GetRX() { Poll(); return g_cached_rx; }
float GetRY() { Poll(); return g_cached_ry; }
}
bool IsWindowFocused()
{
HWND hwnd = FindWindowA("MinecraftClass", NULL);
if (!hwnd)
return false;
return GetForegroundWindow() == hwnd;
}
void C_4JInput::Initialise(int iInputStateC, unsigned char ucMapC, unsigned char ucActionC, unsigned char ucMenuActionC)
{
}
bool m_CurrentKeys[256] = {};
bool m_PreviousKeys[256] = {};
void C_4JInput::Tick(void)
{
MouseEmu::NewFrame();
for (int i = 0; i < 256; ++i)
{
m_PreviousKeys[i] = m_CurrentKeys[i];
m_CurrentKeys[i] = (GetAsyncKeyState(i) & 0x8000) != 0;
}
}
void C_4JInput::SetDeadzoneAndMovementRange(unsigned int uiDeadzone, unsigned int uiMovementRangeMax)
{
}
void C_4JInput::SetGameJoypadMaps(unsigned char ucMap, unsigned char ucAction, unsigned int uiActionVal)
{
}
unsigned int C_4JInput::GetGameJoypadMaps(unsigned char ucMap, unsigned char ucAction)
{
return 0;
}
void C_4JInput::SetJoypadMapVal(int iPad, unsigned char ucMap)
{
}
unsigned char C_4JInput::GetJoypadMapVal(int iPad)
{
return 0;
}
void C_4JInput::SetJoypadSensitivity(int iPad, float fSensitivity)
{
}
bool KeyDown(int key) {
return (GetAsyncKeyState(key) & 0x8000) != 0;
}
bool KeyPressed(int key) {
return m_CurrentKeys[key] && !m_PreviousKeys[key];
}
bool KeyReleased(int key) {
return !m_CurrentKeys[key] && m_PreviousKeys[key];
}
bool C_4JInput::ButtonPressed(int iPad, unsigned char ucAction)
{
if (!IsWindowFocused())
return false;
switch (ucAction) {
//MAIN CONTROLS
case ACTION_MENU_UP: return KeyPressed(VK_UP);
case ACTION_MENU_DOWN: return KeyPressed(VK_DOWN);
case ACTION_MENU_LEFT: return KeyPressed(VK_LEFT);
case ACTION_MENU_RIGHT: return KeyPressed(VK_RIGHT);
case ACTION_MENU_OK:
case ACTION_MENU_A: return KeyPressed(VK_RETURN);
case ACTION_MENU_CANCEL:
case ACTION_MENU_B: return KeyPressed(VK_ESCAPE);
case ACTION_MENU_X: return KeyPressed('R');
case ACTION_MENU_Y: return KeyPressed('T');
case MINECRAFT_ACTION_FORWARD: return KeyPressed('W');
case MINECRAFT_ACTION_BACKWARD: return KeyPressed('S');
case MINECRAFT_ACTION_LEFT: return KeyPressed('A');
case MINECRAFT_ACTION_RIGHT: return KeyPressed('D');
case MINECRAFT_ACTION_JUMP: return KeyPressed(VK_SPACE);
case MINECRAFT_ACTION_INVENTORY: return KeyPressed('R');
case MINECRAFT_ACTION_DROP: return KeyPressed('Z');
case MINECRAFT_ACTION_ACTION: return KeyPressed(VK_LBUTTON);
case MINECRAFT_ACTION_USE: return KeyPressed(VK_RBUTTON);
//AUXILARY ACTIONS
case MINECRAFT_ACTION_RENDER_THIRD_PERSON: return KeyPressed(VK_F5);
case MINECRAFT_ACTION_PAUSEMENU: return KeyPressed(VK_ESCAPE);
case MINECRAFT_ACTION_CRAFTING: return KeyPressed('T');
case MINECRAFT_ACTION_SNEAK_TOGGLE: return KeyPressed(VK_LSHIFT);
//DPAD
case MINECRAFT_ACTION_DPAD_UP: return KeyPressed('I');
case MINECRAFT_ACTION_DPAD_DOWN: return KeyPressed('K');
case MINECRAFT_ACTION_DPAD_LEFT: return KeyPressed('J');
case MINECRAFT_ACTION_DPAD_RIGHT: return KeyPressed('L');
case MINECRAFT_ACTION_LEFT_SCROLL: return KeyPressed('1');
case MINECRAFT_ACTION_RIGHT_SCROLL: return KeyPressed('2');
case ACTION_MENU_LEFT_SCROLL: return KeyPressed('Q');
case ACTION_MENU_RIGHT_SCROLL: return KeyPressed('E');
case ACTION_MENU_OTHER_STICK_PRESS:
case ACTION_MENU_STICK_PRESS: return KeyPressed(VK_LCONTROL);
}
return false;
}
bool C_4JInput::ButtonReleased(int iPad, unsigned char ucAction)
{
if (!IsWindowFocused())
return false;
switch (ucAction) {
//MAIN CONTROLS
case ACTION_MENU_UP: return KeyReleased(VK_UP);
case ACTION_MENU_DOWN: return KeyReleased(VK_DOWN);
case ACTION_MENU_LEFT: return KeyReleased(VK_LEFT);
case ACTION_MENU_RIGHT: return KeyReleased(VK_RIGHT);
case ACTION_MENU_OK:
case ACTION_MENU_A: return KeyReleased(VK_RETURN);
case ACTION_MENU_CANCEL:
case ACTION_MENU_B: return KeyReleased(VK_ESCAPE);
case ACTION_MENU_X: return KeyReleased('R');
case ACTION_MENU_Y: return KeyReleased('T');
case MINECRAFT_ACTION_FORWARD: return KeyReleased('W');
case MINECRAFT_ACTION_BACKWARD: return KeyReleased('S');
case MINECRAFT_ACTION_LEFT: return KeyReleased('A');
case MINECRAFT_ACTION_RIGHT: return KeyReleased('D');
case MINECRAFT_ACTION_JUMP: return KeyReleased(VK_SPACE);
case MINECRAFT_ACTION_INVENTORY: return KeyReleased('R');
case MINECRAFT_ACTION_DROP: return KeyReleased('Z');
case MINECRAFT_ACTION_ACTION: return KeyReleased(VK_LBUTTON);
case MINECRAFT_ACTION_USE: return KeyReleased(VK_RBUTTON);
//AUXILARY ACTIONS
case MINECRAFT_ACTION_RENDER_THIRD_PERSON: return KeyReleased(VK_F5);
case MINECRAFT_ACTION_PAUSEMENU: return KeyReleased(VK_ESCAPE);
case MINECRAFT_ACTION_CRAFTING: return KeyReleased('T');
case MINECRAFT_ACTION_SNEAK_TOGGLE: return KeyReleased(VK_LSHIFT);
//DPAD
case MINECRAFT_ACTION_DPAD_UP: return KeyReleased('I');
case MINECRAFT_ACTION_DPAD_DOWN: return KeyReleased('K');
case MINECRAFT_ACTION_DPAD_LEFT: return KeyReleased('J');
case MINECRAFT_ACTION_DPAD_RIGHT: return KeyReleased('L');
case MINECRAFT_ACTION_LEFT_SCROLL: return KeyReleased('1');
case MINECRAFT_ACTION_RIGHT_SCROLL: return KeyReleased('2');
case ACTION_MENU_LEFT_SCROLL: return KeyReleased('Q');
case ACTION_MENU_RIGHT_SCROLL: return KeyReleased('E');
case ACTION_MENU_OTHER_STICK_PRESS:
case ACTION_MENU_STICK_PRESS: return KeyReleased(VK_LCONTROL);
}
return false;
}
bool C_4JInput::ButtonDown(int iPad, unsigned char ucAction)
{
if (!IsWindowFocused())
return false;
switch (ucAction) {
//MAIN CONTROLS
case ACTION_MENU_UP: return KeyDown(VK_UP);
case ACTION_MENU_DOWN: return KeyDown(VK_DOWN);
case ACTION_MENU_LEFT: return KeyDown(VK_LEFT);
case ACTION_MENU_RIGHT: return KeyDown(VK_RIGHT);
case ACTION_MENU_OK:
case ACTION_MENU_A: return KeyDown(VK_RETURN);
case ACTION_MENU_CANCEL:
case ACTION_MENU_B: return KeyDown(VK_ESCAPE);
case ACTION_MENU_X: return KeyDown('R');
case ACTION_MENU_Y: return KeyDown('T');
case MINECRAFT_ACTION_FORWARD: return KeyDown('W');
case MINECRAFT_ACTION_BACKWARD: return KeyDown('S');
case MINECRAFT_ACTION_LEFT: return KeyDown('A');
case MINECRAFT_ACTION_RIGHT: return KeyDown('D');
case MINECRAFT_ACTION_JUMP: return KeyDown(VK_SPACE);
case MINECRAFT_ACTION_INVENTORY: return KeyDown('R');
case MINECRAFT_ACTION_DROP: return KeyDown('Z');
case MINECRAFT_ACTION_ACTION: return KeyDown(VK_LBUTTON);
case MINECRAFT_ACTION_USE: return KeyDown(VK_RBUTTON);
//AUXILARY ACTIONS
case MINECRAFT_ACTION_RENDER_THIRD_PERSON: return KeyDown(VK_F5);
case MINECRAFT_ACTION_PAUSEMENU: return KeyDown(VK_ESCAPE);
case MINECRAFT_ACTION_CRAFTING: return KeyDown('T');
case MINECRAFT_ACTION_SNEAK_TOGGLE: return KeyDown(VK_LSHIFT);
//DPAD
case MINECRAFT_ACTION_DPAD_UP: return KeyDown('I');
case MINECRAFT_ACTION_DPAD_DOWN: return KeyDown('K');
case MINECRAFT_ACTION_DPAD_LEFT: return KeyDown('J');
case MINECRAFT_ACTION_DPAD_RIGHT: return KeyDown('L');
case MINECRAFT_ACTION_LEFT_SCROLL: return KeyDown('1');
case MINECRAFT_ACTION_RIGHT_SCROLL: return KeyDown('2');
case ACTION_MENU_LEFT_SCROLL: return KeyDown('Q');
case ACTION_MENU_RIGHT_SCROLL: return KeyDown('E');
case ACTION_MENU_OTHER_STICK_PRESS:
case ACTION_MENU_STICK_PRESS: return KeyDown(VK_LCONTROL);
}
return false;
}
/*bool C_4JInput::ButtonPressedDirect(int key) {
return KeyPressed(key);
}
*/
unsigned int C_4JInput::GetValue(int iPad, unsigned char ucAction, bool bRepeat)
{
return ButtonDown(iPad, ucAction);
}
void C_4JInput::SetJoypadStickAxisMap(int iPad, unsigned int uiFrom, unsigned int uiTo)
{
}
void C_4JInput::SetJoypadStickTriggerMap(int iPad, unsigned int uiFrom, unsigned int uiTo)
{
}
void C_4JInput::SetKeyRepeatRate(float fRepeatDelaySecs, float fRepeatRateSecs)
{
}
void C_4JInput::SetDebugSequence(const char* chSequenceA, int(*Func)(LPVOID), LPVOID lpParam)
{
}
FLOAT C_4JInput::GetIdleSeconds(int iPad)
{
return 0.0f;
}
bool C_4JInput::IsPadConnected(int iPad)
{
if (iPad == 0) return true;
return false;
}
float C_4JInput::GetJoypadStick_LX(int iPad, bool bCheckMenuDisplay)
{
if (!IsWindowFocused())
return 0.0f;
if (KeyDown('A')) {
return -1.0f;
} else if (KeyDown('D')) {
return 1.0f;
}
return 0.0f;
}
float C_4JInput::GetJoypadStick_LY(int iPad, bool bCheckMenuDisplay)
{
if (!IsWindowFocused())
return 0.0f;
if (KeyDown('W')) {
return 1.0f;
} else if (KeyDown('S')) {
return -1.0f;
}
return 0.0f;
}
float C_4JInput::GetJoypadStick_RX(int iPad, bool bCheckMenuDisplay)
{
if (!IsWindowFocused())
return 0.0f;
return MouseEmu::GetRX();
}
float C_4JInput::GetJoypadStick_RY(int iPad, bool bCheckMenuDisplay)
{
if (!IsWindowFocused())
return 0.0f;
return MouseEmu::GetRY();
}
unsigned char C_4JInput::GetJoypadLTrigger(int iPad, bool bCheckMenuDisplay)
{
if (!IsWindowFocused())
return 0;
if (KeyDown(VK_RBUTTON)) {
return 1;
}
return 0;
}
unsigned char C_4JInput::GetJoypadRTrigger(int iPad, bool bCheckMenuDisplay)
{
if (!IsWindowFocused())
return 0;
if (KeyDown(VK_LBUTTON)) {
return 1;
}
return 0;
}
void C_4JInput::SetMenuDisplayed(int iPad, bool bVal)
{
}
EKeyboardResult C_4JInput::RequestKeyboard(LPCWSTR Title, LPCWSTR Text, DWORD dwPad, UINT uiMaxChars, int( *Func)(LPVOID,const bool),LPVOID lpParam,C_4JInput::EKeyboardMode eMode)
{
return EKeyboard_Pending;
}
void C_4JInput::GetText(uint16_t* UTF16String)
{
}
bool C_4JInput::VerifyStrings(
WCHAR** pwStringA,
int iStringC,
int(*Func)(LPVOID, STRING_VERIFY_RESPONSE*),
LPVOID lpParam)
{
return false;
}
void C_4JInput::CancelQueuedVerifyStrings(
int(*Func)(LPVOID, STRING_VERIFY_RESPONSE*),
LPVOID lpParam)
{
}
void C_4JInput::CancelAllVerifyInProgress(void)
{
}
@LuBart08
Copy link

LuBart08 commented Mar 6, 2026

Where I need to place that file

@Kaloyan501
Copy link
Author

Where I need to place that file

Everything is explained in the first message below the code, open Minecraft.Client, make a new file named input_keyboard.cpp there, paste the code in, save and compile

@ingfar77-lab
Copy link

What is the button for a?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment