diff --git a/lib/Blackbone/src/BlackBone/BlackBone.vcxproj b/lib/Blackbone/src/BlackBone/BlackBone.vcxproj index 487e0c3..9126324 100644 --- a/lib/Blackbone/src/BlackBone/BlackBone.vcxproj +++ b/lib/Blackbone/src/BlackBone/BlackBone.vcxproj @@ -55,7 +55,7 @@ Win32Proj Xantos BlackBone - 10.0 + 10.0.18362.0 diff --git a/lib/EasyHook/EasyHookDll/EasyHookDll.vcxproj b/lib/EasyHook/EasyHookDll/EasyHookDll.vcxproj index 9cc661a..98f1c2e 100644 --- a/lib/EasyHook/EasyHookDll/EasyHookDll.vcxproj +++ b/lib/EasyHook/EasyHookDll/EasyHookDll.vcxproj @@ -38,7 +38,7 @@ {D087E484-DBC9-4A2E-8368-C1D0E524994D} EasyHookDll Win32Proj - 10.0 + 10.0.18362.0 diff --git a/src/ProtoInput/ProtoInputHooks/BlockXinputHook.cpp b/src/ProtoInput/ProtoInputHooks/BlockXinputHook.cpp new file mode 100644 index 0000000..ea6df2e --- /dev/null +++ b/src/ProtoInput/ProtoInputHooks/BlockXinputHook.cpp @@ -0,0 +1,85 @@ +#include "BlockXinputHook.h" +#include +#include + +namespace Proto +{ + + DWORD WINAPI Hook_XInputGetState(DWORD dwUserIndex, XINPUT_STATE* pState) + { + return ERROR_SUCCESS; + } + DWORD WINAPI Hook_XInputGetStateEx(DWORD dwUserIndex, XINPUT_STATE* pState) + { + return ERROR_SUCCESS; + } + + DWORD WINAPI Hook_XInputSetState(DWORD dwUserIndex, XINPUT_VIBRATION* pVibration) + { + return ERROR_SUCCESS; + } + + + void BlockXinputHook::ShowGuiStatus() + { + + ImGui::Separator(); + ImGui::Text("This hook blocks Xinput Controllers from being discovered by game."); + } + + void BlockXinputHook::InstallImpl() + { + // Some games (e.g. Terraria) haven't loaded the dlls when we inject hooks. So load all XInput dlls. + const wchar_t* xinputNames[] = { + L"xinput1_3.dll", L"xinput1_4.dll", L"xinput1_2.dll", L"xinput1_1.dll", L"xinput9_1_0.dll" + }; + for (const auto xinputName : xinputNames) + { + if (LoadLibraryW(xinputName) == nullptr) + { + fprintf(stderr, "Not hooking %ws as failed to load dll\n", xinputName); + continue; + } + + if (GetModuleHandleW(xinputName) == nullptr) + { + fprintf(stderr, "Not hooking %ws as failed get module\n", xinputName); + continue; + } + + hookInfos.push_back(std::get<1>(InstallNamedHook(xinputName, "XInputGetState", Hook_XInputGetState))); + hookInfos.push_back(std::get<1>(InstallNamedHook(xinputName, "XInputSetState", Hook_XInputSetState))); + } + //XinputGetStateEx (hidden call, ordinal 100). Only present in xinput1_4.dll and xinput1_3.dll. Used by EtG and DoS2 + //DWORD as 1st param and similar structure pointer for 2nd param (with an extra DWORD at the end). Can be treated as a normal XINPUT_STATE. + if (nullptr != LoadLibraryW(L"xinput1_4.dll")) + { + hookInfos.push_back(std::get<1>(InstallNamedHook(L"xinput1_4.dll", (LPCSTR)(100), Hook_XInputGetStateEx, true))); + } + if (nullptr != LoadLibraryW(L"xinput1_3.dll")) + { + hookInfos.push_back(std::get<1>(InstallNamedHook(L"xinput1_3.dll", (LPCSTR)(100), Hook_XInputGetStateEx, true))); + + XInputGetStateExPtr = t_XInputGetStateEx(GetProcAddress(GetModuleHandleW(L"xinput1_3.dll"), (LPCSTR)(100))); + XInputGetStatePtr = t_XInputGetState(GetProcAddress(GetModuleHandleW(L"xinput1_3.dll"), "XInputGetState")); + XInputSetStatePtr = t_XInputSetState(GetProcAddress(GetModuleHandleW(L"xinput1_3.dll"), "XInputSetState")); + + if (XInputGetStateExPtr == nullptr) + MessageBoxA(NULL, "XInputGetStateExPtr is null", "Error", MB_OK); + + if (XInputGetStatePtr == nullptr) + MessageBoxA(NULL, "XInputGetStatePtr is null", "Error", MB_OK); + + if (XInputSetStatePtr == nullptr) + MessageBoxA(NULL, "XInputSetStatePtr is null", "Error", MB_OK); + + if (XInputGetCapabilitiesPtr == nullptr) + MessageBoxA(NULL, "XInputGetCapabilitiesPtr is null", "Error", MB_OK); + } + + void BlockXinputHook::UninstallImpl() + { + UninstallHook(&hookInfoBlockXinput); + } + +} diff --git a/src/ProtoInput/ProtoInputHooks/BlockXinputHook.h b/src/ProtoInput/ProtoInputHooks/BlockXinputHook.h new file mode 100644 index 0000000..b8f786b --- /dev/null +++ b/src/ProtoInput/ProtoInputHooks/BlockXinputHook.h @@ -0,0 +1,29 @@ +#pragma once +#include "Hook.h" +#include "InstallHooks.h" + +namespace Proto +{ + + + class BlockXinputHook final : public Hook + { + private: + std::vector hookInfos{}; + + public: + const char* GetHookName() const override { return "Cursor Visibility"; } + const char* GetHookDescription() const override + { + return "Whenever the game calls for the cursor to be shown/hidden, the 'fake' cursor is shown/hidden instead. " + "Also detects when the game tries to set a custom cursor image, so the fake cursor can copy it. "; + } + bool HasGuiStatus() const override { return true; } + void ShowGuiStatus() override; + void InstallImpl() override; + void UninstallImpl() override; + + static bool ShowCursorWhenImageUpdated; + }; + +} \ No newline at end of file diff --git a/src/ProtoInput/ProtoInputHooks/FakeCursor.cpp b/src/ProtoInput/ProtoInputHooks/FakeCursor.cpp index 377962c..fb8e289 100644 --- a/src/ProtoInput/ProtoInputHooks/FakeCursor.cpp +++ b/src/ProtoInput/ProtoInputHooks/FakeCursor.cpp @@ -3,12 +3,20 @@ #include "InstallHooks.h" #include "FakeMouseKeyboard.h" #include "HwndSelector.h" +#include "ScanThread.h" +#include "TranslateXtoMKB.h" +#include "RawInput.h" +#include "SetCursorPosHook.h" +#include "XinputHook.h" #include namespace Proto { FakeCursor FakeCursor::state{}; +int FakeCursor::Showmessage = 0; +bool FakeCursor::DrawFakeCursorFix; + LRESULT WINAPI FakeCursorWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) { @@ -40,21 +48,300 @@ BOOL CALLBACK EnumWindowsProc(HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMoni } return true; } +void DrawRedX(HDC hdc, int x, int y) //blue +{ + HPEN hPen = CreatePen(PS_SOLID, 3, RGB(0, 0, 255)); + HPEN hOldPen = (HPEN)SelectObject(hdc, hPen); + + MoveToEx(hdc, x - 15, y - 15, NULL); + LineTo(hdc, x + 15, y + 15); + + MoveToEx(hdc, x + 15, y - 15, NULL); + LineTo(hdc, x - 15, y + 15); + + SelectObject(hdc, hOldPen); + DeleteObject(hPen); + return; +} +void DrawBlueCircle(HDC hdc, int x, int y) //red +{ + // Create a NULL brush (hollow fill) + HBRUSH hBrush = (HBRUSH)GetStockObject(NULL_BRUSH); + HBRUSH hOldBrush = (HBRUSH)SelectObject(hdc, hBrush); + + HPEN hPen = CreatePen(PS_SOLID, 3, RGB(255, 0, 0)); + HPEN hOldPen = (HPEN)SelectObject(hdc, hPen); + + Ellipse(hdc, x - 15, y - 15, x + 15, y + 15); + + SelectObject(hdc, hOldBrush); + SelectObject(hdc, hOldPen); + DeleteObject(hPen); +} +void DrawGreenTriangle(HDC hdc, int x, int y) +{ + // Use a NULL brush for hollow + HBRUSH hBrush = (HBRUSH)GetStockObject(NULL_BRUSH); + HBRUSH hOldBrush = (HBRUSH)SelectObject(hdc, hBrush); + + HPEN hPen = CreatePen(PS_SOLID, 3, RGB(0, 255, 0)); + HPEN hOldPen = (HPEN)SelectObject(hdc, hPen); + + POINT pts[3]; + pts[0].x = x; pts[0].y = y - 10; // top center + pts[1].x = x - 10; pts[1].y = y + 10; // bottom left + pts[2].x = x + 10; pts[2].y = y + 10; // bottom right + + Polygon(hdc, pts, 3); + + SelectObject(hdc, hOldBrush); + SelectObject(hdc, hOldPen); + DeleteObject(hPen); +} + +void DrawPinkSquare(HDC hdc, int x, int y) +{ + // Create a NULL brush (hollow fill) + HBRUSH hBrush = (HBRUSH)GetStockObject(NULL_BRUSH); + HBRUSH hOldBrush = (HBRUSH)SelectObject(hdc, hBrush); + + HPEN hPen = CreatePen(PS_SOLID, 3, RGB(255, 192, 203)); + HPEN hOldPen = (HPEN)SelectObject(hdc, hPen); + + // Draw hollow rectangle (square) 20x20 + Rectangle(hdc, x - 15, y - 15, x + 15, y + 15); + + SelectObject(hdc, hOldBrush); + SelectObject(hdc, hOldPen); + DeleteObject(hPen); +} + + +void FakeCursor::DrawMessage(HDC hdc, HWND window, HBRUSH Brush, int message) +{ + POINT here = { 0,0 }; + ClientToScreen(window, &here); + + if (oldmessage != message) + { + // RECT fill{ here.x + 20, here.y + 20, 500, 500 }; + // FillRect(hdc, &fill, Brush); // Note: window, not screen coordinates! + RECT wholewindow; + GetClientRect(pointerWindow, &wholewindow); + wholewindow.bottom = wholewindow.bottom / 2; + FillRect(hdc, &wholewindow, Brush); + // MessageBoxA(NULL, "Message Erased!", "Debug", MB_OK); + messageshown = false; + ScreenshotInput::TranslateXtoMKB::RefreshWindow = 1; //redraw cursor + } + if (!messageshown) + { + if (message == 1){ + TextOutW(hdc, here.x + 20, here.y + 20, TEXT("DISCONNECTED!"), 14); //14 + messageshown = true; + } + if (message == 2) { + TextOutW(hdc, here.x + 20, here.y + 20, TEXT("GUI TOGGLE!"), 11); //14 + messageshown = true; + } + if (message == 3) { + TextOutW(hdc, here.x + 20, here.y + 20, TEXT("SHOWCURSOR TOGGLE!"), 18); //14 + messageshown = true; + } + if (message == 4) { + TextOutW(hdc, here.x + 20, here.y + 20, TEXT("LOCK TOGGLED!"), 13); //14 + messageshown = true; + } + if (message == 5) { + TextOutW(hdc, here.x + 20, here.y + 20, TEXT("Window top!"), 11); //14 + messageshown = true; + } + if (message == 6) { + wchar_t buffer[25]; + swprintf(buffer, sizeof(buffer) / sizeof(buffer[0]), L"Sens Flat Adjust! (%d)", ScreenshotInput::TranslateXtoMKB::Sens); + TextOutW(hdc, here.x + 20, here.y + 20, buffer, (int)wcslen(buffer)); + TextOutW(hdc, here.x + 20, here.y + 40, TEXT("Press Up or Down!"), 17); //14 + messageshown = true; + } + if (message == 7) { + wchar_t buffer[25]; + swprintf(buffer, sizeof(buffer) / sizeof(buffer[0]), L"Sens Curve Adjust! (%d)", ScreenshotInput::TranslateXtoMKB::Sensmult); + TextOutW(hdc, here.x + 20, here.y + 20, buffer, (int)wcslen(buffer)); + TextOutW(hdc, here.x + 20, here.y + 40, TEXT("Press Up or Down!"), 17); + messageshown = true; + } + if (ScreenshotInput::TranslateXtoMKB::SaveBmps) { + TextOutW(hdc, here.x + 20, here.y + 0, TEXT("BMP SAVE MODE!"), 14); //14 + messageshown = true; + } + if (message == 10) { + TextOutW(hdc, here.x + 20, here.y + 25, TEXT("A MAPPED TO SPOT!"), 17); //14 + messageshown = true; + } + if (message == 11) { + TextOutW(hdc, here.x + 20, here.y + 25, TEXT("B MAPPED TO SPOT!"), 17); //14 + messageshown = true; + } + if (message == 12) { + TextOutW(hdc, here.x + 20, here.y + 25, TEXT("X MAPPED TO SPOT!"), 17); //14 + messageshown = true; + } + if (message == 13) { + TextOutW(hdc, here.x + 20, here.y + 25, TEXT("Y MAPPED TO SPOT!"), 17); //14 + messageshown = true; + } + } + oldmessage = message; + +} +void FakeCursor::DrawFoundSpots(HDC hdc, POINT spotA, POINT spotB, POINT spotX, POINT spotY,HWND window, HBRUSH Brush) +{ + bool windowmoved = false; + bool erasedA = false; + bool erased = false; + bool erasedB = false; + bool erasedX = false; + bool erasedY = false; + //detect window change pos + POINT testpos; + ClientToScreen(window, &testpos); + if (testpos.x < OldTestpos.x || testpos.y < OldTestpos.y || testpos.x > OldTestpos.x || testpos.y > OldTestpos.y) + { + erased = true; + } + + //point coordinate changes + if (OldspotA.x != spotA.x || OldspotA.y != spotA.y) + { + RECT fill{ OldspotA.x - 20, OldspotA.y - 20, OldspotA.x + 20, OldspotA.y + 20 }; + FillRect(hdc, &fill, transparencyBrush); // Note: window, not screen coordinates! + erasedA = true; + } + + if (OldspotB.x != spotB.x || OldspotB.y != spotB.y) //|| windowmoved) + { + RECT fill{ OldspotB.x - 20, OldspotB.y - 20, OldspotB.x + 20, OldspotB.y + 20 }; + FillRect(hdc, &fill, transparencyBrush); // Note: window, not screen coordinates! + erasedB = true; + } + if (OldspotX.x != spotX.x || OldspotX.y != spotX.y) //|| windowmoved) + { + RECT fill{ OldspotX.x - 20, OldspotX.y - 20, OldspotX.x + 20, OldspotX.y + 20 }; + FillRect(hdc, &fill, transparencyBrush); // Note: window, not screen coordinates! + erasedX = true; + } + if (OldspotY.x != spotY.x || OldspotY.y != spotY.y) //|| windowmoved) + { + RECT fill{ OldspotY.x - 20, OldspotY.y - 20, OldspotY.x + 20, OldspotY.y + 20 }; + FillRect(hdc, &fill, transparencyBrush); // Note: window, not screen coordinates! + erasedY = true; + + } + + + if (erased == true) + { + RECT wholewindow; + GetClientRect(pointerWindow, &wholewindow); + + FillRect(hdc, &wholewindow, Brush); + + erasedA = true; + erasedB = true; + erasedX = true; + erasedY = true; + + ScreenshotInput::TranslateXtoMKB::RefreshWindow = 1; //redraw cursor + } + + + OldspotA.x = spotA.x; + OldspotA.y = spotA.y; + + OldspotB.x = spotB.x; + OldspotB.y = spotB.y; + + OldspotX.x = spotX.x; + OldspotX.y = spotX.y; + + OldspotY.x = spotY.x; + OldspotY.y = spotY.y; + + + if (spotA.x != 0 && spotA.y != 0 && erasedA == true) + { + POINT drawthere = spotA; + ClientToScreen(window, &drawthere); //A + DrawRedX(hdc, drawthere.x, drawthere.y); + } + + + if (spotB.x != 0 && spotB.y != 0 && erasedB == true) + { + POINT drawthere = spotB; + ClientToScreen(window, &drawthere); //A + DrawBlueCircle(hdc, drawthere.x, drawthere.y); + } + + + if (spotX.x != 0 && spotX.y != 0 && erasedX == true) + { + POINT drawthere = spotX; + ClientToScreen(window, &drawthere); //A + DrawPinkSquare(hdc, drawthere.x, drawthere.y); + + } + + + if (spotY.x != 0 && spotY.y != 0 && erasedY == true) + { + POINT drawthere = spotY; + ClientToScreen(window, &drawthere); //A + DrawGreenTriangle(hdc, drawthere.x, drawthere.y); + } + OldTestpos = testpos; +} + +void FakeCursor::DrawPointsandMessages() //only on Xtranslate +{ + if (ScreenshotInput::ScanThread::scanoption) + { + EnterCriticalSection(&ScreenshotInput::ScanThread::critical); + selectorhwnd = (HWND)HwndSelector::GetSelectedHwnd(); + // FakeCursor::Showmessage = ScreenshotInput::TranslateXtoMKB::showmessage; + POINT Apos = { ScreenshotInput::ScanThread::PointA.x, ScreenshotInput::ScanThread::PointA.y }; + POINT Bpos = { ScreenshotInput::ScanThread::PointB.x, ScreenshotInput::ScanThread::PointB.y }; + POINT Xpos = { ScreenshotInput::ScanThread::PointX.x, ScreenshotInput::ScanThread::PointX.y }; + POINT Ypos = { ScreenshotInput::ScanThread::PointY.x, ScreenshotInput::ScanThread::PointY.y }; + FakeCursor::DrawFoundSpots(hdc, Apos, Bpos, Xpos, Ypos, selectorhwnd, transparencyBrush); + FakeCursor::DrawMessage(hdc, selectorhwnd, transparencyBrush, FakeCursor::Showmessage); + LeaveCriticalSection(&ScreenshotInput::ScanThread::critical); + } + else if (RawInput::TranslateXinputtoMKB) + DrawMessage(hdc, (HWND)HwndSelector::GetSelectedHwnd(), transparencyBrush, FakeCursor::Showmessage); + +} void FakeCursor::DrawCursor() { + POINT pos = { FakeMouseKeyboard::GetMouseState().x,FakeMouseKeyboard::GetMouseState().y }; + + if (XinputHook::TranslateMKBtoXinput) + { + pos.x = SetCursorPosHook::mousesethere.x; + pos.y = SetCursorPosHook::mousesethere.y; + } + ClientToScreen((HWND)HwndSelector::GetSelectedHwnd(), &pos); + ScreenToClient(pointerWindow, &pos); + if (oldHadShowCursor) //erase cursor { RECT fill{ oldX, oldY, oldX + cursorWidth, oldY + cursorHeight }; FillRect(hdc, &fill, transparencyBrush); // Note: window, not screen coordinates! - } oldHadShowCursor = showCursor; - POINT pos = { FakeMouseKeyboard::GetMouseState().x,FakeMouseKeyboard::GetMouseState().y }; - ClientToScreen((HWND)HwndSelector::GetSelectedHwnd(), &pos); - ScreenToClient(pointerWindow, &pos); if (DrawFakeCursorFix) { @@ -64,43 +351,82 @@ void FakeCursor::DrawCursor() if (pos.x < 0) pos.x = 0; if (pos.y < 0) pos.y = 0; + //offsetSET is stepping each cursor update: step 0 check size //step 1 check offset //step 2 only draw if (showCursor)// && hdc && hCursor { if (DrawIconEx(hdc, pos.x, pos.y, hCursor, cursorWidth, cursorHeight, 0, transparencyBrush, DI_NORMAL)) { + if (hCursor != oldhCursor && offsetSET > 1 && nochange == false) + { + offsetSET = 0; + } if (offsetSET == 1 && hCursor != LoadCursorW(NULL, IDC_ARROW) && IsWindowVisible(pointerWindow)) //offset setting { HDC hdcMem = CreateCompatibleDC(hdc); HBITMAP hbmScreen = CreateCompatibleBitmap(hdc, cursorWidth, cursorHeight); SelectObject(hdcMem, hbmScreen); BitBlt(hdcMem, 0, 0, cursorWidth, cursorHeight, hdc, pos.x, pos.y, SRCCOPY); - // Scan within the cursor screenshot pixel area cursoroffsetx = -1; cursoroffsety = -1; + int leftcursoroffsetx = 0; + int leftcursoroffsety = -1; + int rightcursoroffsetx = 0; + // Scanning for (int y = 0; y < cursorHeight; y++) { for (int x = 0; x < cursorWidth; x++) { - COLORREF pixelColor = GetPixel(hdcMem, x, y); // Get copied pixel color + COLORREF pixelColor = GetPixel(hdcMem, x, y); // scan from left and find common y to use in next scan also if (pixelColor != transparencyKey) { - cursoroffsetx = x; - cursoroffsety = y; + leftcursoroffsetx = x; + leftcursoroffsety = y; break; } } - if (cursoroffsetx != -1) break; + if (leftcursoroffsetx != -1) break; } - if (cursoroffsetx < 2) cursoroffsetx = 0; - if (cursoroffsety < 2) cursoroffsety = 0; - offsetSET ++; //offset set to 2 should do drawing only now + + + for (int x = cursorWidth - 1; x >= 0; x--) + { + COLORREF pixelColor = GetPixel(hdcMem, x, leftcursoroffsety); // scan from right + if (pixelColor != transparencyKey) + { + rightcursoroffsetx = cursorWidth - x; + break; + } + } + //Adjusting possible here if symmetric cursor is not found + if (leftcursoroffsetx == rightcursoroffsetx - 1 || leftcursoroffsetx == rightcursoroffsetx + 1 || leftcursoroffsetx == rightcursoroffsetx) //check for symmetric first only if Y offset is small + { + cursoroffsety = cursorHeight / 2; + cursoroffsetx = cursorWidth / 2; + } + else if (leftcursoroffsety > 2 || leftcursoroffsetx > 2) //is there any other offsets? + { + cursoroffsetx = leftcursoroffsetx; + cursoroffsety = leftcursoroffsety; + nochange = true; + } + + else { //no offsets + cursoroffsetx = 0; + cursoroffsety = 0; + } + offsetSET++; //offset set to 2 should do drawing only now DeleteDC(hdcMem); DeleteObject(hbmScreen); + + + } if (offsetSET == 0 && hCursor != LoadCursorW(NULL, IDC_ARROW) && IsWindowVisible(pointerWindow)) //size setting { ICONINFO ii; BITMAP bitmap; + cursoroffsetx = 0; + cursoroffsety = 0; if (GetIconInfo(hCursor, &ii)) { if (GetObject(ii.hbmMask, sizeof(BITMAP), &bitmap)) @@ -121,11 +447,14 @@ void FakeCursor::DrawCursor() } offsetSET++; //size set, doing offset next run } + oldhCursor = hCursor; } } } else if (showCursor) + { DrawIcon(hdc, pos.x, pos.y, hCursor); + } oldX = pos.x; oldY = pos.y; } @@ -141,23 +470,45 @@ DWORD WINAPI FakeCursorDrawLoopThread(LPVOID lpParameter) void FakeCursor::StartDrawLoopInternal() { - int tick = 0; + int tick = 1; + + if (Proto::RawInput::TranslateXinputtoMKB) + ScreenshotInput::TranslateXtoMKB::Initialize(GetModuleHandle(NULL)); while (true) { - std::unique_lock lock(mutex); - conditionvar.wait(lock); - - DrawCursor(); - - //TODO: is this ok? (might eat cpu) - Sleep(drawingEnabled ? 12 : 500); - - tick = (tick + 1) % 200; + if (!Proto::RawInput::TranslateXinputtoMKB) + { + std::unique_lock lock(mutex); + conditionvar.wait(lock); + + DrawCursor(); + + //TODO: is this ok? (might eat cpu) + Sleep(drawingEnabled ? 12 : 500); + tick = (tick + 1) % 200; + } + else + { + ScreenshotInput::TranslateXtoMKB::ThreadFunction(); + if (ScreenshotInput::TranslateXtoMKB::RefreshPoint > 0) + { + DrawPointsandMessages(); + ScreenshotInput::TranslateXtoMKB::RefreshPoint--; + } + if (ScreenshotInput::TranslateXtoMKB::RefreshWindow > 0) + { + DrawCursor(); + ScreenshotInput::TranslateXtoMKB::RefreshWindow--; + } + tick = (tick + 1) % 2000; //guess this run about 10-12 times faster + } if (tick == 0) + { // Nucleus can put the game window above the pointer without this SetWindowPos(pointerWindow, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOREDRAW | SWP_NOSIZE); + } } } @@ -250,10 +601,10 @@ void FakeCursor::EnableDisableFakeCursor(bool enable) UpdateWindow(state.pointerWindow); } -void FakeCursor::Initialise() +void FakeCursor::Initialise(HMODULE module) { const auto threadHandle = CreateThread(nullptr, 0, - (LPTHREAD_START_ROUTINE)FakeCursorThreadStart, GetModuleHandle(0), 0, 0); + (LPTHREAD_START_ROUTINE)FakeCursorThreadStart, module, 0, 0); if (threadHandle != nullptr) CloseHandle(threadHandle); diff --git a/src/ProtoInput/ProtoInputHooks/FakeCursor.h b/src/ProtoInput/ProtoInputHooks/FakeCursor.h index 0574f66..0b7ba83 100644 --- a/src/ProtoInput/ProtoInputHooks/FakeCursor.h +++ b/src/ProtoInput/ProtoInputHooks/FakeCursor.h @@ -5,45 +5,62 @@ namespace Proto { -class FakeCursor -{ - std::mutex mutex{}; - std::condition_variable conditionvar{}; - - HWND pointerWindow = nullptr; - HDC hdc; - HBRUSH transparencyBrush; - HCURSOR hCursor; - static constexpr auto transparencyKey = RGB(0, 0, 1); - - int oldX, oldY; - bool oldHadShowCursor = true; - //TODO: width/height probably needs to change + class FakeCursor + { + std::mutex mutex{}; + std::condition_variable conditionvar{}; + HWND pointerWindow = nullptr; + HDC hdc; + HBRUSH transparencyBrush; + HCURSOR hCursor; - // DrawFakeCursorFix. cursor offset scan and cursor size fix - int cursoroffsetx, cursoroffsety; - int offsetSET; //0:sizing 1:offset 2:done - int cursorWidth = 40; - int cursorHeight = 40; + static constexpr auto transparencyKey = RGB(0, 0, 1); - // This is either on or off for a given game (ie. it doesn't change) - bool drawingEnabled = false; + int oldX, oldY; + bool oldHadShowCursor = true; + //TODO: width/height probably needs to change + + + // DrawFakeCursorFix. cursor offset scan and cursor size fix + int cursoroffsetx, cursoroffsety; + int offsetSET = 0; //0:sizing 1:scanning 2:done, only drawing until cursor change, or nochange + int cursorWidth = 40; //was constant + int cursorHeight = 40;//was constant + bool nochange = false; //if normal offset was found at first then assume all cursors got same offset + HCURSOR oldhCursor = NULL; + POINT OldTestpos = { 0,0 }; + + // This is either on or off for a given game (ie. it doesn't change) + bool drawingEnabled = false; + + // This changes when the hook detects SetCursor/ShowCursor + bool showCursor = true; + + bool toggleVisilbityShorcutEnabled = false; + unsigned int toggleVisibilityVkey = VK_HOME; + + + + //TranslateXtoMKB + POINT OldspotA, OldspotB, OldspotX, OldspotY; + int oldmessage = 0; + bool messageshown = false; + HWND selectorhwnd = nullptr; //copy of variable in TranslateXtoMKB to avoid accessing it multiple times with critical section in DrawCursor + + void DrawMessage(HDC hdc, HWND window, HBRUSH Brush, int message); + void DrawFoundSpots(HDC hdc, POINT spotA, POINT spotB, POINT spotX, POINT spotY, HWND window, HBRUSH Brush); + void DrawPointsandMessages(); + void DrawCursor(); - // This changes when the hook detects SetCursor/ShowCursor - bool showCursor = true; - bool toggleVisilbityShorcutEnabled = false; - unsigned int toggleVisibilityVkey = VK_HOME; - - void DrawCursor(); - public: static FakeCursor state; - bool DrawFakeCursorFix; + static bool DrawFakeCursorFix; void StartInternal(); void StartDrawLoopInternal(); + static int Showmessage; static bool& GetToggleVisilbityShorcutEnabled() { return state.toggleVisilbityShorcutEnabled; @@ -87,7 +104,7 @@ class FakeCursor static void EnableDisableFakeCursor(bool enable); - static void Initialise(); + static void Initialise(HMODULE module); }; } diff --git a/src/ProtoInput/ProtoInputHooks/FakeMouseKeyboard.h b/src/ProtoInput/ProtoInputHooks/FakeMouseKeyboard.h index f83313c..e8cb79d 100644 --- a/src/ProtoInput/ProtoInputHooks/FakeMouseKeyboard.h +++ b/src/ProtoInput/ProtoInputHooks/FakeMouseKeyboard.h @@ -42,6 +42,7 @@ class FakeMouseKeyboard public: static const FakeMouseState& GetMouseState() { return mouseState; } + //static const FakeKeyboardState& GetKeyBoardState() { return keyboardState; } static void AddMouseDelta(int dx, int dy); static void SetMousePos(int x, int y); diff --git a/src/ProtoInput/ProtoInputHooks/GetAsyncKeyStateHook.cpp b/src/ProtoInput/ProtoInputHooks/GetAsyncKeyStateHook.cpp index d585819..896279f 100644 --- a/src/ProtoInput/ProtoInputHooks/GetAsyncKeyStateHook.cpp +++ b/src/ProtoInput/ProtoInputHooks/GetAsyncKeyStateHook.cpp @@ -1,14 +1,21 @@ #include "GetAsyncKeyStateHook.h" #include "FakeMouseKeyboard.h" +#include "XinputHook.h" namespace Proto { SHORT WINAPI Hook_GetAsyncKeyState(int vKey) { + auto ret = (FakeMouseKeyboard::IsKeyStatePressed(vKey) ? 0b1000000000000000 : 0) | (FakeMouseKeyboard::IsAsyncKeyStatePressed(vKey) ? 1 : 0); FakeMouseKeyboard::ClearAsyncKeyState(vKey); - return ret; + if (!XinputHook::TranslateMKBtoXinput) + { + return ret; + } + else return 0; + } void GetAsyncKeyStateHook::InstallImpl() diff --git a/src/ProtoInput/ProtoInputHooks/GetCursorInfoHook.cpp b/src/ProtoInput/ProtoInputHooks/GetCursorInfoHook.cpp new file mode 100644 index 0000000..e6065f7 --- /dev/null +++ b/src/ProtoInput/ProtoInputHooks/GetCursorInfoHook.cpp @@ -0,0 +1,63 @@ +#include "GetCursorInfoHook.h" +#include "FakeMouseKeyboard.h" +#include "HwndSelector.h" +#include "WindowMsgHook.h" +namespace Proto +{ + + BOOL WINAPI Hook_GetCursorInfo(PCURSORINFO pci) + { + if (GetCursorInfo(pci)) + { + + const auto& state = FakeMouseKeyboard::GetMouseState(); + POINT clientPos = { state.x, state.y }; + if (FakeMouseKeyboard::PutMouseInsideWindow) + { + int clientWidth = HwndSelector::windowWidth; + int clientHeight = HwndSelector::windowHeight; + if (!FakeMouseKeyboard::DefaultTopLeftMouseBounds) + { + if (clientPos.y < 1) + clientPos.y = 0; // Top edge + if (clientPos.x < 1) + clientPos.x = 0; // Left edge + } + if (!FakeMouseKeyboard::DefaultBottomRightMouseBounds) + { + if (clientPos.y > clientHeight - 1) + clientPos.y = clientHeight - 1; // Bottom edge + if (clientPos.x > clientWidth - 1) + clientPos.x = clientWidth - 1; // Right edge + } + } + + //any scaling? + clientPos = WindowMsgHook::getfactor(clientPos); + + ClientToScreen((HWND)HwndSelector::GetSelectedHwnd(), &clientPos); + pci->ptScreenPos.x = clientPos.x; + pci->ptScreenPos.y = clientPos.y; + + } + return true; + + + } + + void GetCursorInfoHook::ShowGuiStatus() + { + + } + + void GetCursorInfoHook::InstallImpl() + { + hookInfo = std::get<1>(InstallNamedHook(L"user32", "GetCursorInfo", Hook_GetCursorInfo)); + } + + void GetCursorInfoHook::UninstallImpl() + { + UninstallHook(&hookInfo); + } + +} diff --git a/src/ProtoInput/ProtoInputHooks/GetCursorInfoHook.h b/src/ProtoInput/ProtoInputHooks/GetCursorInfoHook.h new file mode 100644 index 0000000..b8b8c88 --- /dev/null +++ b/src/ProtoInput/ProtoInputHooks/GetCursorInfoHook.h @@ -0,0 +1,22 @@ +#pragma once +#include "Hook.h" +#include "InstallHooks.h" + +namespace Proto +{ + + class GetCursorInfoHook final : public Hook + { + private: + HookInfo hookInfo{}; + + public: + const char* GetHookName() const override { return "GetCursorInfo"; } + const char* GetHookDescription() const override { return "Hooks the GetCursorInfo function to return our 'fake' position"; } + bool HasGuiStatus() const override { return false; } + void ShowGuiStatus() override; + void InstallImpl() override; + void UninstallImpl() override; + }; + +} diff --git a/src/ProtoInput/ProtoInputHooks/GetCursorPosHook.cpp b/src/ProtoInput/ProtoInputHooks/GetCursorPosHook.cpp index bc9448a..5cc0b9d 100644 --- a/src/ProtoInput/ProtoInputHooks/GetCursorPosHook.cpp +++ b/src/ProtoInput/ProtoInputHooks/GetCursorPosHook.cpp @@ -1,6 +1,9 @@ #include "GetCursorPosHook.h" #include "FakeMouseKeyboard.h" #include "HwndSelector.h" +#include "WindowMsgHook.h" +#include "XinputHook.h" +#include "SetCursorPosHook.h" namespace Proto { @@ -9,10 +12,17 @@ BOOL WINAPI Hook_GetCursorPos(LPPOINT lpPoint) { if (lpPoint) { - const auto& state = FakeMouseKeyboard::GetMouseState(); - lpPoint->x = state.x; - lpPoint->y = state.y; - + if (!XinputHook::TranslateMKBtoXinput) + { + const auto& state = FakeMouseKeyboard::GetMouseState(); + lpPoint->x = state.x; + lpPoint->y = state.y; + } + else + { + lpPoint->x = SetCursorPosHook::mousesethere.x; + lpPoint->y = SetCursorPosHook::mousesethere.y; + } if (FakeMouseKeyboard::PutMouseInsideWindow) { int clientWidth = HwndSelector::windowWidth; @@ -32,6 +42,12 @@ BOOL WINAPI Hook_GetCursorPos(LPPOINT lpPoint) lpPoint->x = clientWidth - 1; // Right edge } } + //any scaling? + POINT clientPos = { lpPoint->x, lpPoint->y }; + clientPos = WindowMsgHook::getfactor(clientPos); + + lpPoint->x = clientPos.x; + lpPoint->y = clientPos.y; ClientToScreen((HWND)HwndSelector::GetSelectedHwnd(), lpPoint); } diff --git a/src/ProtoInput/ProtoInputHooks/GetKeyStateHook.cpp b/src/ProtoInput/ProtoInputHooks/GetKeyStateHook.cpp index 58bf852..e117cb6 100644 --- a/src/ProtoInput/ProtoInputHooks/GetKeyStateHook.cpp +++ b/src/ProtoInput/ProtoInputHooks/GetKeyStateHook.cpp @@ -1,12 +1,15 @@ #include "GetKeyStateHook.h" #include "FakeMouseKeyboard.h" +#include "XinputHook.h" namespace Proto { SHORT WINAPI Hook_GetKeyState(int nVirtKey) { - return FakeMouseKeyboard::IsKeyStatePressed(nVirtKey) ? 0b1000000000000000 : 0; + if (!XinputHook::TranslateMKBtoXinput) + return FakeMouseKeyboard::IsKeyStatePressed(nVirtKey) ? 0b1000000000000000 : 0; + else return 0; } void GetKeyStateHook::InstallImpl() diff --git a/src/ProtoInput/ProtoInputHooks/GetKeyboardStateHook.cpp b/src/ProtoInput/ProtoInputHooks/GetKeyboardStateHook.cpp index 3e0a122..1e73dcd 100644 --- a/src/ProtoInput/ProtoInputHooks/GetKeyboardStateHook.cpp +++ b/src/ProtoInput/ProtoInputHooks/GetKeyboardStateHook.cpp @@ -1,5 +1,6 @@ #include "GetKeyboardStateHook.h" #include "FakeMouseKeyboard.h" +#include "XinputHook.h" namespace Proto { @@ -12,7 +13,9 @@ BOOL WINAPI Hook_GetKeyboardState(PBYTE lpKeyState) for (int vkey = 0; vkey < 256; ++vkey) { - lpKeyState[vkey] = FakeMouseKeyboard::IsKeyStatePressed(vkey) ? 0b10000000 : 0; + if (!XinputHook::TranslateMKBtoXinput) + lpKeyState[vkey] = FakeMouseKeyboard::IsKeyStatePressed(vkey) ? 0b10000000 : 0; + else lpKeyState[vkey] = 0; } } diff --git a/src/ProtoInput/ProtoInputHooks/GetRawInputDataHook.cpp b/src/ProtoInput/ProtoInputHooks/GetRawInputDataHook.cpp index a7a4198..244ba66 100644 --- a/src/ProtoInput/ProtoInputHooks/GetRawInputDataHook.cpp +++ b/src/ProtoInput/ProtoInputHooks/GetRawInputDataHook.cpp @@ -3,9 +3,13 @@ #include "RegisterRawInputHook.h" #include #include "RawInput.h" +#include "GtoMnK_RawInputHooks.h" //GtoMnK_RawInput.cpp +#include "GtoMnK_RawInput.h" //GtoMnK_RawInput.cpp//TranslateXtoMKB.h +//#include "TranslateXtoMKB.h" //GtoMnK_RawInput.cpp//TranslateXtoMKB.h namespace Proto { + UINT WINAPI Hook_GetRawInputData( HRAWINPUT hRawInput, @@ -15,19 +19,41 @@ UINT WINAPI Hook_GetRawInputData( UINT cbSizeHeader ) { + unsigned int h = (unsigned int)hRawInput; // Only care about first 4 bytes. bool hasSignature = (h & 0xFF000000) == 0xAB000000; + //MessageBoxA(NULL, "WARNING: GetRawInputData doesn't have the signature. This means Proto Input won't work properly. Please report this to the developer.", "Proto Input", MB_OK | MB_ICONWARNING); if (!hasSignature) { + // printf("GetRawInputData doesn't have signature: h = 0x%X\n", h); return GetRawInputData(hRawInput, uiCommand, pData, pcbSize, cbSizeHeader); } else { + + if (RawInput::TranslateXinputtoMKB2) // TranslateXinputtoMKB2 is just a copy of TranslateXinputtoMKB + { + UINT handleValue = (UINT)(UINT_PTR)hRawInput; + UINT bufferIndex = handleValue & 0x00FFFFFF; + if (bufferIndex >= 20) { + return GetRawInputData(hRawInput, uiCommand, pData, pcbSize, cbSizeHeader); + } + + if (pData == NULL) { + *pcbSize = sizeof(RAWINPUT); + return 0; + } + + RAWINPUT* storedData = &RawInput::inputBuffer[RawInput::bufferCounter]; + memcpy(pData, storedData, sizeof(RAWINPUT)); + return sizeof(RAWINPUT); + } // printf("$"); auto index = h & 0x00FFFFFF; + if (pData == NULL) { *pcbSize = uiCommand == RID_INPUT ? sizeof(RAWINPUT) : sizeof(RAWINPUTHEADER); @@ -35,6 +61,7 @@ UINT WINAPI Hook_GetRawInputData( } else { + if (uiCommand == RID_INPUT) { RAWINPUT* ptr = (RAWINPUT*)pData; @@ -51,13 +78,10 @@ UINT WINAPI Hook_GetRawInputData( } } -// void GetRawInputDataHook::ShowGuiStatus() -// { -// } - void GetRawInputDataHook::InstallImpl() { - hookInfo = std::get<1>(InstallNamedHook(L"user32", "GetRawInputData", Hook_GetRawInputData)); + hookInfo = std::get<1>(InstallNamedHook(L"user32", "GetRawInputData", Hook_GetRawInputData)); + } void GetRawInputDataHook::UninstallImpl() diff --git a/src/ProtoInput/ProtoInputHooks/GetRawInputDataHook.h b/src/ProtoInput/ProtoInputHooks/GetRawInputDataHook.h index b600bba..19cf9f8 100644 --- a/src/ProtoInput/ProtoInputHooks/GetRawInputDataHook.h +++ b/src/ProtoInput/ProtoInputHooks/GetRawInputDataHook.h @@ -18,7 +18,7 @@ class GetRawInputDataHook final : public Hook "This hook forwards the raw input received by Proto Input to the game. " "This is required for any game that uses raw input, or Proto Input will consume all the input."; } - + static int lastVKcode; //keymapping GUI bool HasGuiStatus() const override { return false; } // void ShowGuiStatus() override; void InstallImpl() override; diff --git a/src/ProtoInput/ProtoInputHooks/GtoMnK_RawInput.cpp b/src/ProtoInput/ProtoInputHooks/GtoMnK_RawInput.cpp new file mode 100644 index 0000000..8c6609b --- /dev/null +++ b/src/ProtoInput/ProtoInputHooks/GtoMnK_RawInput.cpp @@ -0,0 +1,159 @@ +#include "GtoMnK_RawInput.h" +#include "GtoMnK_RawInputHooks.h" +#include "HwndSelector.h" +#include "RawInput.h" + +//copied from:https://github.com/SAM1430B/GtoMnK + +namespace ScreenshotInput { + + void RawInput::GenerateRawKey(int vkCode, bool press, bool isExtended) { + if (vkCode == 0) return; + + RAWINPUT ri = {}; + ri.header.dwType = RIM_TYPEKEYBOARD; + ri.header.hDevice = NULL; + + UINT scanCode = MapVirtualKey(vkCode, MAPVK_VK_TO_VSC); + ri.data.keyboard.MakeCode = scanCode; + ri.data.keyboard.Message = press ? WM_KEYDOWN : WM_KEYUP; + ri.data.keyboard.VKey = vkCode; + ri.data.keyboard.Flags = press ? RI_KEY_MAKE : RI_KEY_BREAK; + + if (isExtended) { + ri.data.keyboard.Flags |= RI_KEY_E0; + } + + Proto::RawInput::InjectFakeRawInput(ri); + } + + void RawInput::GenerateRawMouseButton(int actionCode, bool press) { + RAWINPUT ri = {}; + ri.header.dwType = RIM_TYPEMOUSE; + ri.header.hDevice = NULL; + if (actionCode == -8) { // Left Double + GenerateRawMouseButton(-1, true); GenerateRawMouseButton(-1, false); + GenerateRawMouseButton(-1, press); return; + } + if (actionCode == -9) { // Right Double + GenerateRawMouseButton(-2, true); GenerateRawMouseButton(-2, false); + GenerateRawMouseButton(-2, press); return; + } + if (actionCode == -10) { // Middle Double + GenerateRawMouseButton(-3, true); GenerateRawMouseButton(-3, false); + GenerateRawMouseButton(-3, press); return; + } + if (actionCode == -11) { // X1 Double + GenerateRawMouseButton(-4, true); GenerateRawMouseButton(-4, false); + GenerateRawMouseButton(-4, press); return; + } + if (actionCode == -12) { // X2 Double + GenerateRawMouseButton(-5, true); GenerateRawMouseButton(-5, false); + GenerateRawMouseButton(-5, press); return; + } + switch (actionCode) { + case -1: ri.data.mouse.usButtonFlags = press ? RI_MOUSE_LEFT_BUTTON_DOWN : RI_MOUSE_LEFT_BUTTON_UP; break; + case -2: ri.data.mouse.usButtonFlags = press ? RI_MOUSE_RIGHT_BUTTON_DOWN : RI_MOUSE_RIGHT_BUTTON_UP; break; + case -3: ri.data.mouse.usButtonFlags = press ? RI_MOUSE_MIDDLE_BUTTON_DOWN : RI_MOUSE_MIDDLE_BUTTON_UP; break; + case -4: ri.data.mouse.usButtonFlags = press ? RI_MOUSE_BUTTON_4_DOWN : RI_MOUSE_BUTTON_4_UP; break; + case -5: ri.data.mouse.usButtonFlags = press ? RI_MOUSE_BUTTON_5_DOWN : RI_MOUSE_BUTTON_5_UP; break; + case -6: if (press) ri.data.mouse.usButtonFlags = RI_MOUSE_WHEEL; ri.data.mouse.usButtonData = WHEEL_DELTA; break; + case -7: if (press) ri.data.mouse.usButtonFlags = RI_MOUSE_WHEEL; ri.data.mouse.usButtonData = -WHEEL_DELTA; break; + } + Proto::RawInput::InjectFakeRawInput(ri); + } + + // For keyboard actions for both methods + void RawInput::TranslateKeyboardAction(int actionCode, int& outVkCode, bool& outIsExtended) { + outVkCode = 0; + outIsExtended = false; + + // Special & Modifier Keys + if (actionCode == 1) outVkCode = VK_ESCAPE; + if (actionCode == 2) outVkCode = VK_RETURN; // Main Enter Key + if (actionCode == 3) outVkCode = VK_TAB; + if (actionCode == 4) outVkCode = VK_SHIFT; // Generic Shift + if (actionCode == 5) outVkCode = VK_LSHIFT; // Left Shift + if (actionCode == 6) outVkCode = VK_RSHIFT; // Right Shift + if (actionCode == 7) outVkCode = VK_CONTROL; // Generic Control + if (actionCode == 8) outVkCode = VK_LCONTROL; // Left Control + if (actionCode == 9) outVkCode = VK_RCONTROL; // Right Control + if (actionCode == 10) outVkCode = VK_MENU; // Generic Alt + if (actionCode == 11) outVkCode = VK_LMENU; // Left Alt + if (actionCode == 12) outVkCode = VK_RMENU; // Right Alt + if (actionCode == 13) outVkCode = VK_SPACE; + if (actionCode == 14) outVkCode = VK_UP; // Arrow Up + if (actionCode == 15) outVkCode = VK_DOWN; // Arrow Down + if (actionCode == 16) outVkCode = VK_LEFT; // Arrow Left + if (actionCode == 17) outVkCode = VK_RIGHT; // Arrow Right + if (actionCode == 18) outVkCode = VK_BACK; // Backspace + if (actionCode == 19) outVkCode = VK_DELETE; + if (actionCode == 20) outVkCode = VK_INSERT; + if (actionCode == 21) outVkCode = VK_END; + if (actionCode == 22) outVkCode = VK_HOME; + if (actionCode == 23) outVkCode = VK_PRIOR; // Page Up + if (actionCode == 24) outVkCode = VK_NEXT; // Page Down + // Alphabet + if (actionCode >= 25 && actionCode <= 50) outVkCode = 'A' + (actionCode - 25); + // Top Row Numbers + if (actionCode >= 51 && actionCode <= 60) outVkCode = '0' + (actionCode - 51); + // F-Keys + if (actionCode >= 61 && actionCode <= 72) outVkCode = VK_F1 + (actionCode - 61); + // Numpad Numbers & Operators + if (actionCode >= 73 && actionCode <= 82) outVkCode = VK_NUMPAD0 + (actionCode - 73); + if (actionCode == 83) outVkCode = VK_ADD; + if (actionCode == 84) outVkCode = VK_SUBTRACT; + if (actionCode == 85) outVkCode = VK_MULTIPLY; + if (actionCode == 86) outVkCode = VK_DIVIDE; + if (actionCode == 87) outVkCode = VK_DECIMAL; + if (actionCode == 88) outVkCode = VK_RETURN; // Numpad Enter + // Numpad Navigation (when NumLock is OFF) + if (actionCode == 91) outVkCode = VK_INSERT; // Numpad 0 + if (actionCode == 92) outVkCode = VK_END; // Numpad 1 + if (actionCode == 93) outVkCode = VK_DOWN; // Numpad 2 + if (actionCode == 94) outVkCode = VK_NEXT; // Numpad 3 + if (actionCode == 95) outVkCode = VK_LEFT; // Numpad 4 + if (actionCode == 96) outVkCode = VK_RIGHT; // Numpad 6 + if (actionCode == 97) outVkCode = VK_HOME; // Numpad 7 + if (actionCode == 98) outVkCode = VK_UP; // Numpad 8 + if (actionCode == 99) outVkCode = VK_PRIOR; // Numpad 9 + if (actionCode == 100) outVkCode = VK_DELETE; // Numpad . + // Lock Keys + if (actionCode == 101) outVkCode = VK_CAPITAL; // Caps Lock + if (actionCode == 102) outVkCode = VK_NUMLOCK; // Num Lock + if (actionCode == 103) outVkCode = VK_SCROLL; // Scroll Lock + // Symbols + if (actionCode == 104) outVkCode = VK_OEM_1; // ; (Semicolon) + if (actionCode == 105) outVkCode = VK_OEM_PLUS; // = (Plus/Equal) + if (actionCode == 106) outVkCode = VK_OEM_COMMA; // , (Comma) + if (actionCode == 107) outVkCode = VK_OEM_MINUS; // - (Minus) + if (actionCode == 108) outVkCode = VK_OEM_PERIOD; // . (Period) + if (actionCode == 109) outVkCode = VK_OEM_2; // / (Forward Slash) + if (actionCode == 110) outVkCode = VK_OEM_3; // ` (Grave Accent) + if (actionCode == 111) outVkCode = VK_OEM_4; // [ (Left Bracket) + if (actionCode == 112) outVkCode = VK_OEM_5; // \ (Backslash) + if (actionCode == 113) outVkCode = VK_OEM_6; // ] (Right Bracket) + if (actionCode == 114) outVkCode = VK_OEM_7; // ' (Apostrophe) + // Extended Keys + if ((actionCode >= 14 && actionCode <= 17) || // Dedicated Arrow Keys + (actionCode >= 19 && actionCode <= 24) || // Insert, Del, Home, End, PgUp, PgDn + actionCode == 9 || // Right Control + actionCode == 12 || // Right Alt + actionCode == 88 || // Numpad Enter + actionCode == 102) + { + outIsExtended = true; + } + } + void RawInput::SendActionDelta(int deltaX, int deltaY) + { + RAWINPUT ri = {}; + ri.header.dwType = RIM_TYPEMOUSE; + ri.header.hDevice = NULL; + ri.data.mouse.usFlags = MOUSE_MOVE_RELATIVE; + ri.data.mouse.lLastX = deltaX; + ri.data.mouse.lLastY = deltaY; + Proto::RawInput::InjectFakeRawInput(ri); + } + +} \ No newline at end of file diff --git a/src/ProtoInput/ProtoInputHooks/GtoMnK_RawInput.h b/src/ProtoInput/ProtoInputHooks/GtoMnK_RawInput.h new file mode 100644 index 0000000..283d7c4 --- /dev/null +++ b/src/ProtoInput/ProtoInputHooks/GtoMnK_RawInput.h @@ -0,0 +1,12 @@ +#pragma once +#include + +namespace ScreenshotInput { + class RawInput { + public: + static void TranslateKeyboardAction(int actionCode, int& outVkCode, bool& outIsExtended); + static void GenerateRawMouseButton(int actionCode, bool press); + static void GenerateRawKey(int vkCode, bool press, bool isExtended); + static void SendActionDelta(int deltaX, int deltaY); + }; +} \ No newline at end of file diff --git a/src/ProtoInput/ProtoInputHooks/GtoMnK_RawInputHooks.cpp b/src/ProtoInput/ProtoInputHooks/GtoMnK_RawInputHooks.cpp new file mode 100644 index 0000000..c1d6f9e --- /dev/null +++ b/src/ProtoInput/ProtoInputHooks/GtoMnK_RawInputHooks.cpp @@ -0,0 +1,25 @@ +//#include "pch.h" +#include "GtoMnK_RawInputHooks.h" +#include "RawInput.h" +#include "KeyboardButtonFilter.h" +//#include "Mouse.h" +//#include "Keyboard.h" +#include "EasyHook.h" +#include "gui.h" +// Thanks to ProtoInput. + +namespace ScreenshotInput +{ + // HOOK_TRACE_INFO g_getRawInputDataHook = { NULL }; + // HOOK_TRACE_INFO g_registerRawInputDevicesHook = { NULL }; + + // void RawInputHooks::InstallHooks() { + // // Install GetRawInputData hook + // HMODULE hUser32 = GetModuleHandleA("user32"); + // LhInstallHook(GetProcAddress(hUser32, "GetRawInputData"), GetRawInputDataHook, NULL, &g_getRawInputDataHook); + // LhInstallHook(GetProcAddress(hUser32, "RegisterRawInputDevices"), RegisterRawInputDevicesHook, NULL, &g_registerRawInputDevicesHook); + // ULONG ACLEntries[1] = { 0 }; + // LhSetExclusiveACL(ACLEntries, 1, &g_getRawInputDataHook); + // LhSetExclusiveACL(ACLEntries, 1, &g_registerRawInputDevicesHook); + // } +} \ No newline at end of file diff --git a/src/ProtoInput/ProtoInputHooks/GtoMnK_RawInputHooks.h b/src/ProtoInput/ProtoInputHooks/GtoMnK_RawInputHooks.h new file mode 100644 index 0000000..b5bd24d --- /dev/null +++ b/src/ProtoInput/ProtoInputHooks/GtoMnK_RawInputHooks.h @@ -0,0 +1,11 @@ +#pragma once +#include + +namespace ScreenshotInput { + class RawInputHooks { + public: + static UINT WINAPI GetRawInputDataHookX(HRAWINPUT hRawInput, UINT uiCommand, LPVOID pData, PUINT pcbSize, UINT cbSizeHeader); + static BOOL WINAPI RegisterRawInputDevicesHookX(PCRAWINPUTDEVICE pRawInputDevices, UINT uiNumDevices, UINT cbSize); + //static void InstallHooks(); + }; +} diff --git a/src/ProtoInput/ProtoInputHooks/Gui.cpp b/src/ProtoInput/ProtoInputHooks/Gui.cpp index 8bc1c21..b633dc9 100644 --- a/src/ProtoInput/ProtoInputHooks/Gui.cpp +++ b/src/ProtoInput/ProtoInputHooks/Gui.cpp @@ -13,12 +13,19 @@ #include "FocusMessageLoop.h" #include "StateInfo.h" #include "FakeCursor.h" +#include "TranslateXtoMKB.h" +#include "ScanThread.h" +#include "GtoMnK_RawInput.h" +#include "XinputHook.h" +#include "WindowMsgHook.h" + namespace Proto { - intptr_t ConsoleHwnd; +bool PointerInMouseold = false; + static void HelpMarker(const char* desc) { ImGui::TextDisabled("(?)"); @@ -85,7 +92,611 @@ void HandleSelectableDualList(std::vector& selected, std::vector& deselect for (const auto x : removeB) deselected.erase(x); } +std::string VkToKeyName(int vk) +{ + + UINT scan = MapVirtualKey(vk, MAPVK_VK_TO_VSC); + UINT flags = scan << 16; + + // Add extended-key flag when needed + switch (vk) + { + case VK_LEFT: + case VK_RIGHT: + case VK_UP: + case VK_DOWN: + case VK_INSERT: + case VK_DELETE: + case VK_HOME: + case VK_END: + case VK_PRIOR: // Page Up + case VK_NEXT: // Page Down + case VK_RCONTROL: + case VK_RMENU: // Right Alt + case VK_DIVIDE: + case VK_NUMLOCK: + flags |= (1 << 24); + break; + } + + char name[64] = { 0 }; + GetKeyNameTextA(flags, name, sizeof(name)); + return std::string(name); +} +bool mappingrefreshed = false; +USHORT X_A; +USHORT X_B; +USHORT X_X; +USHORT X_Y; + +USHORT X_RS; +USHORT X_LS; +USHORT X_right; +USHORT X_left; +USHORT X_up; +USHORT X_down; + +USHORT X_stickLpress; +USHORT X_stickRpress; +USHORT X_stickright; +USHORT X_stickleft; +USHORT X_stickup; +USHORT X_stickdown; + +USHORT X_option; +USHORT X_start; +//bool + + + +int lastVKkey; +void XTranslatefreshmapping(bool read) { + if (read) { + //collision danger if remote read each frame + X_A = ScreenshotInput::TranslateXtoMKB::Amapping; + X_B = ScreenshotInput::TranslateXtoMKB::Bmapping; + X_X = ScreenshotInput::TranslateXtoMKB::Xmapping; + X_Y = ScreenshotInput::TranslateXtoMKB::Ymapping; + + X_RS = ScreenshotInput::TranslateXtoMKB::RSmapping; + X_LS = ScreenshotInput::TranslateXtoMKB::LSmapping; + X_right = ScreenshotInput::TranslateXtoMKB::rightmapping; + X_left = ScreenshotInput::TranslateXtoMKB::leftmapping; + X_up = ScreenshotInput::TranslateXtoMKB::upmapping; + X_down = ScreenshotInput::TranslateXtoMKB::downmapping; + + X_stickRpress = ScreenshotInput::TranslateXtoMKB::stickRpressmapping; + X_stickLpress = ScreenshotInput::TranslateXtoMKB::stickLpressmapping; + X_stickright = ScreenshotInput::TranslateXtoMKB::stickrightmapping; + X_stickleft = ScreenshotInput::TranslateXtoMKB::stickleftmapping; + X_stickup = ScreenshotInput::TranslateXtoMKB::stickupmapping; + X_stickdown = ScreenshotInput::TranslateXtoMKB::stickdownmapping; + + X_option = ScreenshotInput::TranslateXtoMKB::optionmapping; + X_start = ScreenshotInput::TranslateXtoMKB::startmapping; + X_stickdown = ScreenshotInput::TranslateXtoMKB::stickdownmapping; + }//ImGui::SliderFloat("Slider", &sliderValue, 0.0f, 1.0f); + +} +void GetVK() +{ + BYTE keys[256]; + GetKeyboardState(keys); + for (int vk = 0; vk < 256; vk++) + { + if (keys[vk] & 0x80) + { + lastVKkey = vk; + return; + } + } +} + +void XTranslateMenu() +{ + if (!mappingrefreshed) + XTranslatefreshmapping(true); + + ImGui::SliderInt("Sensitivity flat", (int*)&ScreenshotInput::TranslateXtoMKB::Sens, 1, 40, "%d", ImGuiSliderFlags_AlwaysClamp); + ImGui::Separator(); + ImGui::SliderInt("Sensitivity exponential", (int*)&ScreenshotInput::TranslateXtoMKB::Sensmult, 1, 20, "%d", ImGuiSliderFlags_AlwaysClamp); + ImGui::Separator(); + ImGui::SliderInt("Deadzone", (int*)&ScreenshotInput::TranslateXtoMKB::Deadzone, 0, 20, "%d", ImGuiSliderFlags_AlwaysClamp); + ImGui::Separator(); + { + const auto XAString = VkToKeyName(X_A); + ImGui::TextWrapped("A is mapped to: %s", (XAString.c_str())); + + static bool waitingKeyPressA = false; + + if (waitingKeyPressA) + { + //PushDisabled(); + GetVK(); + ImGui::Button("Press Keyboard button...##A"); //these need unique IDs or text + //PopDisabled(); + // Sleep(100); + if (lastVKkey != -1) + { + waitingKeyPressA = false; + X_A = lastVKkey; + ScreenshotInput::TranslateXtoMKB::Amapping = X_A; + } + } + + else if (ImGui::Button("Click to change##A1"))//these need unique IDs or text + { + waitingKeyPressA = true; + lastVKkey = -1; + } + } + ImGui::Separator(); + { + const auto XBString = VkToKeyName(X_B); + ImGui::TextWrapped("B is mapped to: %s", (XBString.c_str())); + + static bool waitingKeyPressB = false; + if (waitingKeyPressB) + { + //PushDisabled(); + ImGui::Button("Press Keyboard button...##B"); //these need unique IDs or text + GetVK(); + //PopDisabled(); + // Sleep(100); + if (lastVKkey != -1) + { + waitingKeyPressB = false; + X_B = lastVKkey; + ScreenshotInput::TranslateXtoMKB::Bmapping = X_B; + } + } + else if (ImGui::Button("Click to change##B1"))//these need unique IDs or text + { + waitingKeyPressB = true; + lastVKkey = -1; + } + } + ImGui::Separator(); + { + const auto XXString = VkToKeyName(X_X); + ImGui::TextWrapped("X is mapped to: %s", (XXString.c_str())); + + static bool waitingKeyPressX = false; + if (waitingKeyPressX) + { + //PushDisabled(); + ImGui::Button("Press Keyboard button...##X"); //these need unique IDs or text + GetVK(); + //PopDisabled(); + // Sleep(100); + if (lastVKkey != -1) + { + waitingKeyPressX = false; + X_X = lastVKkey; + ScreenshotInput::TranslateXtoMKB::Xmapping = X_X; + } + } + else if (ImGui::Button("Click to change##X1"))//these need unique IDs or text + { + waitingKeyPressX = true; + lastVKkey = -1; + } + } + ImGui::Separator(); + { + const auto XYString = VkToKeyName(X_Y); + ImGui::TextWrapped("Y is mapped to: %s", (XYString.c_str())); + + static bool waitingKeyPressY = false; + if (waitingKeyPressY) + { + //PushDisabled(); + ImGui::Button("Press Keyboard button...##Y"); //these need unique IDs or text + GetVK(); + //PopDisabled(); + // Sleep(100); + if (lastVKkey != -1) + { + waitingKeyPressY = false; + X_Y = lastVKkey; + ScreenshotInput::TranslateXtoMKB::Ymapping = X_Y; + } + } + else if (ImGui::Button("Click to change##Y1"))//these need unique IDs or text + { + waitingKeyPressY = true; + lastVKkey = -1; + } + } + ImGui::Separator(); + { + const auto XRSString = VkToKeyName(X_RS); + ImGui::TextWrapped("Right Shoulder is mapped to: %s", (XRSString.c_str())); + + static bool waitingKeyPressRS = false; + if (waitingKeyPressRS) + { + //PushDisabled(); + ImGui::Button("Press Keyboard button...##RS"); //these need unique IDs or text + GetVK(); + //PopDisabled(); + // Sleep(100); + if (lastVKkey != -1) + { + waitingKeyPressRS = false; + X_RS = lastVKkey; + ScreenshotInput::TranslateXtoMKB::RSmapping = X_RS; + } + } + else if (ImGui::Button("Click to change##RS1"))//these need unique IDs or text + { + waitingKeyPressRS = true; + lastVKkey = -1; + } + } + ImGui::Separator(); + { + const auto XLSString = VkToKeyName(X_LS); + ImGui::TextWrapped("Left Shoulder is mapped to: %s", (XLSString.c_str())); + + static bool waitingKeyPressLS = false; + if (waitingKeyPressLS) + { + //PushDisabled(); + ImGui::Button("Press Keyboard button...##LS"); //these need unique IDs or text + GetVK(); + //PopDisabled(); + // Sleep(100); + if (lastVKkey != -1) + { + waitingKeyPressLS = false; + X_LS = lastVKkey; + ScreenshotInput::TranslateXtoMKB::LSmapping = X_LS; + } + } + else if (ImGui::Button("Click to change##LS1"))//these need unique IDs or text + { + waitingKeyPressLS = true; + lastVKkey = -1; + } + } + ImGui::Separator(); + { + const auto XrightString = VkToKeyName(X_right); + ImGui::TextWrapped("DPAD right is mapped to: %s", (XrightString.c_str())); + + static bool waitingKeyPressright = false; + if (waitingKeyPressright) + { + //PushDisabled(); + ImGui::Button("Press Keyboard button...##DR"); //these need unique IDs or text + GetVK(); + //PopDisabled(); + // Sleep(100); + if (lastVKkey != -1) + { + waitingKeyPressright = false; + X_right = lastVKkey; + ScreenshotInput::TranslateXtoMKB::rightmapping = X_right; + } + } + else if (ImGui::Button("Click to change##DR1"))//these need unique IDs or text + { + waitingKeyPressright = true; + lastVKkey = -1; + } + } + ImGui::Separator(); + { + const auto XleftString = VkToKeyName(X_left); + ImGui::TextWrapped("DPAD left is mapped to: %s", (XleftString.c_str())); + + static bool waitingKeyPressleft = false; + if (waitingKeyPressleft) + { + //PushDisabled(); + ImGui::Button("Press Keyboard button...##DL"); //these need unique IDs or text + GetVK(); + //PopDisabled(); + // Sleep(100); + if (lastVKkey != -1) + { + waitingKeyPressleft = false; + X_left = lastVKkey; + ScreenshotInput::TranslateXtoMKB::leftmapping = X_left; + } + } + else if (ImGui::Button("Click to change##DL1"))//these need unique IDs or text + { + waitingKeyPressleft = true; + lastVKkey = -1; + } + } + + ImGui::Separator(); + { + const auto XupString = VkToKeyName(X_up); + ImGui::TextWrapped("DPAD up is mapped to: %s", (XupString.c_str())); + + static bool waitingKeyPressup = false; + if (waitingKeyPressup) + { + //PushDisabled(); + ImGui::Button("Press Keyboard button...##DU"); //these need unique IDs or text + GetVK(); + //PopDisabled(); + // Sleep(100); + if (lastVKkey != -1) + { + waitingKeyPressup = false; + X_up = lastVKkey; + ScreenshotInput::TranslateXtoMKB::upmapping = X_up; + } + } + else if (ImGui::Button("Click to change##DU1"))//these need unique IDs or text + { + waitingKeyPressup = true; + lastVKkey = -1; + } + } + ImGui::Separator(); + { + const auto XdownString = VkToKeyName(X_down); + ImGui::TextWrapped("DPAD down is mapped to: %s", (XdownString.c_str())); + + static bool waitingKeyPressdown = false; + if (waitingKeyPressdown) + { + //PushDisabled(); + ImGui::Button("Press Keyboard button...##DD"); //these need unique IDs or text + GetVK(); + //PopDisabled(); + // Sleep(100); + if (lastVKkey != -1) + { + waitingKeyPressdown = false; + X_down = lastVKkey; + ScreenshotInput::TranslateXtoMKB::downmapping = X_down; + } + } + else if (ImGui::Button("Click to change##DD1"))//these need unique IDs or text + { + waitingKeyPressdown = true; + lastVKkey = -1; + } + } + ImGui::Separator(); + { + const auto XstickRpressString = VkToKeyName(X_stickRpress); + ImGui::TextWrapped("Right stick press is mapped to: %s", (XstickRpressString.c_str())); + + static bool waitingKeyPressstickRpress = false; + if (waitingKeyPressstickRpress) + { + //PushDisabled(); + ImGui::Button("Press Keyboard button...##RSP"); //these need unique IDs or text + GetVK(); + //PopDisabled(); + // Sleep(100); + if (lastVKkey != -1) + { + waitingKeyPressstickRpress = false; + X_stickRpress = lastVKkey; + ScreenshotInput::TranslateXtoMKB::stickRpressmapping = X_stickRpress; + } + } + else if (ImGui::Button("Click to change##RSP1"))//these need unique IDs or text + { + waitingKeyPressstickRpress = true; + lastVKkey = -1; + } + } + ImGui::Separator(); + { + const auto XstickLpressString = VkToKeyName(X_stickLpress); + ImGui::TextWrapped("left stick press is mapped to: %s", (XstickLpressString.c_str())); + static bool waitingKeyPressstickLpress = false; + if (waitingKeyPressstickLpress) + { + //PushDisabled(); + ImGui::Button("Press Keyboard button...##LSP"); //these need unique IDs or text + GetVK(); + //PopDisabled(); + // Sleep(100); + if (lastVKkey != -1) + { + waitingKeyPressstickLpress = false; + X_stickLpress = lastVKkey; + ScreenshotInput::TranslateXtoMKB::stickLpressmapping = X_stickLpress; + } + } + else if (ImGui::Button("Click to change##LSP1"))//these need unique IDs or text + { + waitingKeyPressstickLpress = true; + lastVKkey = -1; + } + } + ImGui::Separator(); + { + const auto XstickrightString = VkToKeyName(X_stickright); + ImGui::TextWrapped("Stick right axis is mapped to: %s", (XstickrightString.c_str())); + + static bool waitingKeyPressstickright = false; + if (waitingKeyPressstickright) + { + //PushDisabled(); + ImGui::Button("Press Keyboard button...##SRA"); //these need unique IDs or text + GetVK(); + //PopDisabled(); + // Sleep(100); + if (lastVKkey != -1) + { + waitingKeyPressstickright = false; + X_stickright = lastVKkey; + ScreenshotInput::TranslateXtoMKB::stickrightmapping = X_stickright; + } + } + else if (ImGui::Button("Click to change##SRA1"))//these need unique IDs or text + { + waitingKeyPressstickright = true; + lastVKkey = -1; + } + } + ImGui::Separator(); + { + const auto XstickleftString = VkToKeyName(X_stickleft); + ImGui::TextWrapped("Stick left axis is mapped to: %s", (XstickleftString.c_str())); + + static bool waitingKeyPressstickleft = false; + if (waitingKeyPressstickleft) + { + //PushDisabled(); + ImGui::Button("Press Keyboard button...##SLA"); //these need unique IDs or text + GetVK(); + //PopDisabled(); + // Sleep(100); + if (lastVKkey != -1) + { + waitingKeyPressstickleft = false; + X_stickleft = lastVKkey; + ScreenshotInput::TranslateXtoMKB::stickleftmapping = X_stickleft; + } + } + else if (ImGui::Button("Click to change##SLA1"))//these need unique IDs or text + { + waitingKeyPressstickleft = true; + lastVKkey = -1; + } + } + ImGui::Separator(); + { + const auto XstickupString = VkToKeyName(X_stickup); + ImGui::TextWrapped("Stick up axis is mapped to: %s", (XstickupString.c_str())); + + static bool waitingKeyPressstickup = false; + if (waitingKeyPressstickup) + { + //PushDisabled(); + ImGui::Button("Press Keyboard button...##SUA"); //these need unique IDs or text + GetVK(); + //PopDisabled(); + // Sleep(100); + if (lastVKkey != -1) + { + waitingKeyPressstickup = false; + X_stickup = lastVKkey; + ScreenshotInput::TranslateXtoMKB::stickupmapping = X_stickup; + } + } + else if (ImGui::Button("Click to change##SUA1"))//these need unique IDs or text + { + waitingKeyPressstickup = true; + lastVKkey = -1; + } + } + ImGui::Separator(); + { + const auto XstickdownString = VkToKeyName(X_stickdown); + ImGui::TextWrapped("Stick down axis is mapped to: %s", (XstickdownString.c_str())); + + static bool waitingKeyPressstickdown = false; + if (waitingKeyPressstickdown) + { + //PushDisabled(); + ImGui::Button("Press Keyboard button...##SDA"); //these need unique IDs or text + GetVK(); + //PopDisabled(); + // Sleep(100); + if (lastVKkey != -1) + { + waitingKeyPressstickdown = false; + X_stickdown = lastVKkey; + ScreenshotInput::TranslateXtoMKB::stickdownmapping = X_stickdown; + } + } + else if (ImGui::Button("Click to change##SDA1"))//these need unique IDs or text + { + waitingKeyPressstickdown = true; + lastVKkey = -1; + } + } + ImGui::Separator(); + { + const auto XoptionString = VkToKeyName(X_option); + ImGui::TextWrapped("Options button is mapped to: %s", (XoptionString.c_str())); + + static bool waitingKeyPressoption = false; + if (waitingKeyPressoption) + { + //PushDisabled(); + ImGui::Button("Press Keyboard button...##OPT"); //these need unique IDs or text + GetVK(); + //PopDisabled(); + // Sleep(100); + if (lastVKkey != -1) + { + waitingKeyPressoption = false; + X_option = lastVKkey; + ScreenshotInput::TranslateXtoMKB::optionmapping = X_option; + } + } + else if (ImGui::Button("Click to change##OPT1"))//these need unique IDs or text + { + waitingKeyPressoption = true; + lastVKkey = -1; + } + } + ImGui::Separator(); + { + const auto XstartString = VkToKeyName(X_start); + ImGui::TextWrapped("Start button is mapped to: %s", (XstartString.c_str())); + + static bool waitingKeyPressstart = false; + if (waitingKeyPressstart) + { + //PushDisabled(); + ImGui::Button("Press Keyboard button...##STA"); //these need unique IDs or text + GetVK(); + //PopDisabled(); + // Sleep(100); + if (lastVKkey != -1) + { + waitingKeyPressstart = false; + X_start = lastVKkey; + ScreenshotInput::TranslateXtoMKB::startmapping = X_start; + } + } + else if (ImGui::Button("Click to change##STA1"))//these need unique IDs or text + { + waitingKeyPressstart = true; + lastVKkey = -1; + } + } + ImGui::Separator(); //no idea if this may crash. suppose it is not safe + ImGui::Checkbox("Lefthanded Stick. moves mouse with left stick and button map on right stick. or opposite if disabled", &ScreenshotInput::TranslateXtoMKB::lefthanded); // + ImGui::Separator(); + ImGui::Separator(); + if (RawInput::TranslateXinputtoMKB) + { + ImGui::Checkbox("Shoulder Swap BMPs", &ScreenshotInput::ScanThread::ShoulderNextBMP); // + ImGui::Separator(); + ImGui::Text("Input actions for Scanoption. 0 is move+click. 1 is only move. 2 is only click"); + ImGui::SliderInt("A coordinate", (int*)&ScreenshotInput::ScanThread::scanAtype, 0, 2, "%d", ImGuiSliderFlags_AlwaysClamp); + ImGui::SliderInt("B coordinate", (int*)&ScreenshotInput::ScanThread::scanBtype, 0, 2, "%d", ImGuiSliderFlags_AlwaysClamp); + ImGui::SliderInt("X coordinate", (int*)&ScreenshotInput::ScanThread::scanXtype, 0, 2, "%d", ImGuiSliderFlags_AlwaysClamp); + ImGui::SliderInt("Y coordinate", (int*)&ScreenshotInput::ScanThread::scanYtype, 0, 2, "%d", ImGuiSliderFlags_AlwaysClamp); + ImGui::Separator(); + ImGui::Text("Save BMP mode. buttons XYAB will save a bmp on press at fake cursor coordinate when enabled. This option also force ScanOption to deactivate"); + ImGui::Checkbox("Save BMP mode:", &ScreenshotInput::TranslateXtoMKB::SaveBmps); // + ImGui::Separator(); + ImGui::Text("Scanoption will need a restart to discover new bmps."); + ImGui::Checkbox("ScanOption:", &ScreenshotInput::ScanThread::scanoption); // + ImGui::Separator(); + if (!ScreenshotInput::ScanThread::scanoption) + ScreenshotInput::ScanThread::scanloop = false; + } +} void HooksMenu() { const auto& hooks = HookManager::GetHooks(); @@ -174,8 +785,18 @@ void RawInputMenu() "Use this when debugging/scripting so you don't accidentally control the game changing the GUI settings. "); ImGui::Separator(); - - + + //this enough to prevent both en enabled? + if (!XinputHook::TranslateMKBtoXinput) + ImGui::Checkbox("TranslateXtoMKB", &RawInput::TranslateXinputtoMKB); + ImGui::Separator(); + if (!RawInput::TranslateXinputtoMKB) + ImGui::Checkbox("TranslateMKBtoX", &XinputHook::TranslateMKBtoXinput); + ImGui::Separator(); + if (RawInput::TranslateXinputtoMKB && XinputHook::TranslateMKBtoXinput) + RawInput::TranslateXinputtoMKB = false; + RawInput::TranslateXinputtoMKB2 = RawInput::TranslateXinputtoMKB; + bool showFakeCursor = FakeCursor::IsDrawingEnabled(); if (ImGui::Checkbox("Draw fake cursor", &showFakeCursor)) { @@ -202,7 +823,12 @@ void RawInputMenu() ImGui::InputInt("Toggle visibility keyboard VKey", (int*)&FakeCursor::GetToggleVisibilityVkey(), 1, 100); ImGui::Separator(); - + + ImGui::Checkbox("Translate mouse messages to Pointermessages", &RawInput::PointerInMouse); + + if (PointerInMouseold != RawInput::PointerInMouse) + WindowMsgHook::PointerInMouse(RawInput::PointerInMouse); + PointerInMouseold = RawInput::PointerInMouse; ImGui::Checkbox("Send mouse movement messages", &RawInput::rawInputState.sendMouseMoveMessages); ImGui::Checkbox("Send mouse button messages", &RawInput::rawInputState.sendMouseButtonMessages); ImGui::Checkbox("Send mouse wheel messages", &RawInput::rawInputState.sendMouseWheelMessages); @@ -211,28 +837,40 @@ void RawInputMenu() ImGui::Separator(); - if (ImGui::TreeNode("Selected mouse devices")) + + + if (RawInput::TranslateXinputtoMKB) //TranslateXisenabled { - HandleSelectableDualList(RawInput::rawInputState.selectedMouseHandles, RawInput::rawInputState.deselectedMouseHandles); - - ImGui::TreePop(); + + ImGui::TextWrapped("XinputtoMKB ControllerID"); + ImGui::TextWrapped("0 is first controller"); + ImGui::SliderInt("XinputtoMKB ControllerID", (int*)&ScreenshotInput::TranslateXtoMKB::controllerID, 0, 16, "%d", ImGuiSliderFlags_AlwaysClamp); } - - if (ImGui::TreeNode("Selected keyboard devices")) + else { - HandleSelectableDualList(RawInput::rawInputState.selectedKeyboardHandles, RawInput::rawInputState.deselectedKeyboardHandles); + if (ImGui::TreeNode("Selected mouse devices")) + { + HandleSelectableDualList(RawInput::rawInputState.selectedMouseHandles, RawInput::rawInputState.deselectedMouseHandles); - ImGui::TreePop(); - } + ImGui::TreePop(); + } - if (ImGui::Button("Refresh devices")) - { - RawInput::RefreshDevices(); + if (ImGui::TreeNode("Selected keyboard devices")) + { + HandleSelectableDualList(RawInput::rawInputState.selectedKeyboardHandles, RawInput::rawInputState.deselectedKeyboardHandles); + + ImGui::TreePop(); + } + if (ImGui::Button("Refresh devices")) + { + RawInput::RefreshDevices(); + } } + } void ControlsMenu() -{ +{ if (ImGui::Button("Hide GUI")) { SetWindowVisible(false); @@ -288,7 +926,6 @@ void RenderImgui() { // ImGui::ShowDemoWindow(); // return; - const auto displaySize = ImGui::GetIO().DisplaySize; ImGui::SetNextWindowPos(ImVec2(0, 0), ImGuiCond_Always); @@ -322,6 +959,15 @@ void RenderImgui() HooksMenu(); ImGui::EndTabItem(); } + if (RawInput::TranslateXinputtoMKB || XinputHook::TranslateMKBtoXinput) + { + if (ImGui::BeginTabItem("Translation options")) + { + XTranslateMenu(); + ImGui::EndTabItem(); + } + } + if (ImGui::BeginTabItem("Message filter")) { if (ImGui::BeginTabBar("Filter tabs")) @@ -408,5 +1054,24 @@ void RenderImgui() } ImGui::End(); } +DWORD WINAPI GuiThread(LPVOID lpParameter) +{ + std::cout << "Starting gui thread\n"; + + Proto::AddThreadToACL(GetCurrentThreadId()); + + Proto::ShowGuiImpl(); + + return 0; +} +void StartGUIThread() +{ + HANDLE hGuiThread = CreateThread(nullptr, 0, + (LPTHREAD_START_ROUTINE)GuiThread, Proto::hmodule, CREATE_SUSPENDED, &Proto::GuiThreadID); + ResumeThread(hGuiThread); + + if (hGuiThread != nullptr) + CloseHandle(hGuiThread); +} } diff --git a/src/ProtoInput/ProtoInputHooks/Gui.h b/src/ProtoInput/ProtoInputHooks/Gui.h index 2523157..4e1f0ae 100644 --- a/src/ProtoInput/ProtoInputHooks/Gui.h +++ b/src/ProtoInput/ProtoInputHooks/Gui.h @@ -8,11 +8,14 @@ namespace Proto extern unsigned long GuiThreadID; extern intptr_t ConsoleHwnd; extern HWND ProtoGuiHwnd; +extern HMODULE hmodule; + +void Start(); int ShowGuiImpl(); void RenderImgui(); - +void StartGUIThread(); void ToggleWindow(); void SetWindowVisible(bool visible); diff --git a/src/ProtoInput/ProtoInputHooks/GuiImpl.cpp b/src/ProtoInput/ProtoInputHooks/GuiImpl.cpp index 473fd36..ad50830 100644 --- a/src/ProtoInput/ProtoInputHooks/GuiImpl.cpp +++ b/src/ProtoInput/ProtoInputHooks/GuiImpl.cpp @@ -12,6 +12,7 @@ #include "FontData.h" #include "Cleanup.h" +bool guithreadstarted = false; //TODO: default to hidden constexpr bool defaultGuiToHidden = true; constexpr bool defaultConsoleToHidden = true; @@ -123,6 +124,12 @@ void Proto::ToggleWindow() void Proto::SetWindowVisible(bool visible) { + if (!guithreadstarted) + { + StartGUIThread(); + guithreadstarted = true; + Sleep(100); + } RawInput::rawInputState.guiOpened = visible; ShowWindow(ProtoGuiHwnd, visible ? SW_SHOW : SW_HIDE); } diff --git a/src/ProtoInput/ProtoInputHooks/HookManager.cpp b/src/ProtoInput/ProtoInputHooks/HookManager.cpp index 7570030..ba63279 100644 --- a/src/ProtoInput/ProtoInputHooks/HookManager.cpp +++ b/src/ProtoInput/ProtoInputHooks/HookManager.cpp @@ -21,6 +21,9 @@ #include "MoveWindowHook.h" #include "AdjustWindowRectHook.h" #include "RemoveBorderHook.h" +#include "GetCursorInfoHook.h" +#include "RawInput.h" +#include "TranslateXtoMKB.h" namespace Proto { @@ -30,32 +33,34 @@ HookManager HookManager::hookManagerInstance{}; HookManager::HookManager() { // Do these in exactly the same order as in ProtoHookIDs - AddHook(ProtoHookIDs::RegisterRawInputHookID); - AddHook(ProtoHookIDs::GetRawInputDataHookID); - AddHook(ProtoHookIDs::MessageFilterHookID); - AddHook(ProtoHookIDs::GetCursorPosHookID); - AddHook(ProtoHookIDs::SetCursorPosHookID); - AddHook(ProtoHookIDs::GetKeyStateHookID); - AddHook(ProtoHookIDs::GetAsyncKeyStateHookID); - AddHook(ProtoHookIDs::GetKeyboardStateHookID); - AddHook(ProtoHookIDs::CursorVisibilityStateHookID); - AddHook(ProtoHookIDs::ClipCursorHookID); - AddHook(ProtoHookIDs::FocusHooksHookID); - AddHook(ProtoHookIDs::RenameHandlesHookID); - AddHook(ProtoHookIDs::XinputHookID); - AddHook(ProtoHookIDs::DinputOrderHookID); - AddHook(ProtoHookIDs::SetWindowPosHookID); - AddHook(ProtoHookIDs::BlockRawInputHookID); - AddHook(ProtoHookIDs::FindWindowHookID); - AddHook(ProtoHookIDs::CreateSingleHIDHookID); - AddHook(ProtoHookIDs::WindowStyleHookID); - AddHook(ProtoHookIDs::MoveWindowHookID); - AddHook(ProtoHookIDs::AdjustWindowRectHookID); - AddHook(ProtoHookIDs::RemoveBorderHookID); + AddHook(ProtoHookIDs::RegisterRawInputHookID); //0 + AddHook(ProtoHookIDs::GetRawInputDataHookID); //1 + AddHook(ProtoHookIDs::MessageFilterHookID);//2 + AddHook(ProtoHookIDs::GetCursorPosHookID);//3 + AddHook(ProtoHookIDs::SetCursorPosHookID);//4 + AddHook(ProtoHookIDs::GetKeyStateHookID);//5 + AddHook(ProtoHookIDs::GetAsyncKeyStateHookID);//6 + AddHook(ProtoHookIDs::GetKeyboardStateHookID);//7 + AddHook(ProtoHookIDs::CursorVisibilityStateHookID);//8 + AddHook(ProtoHookIDs::ClipCursorHookID);//9 + AddHook(ProtoHookIDs::FocusHooksHookID);//10 + AddHook(ProtoHookIDs::RenameHandlesHookID);//11 + AddHook(ProtoHookIDs::XinputHookID);//12 + AddHook(ProtoHookIDs::DinputOrderHookID);//13 + AddHook(ProtoHookIDs::SetWindowPosHookID);//14 + AddHook(ProtoHookIDs::BlockRawInputHookID);//15 + AddHook(ProtoHookIDs::FindWindowHookID);//16 + AddHook(ProtoHookIDs::CreateSingleHIDHookID);//17 + AddHook(ProtoHookIDs::WindowStyleHookID);//18 + AddHook(ProtoHookIDs::MoveWindowHookID);//19 + AddHook(ProtoHookIDs::AdjustWindowRectHookID);//20 + AddHook(ProtoHookIDs::RemoveBorderHookID);//21 + AddHook(ProtoHookIDs::GetCursorInfoHookID);//22 } void HookManager::InstallHook(ProtoHookIDs hookID) { + if (hookID < 0 || hookID >= hookManagerInstance.hooks.size()) std::cerr << "Trying to install hook ID " << hookID << " which is out of range" << std::endl; else diff --git a/src/ProtoInput/ProtoInputHooks/HwndSelector.cpp b/src/ProtoInput/ProtoInputHooks/HwndSelector.cpp index ab38d6a..c94e8e8 100644 --- a/src/ProtoInput/ProtoInputHooks/HwndSelector.cpp +++ b/src/ProtoInput/ProtoInputHooks/HwndSelector.cpp @@ -7,78 +7,85 @@ namespace Proto { -intptr_t HwndSelector::selectedHwnd = 0; -int HwndSelector::windowWidth, HwndSelector::windowHeight; + intptr_t HwndSelector::selectedHwnd = 0; + int HwndSelector::windowWidth, HwndSelector::windowHeight; -struct HandleData -{ - unsigned long pid; - HWND hwnd; -}; + bool HwndSelector::RemoteHwndEnabled = false; -BOOL IsMainWindow(HWND handle) -{ - // Is top level & visible & not one of ours - return - GetWindow(handle, GW_OWNER) == (HWND)0 && - IsWindowVisible(handle) && - handle != (HWND)Proto::ConsoleHwnd && - handle != Proto::ProtoGuiHwnd && - handle != FakeCursor::GetPointerWindow(); -} - -BOOL CALLBACK EnumWindowsCallback(HWND handle, LPARAM lParam) -{ - HandleData& data = *(HandleData*)lParam; - - DWORD pid = 0; - GetWindowThreadProcessId(handle, &pid); - - if (data.pid != pid || !IsMainWindow(handle)) - return TRUE; // Keep searching - - data.hwnd = handle; - - return FALSE; -} - -void HwndSelector::UpdateMainHwnd(bool logOutput) -{ - // Go through all the top level windows, select the first that's visible & belongs to the process - - HandleData data { GetCurrentProcessId(), nullptr }; - EnumWindows(EnumWindowsCallback, (LPARAM)&data); + struct HandleData + { + unsigned long pid; + HWND hwnd; + }; - const auto hwnd = (intptr_t)data.hwnd; + BOOL IsMainWindow(HWND handle) + { + // Is top level & visible & not one of ours + return + GetWindow(handle, GW_OWNER) == (HWND)0 && + IsWindowVisible(handle) && + handle != (HWND)Proto::ConsoleHwnd && + handle != Proto::ProtoGuiHwnd && + handle != FakeCursor::GetPointerWindow(); + } - if (logOutput) + BOOL CALLBACK EnumWindowsCallback(HWND handle, LPARAM lParam) { - if (hwnd == 0) - printf("Warning: UpdateMainHwnd didn't find a main window\n"); - else - printf("UpdateMainHwnd found hwnd %d (0x%X)\n", hwnd, hwnd); + HandleData& data = *(HandleData*)lParam; + + DWORD pid = 0; + GetWindowThreadProcessId(handle, &pid); + + if (data.pid != pid || !IsMainWindow(handle)) + return TRUE; // Keep searching + + data.hwnd = handle; + + return FALSE; } - - if (data.hwnd != nullptr) - selectedHwnd = (intptr_t)data.hwnd; -} -void HwndSelector::UpdateWindowBounds() -{ - RECT rect; - if (GetClientRect((HWND)selectedHwnd, &rect)) + void HwndSelector::UpdateMainHwnd(bool logOutput) { - windowWidth = rect.right - rect.left; - windowHeight = rect.bottom - rect.top; + // Go through all the top level windows, select the first that's visible & belongs to the process + if (HwndSelector::RemoteHwndEnabled) + { + if (logOutput) + printf("Remote hwnd enabled, skipping search for main window\n"); + return; + } + HandleData data{ GetCurrentProcessId(), nullptr }; + EnumWindows(EnumWindowsCallback, (LPARAM)&data); + + const auto hwnd = (intptr_t)data.hwnd; + + if (logOutput) + { + if (hwnd == 0) + printf("Warning: UpdateMainHwnd didn't find a main window\n"); + else + printf("UpdateMainHwnd found hwnd %d (0x%X)\n", hwnd, hwnd); + } + + if (data.hwnd != nullptr) + selectedHwnd = (intptr_t)data.hwnd; } - else - fprintf(stderr, "GetClientRect failed in update main window bounds\n"); -} -void HwndSelector::SetSelectedHwnd(intptr_t set) -{ - selectedHwnd = set; - UpdateWindowBounds(); -} + void HwndSelector::UpdateWindowBounds() + { + RECT rect; + if (GetClientRect((HWND)selectedHwnd, &rect)) + { + windowWidth = rect.right - rect.left; + windowHeight = rect.bottom - rect.top; + } + else + fprintf(stderr, "GetClientRect failed in update main window bounds\n"); + } + + void HwndSelector::SetSelectedHwnd(intptr_t set) + { + selectedHwnd = set; + UpdateWindowBounds(); + } -} +} \ No newline at end of file diff --git a/src/ProtoInput/ProtoInputHooks/HwndSelector.h b/src/ProtoInput/ProtoInputHooks/HwndSelector.h index 70f42a2..73f0a28 100644 --- a/src/ProtoInput/ProtoInputHooks/HwndSelector.h +++ b/src/ProtoInput/ProtoInputHooks/HwndSelector.h @@ -16,6 +16,7 @@ class HwndSelector static void SetSelectedHwnd(intptr_t set); static void UpdateMainHwnd(bool logOutput = true); static void UpdateWindowBounds(); + static bool RemoteHwndEnabled; }; } diff --git a/src/ProtoInput/ProtoInputHooks/MoveWindowHook.cpp b/src/ProtoInput/ProtoInputHooks/MoveWindowHook.cpp index 6754377..a4621a2 100644 --- a/src/ProtoInput/ProtoInputHooks/MoveWindowHook.cpp +++ b/src/ProtoInput/ProtoInputHooks/MoveWindowHook.cpp @@ -1,5 +1,6 @@ #include "MoveWindowHook.h" #include +#include "HwndSelector.h" namespace Proto { @@ -33,6 +34,15 @@ namespace Proto ImGui::SliderInt2("Size", &size[0], 0, 5000); width = size[0]; height = size[1]; + + ImGui::Checkbox("Dont Resize", &MoveWindowHook::MoveWindowDontResize); + ImGui::Checkbox("Dont Resposition", &MoveWindowHook::MoveWindowDontReposition); + + if (ImGui::Button("Set Position"))//these need unique IDs or text + { + Hook_MoveWindow((HWND)HwndSelector::GetSelectedHwnd(), 0, 0, 0, 0, TRUE); + } + } void MoveWindowHook::InstallImpl() diff --git a/src/ProtoInput/ProtoInputHooks/MoveWindowHook.h b/src/ProtoInput/ProtoInputHooks/MoveWindowHook.h index 0e8d913..57d15da 100644 --- a/src/ProtoInput/ProtoInputHooks/MoveWindowHook.h +++ b/src/ProtoInput/ProtoInputHooks/MoveWindowHook.h @@ -25,7 +25,7 @@ namespace Proto return "When the game tries to reposition/resize its game window, this hook forces it to a fixed position and size. "; } - bool HasGuiStatus() const override { return false; } + bool HasGuiStatus() const override { return true; } void ShowGuiStatus() override; void InstallImpl() override; void UninstallImpl() override; diff --git a/src/ProtoInput/ProtoInputHooks/PipeCommunication.cpp b/src/ProtoInput/ProtoInputHooks/PipeCommunication.cpp index 4904b8f..f0fc820 100644 --- a/src/ProtoInput/ProtoInputHooks/PipeCommunication.cpp +++ b/src/ProtoInput/ProtoInputHooks/PipeCommunication.cpp @@ -24,11 +24,16 @@ #include "FakeMouseKeyboard.h" #include "CursorVisibilityHook.h" #include "MoveWindowHook.h" +#include "RegisterRawInputHook.h" #include "AdjustWindowRectHook.h" #include "RemoveBorderHook.h" +#include "TranslateXtoMKB.h" +#include "ScanThread.h" +#include "WindowMsgHook.h" namespace Proto { + bool gotkeyboardmouse = false; std::wstring GetPipeName() { @@ -76,6 +81,7 @@ DWORD WINAPI PipeThread(LPVOID lpParameter) } while (pipe == INVALID_HANDLE_VALUE); + if (pipe != INVALID_HANDLE_VALUE) { printf("Successfully connected pipe \"%ws\"\n", pipeName.c_str()); @@ -124,17 +130,65 @@ DWORD WINAPI PipeThread(LPVOID lpParameter) switch(msgHeader.messageType) { - case ProtoPipe::PipeMessageType::SetupHook: + + case ProtoPipe::PipeMessageType::AddSelectedMouseOrKeyboard: + { + const auto body = reinterpret_cast(messageBuffer); + + printf("Received message select mouse %d, keyboard %d\n", body->mouse, body->keyboard); + + if (body->mouse != -1) { - const auto body = reinterpret_cast(messageBuffer); - printf("Setup hook message: hook ID %d, install = %d\n", body->hookID, body->install); - if (body->install) - HookManager::InstallHook(body->hookID); - else - HookManager::UninstallHook(body->hookID); + gotkeyboardmouse = true; + RawInput::AddSelectedMouseHandle(body->mouse); + } + - break; + if (body->keyboard != -1) + { + gotkeyboardmouse = true; + RawInput::AddSelectedKeyboardHandle(body->keyboard); } + + break; + } + case ProtoPipe::PipeMessageType::SetTranslateXinputtoMKB: + { + const auto body = reinterpret_cast(messageBuffer); + RawInput::TranslateXinputtoMKB = body->TranslateXinputtoMKB; + if (RawInput::TranslateXinputtoMKB == true) + { + if (gotkeyboardmouse) + { + RawInput::TranslateXinputtoMKB = false; + printf("Discovered mouse or keyboard. disabling TranslateXtoMKB"); + } + else printf("Enabling TranslateXtoMKB"); + } + else printf("TranslateXtoMKB is set to false"); + RawInput::TranslateXinputtoMKB2 = RawInput::TranslateXinputtoMKB; + break; + } + case ProtoPipe::PipeMessageType::SetReregisterinput: //RegisterRawInputHook-Option + { + const auto body = reinterpret_cast(messageBuffer); + + printf("Received ReregisterInput, ReregisterInput enabled = %d\n", body->enabled); + + RegisterRawInputHook::Reregisterinput = body->enabled; + + break; + } + case ProtoPipe::PipeMessageType::SetupHook: + { + const auto body = reinterpret_cast(messageBuffer); + printf("Setup hook message: hook ID %d, install = %d\n", body->hookID, body->install); + if (body->install) + HookManager::InstallHook(body->hookID); + else + HookManager::UninstallHook(body->hookID); + break; + } case ProtoPipe::PipeMessageType::SetupMessageFilter: { const auto body = reinterpret_cast(messageBuffer); @@ -213,6 +267,7 @@ DWORD WINAPI PipeThread(LPVOID lpParameter) printf("Received message to set main window handle to hwnd %lld (0x%llX)\n", body->hwnd, body->hwnd); // HwndSelector::selectedHwnd = body->hwnd; HwndSelector::SetSelectedHwnd((intptr_t)body->hwnd); + HwndSelector::RemoteHwndEnabled = true; } break; @@ -294,11 +349,9 @@ DWORD WINAPI PipeThread(LPVOID lpParameter) { const auto body = reinterpret_cast(messageBuffer); - printf("Received message to %s fake cursor fix\n", body->enable ? "enable" : "disable"); - - // Not sure about this... - FakeCursor::state.DrawFakeCursorFix = body->enable; - + printf("Received message to %s fake cursor with offset fix\n", body->enable ? "enable" : "disable"); + FakeCursor::EnableDisableFakeCursor(body->enable); + FakeCursor::DrawFakeCursorFix = body->enable; break; } case ProtoPipe::PipeMessageType::SetExternalFreezeFakeInput: @@ -311,20 +364,7 @@ DWORD WINAPI PipeThread(LPVOID lpParameter) break; } - case ProtoPipe::PipeMessageType::AddSelectedMouseOrKeyboard: - { - const auto body = reinterpret_cast(messageBuffer); - printf("Received message select mouse %d, keyboard %d\n", body->mouse, body->keyboard); - - if (body->mouse != -1) - RawInput::AddSelectedMouseHandle(body->mouse); - - if (body->keyboard != -1) - RawInput::AddSelectedKeyboardHandle(body->keyboard); - - break; - } case ProtoPipe::PipeMessageType::AddHandleToRename: { const auto body = reinterpret_cast(messageBuffer); @@ -348,7 +388,15 @@ DWORD WINAPI PipeThread(LPVOID lpParameter) XinputHook::controllerIndex2 = body->controllerIndex2; XinputHook::controllerIndex3 = body->controllerIndex3; XinputHook::controllerIndex4 = body->controllerIndex4; - + if (RawInput::TranslateXinputtoMKB == true) + { + ScreenshotInput::TranslateXtoMKB::controllerID = XinputHook::controllerIndex - 1; + //Xinput hook can block controller making TranslateXtoMKB work on games with Xinput support + XinputHook::controllerIndex = 0; + XinputHook::controllerIndex2 = 0; + XinputHook::controllerIndex3 = 0; + XinputHook::controllerIndex4 = 0; + } break; } case ProtoPipe::PipeMessageType::SetUseDinput: @@ -371,6 +419,15 @@ DWORD WINAPI PipeThread(LPVOID lpParameter) break; } + case ProtoPipe::PipeMessageType::TranslateMKBtoXinput: + { + const auto body = reinterpret_cast(messageBuffer); + + printf("Received set translate MKB to Xinput. also extended mousestate bounds. remember Xinputhook also%d\n", body->TranslateMKBtoXinput); + + XinputHook::TranslateMKBtoXinput = body->TranslateMKBtoXinput; + break; + } case ProtoPipe::PipeMessageType::SetDinputDeviceGuid: { const auto body = reinterpret_cast(messageBuffer); @@ -405,7 +462,6 @@ DWORD WINAPI PipeThread(LPVOID lpParameter) SetWindowPosHook::posy = body->posy; SetWindowPosHook::width = body->width; SetWindowPosHook::height = body->height; - break; } case ProtoPipe::PipeMessageType::SetSetWindowPosDontResize: @@ -456,7 +512,6 @@ DWORD WINAPI PipeThread(LPVOID lpParameter) FakeMouseKeyboard::SetIgnoreMouseBounds(body->allowOutOfBounds); FakeMouseKeyboard::SetExtendMouseBounds(body->extendBounds); - break; } case ProtoPipe::PipeMessageType::SetToggleCursorVisibilityShortcut: @@ -480,6 +535,15 @@ DWORD WINAPI PipeThread(LPVOID lpParameter) break; } + + case ProtoPipe::PipeMessageType::SetPointerInMouse: + { + const auto body = reinterpret_cast(messageBuffer); + printf("Received PointerInMouse, PointerInMouse enabled = %d\n", body->enabled); + Proto::WindowMsgHook::PointerInMouse(body->enabled); + RawInput::PointerInMouse = body->enabled; //for runtime GUI + break; + } case ProtoPipe::PipeMessageType::SetShowCursorWhenImageUpdated: { const auto body = reinterpret_cast(messageBuffer); @@ -576,9 +640,92 @@ DWORD WINAPI PipeThread(LPVOID lpParameter) break; } + case ProtoPipe::PipeMessageType::SetManualScaling: + { + const auto body = reinterpret_cast(messageBuffer); + + printf("Received SetManualScaling with settings.from res (%d, %d), to (%d,%d)\n", body->oldX, body->oldY, body->newX, body->newY); + + WindowMsgHook::Settings(body->oldX, body->oldY, body->newX, body->newY); + + break; + } + case ProtoPipe::PipeMessageType::SetXinputtoMKBkeys: + { + const auto body = reinterpret_cast(messageBuffer); + printf("Received TranslateXtoMKB Mapping"); + ScreenshotInput::TranslateXtoMKB::Amapping = body->XinputtoMKBAkey; + ScreenshotInput::TranslateXtoMKB::Bmapping = body->XinputtoMKBBkey; + ScreenshotInput::TranslateXtoMKB::Xmapping = body->XinputtoMKBXkey; + ScreenshotInput::TranslateXtoMKB::Ymapping = body->XinputtoMKBYkey; + ScreenshotInput::TranslateXtoMKB::RSmapping = body->XinputtoMKBRSkey; + ScreenshotInput::TranslateXtoMKB::LSmapping = body->XinputtoMKBLSkey; + ScreenshotInput::TranslateXtoMKB::RSmapping = body->XinputtoMKBRSkey; + + ScreenshotInput::TranslateXtoMKB::rightmapping = body->XinputtoMKBrightkey; + ScreenshotInput::TranslateXtoMKB::leftmapping = body->XinputtoMKBleftkey; + ScreenshotInput::TranslateXtoMKB::upmapping = body->XinputtoMKBupkey; + ScreenshotInput::TranslateXtoMKB::downmapping = body->XinputtoMKBdownkey; + + ScreenshotInput::TranslateXtoMKB::stickRpressmapping = body->XinputtoMKBstickR; + ScreenshotInput::TranslateXtoMKB::stickLpressmapping = body->XinputtoMKBstickL; + ScreenshotInput::TranslateXtoMKB::stickrightmapping = body->XinputtoMKBstickright; + ScreenshotInput::TranslateXtoMKB::stickleftmapping = body->XinputtoMKBstickleft; + ScreenshotInput::TranslateXtoMKB::stickupmapping = body->XinputtoMKBstickup; + ScreenshotInput::TranslateXtoMKB::stickdownmapping = body->XinputtoMKBstickdown; + + ScreenshotInput::TranslateXtoMKB::optionmapping = body->XinputtoMKBoption; + ScreenshotInput::TranslateXtoMKB::startmapping = body->XinputtoMKBstart; + ScreenshotInput::TranslateXtoMKB::Sens = body->XinputtoMKBsens; + ScreenshotInput::TranslateXtoMKB::Sensmult = body->XinputtoMKBsensmult; + ScreenshotInput::TranslateXtoMKB::Deadzone = body->XinputtoMKBDeadzone; + break; + } //PipeMessageSetXinputtoMKBCFG + case ProtoPipe::PipeMessageType::SetXinputtoMKBCFG: + { + const auto body = reinterpret_cast(messageBuffer); + ScreenshotInput::TranslateXtoMKB::lefthanded = body->stickinvert; + ScreenshotInput::ScanThread::scanoption = body->scanoption; + ScreenshotInput::ScanThread::ShoulderNextBMP = body->shoulderswap; + ScreenshotInput::ScanThread::Aisstatic = body->astsatic; + ScreenshotInput::ScanThread::Bisstatic = body->bstsatic; + ScreenshotInput::ScanThread::Xisstatic = body->xstsatic; + ScreenshotInput::ScanThread::Yisstatic = body->ystsatic; + + if (body->amove && body->aclick) + ScreenshotInput::ScanThread::scanAtype = 0; + else if (body->amove) + ScreenshotInput::ScanThread::scanAtype = 1; + else if (body->aclick) + ScreenshotInput::ScanThread::scanAtype = 2; + + if (body->bmove && body->bclick) + ScreenshotInput::ScanThread::scanBtype = 0; + else if (body->bmove) + ScreenshotInput::ScanThread::scanBtype = 1; + else if (body->bclick) + ScreenshotInput::ScanThread::scanBtype = 2; + + if (body->xmove && body->xclick) + ScreenshotInput::ScanThread::scanXtype = 0; + else if (body->xmove) + ScreenshotInput::ScanThread::scanXtype = 1; + else if (body->xclick) + ScreenshotInput::ScanThread::scanXtype = 2; + + if (body->ymove && body->yclick) + ScreenshotInput::ScanThread::scanYtype = 0; + else if (body->ymove) + ScreenshotInput::ScanThread::scanYtype = 1; + else if (body->yclick) + ScreenshotInput::ScanThread::scanYtype = 2; + + break; + } default: { fprintf(stderr, "Unrecongnised message type, exiting pipe\n"); + //MessageBoxA(NULL, "ukjent message", "quit pipe", MB_OK); goto endPipe; } } @@ -586,10 +733,9 @@ DWORD WINAPI PipeThread(LPVOID lpParameter) } endPipe: + //MessageBoxA(NULL, "report this error: Pipe ended", "Pipe ended", MB_OK); printf("End of pipe thread\n"); - CloseHandle(pipe); - return 0; } diff --git a/src/ProtoInput/ProtoInputHooks/PipeCommunication.h b/src/ProtoInput/ProtoInputHooks/PipeCommunication.h index 7f046d3..705feb4 100644 --- a/src/ProtoInput/ProtoInputHooks/PipeCommunication.h +++ b/src/ProtoInput/ProtoInputHooks/PipeCommunication.h @@ -4,5 +4,7 @@ namespace Proto { void StartPipeCommunication(); +//static HANDLE evt; + } diff --git a/src/ProtoInput/ProtoInputHooks/ProtoInputHooks.vcxproj b/src/ProtoInput/ProtoInputHooks/ProtoInputHooks.vcxproj index ee51cdc..91d29cf 100644 --- a/src/ProtoInput/ProtoInputHooks/ProtoInputHooks.vcxproj +++ b/src/ProtoInput/ProtoInputHooks/ProtoInputHooks.vcxproj @@ -29,7 +29,7 @@ DynamicLibrary true - v142 + v143 Unicode @@ -42,7 +42,7 @@ DynamicLibrary true - v142 + v143 Unicode @@ -87,6 +87,9 @@ $(SolutionDir)$(Configuration)\ $(PlatformShortName)\$(Configuration)\ $(ProjectName)$(PlatformArchitecture) + CppCoreCheckConcurrencyRules.ruleset + true + false false @@ -205,10 +208,12 @@ + + @@ -232,12 +237,15 @@ + + + @@ -265,10 +273,12 @@ + + @@ -283,10 +293,13 @@ + + + diff --git a/src/ProtoInput/ProtoInputHooks/ProtoInputHooks.vcxproj.filters b/src/ProtoInput/ProtoInputHooks/ProtoInputHooks.vcxproj.filters index 624e681..caa51f6 100644 --- a/src/ProtoInput/ProtoInputHooks/ProtoInputHooks.vcxproj.filters +++ b/src/ProtoInput/ProtoInputHooks/ProtoInputHooks.vcxproj.filters @@ -28,6 +28,12 @@ {14e41680-f011-4d2c-b31b-3fd2d6ae9a52} + + {a0d1a945-2bce-40dd-88b8-54724cf1b678} + + + {2852b253-94b1-4a59-954e-55b28a17010b} + @@ -180,6 +186,21 @@ Source Files\Hooks + + Source Files\TranslateXtoMKB + + + Source Files\TranslateXtoMKB + + + Source Files\TranslateXtoMKB + + + Source Files\Hooks + + + Source Files + @@ -323,5 +344,20 @@ Source Files\Hooks + + Source Files\TranslateXtoMKB + + + Source Files\TranslateXtoMKB + + + Source Files\TranslateXtoMKB + + + Source Files\Hooks + + + Source Files + \ No newline at end of file diff --git a/src/ProtoInput/ProtoInputHooks/ProtoInputHooks.vcxproj.user b/src/ProtoInput/ProtoInputHooks/ProtoInputHooks.vcxproj.user index 0f14913..dc63f8a 100644 --- a/src/ProtoInput/ProtoInputHooks/ProtoInputHooks.vcxproj.user +++ b/src/ProtoInput/ProtoInputHooks/ProtoInputHooks.vcxproj.user @@ -1,4 +1,6 @@  - + + false + \ No newline at end of file diff --git a/src/ProtoInput/ProtoInputHooks/RawInput.cpp b/src/ProtoInput/ProtoInputHooks/RawInput.cpp index a05f0d1..0e80ca7 100644 --- a/src/ProtoInput/ProtoInputHooks/RawInput.cpp +++ b/src/ProtoInput/ProtoInputHooks/RawInput.cpp @@ -2,6 +2,7 @@ #include "Gui.h" #include #include +#include #include #include #include "HookManager.h" @@ -15,6 +16,9 @@ #include "protoinpututil.h" #include "KeyboardButtonFilter.h" #include "MessageFilterHook.h" +#include "TranslateXtoMKB.h" +#include "XinputHook.h" +#include "WindowMsgHook.h" namespace Proto { @@ -22,13 +26,19 @@ namespace Proto RawInputState RawInput::rawInputState{}; std::bitset<9> RawInput::usages{}; std::vector RawInput::forwardingWindows{}; -bool RawInput::forwardRawInput = true; +bool RawInput::forwardRawInput = true; //ReRegisterInput +bool RawInput::PointerInMouse; //ReRegisterInput bool RawInput::lockInputToggleEnabled = false; bool RawInput::rawInputBypass = false; - - RAWINPUT RawInput::inputBuffer[RawInputBufferSize]{}; std::vector RawInput::rawinputs{}; +bool RawInput::TranslateXinputtoMKB; +bool RawInput::TranslateXinputtoMKB2; //copy to prevent crash +bool RawInput::locked = false; +bool RawInput::alreadyAddToACL = false; + +size_t RawInput::bufferCounter = 0; + const std::vector RawInput::usageTypesOfInterest { @@ -43,85 +53,29 @@ const std::vector RawInput::usageTypesOfInterest HWND RawInput::rawInputHwnd = nullptr; -void RawInput::ProcessMouseInput(const RAWMOUSE& data, HANDLE deviceHandle) -{ - // Update fake mouse position - if ((data.usFlags & MOUSE_MOVE_ABSOLUTE) == MOUSE_MOVE_ABSOLUTE) - { - const bool isVirtualDesktop = (data.usFlags & MOUSE_VIRTUAL_DESKTOP) == MOUSE_VIRTUAL_DESKTOP; - - // const int width = GetSystemMetrics(isVirtualDesktop ? SM_CXVIRTUALSCREEN : SM_CXSCREEN); - // const int height = GetSystemMetrics(isVirtualDesktop ? SM_CYVIRTUALSCREEN : SM_CYSCREEN); - - static int widthVirtual = GetSystemMetrics(SM_CXVIRTUALSCREEN); - static int widthNonVirtual = GetSystemMetrics(SM_CXSCREEN); - static int heightVirtual = GetSystemMetrics(SM_CYVIRTUALSCREEN); - static int heightNonVirtual = GetSystemMetrics(SM_CYSCREEN); - - const int absoluteX = int((data.lLastX / 65535.0f) * (isVirtualDesktop ? widthVirtual : widthNonVirtual)); - const int absoluteY = int((data.lLastY / 65535.0f) * (isVirtualDesktop ? heightVirtual : heightNonVirtual)); - - static std::unordered_map> oldPositions{}; - - if (const auto find = oldPositions.find(deviceHandle); find != oldPositions.end()) - { - FakeMouseKeyboard::AddMouseDelta(absoluteX - find->second.first, absoluteY - find->second.second); - } - else - { - oldPositions.emplace(std::make_pair( deviceHandle, std::pair{ absoluteX, absoluteY } )); - } - } - else if (data.lLastX != 0 || data.lLastY != 0) - { - const int relativeX = data.lLastX; - const int relativeY = data.lLastY; - FakeMouseKeyboard::AddMouseDelta(relativeX, relativeY); - } - - // Set vkeys (GetKeyState/etc can be used to get the mouse buttons state) - if ((data.usButtonFlags & RI_MOUSE_LEFT_BUTTON_DOWN) != 0) - FakeMouseKeyboard::ReceivedKeyPressOrRelease(VK_LBUTTON, true); - if ((data.usButtonFlags & RI_MOUSE_LEFT_BUTTON_UP) != 0) - FakeMouseKeyboard::ReceivedKeyPressOrRelease(VK_LBUTTON, false); - - if ((data.usButtonFlags & RI_MOUSE_MIDDLE_BUTTON_DOWN) != 0) - FakeMouseKeyboard::ReceivedKeyPressOrRelease(VK_MBUTTON, true); - if ((data.usButtonFlags & RI_MOUSE_MIDDLE_BUTTON_UP) != 0) - FakeMouseKeyboard::ReceivedKeyPressOrRelease(VK_MBUTTON, false); - - if ((data.usButtonFlags & RI_MOUSE_RIGHT_BUTTON_DOWN) != 0) - FakeMouseKeyboard::ReceivedKeyPressOrRelease(VK_RBUTTON, true); - if ((data.usButtonFlags & RI_MOUSE_RIGHT_BUTTON_UP) != 0) - FakeMouseKeyboard::ReceivedKeyPressOrRelease(VK_RBUTTON, false); - - if ((data.usButtonFlags & RI_MOUSE_BUTTON_4_DOWN) != 0) - FakeMouseKeyboard::ReceivedKeyPressOrRelease(VK_XBUTTON1, true); - if ((data.usButtonFlags & RI_MOUSE_BUTTON_4_UP) != 0) - FakeMouseKeyboard::ReceivedKeyPressOrRelease(VK_XBUTTON1, false); - - if ((data.usButtonFlags & RI_MOUSE_BUTTON_5_DOWN) != 0) - FakeMouseKeyboard::ReceivedKeyPressOrRelease(VK_XBUTTON2, true); - if ((data.usButtonFlags & RI_MOUSE_BUTTON_5_UP) != 0) - FakeMouseKeyboard::ReceivedKeyPressOrRelease(VK_XBUTTON2, false); - - +void RawInput::SendInputMessages(const RAWMOUSE& data) +{ // This is used a lot in sending messages const unsigned int mouseMkFlags = FakeMouseKeyboard::GetMouseMkFlags(); const unsigned int mousePointLparam = MAKELPARAM(FakeMouseKeyboard::GetMouseState().x, FakeMouseKeyboard::GetMouseState().y); - - + // Send mouse wheel if (rawInputState.sendMouseWheelMessages) { - if((data.usButtonFlags & RI_MOUSE_WHEEL) != 0) + if ((data.usButtonFlags & RI_MOUSE_WHEEL) != 0) { + //mousewheel messages use screen coordinates instead of client coordinates + POINT screen; + screen.x = FakeMouseKeyboard::GetMouseState().x; + screen.y = FakeMouseKeyboard::GetMouseState().y; + ClientToScreen((HWND)HwndSelector::GetSelectedHwnd(), &screen); + LPARAM newmousePoint = MAKELPARAM(screen.x, screen.y); + const unsigned int wparam = (data.usButtonData << 16) | MouseWheelFilter::protoInputSignature | mouseMkFlags; - - PostMessageW((HWND)HwndSelector::GetSelectedHwnd(), WM_MOUSEWHEEL, wparam, mousePointLparam); + PostMessageW((HWND)HwndSelector::GetSelectedHwnd(), WM_MOUSEWHEEL, wparam, newmousePoint); } } @@ -168,7 +122,7 @@ void RawInput::ProcessMouseInput(const RAWMOUSE& data, HANDLE deviceHandle) } // Send mouse button messages else if (rawInputState.sendMouseButtonMessages) - { + { if ((data.usButtonFlags & RI_MOUSE_LEFT_BUTTON_DOWN) != 0) PostMessageW((HWND)HwndSelector::GetSelectedHwnd(), WM_LBUTTONDOWN, mouseMkFlags | MouseButtonFilter::signature, mousePointLparam); if ((data.usButtonFlags & RI_MOUSE_LEFT_BUTTON_UP) != 0) @@ -193,62 +147,111 @@ void RawInput::ProcessMouseInput(const RAWMOUSE& data, HANDLE deviceHandle) PostMessageW((HWND)HwndSelector::GetSelectedHwnd(), WM_XBUTTONDOWN, mouseMkFlags | (XBUTTON2 << 4) | MouseButtonFilter::signature, mousePointLparam); if ((data.usButtonFlags & RI_MOUSE_BUTTON_5_UP) != 0) PostMessageW((HWND)HwndSelector::GetSelectedHwnd(), WM_XBUTTONUP, mouseMkFlags | (XBUTTON2 << 4) | MouseButtonFilter::signature, mousePointLparam); - } - - + } // WM_MOUSEMOVE if (rawInputState.sendMouseMoveMessages) { PostMessageW((HWND)HwndSelector::GetSelectedHwnd(), WM_MOUSEMOVE, mouseMkFlags, mousePointLparam); } + FakeCursor::NotifyUpdatedCursorPosition(); +} +void RawInput::ProcessMouseInput(const RAWMOUSE& data, HANDLE deviceHandle) +{ - // Fake cursor - FakeCursor::NotifyUpdatedCursorPosition(); + // Update fake mouse position + if ((data.usFlags & MOUSE_MOVE_ABSOLUTE) == MOUSE_MOVE_ABSOLUTE) + { + const bool isVirtualDesktop = (data.usFlags & MOUSE_VIRTUAL_DESKTOP) == MOUSE_VIRTUAL_DESKTOP; + + // const int width = GetSystemMetrics(isVirtualDesktop ? SM_CXVIRTUALSCREEN : SM_CXSCREEN); + // const int height = GetSystemMetrics(isVirtualDesktop ? SM_CYVIRTUALSCREEN : SM_CYSCREEN); + + static int widthVirtual = GetSystemMetrics(SM_CXVIRTUALSCREEN); + static int widthNonVirtual = GetSystemMetrics(SM_CXSCREEN); + static int heightVirtual = GetSystemMetrics(SM_CYVIRTUALSCREEN); + static int heightNonVirtual = GetSystemMetrics(SM_CYSCREEN); + + const int absoluteX = int((data.lLastX / 65535.0f) * (isVirtualDesktop ? widthVirtual : widthNonVirtual)); + const int absoluteY = int((data.lLastY / 65535.0f) * (isVirtualDesktop ? heightVirtual : heightNonVirtual)); + + static std::unordered_map> oldPositions{}; + + if (const auto find = oldPositions.find(deviceHandle); find != oldPositions.end()) + { + FakeMouseKeyboard::AddMouseDelta(absoluteX - find->second.first, absoluteY - find->second.second); + } + else + { + oldPositions.emplace(std::make_pair( deviceHandle, std::pair{ absoluteX, absoluteY } )); + } + } + else if (data.lLastX != 0 || data.lLastY != 0) + { + const int relativeX = data.lLastX; + const int relativeY = data.lLastY; + FakeMouseKeyboard::AddMouseDelta(relativeX, relativeY); + } + + // Set vkeys (GetKeyState/etc can be used to get the mouse buttons state) + if ((data.usButtonFlags & RI_MOUSE_LEFT_BUTTON_DOWN) != 0) + FakeMouseKeyboard::ReceivedKeyPressOrRelease(VK_LBUTTON, true); + if ((data.usButtonFlags & RI_MOUSE_LEFT_BUTTON_UP) != 0) + FakeMouseKeyboard::ReceivedKeyPressOrRelease(VK_LBUTTON, false); + + if ((data.usButtonFlags & RI_MOUSE_MIDDLE_BUTTON_DOWN) != 0) + FakeMouseKeyboard::ReceivedKeyPressOrRelease(VK_MBUTTON, true); + if ((data.usButtonFlags & RI_MOUSE_MIDDLE_BUTTON_UP) != 0) + FakeMouseKeyboard::ReceivedKeyPressOrRelease(VK_MBUTTON, false); + + if ((data.usButtonFlags & RI_MOUSE_RIGHT_BUTTON_DOWN) != 0) + FakeMouseKeyboard::ReceivedKeyPressOrRelease(VK_RBUTTON, true); + if ((data.usButtonFlags & RI_MOUSE_RIGHT_BUTTON_UP) != 0) + FakeMouseKeyboard::ReceivedKeyPressOrRelease(VK_RBUTTON, false); + + if ((data.usButtonFlags & RI_MOUSE_BUTTON_4_DOWN) != 0) + FakeMouseKeyboard::ReceivedKeyPressOrRelease(VK_XBUTTON1, true); + if ((data.usButtonFlags & RI_MOUSE_BUTTON_4_UP) != 0) + FakeMouseKeyboard::ReceivedKeyPressOrRelease(VK_XBUTTON1, false); + + if ((data.usButtonFlags & RI_MOUSE_BUTTON_5_DOWN) != 0) + FakeMouseKeyboard::ReceivedKeyPressOrRelease(VK_XBUTTON2, true); + if ((data.usButtonFlags & RI_MOUSE_BUTTON_5_UP) != 0) + FakeMouseKeyboard::ReceivedKeyPressOrRelease(VK_XBUTTON2, false); + + if (!XinputHook::TranslateMKBtoXinput) + RawInput::SendInputMessages(data); } -void RawInput::ProcessKeyboardInput(const RAWKEYBOARD& data, HANDLE deviceHandle) +void RawInput::SendKeyMessage(const RAWKEYBOARD& data, bool pressed) { - const bool released = (data.Flags & RI_KEY_BREAK) != 0; - const bool pressed = !released; - - if (pressed && FakeCursor::GetToggleVisilbityShorcutEnabled() && data.VKey == FakeCursor::GetToggleVisibilityVkey()) + if (pressed && FakeCursor::GetToggleVisilbityShorcutEnabled() && data.VKey == FakeCursor::GetToggleVisibilityVkey()) { FakeCursor::SetCursorVisibility(!FakeCursor::GetCursorVisibility()); return; } - + if (rawInputState.sendKeyboardPressMessages) { if (pressed) { unsigned int lparam = 0; - + lparam |= 1; // Repeat bit lparam |= (data.MakeCode << 16); // Scan code - + if (FakeMouseKeyboard::IsKeyStatePressed(data.VKey)) { lparam |= (1 << 30); } - - PostMessageW((HWND)HwndSelector::GetSelectedHwnd(), WM_KEYDOWN, - MessageFilterHook::IsKeyboardButtonFilterEnabled() ? data.VKey | KeyboardButtonFilter::signature : data.VKey, + + PostMessageW((HWND)HwndSelector::GetSelectedHwnd(), WM_KEYDOWN, + MessageFilterHook::IsKeyboardButtonFilterEnabled() ? data.VKey | KeyboardButtonFilter::signature : data.VKey, lparam); - - // if (data.VKey == VK_SHIFT || data.VKey == VK_LSHIFT) - // { - // PostMessageW((HWND)HwndSelector::GetSelectedHwnd(), WM_KEYDOWN, VK_SHIFT, lparam); - // PostMessageW((HWND)HwndSelector::GetSelectedHwnd(), WM_KEYDOWN, VK_LSHIFT, lparam); - // } - // else - // { - // PostMessageW((HWND)HwndSelector::GetSelectedHwnd(), WM_KEYDOWN, data.VKey, lparam); - // } } - else if (released) + else { unsigned int lparam = 0; lparam |= 1; // Repeat count (always 1 for key up) @@ -256,26 +259,43 @@ void RawInput::ProcessKeyboardInput(const RAWKEYBOARD& data, HANDLE deviceHandle lparam |= (1 << 30); // Previous key state (always 1 for key up) lparam |= (1 << 31); // Transition state (always 1 for key up) - PostMessageW((HWND)HwndSelector::GetSelectedHwnd(), WM_KEYUP, + PostMessageW((HWND)HwndSelector::GetSelectedHwnd(), WM_KEYUP, MessageFilterHook::IsKeyboardButtonFilterEnabled() ? data.VKey | KeyboardButtonFilter::signature : data.VKey, lparam); - - // if (data.VKey == VK_SHIFT || data.VKey == VK_LSHIFT) - // { - // PostMessageW((HWND)HwndSelector::GetSelectedHwnd(), WM_KEYUP, VK_SHIFT, lparam); - // PostMessageW((HWND)HwndSelector::GetSelectedHwnd(), WM_KEYUP, VK_LSHIFT, lparam); - // } - // else - // { - // PostMessageW((HWND)HwndSelector::GetSelectedHwnd(), WM_KEYUP, data.VKey, lparam); - // } - } } +} +void RawInput::ProcessKeyboardInput(const RAWKEYBOARD& data, HANDLE deviceHandle) +{ + const bool released = (data.Flags & RI_KEY_BREAK) != 0; + const bool pressed = !released; + + if (!XinputHook::TranslateMKBtoXinput) + RawInput::SendKeyMessage(data, pressed); FakeMouseKeyboard::ReceivedKeyPressOrRelease(data.VKey, pressed); } + + +void RawInput::ToggleLockInput() +{ + RawInput::locked = !RawInput::locked; + static unsigned int loopThreadId = 0; + loopThreadId = LockInput(locked); + // Add the looping thread to the ACL so it can still use ClipCursor, etc + if (!RawInput::alreadyAddToACL && loopThreadId != 0) + { + RawInput::alreadyAddToACL = true; + printf("Adding loop thread %d to ACL\n", loopThreadId); + AddThreadToACL(loopThreadId); + } + if (locked) + SuspendExplorer(); + else + RestartExplorer(); +} + void RawInput::ProcessRawInput(HRAWINPUT rawInputHandle, bool inForeground, const MSG& msg) { // if (rawInputBypass) @@ -319,6 +339,7 @@ void RawInput::ProcessRawInput(HRAWINPUT rawInputHandle, bool inForeground, cons if ((GetAsyncKeyState(VK_RCONTROL) & ~1) != 0 && (GetAsyncKeyState(VK_RMENU) & ~1) != 0) // if ((GetAsyncKeyState(VK_LCONTROL) & ~1) != 0 && (GetAsyncKeyState(VK_LMENU) & ~1) != 0) { + //FakeCursor::Showmessage = 2; Proto::ToggleWindow(); } } @@ -334,7 +355,7 @@ void RawInput::ProcessRawInput(HRAWINPUT rawInputHandle, bool inForeground, cons { //TODO: This may waste CPU? (But need a way to update window otherwise) //if (HwndSelector::GetSelectedHwnd() == 0) - HwndSelector::UpdateMainHwnd(false); + HwndSelector::UpdateMainHwnd(false); HwndSelector::UpdateWindowBounds(); } @@ -343,29 +364,22 @@ void RawInput::ProcessRawInput(HRAWINPUT rawInputHandle, bool inForeground, cons // Lock input toggle if (lockInputToggleEnabled && rawinput.header.dwType == RIM_TYPEKEYBOARD && rawinput.data.keyboard.VKey == VK_HOME && rawinput.data.keyboard.Message == WM_KEYUP) { - static bool locked = false; - locked = !locked; printf(locked ? "Locking input\n" : "Unlocking input\n"); - - // Add the looping thread to the ACL so it can still use ClipCursor, etc - static unsigned int loopThreadId = 0; - static bool alreadyAddToACL = false; - loopThreadId = LockInput(locked); - if (!alreadyAddToACL && loopThreadId != 0) - { - alreadyAddToACL = true; - printf("Adding loop thread %d to ACL\n", loopThreadId); - AddThreadToACL(loopThreadId); - } - - if (locked) - SuspendExplorer(); - else - RestartExplorer(); + RawInput::ToggleLockInput(); + //FakeCursor::Showmessage = 3; } //TODO: handle forwarding HID input + + //attempted: + //std::byte type large, in array[inputbuffer]. then resize byte to size rawinput, + // and copy it over in getrawinputdatahook. worked for controller, but not mouse and keyboard. + // used seperate signature on HID input so std::byte was only used on hid. example: 0xAB000000 for mouse+kb + //then 0xAC000000 for HID. worked well on a pure raw controller game, but crashed on games with registered mouse+KB also + //could be because i did not seperate what window to send input message, as game was not meant to receive the messages, + //or the custom Dinput8 that i built that polled rawinput for controller. + //possible to try again, but then i think getting usages need to be array, so check each window seperatly what devices it is registered for if ( ( @@ -387,7 +401,7 @@ void RawInput::ProcessRawInput(HRAWINPUT rawInputHandle, bool inForeground, cons if (allowMouse || allowKeyboard) { - if (!rawInputBypass) + if (!rawInputBypass) //!XinputHook::TranslateMKBtoXinput { if (allowMouse) ProcessMouseInput(rawinput.data.mouse, rawinput.header.hDevice); @@ -398,18 +412,20 @@ void RawInput::ProcessRawInput(HRAWINPUT rawInputHandle, bool inForeground, cons if ((allowMouse && usages[HID_USAGE_GENERIC_MOUSE]) || (allowKeyboard && usages[HID_USAGE_GENERIC_KEYBOARD])) // if ((allowMouse) || (allowKeyboard)) { - for (const auto& hwnd : forwardingWindows) - { - static size_t inputBufferCounter = 0; + + for (const auto& hwnd : forwardingWindows) + { + static size_t inputBufferCounter = 0; - // The game is going to lag behind the data we get by a few times, so store in an array and pass the index as a message parameter + // The game is going to lag behind the data we get by a few times, so store in an array and pass the index as a message parameter - inputBufferCounter = (inputBufferCounter + 1) % RawInputBufferSize; - inputBuffer[inputBufferCounter] = rawinput; + inputBufferCounter = (inputBufferCounter + 1) % RawInputBufferSize; + inputBuffer[inputBufferCounter] = rawinput; - const LPARAM x = (inputBufferCounter) | 0xAB000000; - PostMessageW(hwnd, WM_INPUT, RIM_INPUT, x); - } + const LPARAM x = (inputBufferCounter) | 0xAB000000; + if (!XinputHook::TranslateMKBtoXinput) + PostMessageW(hwnd, WM_INPUT, RIM_INPUT, x); + } } } } @@ -439,9 +455,9 @@ DWORD WINAPI RawInputWindowThread(LPVOID lpParameter) printf("Starting Raw Input window thread\n"); AddThreadToACL(GetCurrentThreadId()); - + const auto hinstance = GetModuleHandle(nullptr); - + WNDCLASS wc = { 0 }; wc.lpfnWndProc = RawInputWindowWndProc; wc.hInstance = hinstance; @@ -477,7 +493,7 @@ DWORD WINAPI RawInputWindowThread(LPVOID lpParameter) if (GetMessage(&msg, RawInput::rawInputHwnd, WM_INPUT, WM_INPUT)) { // if (msg.message == WM_INPUT) - { + { RawInput::ProcessRawInput((HRAWINPUT)msg.lParam, GET_RAWINPUT_CODE_WPARAM(msg.wParam) == RIM_INPUT, msg); } @@ -501,17 +517,17 @@ void RawInput::RefreshDevices() const auto oldKbCount = rawInputState.keyboardHandles.size(); const auto oldMouseCount = rawInputState.mouseHandles.size(); - + rawInputState.keyboardHandles.clear(); rawInputState.mouseHandles.clear(); - + std::cout << "Raw input devices:\n"; for (unsigned int i = 0; i < numDevices; ++i) { auto* device = &deviceArray[i]; std::cout << (device->dwType == RIM_TYPEHID ? "HID" : device->dwType == RIM_TYPEKEYBOARD ? "Keyboard" : "Mouse") << ": " << device->hDevice << std::endl; - + if (device->dwType == RIM_TYPEKEYBOARD) { rawInputState.keyboardHandles.push_back(device->hDevice); @@ -555,7 +571,7 @@ void RawInput::RefreshDevices() if (std::find(rawInputState.mouseHandles.begin(), rawInputState.mouseHandles.end(), rawInputState.deselectedMouseHandles[i]) == rawInputState.mouseHandles.end()) rawInputState.deselectedMouseHandles.erase(rawInputState.deselectedMouseHandles.begin() + i); } - + for (int i = rawInputState.selectedKeyboardHandles.size() - 1; i >= 0; --i) { if (std::find(rawInputState.keyboardHandles.begin(), rawInputState.keyboardHandles.end(), rawInputState.selectedKeyboardHandles[i]) == rawInputState.keyboardHandles.end()) @@ -611,34 +627,56 @@ std::bitset<9> RawInput::GetUsageBitField() return usages; } +bool initializedrawinput = false; //for X to MKB translation +void RawInput::InjectFakeRawInput(const RAWINPUT& fakeInput) { + + bufferCounter = (bufferCounter + 1) % 20; + RawInput::inputBuffer[bufferCounter] = fakeInput; + + const LPARAM magicLParam = (bufferCounter) | 0xAB000000; + for (const auto& hwnd : forwardingWindows) + { + //bypassing rawinputhwnd, game windows direct + PostMessageW(hwnd, WM_INPUT, RIM_INPUT, magicLParam); + } +} + void RawInput::InitialiseRawInput() { - RefreshDevices(); - - HANDLE hThread = CreateThread(nullptr, 0, - (LPTHREAD_START_ROUTINE)RawInputWindowThread, GetModuleHandle(nullptr), 0, 0); - if (hThread != nullptr) - CloseHandle(hThread); + if (!initializedrawinput) //initalizeonlyonce + { + RefreshDevices(); + + HANDLE hThread = CreateThread(nullptr, 0, + (LPTHREAD_START_ROUTINE)RawInputWindowThread, GetModuleHandle(nullptr), 0, 0); + if (hThread != nullptr) + CloseHandle(hThread); + initializedrawinput = true; + } + return; } + + void RawInput::UnregisterGameFromRawInput() { printf("Unregistering game from raw input\n"); - std::vector devices{}; + std::vector devices{}; - for (const auto& usage : usageTypesOfInterest) - { - RAWINPUTDEVICE dev; - dev.usUsagePage = HID_USAGE_PAGE_GENERIC; - dev.usUsage = usage; - dev.dwFlags = RIDEV_REMOVE; - dev.hwndTarget = NULL; - devices.push_back(dev); - - auto res = RegisterRawInputDevices(&dev, 1, sizeof(RAWINPUTDEVICE)); - printf("Deregister usage 0x%X: Result 0x%X\n", usage, res); - } + for (const auto& usage : usageTypesOfInterest) + { + RAWINPUTDEVICE dev; + dev.usUsagePage = HID_USAGE_PAGE_GENERIC; + dev.usUsage = usage; + dev.dwFlags = RIDEV_REMOVE; + dev.hwndTarget = NULL; + devices.push_back(dev); + + auto res = RegisterRawInputDevices(&dev, 1, sizeof(RAWINPUTDEVICE)); + printf("Deregister usage 0x%X: Result 0x%X\n", usage, res); + } + return; } void RawInput::RegisterProtoForRawInput() diff --git a/src/ProtoInput/ProtoInputHooks/RawInput.h b/src/ProtoInput/ProtoInputHooks/RawInput.h index dbdc7fd..3bdaf41 100644 --- a/src/ProtoInput/ProtoInputHooks/RawInput.h +++ b/src/ProtoInput/ProtoInputHooks/RawInput.h @@ -36,20 +36,35 @@ class RawInput { private: static std::bitset<9> usages; + static std::vector forwardingWindows; - static const std::vector usageTypesOfInterest; static void ProcessMouseInput(const RAWMOUSE& data, HANDLE deviceHandle); static void ProcessKeyboardInput(const RAWKEYBOARD& data, HANDLE deviceHandle); + static bool locked; //input lock state + static bool alreadyAddToACL; + public: + static void SendInputMessages(const RAWMOUSE& data); + static void SendKeyMessage(const RAWKEYBOARD& data, bool pressed); + static void ToggleLockInput(); + static void InjectFakeRawInput(const RAWINPUT& fakeInput); static RawInputState rawInputState; static HWND rawInputHwnd; static bool forwardRawInput; + static bool PointerInMouse; //runtime gui toggle + static bool TranslateXinputtoMKB; + static bool TranslateXinputtoMKB2; + //static bool TranslateMKBtoXinput; //in XinputHook + + static size_t bufferCounter; // Passes input from all devices to the game. Proto Input doesn't process anything static bool rawInputBypass; + + //Reregisters devices to game then reactivates registerinput hook. called from dllmain static std::vector rawinputs; static RAWINPUT inputBuffer[RawInputBufferSize]; diff --git a/src/ProtoInput/ProtoInputHooks/RegisterRawInputHook.cpp b/src/ProtoInput/ProtoInputHooks/RegisterRawInputHook.cpp index 1d453e1..ebb0d5b 100644 --- a/src/ProtoInput/ProtoInputHooks/RegisterRawInputHook.cpp +++ b/src/ProtoInput/ProtoInputHooks/RegisterRawInputHook.cpp @@ -5,13 +5,16 @@ #include #include "RawInput.h" #include -#include "HwndSelector.h" +#include "HwndSelector.h" //GtoMnK_RawInputHooks +#include "GtoMnK_RawInputHooks.h" //GtoMnK_RawInputHooks namespace Proto { bool RegisterRawInputHook::logCallsToRegisterRawInput = false; RegisterRawInputHook* registerRawInputHookPtr = nullptr; +bool RegisterRawInputHook::Reregisterinput; + BOOL WINAPI Hook_RegisterRawInputDevices(PCRAWINPUTDEVICE pRawInputDevices, UINT uiNumDevices, UINT cbSize) { @@ -119,7 +122,12 @@ void RegisterRawInputHook::FindAlreadySubscribedWindows() } if (targetHWND == nullptr) + { printf("Couldn't find a hwnd subscribed to raw input\n"); + //assuming main window + if (RegisterRawInputHook::Reregisterinput) + AddWindowToForward((HWND)HwndSelector::GetSelectedHwnd(), usagesToForward); + } else { printf("Found raw input hwnd: 0x%X\n", targetHWND); @@ -143,6 +151,8 @@ void RegisterRawInputHook::ShowGuiStatus() ImGui::Checkbox("Forward raw input", &RawInput::forwardRawInput); ImGui::Checkbox("Log calls to registering raw input", &logCallsToRegisterRawInput); + ImGui::Checkbox("ReRegister Input", &RegisterRawInputHook::Reregisterinput); + ImGui::Checkbox("Raw input bypass", &RawInput::rawInputBypass); if (ImGui::IsItemHovered()) { @@ -156,20 +166,18 @@ void RegisterRawInputHook::ShowGuiStatus() void RegisterRawInputHook::InstallImpl() { - if (!installedAtLeastOnce) - { - installedAtLeastOnce = true; - std::bitset<9> usages{}; - // usages[HID_USAGE_GENERIC_MOUSE] = true; - // usages[HID_USAGE_GENERIC_KEYBOARD] = true; - RawInput::SetUsageBitField(usages); - } + std::bitset<9> usages{}; + if (!installedAtLeastOnce) + { + installedAtLeastOnce = true; + RawInput::SetUsageBitField(usages); + } + auto [status, _hookInfo] = InstallNamedHook(L"user32", "RegisterRawInputDevices", Hook_RegisterRawInputDevices); this->hookInfo = _hookInfo; FindAlreadySubscribedWindows(); - RawInput::UnregisterGameFromRawInput(); RawInput::RegisterProtoForRawInput(); } diff --git a/src/ProtoInput/ProtoInputHooks/RegisterRawInputHook.h b/src/ProtoInput/ProtoInputHooks/RegisterRawInputHook.h index 25c9774..194acaf 100644 --- a/src/ProtoInput/ProtoInputHooks/RegisterRawInputHook.h +++ b/src/ProtoInput/ProtoInputHooks/RegisterRawInputHook.h @@ -21,7 +21,9 @@ class RegisterRawInputHook final : public Hook public: static bool logCallsToRegisterRawInput; - + + static bool Reregisterinput; + const char* GetHookName() const override { return "Register Raw Input"; } const char* GetHookDescription() const override { @@ -33,6 +35,7 @@ class RegisterRawInputHook final : public Hook "Note that you need this hook for the GUI shortcut to work, so you should almost always have this enabled. "; } + bool HasGuiStatus() const override { return true; } void ShowGuiStatus() override; void InstallImpl() override; diff --git a/src/ProtoInput/ProtoInputHooks/ScanThread.cpp b/src/ProtoInput/ProtoInputHooks/ScanThread.cpp new file mode 100644 index 0000000..2b0f922 --- /dev/null +++ b/src/ProtoInput/ProtoInputHooks/ScanThread.cpp @@ -0,0 +1,1268 @@ +#include +#include +#define NOMINMAX +#include +#include +#include +#include +#include +#include +#include +#include "FakeMouseKeyboard.h" +#include "ScanThread.h" +#include "TranslateXtoMKB.h" +#include "FakeCursor.h" +#include "HwndSelector.h" + + +//coordinate pixel scanner from .bmp files or static points in ini next to exe. + +namespace ScreenshotInput { + + //public + // extern int drawfakecursor; + int ScanThread::Aisstatic, ScanThread::Bisstatic, ScanThread::Xisstatic, ScanThread::Yisstatic; + bool ScanThread::UpdateWindow; + int ScanThread::numphotoA, ScanThread::numphotoB, ScanThread::numphotoX, ScanThread::numphotoY; + int ScanThread::numphotoC, ScanThread::numphotoD, ScanThread::numphotoE, ScanThread::numphotoF; + int ScanThread::numphotoAbmps, ScanThread::numphotoBbmps, ScanThread::numphotoXbmps, ScanThread::numphotoYbmps; + int ScanThread::startsearchA, ScanThread::startsearchB, ScanThread::startsearchX, ScanThread::startsearchY; + int ScanThread::startsearchC, ScanThread::startsearchD, ScanThread::startsearchE, ScanThread::startsearchF; + POINT ScanThread::PointA, ScanThread::PointB, ScanThread::PointX, ScanThread::PointY; + CRITICAL_SECTION ScanThread::critical; + std::vector ScanThread::staticPointA, ScanThread::staticPointB, ScanThread::staticPointX, ScanThread::staticPointY; + int ScanThread::scanAtype, ScanThread::scanBtype, ScanThread::scanXtype, ScanThread::scanYtype; + int ScanThread::Ctype, ScanThread::Dtype, ScanThread::Etype, ScanThread::Ftype; + bool ScanThread::scanloop = false; + bool ScanThread::scanoption; + bool ScanThread::ShoulderNextBMP; + int ScanThread::resize = 1; //support scaling + + HWND hwndhandle; + POINT hwndres{ 0,0 }; + //private + bool PreScanningEnabled = false; + bool Astatic; + bool Bstatic; + bool Xstatic; + bool Ystatic; + HBITMAP hbm; + std::vector largePixels, smallPixels; + SIZE screenSize; + int strideLarge, strideSmall; + int smallW, smallH; + + //copies of criticals + int ModeScanThread; + int showmessageScanThread; + + std::string UGetExecutableFolder() + { + char path[MAX_PATH]; + GetModuleFileNameA(NULL, path, MAX_PATH); + std::string exePath(path); + size_t lastSlash = exePath.find_last_of("\\/"); + return exePath.substr(0, lastSlash); + } + + + std::wstring WGetExecutableFolder() { + wchar_t path[MAX_PATH]; + GetModuleFileNameW(NULL, path, MAX_PATH); + std::wstring exePath(path); + size_t lastSlash = exePath.find_last_of(L"\\/"); + + if (lastSlash == std::wstring::npos) + return L""; + return exePath.substr(0, lastSlash); + } + + int CalculateStride(int width) { + return ((width * 3 + 3) & ~3); + } + + bool LoadBMP24Bit(std::wstring filename, std::vector& pixels, int& width, int& height, int& stride) { + HBITMAP hbm = (HBITMAP)LoadImageW(NULL, filename.c_str(), IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_CREATEDIBSECTION); + if (!hbm) return false; + + //BITMAP scaledbmp; + BITMAP bmp; + GetObject(hbm, sizeof(BITMAP), &bmp); + width = bmp.bmWidth - 1; + height = bmp.bmHeight - 1; + stride = CalculateStride(width); + + pixels.resize(stride * height); + + BITMAPINFO bmi = {}; + bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); + bmi.bmiHeader.biWidth = width; + bmi.bmiHeader.biHeight = -height; + bmi.bmiHeader.biPlanes = 1; + bmi.bmiHeader.biBitCount = 24; + bmi.bmiHeader.biCompression = BI_RGB; + + BYTE* pBits = nullptr; + HDC hdc = GetDC(NULL); + GetDIBits(hdc, hbm, 0, height, pixels.data(), &bmi, DIB_RGB_COLORS); + + if (hdc) DeleteDC(hdc); + if (hbm) DeleteObject(hbm); + return true; + } + + //calling fuction in critical lock + void BmpInputAction(int X, int Y, int type) //moveclickorboth + { + Proto::FakeMouseState muusjn = Proto::FakeMouseKeyboard::GetMouseState(); + int Xhold = muusjn.x; + int Yhold = muusjn.y; + if (Xhold < X) + X = X - Xhold; + else + X = X - Xhold; + if (Yhold < Y) + Y= Y - Yhold; + else + Y = Y - Yhold; + if (type == 0) //click and move + { + + TranslateXtoMKB::SendMouseClick(X, Y, 8); + // Proto::FakeMouseKeyboard::SetMousePos(X, Y); + Sleep(5); + TranslateXtoMKB::SendMouseClick(X, Y, 3); + Sleep(5); + TranslateXtoMKB::SendMouseClick(X, Y, 4); + } + else if (type == 1) //only move + { + TranslateXtoMKB::SendMouseClick(X, Y, 8); + } + else if (type == 2) //only click + { + TranslateXtoMKB::SendMouseClick(X, Y, 8); + Sleep(5); + TranslateXtoMKB::SendMouseClick(X, Y, 3); + Sleep(5); + TranslateXtoMKB::SendMouseClick(X, Y, 4); + Sleep(5); + TranslateXtoMKB::SendMouseClick(-X, -Y, 8); + } + } + POINT Aprevious{ 0,0 }, Bprevious{ 0,0 }, Xprevious{ 0,0 }, Yprevious{ 0,0 }; + int Awas; int Bwas; int Xwas; int Ywas; + void Bmpfound(const char key[3], int X, int Y, int i, bool onlysearch, bool found, int store) + { + int input = 0; + //wait event + + if (strcmp(key, "\\A") == 0) + { + if (found) + { + if (onlysearch) + { + EnterCriticalSection(&ScanThread::critical); + ScanThread::startsearchA = i; + input = ScanThread::scanAtype; + ScanThread::staticPointA[i].x = X; + ScanThread::staticPointA[i].y = Y; + ScanThread::PointA.x = X; + ScanThread::PointA.y = Y; + if (Aprevious.x != X || Aprevious.y != Y) + ScanThread::UpdateWindow = true; + Aprevious.x = X; + Aprevious.y = Y; + LeaveCriticalSection(&ScanThread::critical); + } + else + { + input = ScanThread::scanAtype; + if (store) { + ScanThread::staticPointA[i].x = X; + ScanThread::staticPointA[i].y = Y; + + } + if (ScanThread::startsearchA < ScanThread::numphotoA - 1) + ScanThread::startsearchA = i + 1; + else ScanThread::startsearchA = 0; + } + } + else + { + if (onlysearch) + { + EnterCriticalSection(&ScanThread::critical); + ScanThread::startsearchA = 0; + ScanThread::PointA.x = 0; + ScanThread::PointA.y = 0; + if (Aprevious.x != X || Aprevious.y != Y) + ScanThread::UpdateWindow = true; + Aprevious.x = X; + Aprevious.y = Y; + LeaveCriticalSection(&ScanThread::critical); + } + } + } + if (strcmp(key, "\\B") == 0) + { + if (found) + { + //EnterCriticalSection(&critical); + + //LeaveCriticalSection(&critical); + if (onlysearch) + { + EnterCriticalSection(&ScanThread::critical); + ScanThread::startsearchB = i; + ScanThread::PointB.x = X; + ScanThread::staticPointB[i].x = X; + ScanThread::staticPointB[i].y = Y; + ScanThread::PointB.y = Y; + if (Bprevious.x != X || Bprevious.y != Y) + ScanThread::UpdateWindow = true; + Bprevious.x = X; + Bprevious.y = Y; + LeaveCriticalSection(&ScanThread::critical); + } + else + { + input = ScanThread::scanBtype; + if (store) { + ScanThread::staticPointB[i].x = X; + ScanThread::staticPointB[i].y = Y; + } + if (ScanThread::startsearchB < ScanThread::numphotoB - 1) + ScanThread::startsearchB = i + 1; + else ScanThread::startsearchB = 0; + } + } + else + { + if (onlysearch) + { + EnterCriticalSection(&ScanThread::critical); + ScanThread::startsearchB = 0; + ScanThread::PointB.x = 0; + ScanThread::PointB.y = 0; + if (Bprevious.x != X || Bprevious.y != Y) + ScanThread::UpdateWindow = true; + Bprevious.x = X; + Bprevious.y = Y; + LeaveCriticalSection(&ScanThread::critical); + } + } + } + if (strcmp(key, "\\X") == 0) + { + if (found) + { + // EnterCriticalSection(&critical); + + //LeaveCriticalSection(&critical); + if (onlysearch) + { + EnterCriticalSection(&ScanThread::critical); + ScanThread::startsearchX = i; + ScanThread::PointX.x = X; + ScanThread::PointX.y = Y; + ScanThread::staticPointX[i].x = X; + ScanThread::staticPointX[i].y = Y; + if (Xprevious.x != X || Xprevious.y != Y) + ScanThread::UpdateWindow = true; + Xprevious.x = X; + Xprevious.y = Y; + LeaveCriticalSection(&ScanThread::critical); + } + else + { + input = ScanThread::scanXtype; + ScanThread::startsearchX = i + 1; + if (store) { + ScanThread::staticPointX[i].x = X; + ScanThread::staticPointX[i].y = Y; + } + if (ScanThread::startsearchX < ScanThread::numphotoX - 1) + ScanThread::startsearchX = i + 1; + else ScanThread::startsearchX = 0; + } + } + else + { + if (onlysearch) + { + EnterCriticalSection(&ScanThread::critical); + ScanThread::startsearchX = 0; + ScanThread::PointX.x = 0; + ScanThread::PointX.y = 0; + if (Xprevious.x != X || Xprevious.y != Y) + ScanThread::UpdateWindow = true; + Xprevious.x = ScanThread::PointX.x; + Xprevious.y = ScanThread::PointX.y; + LeaveCriticalSection(&ScanThread::critical); + } + } + } + if (strcmp(key, "\\Y") == 0) + { + //EnterCriticalSection(&critical); + + //LeaveCriticalSection(&critical); + if (found) + { + if (onlysearch) + { + EnterCriticalSection(&ScanThread::critical); + ScanThread::startsearchX = i; + ScanThread::staticPointY[i].x = X; + ScanThread::staticPointY[i].y = Y; + ScanThread::PointY.x = X; + ScanThread::PointY.y = Y; + if (Yprevious.x != X || Yprevious.y != Y) + ScanThread::UpdateWindow = true; + Yprevious.x = X; + Yprevious.y = Y; + LeaveCriticalSection(&ScanThread::critical); + } + else + { + input = ScanThread::scanYtype; + ScanThread::startsearchY = i + 1; + if (store) { + ScanThread::staticPointY[i].x = X; + ScanThread::staticPointY[i].y = Y; + } + if (ScanThread::startsearchY < ScanThread::numphotoY - 1) + ScanThread::startsearchY = i + 1; + else ScanThread::startsearchY = 0; + } + } + else + { + if (onlysearch) + { + EnterCriticalSection(&ScanThread::critical); + ScanThread::startsearchY = 0; + //input = scanYtype; + ScanThread::PointY.x = 0; + ScanThread::PointY.y = 0; + if (Yprevious.x != X || Yprevious.y != Y) + ScanThread::UpdateWindow = true; + Yprevious.x = ScanThread::PointY.x; + Yprevious.y = ScanThread::PointY.y; + LeaveCriticalSection(&ScanThread::critical); + } + } + } + if (strcmp(key, "\\C") == 0) + { + if (found && !onlysearch) + { + ScanThread::startsearchC = i + 1; + input = ScanThread::Ctype; + } + } + if (strcmp(key, "\\D") == 0) + { + if (found && !onlysearch) + { + ScanThread::startsearchD = i + 1; + input = ScanThread::Dtype; + } + } + if (strcmp(key, "\\E") == 0) + { + if (found && !onlysearch) + { + ScanThread::startsearchE = i + 1; + input = ScanThread::Etype; + } + } + if (strcmp(key, "\\F") == 0) + { + if (found && !onlysearch) + { + ScanThread::startsearchF = i + 1; + input = ScanThread::Ftype; + } + } + if (!onlysearch) + { + if (found) + { //input sent in this function + BmpInputAction(X, Y, input); + } + } + return; + } + + + POINT GetStaticFactor(POINT pp, int doscale, bool isnotbmp) + { + POINT currentres; + currentres.x = Proto::HwndSelector::windowWidth; + currentres.y = Proto::HwndSelector::windowHeight; + FLOAT currentwidth = static_cast(currentres.x); + FLOAT currentheight = static_cast(currentres.y); + if (doscale == 1) + { + float scalex = currentwidth / 1024.0f; + float scaley = currentheight / 768.0f; + + pp.x = static_cast(std::lround(pp.x * scalex)); + pp.y = static_cast(std::lround(pp.y * scaley)); + } + if (doscale == 2) //4:3 blackbar only x + { + float difference = 0.0f; + float newwidth = currentwidth; + float curraspect = currentheight / currentwidth; + if (curraspect < 0.75f) + { + newwidth = currentheight / 0.75f; + if (isnotbmp) //cant pluss blackbars on bmps + difference = (currentwidth - newwidth) / 2; + } + float scalex = newwidth / 1024.0f; + float scaley = currentheight / 768.0f; + pp.x = static_cast(std::lround(pp.x * scalex) + difference); + pp.y = static_cast(std::lround(pp.y * scaley)); + } + if (doscale == 3) //only vertical stretch equal + { + float difference = 0.0f; + float newwidth = currentwidth; + float curraspect = currentheight / currentwidth; + if (curraspect < 0.5625f) + { + newwidth = currentheight / 0.5625f; + if (isnotbmp) //cant pluss blackbars on bmps + difference = (currentwidth - newwidth) / 2; + } + float scalex = newwidth / 1337.0f; + float scaley = currentheight / 768.0f; + pp.x = static_cast(std::lround(pp.x * scalex) + difference); + pp.y = static_cast(std::lround(pp.y * scaley)); + } + return pp; + } + + bool CaptureWindow24Bit(HWND hwnd, SIZE& capturedwindow, std::vector& pixels, int& strideOut, bool draw, bool stretchblt) + { + if (PreScanningEnabled) + EnterCriticalSection(&ScanThread::critical); + HDC hdcWindow = GetDC(hwnd); + HDC hdcMem = CreateCompatibleDC(hdcWindow); + + + RECT rcClient; + GetClientRect(hwnd, &rcClient); + int width = rcClient.right - rcClient.left; + int height = rcClient.bottom - rcClient.top; + capturedwindow.cx = width; + capturedwindow.cy = height; + + int stride = ((width * 3 + 3) & ~3); + strideOut = stride; + pixels.resize(stride * height); + + BITMAPINFO bmi = {}; + bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); + bmi.bmiHeader.biWidth = width; + bmi.bmiHeader.biHeight = -height; // top-down + bmi.bmiHeader.biPlanes = 1; + bmi.bmiHeader.biBitCount = 24; + bmi.bmiHeader.biCompression = BI_RGB; + + BYTE* pBits = nullptr; + HBITMAP hbm24 = CreateDIBSection(hdcWindow, &bmi, DIB_RGB_COLORS, (void**)&pBits, NULL, 0); + if (hbm24) + { + HGDIOBJ oldBmp = SelectObject(hdcMem, hbm24); + BitBlt(hdcMem, 0, 0, width, height, hdcWindow, 0, 0, SRCCOPY); + GetDIBits(hdcMem, hbm24, 0, height, pixels.data(), &bmi, DIB_RGB_COLORS); + SelectObject(hdcMem, oldBmp); + DeleteObject(hbm24); + // hbm24 = nullptr; + + } //hbm24 not null + + if (hdcMem) DeleteDC(hdcMem); + if (hdcWindow) ReleaseDC(hwnd, hdcWindow); + + if (PreScanningEnabled) + LeaveCriticalSection(&ScanThread::critical); + return true; + } //function end + + POINT CheckStatics(const char abc[3], int numtocheck) + { + POINT newpoint{ 0,0 }; + if (strcmp(abc, "\\A") == 0) + { + if (ScanThread::staticPointA[numtocheck].x != 0) + { + // + newpoint.x = ScanThread::staticPointA[numtocheck].x; + newpoint.y = ScanThread::staticPointA[numtocheck].y; + } + } + if (strcmp(abc, "\\B") == 0) + { + if (ScanThread::staticPointB[numtocheck].x != 0) + { + newpoint.x = ScanThread::staticPointB[numtocheck].x; + newpoint.y = ScanThread::staticPointB[numtocheck].y; + } + } + if (strcmp(abc, "\\X") == 0) + { + if (ScanThread::staticPointX[numtocheck].x != 0) + { + newpoint.x = ScanThread::staticPointX[numtocheck].x; + newpoint.y = ScanThread::staticPointX[numtocheck].y; + } + } + if (strcmp(abc, "\\Y") == 0) + { + if (ScanThread::staticPointY[numtocheck].x != 0) + { + newpoint.x = ScanThread::staticPointY[numtocheck].x; + newpoint.y = ScanThread::staticPointY[numtocheck].y; + } + } + return newpoint; + } + + bool FindSubImage24( + const BYTE* largeData, int largeW, int largeH, int strideLarge, + const BYTE* smallData, int smallW, int smallH, int strideSmall, + POINT& foundAt, int Xstart, int Ystart + ) { + for (int y = Ystart; y <= largeH - smallH; ++y) { + for (int x = Xstart; x <= largeW - smallW; ++x) { + bool match = true; + for (int j = 0; j < smallH && match; ++j) { + const BYTE* pLarge = largeData + (y + j) * strideLarge + x * 3; + const BYTE* pSmall = smallData + j * strideSmall; + if (memcmp(pLarge, pSmall, smallW * 3) != 0) { + match = false; + } + } + if (match) { + foundAt.x = x; + foundAt.y = y; + return true; + } + } + } + return false; + } + + bool Save24BitBMP(std::wstring filename, const BYTE* pixels, int width, int height) { //for testing purposes + int stride = ((width * 3 + 3) & ~3); + int imageSize = stride * height; + + BITMAPFILEHEADER bfh = {}; + bfh.bfType = 0x4D42; // "BM" + bfh.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER); + bfh.bfSize = bfh.bfOffBits + imageSize; + + BITMAPINFOHEADER bih = {}; + bih.biSize = sizeof(BITMAPINFOHEADER); + bih.biWidth = width; + bih.biHeight = -height; // bottom-up BMP (positive height) + bih.biPlanes = 1; + bih.biBitCount = 24; + bih.biCompression = BI_RGB; + bih.biSizeImage = imageSize; + + HANDLE hFile = CreateFileW(filename.c_str(), GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); + if (hFile == INVALID_HANDLE_VALUE) return false; + + DWORD written; + WriteFile(hFile, &bfh, sizeof(bfh), &written, NULL); + WriteFile(hFile, &bih, sizeof(bih), &written, NULL); + WriteFile(hFile, pixels, imageSize, &written, NULL); + CloseHandle(hFile); + + return true; + } + + bool ScanThread::SaveWindow10x10BMP(HWND hwnd, std::wstring filename, int x, int y) { + HDC hdcWindow = GetDC(hwnd); + HDC hdcMem = CreateCompatibleDC(hdcWindow); + + // Size: 10x10 + int width = 10; + int height = 10; + int stride = ((width * 3 + 3) & ~3); + std::vector pixels(stride * height); + + // Create a 24bpp bitmap + BITMAPINFO bmi = {}; + bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); + bmi.bmiHeader.biWidth = width; + bmi.bmiHeader.biHeight = -height; // top-down DIB + bmi.bmiHeader.biPlanes = 1; + bmi.bmiHeader.biBitCount = 24; + bmi.bmiHeader.biCompression = BI_RGB; + + //stretchblt + + BYTE* pBits = nullptr; + + HBITMAP hbm24 = CreateDIBSection(hdcWindow, &bmi, DIB_RGB_COLORS, (void**)&pBits, 0, 0); + if (!hbm24) { + DeleteDC(hdcMem); + ReleaseDC(hwnd, hdcWindow); + return false; + } + + HGDIOBJ oldbmp = SelectObject(hdcMem, hbm24); + + BitBlt(hdcMem, 0, 0, width, height, hdcWindow, x, y, SRCCOPY); + + // Prepare to retrieve bits + BITMAPINFOHEADER bih = {}; + bih.biSize = sizeof(BITMAPINFOHEADER); + bih.biWidth = width; + bih.biHeight = -height; // top-down for easier use + bih.biPlanes = 1; + bih.biBitCount = 24; + bih.biCompression = BI_RGB; + + GetDIBits(hdcMem, hbm24, 0, height, pixels.data(), (BITMAPINFO*)&bih, DIB_RGB_COLORS); + + // Save + bool ok = Save24BitBMP(filename.c_str(), pixels.data(), width, height); + + // Cleanup + SelectObject(hdcMem, oldbmp); + if (hbm24) DeleteObject(hbm24); + if (hdcMem)DeleteDC(hdcMem); + if (hdcWindow) ReleaseDC(hwnd, hdcWindow); + + return ok; + } + int HowManyBmps(std::wstring path, bool andstatics) + { + int start = -1; + + int x = 0; + std::wstring filename; + while (x < 50 && start == -1) + { + filename = path + std::to_wstring(x) + L".bmp"; + if (HBITMAP hbm = (HBITMAP)LoadImageW(NULL, filename.c_str(), IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_CREATEDIBSECTION)) + { + x++; + DeleteObject(hbm); + + } + else { + start = x; + } + } + + //searching statics + x = 0; + int inistart = -1; + while (x < 50 && inistart == -1) + { + std::string iniPath = UGetExecutableFolder() + "\\GtoMnK.ini"; + std::string iniSettings = "Statics"; + + std::string name(path.end() - 1, path.end()); + std::string string = name.c_str() + std::to_string(x) + "X"; + + + int sjekkX = GetPrivateProfileIntA(iniSettings.c_str(), string.c_str(), 0, iniPath.c_str()); //simple test if settings read but write it wont work. + if (sjekkX != 0) + { + string = name.c_str() + std::to_string(x) + "X"; + x++; + } + else inistart = x; + } + if (!andstatics || inistart == 0) + return start; + else return start + inistart; + } + bool ScanThread::initovector() + { + std::string iniPath = UGetExecutableFolder() + "\\GtoMnK.ini"; + std::string iniSettings = "Statics"; + std::string name = "A"; + int y = -1; + int sjekkx = 0; + bool test = false; + int x = -1; + int scalemethod = 0; + POINT inipoint; + while (x < 50 && y == -1) + { + x++; + std::string string = name + std::to_string(x) + "X"; + sjekkx = GetPrivateProfileIntA(iniSettings.c_str(), string.c_str(), 0, iniPath.c_str()); + if (sjekkx != 0) + { + test = true; + inipoint.x = sjekkx; + + string = name + std::to_string(x) + "Y"; + inipoint.y = GetPrivateProfileIntA(iniSettings.c_str(), string.c_str(), 0, iniPath.c_str()); + + string = name + std::to_string(x) + "Z"; + scalemethod = GetPrivateProfileIntA(iniSettings.c_str(), string.c_str(), 0, iniPath.c_str()); + if (scalemethod != 0) + inipoint = GetStaticFactor(inipoint, scalemethod, true); + ScanThread::staticPointA[x + ScanThread::numphotoAbmps].y = inipoint.y; + ScanThread::staticPointA[x + ScanThread::numphotoAbmps].x = inipoint.x; + } + else y = 10;// break; + } + y = -1; + name = "B"; + sjekkx = 0; + x = -1; + while (x < 50 && y == -1) + { + x++; + std::string string = name + std::to_string(x) + "X"; + sjekkx = GetPrivateProfileIntA(iniSettings.c_str(), string.c_str(), 0, iniPath.c_str()); + if (sjekkx != 0) + { + test = true; + inipoint.x = sjekkx; + + string = name + std::to_string(x) + "Y"; + inipoint.y = GetPrivateProfileIntA(iniSettings.c_str(), string.c_str(), 0, iniPath.c_str()); + + string = name + std::to_string(x) + "Z"; + scalemethod = GetPrivateProfileIntA(iniSettings.c_str(), string.c_str(), 0, iniPath.c_str()); + if (scalemethod != 0) + inipoint = GetStaticFactor(inipoint, scalemethod, true); + ScanThread::staticPointB[x + ScanThread::numphotoBbmps].y = inipoint.y; + ScanThread::staticPointB[x + ScanThread::numphotoBbmps].x = inipoint.x; + } + + else y = 10;// break; + } + y = -1; + name = "X"; + sjekkx = 0; + x = -1; + while (x < 50 && y == -1) + { + x++; + std::string string = name.c_str() + std::to_string(x) + "X"; + //MessageBoxA(NULL, "no bmps", "aaahaAAAHAA", MB_OK); + sjekkx = GetPrivateProfileIntA(iniSettings.c_str(), string.c_str(), 0, iniPath.c_str()); + if (sjekkx != 0) + { + test = true; + inipoint.x = sjekkx; + + string = name + std::to_string(x) + "Y"; + inipoint.y = GetPrivateProfileIntA(iniSettings.c_str(), string.c_str(), 0, iniPath.c_str()); + + string = name + std::to_string(x) + "Z"; + scalemethod = GetPrivateProfileIntA(iniSettings.c_str(), string.c_str(), 0, iniPath.c_str()); + if (scalemethod != 0) + inipoint = GetStaticFactor(inipoint, scalemethod, true); + ScanThread::staticPointX[x + ScanThread::numphotoXbmps].y = inipoint.y; + ScanThread::staticPointX[x + ScanThread::numphotoXbmps].x = inipoint.x; + + } + + else y = 10;// break; + } + y = -1; + name = "Y"; + sjekkx = 0; + x = -1; + while (x < 50 && y == -1) + { + x++; + std::string string = name.c_str() + std::to_string(x) + "X"; + sjekkx = GetPrivateProfileIntA(iniSettings.c_str(), string.c_str(), 0, iniPath.c_str()); + if (sjekkx != 0) + { + test = true; + inipoint.x = sjekkx; + + string = name + std::to_string(x) + "Y"; + inipoint.y = GetPrivateProfileIntA(iniSettings.c_str(), string.c_str(), 0, iniPath.c_str()); + + string = name + std::to_string(x) + "Z"; + scalemethod = GetPrivateProfileIntA(iniSettings.c_str(), string.c_str(), 0, iniPath.c_str()); + if (scalemethod != 0) + inipoint = GetStaticFactor(inipoint, scalemethod, true); + ScanThread::staticPointY[x + ScanThread::numphotoYbmps].y = inipoint.y; + ScanThread::staticPointY[x + ScanThread::numphotoYbmps].x = inipoint.x; + } + else y = 10; // break; + } + if (test == true) + return true; + else return false; //no points + } + + bool ScanThread::enumeratebmps() + { + ScanThread::numphotoA = 0; + ScanThread::startsearchA = 0; + ScanThread::numphotoB = 0; + ScanThread::startsearchB = 0; + ScanThread::numphotoX = 0; + ScanThread::startsearchX = 0; + ScanThread::numphotoY = 0; + ScanThread::startsearchY = 0; + std::wstring path = WGetExecutableFolder() + L"\\A"; + ScanThread::numphotoA = HowManyBmps(path, true); + ScanThread::numphotoAbmps = HowManyBmps(path, false); + path = WGetExecutableFolder() + L"\\B"; + ScanThread::numphotoB = HowManyBmps(path, true); + ScanThread::numphotoBbmps = HowManyBmps(path, false); + path = WGetExecutableFolder() + L"\\X"; + ScanThread::numphotoX = HowManyBmps(path, true); + ScanThread::numphotoXbmps = HowManyBmps(path, false); + path = WGetExecutableFolder() + L"\\Y"; + ScanThread::numphotoY = HowManyBmps(path, true); + ScanThread::numphotoYbmps = HowManyBmps(path, false); + path = WGetExecutableFolder() + L"\\C"; + ScanThread::numphotoC = HowManyBmps(path, false); + path = WGetExecutableFolder() + L"\\D"; + ScanThread::numphotoD = HowManyBmps(path, false); + path = WGetExecutableFolder() + L"\\E"; + ScanThread::numphotoE = HowManyBmps(path, false); + path = WGetExecutableFolder() + L"\\F"; + ScanThread::numphotoF = HowManyBmps(path, false); + + if (ScanThread::numphotoA < 0 && ScanThread::numphotoB < 0 && ScanThread::numphotoX < 0 && ScanThread::numphotoY < 0) + { + return false; + } + return true; + } + bool ButtonScanAction(const char key[3], int mode, int serchnum, int startsearch, bool onlysearch, POINT currentpoint, int checkarray) + { + bool found = false; + POINT pt = { 0,0 }; + POINT noeder = { 0,0 }; + int numbmp = 0; + + // if (ModeScanThread != 2) + // { + int numphoto = 0; + //MessageBoxA(NULL, "starting scan", "BMPs not found", MB_OK); + if (checkarray == 1) + { //always check static first? + noeder = CheckStatics(key, startsearch); + if (noeder.x != 0) + { + Bmpfound(key, noeder.x, noeder.y, startsearch, onlysearch, true, checkarray); //or not found + found = true; + return true; + } + } + if (!found) + { + for (int i = startsearch; i < serchnum; i++) + { + if (checkarray == 1) + { + noeder = CheckStatics(key, i); + if (noeder.x != 0) + { + Bmpfound(key, noeder.x, noeder.y, i, onlysearch, true, checkarray); //or not found + found = true; + return true; + } + } + std::string path = UGetExecutableFolder() + key + std::to_string(i) + ".bmp"; + + std::wstring wpath(path.begin(), path.end()); + // + // HDC soke; + if (LoadBMP24Bit(wpath.c_str(), smallPixels, smallW, smallH, strideSmall) && !found) + { + // MessageBoxA(NULL, "loaded bmp.", "BMPs not found", MB_OK); + if (CaptureWindow24Bit(hwndhandle, screenSize, largePixels, strideLarge, false, ScanThread::resize)) + { + if (onlysearch) + { + if (FindSubImage24(largePixels.data(), screenSize.cx, screenSize.cy, strideLarge, smallPixels.data(), smallW, smallH, strideSmall, pt, currentpoint.x, currentpoint.y)) + { + numphoto = i; + found = true; + break; + } + } + if (found == false) + { + if (FindSubImage24(largePixels.data(), screenSize.cx, screenSize.cy, strideLarge, smallPixels.data(), smallW, smallH, strideSmall, pt, 0, 0)) + { + found = true; + numphoto = i; + break; + } + }//found + } //hbmdessktop + }//loadbmp + } + } + if (!found) + { + for (int i = 0; i < serchnum; i++) + { + if (checkarray == 1) + { + noeder = CheckStatics(key, i); + if (noeder.x != 0) + { + Bmpfound(key, noeder.x, noeder.y, i, onlysearch, true, checkarray); //or not found + found = true; + return true; + } + } + std::string path = UGetExecutableFolder() + key + std::to_string(i) + ".bmp"; + std::wstring wpath(path.begin(), path.end()); + if (LoadBMP24Bit(wpath.c_str(), smallPixels, smallW, smallH, strideSmall) && !found) + { + //ShowMemoryUsageMessageBox(); + if (CaptureWindow24Bit(hwndhandle, screenSize, largePixels, strideLarge, false, ScanThread::resize)) + + {// MessageBox(NULL, "some kind of error", "captured desktop", MB_OK | MB_ICONINFORMATION); + if (FindSubImage24(largePixels.data(), screenSize.cx, screenSize.cy, strideLarge, smallPixels.data(), smallW, smallH, strideSmall, pt, 0, 0)) + { + // MessageBox(NULL, "some kind of error", "found spot", MB_OK | MB_ICONINFORMATION); + found = true; + numphoto = i; + break; + } + } //hbmdessktop + }//loadbmp + } + + } + Bmpfound(key, pt.x, pt.y, numphoto, onlysearch, found, checkarray); //or not found + if (found == true) + return true; + else return false; + // } + + // if (mode == 2 && MainThread::showmessage == 0 && onlysearch == false) //mode 2 button mapping //showmessage var to make sure no double map or map while message + // { + // Sleep(100); //to make sure red flicker expired + // std::string path = UGetExecutableFolder() + key + std::to_string(serchnum) + ".bmp"; + // std::wstring wpath(path.begin(), path.end()); + // SaveWindow10x10BMP(hwndhandle, wpath.c_str(), Mouse::Xf, Mouse::Yf); + // // MainThread::showmessage = 10; //signal is saving + // return true; + // } + // else if (MainThread::showmessage != 0) + // MainThread::showmessage = 11;//wait for mesage expire + return false; + } + + DWORD WINAPI ScanThreadMain(LPVOID, int Aisstatic, int Bisstatic, int Xisstatic, int Yisstatic) + { + ScanThread::scanloop = true; + int scantick = 0; + Sleep(3000); + Astatic = Aisstatic; + Bstatic = Bisstatic; + Xstatic = Xisstatic; + Ystatic = Yisstatic; + // + + while (ScanThread::scanloop) + { + EnterCriticalSection(&ScanThread::critical); + POINT Apos = { ScanThread::PointA.x, ScanThread::PointA.y }; + POINT Bpos = { ScanThread::PointB.x, ScanThread::PointB.y }; + POINT Xpos = { ScanThread::PointX.x, ScanThread::PointX.y }; + POINT Ypos = { ScanThread::PointY.x, ScanThread::PointY.y }; + int startsearchAW = ScanThread::startsearchA; + int startsearchBW = ScanThread::startsearchB; + int startsearchXW = ScanThread::startsearchX; + int startsearchYW = ScanThread::startsearchY; + POINT PointAW = ScanThread::PointA; + POINT PointBW = ScanThread::PointB; + POINT PointXW = ScanThread::PointX; + POINT PointYW = ScanThread::PointY; + ModeScanThread = TranslateXtoMKB::mode; + //showmessageScanThread = TranslateXtoMKB::showmessage; + hwndhandle = (HWND)Proto::HwndSelector::GetSelectedHwnd(); + LeaveCriticalSection(&ScanThread::critical); + + if (scantick < 3) + scantick++; + else scantick = 0; + if (PreScanningEnabled) + { + + if (scantick == 0 && ScanThread::numphotoA > 0) + { + if (Astatic == 1) + { + if (ScanThread::staticPointA[startsearchAW].x == 0 && ScanThread::staticPointA[startsearchAW].y == 0) + ButtonScanAction("\\A", 1, ScanThread::numphotoA, startsearchAW, true, PointAW, Astatic); + else + Bmpfound("\\A", ScanThread::staticPointA[startsearchAW].x, ScanThread::staticPointA[startsearchAW].y, startsearchAW, true, true, Astatic); + } + else ButtonScanAction("\\A", 1, ScanThread::numphotoA, startsearchAW, true, PointAW, Astatic); + } + + if (scantick == 1 && ScanThread::numphotoB > 0) + { + if (Bstatic == 1) + { + if (ScanThread::staticPointB[startsearchBW].x == 0 && ScanThread::staticPointB[startsearchBW].y == 0) + //MessageBoxA(NULL, "heisann", "A", MB_OK); + ButtonScanAction("\\B", 1, ScanThread::numphotoB, startsearchBW, true, PointAW, Bstatic); + else + Bmpfound("\\B", ScanThread::staticPointB[startsearchBW].x, ScanThread::staticPointB[startsearchBW].y, startsearchBW, true, true, Bstatic); + } + else ButtonScanAction("\\B", 1, ScanThread::numphotoB, startsearchBW, true, PointBW, Bstatic); + + } + if (scantick == 2 && ScanThread::numphotoX > 0) + { + if (Xstatic == 1) + { + if (ScanThread::staticPointX[startsearchXW].x == 0 && ScanThread::staticPointX[startsearchXW].y == 0) + ButtonScanAction("\\X", 1, ScanThread::numphotoX, startsearchXW, true, PointXW, Xstatic); + else Bmpfound("\\X", ScanThread::staticPointX[startsearchXW].x, ScanThread::staticPointX[startsearchXW].y, startsearchXW, true, true, Xstatic); + } + else ButtonScanAction("\\X", 1, ScanThread::numphotoX, startsearchXW, true, PointXW, Xstatic); + + } + if (scantick == 3 && ScanThread::numphotoY > 0) + { + if (Ystatic == 1) + { + if (ScanThread::staticPointY[startsearchYW].x == 0 && ScanThread::staticPointY[startsearchYW].y == 0) + //MessageBoxA(NULL, "heisann", "A", MB_OK); + ButtonScanAction("\\Y", 1, ScanThread::numphotoY, startsearchYW, true, PointYW, Ystatic); + else + Bmpfound("\\Y", ScanThread::staticPointY[startsearchYW].x, ScanThread::staticPointY[startsearchYW].y, startsearchYW, true, true, Ystatic); + } + ButtonScanAction("\\Y", 1, ScanThread::numphotoY, startsearchYW, true, PointYW, Ystatic); + } + Sleep(10); + } + else Sleep(100); + } + return 0; + } + + bool ScanThread::ButtonPressed(UINT buttonFlagg) + { + bool returnedvalue = false; + if (buttonFlagg == 0) + { + if (!PreScanningEnabled) { + returnedvalue = ButtonScanAction("\\A", ModeScanThread, ScanThread::numphotoA, ScanThread::startsearchA, false, { 0,0 }, Astatic);//buttonacton will be occupied by scanthread + } + else + { + EnterCriticalSection(&ScanThread::critical); + POINT Cpoint; + Cpoint.x = ScanThread::PointA.x; + Cpoint.y = ScanThread::PointA.y; + if (Cpoint.x != 0 && Cpoint.y != 0) + { + if (!ScanThread::ShoulderNextBMP) + { + if (ScanThread::startsearchA < ScanThread::numphotoA - 1) + ScanThread::startsearchA++; //dont want it to update before input done + else ScanThread::startsearchA = 0; + ScanThread::PointA.x = 0; + ScanThread::PointA.y = 0; + } + BmpInputAction(Cpoint.x, Cpoint.y, scanAtype); + returnedvalue = true; + + } + LeaveCriticalSection(&ScanThread::critical); + } + } + if (buttonFlagg == 1) + { + if (!PreScanningEnabled) { + returnedvalue = ButtonScanAction("\\B", ModeScanThread, ScanThread::numphotoB, ScanThread::startsearchB, false, { 0,0 }, Bstatic);//buttonacton will be occupied by scanthread + } + else + { + EnterCriticalSection(&ScanThread::critical); + POINT Cpoint; + Cpoint.x = ScanThread::PointB.x; + Cpoint.y = ScanThread::PointB.y; + if (Cpoint.x != 0 && Cpoint.y != 0) + { + if (!ScanThread::ShoulderNextBMP) + { + if (ScanThread::startsearchB < ScanThread::numphotoB - 1) + ScanThread::startsearchB++; //dont want it to update before input done + else ScanThread::startsearchB = 0; + ScanThread::PointA.x = 0; + ScanThread::PointA.y = 0; + } + BmpInputAction(Cpoint.x, Cpoint.y, ScanThread::scanBtype); + returnedvalue = true; + } + LeaveCriticalSection(&ScanThread::critical); + } + } + if (buttonFlagg == 2) + { + if (!PreScanningEnabled) { + returnedvalue = ButtonScanAction("\\X", ModeScanThread, ScanThread::numphotoX, ScanThread::startsearchX, false, { 0,0 }, Xstatic);//buttonacton will be occupied by scanthread + } + else + { + EnterCriticalSection(&ScanThread::critical); + POINT Cpoint; + Cpoint.x = ScanThread::PointX.x; + Cpoint.y = ScanThread::PointX.y; + + if (Cpoint.x != 0 && Cpoint.y != 0) + { + if (!ScanThread::ShoulderNextBMP) + { + if (ScanThread::startsearchX < ScanThread::numphotoX - 1) + ScanThread::startsearchX++; //dont want it to update before input done + else ScanThread::startsearchX = 0; + ScanThread::PointX.x = 0; + ScanThread::PointX.y = 0; + } + BmpInputAction(Cpoint.x, Cpoint.y, ScanThread::scanXtype); + returnedvalue = true; + + } + LeaveCriticalSection(&ScanThread::critical); + } + } + if (buttonFlagg == 3) + { + if (!PreScanningEnabled) { + returnedvalue = ButtonScanAction("\\Y", ModeScanThread, ScanThread::numphotoY, ScanThread::startsearchY, false, { 0,0 }, Ystatic);//buttonacton will be occupied by scanthread + } + else + { + EnterCriticalSection(&ScanThread::critical); + POINT Cpoint; + Cpoint.x = ScanThread::PointY.x; + Cpoint.y = ScanThread::PointY.y; + if (Cpoint.x != 0 && Cpoint.y != 0) + { + if (!ScanThread::ShoulderNextBMP) + { + if (ScanThread::startsearchY < ScanThread::numphotoY - 1) + ScanThread::startsearchY++; //dont want it to update before input done + else ScanThread::startsearchY = 0; + PointY.x = 0; + PointY.y = 0; + } + BmpInputAction(Cpoint.x, Cpoint.y, ScanThread::scanYtype); + returnedvalue = true; + + } + LeaveCriticalSection(&critical); + } + if (ModeScanThread == 2 && showmessageScanThread != 11) + { + ScanThread::numphotoY++; + Sleep(500); + } + } + if (buttonFlagg == 4) //C + { + if (!PreScanningEnabled) + { + EnterCriticalSection(&ScanThread::critical); + returnedvalue = ButtonScanAction("\\C", ModeScanThread, ScanThread::numphotoC, ScanThread::startsearchC, false, { 0,0 }, false); //2 save bmps + LeaveCriticalSection(&ScanThread::critical); + //MessageBoxA(NULL, "ooonei", "A", MB_OK); + } + else if (ScanThread::ShoulderNextBMP) + { + //MessageBoxA(NULL, "heisann2", "A", MB_OK); + EnterCriticalSection(&ScanThread::critical); + if (ScanThread::startsearchA < ScanThread::numphotoA - 1) + ScanThread::startsearchA++; //dont want it to update before input done + else ScanThread::startsearchA = 0; + if (ScanThread::startsearchB < ScanThread::numphotoB - 1) + ScanThread::startsearchB++; //dont want it to update before input done + else ScanThread::startsearchB = 0; + if (ScanThread::startsearchX < ScanThread::numphotoX - 1) + ScanThread::startsearchX++; //dont want it to update before input done + else ScanThread::startsearchX = 0; + LeaveCriticalSection(&ScanThread::critical); + } + } + if (buttonFlagg == 5) //D + { + if (!PreScanningEnabled) + { + EnterCriticalSection(&ScanThread::critical); + returnedvalue = ButtonScanAction("\\D", ModeScanThread, ScanThread::numphotoD, ScanThread::startsearchD, false, { 0,0 }, false); //2 save bmps + LeaveCriticalSection(&ScanThread::critical); + } + else if (ScanThread::ShoulderNextBMP) + { + + EnterCriticalSection(&ScanThread::critical); + if (ScanThread::startsearchA > 0) + ScanThread::startsearchA--; + else ScanThread::startsearchA = ScanThread::numphotoA - 1; + if (ScanThread::startsearchB > 0) + ScanThread::startsearchB--; + else ScanThread::startsearchB = ScanThread::numphotoB - 1; + if (ScanThread::startsearchX > 0) + ScanThread::startsearchX--; + else ScanThread::startsearchX = ScanThread::numphotoX - 1; + if (ScanThread::startsearchY > 0) + ScanThread::startsearchY--; + else ScanThread::startsearchY = ScanThread::numphotoY - 1; + LeaveCriticalSection(&ScanThread::critical); + } + + } + if (buttonFlagg == 6) //E + { + // MessageBoxA(NULL, "heisann", "RSB", MB_OK); + if (!PreScanningEnabled) + { + EnterCriticalSection(&critical); + returnedvalue = ButtonScanAction("\\E", ModeScanThread, ScanThread::numphotoD, ScanThread::startsearchD, false, { 0,0 }, false); //2 save bmps + LeaveCriticalSection(&critical); + } + } + if (buttonFlagg == 7) //F + { + //MessageBoxA(NULL, "heisann", "LSB", MB_OK); + if (!PreScanningEnabled) + { + EnterCriticalSection(&critical); + returnedvalue = ButtonScanAction("\\F", ModeScanThread, ScanThread::numphotoF, ScanThread::startsearchF, false, { 0,0 }, false); //2 save bmps + LeaveCriticalSection(&critical); + } + } + return returnedvalue; + + } + + + void ScanThread::StartScanThread(HMODULE hmodule, int Astatic, int Bstatic, int Xstatic, int Ystatic, bool prescan) { + PreScanningEnabled = prescan; + std::thread tree(ScanThreadMain, hmodule, Astatic, Bstatic, Xstatic, Ystatic); + tree.detach(); + } + + +}; \ No newline at end of file diff --git a/src/ProtoInput/ProtoInputHooks/ScanThread.h b/src/ProtoInput/ProtoInputHooks/ScanThread.h new file mode 100644 index 0000000..9803c74 --- /dev/null +++ b/src/ProtoInput/ProtoInputHooks/ScanThread.h @@ -0,0 +1,32 @@ +#pragma once +//#include "HandleMainWindow.h" + + +namespace ScreenshotInput { + + class ScanThread { + public: + static CRITICAL_SECTION critical; //window thread + static int scanAtype, scanBtype, scanXtype, scanYtype, Ctype, Dtype, Etype, Ftype; + static int numphotoA, numphotoB, numphotoX, numphotoY, numphotoC, numphotoD, numphotoE, numphotoF; + static int numphotoAbmps, numphotoBbmps, numphotoXbmps, numphotoYbmps; + static bool UpdateWindow; + static POINT PointA, PointB, PointX, PointY; + static int startsearchA, startsearchB, startsearchX, startsearchY, startsearchC, startsearchD, startsearchE, startsearchF; + static std::vector staticPointA, staticPointB, staticPointX, staticPointY; + static bool scanloop; + //tunell + static int Aisstatic, Bisstatic, Xisstatic, Yisstatic; + static bool scanoption; + static bool ShoulderNextBMP; + + static int resize; + static int ignorerect; + static void StartScanThread(HMODULE hmodule, int Astatic, int Bstatic, int Xstatic, int Ystatic, bool prescan); + + static bool SaveWindow10x10BMP(HWND hwnd, std::wstring filename, int x, int y); + static bool enumeratebmps(); //false if no bmps found + static bool initovector(); + static bool ButtonPressed(UINT buttonFlag); + }; +} \ No newline at end of file diff --git a/src/ProtoInput/ProtoInputHooks/SetCursorPosHook.cpp b/src/ProtoInput/ProtoInputHooks/SetCursorPosHook.cpp index f67b94f..01fc9db 100644 --- a/src/ProtoInput/ProtoInputHooks/SetCursorPosHook.cpp +++ b/src/ProtoInput/ProtoInputHooks/SetCursorPosHook.cpp @@ -3,14 +3,17 @@ #include "HwndSelector.h" #include "FakeMouseKeyboard.h" #include "FakeCursor.h" +#include "XinputHook.h" +#include "WindowMsgHook.h" namespace Proto { bool SetCursorPosHook::blockSettingCursorPos = false; - +POINT SetCursorPosHook::mousesethere; BOOL WINAPI Hook_SetCursorPos(int X, int Y) { + if (!SetCursorPosHook::blockSettingCursorPos) { POINT p; @@ -20,7 +23,13 @@ BOOL WINAPI Hook_SetCursorPos(int X, int Y) //SetCursorPos require screen coordinates (relative to 0,0 of monitor) ScreenToClient((HWND)HwndSelector::GetSelectedHwnd(), &p); - FakeMouseKeyboard::SetMousePos(p.x, p.y); + if (XinputHook::TranslateMKBtoXinput) + { + SetCursorPosHook::mousesethere.x = p.x; + SetCursorPosHook::mousesethere.y = p.y; + } + if (!XinputHook::TranslateMKBtoXinput) + FakeMouseKeyboard::SetMousePos(p.x, p.y); FakeCursor::NotifyUpdatedCursorPosition(); } diff --git a/src/ProtoInput/ProtoInputHooks/SetCursorPosHook.h b/src/ProtoInput/ProtoInputHooks/SetCursorPosHook.h index 4efa2fa..a70e681 100644 --- a/src/ProtoInput/ProtoInputHooks/SetCursorPosHook.h +++ b/src/ProtoInput/ProtoInputHooks/SetCursorPosHook.h @@ -13,7 +13,7 @@ class SetCursorPosHook final : public Hook public: //TODO: pipe option? static bool blockSettingCursorPos; - + static POINT mousesethere; const char* GetHookName() const override { return "Set Cursor Position"; } const char* GetHookDescription() const override { diff --git a/src/ProtoInput/ProtoInputHooks/SetWindowPosHook.cpp b/src/ProtoInput/ProtoInputHooks/SetWindowPosHook.cpp index e9a90cb..7ffaa5f 100644 --- a/src/ProtoInput/ProtoInputHooks/SetWindowPosHook.cpp +++ b/src/ProtoInput/ProtoInputHooks/SetWindowPosHook.cpp @@ -1,5 +1,6 @@ #include "SetWindowPosHook.h" #include +#include "HwndSelector.h" namespace Proto { @@ -25,7 +26,7 @@ BOOL WINAPI Hook_SetWindowPos(HWND hWnd, HWND hWndInsertAfter, int X, int Y, int void SetWindowPosHook::ShowGuiStatus() { int pos[2] = { posx, posy }; - ImGui::SliderInt2("Position", &pos[0], -5000, 5000); + ImGui::SliderInt2("Position", &pos[0], 0, 5000); posx = pos[0]; posy = pos[1]; @@ -33,6 +34,14 @@ void SetWindowPosHook::ShowGuiStatus() ImGui::SliderInt2("Size", &size[0], 0, 5000); width = size[0]; height = size[1]; + + ImGui::Checkbox("Dont Resize", &SetWindowPosHook::SetWindowPosDontResize); + ImGui::Checkbox("Dont Resposition", &SetWindowPosHook::SetWindowPosDontReposition); + + if (ImGui::Button("Set Position"))//these need unique IDs or text + { + Hook_SetWindowPos((HWND)HwndSelector::GetSelectedHwnd(), HWND_TOP, 0, 0, 0, 0, SWP_NOOWNERZORDER | SWP_SHOWWINDOW); + } } void SetWindowPosHook::InstallImpl() diff --git a/src/ProtoInput/ProtoInputHooks/TranslateXtoMKB.cpp b/src/ProtoInput/ProtoInputHooks/TranslateXtoMKB.cpp new file mode 100644 index 0000000..e830e8a --- /dev/null +++ b/src/ProtoInput/ProtoInputHooks/TranslateXtoMKB.cpp @@ -0,0 +1,944 @@ +#include +#include "Gui.h" +#include +#include +#include +#include "TranslateXtoMKB.h" +#include "RawInput.h" +#include +#include +#define NOMINMAX +#include +#include "EasyHook.h" +#include +#include +#include "HwndSelector.h" +#include "FakeCursor.h" +#include "Gui.h" +#include "GtoMnK_RawInput.h" +#include "FakeMouseKeyboard.h" +#include "ScanThread.h" +#include "StateInfo.h" + + +namespace ScreenshotInput +{ + int InstanceID = 0; //InstanceID copy from stateinfo.h + + int TranslateXtoMKB::RefreshWindow; + int TranslateXtoMKB::RefreshPoint; + + //from tunnell + int TranslateXtoMKB::controllerID; + bool TranslateXtoMKB::rawinputhook; //registerrawinputhook + bool TranslateXtoMKB::registerrawinputhook; //registerrawinputhook + int TranslateXtoMKB::stickrightmapping; + int TranslateXtoMKB::stickleftmapping; + int TranslateXtoMKB::stickupmapping; + int TranslateXtoMKB::stickdownmapping; + int TranslateXtoMKB::Amapping; + int TranslateXtoMKB::Bmapping; + int TranslateXtoMKB::Xmapping; + int TranslateXtoMKB::Ymapping; + int TranslateXtoMKB::RSmapping; + int TranslateXtoMKB::LSmapping; + int TranslateXtoMKB::rightmapping; + int TranslateXtoMKB::leftmapping; + int TranslateXtoMKB::upmapping; + int TranslateXtoMKB::downmapping; + int TranslateXtoMKB::stickRpressmapping; + int TranslateXtoMKB::stickLpressmapping; + int TranslateXtoMKB::optionmapping; + int TranslateXtoMKB::startmapping; + bool TranslateXtoMKB::lefthanded; + int TranslateXtoMKB::mode = 1; + bool TranslateXtoMKB::SaveBmps; + + int TranslateXtoMKB::Sens = 12; + int TranslateXtoMKB::Sensmult = 4; + int TranslateXtoMKB::Deadzone = 2; + + int updatewindowtick = 300; + + float axial_deadzone = 0.00f; // Square/Axial Deadzone (0.0 to 0.3) + const float max_threshold = 0.03f; // Max Input Threshold, an "outer deadzone" (0.0 to 0.15) + const float curve_slope = 0.16f; // The linear portion of the response curve (0.0 to 1.0) + const float curve_exponent = 5.00f; // The exponential portion of the curve (1.0 to 10.0) + + int startbuttontimer, backbuttontimer; + + + HMODULE g_hModule = nullptr; + + bool loop = true; + //int TranslateXtoMKB::showmessage = 0; //0 = no message, 1 = initializing, 2 = bmp mode, 3 = bmp and cursor mode, 4 = edit mode + + int counter = 0; + bool oldhome = false; //toggle lock input with home key + + //copy of criticals + int modeMT; + + POINT delta; + //hooks + + + //fake cursor + int Xf = 0; + int Yf = 0; + + + int tick = 0; + + bool leftPressedold = false; + bool rightPressedold = false; + bool oldA = false; + bool oldB = false; + bool oldX = false; + bool oldY = false; + + bool oldC = false; + bool oldD = false; + bool oldE = false; + bool oldF = false; + + bool olddown = false; + bool oldup = false; + bool oldleft = false; + bool oldright = false; + bool oldoptions = false; + bool oldstart = false; + bool oldstartoptions = false; + bool oldscrolldown = false; + bool oldscrollleft = false; + bool oldscrollright = false; + bool oldscrollup = false; + bool oldGUIkey = false; + + + void StartScanner() { + ScanThread::numphotoA = 0; + ScanThread::numphotoB = 0; + ScanThread::numphotoX = 0; + ScanThread::numphotoY = 0; + // InitializeCriticalSection(&ScanThread::critical); + if (!ScanThread::enumeratebmps()) //false means no bmps found. also counts statics + { + // printf("BMPs enumerated but not found"); + if (ScanThread::scanoption) + { + ScanThread::scanoption = false; + // printf("Error. Nothing to scan for. Disabling scanoption"); + } + + } + else { + // printf("BMPs found"); + ScanThread::staticPointA.assign(ScanThread::numphotoA + 1, POINT{ 0, 0 }); + ScanThread::staticPointB.assign(ScanThread::numphotoB + 1, POINT{ 0, 0 }); + ScanThread::staticPointX.assign(ScanThread::numphotoX + 1, POINT{ 0, 0 }); + ScanThread::staticPointY.assign(ScanThread::numphotoY + 1, POINT{ 0, 0 }); + } + ScanThread::initovector(); + if (ScanThread::scanoption) + { //starting bmp continous scanner + ScanThread::StartScanThread(g_hModule, ScanThread::Aisstatic, ScanThread::Bisstatic, ScanThread::Xisstatic, ScanThread::Yisstatic, ScanThread::scanoption); + // printf("BMP scanner started"); + } + Sleep(20); //give time for ScanThread::scanloop toggle true + } + + USHORT lastVKkey = 0; + bool IsKeyPressed(int Vkey) + { + return (GetAsyncKeyState(Vkey) & 0x8000) != 0; + + } + void TranslateXtoMKB::SendMouseClick(int x, int y, int z) { + // Create a named mutex + RAWMOUSE muusjn = { 0 }; + muusjn.usButtonFlags = 0; + + muusjn.lLastX = x; + muusjn.lLastY = y; + + if (z == 3) { + muusjn.usButtonFlags |= RI_MOUSE_LEFT_BUTTON_DOWN; + RawInput::GenerateRawMouseButton(-1, true); + Proto::FakeMouseKeyboard::ReceivedKeyPressOrRelease(VK_LBUTTON, true); //last originally + } + if (z == 4) + { + muusjn.usButtonFlags |= RI_MOUSE_LEFT_BUTTON_UP; + Proto::FakeMouseKeyboard::ReceivedKeyPressOrRelease(VK_LBUTTON, false); + RawInput::GenerateRawMouseButton(-1, false); + } + if (z == 5) { + muusjn.usButtonFlags |= RI_MOUSE_RIGHT_BUTTON_DOWN; + Proto::FakeMouseKeyboard::ReceivedKeyPressOrRelease(VK_RBUTTON, true); + RawInput::GenerateRawMouseButton(-2, true); + } + if (z == 6) + { + muusjn.usButtonFlags |= RI_MOUSE_RIGHT_BUTTON_UP; + Proto::FakeMouseKeyboard::ReceivedKeyPressOrRelease(VK_RBUTTON, false); + RawInput::GenerateRawMouseButton(-2, false); + + } + if (z == 20 || z == 21) //WM_mousewheel need desktop coordinates + { + } + else if (z == 8 || z == 10 || z == 11) //only mousemove + { + RawInput::SendActionDelta(x, y); + Proto::FakeMouseKeyboard::AddMouseDelta(x, y); + + } + Proto::RawInput::SendInputMessages(muusjn); + } + std::string UGetExeFolder() { + char path[MAX_PATH]; + GetModuleFileNameA(NULL, path, MAX_PATH); + + std::string exePath(path); + + size_t lastSlash = exePath.find_last_of("\\/"); + return exePath.substr(0, lastSlash); + } + void ButtonStateImpulse(int vk, bool state, int whocalled) + { + if (modeMT == 1) + { + RAWKEYBOARD data{}; + data.MakeCode = MapVirtualKey(vk, MAPVK_VK_TO_VSC); + data.VKey = vk; + data.ExtraInformation = 0; + data.Flags = state ? 0 : RI_KEY_BREAK; + data.Message = state ? WM_KEYDOWN : WM_KEYUP; + // Extended key? + switch (vk) + { + case VK_LEFT: + case VK_RIGHT: + case VK_UP: + case VK_DOWN: + case VK_INSERT: + case VK_DELETE: + case VK_HOME: + case VK_END: + case VK_PRIOR: + case VK_NEXT: + case VK_RCONTROL: + case VK_RMENU: + case VK_DIVIDE: + case VK_NUMLOCK: + data.Flags |= RI_KEY_E0; + break; + } + Proto::FakeMouseKeyboard::ReceivedKeyPressOrRelease(vk, state); + Proto::RawInput::SendKeyMessage(data, state); + RawInput::GenerateRawKey(vk, state, false); + } + if (modeMT == 2) + { + if (Proto::FakeCursor::Showmessage == 0) + { + HWND hwndhere = (HWND)Proto::HwndSelector::GetSelectedHwnd(); + Proto::FakeMouseState muusjn = Proto::FakeMouseKeyboard::GetMouseState(); + int Xhold = muusjn.x; + int Yhold = muusjn.y; + std::string path; + if ( whocalled == 0) //A + { + path = UGetExeFolder() + "\\A" + std::to_string(ScanThread::numphotoA) + ".bmp"; + Proto::FakeCursor::Showmessage = 10; //signal is saving + ScanThread::numphotoA++; + } + if (whocalled == 1) //B + { + path = UGetExeFolder() + "\\B" + std::to_string(ScanThread::numphotoB) + ".bmp"; + Proto::FakeCursor::Showmessage = 11; //signal is saving + ScanThread::numphotoB++; + } + if (whocalled == 2) //X + { + path = UGetExeFolder() + "\\X" + std::to_string(ScanThread::numphotoX) + ".bmp"; + Proto::FakeCursor::Showmessage = 12; //signal is saving + ScanThread::numphotoX++; + } + if (whocalled == 3) //Y + { + path = UGetExeFolder() + "\\Y" + std::to_string(ScanThread::numphotoY) + ".bmp"; + Proto::FakeCursor::Showmessage = 13; //signal is saving + ScanThread::numphotoY++; + } + + std::wstring wpath(path.begin(), path.end()); + ScanThread::SaveWindow10x10BMP(hwndhere, wpath.c_str(), muusjn.x, muusjn.y); + // MessageBoxW(nullptr, wpath.c_str(), L"Path", MB_OK); + + TranslateXtoMKB::RefreshPoint ++; + counter = 0; + } + } + } + + + + std::wstring WGetExeFolder() { + wchar_t path[MAX_PATH]; + GetModuleFileNameW(NULL, path, MAX_PATH); + std::wstring exePath(path); + size_t lastSlash = exePath.find_last_of(L"\\/"); + + if (lastSlash == std::wstring::npos) + return L""; + return exePath.substr(0, lastSlash); + } + + + bool IsTriggerPressed(BYTE triggerValue) { + BYTE threshold = 175; + return triggerValue > threshold; + } + + + // Helper: Get stick magnitude + float GetStickMagnitude(SHORT x, SHORT y) { + return sqrtf(static_cast(x) * x + static_cast(y) * y); + } + + // Helper: Clamp value to range [-1, 1] + float Clamp(float v) { + if (v < -1.0f) return -1.0f; + if (v > 1.0f) return 1.0f; + return v; + } + + POINT CalculateUltimateCursorMove( + SHORT stickX, SHORT stickY, + float c_deadzone, + float s_deadzone, + float max_threshold, + float curve_slope, + float curve_exponent, + float sensitivity, + float accel_multiplier + ) { + static double mouseDeltaAccumulatorX = 0.0; + static double mouseDeltaAccumulatorY = 0.0; + + double normX = static_cast(stickX) / 32767.0; + double normY = static_cast(stickY) / 32767.0; + + double magnitude = std::sqrt(normX * normX + normY * normY); + if (magnitude < c_deadzone) { + return { 0, 0 }; // Inside circular deadzone + } + if (std::abs(normX) < s_deadzone) { + normX = 0.0; // Inside axial deadzone for X + } + if (std::abs(normY) < s_deadzone) { + normY = 0.0; // Inside axial deadzone for Y + } + magnitude = std::sqrt(normX * normX + normY * normY); + if (magnitude < 1e-6) { + return { 0, 0 }; + } + + double effectiveRange = 1.0 - max_threshold - c_deadzone; + if (effectiveRange < 1e-6) effectiveRange = 1.0; + + double remappedMagnitude = (magnitude - c_deadzone) / effectiveRange; + remappedMagnitude = (std::max)(0.0, (std::min)(1.0, remappedMagnitude)); + + double curvedMagnitude = curve_slope * remappedMagnitude + (1.0 - curve_slope) * std::pow(remappedMagnitude, curve_exponent); + + double finalSpeed = sensitivity * accel_multiplier; + + double dirX = normX / magnitude; + double dirY = normY / magnitude; + double finalMouseDeltaX = dirX * curvedMagnitude * finalSpeed; + double finalMouseDeltaY = dirY * curvedMagnitude * finalSpeed; + + mouseDeltaAccumulatorX += finalMouseDeltaX; + mouseDeltaAccumulatorY += finalMouseDeltaY; + LONG integerDeltaX = static_cast(mouseDeltaAccumulatorX); + LONG integerDeltaY = static_cast(mouseDeltaAccumulatorY); + + mouseDeltaAccumulatorX -= integerDeltaX; + mouseDeltaAccumulatorY -= integerDeltaY; + + return { integerDeltaX, -integerDeltaY }; + } + + void TranslateXtoMKB::ThreadFunction() + { + if (ScanThread::scanoption && ScanThread::scanloop == false) + { + //MessageBoxA(NULL, "Starting BMP scanner...", "Info", MB_OK); + StartScanner(); + } + float sensitivity = static_cast(TranslateXtoMKB::Sens); + float accel_multiplier = static_cast(TranslateXtoMKB::Sensmult) / 2.0f; + float radial_deadzone = static_cast(TranslateXtoMKB::Deadzone) / 20.0f; + int deadzonelimit = 7000 + (TranslateXtoMKB::Deadzone * 1300); + EnterCriticalSection(&ScanThread::critical); + if (ScanThread::UpdateWindow) + TranslateXtoMKB::RefreshPoint = 1; + LeaveCriticalSection(&ScanThread::critical); + modeMT = 1; + if (TranslateXtoMKB::SaveBmps) { + modeMT = 2; + } + + //GUI + if (oldGUIkey) + { + if (IsKeyPressed(VK_RCONTROL) && IsKeyPressed(VK_RMENU) && IsKeyPressed(0x30 + InstanceID)) + { + } + else + { + oldGUIkey = false; + ButtonStateImpulse(VK_HOME, false, 99);//down} + } + } + else if (IsKeyPressed(VK_RCONTROL) && IsKeyPressed(VK_RMENU) && IsKeyPressed(0x30 + InstanceID))//gui or fake cursor toggle + { + Proto::ToggleWindow(); + oldGUIkey = true; + Proto::FakeCursor::Showmessage = 2; + TranslateXtoMKB::RefreshPoint = 1; + tick = 0; + if (TranslateXtoMKB::mode == 1) //modechange + { + TranslateXtoMKB::mode = 2; + } + else TranslateXtoMKB::mode = 1; + } + + XINPUT_STATE state; + ZeroMemory(&state, sizeof(XINPUT_STATE)); + // Check controller 0 + DWORD dwResult = OpenXInputGetState(TranslateXtoMKB::controllerID, &state); + if (dwResult == ERROR_SUCCESS) + { + WORD buttons = state.Gamepad.wButtons; + if (Proto::FakeCursor::Showmessage == 1) + {//remove disconnected message + Proto::FakeCursor::Showmessage = 0; + TranslateXtoMKB::RefreshPoint = 1; + } + if (modeMT > 0) + { + //fake cursor poll + int Xaxis = 0; + int Yaxis = 0; + int scrollXaxis = 0; + int scrollYaxis = 0; + int Yscroll = 0; + int Xscroll = 0; + bool leftPressed = IsTriggerPressed(state.Gamepad.bLeftTrigger); + bool rightPressed = IsTriggerPressed(state.Gamepad.bRightTrigger); + + if (TranslateXtoMKB::lefthanded == 1) { + Xaxis = state.Gamepad.sThumbLX; + Yaxis = state.Gamepad.sThumbLY; + scrollXaxis = state.Gamepad.sThumbRX; + scrollYaxis = state.Gamepad.sThumbRY; + } + else + { + Xaxis = state.Gamepad.sThumbRX; + Yaxis = state.Gamepad.sThumbRY; + scrollXaxis = state.Gamepad.sThumbLX; + scrollYaxis = state.Gamepad.sThumbLY; + } + + delta = CalculateUltimateCursorMove( + Xaxis, Yaxis, + radial_deadzone, axial_deadzone, max_threshold, + curve_slope, curve_exponent, + sensitivity, accel_multiplier + ); + if (delta.x != 0 || delta.y != 0) { + Xf += delta.x; + Yf += delta.y; + TranslateXtoMKB::RefreshWindow = 1; + TranslateXtoMKB::SendMouseClick(delta.x, delta.y, 8); + } + + if (leftPressedold) + { + if (!leftPressed) + { + + TranslateXtoMKB::SendMouseClick(Xf, Yf, 6); //double click + leftPressedold = false; + } + } + else if (leftPressed) + { + if (leftPressedold == false) + { + TranslateXtoMKB::SendMouseClick(Xf, Yf, 5); //4 skal vere 3 + leftPressedold = true; + } + } + + if (rightPressedold) + { + if (!rightPressed) + { + TranslateXtoMKB::SendMouseClick(Xf, Yf, 4); + rightPressedold = false; + } + } //if rightpress + else if (rightPressed) + { + if (rightPressedold == false) + { + TranslateXtoMKB::SendMouseClick(Xf, Yf, 3); + rightPressedold = true; + + } + } + + //buttons + if (oldscrollleft) + { + if (scrollXaxis < -deadzonelimit) //left + { + } + else { + oldscrollleft = false; + ButtonStateImpulse(TranslateXtoMKB::stickleftmapping, false, 99);//down + } + } + else if (scrollXaxis < -deadzonelimit) //left + { + oldscrollleft = true; + + ButtonStateImpulse(TranslateXtoMKB::stickleftmapping, true, 99);//down + } + + if (oldscrollright) + { + if (scrollXaxis > deadzonelimit) //left + { + } + else { + oldscrollright = false; + ButtonStateImpulse(TranslateXtoMKB::stickrightmapping, false, 99);//down + } + } + else if (scrollXaxis > deadzonelimit) //left + { + oldscrollright = true; + ButtonStateImpulse(TranslateXtoMKB::stickrightmapping, true, 99);//down + } + + if (oldscrollup) + { + if (scrollYaxis > deadzonelimit) //left + { + } + else { + oldscrollup = false; + ButtonStateImpulse(TranslateXtoMKB::stickupmapping, false, 99);//down + } + } + else if (scrollYaxis > deadzonelimit) //left + { + oldscrollup = true; + ButtonStateImpulse(TranslateXtoMKB::stickupmapping, true, 99);//down + } + + if (oldscrolldown) + { + if (scrollYaxis < -deadzonelimit) //left + { + } + else { + oldscrolldown = false; + ButtonStateImpulse(TranslateXtoMKB::stickdownmapping, false, 99);//down + } + } + else if (scrollYaxis < -deadzonelimit) //left + { + oldscrolldown = true; + ButtonStateImpulse(TranslateXtoMKB::stickdownmapping, true, 99);//down + } + + if (oldA) + { + if (buttons & XINPUT_GAMEPAD_A) + { + } + else { + oldA = false; + + ButtonStateImpulse(TranslateXtoMKB::Amapping, false, 0);//release + } + + } + else if (buttons & XINPUT_GAMEPAD_A) + { + oldA = true; + if (ScanThread::scanoption) + { + bool found = ScanThread::ButtonPressed(0); + if (!found) + ButtonStateImpulse(TranslateXtoMKB::Amapping, true, 0);//down + } + else ButtonStateImpulse(TranslateXtoMKB::Amapping, true, 0); + TranslateXtoMKB::RefreshPoint = 2; + } + + + if (oldB) + { + if (buttons & XINPUT_GAMEPAD_B) + { + } + else { + oldB = false; + ButtonStateImpulse(TranslateXtoMKB::Bmapping, false,1);//release + } + } + else if (buttons & XINPUT_GAMEPAD_B) + { + oldB = true; + if (ScanThread::scanoption && modeMT != 2) + { + bool found = ScanThread::ButtonPressed(1); + if (!found) + ButtonStateImpulse(TranslateXtoMKB::Bmapping, true, 1);//down + } + else ButtonStateImpulse(TranslateXtoMKB::Bmapping, true, 1);//down + TranslateXtoMKB::RefreshPoint = 2; + } + + + if (oldX) + { + if (buttons & XINPUT_GAMEPAD_X) + { + } + else { + oldX = false; + ButtonStateImpulse(TranslateXtoMKB::Xmapping, false, 2);//release + } + } + else if (buttons & XINPUT_GAMEPAD_X) + { + oldX = true; + if (ScanThread::scanoption && modeMT != 2) + { + bool found = ScanThread::ButtonPressed(2); + if (!found) + ButtonStateImpulse(TranslateXtoMKB::Xmapping, true, 2);//down + } + else ButtonStateImpulse(TranslateXtoMKB::Xmapping, true, 2);//down + TranslateXtoMKB::RefreshPoint = 2; + } + + + if (oldY) + { + if (buttons & XINPUT_GAMEPAD_Y) + { + } + else { + oldY = false; + ButtonStateImpulse(TranslateXtoMKB::Ymapping, false, 3);//release + } + } + else if (buttons & XINPUT_GAMEPAD_Y) + { + oldY = true; + if (ScanThread::scanoption && modeMT != 2) + { + bool found = ScanThread::ButtonPressed(3); + if (!found) + ButtonStateImpulse(TranslateXtoMKB::Ymapping, true, 3);//down + } + else ButtonStateImpulse(TranslateXtoMKB::Ymapping, true, 3);//down + TranslateXtoMKB::RefreshPoint = 2; + } + + + if (oldC) + { + if (buttons & XINPUT_GAMEPAD_RIGHT_SHOULDER) + { + } + else { + oldC = false; + ButtonStateImpulse(TranslateXtoMKB::RSmapping, false, 99); //release + } + } + else if (buttons & XINPUT_GAMEPAD_RIGHT_SHOULDER) + { + oldC = true; + if (ScanThread::scanoption) + { + bool found = ScanThread::ButtonPressed(4); + if (!found) + ButtonStateImpulse(TranslateXtoMKB::RSmapping, true, 99); //down + } + else ButtonStateImpulse(TranslateXtoMKB::RSmapping, true, 99); //down + TranslateXtoMKB::RefreshPoint = 10; + } + + + if (oldD) + { + if (buttons & XINPUT_GAMEPAD_LEFT_SHOULDER) + { + } + else { + oldD = false; + ButtonStateImpulse(TranslateXtoMKB::LSmapping, false, 99);//release + } + } + else if (buttons & XINPUT_GAMEPAD_LEFT_SHOULDER) + { + oldD = true; + if (ScanThread::scanoption) + { + bool found = ScanThread::ButtonPressed(5); + if (!found) + ButtonStateImpulse(TranslateXtoMKB::LSmapping, true, 99);//down + } + else ButtonStateImpulse(TranslateXtoMKB::LSmapping, true, 99);//down + TranslateXtoMKB::RefreshPoint = 10; + } + + + if (oldleft) + { + if (buttons & XINPUT_GAMEPAD_DPAD_LEFT) + { + } + else { + oldleft = false; + ButtonStateImpulse(TranslateXtoMKB::leftmapping, false, 99); //release + } + } + else if (buttons & XINPUT_GAMEPAD_DPAD_LEFT) + { + oldleft = true; + ButtonStateImpulse(TranslateXtoMKB::leftmapping, true, 99);//down + } + + + if (oldright) + { + if (buttons & XINPUT_GAMEPAD_DPAD_RIGHT) + { + } + else { + oldright = false; + ButtonStateImpulse(TranslateXtoMKB::rightmapping, false, 99);//release + } + } + else if (buttons & XINPUT_GAMEPAD_DPAD_RIGHT) + { + oldright = true; + ButtonStateImpulse(TranslateXtoMKB::rightmapping, true, 99);//down + } + + + + + if (oldstartoptions) //toggle fake cursor + { + if (oldstart && oldoptions) + { + } + else + { + oldstartoptions = false; + } + } + else if (oldstart && oldoptions)//fake cursor toggle + { + Proto::FakeCursor::SetCursorVisibility(!Proto::FakeCursor::GetCursorVisibility()); + Proto::FakeCursor::Showmessage = 3; + TranslateXtoMKB::RefreshPoint = 1; + tick = 0; + oldstartoptions = true; + } + if (oldstart) + { + + if (buttons & XINPUT_GAMEPAD_START) + { + if (startbuttontimer < 1500) //delay setting menu. hold button to show + startbuttontimer++; + else + { + Proto::FakeCursor::Showmessage = 7; //adjust sensitivity + TranslateXtoMKB::RefreshPoint = 1; + } + } + else { + Proto::FakeCursor::Showmessage = 0; //adjust sensitivity + TranslateXtoMKB::RefreshPoint = 1; + oldstart = false; + ButtonStateImpulse(TranslateXtoMKB::startmapping, false, 99);//release + } + } + else if (buttons & XINPUT_GAMEPAD_START) + { + startbuttontimer = 0; + oldstart = true; + ButtonStateImpulse(TranslateXtoMKB::startmapping, true, 99);//down + + } + + if (oldoptions) + { + if (buttons & XINPUT_GAMEPAD_BACK) + { + if (backbuttontimer < 1500) + backbuttontimer ++; + else + { + Proto::FakeCursor::Showmessage = 6; //adjust sensitivity + TranslateXtoMKB::RefreshPoint = 1; + } + } + else { + Proto::FakeCursor::Showmessage = 0; //adjust sensitivity + TranslateXtoMKB::RefreshPoint = 1; + oldoptions = false; + ButtonStateImpulse(TranslateXtoMKB::optionmapping, false, 99);//release + } + } + else if (buttons & XINPUT_GAMEPAD_BACK) + { + backbuttontimer = 0; + oldoptions = true; + ButtonStateImpulse(TranslateXtoMKB::optionmapping, true, 99);//down + } + if (oldup) + { + if (buttons & XINPUT_GAMEPAD_DPAD_UP) + { + } + else { + if (Proto::FakeCursor::Showmessage == 6) + { + if (TranslateXtoMKB::Sens < 50) + { + TranslateXtoMKB::Sens++; + Proto::FakeCursor::Showmessage = 0; + ScreenshotInput::TranslateXtoMKB::RefreshPoint = 1; + } + } + if (Proto::FakeCursor::Showmessage == 7) + { + if (TranslateXtoMKB::Sensmult < 50) + { + TranslateXtoMKB::Sensmult++; + Proto::FakeCursor::Showmessage = 0; + ScreenshotInput::TranslateXtoMKB::RefreshPoint = 1; + } + } + oldup = false; + ButtonStateImpulse(TranslateXtoMKB::upmapping, false, 99);//release + } + } + else if (buttons & XINPUT_GAMEPAD_DPAD_UP) + { + oldup = true; + ButtonStateImpulse(TranslateXtoMKB::upmapping, true, 99);//down + } + + + if (olddown) + { + if (buttons & XINPUT_GAMEPAD_DPAD_DOWN) + { + } + else + { + if (Proto::FakeCursor::Showmessage == 6) + { + if (TranslateXtoMKB::Sens > 1) + { + TranslateXtoMKB::Sens--; + Proto::FakeCursor::Showmessage = 0; + ScreenshotInput::TranslateXtoMKB::RefreshPoint = 1; + } + } + if (Proto::FakeCursor::Showmessage == 7) + { + if (TranslateXtoMKB::Sensmult > 1) + { + TranslateXtoMKB::Sensmult--; + Proto::FakeCursor::Showmessage = 0; + ScreenshotInput::TranslateXtoMKB::RefreshPoint = 1; + } + } + olddown = false; + ButtonStateImpulse(TranslateXtoMKB::downmapping, false, 99);//release + } + } + else if (buttons & XINPUT_GAMEPAD_DPAD_DOWN) + { + olddown = true; + ButtonStateImpulse(TranslateXtoMKB::downmapping, true, 99);//down + } + } //if mode above 0 + } //if controller + else { //no controller + Proto::FakeCursor::Showmessage = 1; + TranslateXtoMKB::RefreshPoint = 1; + tick = 0; + } + if (tick < updatewindowtick) + tick++; + else { //need to update hwnd and bounds periodically + // EnterCriticalSection(&ScanThread::critical); + Proto::HwndSelector::UpdateMainHwnd(false); + Proto::HwndSelector::UpdateWindowBounds(); + TranslateXtoMKB::RefreshPoint = 1; + tick = 0; + } + + if (Proto::FakeCursor::Showmessage != 0 && Proto::FakeCursor::Showmessage != 6 && Proto::FakeCursor::Showmessage != 7) { //drawing messages or something + if (counter < 1000) { + counter++; + } + else { + Proto::FakeCursor::Showmessage = 0; + TranslateXtoMKB::RefreshPoint = 1; + counter = 0; + } + } + if (!ScanThread::scanoption) + { + // Proto::FakeCursor::Showmessage = TranslateXtoMKB::showmessage; + } + if (modeMT > 0) { + Sleep(1); + } + else Sleep(10); + + + return; + } + + void TranslateXtoMKB::Initialize(HMODULE hModule) + { + g_hModule = hModule; + InstanceID = Proto::StateInfo::info.instanceIndex; + Proto::AddThreadToACL(GetCurrentThreadId()); + //Sleep(50); + return; + } +} \ No newline at end of file diff --git a/src/ProtoInput/ProtoInputHooks/TranslateXtoMKB.h b/src/ProtoInput/ProtoInputHooks/TranslateXtoMKB.h new file mode 100644 index 0000000..8f07bf4 --- /dev/null +++ b/src/ProtoInput/ProtoInputHooks/TranslateXtoMKB.h @@ -0,0 +1,49 @@ +#pragma once +#include "Hook.h" +#include "InstallHooks.h" + +namespace ScreenshotInput +{ + + class TranslateXtoMKB + { + private: + // static bool usetraqnslation; + + public: + static void Initialize(HMODULE g_hModule); + static void ThreadFunction(); //polling from idle drawfakecursor thread + static void SendMouseClick(int x, int y, int z); + static int RefreshWindow; + static int RefreshPoint; + static int controllerID; + static bool rawinputhook; + static bool registerrawinputhook; + //static int showmessage; + static int mode; + static int Amapping; + static int Bmapping; + static int Xmapping; + static int Ymapping; + static int RSmapping; + static int LSmapping; + static int rightmapping; + static int leftmapping; + static int upmapping; + static int downmapping; + static int stickRpressmapping; + static int stickLpressmapping; + static int stickrightmapping; + static int stickleftmapping; + static int stickupmapping; + static int stickdownmapping; + static int optionmapping; + static int startmapping; + static bool lefthanded; + static int Sens; + static int Sensmult; + static int Deadzone; + static bool SaveBmps; + }; + +} \ No newline at end of file diff --git a/src/ProtoInput/ProtoInputHooks/WindowMsgHook.cpp b/src/ProtoInput/ProtoInputHooks/WindowMsgHook.cpp new file mode 100644 index 0000000..8c47049 --- /dev/null +++ b/src/ProtoInput/ProtoInputHooks/WindowMsgHook.cpp @@ -0,0 +1,395 @@ +#include "WindowMsgHook.h" +#include "FakeMouseKeyboard.h" +#include "HwndSelector.h" +#include "SetWindowPosHook.h" +#include +#include +#include "windowsx.h" +#pragma comment(lib, "dwmapi.lib") + + +namespace Proto +{ + int scalewidth = 0; + int scaleheight = 0; + int origwidth = 0; + int origheight = 0; + + bool Enableornot = false; + bool onlyonetimethis = false; + bool scalenotpointer = false; + + WNDPROC g_OldWndProc = nullptr; + + WPARAM defaultmove = 0x00060001; + WPARAM primary = 0x00100000; + WPARAM secondary = 0x00200000; + WPARAM third = 0x00400000; + WPARAM fourth = 0x00800000; + WPARAM fifth = 0x01000000; + + int now = 0; + bool leftdown, rightdown = false; + bool tredown, firdown, femdown = false; + + void UninstallWndProc() + { + if (onlyonetimethis) + { + HWND hwnd = (HWND)Proto::HwndSelector::GetSelectedHwnd(); + SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG_PTR)g_OldWndProc); + onlyonetimethis = false; + } + } + + void WindowMsgHook::Uninstall() + { + UninstallWndProc(); + } + + WPARAM updatePointer(bool pressed, WPARAM button) + { + WPARAM returned; + + returned = button; + + if (returned == primary) + { + // wParam = defaultmove; + if (rightdown) returned += secondary; + if (tredown) returned += third; + if (firdown) returned += fourth; + if (femdown) returned += fifth; + } + else if (returned == secondary) + { + if (leftdown) returned += primary; + if (tredown) returned += third; + if (firdown) returned += fourth; + if (femdown) returned += fifth; + } + else if (returned == third) + { + if (leftdown) returned += primary; + if (rightdown) returned += secondary; + if (firdown) returned += fourth; + if (femdown) returned += fifth; + } + else if (returned == fourth) + { + if (leftdown) returned += primary; + if (rightdown) returned += secondary; + if (tredown) returned += third; + if (femdown) returned += fifth; + } + else if (returned == fifth) + { + if (leftdown) returned += primary; + if (rightdown) returned += secondary; + if (tredown) returned += third; + if (firdown) returned += fourth; + } + if (pressed) + returned += defaultmove; + else + returned += 0x00020001; + + return returned; + } + + POINT WindowMsgHook::getfactor(POINT pp) + { + if (pp.x != 0 && pp.y != 0 && Enableornot) + { + float scalex = float(origwidth) / float(scalewidth); + float scaley = float(origheight) / float(scaleheight); + pp.x = static_cast(std::lround(pp.x * scalex)); + pp.y = static_cast(std::lround(pp.y * scaley)); + } + return pp; + } + + LPARAM GetScaledLParam(HWND hwnd, bool clienttoscreen) + { + const auto& state = Proto::FakeMouseKeyboard::GetMouseState(); + POINT clientPos = { state.x, state.y }; + clientPos = WindowMsgHook::getfactor(clientPos); + if (clienttoscreen) + ClientToScreen(hwnd, &clientPos); + return MAKELPARAM(clientPos.x, clientPos.y); + } + + LPARAM ProcessedLparam(LPARAM lParam, HWND hwnd, bool clienttoscreen) + { + POINT clientPos = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) }; + if (clienttoscreen) + ClientToScreen(hwnd, &clientPos); + return MAKELPARAM(clientPos.x, clientPos.y); + } + + LRESULT CALLBACK SubclassProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) + { + switch (msg) + { + + case WM_MOUSEMOVE: + { + if (scalenotpointer) + return CallWindowProc(g_OldWndProc, hwnd, msg, wParam, GetScaledLParam(hwnd, false)); + + msg = WM_POINTERUPDATE; + + if (!leftdown && !rightdown && !tredown && !firdown && !femdown) + wParam = 0x20020001; + else + { + wParam = defaultmove; + if (leftdown) wParam += primary; + if (rightdown) wParam += secondary; + if (tredown) wParam += third; + if (firdown) wParam += fourth; + if (femdown) wParam += fifth; + } + return CallWindowProc(g_OldWndProc, hwnd, msg, wParam, ProcessedLparam(lParam, hwnd, true)); + } + case WM_LBUTTONDOWN: + { + if (scalenotpointer) + return CallWindowProc(g_OldWndProc, hwnd, msg, wParam, GetScaledLParam(hwnd, false)); + + leftdown = true; + if (!rightdown && !tredown && !firdown && !femdown) + { + wParam = 0x20160001; + msg = WM_POINTERDOWN; + } + else { + wParam = updatePointer(true, primary); + msg = WM_POINTERUPDATE; + } + return CallWindowProc(g_OldWndProc, hwnd, msg, wParam, ProcessedLparam(lParam, hwnd, true)); + } + case WM_LBUTTONUP: + { + if (scalenotpointer) + return CallWindowProc(g_OldWndProc, hwnd, msg, wParam, GetScaledLParam(hwnd, false)); + leftdown = false; + if (!rightdown && !tredown && !firdown && !femdown) + { + wParam = 0x00020001; + msg = WM_POINTERUP; + } + else { + wParam = updatePointer(false, primary); + msg = WM_POINTERUPDATE; + } + return CallWindowProc(g_OldWndProc, hwnd, msg, wParam, ProcessedLparam(lParam, hwnd, true)); + } + case WM_RBUTTONDOWN: + { + if (scalenotpointer) + return CallWindowProc(g_OldWndProc, hwnd, msg, wParam, GetScaledLParam(hwnd, false)); + rightdown = true; + if (!leftdown && !tredown && !firdown && !femdown) + { + wParam = 0x20260001; + msg = WM_POINTERDOWN; + } + else { + wParam = updatePointer(true, secondary); + msg = WM_POINTERUPDATE; + } + return CallWindowProc(g_OldWndProc, hwnd, msg, wParam, ProcessedLparam(lParam, hwnd, true)); + } + case WM_RBUTTONUP: + { + if (scalenotpointer) + return CallWindowProc(g_OldWndProc, hwnd, msg, wParam, GetScaledLParam(hwnd, false)); + rightdown = false; + if (!leftdown && !tredown && !firdown && !femdown) + { + wParam = 0x00020001; + msg = WM_POINTERUP; + } + else { + wParam = updatePointer(false, secondary); + msg = WM_POINTERUPDATE; + } + return CallWindowProc(g_OldWndProc, hwnd, msg, wParam, ProcessedLparam(lParam, hwnd, true)); + } + case WM_MBUTTONDOWN: + { + if (scalenotpointer) + return CallWindowProc(g_OldWndProc, hwnd, msg, wParam, GetScaledLParam(hwnd, false)); + tredown = true; + if (!rightdown && !leftdown && !firdown && !femdown) + { + wParam = 0x20460001; + msg = WM_POINTERDOWN; + } + else { + wParam = updatePointer(true, third); + msg = WM_POINTERUPDATE; + } + return CallWindowProc(g_OldWndProc, hwnd, msg, wParam, ProcessedLparam(lParam, hwnd, true)); + } + case WM_MBUTTONUP: + { + if (scalenotpointer) + return CallWindowProc(g_OldWndProc, hwnd, msg, wParam, GetScaledLParam(hwnd, false)); + tredown = false; + if (!rightdown && !leftdown && !firdown && !femdown) + { + wParam = 0x00020001; + msg = WM_POINTERUP; + } + else { + wParam = updatePointer(false, third); + msg = WM_POINTERUPDATE; + } + + return CallWindowProc(g_OldWndProc, hwnd, msg, wParam, ProcessedLparam(lParam, hwnd, true)); + } + + case WM_XBUTTONDOWN: + { + if (scalenotpointer) + return CallWindowProc(g_OldWndProc, hwnd, msg, wParam, GetScaledLParam(hwnd, false)); + int fwButton = GET_XBUTTON_WPARAM(wParam); + if (fwButton == XBUTTON1) + { + firdown = true; + if (!rightdown && !leftdown && !tredown && !femdown) + { + wParam = 0x20860001; + msg = WM_POINTERDOWN; + } + else + { + wParam = updatePointer(true, fourth); + msg = WM_POINTERUPDATE; + } + } + else if (fwButton == XBUTTON2) + { + if (scalenotpointer) + return CallWindowProc(g_OldWndProc, hwnd, msg, wParam, GetScaledLParam(hwnd, false)); + femdown = true; + if (!rightdown && !leftdown && !tredown && !firdown) + { + wParam = 0x21060001; + msg = WM_POINTERDOWN; + } + else { + wParam = updatePointer(true, fifth); + msg = WM_POINTERUPDATE; + } + } + else return CallWindowProc(g_OldWndProc, hwnd, msg, wParam, lParam); //fwbutton unrecongnized + + return CallWindowProc(g_OldWndProc, hwnd, msg, wParam, ProcessedLparam(lParam, hwnd, true)); + } + case WM_XBUTTONUP: + { + if (scalenotpointer) + return CallWindowProc(g_OldWndProc, hwnd, msg, wParam, GetScaledLParam(hwnd, false)); + int fwButton = GET_XBUTTON_WPARAM(wParam); + if (fwButton == XBUTTON1) + { + firdown = false; + if (!rightdown && !leftdown && !tredown && !femdown) + { + msg = WM_POINTERUP; + wParam = 0x00020001; + } + else { + wParam = updatePointer(false, fourth); + msg = WM_POINTERUPDATE; + } + } + else if (fwButton == XBUTTON2) + { + femdown = false; + if (!rightdown && !leftdown && !tredown && !firdown) + { + msg = WM_POINTERUP; + wParam = 0x00020001; + } + else { + wParam = updatePointer(false, fifth); + msg = WM_POINTERUPDATE; + } + } + else return CallWindowProc(g_OldWndProc, hwnd, msg, wParam, lParam); //none of these buttons? + + return CallWindowProc(g_OldWndProc, hwnd, msg, wParam, ProcessedLparam(lParam, hwnd, true)); + } + case WM_MOUSEWHEEL: + { + if (scalenotpointer) + return CallWindowProc(g_OldWndProc, hwnd, msg, wParam, GetScaledLParam(hwnd, true)); //client coordinates + + msg = WM_POINTERWHEEL; + + return CallWindowProc(g_OldWndProc, hwnd, msg, wParam, lParam); //lParam should be screen coordinates already and that is correct + } + + //less cpu usage blocking these here i guess as the wndproc is already hooked + case WM_POINTERLEAVE: + case WM_POINTERCAPTURECHANGED: //POINTERCAPTURECHANGED is not listed in proto yet + case WM_MOUSELEAVE: + { + return 0; + } + case WM_QUIT: + { + UninstallWndProc(); + return CallWindowProc(g_OldWndProc, hwnd, msg, wParam, lParam); + } + }//end of switch + return CallWindowProc(g_OldWndProc, hwnd, msg, wParam, lParam); + } + + void WindowMsgHook::Install() + { + if (Enableornot && !onlyonetimethis) + { + g_OldWndProc = (WNDPROC)SetWindowLongPtr( + (HWND)Proto::HwndSelector::GetSelectedHwnd(), + GWLP_WNDPROC, + (LONG_PTR)SubclassProc + ); + onlyonetimethis = true; //or else crash + } + } + + + void WindowMsgHook::Settings(int oldX, int oldY, int newX, int newY) + { + Enableornot = true; + + scalewidth = newX; + scaleheight = newY; + origwidth = oldX; + origheight = oldY; + + //validating settings + if (scalewidth > 5 && scaleheight > 5 && origwidth > 5 && origheight > 5) + { + scalenotpointer = true; + Enableornot = true; + } + else Enableornot = false; + if (Enableornot) + WindowMsgHook::Install(); + } + void WindowMsgHook::PointerInMouse( bool enable) + { + + scalenotpointer = false; + Enableornot = enable; + if (enable) + WindowMsgHook::Install(); + else WindowMsgHook::Uninstall(); + } +} diff --git a/src/ProtoInput/ProtoInputHooks/WindowMsgHook.h b/src/ProtoInput/ProtoInputHooks/WindowMsgHook.h new file mode 100644 index 0000000..f62119f --- /dev/null +++ b/src/ProtoInput/ProtoInputHooks/WindowMsgHook.h @@ -0,0 +1,21 @@ +#pragma once +#include "Hook.h" +#include "InstallHooks.h" + +namespace Proto +{ + + class WindowMsgHook + { + private: + static void Install(); + static void Uninstall(); + + public: + static POINT getfactor(POINT pp); + + static void PointerInMouse(bool enable); //convert mouse message to pointer message + static void Settings(int oldX, int oldY, int newX, int newY); //scale up or down messages + }; + +} diff --git a/src/ProtoInput/ProtoInputHooks/XinputHook.cpp b/src/ProtoInput/ProtoInputHooks/XinputHook.cpp index 5764340..5c830a3 100644 --- a/src/ProtoInput/ProtoInputHooks/XinputHook.cpp +++ b/src/ProtoInput/ProtoInputHooks/XinputHook.cpp @@ -5,6 +5,8 @@ #include "Gui.h" #include #include "OpenXinputWrapper.h" +#include "FakeMouseKeyboard.h" +#include "TranslateXtoMKB.h" namespace Proto @@ -14,6 +16,8 @@ constexpr LONG DINPUT_RANGE_MAX = 32767; constexpr LONG DINPUT_RANGE_MIN = -32768; bool XinputHook::useDinput = false; bool XinputHook::useOpenXinput = false; +bool XinputHook::TranslateMKBtoXinput = false; + IDirectInputDevice8W* dinputDevice = nullptr; GUID dinputDeviceGuid{}; std::wstring dinputDeviceName{}; @@ -72,36 +76,264 @@ inline std::pair GetTargetControllerIndex(DWORD dwUserIndex) return { false, 0 }; } -inline DWORD WINAPI XInputGetState_Inline(DWORD dwUserIndex, XINPUT_STATE* pState, bool extended) +bool IsKeyPressed(int Vkey) +{ + return FakeMouseKeyboard::IsKeyStatePressed(Vkey); +} +POINT deltaL; +POINT deltaR; +bool oldA, oldB, oldX, oldY, oldtriggerleft, oldtriggerright, oldLS, oldRS, oldup, olddown, oldleft, oldright; +bool oldstart, oldback, oldstickRB, oldstickLB; +bool firstcall = false; +DWORD fakedwpacketnumber = 0; +bool changed; +SHORT LaxisX, LaxisY, RaxisX, RaxisY; +SHORT deadzone = 14000; +POINT axisvaluemouse(SHORT currentX, SHORT currentY) +{ + const auto& mousestate = FakeMouseKeyboard::GetMouseState(); + POINT Pos = { mousestate.x - 100, mousestate.y - 100}; + + int dx = Pos.x * (2 * ScreenshotInput::TranslateXtoMKB::Sens); + int dy = -Pos.y * (2 * ScreenshotInput::TranslateXtoMKB::Sens); + if (dx != 0 || dy != 0) + { + if (currentX + dx > 32767) currentX = 32767; + else if (currentX + dx < -32767) currentX = -32767; + else currentX += dx; + + if (currentY + dy > 32767) currentY = 32767; + else if (currentY + dy< -32767) currentY = -32767; + else currentY += dy; + changed = true; + FakeMouseKeyboard::SetMousePos(100, 100); + } + + POINT returnaxis; + returnaxis.x = currentX; + returnaxis.y = currentY; + return returnaxis; +} +SHORT axisvaluebutton(SHORT currentvalue, BOOL upkey, BOOL downkey) { + SHORT diditchange = currentvalue; + if (upkey && !downkey) + { + //jump to above deadzone + if (currentvalue < deadzone) + currentvalue = deadzone; + + //increase or stall at max + if (currentvalue + (7 * ScreenshotInput::TranslateXtoMKB::Sens) < 32767) + currentvalue = currentvalue + (7 * ScreenshotInput::TranslateXtoMKB::Sens); + else currentvalue = 32767; + } + if (downkey && !upkey) + { + //jump to above dead + if (currentvalue > -deadzone) + currentvalue = -deadzone; + + //increase or stall + if (currentvalue - (7 * ScreenshotInput::TranslateXtoMKB::Sens) > -32767) + currentvalue = currentvalue - (7 * ScreenshotInput::TranslateXtoMKB::Sens); + else currentvalue = -32767; + } + //drift to 0 + if (!downkey && !upkey) + { + if (currentvalue > 0 + (7 * ScreenshotInput::TranslateXtoMKB::Sens)) + currentvalue = currentvalue - (7 * ScreenshotInput::TranslateXtoMKB::Sens); + else currentvalue = 0; + + if (currentvalue < 0 - (7 * ScreenshotInput::TranslateXtoMKB::Sens)) + currentvalue = currentvalue + (7 * ScreenshotInput::TranslateXtoMKB::Sens); + else currentvalue = 0; + } + if (diditchange != currentvalue) + changed = true; + return currentvalue; +} +void FillXbuttons(XINPUT_STATE* pState) +{ + //triggers + if (IsKeyPressed(VK_RBUTTON)) { + pState->Gamepad.bLeftTrigger = 255; + } + else { + pState->Gamepad.bLeftTrigger = 0; + } + + if (IsKeyPressed(VK_LBUTTON)) { + pState->Gamepad.bRightTrigger = 255; + } + else { + pState->Gamepad.bRightTrigger = 0; + } + + //bool buttons + if (IsKeyPressed(ScreenshotInput::TranslateXtoMKB::Amapping)) + pState->Gamepad.wButtons |= XINPUT_GAMEPAD_A; + + if (IsKeyPressed(ScreenshotInput::TranslateXtoMKB::Bmapping)) + pState->Gamepad.wButtons |= XINPUT_GAMEPAD_B; + + if (IsKeyPressed(ScreenshotInput::TranslateXtoMKB::Ymapping)) + pState->Gamepad.wButtons |= XINPUT_GAMEPAD_Y; + + if (IsKeyPressed(ScreenshotInput::TranslateXtoMKB::Xmapping)) + pState->Gamepad.wButtons |= XINPUT_GAMEPAD_X; + + if (IsKeyPressed(ScreenshotInput::TranslateXtoMKB::LSmapping)) + pState->Gamepad.wButtons |= XINPUT_GAMEPAD_LEFT_SHOULDER; + + if (IsKeyPressed(ScreenshotInput::TranslateXtoMKB::RSmapping)) + pState->Gamepad.wButtons |= XINPUT_GAMEPAD_RIGHT_SHOULDER; + + if (IsKeyPressed(ScreenshotInput::TranslateXtoMKB::upmapping)) + pState->Gamepad.wButtons |= XINPUT_GAMEPAD_DPAD_UP; + + if (IsKeyPressed(ScreenshotInput::TranslateXtoMKB::downmapping)) + pState->Gamepad.wButtons |= XINPUT_GAMEPAD_DPAD_DOWN; + + if (IsKeyPressed(ScreenshotInput::TranslateXtoMKB::leftmapping)) + pState->Gamepad.wButtons |= XINPUT_GAMEPAD_DPAD_LEFT; + + if (IsKeyPressed(ScreenshotInput::TranslateXtoMKB::rightmapping)) + pState->Gamepad.wButtons |= XINPUT_GAMEPAD_DPAD_RIGHT; + + if (IsKeyPressed(ScreenshotInput::TranslateXtoMKB::startmapping)) + pState->Gamepad.wButtons |= XINPUT_GAMEPAD_START; + + if (IsKeyPressed(ScreenshotInput::TranslateXtoMKB::optionmapping)) + pState->Gamepad.wButtons |= XINPUT_GAMEPAD_BACK; +} +inline DWORD WINAPI XInputfromkbm(DWORD dwUserIndex, XINPUT_STATE* pState, bool extended) +{ + deadzone = 1000 + (ScreenshotInput::TranslateXtoMKB::Deadzone * 3000); if (extended) getStateExCounter++; else getStateCounter++; - auto [ connected, targetControllerIndex ] = GetTargetControllerIndex(dwUserIndex); - - if (!connected) - return ERROR_DEVICE_NOT_CONNECTED; + pState->Gamepad.wButtons = 0; - if (XinputHook::useOpenXinput) + if (!firstcall) { - return OpenXinput::ProtoOpenXinputGetState(targetControllerIndex, pState, extended); + FakeMouseKeyboard::SetMousePos(100, 100); + pState->Gamepad.sThumbLY = 0; + pState->Gamepad.sThumbLX = 0; + pState->Gamepad.sThumbRY = 0; + pState->Gamepad.sThumbRX = 0; + firstcall = true; } - if (!XinputHook::GetUseDinput()) + RaxisX = axisvaluebutton(RaxisX, IsKeyPressed(ScreenshotInput::TranslateXtoMKB::stickleftmapping), IsKeyPressed(ScreenshotInput::TranslateXtoMKB::stickrightmapping)); + RaxisY = axisvaluebutton(RaxisY, IsKeyPressed(ScreenshotInput::TranslateXtoMKB::stickupmapping), IsKeyPressed(ScreenshotInput::TranslateXtoMKB::stickdownmapping)); + + POINT mouseaxis = axisvaluemouse(LaxisX, LaxisY); + LaxisX = mouseaxis.x; + LaxisY = mouseaxis.y; + + + + FillXbuttons(pState); + + + //normal buttons + + + + if (ScreenshotInput::TranslateXtoMKB::lefthanded) { - if (extended && XInputGetStateExPtr != nullptr) - { - return XInputGetStateExPtr(targetControllerIndex, pState); - } - return XInputGetStatePtr(targetControllerIndex, pState); + pState->Gamepad.sThumbLY = LaxisY; + pState->Gamepad.sThumbLX = LaxisX; + pState->Gamepad.sThumbRY = RaxisY; + pState->Gamepad.sThumbRX = RaxisX; + } + else { + pState->Gamepad.sThumbLY = RaxisY; + pState->Gamepad.sThumbLX = RaxisX; + pState->Gamepad.sThumbRY = LaxisY; + pState->Gamepad.sThumbRX = LaxisX; + } + + //increase dwpacketnumber if statechange + if (changed == false) + { + changed = + oldA != IsKeyPressed(ScreenshotInput::TranslateXtoMKB::Amapping) || + oldB != IsKeyPressed(ScreenshotInput::TranslateXtoMKB::Bmapping) || + oldX != IsKeyPressed(ScreenshotInput::TranslateXtoMKB::Xmapping) || + oldY != IsKeyPressed(ScreenshotInput::TranslateXtoMKB::Ymapping) || + oldtriggerleft != IsKeyPressed(0x4F) || + oldtriggerright != IsKeyPressed(0x50) || + oldLS != IsKeyPressed(ScreenshotInput::TranslateXtoMKB::LSmapping) || + oldRS != IsKeyPressed(ScreenshotInput::TranslateXtoMKB::RSmapping) || + oldup != IsKeyPressed(ScreenshotInput::TranslateXtoMKB::upmapping) || + olddown != IsKeyPressed(ScreenshotInput::TranslateXtoMKB::downmapping) || + oldleft != IsKeyPressed(ScreenshotInput::TranslateXtoMKB::leftmapping) || + + oldstart != IsKeyPressed(ScreenshotInput::TranslateXtoMKB::startmapping) || + oldback != IsKeyPressed(ScreenshotInput::TranslateXtoMKB::optionmapping) || + oldstickRB != IsKeyPressed(ScreenshotInput::TranslateXtoMKB::stickRpressmapping) || + oldstickLB != IsKeyPressed(ScreenshotInput::TranslateXtoMKB::stickLpressmapping) || + + oldright != IsKeyPressed(ScreenshotInput::TranslateXtoMKB::rightmapping); + } + if (changed) + { + pState->dwPacketNumber++; + changed = false; } + + oldA = IsKeyPressed(ScreenshotInput::TranslateXtoMKB::Amapping); + oldB = IsKeyPressed(ScreenshotInput::TranslateXtoMKB::Bmapping); + oldX = IsKeyPressed(ScreenshotInput::TranslateXtoMKB::Xmapping); + oldY = IsKeyPressed(ScreenshotInput::TranslateXtoMKB::Ymapping); + + oldLS = IsKeyPressed(ScreenshotInput::TranslateXtoMKB::LSmapping); + oldRS = IsKeyPressed(ScreenshotInput::TranslateXtoMKB::RSmapping); + oldup = IsKeyPressed(ScreenshotInput::TranslateXtoMKB::upmapping); + olddown = IsKeyPressed(ScreenshotInput::TranslateXtoMKB::downmapping); + oldleft = IsKeyPressed(ScreenshotInput::TranslateXtoMKB::leftmapping); + oldright = IsKeyPressed(ScreenshotInput::TranslateXtoMKB::rightmapping); + + oldstart = IsKeyPressed(ScreenshotInput::TranslateXtoMKB::startmapping); + oldback = IsKeyPressed(ScreenshotInput::TranslateXtoMKB::optionmapping); + oldstickRB = IsKeyPressed(ScreenshotInput::TranslateXtoMKB::stickRpressmapping); + oldstickLB != IsKeyPressed(ScreenshotInput::TranslateXtoMKB::stickLpressmapping); + + oldtriggerleft = IsKeyPressed(VK_RBUTTON); + oldtriggerright = IsKeyPressed(VK_LBUTTON); + + + return ERROR_SUCCESS; + +} +inline DWORD WINAPI GetCapabilitiesfromkbm(DWORD dwUserIndex, DWORD dwFlags, XINPUT_CAPABILITIES* pCapabilities) +{ + XINPUT_STATE state{}; + XInputfromkbm(dwUserIndex, &state, false); + + pCapabilities->Gamepad = state.Gamepad; + //pCapabilities->Flags = 0; + pCapabilities->SubType = XINPUT_DEVSUBTYPE_GAMEPAD; + pCapabilities->Type = XINPUT_DEVTYPE_GAMEPAD; + pCapabilities->Vibration.wLeftMotorSpeed = 0; + pCapabilities->Vibration.wRightMotorSpeed = 0; + return ERROR_SUCCESS; +} + +inline DWORD WINAPI XInputGetStateDinput_Inline(DWORD dwUserIndex, XINPUT_STATE* pState, bool extended) +{ + if (dinputDevice == nullptr) return ERROR_DEVICE_NOT_CONNECTED; + //WORK TODO TO DO is this an error? it is supposed to increase on statechange. doesnt look correct now? static DWORD packetNumber = 0; - pState->dwPacketNumber = packetNumber++; + pState->dwPacketNumber = packetNumber++; // memset(&(pState->Gamepad), 0, extended ? sizeof(XINPUT_GAMEPAD_EX) : sizeof(XINPUT_GAMEPAD)); dinputDevice->Poll(); DIJOYSTATE2 diState; @@ -152,17 +384,64 @@ inline DWORD WINAPI XInputGetState_Inline(DWORD dwUserIndex, XINPUT_STATE* pStat #undef TRIGGERDEADZONE return ERROR_SUCCESS; } + +inline DWORD WINAPI XInputGetState_Inline(DWORD dwUserIndex, XINPUT_STATE* pState, bool extended) +{ + if (extended) + getStateExCounter++; + else + getStateCounter++; + + auto [ connected, targetControllerIndex ] = GetTargetControllerIndex(dwUserIndex); + + if (!connected) + return ERROR_DEVICE_NOT_CONNECTED; + + if (XinputHook::useOpenXinput) + { + return OpenXinput::ProtoOpenXinputGetState(targetControllerIndex, pState, extended); + } + + if (!XinputHook::GetUseDinput()) + { + if (extended && XInputGetStateExPtr != nullptr) + { + return XInputGetStateExPtr(targetControllerIndex, pState); + } + return XInputGetStatePtr(targetControllerIndex, pState); + } + return XInputGetStateDinput_Inline(targetControllerIndex, pState, extended); +} + + + DWORD WINAPI Hook_XInputGetState(DWORD dwUserIndex, XINPUT_STATE* pState) { - return XInputGetState_Inline(dwUserIndex, pState, false); + if (!XinputHook::TranslateMKBtoXinput) + return XInputGetState_Inline(dwUserIndex, pState, false); + else if ((dwUserIndex == 0 && XinputHook::controllerIndex == 0) || (dwUserIndex == 1 && XinputHook::controllerIndex2 == 0) || (dwUserIndex == 2 && XinputHook::controllerIndex3 == 0) || (dwUserIndex == 3 && XinputHook::controllerIndex4 == 0)) { + return XInputfromkbm(dwUserIndex, pState, false); + } + else return XInputGetState_Inline(dwUserIndex, pState, false); } -DWORD WINAPI Hook_XInputGetStateEx(DWORD dwUserIndex, XINPUT_STATE* pState) +DWORD WINAPI Hook_XInputGetStateEx(DWORD dwUserIndex, XINPUT_STATE* pState) //XInputfromkbm { - return XInputGetState_Inline(dwUserIndex, pState, true); + if (!XinputHook::TranslateMKBtoXinput) + return XInputGetState_Inline(dwUserIndex, pState, true); + else if ((dwUserIndex == 0 && XinputHook::controllerIndex == 0) || (dwUserIndex == 1 && XinputHook::controllerIndex2 == 0) || (dwUserIndex == 2 && XinputHook::controllerIndex3 == 0) || (dwUserIndex == 3 && XinputHook::controllerIndex4 == 0)){ + return XInputfromkbm(dwUserIndex, pState, true); + } + else return XInputGetState_Inline(dwUserIndex, pState, true); } DWORD WINAPI Hook_XInputSetState(DWORD dwUserIndex, XINPUT_VIBRATION* pVibration) { + if (XinputHook::TranslateMKBtoXinput) + { + if ((dwUserIndex == 0 && XinputHook::controllerIndex == 0) || (dwUserIndex == 1 && XinputHook::controllerIndex2 == 0) || (dwUserIndex == 2 && XinputHook::controllerIndex3 == 0) || (dwUserIndex == 3 && XinputHook::controllerIndex4 == 0)) + return ERROR_SUCCESS; + } + auto [connected, targetControllerIndex] = GetTargetControllerIndex(dwUserIndex); if (!connected) @@ -181,6 +460,11 @@ DWORD WINAPI Hook_XInputSetState(DWORD dwUserIndex, XINPUT_VIBRATION* pVibration DWORD WINAPI Hook_XInputGetCapabilities(DWORD dwUserIndex, DWORD dwFlags, XINPUT_CAPABILITIES* pCapabilities) { + if (XinputHook::TranslateMKBtoXinput) + { + if ((dwUserIndex == 0 && XinputHook::controllerIndex == 0) || (dwUserIndex == 1 && XinputHook::controllerIndex2 == 0) || (dwUserIndex == 2 && XinputHook::controllerIndex3 == 0) || (dwUserIndex == 3 && XinputHook::controllerIndex4 == 0)) + return GetCapabilitiesfromkbm(dwUserIndex, dwFlags, pCapabilities); + } auto [connected, targetControllerIndex] = GetTargetControllerIndex(dwUserIndex); if (!connected) @@ -331,7 +615,13 @@ void XinputHook::ShowGuiStatus() ImGui::SliderInt("Controller index 2", (int*)&controllerIndex2, 0, 16, "%d", ImGuiSliderFlags_AlwaysClamp); ImGui::SliderInt("Controller index 3", (int*)&controllerIndex3, 0, 16, "%d", ImGuiSliderFlags_AlwaysClamp); ImGui::SliderInt("Controller index 4", (int*)&controllerIndex4, 0, 16, "%d", ImGuiSliderFlags_AlwaysClamp); - + { + ImGui::PushID(123896); + ImGui::Checkbox("", &TranslateMKBtoXinput); + ImGui::SameLine(); + ImGui::TextWrapped("Enable KBM to Xinput. emulate Xinput gamepad on controllerindex 0"); + ImGui::PopID(); + } if (dinputDevice != nullptr) { ImGui::TextWrapped("Selected Dinput device \"%ws\" (GUID %lu-%u-%u)", @@ -397,6 +687,7 @@ void XinputHook::InstallImpl() XInputGetStateExPtr = t_XInputGetStateEx(GetProcAddress(GetModuleHandleW(L"xinput1_3.dll"), (LPCSTR)(100))); XInputGetStatePtr = t_XInputGetState(GetProcAddress(GetModuleHandleW(L"xinput1_3.dll"), "XInputGetState")); + //MessageBoxA(NULL, "hOOKED xINPUT", "Error", MB_OK); XInputSetStatePtr = t_XInputSetState(GetProcAddress(GetModuleHandleW(L"xinput1_3.dll"), "XInputSetState")); XInputGetCapabilitiesPtr = t_XInputGetCapabilities(GetProcAddress(GetModuleHandleW(L"xinput1_3.dll"), "XInputGetCapabilities")); @@ -430,4 +721,4 @@ void XinputHook::SetUseDinput(bool _useDinput) PollDinputDevices(); } -} \ No newline at end of file +} diff --git a/src/ProtoInput/ProtoInputHooks/XinputHook.h b/src/ProtoInput/ProtoInputHooks/XinputHook.h index 861a870..0a49bbb 100644 --- a/src/ProtoInput/ProtoInputHooks/XinputHook.h +++ b/src/ProtoInput/ProtoInputHooks/XinputHook.h @@ -5,34 +5,34 @@ namespace Proto { -class XinputHook final : public Hook -{ -private: - std::vector hookInfos{}; + class XinputHook final : public Hook + { + private: + std::vector hookInfos{}; - static bool useDinput; + static bool useDinput; -public: - static unsigned int controllerIndex; - static unsigned int controllerIndex2; - static unsigned int controllerIndex3; - static unsigned int controllerIndex4; + public: + static unsigned int controllerIndex; + static unsigned int controllerIndex2; + static unsigned int controllerIndex3; + static unsigned int controllerIndex4; - static bool useOpenXinput; - - const char* GetHookName() const override { return "Xinput"; } - const char* GetHookDescription() const override { - return - "Hooks Xinput functions to redirect input to the selected controller. " - "DirectInput (Dinput) redirecting is required to use more than 4 controllers (Xinput has a maximum of 4). "; - } - bool HasGuiStatus() const override { return true; } - void ShowGuiStatus() override; - void InstallImpl() override; - void UninstallImpl() override; + static bool useOpenXinput; + static bool TranslateMKBtoXinput; + const char* GetHookName() const override { return "Xinput"; } + const char* GetHookDescription() const override { + return + "Hooks Xinput functions to redirect input to the selected controller. " + "DirectInput (Dinput) redirecting is required to use more than 4 controllers (Xinput has a maximum of 4). "; + } + bool HasGuiStatus() const override { return true; } + void ShowGuiStatus() override; + void InstallImpl() override; + void UninstallImpl() override; - static void SetUseDinput(bool useDinput); - static bool GetUseDinput() { return useDinput; } -}; + static void SetUseDinput(bool useDinput); + static bool GetUseDinput() { return useDinput; } + }; -} +} \ No newline at end of file diff --git a/src/ProtoInput/ProtoInputHooks/dllmain.cpp b/src/ProtoInput/ProtoInputHooks/dllmain.cpp index c8350b7..52ca0dd 100644 --- a/src/ProtoInput/ProtoInputHooks/dllmain.cpp +++ b/src/ProtoInput/ProtoInputHooks/dllmain.cpp @@ -11,27 +11,20 @@ #include "RawInput.h" #include "HookManager.h" #include "protoloader.h" +#include "WindowMsgHook.h" #include "PipeCommunication.h" #include "HwndSelector.h" #include "FocusMessageLoop.h" -#include "Gui.h" #include "FakeCursor.h" +#include "TranslateXtoMKB.h" +#include "ScanThread.h" -HMODULE dll_hModule; - -DWORD WINAPI GuiThread(LPVOID lpParameter) -{ - std::cout << "Starting gui thread\n"; - - Proto::AddThreadToACL(GetCurrentThreadId()); - - Proto::ShowGuiImpl(); - - return 0; -} +HMODULE Proto::hmodule; DWORD WINAPI StartThread(LPVOID lpParameter) { + + // Useful to add a pause if we need to attach a debugger AllocConsole(); FILE* f = new FILE(); freopen_s(&f, "CONOUT$", "w", stdout); @@ -42,34 +35,23 @@ DWORD WINAPI StartThread(LPVOID lpParameter) std::cout << "Hooks DLL loaded\n"; - // Useful to add a pause if we need to attach a debugger - // MessageBoxW(NULL, L"Press OK to start", L"", MB_OK); - Proto::HwndSelector::UpdateMainHwnd(); Proto::FocusMessageLoop::SetupThread(); - Proto::FakeCursor::Initialise(); - - Proto::AddThreadToACL(GetCurrentThreadId()); - - HANDLE hGuiThread = CreateThread(nullptr, 0, - (LPTHREAD_START_ROUTINE)GuiThread, dll_hModule, CREATE_SUSPENDED, &Proto::GuiThreadID); - + Proto::FakeCursor::Initialise(Proto::hmodule); + + InitializeCriticalSection(&ScreenshotInput::ScanThread::critical);//must be placed before InitialiseRawInput + Proto::RawInput::InitialiseRawInput(); - - Proto::StartPipeCommunication(); - ResumeThread(hGuiThread); + Proto::AddThreadToACL(GetCurrentThreadId()); - if (hGuiThread != nullptr) - CloseHandle(hGuiThread); - - std::cout << "Reached end of startup thread\n"; - + Proto::StartPipeCommunication(); + return 0; } - + // EasyHook entry point extern "C" __declspec(dllexport) void __stdcall NativeInjectionEntryPoint(REMOTE_ENTRY_INFO * inRemoteInfo) { @@ -94,7 +76,7 @@ BOOL APIENTRY DllMain( HMODULE hModule, { case DLL_PROCESS_ATTACH: { - dll_hModule = hModule; + Proto::hmodule = hModule; HANDLE hThread = CreateThread(nullptr, 0, (LPTHREAD_START_ROUTINE)StartThread, hModule, 0, 0); diff --git a/src/ProtoInput/ProtoInputHooks/pipeinclude/pipeinclude.h b/src/ProtoInput/ProtoInputHooks/pipeinclude/pipeinclude.h index 3410825..c31de9f 100644 --- a/src/ProtoInput/ProtoInputHooks/pipeinclude/pipeinclude.h +++ b/src/ProtoInput/ProtoInputHooks/pipeinclude/pipeinclude.h @@ -7,6 +7,9 @@ namespace ProtoPipe enum class PipeMessageType { + AddSelectedMouseOrKeyboard, + SetTranslateXinputtoMKB, + SetReregisterinput, SetupHook, WakeUpProcess, SetupMessageFilter, @@ -18,12 +21,12 @@ enum class PipeMessageType SetDrawFakeCursor, SetDrawFakeCursorFix, SetExternalFreezeFakeInput, - AddSelectedMouseOrKeyboard, AddHandleToRename, SetControllerIndex, SetUseDinput, StopFocusMessageLoop, SetUseOpenXinput, + TranslateMKBtoXinput, SetDinputDeviceGuid, SetDinputHookGetDeviceState, SetSetWindowPosSettings, @@ -34,6 +37,7 @@ enum class PipeMessageType SetAllowFakeCursorOutOfBounds, SetToggleCursorVisibilityShortcut, SetRawInputBypass, + SetPointerInMouse, SetShowCursorWhenImageUpdated, SetPutMouseInsideWindow, SetDefaultTopLeftMouseBounds, @@ -42,7 +46,10 @@ enum class PipeMessageType SetMoveWindowDontResize, SetMoveWindowDontReposition, SetAdjustWindowRectSettings, - SetDontWaitWindowBorder + SetDontWaitWindowBorder, + SetManualScaling, + SetXinputtoMKBkeys, + SetXinputtoMKBCFG }; struct PipeMessageHeader @@ -50,6 +57,21 @@ struct PipeMessageHeader PipeMessageType messageType; unsigned int messageSize; }; +struct PipeMessageAddSelectedMouseOrKeyboard +{ + unsigned int mouse = -1; + unsigned int keyboard = -1; +}; + +struct PipeMessageSetTranslateXinputtoMKB +{ + bool TranslateXinputtoMKB; +}; + +struct PipeMessageSetReregisterinput +{ + bool enabled; +}; struct PipeMessageSetupHook { @@ -73,6 +95,10 @@ struct PipeMessageWakeUpProcess { }; +//struct PipeMessageSetNoGUI +//{ +// bool SetNoGUI; +//}; struct PipeMesasgeUpdateMainWindowHandle { uint64_t hwnd = 0; @@ -115,11 +141,7 @@ struct PipeMessageSetExternalFreezeFakeInput bool freezeEnabled; }; -struct PipeMesasgeAddSelectedMouseOrKeyboard -{ - unsigned int mouse = -1; - unsigned int keyboard = -1; -}; + struct PipeMessageAddHandleToRename { @@ -150,6 +172,11 @@ struct PipeMessageSetUseOpenXinput bool useOpenXinput; }; +struct PipeMessageSetTranslateMKBtoXinput +{ + bool TranslateMKBtoXinput; +}; + struct PipeMessageSetDinputDeviceGuid { GUID guid; @@ -205,6 +232,13 @@ struct PipeMessageSetRawInputBypass bool bypassEnabled; }; + + +struct PipeMessageSetPointerInMouse +{ + bool enabled; +}; + struct PipeMessageShowCursorWhenImageUpdated { bool ShowCursorWhenImageUpdated; @@ -256,4 +290,54 @@ struct PipeMessageSetDontWaitWindowBorder bool DontWaitWindowBorder; }; +struct PipeMessageSetManualScaling +{ + int oldX; + int oldY; + int newX; + int newY; +}; + +struct PipeMessageSetXinputtoMKBkeys +{ + int XinputtoMKBAkey; + int XinputtoMKBBkey; + int XinputtoMKBXkey; + int XinputtoMKBYkey; + int XinputtoMKBRSkey; + int XinputtoMKBLSkey; + int XinputtoMKBrightkey; + int XinputtoMKBleftkey; + int XinputtoMKBupkey; + int XinputtoMKBdownkey; + int XinputtoMKBstickR; + int XinputtoMKBstickL; + int XinputtoMKBstickright; + int XinputtoMKBstickleft; + int XinputtoMKBstickup; + int XinputtoMKBstickdown; + int XinputtoMKBoption; + int XinputtoMKBstart; + int XinputtoMKBsens; + int XinputtoMKBsensmult; + int XinputtoMKBDeadzone; +}; +struct PipeMessageSetXinputtoMKBCFG +{ + bool stickinvert; + bool scanoption; + bool shoulderswap; + bool astsatic; + bool aclick; + bool amove; + bool bstsatic; + bool bclick; + bool bmove; + bool xstsatic; + bool xclick; + bool xmove; + bool ystsatic; + bool yclick; + bool ymove; +}; } \ No newline at end of file diff --git a/src/ProtoInput/ProtoInputHost/Gui.cpp b/src/ProtoInput/ProtoInputHost/Gui.cpp index e69f1a0..5ed4443 100644 --- a/src/ProtoInput/ProtoInputHost/Gui.cpp +++ b/src/ProtoInput/ProtoInputHost/Gui.cpp @@ -11,7 +11,6 @@ #include "RawInput.h" #include "protoloader.h" #include "Profiles.h" -#include "RawInput.h" #include "MessageList.h" namespace ProtoHost @@ -52,6 +51,52 @@ StartupInjectionType selectedStartupInjectionType = StartupInjectionType::EASYHO std::vector trackedInstanceHandles{}; static bool isInputCurrentlyLocked = false; + +//TranslateXtoMKB +float Sensitivitymultiplier = 3.5f; +float Sensitivity = 15.0f; + +bool IsHookEnabled(const Profile& profile, unsigned int id) +{ + for (auto& h : profile.hooks) + if (h.id == id) + return h.enabled; + return false; +} + +std::string VkToKeyName(int vk) +{ + + UINT scan = MapVirtualKey(vk, MAPVK_VK_TO_VSC); + UINT flags = scan << 16; + + // Add extended-key flag when needed + switch (vk) + { + case VK_LEFT: + case VK_RIGHT: + case VK_UP: + case VK_DOWN: + case VK_INSERT: + case VK_DELETE: + case VK_HOME: + case VK_END: + case VK_PRIOR: // Page Up + case VK_NEXT: // Page Down + case VK_RCONTROL: + case VK_RMENU: // Right Alt + case VK_DIVIDE: + case VK_NUMLOCK: + flags |= (1 << 24); + break; + } + + char name[64] = { 0 }; + GetKeyNameTextA(flags, name, sizeof(name)); + return std::string(name); +} + + void OnInputLockChange(bool locked) { isInputCurrentlyLocked = locked; @@ -134,11 +179,22 @@ bool Launch() return false; }; + if (instance.mouseHandle != -1) + AddSelectedMouseHandle(instanceHandle, instance.mouseHandle); + + if (instance.keyboardHandle != -1) + AddSelectedKeyboardHandle(instanceHandle, instance.keyboardHandle); + + SetTranslateXinputtoMKB(instanceHandle, currentProfile.TranslateXinputtoMKB); + + SetReregisterinput(instanceHandle, currentProfile.Reregisterinput); + SetPointerInMouse(instanceHandle, currentProfile.PointerInMouse); if (hookEnabled(RegisterRawInputHookID)) InstallHook(instanceHandle, RegisterRawInputHookID); if (hookEnabled(GetRawInputDataHookID)) InstallHook(instanceHandle, GetRawInputDataHookID); if (hookEnabled(MessageFilterHookID)) InstallHook(instanceHandle, MessageFilterHookID); SetPutMouseInsideWindow(instanceHandle, currentProfile.putMouseInsideWindow); + if (hookEnabled(GetCursorPosHookID)) InstallHook(instanceHandle, GetCursorPosHookID); if (hookEnabled(SetCursorPosHookID)) InstallHook(instanceHandle, SetCursorPosHookID); if (hookEnabled(GetKeyStateHookID)) InstallHook(instanceHandle, GetKeyStateHookID); @@ -157,10 +213,13 @@ bool Launch() if (hookEnabled(BlockRawInputHookID)) InstallHook(instanceHandle, BlockRawInputHookID); SetUseOpenXinput(instanceHandle, currentProfile.useOpenXinput); + SetTranslateMKBtoXinput(instanceHandle, currentProfile.TranslateMKBtoXinput); + SetUseDinputRedirection(instanceHandle, currentProfile.dinputToXinputRedirection); if (hookEnabled(XinputHookID)) InstallHook(instanceHandle, XinputHookID); if (hookEnabled(DinputOrderHookID)) InstallHook(instanceHandle, DinputOrderHookID); + if (hookEnabled(GetCursorInfoHookID)) InstallHook(instanceHandle, GetCursorInfoHookID); if (filterEnabled(RawInputFilterID)) EnableMessageFilter(instanceHandle, RawInputFilterID); if (filterEnabled(MouseMoveFilterID)) EnableMessageFilter(instanceHandle, MouseMoveFilterID); @@ -207,16 +266,17 @@ bool Launch() for (const auto& renameNamedPipeHandle : currentProfile.renameNamedPipeHandles) AddNamedPipeToRename(instanceHandle, utf8_decode(renameNamedPipeHandle).c_str()); - if (instance.mouseHandle != -1) - AddSelectedMouseHandle(instanceHandle, instance.mouseHandle); - - if (instance.keyboardHandle != -1) - AddSelectedKeyboardHandle(instanceHandle, instance.keyboardHandle); - SetControllerIndex(instanceHandle, instance.controllerIndex); + SetControllerIndex(instanceHandle, instance.controllerIndex, instance.controllerIndex2, instance.controllerIndex3, instance.controllerIndex4); SetExternalFreezeFakeInput(instanceHandle, !isInputCurrentlyLocked && freezeGameInputWhileInputNotLocked); + //Xinput translate settings + SetXinputtoMKBkeys(instanceHandle, currentProfile.XinputtoMKBAkey, currentProfile.XinputtoMKBBkey, currentProfile.XinputtoMKBXkey, currentProfile.XinputtoMKBYkey, currentProfile.XinputtoMKBRSkey, currentProfile.XinputtoMKBLSkey, currentProfile.XinputtoMKBrightkey, currentProfile.XinputtoMKBleftkey, currentProfile.XinputtoMKBupkey, currentProfile.XinputtoMKBdownkey, + currentProfile.XinputtoMKBstickR, currentProfile.XinputtoMKBstickL, currentProfile.XinputtoMKBstickright, currentProfile.XinputtoMKBstickleft, currentProfile.XinputtoMKBstickup, currentProfile.XinputtoMKBstickdown, + currentProfile.XinputtoMKBoption, currentProfile.XinputtoMKBstart, currentProfile.XinputtoMKBsens, currentProfile.XinputtoMKBsensmult, currentProfile.XinputtoMKBDeadzone); + SetXinputtoMKBCFG(instanceHandle, currentProfile.XinputtoMKBstickinvert, currentProfile.ScanOption, currentProfile.Shoulderswappoints, currentProfile.XAstatic, currentProfile.XAclick, currentProfile.XAmove, currentProfile.XBstatic, currentProfile.XBclick, currentProfile.XBmove, currentProfile.XXstatic, currentProfile.XXclick, currentProfile.XXmove, currentProfile.XYstatic, currentProfile.XYclick, currentProfile.XYmove); + if (!instance.runtime) WakeUpProcess(instanceHandle); @@ -671,8 +731,554 @@ void SelectedInstanceWindow() ImGui::PushID(128794); ImGui::Spacing(); - ImGui::TextWrapped("Controller index"); - ImGui::SliderInt("", (int*)&instance.controllerIndex, 0, 16, "%d", ImGuiSliderFlags_AlwaysClamp); + ImGui::Separator(); + ImGui::TextWrapped("Controller index 1"); + ImGui::SliderInt("##CI1", (int*)&instance.controllerIndex, 0, 16, "%d", ImGuiSliderFlags_AlwaysClamp); + ImGui::Spacing(); + ImGui::Separator(); + ImGui::TextWrapped("Controller index 2"); + ImGui::SliderInt("##CI2", (int*)&instance.controllerIndex2, 0, 16, "%d", ImGuiSliderFlags_AlwaysClamp); + ImGui::Separator(); + ImGui::TextWrapped("Controller index 3"); + ImGui::SliderInt("##CI3", (int*)&instance.controllerIndex3, 0, 16, "%d", ImGuiSliderFlags_AlwaysClamp); + ImGui::Separator(); + ImGui::TextWrapped("Controller index 4"); + ImGui::SliderInt("##CI4", (int*)&instance.controllerIndex4, 0, 16, "%d", ImGuiSliderFlags_AlwaysClamp); + ImGui::Spacing(); + ImGui::Separator(); + ImGui::TextWrapped("If Translate X to MKB is selected, mouse and keyboard will be emulated from first ControllerIndex." + "Option will automatically deactivate if a keyboard or mouse is selected for the instance. " + "Uses OpenXinput directly. " + ""); + ImGui::Checkbox("Translate X to MKB", ¤tProfile.TranslateXinputtoMKB); // + if (currentProfile.TranslateXinputtoMKB) + currentProfile.TranslateMKBtoXinput = false; + if (currentProfile.TranslateXinputtoMKB || currentProfile.TranslateMKBtoXinput) + { + if (ImGui::CollapsingHeader("Translation Mappings", ImGuiTreeNodeFlags_DefaultOpen)) + { + // A key + { + const auto XAString = VkToKeyName(currentProfile.XinputtoMKBAkey); + ImGui::TextWrapped("A is mapped to: %s", (XAString.c_str())); + + static bool waitingKeyPressA = false; + + if (waitingKeyPressA) + { + PushDisabled(); + ImGui::Button("Press Keyboard button...##A"); //these need unique IDs or text + PopDisabled(); + + if (lastVKcode != -1) + { + waitingKeyPressA = false; + currentProfile.XinputtoMKBAkey = lastVKcode; + } + } + else if (ImGui::Button("Click to change##A1"))//these need unique IDs or text + { + waitingKeyPressA = true; + lastVKcode = -1; + } + } + ImGui::Separator(); + // B key + { + const auto XAString = VkToKeyName(currentProfile.XinputtoMKBBkey); + ImGui::TextWrapped("B is mapped to: %s", (XAString.c_str())); + + static bool waitingKeyPressB = false; + + if (waitingKeyPressB) + { + PushDisabled(); + ImGui::Button("Press Keyboard button...##B"); + PopDisabled(); + + if (lastVKcode != -1) + { + waitingKeyPressB = false; + currentProfile.XinputtoMKBBkey = lastVKcode; + } + } + else if (ImGui::Button("Click to change##B1")) + { + waitingKeyPressB = true; + lastVKcode = -1; + } + } + ImGui::Separator(); + // X key + { + const auto XAString = VkToKeyName(currentProfile.XinputtoMKBXkey); + ImGui::TextWrapped("X is mapped to: %s", (XAString.c_str())); + + static bool waitingKeyPressX = false; + + if (waitingKeyPressX) + { + PushDisabled(); + ImGui::Button("Press Keyboard button...##C"); + PopDisabled(); + + if (lastVKcode != -1) + { + waitingKeyPressX = false; + currentProfile.XinputtoMKBXkey = lastVKcode; + } + } + else if (ImGui::Button("Click to change##C1")) + { + waitingKeyPressX = true; + lastVKcode = -1; + } + } + ImGui::Separator(); + // Y key + { + const auto XAString = VkToKeyName(currentProfile.XinputtoMKBYkey); + ImGui::TextWrapped("Y is mapped to: %s", (XAString.c_str())); + + static bool waitingKeyPressY = false; + + if (waitingKeyPressY) + { + PushDisabled(); + ImGui::Button("Press Keyboard button...##D1"); + PopDisabled(); + + if (lastVKcode != -1) + { + waitingKeyPressY = false; + currentProfile.XinputtoMKBYkey = lastVKcode; + } + } + else if (ImGui::Button("Click to change##D1")) + { + waitingKeyPressY = true; + lastVKcode = -1; + } + } + ImGui::Separator(); + // RS key + { + const auto XAString = VkToKeyName(currentProfile.XinputtoMKBRSkey); + ImGui::TextWrapped("Right Shoulder is mapped to: %s", (XAString.c_str())); + + static bool waitingKeyPressRS = false; + + if (waitingKeyPressRS) + { + PushDisabled(); + ImGui::Button("Press Keyboard button...##E"); + PopDisabled(); + + if (lastVKcode != -1) + { + waitingKeyPressRS = false; + currentProfile.XinputtoMKBRSkey = lastVKcode; + } + } + else if (ImGui::Button("Click to change##E1")) + { + waitingKeyPressRS = true; + lastVKcode = -1; + } + } + ImGui::Separator(); + // LS key + { + const auto XAString = VkToKeyName(currentProfile.XinputtoMKBLSkey); + ImGui::TextWrapped("Left Shoulder is mapped to: %s", (XAString.c_str())); + + static bool waitingKeyPressLS = false; + + if (waitingKeyPressLS) + { + PushDisabled(); + ImGui::Button("Press Keyboard button...##F"); + PopDisabled(); + + if (lastVKcode != -1) + { + waitingKeyPressLS = false; + currentProfile.XinputtoMKBLSkey = lastVKcode; + } + } + else if (ImGui::Button("Click to change##F1")) + { + waitingKeyPressLS = true; + lastVKcode = -1; + } + } + ImGui::Separator(); + ///right + { + const auto XAString = VkToKeyName(currentProfile.XinputtoMKBrightkey); + ImGui::TextWrapped("right is mapped to: %s", (XAString.c_str())); + + static bool waitingKeyPressright = false; + + if (waitingKeyPressright) + { + PushDisabled(); + ImGui::Button("Press Keyboard button...##G"); + PopDisabled(); + + if (lastVKcode != -1) + { + waitingKeyPressright = false; + currentProfile.XinputtoMKBrightkey = lastVKcode; + } + } + else if (ImGui::Button("Click to change##G1")) + { + waitingKeyPressright = true; + lastVKcode = -1; + } + } + ImGui::Separator(); + ///left + { + const auto XAString = VkToKeyName(currentProfile.XinputtoMKBleftkey); + ImGui::TextWrapped("left is mapped to: %s", (XAString.c_str())); + + static bool waitingKeyPressleft = false; + + if (waitingKeyPressleft) + { + PushDisabled(); + ImGui::Button("Press Keyboard button...##H"); + PopDisabled(); + + if (lastVKcode != -1) + { + waitingKeyPressleft = false; + currentProfile.XinputtoMKBleftkey = lastVKcode; + } + } + else if (ImGui::Button("Click to change##H1")) + { + waitingKeyPressleft = true; + lastVKcode = -1; + } + } + ImGui::Separator(); + ///up + { + const auto XAString = VkToKeyName(currentProfile.XinputtoMKBupkey); + ImGui::TextWrapped("up is mapped to: %s", (XAString.c_str())); + + static bool waitingKeyPressup = false; + + if (waitingKeyPressup) + { + PushDisabled(); + ImGui::Button("Press Keyboard button...##I"); + PopDisabled(); + + if (lastVKcode != -1) + { + waitingKeyPressup = false; + currentProfile.XinputtoMKBupkey = lastVKcode; + } + } + else if (ImGui::Button("Click to change##I1")) + { + waitingKeyPressup = true; + lastVKcode = -1; + } + } + ImGui::Separator(); + ///down + { + const auto XAString = VkToKeyName(currentProfile.XinputtoMKBdownkey); + ImGui::TextWrapped("down is mapped to: %s", (XAString.c_str())); + + static bool waitingKeyPressdown = false; + + if (waitingKeyPressdown) + { + PushDisabled(); + ImGui::Button("Press Keyboard button...##J"); + PopDisabled(); + + if (lastVKcode != -1) + { + waitingKeyPressdown = false; + currentProfile.XinputtoMKBdownkey = lastVKcode; + } + } + else if (ImGui::Button("Click to change##J2")) + { + waitingKeyPressdown = true; + lastVKcode = -1; + } + } + ImGui::Separator(); + ///right stick press + { + const auto XAString = VkToKeyName(currentProfile.XinputtoMKBstickR); + ImGui::TextWrapped("Right Stick Press is mapped to: %s", (XAString.c_str())); + + static bool waitingKeyPressstickR = false; + + if (waitingKeyPressstickR) + { + PushDisabled(); + ImGui::Button("Press Keyboard button...##K"); + PopDisabled(); + + if (lastVKcode != -1) + { + waitingKeyPressstickR = false; + currentProfile.XinputtoMKBstickR = lastVKcode; + } + } + else if (ImGui::Button("Click to change##K1")) + { + waitingKeyPressstickR = true; + lastVKcode = -1; + } + } + ImGui::Separator(); + ///left stick press + { + const auto XAString = VkToKeyName(currentProfile.XinputtoMKBstickL); + ImGui::TextWrapped("Left Stick Press is mapped to: %s", (XAString.c_str())); + + static bool waitingKeyPressstickL = false; + + if (waitingKeyPressstickL) + { + PushDisabled(); + ImGui::Button("Press Keyboard button...##L"); + PopDisabled(); + + if (lastVKcode != -1) + { + waitingKeyPressstickL = false; + currentProfile.XinputtoMKBstickL = lastVKcode; + } + } + else if (ImGui::Button("Click to change##L1")) + { + waitingKeyPressstickL = true; + lastVKcode = -1; + } + } + ImGui::Separator(); + ///stick move right + { + const auto XAString = VkToKeyName(currentProfile.XinputtoMKBstickright); + ImGui::TextWrapped("stick move right is mapped to: %s", (XAString.c_str())); + + static bool waitingKeyPressstickright = false; + + if (waitingKeyPressstickright) + { + PushDisabled(); + ImGui::Button("Press Keyboard button...##M2"); + PopDisabled(); + + if (lastVKcode != -1) + { + waitingKeyPressstickright = false; + currentProfile.XinputtoMKBstickright = lastVKcode; + } + } + else if (ImGui::Button("Click to change##M")) + { + waitingKeyPressstickright = true; + lastVKcode = -1; + } + } + ImGui::Separator(); + ///stick move left + { + const auto XAString = VkToKeyName(currentProfile.XinputtoMKBstickleft); + ImGui::TextWrapped("stick move left is mapped to: %s", (XAString.c_str())); + + static bool waitingKeyPressstickleft = false; + + if (waitingKeyPressstickleft) + { + PushDisabled(); + ImGui::Button("Press Keyboard button...##N"); + PopDisabled(); + + if (lastVKcode != -1) + { + waitingKeyPressstickleft = false; + currentProfile.XinputtoMKBstickleft = lastVKcode; + } + } + else if (ImGui::Button("Click to change##N1")) + { + waitingKeyPressstickleft = true; + lastVKcode = -1; + } + } + ImGui::Separator(); + ///stick move up + { + const auto XAString = VkToKeyName(currentProfile.XinputtoMKBstickup); + ImGui::TextWrapped("stick move up is mapped to: %s", (XAString.c_str())); + + static bool waitingKeyPressstickup = false; + + if (waitingKeyPressstickup) + { + PushDisabled(); + ImGui::Button("Press Keyboard button...##O"); + PopDisabled(); + + if (lastVKcode != -1) + { + waitingKeyPressstickup = false; + currentProfile.XinputtoMKBstickup = lastVKcode; + } + } + else if (ImGui::Button("Click to change##O1")) + { + waitingKeyPressstickup = true; + lastVKcode = -1; + } + } + ImGui::Separator(); + ///stick move up + { + const auto XAString = VkToKeyName(currentProfile.XinputtoMKBstickdown); + ImGui::TextWrapped("stick move Down is mapped to: %s", (XAString.c_str())); + + static bool waitingKeyPressstickdown = false; + + if (waitingKeyPressstickdown) + { + PushDisabled(); + ImGui::Button("Press Keyboard button...##P"); + PopDisabled(); + + if (lastVKcode != -1) + { + waitingKeyPressstickdown = false; + currentProfile.XinputtoMKBstickdown = lastVKcode; + } + } + else if (ImGui::Button("Click to change##P1")) + { + waitingKeyPressstickdown = true; + lastVKcode = -1; + } + } + ImGui::Separator(); + ///start button + { + const auto XAString = VkToKeyName(currentProfile.XinputtoMKBstart); + ImGui::TextWrapped("Start button is mapped to: %s", (XAString.c_str())); + + static bool waitingKeyPressstart = false; + + if (waitingKeyPressstart) + { + PushDisabled(); + ImGui::Button("Press Keyboard button...##Q"); + PopDisabled(); + + if (lastVKcode != -1) + { + waitingKeyPressstart = false; + currentProfile.XinputtoMKBstart = lastVKcode; + } + } + else if (ImGui::Button("Click to change##Q1")) + { + waitingKeyPressstart = true; + lastVKcode = -1; + } + } + ImGui::Separator(); + ///option button + { + const auto XAString = VkToKeyName(currentProfile.XinputtoMKBoption); + ImGui::TextWrapped("option button is mapped to: %s", (XAString.c_str())); + + static bool waitingKeyPressoption = false; + + if (waitingKeyPressoption) + { + PushDisabled(); + ImGui::Button("Press Keyboard button...##R"); + PopDisabled(); + + if (lastVKcode != -1) + { + waitingKeyPressoption = false; + currentProfile.XinputtoMKBoption = lastVKcode; + } + } + else if (ImGui::Button("Click to change##R2")) + { + waitingKeyPressoption = true; + lastVKcode = -1; + } + } + } + if (ImGui::CollapsingHeader("Translation Options", ImGuiTreeNodeFlags_DefaultOpen)) + { + if (currentProfile.TranslateXinputtoMKB) + { + currentProfile.TranslateMKBtoXinput = false; + ImGui::Separator(); + ImGui::Spacing(); + ImGui::TextWrapped("Scanoption Will prescan and render coordinates if any BMPs or static points are loaded." + "Place .BMP files next to exe. named A0 for A button and +1 for each bmp"); + ImGui::Checkbox("Scanoption", ¤tProfile.ScanOption); // + ImGui::Separator(); + ImGui::Spacing(); + ImGui::TextWrapped("Uses shoulder buttons for point next or previous point if enabled" + ""); + ImGui::Checkbox("ShoulderScroll", ¤tProfile.Shoulderswappoints); // + ImGui::Separator(); + ImGui::Spacing(); + } + if (currentProfile.ScanOption) + { + ImGui::TextWrapped("Any button set as static will not forget coordinates found" + ""); + + ImGui::Spacing(); + ImGui::Checkbox("A static", ¤tProfile.XAstatic); // + ImGui::Checkbox("B static", ¤tProfile.XBstatic); // + ImGui::Checkbox("X static", ¤tProfile.XXstatic); // + ImGui::Checkbox("Y static", ¤tProfile.XYstatic); // + ImGui::Separator(); + ImGui::Spacing(); + ImGui::TextWrapped("Input Actions on coordinate" + ""); + + ImGui::Spacing(); + ImGui::Checkbox("A click", ¤tProfile.XAclick); // + ImGui::Checkbox("A move", ¤tProfile.XAmove); // + ImGui::Checkbox("B click", ¤tProfile.XBclick); // + ImGui::Checkbox("B move", ¤tProfile.XBmove); // + ImGui::Checkbox("X click", ¤tProfile.XXclick); // + ImGui::Checkbox("X move", ¤tProfile.XXmove); // + ImGui::Checkbox("Y click", ¤tProfile.XYclick); // + ImGui::Checkbox("Y move", ¤tProfile.XYmove); // + ImGui::Separator(); + } + ImGui::Separator(); + ImGui::Checkbox("Lefthanded Stick. moves mouse with left stick and button map on right stick. or opposite if disabled", ¤tProfile.XinputtoMKBstickinvert); // + ImGui::Separator(); + ImGui::SliderInt("Sens", (int*)¤tProfile.XinputtoMKBsens, 1, 40, "%d", ImGuiSliderFlags_AlwaysClamp); + ImGui::Separator(); + ImGui::SliderInt("Sens curve", (int*)¤tProfile.XinputtoMKBsensmult, 1, 20, "%d", ImGuiSliderFlags_AlwaysClamp); + ImGui::Separator(); + ImGui::SliderInt("Deadzone", (int*)¤tProfile.XinputtoMKBDeadzone, 1, 20, "%d", ImGuiSliderFlags_AlwaysClamp); + } + } ImGui::PopID(); } @@ -698,7 +1304,7 @@ void OptionsMenu() if (!lockInputWithTheEndKey) PopDisabled(); } - if (ImGui::CollapsingHeader("Profiles", ImGuiTreeNodeFlags_DefaultOpen | ImGuiTreeNodeFlags_Leaf)) + if (ImGui::CollapsingHeader("Profiles", ImGuiTreeNodeFlags_DefaultOpen)) { static bool needsRefreshing = true; @@ -806,7 +1412,7 @@ void OptionsMenu() } } - if (ImGui::CollapsingHeader("Injection method", ImGuiTreeNodeFlags_DefaultOpen | ImGuiTreeNodeFlags_Leaf)) + if (ImGui::CollapsingHeader("Injection method", ImGuiTreeNodeFlags_DefaultOpen)) { { const char* items[] = { "Remote Load Library", "EasyHook Inject", "EasyHook Stealth Inject" }; @@ -855,7 +1461,7 @@ void OptionsMenu() } } - if (ImGui::CollapsingHeader("Hooks", ImGuiTreeNodeFlags_DefaultOpen | ImGuiTreeNodeFlags_Leaf)) + if (ImGui::CollapsingHeader("Hooks", ImGuiTreeNodeFlags_DefaultOpen)) { ImGui::TextWrapped("See the descriptions in the in-game hooks GUI for more details"); @@ -865,17 +1471,42 @@ void OptionsMenu() } } - ImGui::Checkbox("Dinput to Xinput redirection", ¤tProfile.dinputToXinputRedirection); + if (ImGui::CollapsingHeader("Hooks Options", ImGuiTreeNodeFlags_DefaultOpen)) + { + if (IsHookEnabled(currentProfile, ProtoHookIDs::XinputHookID)) + { + ImGui::Checkbox("Xinput: Use OpenXinput", ¤tProfile.useOpenXinput); + } + else currentProfile.useOpenXinput = false; - ImGui::Checkbox("Use OpenXinput", ¤tProfile.useOpenXinput); - - ImGui::Checkbox("Use fake clip cursor", ¤tProfile.useFakeClipCursor); - - ImGui::Checkbox("Show fake cursor when image updated", ¤tProfile.showCursorWhenImageUpdated); + if (IsHookEnabled(currentProfile, ProtoHookIDs::XinputHookID)) + { + ImGui::Checkbox("Xinput: Translate MKB to fake Xinput", ¤tProfile.TranslateMKBtoXinput); + ImGui::Checkbox("Xinput: Dinput to Xinput redirection", ¤tProfile.dinputToXinputRedirection); + } + else currentProfile.TranslateMKBtoXinput = false; + + if (currentProfile.TranslateMKBtoXinput) + { + currentProfile.TranslateXinputtoMKB = false; + currentProfile.ScanOption = false; + } + if (IsHookEnabled(currentProfile, ProtoHookIDs::RegisterRawInputHookID)) + { + ImGui::Checkbox("RegisterRawInput: ReRegister", ¤tProfile.Reregisterinput); + } + else currentProfile.dinputToXinputRedirection = false; - ImGui::Checkbox("Put Mouse Inside Window", ¤tProfile.putMouseInsideWindow); + if (IsHookEnabled(currentProfile, ProtoHookIDs::ClipCursorHookID)) + { + ImGui::Checkbox("Clipcursor: Use fake clip cursor", ¤tProfile.useFakeClipCursor); + } + else currentProfile.useFakeClipCursor = false; - if (ImGui::CollapsingHeader("Message Filters", ImGuiTreeNodeFlags_DefaultOpen | ImGuiTreeNodeFlags_Leaf)) + if (IsHookEnabled(currentProfile, ProtoHookIDs::CursorVisibilityStateHookID)) + ImGui::Checkbox("CursorVisibility: Show fake cursor when image updated", ¤tProfile.showCursorWhenImageUpdated); + } + if (ImGui::CollapsingHeader("Message Filters", ImGuiTreeNodeFlags_DefaultOpen)) { for (auto& filter : currentProfile.messageFilters) { @@ -883,17 +1514,18 @@ void OptionsMenu() } } - if (ImGui::CollapsingHeader("Options", ImGuiTreeNodeFlags_DefaultOpen | ImGuiTreeNodeFlags_Leaf)) + if (ImGui::CollapsingHeader("Options", ImGuiTreeNodeFlags_DefaultOpen)) { ImGui::Checkbox("Draw fake mouse cursor", ¤tProfile.drawFakeMouseCursor); - - ImGui::Checkbox("Fake cursor offset fix", ¤tProfile.drawFakeCursorFix); - + + if (currentProfile.drawFakeMouseCursor) + { + ImGui::Checkbox("Fake cursor offset fix", ¤tProfile.drawFakeCursorFix); + ImGui::Checkbox("Toggle fake cursor shortcut (Home)", ¤tProfile.toggleFakeCursorVisibilityShortcut); + } ImGui::Checkbox("Allow fake cursor to go out of bounds", ¤tProfile.allowMouseOutOfBounds); ImGui::Checkbox("Extend fake cursor boundaries", ¤tProfile.extendMouseBounds); - - ImGui::Checkbox("Toggle fake cursor shortcut (Home)", ¤tProfile.toggleFakeCursorVisibilityShortcut); - + ImGui::Checkbox("Put Mouse Inside Window", ¤tProfile.putMouseInsideWindow); ImGui::Separator(); ImGui::Checkbox("Send mouse movement messages", ¤tProfile.sendMouseMovementMessages); @@ -901,27 +1533,30 @@ void OptionsMenu() ImGui::Checkbox("Send mouse wheel messages", ¤tProfile.sendMouseWheelMessages); ImGui::Checkbox("Send keyboard button messages", ¤tProfile.sendKeyboardButtonMessages); ImGui::Checkbox("Send mouse double click messages", ¤tProfile.sendMouseDblClkMessages); + ImGui::Separator(); + ImGui::Checkbox("Use Pointer Messages For Mouse", ¤tProfile.PointerInMouse); } - if (ImGui::CollapsingHeader("Focus loop", ImGuiTreeNodeFlags_DefaultOpen | ImGuiTreeNodeFlags_Leaf)) + if (ImGui::CollapsingHeader("Focus loop", ImGuiTreeNodeFlags_DefaultOpen)) { ImGui::TextWrapped("This is required for any focus loop messages to be sent"); ImGui::Checkbox("Enabled focus message loop", ¤tProfile.focusMessageLoop); ImGui::Separator(); - - ImGui::TextWrapped("Some games only work with specific messages, some games break with specific messages. Make sure to test different combinations"); - - ImGui::Checkbox("Send WM_ACTIVATE", ¤tProfile.focusLoopSendWM_ACTIVATE); - ImGui::Checkbox("Send WM_NCACTIVATE", ¤tProfile.focusLoopSendWM_NCACTIVATE); - ImGui::Checkbox("Send WM_ACTIVATEAPP", ¤tProfile.focusLoopSendWM_ACTIVATEAPP); - ImGui::Checkbox("Send WM_SETFOCUS", ¤tProfile.focusLoopSendWM_SETFOCUS); - ImGui::Checkbox("Send WM_MOUSEACTIVATE", ¤tProfile.focusLoopSendWM_MOUSEACTIVATE); - + if (currentProfile.focusMessageLoop) + { + ImGui::TextWrapped("Some games only work with specific messages, some games break with specific messages. Make sure to test different combinations"); + + ImGui::Checkbox("Send WM_ACTIVATE", ¤tProfile.focusLoopSendWM_ACTIVATE); + ImGui::Checkbox("Send WM_NCACTIVATE", ¤tProfile.focusLoopSendWM_NCACTIVATE); + ImGui::Checkbox("Send WM_ACTIVATEAPP", ¤tProfile.focusLoopSendWM_ACTIVATEAPP); + ImGui::Checkbox("Send WM_SETFOCUS", ¤tProfile.focusLoopSendWM_SETFOCUS); + ImGui::Checkbox("Send WM_MOUSEACTIVATE", ¤tProfile.focusLoopSendWM_MOUSEACTIVATE); + } } - if (ImGui::CollapsingHeader("Handles to rename", ImGuiTreeNodeFlags_DefaultOpen | ImGuiTreeNodeFlags_Leaf)) + if (ImGui::CollapsingHeader("Handles to rename", ImGuiTreeNodeFlags_DefaultOpen)) { ImGui::TextWrapped("These options require the Rename Handles hook"); @@ -1018,7 +1653,7 @@ void OptionsMenu() } } - if (ImGui::CollapsingHeader("Messages to block", ImGuiTreeNodeFlags_DefaultOpen | ImGuiTreeNodeFlags_Leaf)) + if (ImGui::CollapsingHeader("Messages to block", ImGuiTreeNodeFlags_DefaultOpen)) { static bool onlyShowBlocked = false; ImGui::Checkbox("Only show blocked", &onlyShowBlocked); diff --git a/src/ProtoInput/ProtoInputHost/Instance.h b/src/ProtoInput/ProtoInputHost/Instance.h index decad62..2eb1d79 100644 --- a/src/ProtoInput/ProtoInputHost/Instance.h +++ b/src/ProtoInput/ProtoInputHost/Instance.h @@ -22,6 +22,9 @@ class Instance intptr_t mouseHandle = -1; unsigned int controllerIndex = 0; + unsigned int controllerIndex2 = 0; + unsigned int controllerIndex3 = 0; + unsigned int controllerIndex4 = 0; std::string instanceName; diff --git a/src/ProtoInput/ProtoInputHost/Profiles.h b/src/ProtoInput/ProtoInputHost/Profiles.h index 3fe6cd5..660b3a0 100644 --- a/src/ProtoInput/ProtoInputHost/Profiles.h +++ b/src/ProtoInput/ProtoInputHost/Profiles.h @@ -37,13 +37,13 @@ struct ProfileOption } }; -struct Profile +struct Profile //Profile::hooks::ProtoHookIDs::RenameHandlesHookID { std::vector hooks { - { "Register Raw Input", true, "Register Raw Input", ProtoHookIDs::RegisterRawInputHookID }, - { "Get Raw Input Data", true, "Get Raw Input Data", ProtoHookIDs::GetRawInputDataHookID }, - { "Message Filter", true, "Message Filter", ProtoHookIDs::MessageFilterHookID }, + { "Register Raw Input", true, "Register Raw Input", ProtoHookIDs::RegisterRawInputHookID }, //0 + { "Get Raw Input Data", true, "Get Raw Input Data", ProtoHookIDs::GetRawInputDataHookID }, //1 + { "Message Filter", true, "Message Filter", ProtoHookIDs::MessageFilterHookID }, //2 { "Get Cursor Position", true, "Get Cursor Position", ProtoHookIDs::GetCursorPosHookID }, { "Set Cursor Position", true, "Set Cursor Position", ProtoHookIDs::SetCursorPosHookID }, { "Get Key State", true, "Get Key State", ProtoHookIDs::GetKeyStateHookID }, @@ -55,7 +55,8 @@ struct Profile { "Rename Handles", true, "Rename Handles", ProtoHookIDs::RenameHandlesHookID }, { "Block Raw Input", false, "Block Raw Input", ProtoHookIDs::BlockRawInputHookID }, { "Dinput Order", false, "Dinput Order", ProtoHookIDs::DinputOrderHookID }, - { "Xinput", false, "Xinput", ProtoHookIDs::XinputHookID } + { "Xinput", false, "Xinput", ProtoHookIDs::XinputHookID }, + { "GetCursorInfo", false, "GetCursorInfo", ProtoHookIDs::GetCursorInfoHookID } }; std::vector messageFilters @@ -73,11 +74,56 @@ struct Profile bool dinputToXinputRedirection = false; bool useOpenXinput = false; + //reregister devices to game after hooking + bool Reregisterinput = false; + bool PointerInMouse = false; + + bool TranslateMKBtoXinput = false; + bool TranslateXinputtoMKB = false; + + bool XinputtoMKBstickinvert = false; + bool ScanOption = false; + bool Shoulderswappoints = false; + bool XAstatic = false; + bool XAclick = true; + bool XAmove = true; + bool XBstatic = false; + bool XBclick = true; + bool XBmove = true; + bool XXstatic = false; + bool XXclick = true; + bool XXmove = true; + bool XYstatic = false; + bool XYclick = true; + bool XYmove = true; + int XinputtoMKBAkey = 0x52; //R + int XinputtoMKBBkey = 0x47; //G + int XinputtoMKBXkey = 0x45; //E + int XinputtoMKBYkey = 0x43; //C + int XinputtoMKBRSkey = 0x10; + int XinputtoMKBLSkey = 0x20; + int XinputtoMKBrightkey = 0x27; + int XinputtoMKBleftkey = 0x25; + int XinputtoMKBupkey = 0x26; + int XinputtoMKBdownkey = 0x28; + int XinputtoMKBstickR = 0x5A; //Z + int XinputtoMKBstickL = 0x4D; //M + int XinputtoMKBstickright = 0x41; //A + int XinputtoMKBstickleft = 0x44; //D + int XinputtoMKBstickup = 0x57; //W + int XinputtoMKBstickdown = 0x53; //S + int XinputtoMKBoption = 0x1B; // + int XinputtoMKBstart = 0x0D; + int XinputtoMKBsens = 15; + int XinputtoMKBsensmult = 4; + int XinputtoMKBDeadzone = 2; + + bool useFakeClipCursor = true; bool showCursorWhenImageUpdated = false; - bool putMouseInsideWindow = false; + bool putMouseInsideWindow = true; bool drawFakeMouseCursor = true; bool drawFakeCursorFix = false; @@ -112,8 +158,55 @@ struct Profile cereal::make_nvp("renameHandles", renameHandles), cereal::make_nvp("renameNamedPipeHandles", renameNamedPipeHandles), + cereal::make_nvp("Reregisterinput", Reregisterinput), + cereal::make_nvp("PointerInMouse", PointerInMouse), + cereal::make_nvp("dinputToXinputRedirection", dinputToXinputRedirection), cereal::make_nvp("useOpenXinput", useOpenXinput), + cereal::make_nvp("TranslateMKBtoXinput", TranslateMKBtoXinput), + cereal::make_nvp("TranslateXinputtoMKB", TranslateXinputtoMKB), + cereal::make_nvp("XinputtoMKBstickinvert", XinputtoMKBstickinvert), + cereal::make_nvp("ScanOption", ScanOption), + + cereal::make_nvp("Shoulderswappoints", Shoulderswappoints), + cereal::make_nvp("XAstatic", XAstatic), + cereal::make_nvp("XAclick", XAclick), + cereal::make_nvp("XAmove", XAmove), + + cereal::make_nvp("XBstatic", XBstatic), + cereal::make_nvp("XBclick", XBclick), + cereal::make_nvp("XBmove", XBmove), + cereal::make_nvp("XXstatic", XXstatic), + + cereal::make_nvp("XXclick", XXclick), + cereal::make_nvp("XXmove", XXmove), + cereal::make_nvp("XYclick", XYclick), + cereal::make_nvp("XYmove", XYmove), + + cereal::make_nvp("XinputtoMKBAkey", XinputtoMKBAkey), + cereal::make_nvp("XinputtoMKBBkey", XinputtoMKBBkey), + cereal::make_nvp("XinputtoMKBXkey", XinputtoMKBXkey), + cereal::make_nvp("XinputtoMKBYkey", XinputtoMKBYkey), + cereal::make_nvp("XinputtoMKBRSkey", XinputtoMKBRSkey), + cereal::make_nvp("XinputtoMKBLSkey", XinputtoMKBLSkey), + cereal::make_nvp("XinputtoMKBrightkey", XinputtoMKBrightkey), + cereal::make_nvp("XinputtoMKBleftkey", XinputtoMKBleftkey), + cereal::make_nvp("XinputtoMKBupkey", XinputtoMKBupkey), + cereal::make_nvp("XinputtoMKBdownkey", XinputtoMKBdownkey), + cereal::make_nvp("XinputtoMKBstickR", XinputtoMKBstickR), + cereal::make_nvp("XinputtoMKBstickL", XinputtoMKBstickL), + cereal::make_nvp("XinputtoMKBstickright", XinputtoMKBstickright), + cereal::make_nvp("XinputtoMKBstickleft", XinputtoMKBstickleft), + + cereal::make_nvp("XinputtoMKBstickleft", XinputtoMKBstickleft), + cereal::make_nvp("XinputtoMKBstickup", XinputtoMKBstickup), + cereal::make_nvp("XinputtoMKBstickdown", XinputtoMKBstickdown), + cereal::make_nvp("XinputtoMKBoption", XinputtoMKBoption), + cereal::make_nvp("XinputtoMKBstart", XinputtoMKBstart), + cereal::make_nvp("XinputtoMKBsens", XinputtoMKBsens), + cereal::make_nvp("XinputtoMKBsensmult", XinputtoMKBsensmult), + cereal::make_nvp("XinputtoMKBDeadzone", XinputtoMKBDeadzone), + cereal::make_nvp("useFakeClipCursor", useFakeClipCursor), cereal::make_nvp("showCursorWhenImageUpdated", showCursorWhenImageUpdated), diff --git a/src/ProtoInput/ProtoInputHost/ProtoInputHost.cpp b/src/ProtoInput/ProtoInputHost/ProtoInputHost.cpp index ea783a0..efd6e87 100644 --- a/src/ProtoInput/ProtoInputHost/ProtoInputHost.cpp +++ b/src/ProtoInput/ProtoInputHost/ProtoInputHost.cpp @@ -124,6 +124,7 @@ int main() InstallHook(instanceHandle, ClipCursorHookID); InstallHook(instanceHandle, FocusHooksHookID); InstallHook(instanceHandle, RenameHandlesHookID); + InstallHook(instanceHandle, GetCursorInfoHookID); EnableMessageFilter(instanceHandle, RawInputFilterID); EnableMessageFilter(instanceHandle, MouseMoveFilterID); diff --git a/src/ProtoInput/ProtoInputHost/ProtoInputHost.vcxproj b/src/ProtoInput/ProtoInputHost/ProtoInputHost.vcxproj index d1003be..2383764 100644 --- a/src/ProtoInput/ProtoInputHost/ProtoInputHost.vcxproj +++ b/src/ProtoInput/ProtoInputHost/ProtoInputHost.vcxproj @@ -23,7 +23,7 @@ {91F50DCA-3875-4D2B-8B49-F2AD1DBDB209} Win32Proj ProtoInputHost - 10.0 + 10.0.18362.0 diff --git a/src/ProtoInput/ProtoInputHost/RawInput.cpp b/src/ProtoInput/ProtoInputHost/RawInput.cpp index ebcdc68..ef14636 100644 --- a/src/ProtoInput/ProtoInputHost/RawInput.cpp +++ b/src/ProtoInput/ProtoInputHost/RawInput.cpp @@ -13,6 +13,13 @@ namespace ProtoHost intptr_t lastKeypressKeyboardHandle = -1; intptr_t lastMouseClicked = -1; +int lastVKcode = 0; +//int Akey = 0x57; //wasd +//int Bkey = 0x53; +//int Xkey = 0x41; +//int Ykey = 0x44; +//int RSkey = VK_RETURN; +//int LSkey = VK_SPACE; bool lockInputWithTheEndKey = true; bool lockInputSuspendsExplorer = true; bool freezeGameInputWhileInputNotLocked = true; @@ -22,6 +29,8 @@ HWND rawInputHwnd; std::vector keyboardHandles{}; std::vector mouseHandles{}; + + void ProcessRawInput(HRAWINPUT rawInputHandle) { RAWINPUT rawinput; @@ -37,10 +46,13 @@ void ProcessRawInput(HRAWINPUT rawInputHandle) return; if (rawinput.header.dwType == RIM_TYPEKEYBOARD && - rawinput.data.keyboard.Flags == RI_KEY_MAKE) + (rawinput.data.keyboard.Flags & RI_KEY_BREAK) == 0) // key down { + USHORT vkey = rawinput.data.keyboard.VKey; + lastVKcode = vkey; lastKeypressKeyboardHandle = (intptr_t)rawinput.header.hDevice; } + else if (rawinput.header.dwType == RIM_TYPEMOUSE && rawinput.data.mouse.usButtonFlags != 0) { diff --git a/src/ProtoInput/ProtoInputHost/RawInput.h b/src/ProtoInput/ProtoInputHost/RawInput.h index 1be5a76..0667f91 100644 --- a/src/ProtoInput/ProtoInputHost/RawInput.h +++ b/src/ProtoInput/ProtoInputHost/RawInput.h @@ -10,6 +10,14 @@ extern HWND rawInputHwnd; extern intptr_t lastKeypressKeyboardHandle; extern intptr_t lastMouseClicked; +extern int lastVKcode; +//extern int Akey; +//extern int Bkey; +//extern int Xkey; +//extern int Ykey; +//extern int RSkey; +//extern int LSkey; + extern bool lockInputWithTheEndKey; extern bool lockInputSuspendsExplorer; extern bool freezeGameInputWhileInputNotLocked; diff --git a/src/ProtoInput/ProtoInputInjector/ProtoInputInjector.vcxproj b/src/ProtoInput/ProtoInputInjector/ProtoInputInjector.vcxproj index 49ba5a5..4846bc5 100644 --- a/src/ProtoInput/ProtoInputInjector/ProtoInputInjector.vcxproj +++ b/src/ProtoInput/ProtoInputInjector/ProtoInputInjector.vcxproj @@ -23,7 +23,7 @@ Win32Proj {f35b945e-f71b-4f81-ab1e-f5a148180ba0} ProtoInputInjector - 10.0 + 10.0.18362.0 diff --git a/src/ProtoInput/ProtoInputInjectorProxy/ProtoInputInjectorProxy.vcxproj b/src/ProtoInput/ProtoInputInjectorProxy/ProtoInputInjectorProxy.vcxproj index 1e45a17..bf8162d 100644 --- a/src/ProtoInput/ProtoInputInjectorProxy/ProtoInputInjectorProxy.vcxproj +++ b/src/ProtoInput/ProtoInputInjectorProxy/ProtoInputInjectorProxy.vcxproj @@ -23,7 +23,7 @@ Win32Proj {218630bd-13d1-4c93-b5c0-db191018db41} ProtoInputInjectorProxy - 10.0 + 10.0.18362.0 diff --git a/src/ProtoInput/ProtoInputLoader/Inject.cpp b/src/ProtoInput/ProtoInputLoader/Inject.cpp index 58bcf33..210f59d 100644 --- a/src/ProtoInput/ProtoInputLoader/Inject.cpp +++ b/src/ProtoInput/ProtoInputLoader/Inject.cpp @@ -46,6 +46,65 @@ bool Isx64(unsigned long pid) return !is32; } +void AddSelectedInputHandleImpl(ProtoInstanceHandle instanceHandle, unsigned int handle, bool mouse) +{ + if (const auto find = Proto::instances.find(instanceHandle); find != Proto::instances.end()) + { + auto& instance = find->second; + + WaitClientConnect(instance); + + ProtoPipe::PipeMessageAddSelectedMouseOrKeyboard message //spelling okay? + { + mouse ? handle : -1, + mouse ? -1 : handle + }; + + ProtoSendPipeMessage(instance.pipeHandle, ProtoPipe::PipeMessageType::AddSelectedMouseOrKeyboard, &message); + } +} +extern "C" __declspec(dllexport) void AddSelectedMouseHandle(ProtoInstanceHandle instanceHandle, unsigned int mouseHandle) +{ + AddSelectedInputHandleImpl(instanceHandle, mouseHandle, true); +} + +extern "C" __declspec(dllexport) void AddSelectedKeyboardHandle(ProtoInstanceHandle instanceHandle, unsigned int keyboardHandle) +{ + AddSelectedInputHandleImpl(instanceHandle, keyboardHandle, false); +} +void SetTranslateXinputtoMKB(ProtoInstanceHandle instanceHandle, bool TranslateXinputtoMKB) +{ + if (const auto find = Proto::instances.find(instanceHandle); find != Proto::instances.end()) + { + auto& instance = find->second; + + WaitClientConnect(instance); + + ProtoPipe::PipeMessageSetTranslateXinputtoMKB message + { + TranslateXinputtoMKB + }; + + ProtoSendPipeMessage(instance.pipeHandle, ProtoPipe::PipeMessageType::SetTranslateXinputtoMKB, &message); + } +} +void SetReregisterinput(ProtoInstanceHandle instanceHandle, bool enabled) +{ + if (const auto find = Proto::instances.find(instanceHandle); find != Proto::instances.end()) + { + auto& instance = find->second; + + WaitClientConnect(instance); + + ProtoPipe::PipeMessageSetReregisterinput message + { + enabled + }; + + ProtoSendPipeMessage(instance.pipeHandle, ProtoPipe::PipeMessageType::SetReregisterinput, &message); + } +} + extern "C" __declspec(dllexport) void StartFocusMessageLoop(ProtoInstanceHandle instanceHandle, int milliseconds, bool wm_activate, bool wm_activateapp, bool wm_ncactivate, bool wm_setfocus, bool wm_mouseactivate) @@ -138,33 +197,7 @@ extern "C" __declspec(dllexport) void SetExternalFreezeFakeInput(ProtoInstanceHa } } -void AddSelectedInputHandleImpl(ProtoInstanceHandle instanceHandle, unsigned int handle, bool mouse) -{ - if (const auto find = Proto::instances.find(instanceHandle); find != Proto::instances.end()) - { - auto& instance = find->second; - - WaitClientConnect(instance); - - ProtoPipe::PipeMesasgeAddSelectedMouseOrKeyboard message //spelling okay? - { - mouse ? handle : -1, - mouse ? -1 : handle - }; - - ProtoSendPipeMessage(instance.pipeHandle, ProtoPipe::PipeMessageType::AddSelectedMouseOrKeyboard, &message); - } -} - -extern "C" __declspec(dllexport) void AddSelectedMouseHandle(ProtoInstanceHandle instanceHandle, unsigned int mouseHandle) -{ - AddSelectedInputHandleImpl(instanceHandle, mouseHandle, true); -} -extern "C" __declspec(dllexport) void AddSelectedKeyboardHandle(ProtoInstanceHandle instanceHandle, unsigned int keyboardHandle) -{ - AddSelectedInputHandleImpl(instanceHandle, keyboardHandle, false); -} extern "C" __declspec(dllexport) void SetControllerIndex(ProtoInstanceHandle instanceHandle, unsigned int controllerIndex, unsigned int controllerIndex2, unsigned int controllerIndex3, unsigned int controllerIndex4) { @@ -221,6 +254,22 @@ void SetUseOpenXinput(ProtoInstanceHandle instanceHandle, bool useOpenXinput) } } +void SetTranslateMKBtoXinput(ProtoInstanceHandle instanceHandle, bool TranslateMKBtoXinput) +{ + if (const auto find = Proto::instances.find(instanceHandle); find != Proto::instances.end()) + { + auto& instance = find->second; + + WaitClientConnect(instance); + + ProtoPipe::PipeMessageSetTranslateMKBtoXinput message + { + TranslateMKBtoXinput + }; + + ProtoSendPipeMessage(instance.pipeHandle, ProtoPipe::PipeMessageType::TranslateMKBtoXinput, &message); + } +} extern "C" __declspec(dllexport) void SetupState(ProtoInstanceHandle instanceHandle, int instanceIndex) { if (instanceIndex < 1) @@ -527,6 +576,23 @@ void SetRawInputBypass(ProtoInstanceHandle instanceHandle, bool enabled) } } +void SetPointerInMouse(ProtoInstanceHandle instanceHandle, bool enabled) +{ + if (const auto find = Proto::instances.find(instanceHandle); find != Proto::instances.end()) + { + auto& instance = find->second; + + WaitClientConnect(instance); + + ProtoPipe::PipeMessageSetPointerInMouse message + { + enabled + }; + + ProtoSendPipeMessage(instance.pipeHandle, ProtoPipe::PipeMessageType::SetPointerInMouse, &message); + } +} + void SetShowCursorWhenImageUpdated(ProtoInstanceHandle instanceHandle, bool enabled) { if (const auto find = Proto::instances.find(instanceHandle); find != Proto::instances.end()) @@ -678,4 +744,89 @@ void SetDontWaitWindowBorder(ProtoInstanceHandle instanceHandle, bool enabled) ProtoSendPipeMessage(instance.pipeHandle, ProtoPipe::PipeMessageType::SetDontWaitWindowBorder, &message); } +} +void SetManualScaling(ProtoInstanceHandle instanceHandle, int oldX, int oldY, int newX, int newY) +{ + if (const auto find = Proto::instances.find(instanceHandle); find != Proto::instances.end()) + { + auto& instance = find->second; + + WaitClientConnect(instance); + + ProtoPipe::PipeMessageSetManualScaling message + { + oldX, + oldY, + newX, + newY + }; + + ProtoSendPipeMessage(instance.pipeHandle, ProtoPipe::PipeMessageType::SetManualScaling, &message); + } +} +void SetXinputtoMKBkeys(ProtoInstanceHandle instanceHandle, int XinputtoMKBAkey, int XinputtoMKBBkey, int XinputtoMKBXkey, int XinputtoMKBYkey, int XinputtoMKBRSkey, int XinputtoMKBLSkey, int XinputtoMKBrightkey, int XinputtoMKBleftkey, int XinputtoMKBupkey, int XinputtoMKBdownkey, int XinputtoMKBstickR, int XinputtoMKBstickL, int XinputtoMKBstickright, int XinputtoMKBstickleft, int XinputtoMKBstickup, int XinputtoMKBstickdown, int XinputtoMKBoption, int XinputtoMKBstart, int XinputtoMKBsens, int XinputtoMKBsensmult, int XinputtoMKBDeadzone) +{ + if (const auto find = Proto::instances.find(instanceHandle); find != Proto::instances.end()) + { + auto& instance = find->second; + + WaitClientConnect(instance); + + ProtoPipe::PipeMessageSetXinputtoMKBkeys message + { + XinputtoMKBAkey, + XinputtoMKBBkey, + XinputtoMKBXkey, + XinputtoMKBYkey, + XinputtoMKBRSkey, + XinputtoMKBLSkey, + XinputtoMKBrightkey, + XinputtoMKBleftkey, + XinputtoMKBupkey, + XinputtoMKBdownkey, + XinputtoMKBstickR, + XinputtoMKBstickL, + XinputtoMKBstickright, + XinputtoMKBstickleft, + XinputtoMKBstickup, + XinputtoMKBstickdown, + XinputtoMKBoption, + XinputtoMKBstart, + XinputtoMKBsens, + XinputtoMKBsensmult, + XinputtoMKBDeadzone + }; + + ProtoSendPipeMessage(instance.pipeHandle, ProtoPipe::PipeMessageType::SetXinputtoMKBkeys, &message); + } +} +void SetXinputtoMKBCFG(ProtoInstanceHandle instanceHandle, bool stickinvert, bool scanoption, bool shoulderswap, bool astatic, bool aclick, bool amove, bool bstatic, bool bclick, bool bmove, bool xstatic, bool xclick, bool xmove, bool ystatic, bool yclick, bool ymove ) +{ + if (const auto find = Proto::instances.find(instanceHandle); find != Proto::instances.end()) + { + auto& instance = find->second; + + WaitClientConnect(instance); + + ProtoPipe::PipeMessageSetXinputtoMKBCFG message + { + stickinvert, + scanoption, + shoulderswap, + astatic, + aclick, + amove, + bstatic, + bclick, + bmove, + xstatic, + xclick, + xmove, + ystatic, + yclick, + ymove + }; + + ProtoSendPipeMessage(instance.pipeHandle, ProtoPipe::PipeMessageType::SetXinputtoMKBCFG, &message); + } } \ No newline at end of file diff --git a/src/ProtoInput/ProtoInputLoader/ProtoInputLoader.vcxproj b/src/ProtoInput/ProtoInputLoader/ProtoInputLoader.vcxproj index 6b1ff09..d7f6646 100644 --- a/src/ProtoInput/ProtoInputLoader/ProtoInputLoader.vcxproj +++ b/src/ProtoInput/ProtoInputLoader/ProtoInputLoader.vcxproj @@ -23,7 +23,7 @@ {564C672A-AEB8-4C04-A349-B125A3A552DB} Win32Proj ProtoInputLoader - 10.0 + 10.0.18362.0 diff --git a/src/ProtoInput/ProtoInputLoader/include/protoloader.h b/src/ProtoInput/ProtoInputLoader/include/protoloader.h index 853489a..4ac8e35 100644 --- a/src/ProtoInput/ProtoInputLoader/include/protoloader.h +++ b/src/ProtoInput/ProtoInputLoader/include/protoloader.h @@ -27,7 +27,8 @@ enum ProtoHookIDs : unsigned int WindowStyleHookID, MoveWindowHookID, AdjustWindowRectHookID, - RemoveBorderHookID + RemoveBorderHookID, + GetCursorInfoHookID }; enum ProtoMessageFilterIDs : unsigned int @@ -55,6 +56,11 @@ extern "C" __declspec(dllexport) ProtoInstanceHandle EasyHookInjectStartup( unsigned long* outPid, void* environment = nullptr); + +extern "C" __declspec(dllexport) void AddSelectedMouseHandle(ProtoInstanceHandle instanceHandle, unsigned int mouseHandle); +extern "C" __declspec(dllexport) void AddSelectedKeyboardHandle(ProtoInstanceHandle instanceHandle, unsigned int keyboardHandle); +extern "C" __declspec(dllexport) void SetTranslateXinputtoMKB(ProtoInstanceHandle instanceHandle, bool TranslateXinputtoMKB); +extern "C" __declspec(dllexport) void SetReregisterinput(ProtoInstanceHandle instanceHandle, bool enabled); extern "C" __declspec(dllexport) void InstallHook(ProtoInstanceHandle instanceHandle, ProtoHookIDs hookID); extern "C" __declspec(dllexport) void UninstallHook(ProtoInstanceHandle instanceHandle, ProtoHookIDs hookID); @@ -84,16 +90,16 @@ extern "C" __declspec(dllexport) void SetDrawFakeCursorFix(ProtoInstanceHandle i extern "C" __declspec(dllexport) void SetExternalFreezeFakeInput(ProtoInstanceHandle instanceHandle, bool enableFreeze); -extern "C" __declspec(dllexport) void AddSelectedMouseHandle(ProtoInstanceHandle instanceHandle, unsigned int mouseHandle); -extern "C" __declspec(dllexport) void AddSelectedKeyboardHandle(ProtoInstanceHandle instanceHandle, unsigned int keyboardHandle); -extern "C" __declspec(dllexport) void SetControllerIndex(ProtoInstanceHandle instanceHandle, unsigned int controllerIndex, unsigned int controllerIndex2 = 0, unsigned int controllerIndex3 = 0, unsigned int controllerIndex4 = 0); +extern "C" __declspec(dllexport) void SetControllerIndex(ProtoInstanceHandle instanceHandle, unsigned int controllerIndex, unsigned int controllerIndex2, unsigned int controllerIndex3, unsigned int controllerIndex4); // This MUST be called before calling InstallHook on the Xinput hook extern "C" __declspec(dllexport) void SetUseDinputRedirection(ProtoInstanceHandle instanceHandle, bool useRedirection); extern "C" __declspec(dllexport) void SetUseOpenXinput(ProtoInstanceHandle instanceHandle, bool useOpenXinput); +extern "C" __declspec(dllexport) void SetTranslateMKBtoXinput(ProtoInstanceHandle instanceHandle, bool TranslateMKBtoXinput); + // Both of these functions require RenameHandlesHookHookID hook extern "C" __declspec(dllexport) void AddHandleToRename(ProtoInstanceHandle instanceHandle, const wchar_t* name); @@ -131,6 +137,8 @@ extern "C" __declspec(dllexport) void SetToggleFakeCursorVisibilityShortcut(Prot extern "C" __declspec(dllexport) void SetRawInputBypass(ProtoInstanceHandle instanceHandle, bool enabled); +extern "C" __declspec(dllexport) void SetPointerInMouse(ProtoInstanceHandle instanceHandle, bool enabled); + extern "C" __declspec(dllexport) void SetShowCursorWhenImageUpdated(ProtoInstanceHandle instanceHandle, bool enabled); extern "C" __declspec(dllexport) void SetPutMouseInsideWindow(ProtoInstanceHandle instanceHandle, bool enabled); @@ -147,4 +155,10 @@ extern "C" __declspec(dllexport) void SetMoveWindowDontReposition(ProtoInstanceH extern "C" __declspec(dllexport) void SetAdjustWindowRectSettings(ProtoInstanceHandle instanceHandle, int posx, int posy, int width, int height); -extern "C" __declspec(dllexport) void SetDontWaitWindowBorder(ProtoInstanceHandle instanceHandle, bool enabled); \ No newline at end of file +extern "C" __declspec(dllexport) void SetDontWaitWindowBorder(ProtoInstanceHandle instanceHandle, bool enabled); + +extern "C" __declspec(dllexport) void SetManualScaling(ProtoInstanceHandle instanceHandle, int oldX, int oldY, int newX, int newY); + +extern "C" __declspec(dllexport) void SetXinputtoMKBkeys(ProtoInstanceHandle instanceHandle, int XinputtoMKBAkey, int XinputtoMKBBkey, int XinputtoMKBXkey, int XinputtoMKBYkey, int XinputtoMKBRSkey, int XinputtoMKBLSkey, int XinputtoMKBrightkey, int XinputtoMKBleftkey, int XinputtoMKBupkey, int XinputtoMKBdownkey, int XinputtoMKBstickR, int XinputtoMKBstickL, int XinputtoMKBstickright, int XinputtoMKBstickleft, int XinputtoMKBstickup, int XinputtoMKBstickdown, int XinputtoMKBoption, int XinputtoMKBstart, int XinputtoMKBsens, int XinputtoMKBsensmult, int XinputtoMKBDeadzone); + +extern "C" __declspec(dllexport) void SetXinputtoMKBCFG(ProtoInstanceHandle instanceHandle, bool stickinvert, bool scanoption, bool shoulderswap, bool astatic, bool aclick, bool amove, bool bstatic, bool bclick, bool bmove, bool xstatic, bool xclick, bool xmove, bool ystatic, bool yclick, bool ymove); \ No newline at end of file diff --git a/src/ProtoInput/ProtoInputUtil/ProtoInputUtil.vcxproj b/src/ProtoInput/ProtoInputUtil/ProtoInputUtil.vcxproj index 2224c9e..d64c6c8 100644 --- a/src/ProtoInput/ProtoInputUtil/ProtoInputUtil.vcxproj +++ b/src/ProtoInput/ProtoInputUtil/ProtoInputUtil.vcxproj @@ -23,7 +23,7 @@ Win32Proj {1b052c6a-f9e6-4b73-be05-b33bb100b975} ProtoInputUtil - 10.0 + 10.0.18362.0 ProtoInputUtilStatic diff --git a/src/ProtoInput/ProtoInputUtilDynamic/ProtoInputUtilDynamic.vcxproj b/src/ProtoInput/ProtoInputUtilDynamic/ProtoInputUtilDynamic.vcxproj index e423b39..7be1af7 100644 --- a/src/ProtoInput/ProtoInputUtilDynamic/ProtoInputUtilDynamic.vcxproj +++ b/src/ProtoInput/ProtoInputUtilDynamic/ProtoInputUtilDynamic.vcxproj @@ -23,7 +23,7 @@ Win32Proj {c47d024a-b89c-4f08-9e5d-0a07946cf0b1} ProtoInputUtilDynamic - 10.0 + 10.0.18362.0 diff --git a/src/ProtoInput/UpgradeLog.htm b/src/ProtoInput/UpgradeLog.htm new file mode 100644 index 0000000..5b72eec --- /dev/null +++ b/src/ProtoInput/UpgradeLog.htm @@ -0,0 +1,284 @@ + + + + Migration Report +

+ Migration Report -

Overview

ProjectPathErrorsWarningsMessages
BlackBone..\..\lib\Blackbone\src\BlackBone\BlackBone.vcxproj100
DEVOBJ..\..\lib\openxinput-OpenXinput1_4\DEVOBJ\DEVOBJ.vcxproj100
EasyHookDll..\..\lib\EasyHook\EasyHookDll\EasyHookDll.vcxproj100
OpenXinput..\..\lib\openxinput-OpenXinput1_4\OpenXinput.vcxproj100
ProtoInputHooksProtoInputHooks\ProtoInputHooks.vcxproj100
ProtoInputHostProtoInputHost\ProtoInputHost.vcxproj100
ProtoInputInjectorProtoInputInjector\ProtoInputInjector.vcxproj100
ProtoInputInjectorProxyProtoInputInjectorProxy\ProtoInputInjectorProxy.vcxproj100
ProtoInputLoaderProtoInputLoader\ProtoInputLoader.vcxproj100
ProtoInputUtilDynamicProtoInputUtilDynamic\ProtoInputUtilDynamic.vcxproj100
ProtoInputUtilStaticProtoInputUtil\ProtoInputUtil.vcxproj100
XinputXinput000
SolutionProtoInput.sln001

Solution and projects

BlackBone

Message
..\..\lib\Blackbone\src\BlackBone\BlackBone.vcxproj: + The application which this project type is based on was not found. Please try this link for further information: 8bc9ceb8-8b4a-11d0-8d11-00a0c91bc942

DEVOBJ

Message
..\..\lib\openxinput-OpenXinput1_4\DEVOBJ\DEVOBJ.vcxproj: + The application which this project type is based on was not found. Please try this link for further information: 8bc9ceb8-8b4a-11d0-8d11-00a0c91bc942

EasyHookDll

Message
..\..\lib\EasyHook\EasyHookDll\EasyHookDll.vcxproj: + The application which this project type is based on was not found. Please try this link for further information: 8bc9ceb8-8b4a-11d0-8d11-00a0c91bc942

OpenXinput

Message
..\..\lib\openxinput-OpenXinput1_4\OpenXinput.vcxproj: + The application which this project type is based on was not found. Please try this link for further information: 8bc9ceb8-8b4a-11d0-8d11-00a0c91bc942

ProtoInputHooks

Message
ProtoInputHooks\ProtoInputHooks.vcxproj: + The application which this project type is based on was not found. Please try this link for further information: 8bc9ceb8-8b4a-11d0-8d11-00a0c91bc942

ProtoInputHost

Message
ProtoInputHost\ProtoInputHost.vcxproj: + The application which this project type is based on was not found. Please try this link for further information: 8bc9ceb8-8b4a-11d0-8d11-00a0c91bc942

ProtoInputInjector

Message
ProtoInputInjector\ProtoInputInjector.vcxproj: + The application which this project type is based on was not found. Please try this link for further information: 8bc9ceb8-8b4a-11d0-8d11-00a0c91bc942

ProtoInputInjectorProxy

Message
ProtoInputInjectorProxy\ProtoInputInjectorProxy.vcxproj: + The application which this project type is based on was not found. Please try this link for further information: 8bc9ceb8-8b4a-11d0-8d11-00a0c91bc942

ProtoInputLoader

Message
ProtoInputLoader\ProtoInputLoader.vcxproj: + The application which this project type is based on was not found. Please try this link for further information: 8bc9ceb8-8b4a-11d0-8d11-00a0c91bc942

ProtoInputUtilDynamic

Message
ProtoInputUtilDynamic\ProtoInputUtilDynamic.vcxproj: + The application which this project type is based on was not found. Please try this link for further information: 8bc9ceb8-8b4a-11d0-8d11-00a0c91bc942

ProtoInputUtilStatic

Message
ProtoInputUtil\ProtoInputUtil.vcxproj: + The application which this project type is based on was not found. Please try this link for further information: 8bc9ceb8-8b4a-11d0-8d11-00a0c91bc942

Xinput

Message
Xinput logged no messages. +

Solution

Message
+ Show 1 additional messages +
ProtoInput.sln: + The solution file does not require migration.
+ Hide 1 additional messages +
\ No newline at end of file