1. #1
    FWP's Avatar
    Registered
    07/06/10
    Location
    Zonhoven
    Posts
    80
    iTrader
    2 (100%)
    Mentioned
    0 Post(s)

    Unhappy Low level keyboard hook werkt overal in systeem buiten waar ik het wil... (opgelost)

    Ik ben al even aan een toevoeging van Worms: Reloaded bezig. Dit spel schakelt het gebruik van het start menu uit als deze focus heeft (zeer irritant, als je snel focus van het spel wilt afnemen).

    Nu heb ik een low level keyboard hook geprogrammeerd in de dll die ik met een loader in het spel laad. Deze werkt overal, zelfs op de desktop, maar niet in het spel. Ik heb dit getest door er een message box er aan toe te voegen. Ik vermoed dat ik ergens met access rights moet gaan prutsen, maar weet echter niet waar ik moet beginnen.

    Heb specifieke delen in het groen gezet (waarvan ik denk dat deze van belang kunnen zijn). Hier zijn de project bestanden: WormsAppSrc090810.zip (11.4 KB)

    Loader
    Code:
    //////////////////////////////////////////////////////////////////////////////////
    //////////////////////////////////////////////////////////////////////////////////
    /////// Name:			Worms: Reloaded Windowed Loader b12395
    /////// Description:	Allows you to run the game in windowed mode flawlessly
    /////// Author:			*snip*
    /////// Email:			*snip*
    /////// URL:			http://forums.steampowered.com/forums/showthread.php?p=16796532
    /////// License:		GPLv3 (or later)
    ///////
    /////// This program is free software: you can redistribute it and/or modify
    /////// it under the terms of the GNU General Public License as published by
    /////// the Free Software Foundation, either version 3 of the License, or
    /////// (at your option) any later version.
    ///////
    /////// This program is distributed in the hope that it will be useful,
    /////// but WITHOUT ANY WARRANTY; without even the implied warranty of
    /////// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    /////// GNU General Public License for more details.
    ///////
    /////// You should have received a copy of the GNU General Public License
    /////// along with this program.  If not, see <http://www.gnu.org/licenses/>.
    ///////
    //////// Contributors (see changelog in readme.txt for exact details):
    //////// Name:		CyberShadow
    //////// Email:		vladimir@thecybershadow.net
    //////// Website:	http://thecybershadow.net/
    //////// Profile:	http://forums.steampowered.com/forums/member.php?u=595488
    //////////////////////////////////////////////////////////////////////////////////
    //////////////////////////////////////////////////////////////////////////////////
    
    // Dependencies
    #pragma comment(lib,"advapi32")
    #pragma comment(lib,"shell32")
    #pragma comment(lib,"user32")
    
    // Library inclusion
    #include <direct.h>
    #include <tchar.h>
    #include <windows.h>
    #include <tlhelp32.h>
    
    // General project properties
    const wchar_t gameName[] = _T("Worms: Reloaded");
    const wchar_t gameExecutable[MAX_PATH] = _T("steam://rungameid/22600");		// The initial executable can sometimes differ from the actual game process
    const wchar_t gameProcess[MAX_PATH] = _T("WormsReloaded.exe");
    const char dllFileName[MAX_PATH] = "WormsReloadedWindowedDll.dll";
    const unsigned int injectTimeout = 10000;									// Amount of time in miliseconds before the loader will stop looking for the process to inject
    
    // Retrieve process handle by its name
    HANDLE GetProcessHandle(LPCTSTR szExeName);
    
    // The function that injects the dynamic link library
    bool DllInject(HANDLE hProcess, LPSTR lpszDllPath);
    
    // Main entry point of the loader
    int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
    {
    	// Open the game
    	ShellExecute(0, _T("open"), gameExecutable, 0, 0, SW_SHOWNORMAL);
    
    	// Look for the game process
    	HANDLE hProcess;
    	do
    	{
    		hProcess = GetProcessHandle(gameProcess);
    		Sleep(1);
    	}while(hProcess == 0);
    
    	// Obtain the full path of the dynamic link library to pass on
    	char location[MAX_PATH] = "";
    	_getcwd(location, MAX_PATH);
    	strcat_s(location, "\\");
    	strcat_s(location, dllFileName);
    
    	// Error message
    	wchar_t errorMessage[300] = _T("");
    	_tcscat_s(errorMessage, _T("Failed to inject the dynamic link library into "));
    	_tcscat_s(errorMessage, gameName);
    	_tcscat_s(errorMessage, _T(". Do you wish to start the game normally?"));
    
    	if(!DllInject(hProcess, location))
    	{
    		// Injection failure, stop the game and ask the user whether to run the game normally
    		TerminateProcess(hProcess, 0);
    		if(IDYES == MessageBox(0, errorMessage, _T("Loader Injection Failure"), MB_YESNO |  MB_ICONERROR))
    		{
    			ShellExecute(0, _T("open"), gameExecutable, 0, 0, SW_SHOWNORMAL);
    		}
    	}
    
    	return 0;
    }
    
    // Injection process
    bool DllInject(HANDLE hProcess, LPSTR lpszDllPath)
    {
    	HMODULE hmKernel = GetModuleHandle(_T("kernel32"));
    	if(hmKernel == 0 || hProcess == 0)
    	{
    		// Unable to proceed with injection due to lack of necessary information
    		return false;
    	}
    	int nPathLength = strlen(lpszDllPath) + 1;
    	LPVOID lpvMemory = VirtualAllocEx(hProcess, 0, nPathLength, MEM_COMMIT, PAGE_READWRITE);
    	WriteProcessMemory(hProcess, lpvMemory, lpszDllPath, nPathLength, 0);
    	DWORD dwWaitResult, dwExitResult = 0;
    	HANDLE hThread = CreateRemoteThread(hProcess, 0, 0, (LPTHREAD_START_ROUTINE)GetProcAddress(hmKernel, "LoadLibraryA"), lpvMemory, 0, 0);
    	if(hThread != 0)
    	{
    		dwWaitResult = WaitForSingleObject(hThread, injectTimeout);
    		GetExitCodeThread(hThread, &dwExitResult);
    		CloseHandle(hThread);
    	}
    	VirtualFreeEx(hProcess, lpvMemory, 0, MEM_RELEASE);
    	return ((dwWaitResult != WAIT_TIMEOUT) && (dwExitResult > 0));
    }
    
    // Retrieving the process handle
    HANDLE GetProcessHandle(LPCTSTR szExeName)
    {
    	PROCESSENTRY32 pEntry = { sizeof(PROCESSENTRY32) };
    	HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPALL, 0);
    	HANDLE hProcess = 0;
    	if(Process32First(hSnapshot, &pEntry))
    	{
    		do
    		{
    			if(!lstrcmp(pEntry.szExeFile, szExeName))
    			{
    				HANDLE hToken;
    				if(OpenProcessToken(GetCurrentProcess(), TOKEN_ALL_ACCESS, &hToken))
    				{
    					LUID luidProcess;
    					if(LookupPrivilegeValue(0, SE_DEBUG_NAME, &luidProcess))
    					{
    						TOKEN_PRIVILEGES tpProcess;
    						tpProcess.PrivilegeCount = 1;
    						tpProcess.Privileges[0].Luid = luidProcess;
    						tpProcess.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
    						if(AdjustTokenPrivileges(hToken, FALSE, &tpProcess, sizeof(TOKEN_PRIVILEGES), 0, 0))
    						{
    							hProcess = OpenProcess(PROCESS_ALL_ACCESS, true, pEntry.th32ProcessID);
    						}
    					}
    				}
    				if(hProcess == 0)
    				{
    					DWORD dwError = GetLastError();
    					dwError = 0;
    				}
    			}
    		}while(Process32Next(hSnapshot, &pEntry));
    	}
    	return hProcess;
    }
    Dll
    Code:
    //////////////////////////////////////////////////////////////////////////////////
    //////////////////////////////////////////////////////////////////////////////////
    /////// Name:			Worms: Reloaded Windowed Dll b12395
    /////// Description:	Allows you to run the game in windowed mode flawlessly
    /////// Author:			*snip*
    /////// Email:			*snip*
    /////// URL:			http://forums.steampowered.com/forums/showthread.php?p=16796532
    /////// License:		GPLv3 (or later)
    ///////
    /////// This program is free software: you can redistribute it and/or modify
    /////// it under the terms of the GNU General Public License as published by
    /////// the Free Software Foundation, either version 3 of the License, or
    /////// (at your option) any later version.
    ///////
    /////// This program is distributed in the hope that it will be useful,
    /////// but WITHOUT ANY WARRANTY; without even the implied warranty of
    /////// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    /////// GNU General Public License for more details.
    ///////
    /////// You should have received a copy of the GNU General Public License
    /////// along with this program.  If not, see <http://www.gnu.org/licenses/>.
    ///////
    //////// Contributors (see changelog in readme.txt for exact details):
    //////// Name:		CyberShadow
    //////// Email:		vladimir@thecybershadow.net
    //////// Website:	http://thecybershadow.net/
    //////// Profile:	http://forums.steampowered.com/forums/member.php?u=595488
    //////////////////////////////////////////////////////////////////////////////////
    //////////////////////////////////////////////////////////////////////////////////
    
    // Dependencies
    #pragma comment(lib,"dwmapi")
    #pragma comment(lib,"shell32")
    #pragma comment(lib,"user32")
    
    // Library inclusion
    #include <dwmapi.h>
    #include <tchar.h>
    #include <windows.h>
    
    // Definition of function that will hook the code
    DWORD HookIt(const wchar_t *dllFile, const char *hookedAPI, void *redirectAPI, wchar_t *originalCodeBackup);
    
    // Definintion of function that will check for keyboard input
    DWORD WINAPI KeyboardCheckThread(LPVOID args);
    LRESULT CALLBACK LowLevelKeyboardProc( int nCode, WPARAM wParam, LPARAM lParam ); 
    
    // Definitions of functions that will be hooked
    HWND WINAPI hkCreateWindowEx(DWORD dwExStyle, LPCWSTR lpClassName, LPCWSTR lpWindowName, DWORD dwStyle, int x, int y, int nWidth, int nHeight, HWND hWndParent, HMENU hMenu, HINSTANCE hInstance, LPVOID lpParam);
    long WINAPI hkChangeDisplaySettings(DEVMODE *lpDevMode, DWORD dwflags);
    bool WINAPI hkCloseWindow(HWND hWnd);
    
    // General project properties
    const wchar_t targetFileName[MAX_PATH] = _T("WormsReloaded.exe");	// File name of target
    
    // Addresses of the hook functions
    DWORD dwCreateWindowExAddress = 0;
    DWORD dwChangeDisplaySettingsAddress = 0;
    DWORD dwCloseWindowAddress = 0;
    
    // Original function addresses for restoration purposes
    byte backupCreateWindowEx[6];
    byte backupChangeDisplaySettings[6];
    byte backupCloseWindow[6];
    
    // Size properties of the game itself
    int gameScreenWidth = 0;
    int gameScreenHeight = 0;
    
    // Takes care of hooking and unhooking the functions
    bool WINAPI DllMain(HINSTANCE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
    {
    	DWORD dwKeyboardCheckThread;
    	HANDLE hKeyboardCheck = CreateThread(0, 0, KeyboardCheckThread, 0, 0, &dwKeyboardCheckThread);
    	switch(ul_reason_for_call)
    	{
    	case DLL_PROCESS_ATTACH:
    		DisableThreadLibraryCalls(hModule);
    		dwCreateWindowExAddress = HookIt(_T("user32.dll"), "CreateWindowExW", hkCreateWindowEx, (_TUCHAR*)backupCreateWindowEx);
    		dwChangeDisplaySettingsAddress = HookIt(_T("user32.dll"), "ChangeDisplaySettingsW", hkChangeDisplaySettings, (_TUCHAR*)backupChangeDisplaySettings);
    		dwCloseWindowAddress = HookIt(_T("user32.dll"), "CloseWindow", hkCloseWindow, (_TUCHAR*)backupCloseWindow);
    		break;
    	case DLL_PROCESS_DETACH:
    		if(dwCreateWindowExAddress)
    			WriteProcessMemory((HANDLE) -1, (void*)dwCreateWindowExAddress, backupCreateWindowEx, 6, 0);
    		if(dwChangeDisplaySettingsAddress)
    			WriteProcessMemory((HANDLE) -1, (void*)dwChangeDisplaySettingsAddress, backupChangeDisplaySettings, 6, 0);
    		if(dwCloseWindowAddress)
    			WriteProcessMemory((HANDLE) -1, (void*)dwCloseWindowAddress, backupCloseWindow, 6, 0);
    		break;
    	}
    	return true;
    }
    
    // Hook the process and its modules by writing to the kernel memory area
    DWORD HookIt(const wchar_t *dllFile, const char *hookedAPI, void *redirectAPI, wchar_t *originalCodeBackup)
    {
    	DWORD dwAddress = (DWORD)GetProcAddress(GetModuleHandle(dllFile), hookedAPI);		// Obtain the address of the API
    	BYTE jump[6] = {0xE9, 0x00, 0x00, 0x00, 0x00, 0xC3};								// 0xE9 = jump, 0x00, 0x00, 0x00, 0x00 = address, 0xC3 = return
    	ReadProcessMemory((HANDLE)-1, (void*)dwAddress, originalCodeBackup, 6, 0);			// Obtain first six bytes of the API
    	DWORD dwJumpCalculation = ((DWORD)redirectAPI - dwAddress - 5);						// Calculate the jump
    	memcpy(&jump[1], &dwJumpCalculation, 4);											// Build the jump
    	WriteProcessMemory((HANDLE) -1, (void*)dwAddress, jump, 6, 0);						// Overwrite first six bytes of the API with a jump to the hook function
    	return dwAddress;																	// Return the API address so restoring to the original address is possible
    }
    
    DWORD WINAPI KeyboardCheckThread(LPVOID args)
    {
    	// Obtain application instance
    	HINSTANCE applicationInstance = GetModuleHandle(0);
    	// Global Windows hook to capture keyboard strokes
    	SetWindowsHookEx(WH_KEYBOARD_LL, LowLevelKeyboardProc, applicationInstance, 0);
    	MSG message;
    	while(GetMessage(&message, 0, 0, 0) > 0)
    	{
    		TranslateMessage(&message);
    		DispatchMessage(&message);
    	}
    	return 0;
    }
    
    LRESULT CALLBACK LowLevelKeyboardProc(int nCode, WPARAM wParam, LPARAM lParam )
    {
    	MessageBox(0, _T("Test"), _T("Test"), 0);
    	// Declare our pointer to the KBDLLHOOKSTRUCT
    	KBDLLHOOKSTRUCT *pKeyBoard = (KBDLLHOOKSTRUCT *)lParam;
    	switch( wParam )
    	{
    	case WM_KEYDOWN:
    		// When the key has been pressed and released
    		{
    			switch( pKeyBoard->vkCode )
    				// Check to see what key has been pushed
    			{
    			case VK_LWIN:
    				MessageBox(0, _T("test"), _T("test"), 0);
    				keybd_event(VK_LWIN, 0xb8, 0, 0);
    				keybd_event(VK_LWIN, 0x8f, KEYEVENTF_KEYUP, 0);
    				break;
    			case VK_RWIN:
    				keybd_event(VK_RWIN, 0xb8, 0, 0);
    				keybd_event(VK_RWIN, 0x8f, KEYEVENTF_KEYUP, 0);
    				break;
    			}
    		}
    	default:
    		return CallNextHookEx( NULL, nCode, wParam, lParam );
    	}
    	return 0;
    }
    
    // Window property definitions and creation of the window
    HWND WINAPI hkCreateWindowEx(DWORD dwExStyle, LPCWSTR lpClassName, LPCWSTR lpWindowName, DWORD dwStyle, int x, int y, int nWidth, int nHeight, HWND hWndParent, HMENU hMenu, HINSTANCE hInstance, LPVOID lpParam)
    {
    	// Set game resolution height and width so the window size can be adjusted to it
    	nWidth = gameScreenWidth;
    	nHeight = gameScreenHeight;
    
    	// If the game resolution equals the desktop resolution it will create a borderless window
    	if(!(nWidth == GetSystemMetrics(SM_CXSCREEN) && nHeight == GetSystemMetrics(SM_CYSCREEN)))
    	{
    		// Window style properties
    		dwStyle = WS_OVERLAPPEDWINDOW & ~(WS_THICKFRAME | WS_MAXIMIZEBOX) | WS_CLIPSIBLINGS | WS_CLIPCHILDREN;
    
    		// Ensure the game is fully displayed and nothing gets cut off
    		RECT windowSizeProperties;
    		windowSizeProperties.right = nWidth;
    		windowSizeProperties.bottom = nHeight;
    		AdjustWindowRect(&windowSizeProperties, WS_OVERLAPPEDWINDOW, FALSE);
    		// Included minor adjustment size values for perfect fitting
    		nWidth = windowSizeProperties.right - 2;
    		nHeight = windowSizeProperties.bottom + 20;
    
    		// Center the window when the game starts
    		x = (GetSystemMetrics(SM_CXSCREEN) / 2) - (nWidth / 2);
    		y = (GetSystemMetrics(SM_CYSCREEN) / 2) - (nHeight / 2);
    	}
    	dwExStyle = WS_EX_APPWINDOW | WS_EX_WINDOWEDGE;
    
    	// Unhook the API, create the new window and setup the hook again
    	WriteProcessMemory((HANDLE) -1, (void*)dwCreateWindowExAddress, backupCreateWindowEx, 6, 0);
    	HWND hWindow = CreateWindowExW(WS_EX_APPWINDOW | dwExStyle, lpClassName, lpWindowName, dwStyle, x, y, nWidth, nHeight, hWndParent, hMenu, hInstance, lpParam);
    	dwCreateWindowExAddress = HookIt(L"user32.dll", "CreateWindowExW", hkCreateWindowEx, (_TUCHAR*)backupCreateWindowEx);
    
    	// Set the window icon
    	SendMessage(hWindow, WM_SETICON, ICON_BIG, (LPARAM)ExtractIcon(0, targetFileName, 0));
    
    	// Confine the cursor to the game as long as it has focus
    	RECT cursorArea;
    	GetWindowRect(GetForegroundWindow(), &cursorArea);
    	// Make the title bar inaccessible so it can't be accidently moved, minimized or closed while in-game
    	cursorArea.top += 25;
    	ClipCursor(&cursorArea);
    
    	// Make sure desktop composition does not get disabled
    	DwmEnableComposition(DWM_EC_ENABLECOMPOSITION);
    
    	return hWindow;
    }
    
    // Obtain the game resolution height and width
    long WINAPI hkChangeDisplaySettings(DEVMODE *lpDevMode, DWORD dwflags)
    {
    	DEVMODEW dmGameScreenSettings = *lpDevMode;
    	gameScreenWidth = dmGameScreenSettings.dmPelsWidth;
    	gameScreenHeight = dmGameScreenSettings.dmPelsHeight;
    	return 0;
    }
    
    // Ensures the window does not minimize when it loses focus
    bool WINAPI hkCloseWindow(HWND hWnd)
    {
    	return 0;
    }
    Last edited by FWP; 11-09-2010 at 23:32.
    no votes  

  2. #2
    Litheon's Avatar
    Registered
    10/08/02
    Location
    Zandhoven
    Posts
    57
    iTrader
    0
    Mentioned
    0 Post(s)
    Reputation
    0/1
    Hey,

    Heb je code niet bestudeerd, maar sommige spellen gebruiken DirectInput voor keyboard input te vekrijgen, dus dit kan een reden zijn.
    no votes  

  3. #3
    FWP's Avatar
    Registered
    07/06/10
    Location
    Zonhoven
    Posts
    80
    iTrader
    2 (100%)
    Mentioned
    0 Post(s)
    Quote Originally Posted by Litheon View Post
    This quote is hidden because you are ignoring this member. Show
    Hey,

    Heb je code niet bestudeerd, maar sommige spellen gebruiken DirectInput voor keyboard input te vekrijgen, dus dit kan een reden zijn.
    Bedankt voor de tip, zal daaruit verder zoeken.
    no votes  

  4. #4
    FWP's Avatar
    Registered
    07/06/10
    Location
    Zonhoven
    Posts
    80
    iTrader
    2 (100%)
    Mentioned
    0 Post(s)
    Heb het opgelost, hieronder de code. Broncode kan hier verkregen worden.

    Code:
        // Keyboard hook thread
        HANDLE hKeybooardHook;
        DWORD dwKeybooardHook;
        hKeybooardHook = CreateThread(0, 0, (LPTHREAD_START_ROUTINE)MyDirectInput, 0, 0, &dwKeybooardHook);
    Code:
    // Keyboard hook functions to restore start menu opening through keyboard functionality
    void InitializeDirectInput(HINSTANCE hInstance, HWND hWnd)
    {
        DirectInput8Create(hInstance, DIRECTINPUT_VERSION, IID_IDirectInput8, (void**)&directInput, 0);
        directInput->CreateDevice(GUID_SysKeyboard, &directInputDevice, 0);
        directInputDevice->SetDataFormat(&c_dfDIKeyboard);
        directInputDevice->SetCooperativeLevel(hWnd, DISCL_NONEXCLUSIVE | DISCL_BACKGROUND);
    }
    
    void DetectKeys(void)
    {
        static BYTE keystate[256];
        directInputDevice->Acquire();
        directInputDevice->GetDeviceState(256, (LPVOID)keystate);
        if(keystate[DIK_LWIN] & 0x80)
        {
            SetForegroundWindow(GetDesktopWindow());
        }
        if(keystate[DIK_RWIN] & 0x80)
        {
            SetForegroundWindow(GetDesktopWindow());
        }
        if(keystate[DIK_LCONTROL] && keystate[DIK_ESCAPE] & 0x80)
        {
            SetForegroundWindow(GetDesktopWindow());
            Sleep(50);
            keybd_event(VK_RWIN, 0, 0, 0);
            keybd_event(VK_RWIN, 0, KEYEVENTF_KEYUP, 0);
        }
    }
    
    void CloseDirectInput(void)
    {
        directInputDevice->Unacquire();
        directInput->Release();
    }
    
    void MessageLoop()
    {
        MSG message;
        while(true)
        {
            DWORD dwStartPoint = GetTickCount();
            if (PeekMessage(&message, 0, 0, 0, PM_REMOVE))
            {
                if (message.message == WM_QUIT)
                    break;
                TranslateMessage(&message);
                DispatchMessage(&message);
            }
            DetectKeys();
            while ((GetTickCount() - dwStartPoint) < 25);
        }
        CloseDirectInput();
    }
    
    DWORD WINAPI MyDirectInput(LPVOID lpParm)
    {
        HINSTANCE hInstance = GetModuleHandle(0);
        InitializeDirectInput(hInstance, 0);
        MessageLoop();
        return 0;
    }
    no votes  

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  

Log in

Log in