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..6fd47a5 100644 --- a/src/ProtoInput/ProtoInputHooks/FakeCursor.cpp +++ b/src/ProtoInput/ProtoInputHooks/FakeCursor.cpp @@ -3,6 +3,11 @@ #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 @@ -10,6 +15,13 @@ namespace Proto FakeCursor FakeCursor::state{}; +//TranslateXtoMKB +POINT OldspotA, OldspotB, OldspotX, OldspotY; +int FakeCursor::Showmessage = 0; +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 + LRESULT WINAPI FakeCursorWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) { switch (msg) @@ -40,21 +52,294 @@ 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); +} +POINT OldTestpos = { 0,0 }; + +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){ + // DrawGreenTriangle(hdc, here.x + 50, here.y + 50); + TextOutW(hdc, here.x + 20, here.y + 20, TEXT("DISCONNECTED!"), 14); //14 + messageshown = true; + } + if (message == 2) { + // DrawGreenTriangle(hdc, here.x + 50, here.y + 50); + TextOutW(hdc, here.x + 20, here.y + 20, TEXT("GUI TOGGLE!"), 11); //14 + messageshown = true; + } + if (message == 3) { + // DrawGreenTriangle(hdc, here.x + 50, here.y + 50); + TextOutW(hdc, here.x + 20, here.y + 20, TEXT("SHOWCURSOR TOGGLE!"), 18); //14 + messageshown = true; + } + if (message == 4) { + // DrawGreenTriangle(hdc, here.x + 50, here.y + 50); + TextOutW(hdc, here.x + 20, here.y + 20, TEXT("LOCK TOGGLED!"), 13); //14 + messageshown = true; + } + if (message == 5) { + // DrawGreenTriangle(hdc, here.x + 50, here.y + 50); + 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) { + // DrawGreenTriangle(hdc, here.x + 50, here.y + 50); + 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) { + // DrawGreenTriangle(hdc, here.x + 50, here.y + 50); + TextOutW(hdc, here.x + 20, here.y + 0, TEXT("BMP SAVE MODE!"), 14); //14 + messageshown = true; + } + if (message == 10) { + // DrawGreenTriangle(hdc, here.x + 50, here.y + 50); + TextOutW(hdc, here.x + 20, here.y + 25, TEXT("A MAPPED TO SPOT!"), 17); //14 + messageshown = true; + } + if (message == 11) { + // DrawGreenTriangle(hdc, here.x + 50, here.y + 50); + TextOutW(hdc, here.x + 20, here.y + 25, TEXT("B MAPPED TO SPOT!"), 17); //14 + messageshown = true; + } + if (message == 12) { + // DrawGreenTriangle(hdc, here.x + 50, here.y + 50); + TextOutW(hdc, here.x + 20, here.y + 25, TEXT("X MAPPED TO SPOT!"), 17); //14 + messageshown = true; + } + if (message == 13) { + // DrawGreenTriangle(hdc, here.x + 50, here.y + 50); + 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) + { + windowmoved = true; + //MessageBoxA(NULL, "Window moved!", "Debug", MB_OK); + } + if (OldspotA.x != spotA.x || OldspotA.y != spotA.y) + { + RECT wholewindow; + GetClientRect(pointerWindow, &wholewindow); + + FillRect(hdc, &wholewindow, Brush); + erased = true; + ScreenshotInput::TranslateXtoMKB::RefreshWindow = 1; //redraw cursor + } + + if (OldspotB.x != spotB.x || OldspotB.y != spotB.y) //|| windowmoved) + { + RECT wholewindow; + GetClientRect(pointerWindow, &wholewindow); + + FillRect(hdc, &wholewindow, Brush); + erased = true; + ScreenshotInput::TranslateXtoMKB::RefreshWindow = 1; //redraw cursor + } + if (OldspotX.x != spotX.x || OldspotX.y != spotX.y) //|| windowmoved) + { + RECT wholewindow; + GetClientRect(pointerWindow, &wholewindow); + + FillRect(hdc, &wholewindow, Brush); + erased = true; + ScreenshotInput::TranslateXtoMKB::RefreshWindow = 1; //redraw cursor + } + if (OldspotY.x != spotY.x || OldspotY.y != spotY.y) //|| windowmoved) + { + RECT wholewindow; + GetClientRect(pointerWindow, &wholewindow); + + FillRect(hdc, &wholewindow, Brush); + erased = 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 && erased == true) + { + ClientToScreen(window, &spotA); + DrawRedX(hdc, spotA.x, spotA.y); + //MessageBoxA(NULL, "Spot A drawn!", "Debug", MB_OK); + erasedA = false; + } + if (spotB.x != 0 && spotB.y != 0 && erased == true) + { + ClientToScreen(window, &spotB); + DrawBlueCircle(hdc, spotB.x, spotB.y); + } + if (spotX.x != 0 && spotX.y != 0 && erased == true) + { + ClientToScreen(window, &spotX); + DrawGreenTriangle(hdc, spotX.x, spotX.y); + } + if (spotY.x != 0 && spotY.y != 0 && erased == true) + { + ClientToScreen(window, &spotY); + DrawPinkSquare(hdc, spotY.x, spotY.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) { @@ -68,39 +353,77 @@ void FakeCursor::DrawCursor() { 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 +444,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 +467,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 +598,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..0a4a2e1 100644 --- a/src/ProtoInput/ProtoInputHooks/FakeCursor.h +++ b/src/ProtoInput/ProtoInputHooks/FakeCursor.h @@ -5,45 +5,53 @@ 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; + + // 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; + + 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; void StartInternal(); void StartDrawLoopInternal(); + static int Showmessage; static bool& GetToggleVisilbityShorcutEnabled() { return state.toggleVisilbityShorcutEnabled; @@ -87,7 +95,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..ef8ba87 --- /dev/null +++ b/src/ProtoInput/ProtoInputHooks/GetCursorInfoHook.cpp @@ -0,0 +1,63 @@ +#include "GetCursorInfoHook.h" +#include "FakeMouseKeyboard.h" +#include "HwndSelector.h" +#include "Scaler.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 = Scaler::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..0e1a016 --- /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 "Get Cursor Position with 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..ed8a2b6 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 "Scaler.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 = Scaler::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..cb1fb84 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,6 +19,7 @@ UINT WINAPI Hook_GetRawInputData( UINT cbSizeHeader ) { + unsigned int h = (unsigned int)hRawInput; // Only care about first 4 bytes. bool hasSignature = (h & 0xFF000000) == 0xAB000000; if (!hasSignature) @@ -51,13 +56,13 @@ UINT WINAPI Hook_GetRawInputData( } } -// void GetRawInputDataHook::ShowGuiStatus() -// { -// } - void GetRawInputDataHook::InstallImpl() { - hookInfo = std::get<1>(InstallNamedHook(L"user32", "GetRawInputData", Hook_GetRawInputData)); + if (RawInput::TranslateXinputtoMKB) + hookInfo = std::get<1>(InstallNamedHook(L"user32", "GetRawInputData", ScreenshotInput::RawInputHooks::GetRawInputDataHookX)); + else + 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..8bd9e3f --- /dev/null +++ b/src/ProtoInput/ProtoInputHooks/GtoMnK_RawInput.cpp @@ -0,0 +1,303 @@ +#include "GtoMnK_RawInput.h" +#include "GtoMnK_RawInputHooks.h" +#include "HwndSelector.h" + +namespace ScreenshotInput { + + //public + RAWINPUT RawInput::g_inputBuffer[20]{}; + std::vector RawInput::g_forwardingWindows{}; + HWND RawInput::g_rawInputHwnd = nullptr; + bool RawInput::createdWindowIsOwned; + LRESULT WINAPI RawInputWindowWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); + DWORD WINAPI RawInputWindowThread(LPVOID lpParameter); + //void RecoverMissedRegistration(); + + // A fix for RawInput registrations that get lost. e.g when we use `StartUpDelay` or add a dinput.dll + void RecoverMissedRegistration() { + UINT nDevices = 0; + GetRegisteredRawInputDevices(NULL, &nDevices, sizeof(RAWINPUTDEVICE)); + + if (nDevices == 0) return; + + std::vector devices(nDevices); + if (GetRegisteredRawInputDevices(devices.data(), &nDevices, sizeof(RAWINPUTDEVICE)) == (UINT)-1) { + return; + } + + //LOG("Recovery: checking %u registered RawInput devices...", nDevices); + + for (const auto& device : devices) { + if (device.usUsagePage == 1 && device.usUsage == 2) { + + HWND target = device.hwndTarget; + + // If target is NULL, it means "Focus Window", so we rely on our Foreground check. + // But if it is NOT NULL, it is the specific window (likely hidden) the game wants. + if (target != NULL) { + + bool known = false; + for (auto w : RawInput::g_forwardingWindows) { + if (w == target) { known = true; break; } + } + + if (!known) { + //LOG("Recovery: Found registered RawInput Target (0x%p). Adding to list.", target); + RawInput::g_forwardingWindows.push_back(target); + } + } + } + } + } + void RawInput::Initialize() { + // LOG("RawInput System: Initializing..."); + + RecoverMissedRegistration(); + + HANDLE hWindowReadyEvent = CreateEvent(NULL, TRUE, FALSE, NULL); + if (hWindowReadyEvent == NULL) { + //LOG("FATAL: Could not create window ready event!"); + return; + } + + HANDLE hThread = CreateThread(nullptr, 0, RawInputWindowThread, hWindowReadyEvent, 0, 0); + if (hThread) { + WaitForSingleObject(hWindowReadyEvent, 2000); + CloseHandle(hThread); + } + // RawInputHooks::InstallHooks(); + CloseHandle(hWindowReadyEvent); + } + + void RawInput::Shutdown() { + //LOG("RawInput System: Shutting down..."); + + if (RawInput::g_rawInputHwnd) { + PostMessage(RawInput::g_rawInputHwnd, WM_QUIT, 0, 0); + } + } + + + LRESULT WINAPI RawInputWindowWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) + { + switch (msg) + { + case WM_DESTROY: { + PostQuitMessage(0); + return 0; + } + } + return DefWindowProc(hWnd, msg, wParam, lParam); + } + + DWORD WINAPI RawInputWindowThread(LPVOID lpParameter) { + HANDLE hWindowReadyEvent = (HANDLE)lpParameter; + + /*if (createdWindowIsOwned) + { + hwnd = GetMainWindowHandle(GetCurrentProcessId(), iniWindowName, iniClassName, 60000); + + if (!hwnd || !IsWindow(hwnd)) { + LOG("Timeout: Game Window never appeared. RawInput aborting."); + return 1; + } + LOG("RawInput window is owned by the game window."); + }*/ + + //LOG("RawInput hidden window thread started."); + WNDCLASSW wc = { 0 }; + wc.lpfnWndProc = RawInputWindowWndProc; + wc.hInstance = GetModuleHandle(NULL); + wc.lpszClassName = L"GtoMnK_RawInput_Window"; + + HWND parentWindow; + if (RawInput::createdWindowIsOwned) + parentWindow = (HWND)Proto::HwndSelector::GetSelectedHwnd(); + else + parentWindow = nullptr; + + if (RegisterClassW(&wc)) { + RawInput::g_rawInputHwnd = CreateWindowW(wc.lpszClassName, L"GtoMnK RI Sink", 0, 0, 0, 0, 0, parentWindow, NULL, wc.hInstance, NULL); + } + + if (!RawInput::g_rawInputHwnd) { + //LOG("FATAL: Failed to create RawInput hidden window!"); + SetEvent(hWindowReadyEvent); + return 1; + } + + SetEvent(hWindowReadyEvent); + //LOG("RawInput hidden window created and ready."); + + MSG msg; + while (GetMessage(&msg, NULL, 0, 0) > 0) { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + + //LOG("RawInput hidden window thread finished."); + return 0; + } + + void RawInput::InjectFakeRawInput(const RAWINPUT& fakeInput) { + static size_t bufferCounter = 0; + bufferCounter = (bufferCounter + 1) % RawInput::RAWINPUT_BUFFER_SIZE; + RawInput::g_inputBuffer[bufferCounter] = fakeInput; + + const LPARAM magicLParam = (bufferCounter) | 0xAB000000; + + for (const auto& hwnd : RawInput::g_forwardingWindows) { + PostMessageW(hwnd, WM_INPUT, RIM_INPUT, magicLParam); + + } + } + 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; + } + + 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; + } + 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; + 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..c2125f3 --- /dev/null +++ b/src/ProtoInput/ProtoInputHooks/GtoMnK_RawInput.h @@ -0,0 +1,26 @@ +#pragma once +#include +#include + +namespace ScreenshotInput { + class RawInput { + public: + // To start the RawInput method. + static void Initialize(); + + static void Shutdown(); + + static void InjectFakeRawInput(const RAWINPUT& fakeInput); + 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); + static const int RAWINPUT_BUFFER_SIZE = 20; + static RAWINPUT g_inputBuffer[RAWINPUT_BUFFER_SIZE]; + + + static std::vector g_forwardingWindows; + static HWND g_rawInputHwnd; + static bool createdWindowIsOwned; + }; +} \ 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..bb8f6c3 --- /dev/null +++ b/src/ProtoInput/ProtoInputHooks/GtoMnK_RawInputHooks.cpp @@ -0,0 +1,64 @@ +//#include "pch.h" +#include "GtoMnK_RawInputHooks.h" +#include "GtoMnK_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 }; + + + UINT WINAPI RawInputHooks::GetRawInputDataHookX(HRAWINPUT hRawInput, UINT uiCommand, LPVOID pData, PUINT pcbSize, UINT cbSizeHeader) { + UINT handleValue = (UINT)(UINT_PTR)hRawInput; + if ((handleValue & 0xFF000000) == 0xAB000000) { + + UINT bufferIndex = handleValue & 0x00FFFFFF; + if (bufferIndex >= ScreenshotInput::RawInput::RAWINPUT_BUFFER_SIZE) { + return GetRawInputData(hRawInput, uiCommand, pData, pcbSize, cbSizeHeader); + } + + if (pData == NULL) { + *pcbSize = sizeof(RAWINPUT); + return 0; + } + + RAWINPUT* storedData = &ScreenshotInput::RawInput::g_inputBuffer[bufferIndex]; + memcpy(pData, storedData, sizeof(RAWINPUT)); + return sizeof(RAWINPUT); + + } + else { + return GetRawInputData(hRawInput, uiCommand, pData, pcbSize, cbSizeHeader); + } + } + + BOOL WINAPI RawInputHooks::RegisterRawInputDevicesHookX(PCRAWINPUTDEVICE pRawInputDevices, UINT uiNumDevices, UINT cbSize) { + for (UINT i = 0; i < uiNumDevices; ++i) { + HWND targetHwnd = pRawInputDevices[i].hwndTarget; + + if (targetHwnd != NULL && targetHwnd != ScreenshotInput::RawInput::g_rawInputHwnd) { + auto& windows = ScreenshotInput::RawInput::g_forwardingWindows; + if (std::find(windows.begin(), windows.end(), targetHwnd) == windows.end()) { + //LOG("Captured new game window HWND: 0x%p", targetHwnd); + windows.push_back(targetHwnd); + } + } + } + return TRUE; + } + // 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..cb8e00a 100644 --- a/src/ProtoInput/ProtoInputHooks/Gui.cpp +++ b/src/ProtoInput/ProtoInputHooks/Gui.cpp @@ -13,10 +13,13 @@ #include "FocusMessageLoop.h" #include "StateInfo.h" #include "FakeCursor.h" +#include "TranslateXtoMKB.h" +#include "ScanThread.h" +#include "GtoMnK_RawInput.h" +#include "XinputHook.h" namespace Proto { - intptr_t ConsoleHwnd; static void HelpMarker(const char* desc) @@ -85,7 +88,608 @@ 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(); + { + 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(); @@ -211,28 +815,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 +904,6 @@ void RenderImgui() { // ImGui::ShowDemoWindow(); // return; - const auto displaySize = ImGui::GetIO().DisplaySize; ImGui::SetNextWindowPos(ImVec2(0, 0), ImGuiCond_Always); @@ -322,6 +937,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 +1032,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/PipeCommunication.cpp b/src/ProtoInput/ProtoInputHooks/PipeCommunication.cpp index 4904b8f..0d617ce 100644 --- a/src/ProtoInput/ProtoInputHooks/PipeCommunication.cpp +++ b/src/ProtoInput/ProtoInputHooks/PipeCommunication.cpp @@ -26,6 +26,9 @@ #include "MoveWindowHook.h" #include "AdjustWindowRectHook.h" #include "RemoveBorderHook.h" +#include "TranslateXtoMKB.h" +#include "ScanThread.h" +#include "Scaler.h" namespace Proto { @@ -76,6 +79,7 @@ DWORD WINAPI PipeThread(LPVOID lpParameter) } while (pipe == INVALID_HANDLE_VALUE); + bool gotkeyboardmouse = false; if (pipe != INVALID_HANDLE_VALUE) { printf("Successfully connected pipe \"%ws\"\n", pipeName.c_str()); @@ -124,17 +128,56 @@ 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"); + SetEvent(evt); + 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 +256,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; @@ -295,7 +339,7 @@ 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; @@ -311,20 +355,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 +379,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 +410,16 @@ 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 +454,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 +504,6 @@ DWORD WINAPI PipeThread(LPVOID lpParameter) FakeMouseKeyboard::SetIgnoreMouseBounds(body->allowOutOfBounds); FakeMouseKeyboard::SetExtendMouseBounds(body->extendBounds); - break; } case ProtoPipe::PipeMessageType::SetToggleCursorVisibilityShortcut: @@ -576,9 +623,91 @@ 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); + + Scaler::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; + 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,19 +715,22 @@ 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; } void StartPipeCommunication() { + evt = CreateEvent(nullptr, TRUE, FALSE, nullptr); + HANDLE hThread = CreateThread(nullptr, 0, (LPTHREAD_START_ROUTINE)PipeThread, GetModuleHandle(0), 0, 0); + WaitForSingleObject(evt, INFINITE); //waits on TranslateXtoMKB and input devices settings if (hThread != nullptr) CloseHandle(hThread); + } } diff --git a/src/ProtoInput/ProtoInputHooks/PipeCommunication.h b/src/ProtoInput/ProtoInputHooks/PipeCommunication.h index 7f046d3..276b503 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..b00a36a 100644 --- a/src/ProtoInput/ProtoInputHooks/ProtoInputHooks.vcxproj +++ b/src/ProtoInput/ProtoInputHooks/ProtoInputHooks.vcxproj @@ -87,6 +87,9 @@ $(SolutionDir)$(Configuration)\ $(PlatformShortName)\$(Configuration)\ $(ProjectName)$(PlatformArchitecture) + CppCoreCheckConcurrencyRules.ruleset + true + false false @@ -205,10 +208,13 @@ + + + @@ -232,12 +238,15 @@ + + + @@ -265,10 +274,13 @@ + + + @@ -283,10 +295,13 @@ + + + diff --git a/src/ProtoInput/ProtoInputHooks/ProtoInputHooks.vcxproj.filters b/src/ProtoInput/ProtoInputHooks/ProtoInputHooks.vcxproj.filters index 624e681..4e3f5f3 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,24 @@ Source Files\Hooks + + Source Files\TranslateXtoMKB + + + Source Files\TranslateXtoMKB + + + Source Files\TranslateXtoMKB + + + Source Files\TranslateXtoMKB + + + Source Files\Hooks + + + Source Files + @@ -323,5 +347,23 @@ Source Files\Hooks + + Source Files\TranslateXtoMKB + + + 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..a7488ca 100644 --- a/src/ProtoInput/ProtoInputHooks/RawInput.cpp +++ b/src/ProtoInput/ProtoInputHooks/RawInput.cpp @@ -15,6 +15,8 @@ #include "protoinpututil.h" #include "KeyboardButtonFilter.h" #include "MessageFilterHook.h" +#include "TranslateXtoMKB.h" +#include "XinputHook.h" namespace Proto { @@ -25,11 +27,11 @@ std::vector RawInput::forwardingWindows{}; bool RawInput::forwardRawInput = true; bool RawInput::lockInputToggleEnabled = false; bool RawInput::rawInputBypass = false; - - RAWINPUT RawInput::inputBuffer[RawInputBufferSize]{}; std::vector RawInput::rawinputs{}; - +bool RawInput::TranslateXinputtoMKB; +bool RawInput::locked = false; +bool RawInput::alreadyAddToACL = false; const std::vector RawInput::usageTypesOfInterest { HID_USAGE_GENERIC_POINTER, @@ -43,85 +45,30 @@ 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 +115,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) @@ -202,53 +149,103 @@ void RawInput::ProcessMouseInput(const RAWMOUSE& data, HANDLE deviceHandle) { PostMessageW((HWND)HwndSelector::GetSelectedHwnd(), WM_MOUSEMOVE, mouseMkFlags, mousePointLparam); } + FakeCursor::NotifyUpdatedCursorPosition(); +} +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; - // Fake cursor - FakeCursor::NotifyUpdatedCursorPosition(); + // 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 +253,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 +333,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 +349,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,25 +358,9 @@ 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; } @@ -398,18 +397,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 +440,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 +478,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 +502,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 +556,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()) @@ -614,11 +615,15 @@ std::bitset<9> RawInput::GetUsageBitField() void RawInput::InitialiseRawInput() { RefreshDevices(); + if (!RawInput::TranslateXinputtoMKB) + { - HANDLE hThread = CreateThread(nullptr, 0, - (LPTHREAD_START_ROUTINE)RawInputWindowThread, GetModuleHandle(nullptr), 0, 0); - if (hThread != nullptr) - CloseHandle(hThread); + HANDLE hThread = CreateThread(nullptr, 0, + (LPTHREAD_START_ROUTINE)RawInputWindowThread, GetModuleHandle(nullptr), 0, 0); + if (hThread != nullptr) + CloseHandle(hThread); + } + return; } void RawInput::UnregisterGameFromRawInput() diff --git a/src/ProtoInput/ProtoInputHooks/RawInput.h b/src/ProtoInput/ProtoInputHooks/RawInput.h index dbdc7fd..ded1127 100644 --- a/src/ProtoInput/ProtoInputHooks/RawInput.h +++ b/src/ProtoInput/ProtoInputHooks/RawInput.h @@ -36,17 +36,24 @@ 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 RawInputState rawInputState; static HWND rawInputHwnd; static bool forwardRawInput; + static bool TranslateXinputtoMKB; + static bool TranslateMKBtoXinput; // Passes input from all devices to the game. Proto Input doesn't process anything static bool rawInputBypass; diff --git a/src/ProtoInput/ProtoInputHooks/RegisterRawInputHook.cpp b/src/ProtoInput/ProtoInputHooks/RegisterRawInputHook.cpp index 1d453e1..a21b821 100644 --- a/src/ProtoInput/ProtoInputHooks/RegisterRawInputHook.cpp +++ b/src/ProtoInput/ProtoInputHooks/RegisterRawInputHook.cpp @@ -5,7 +5,8 @@ #include #include "RawInput.h" #include -#include "HwndSelector.h" +#include "HwndSelector.h" //GtoMnK_RawInputHooks +#include "GtoMnK_RawInputHooks.h" //GtoMnK_RawInputHooks namespace Proto { @@ -156,22 +157,29 @@ void RegisterRawInputHook::ShowGuiStatus() void RegisterRawInputHook::InstallImpl() { - if (!installedAtLeastOnce) + if (RawInput::TranslateXinputtoMKB) { - installedAtLeastOnce = true; - std::bitset<9> usages{}; - // usages[HID_USAGE_GENERIC_MOUSE] = true; - // usages[HID_USAGE_GENERIC_KEYBOARD] = true; - RawInput::SetUsageBitField(usages); + auto [status, _hookInfo] = InstallNamedHook(L"user32", "RegisterRawInputDevices", ScreenshotInput::RawInputHooks::RegisterRawInputDevicesHookX); + this->hookInfo = _hookInfo; } + else + { + if (!installedAtLeastOnce) + { + installedAtLeastOnce = true; + std::bitset<9> usages{}; + // usages[HID_USAGE_GENERIC_MOUSE] = true; + // usages[HID_USAGE_GENERIC_KEYBOARD] = true; + RawInput::SetUsageBitField(usages); + } - auto [status, _hookInfo] = InstallNamedHook(L"user32", "RegisterRawInputDevices", Hook_RegisterRawInputDevices); - this->hookInfo = _hookInfo; + auto [status, _hookInfo] = InstallNamedHook(L"user32", "RegisterRawInputDevices", Hook_RegisterRawInputDevices); + this->hookInfo = _hookInfo; - FindAlreadySubscribedWindows(); - - RawInput::UnregisterGameFromRawInput(); - RawInput::RegisterProtoForRawInput(); + FindAlreadySubscribedWindows(); + RawInput::UnregisterGameFromRawInput(); + RawInput::RegisterProtoForRawInput(); + } } void RegisterRawInputHook::UninstallImpl() diff --git a/src/ProtoInput/ProtoInputHooks/Scaler.cpp b/src/ProtoInput/ProtoInputHooks/Scaler.cpp new file mode 100644 index 0000000..d609238 --- /dev/null +++ b/src/ProtoInput/ProtoInputHooks/Scaler.cpp @@ -0,0 +1,148 @@ +#include "Scaler.h" +#include "FakeMouseKeyboard.h" +#include "HwndSelector.h" +#include "SetWindowPosHook.h" +#include +#include +#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; + + WNDPROC g_OldWndProc = nullptr; + + POINT Scaler::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; + } + LRESULT CALLBACK SubclassProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) + { + switch (msg) + { + case WM_MOUSEHOVER: // + MOVE // + click + { + const auto& state = Proto::FakeMouseKeyboard::GetMouseState(); + POINT clientPos = { state.x, state.y }; + clientPos = Scaler::getfactor(clientPos); + LPARAM newLParam = MAKELPARAM(clientPos.x, clientPos.y); + + return CallWindowProc(g_OldWndProc, hwnd, msg, wParam, newLParam); + break; + } + case WM_MOUSEMOVE: + { + const auto& state = Proto::FakeMouseKeyboard::GetMouseState(); + POINT clientPos = { state.x, state.y }; + clientPos = Scaler::getfactor(clientPos); + LPARAM newLParam = MAKELPARAM(clientPos.x, clientPos.y); + + return CallWindowProc(g_OldWndProc, hwnd, msg, wParam, newLParam); + break; + } + case WM_LBUTTONDOWN: + { + const auto& state = Proto::FakeMouseKeyboard::GetMouseState(); + POINT clientPos = { state.x, state.y }; + clientPos = Scaler::getfactor(clientPos); + LPARAM newLParam = MAKELPARAM(clientPos.x, clientPos.y); + return CallWindowProc(g_OldWndProc, hwnd, msg, wParam, newLParam); + + break; + } + case WM_LBUTTONUP: + { + const auto& state = Proto::FakeMouseKeyboard::GetMouseState(); + POINT clientPos = { state.x, state.y }; + clientPos = Scaler::getfactor(clientPos); + LPARAM newLParam = MAKELPARAM(clientPos.x, clientPos.y); + return CallWindowProc(g_OldWndProc, hwnd, msg, wParam, newLParam); + + break; + } + case WM_RBUTTONDOWN: + { + const auto& state = Proto::FakeMouseKeyboard::GetMouseState(); + POINT clientPos = { state.x, state.y }; + clientPos = Scaler::getfactor(clientPos); + LPARAM newLParam = MAKELPARAM(clientPos.x, clientPos.y); + return CallWindowProc(g_OldWndProc, hwnd, msg, wParam, newLParam); + + break; + } + case WM_RBUTTONUP: + { + const auto& state = Proto::FakeMouseKeyboard::GetMouseState(); + POINT clientPos = { state.x, state.y }; + clientPos = Scaler::getfactor(clientPos); + LPARAM newLParam = MAKELPARAM(clientPos.x, clientPos.y); + return CallWindowProc(g_OldWndProc, hwnd, msg, wParam, newLParam); + + break; + } + + } + // Forward all other messages unchanged + return CallWindowProc(g_OldWndProc, hwnd, msg, wParam, lParam); + } + + void Scaler::Install() + { + // MessageBoxA(NULL, "hihu", "letssee", MB_OK); + if (Enableornot && !onlyonetimethis) + { + //MessageBoxA(NULL, "Ohyea", "Scaler enabled", MB_OK); + + g_OldWndProc = (WNDPROC)SetWindowLongPtr( + (HWND)Proto::HwndSelector::GetSelectedHwnd(), + GWLP_WNDPROC, + (LONG_PTR)SubclassProc + ); + onlyonetimethis = true; //or else crash + } + } + void Scaler::Uninstall() + { + if (onlyonetimethis) + { + HWND hwnd = (HWND)Proto::HwndSelector::GetSelectedHwnd(); + + SetWindowLongPtr( + hwnd, + GWLP_WNDPROC, + (LONG_PTR)g_OldWndProc + ); + + onlyonetimethis = false; + } + } + + void Scaler::Settings(int oldX, int oldY, int newX, int newY) + { + Enableornot = true; + scalewidth = newX; + scaleheight = newY; + origwidth = oldX; + origheight = oldY; + if (scalewidth > 5 && scaleheight > 5 && origwidth > 5 && origheight > 5) + Enableornot = true; + else Enableornot = false; + if (Enableornot) + Scaler::Install(); + else Scaler::Uninstall(); + } +} diff --git a/src/ProtoInput/ProtoInputHooks/Scaler.h b/src/ProtoInput/ProtoInputHooks/Scaler.h new file mode 100644 index 0000000..3484c93 --- /dev/null +++ b/src/ProtoInput/ProtoInputHooks/Scaler.h @@ -0,0 +1,20 @@ +#pragma once +#include "Hook.h" +#include "InstallHooks.h" + +namespace Proto +{ + + class Scaler + { + private: + static void Install(); + static void Uninstall(); + + public: + static POINT getfactor(POINT pp); + + static void Settings(int oldX, int oldY, int newX, int newY); + }; + +} diff --git a/src/ProtoInput/ProtoInputHooks/ScanThread.cpp b/src/ProtoInput/ProtoInputHooks/ScanThread.cpp new file mode 100644 index 0000000..63602f6 --- /dev/null +++ b/src/ProtoInput/ProtoInputHooks/ScanThread.cpp @@ -0,0 +1,1282 @@ +#include +//#include "pch.h" +#include +#define NOMINMAX +#include +//#include +#include +#include +#include +#include +#include +#include // for swprintf +#include +#include +#include // For strtoul +#include +#include +#include +//#include "input.h" +//#include "MainThread.h" +//#include "Mouse.h" +#include "FakeMouseKeyboard.h" +#include "ScanThread.h" +#include "TranslateXtoMKB.h" +#include "FakeCursor.h" +#include "HwndSelector.h" + +#pragma comment(lib, "dwmapi.lib") + + + + +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) + { + FLOAT ny; + 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..0d02558 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 "Scaler.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/TranslateXtoMKB.cpp b/src/ProtoInput/ProtoInputHooks/TranslateXtoMKB.cpp new file mode 100644 index 0000000..f5c49c9 --- /dev/null +++ b/src/ProtoInput/ProtoInputHooks/TranslateXtoMKB.cpp @@ -0,0 +1,984 @@ +//#include "XinputHook.h" +//#include +#include +#include "Gui.h" +#include +#include +//#include "OpenXinputWrapper.h" +#include "TranslateXtoMKB.h" +#include "RawInput.h" +#include +#include +#define NOMINMAX +#include +#include +#include "EasyHook.h" +#include +#include +#include +#include +#include // for swprintf +#include +#include // For strtoul +#include +#include +#include +#include "HwndSelector.h" +#include "FakeCursor.h" +#include "Gui.h" +#include "GtoMnK_RawInput.h" +#include "FakeMouseKeyboard.h" +#include "ScanThread.h" +#include "StateInfo.h" +//#include +#pragma comment(lib, "dwmapi.lib") +#include + + +//#include "dllmain.h" +//#include "PostKeyFunction.cpp" + +#pragma comment(lib, "Xinput.lib") + +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 updatewindowtick = 300; + + int AxisLeftsens = -9000; + int AxisRightsens = 9000; + int AxisUpsens = 9000; + int AxisDownsens = -9000; + int scrollspeed3; + float radial_deadzone = 0.10f; // Circular/Radial Deadzone (0.0 to 0.3) + 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) + //float sensitivity = 9.00f; // Base sensitivity / max speed (1.0 to 30.0) + //float accel_multiplier = 1.90f; // Look Acceleration Multiplier (1.0 to 3.0) + int startbuttontimer, backbuttontimer; + ///////////////// + + bool leftPressedold = false; + bool rightPressedold = false; + HMODULE g_hModule = nullptr; + + bool loop = true; + //CRITICAL_SECTION critical; //window thread + //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 rawmouseWu = false; + bool rawmouseWd = 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 }; + POINT heer; + 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; + // MessageBoxA(NULL, path.c_str(), "1", MB_OK); + 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; + } + // #define DEADZONE 8000 + // #define MAX_SPEED 30.0f // Maximum pixels per poll + // #define ACCELERATION 2.0f // Controls non-linear ramp (higher = more acceleration) + + + 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 }; + } + + + std::wstring ToWString(const std::string& s) + { + return std::wstring(s.begin(), s.end()); + } + 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; + + 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 < AxisLeftsens) //left + { + } + else { + oldscrollleft = false; + ButtonStateImpulse(TranslateXtoMKB::stickrightmapping, false, 99);//down + } + } + else if (scrollXaxis < AxisLeftsens) //left + { + oldscrollleft = true; + + ButtonStateImpulse(TranslateXtoMKB::stickrightmapping, true, 99);//down + } + + if (oldscrollright) + { + if (scrollXaxis > AxisRightsens) //left + { + } + else { + oldscrollright = false; + ButtonStateImpulse(TranslateXtoMKB::stickleftmapping, false, 99);//down + } + } + else if (scrollXaxis > AxisRightsens) //left + { + oldscrollright = true; + ButtonStateImpulse(TranslateXtoMKB::stickleftmapping, true, 99);//down + } + + if (oldscrollup) + { + if (scrollYaxis > AxisUpsens) //left + { + } + else { + oldscrollup = false; + ButtonStateImpulse(TranslateXtoMKB::stickupmapping, false, 99);//down + } + } + else if (scrollYaxis > AxisUpsens) //left + { + oldscrollup = true; + ButtonStateImpulse(TranslateXtoMKB::stickupmapping, true, 99);//down + } + + if (oldscrolldown) + { + if (scrollYaxis < AxisDownsens) //left + { + } + else { + oldscrolldown = false; + ButtonStateImpulse(TranslateXtoMKB::stickdownmapping, false, 99);//down + } + } + else if (scrollYaxis < AxisDownsens) //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) + { + RawInput::Initialize(); + 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..ce3d16c --- /dev/null +++ b/src/ProtoInput/ProtoInputHooks/TranslateXtoMKB.h @@ -0,0 +1,48 @@ +#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 bool SaveBmps; + }; + +} \ No newline at end of file diff --git a/src/ProtoInput/ProtoInputHooks/XinputHook.cpp b/src/ProtoInput/ProtoInputHooks/XinputHook.cpp index 5764340..1181d75 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,268 @@ 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; +POINT olddeltaL; +POINT olddeltaR; +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; +SHORT negativedeadzone = -14000; +SHORT oldcurrentX, oldcurrentY; +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 < 12000) + currentvalue = 12000; + + //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 > -12000) + currentvalue = -12000; + + //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); + + if (currentvalue < 0 - (7 * ScreenshotInput::TranslateXtoMKB::Sens)) + currentvalue = currentvalue + (7 * ScreenshotInput::TranslateXtoMKB::Sens); + } + if (diditchange != currentvalue) + changed = true; + return currentvalue; +} + +inline DWORD WINAPI XInputfromkbm(DWORD dwUserIndex, XINPUT_STATE* pState, bool extended) +{ + 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; + if (ScreenshotInput::TranslateXtoMKB::upmapping == VK_UP || ScreenshotInput::TranslateXtoMKB::upmapping == VK_DOWN) + ScreenshotInput::TranslateXtoMKB::upmapping = VK_NUMPAD8; + if (ScreenshotInput::TranslateXtoMKB::downmapping == VK_UP || ScreenshotInput::TranslateXtoMKB::downmapping == VK_DOWN) + ScreenshotInput::TranslateXtoMKB::downmapping = VK_NUMPAD5; + if (ScreenshotInput::TranslateXtoMKB::leftmapping == VK_LEFT || ScreenshotInput::TranslateXtoMKB::leftmapping == VK_RIGHT) + ScreenshotInput::TranslateXtoMKB::leftmapping = VK_NUMPAD4; + if (ScreenshotInput::TranslateXtoMKB::rightmapping == VK_LEFT || ScreenshotInput::TranslateXtoMKB::rightmapping == VK_RIGHT) + ScreenshotInput::TranslateXtoMKB::rightmapping = VK_NUMPAD6; + 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; + + if (IsKeyPressed(VK_RBUTTON)) { + pState->Gamepad.bLeftTrigger = 255; + //changed = true; + } + else { + pState->Gamepad.bLeftTrigger = 0; + //changed = true; + } + + if (IsKeyPressed(VK_LBUTTON)) { + pState->Gamepad.bRightTrigger = 255; + } + else { + pState->Gamepad.bRightTrigger = 0; + } + + + + + //normal 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; + + + 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++; + } + + 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 +388,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 +464,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 +619,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 +691,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 +725,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..344148b 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 "Scaler.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) { + AllocConsole(); FILE* f = new FILE(); freopen_s(&f, "CONOUT$", "w", stdout); @@ -42,34 +35,28 @@ 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::FakeCursor::Initialise(Proto::hmodule); + Proto::AddThreadToACL(GetCurrentThreadId()); - - HANDLE hGuiThread = CreateThread(nullptr, 0, - (LPTHREAD_START_ROUTINE)GuiThread, dll_hModule, CREATE_SUSPENDED, &Proto::GuiThreadID); - - Proto::RawInput::InitialiseRawInput(); - - Proto::StartPipeCommunication(); - ResumeThread(hGuiThread); + Proto::StartPipeCommunication(); + + Proto::HwndSelector::UpdateMainHwnd(); + + InitializeCriticalSection(&ScreenshotInput::ScanThread::critical);//must be placed before InitialiseRawInput + Proto::RawInput::InitialiseRawInput(); + // Useful to add a pause if we need to attach a debugger + + InitializeCriticalSection(&ScreenshotInput::ScanThread::critical); - if (hGuiThread != nullptr) - CloseHandle(hGuiThread); - std::cout << "Reached end of startup thread\n"; - return 0; } - + // EasyHook entry point extern "C" __declspec(dllexport) void __stdcall NativeInjectionEntryPoint(REMOTE_ENTRY_INFO * inRemoteInfo) { @@ -94,7 +81,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..e05e8e6 100644 --- a/src/ProtoInput/ProtoInputHooks/pipeinclude/pipeinclude.h +++ b/src/ProtoInput/ProtoInputHooks/pipeinclude/pipeinclude.h @@ -7,6 +7,8 @@ namespace ProtoPipe enum class PipeMessageType { + AddSelectedMouseOrKeyboard, + SetTranslateXinputtoMKB, SetupHook, WakeUpProcess, SetupMessageFilter, @@ -18,12 +20,12 @@ enum class PipeMessageType SetDrawFakeCursor, SetDrawFakeCursorFix, SetExternalFreezeFakeInput, - AddSelectedMouseOrKeyboard, AddHandleToRename, SetControllerIndex, SetUseDinput, StopFocusMessageLoop, SetUseOpenXinput, + TranslateMKBtoXinput, SetDinputDeviceGuid, SetDinputHookGetDeviceState, SetSetWindowPosSettings, @@ -42,7 +44,10 @@ enum class PipeMessageType SetMoveWindowDontResize, SetMoveWindowDontReposition, SetAdjustWindowRectSettings, - SetDontWaitWindowBorder + SetDontWaitWindowBorder, + SetManualScaling, + SetXinputtoMKBkeys, + SetXinputtoMKBCFG }; struct PipeMessageHeader @@ -50,6 +55,17 @@ struct PipeMessageHeader PipeMessageType messageType; unsigned int messageSize; }; +struct PipeMessageAddSelectedMouseOrKeyboard +{ + unsigned int mouse = -1; + unsigned int keyboard = -1; +}; + +struct PipeMessageSetTranslateXinputtoMKB +{ + bool TranslateXinputtoMKB; +}; + struct PipeMessageSetupHook { @@ -73,6 +89,10 @@ struct PipeMessageWakeUpProcess { }; +//struct PipeMessageSetNoGUI +//{ +// bool SetNoGUI; +//}; struct PipeMesasgeUpdateMainWindowHandle { uint64_t hwnd = 0; @@ -115,11 +135,7 @@ struct PipeMessageSetExternalFreezeFakeInput bool freezeEnabled; }; -struct PipeMesasgeAddSelectedMouseOrKeyboard -{ - unsigned int mouse = -1; - unsigned int keyboard = -1; -}; + struct PipeMessageAddHandleToRename { @@ -150,6 +166,11 @@ struct PipeMessageSetUseOpenXinput bool useOpenXinput; }; +struct PipeMessageSetTranslateMKBtoXinput +{ + bool TranslateMKBtoXinput; +}; + struct PipeMessageSetDinputDeviceGuid { GUID guid; @@ -256,4 +277,53 @@ 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; +}; +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..7c11fce 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,43 @@ StartupInjectionType selectedStartupInjectionType = StartupInjectionType::EASYHO std::vector trackedInstanceHandles{}; static bool isInputCurrentlyLocked = false; + +//TranslateXtoMKB +float Sensitivitymultiplier = 3.5f; +float Sensitivity = 15.0f; +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,6 +170,14 @@ bool Launch() return false; }; + if (instance.mouseHandle != -1) + AddSelectedMouseHandle(instanceHandle, instance.mouseHandle); + + if (instance.keyboardHandle != -1) + AddSelectedKeyboardHandle(instanceHandle, instance.keyboardHandle); + SetTranslateXinputtoMKB(instanceHandle, currentProfile.TranslateXinputtoMKB); + + if (hookEnabled(RegisterRawInputHookID)) InstallHook(instanceHandle, RegisterRawInputHookID); if (hookEnabled(GetRawInputDataHookID)) InstallHook(instanceHandle, GetRawInputDataHookID); if (hookEnabled(MessageFilterHookID)) InstallHook(instanceHandle, MessageFilterHookID); @@ -157,10 +201,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 +254,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); 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); + 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,9 +719,545 @@ void SelectedInstanceWindow() ImGui::PushID(128794); ImGui::Spacing(); + ImGui::Separator(); ImGui::TextWrapped("Controller index"); ImGui::SliderInt("", (int*)&instance.controllerIndex, 0, 16, "%d", ImGuiSliderFlags_AlwaysClamp); + ImGui::Spacing(); + ImGui::Separator(); + ImGui::Spacing(); + ImGui::TextWrapped("If Translate X to MKB is selected, then it will emulate mouse and keyboard from selected ControllerIndex." + "Option will automatically deactivate if a keyboard or mouse is selected for the instance. " + "Also you should make sure ControllerIndex is not zero, as zero still implies no controller" + "UseOpenXinput hook or Xinput hook are not needed, as it will use OpenXinput already and poll selected controllerindex" + ""); + ImGui::Checkbox("Translate X to MKB", ¤tProfile.TranslateXinputtoMKB); // + 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(); + 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::TextWrapped("Mappings:" + ""); + // 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; + } + } + 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("XtoMKB Sensitivity", (int*)¤tProfile.XinputtoMKBsens, 1, 40, "%d", ImGuiSliderFlags_AlwaysClamp); + ImGui::Separator(); + ImGui::SliderInt("XtoMKB Sensitivity multiplier", (int*)¤tProfile.XinputtoMKBsensmult, 1, 20, "%d", ImGuiSliderFlags_AlwaysClamp); + ImGui::PopID(); + 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; } void OptionsMenu() @@ -864,11 +1448,12 @@ void OptionsMenu() ImGui::Checkbox(hook.uiLabel.c_str(), &hook.enabled); } } + ImGui::Checkbox("Use OpenXinput", ¤tProfile.useOpenXinput); + + ImGui::Checkbox("Translate MKB to fake Xinput", ¤tProfile.TranslateMKBtoXinput); ImGui::Checkbox("Dinput to Xinput redirection", ¤tProfile.dinputToXinputRedirection); - ImGui::Checkbox("Use OpenXinput", ¤tProfile.useOpenXinput); - ImGui::Checkbox("Use fake clip cursor", ¤tProfile.useFakeClipCursor); ImGui::Checkbox("Show fake cursor when image updated", ¤tProfile.showCursorWhenImageUpdated); diff --git a/src/ProtoInput/ProtoInputHost/Profiles.h b/src/ProtoInput/ProtoInputHost/Profiles.h index 3fe6cd5..4a42c71 100644 --- a/src/ProtoInput/ProtoInputHost/Profiles.h +++ b/src/ProtoInput/ProtoInputHost/Profiles.h @@ -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 @@ -72,12 +73,51 @@ struct Profile bool dinputToXinputRedirection = false; bool useOpenXinput = 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; + bool useFakeClipCursor = true; bool showCursorWhenImageUpdated = false; - bool putMouseInsideWindow = false; + bool putMouseInsideWindow = true; bool drawFakeMouseCursor = true; bool drawFakeCursorFix = false; @@ -114,6 +154,49 @@ struct Profile 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("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/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/ProtoInputLoader/Inject.cpp b/src/ProtoInput/ProtoInputLoader/Inject.cpp index 58bcf33..35e9bf9 100644 --- a/src/ProtoInput/ProtoInputLoader/Inject.cpp +++ b/src/ProtoInput/ProtoInputLoader/Inject.cpp @@ -46,6 +46,50 @@ 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); + } +} + + 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 +182,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 +239,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) @@ -678,4 +712,88 @@ 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) +{ + 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 + }; + + 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/include/protoloader.h b/src/ProtoInput/ProtoInputLoader/include/protoloader.h index 853489a..007fdb6 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 InstallHook(ProtoInstanceHandle instanceHandle, ProtoHookIDs hookID); extern "C" __declspec(dllexport) void UninstallHook(ProtoInstanceHandle instanceHandle, ProtoHookIDs hookID); @@ -84,8 +90,6 @@ 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); @@ -94,6 +98,8 @@ extern "C" __declspec(dllexport) void SetUseDinputRedirection(ProtoInstanceHandl 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); @@ -147,4 +153,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); + +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/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