I want to detect keypress in C++ and i need to use Windows System Call. So, i did some research and this is what i got using Hooks and Message:
#include <Windows.h>
#include <iostream>
#include <sstream>
#include <fstream>
#include <ctime>
using namespace std;
LRESULT CALLBACK LowLevelKeyboardProc(int code, WPARAM wParam, LPARAM lParam) {
if (code == HC_ACTION) {
switch (wParam) {
case WM_KEYDOWN:
PKBDLLHOOKSTRUCT p = (PKBDLLHOOKSTRUCT)lParam;
char c = char(MapVirtualKey(p->vkCode, MAPVK_VK_TO_CHAR));
cout << c << endl;
}
}
return CallNextHookEx(NULL, code, wParam, lParam);
}
int main() {
HHOOK HKeyboard = SetWindowsHookEx(WH_KEYBOARD_LL, LowLevelKeyboardProc, 0, 0);
MSG msg;
BOOL bRet;
while ((bRet = GetMessage(&msg, NULL, 0, 0)) > 0) {
cout << "bRet = " << bRet << endl; // I want to do something here, but the program doesn't seem to go in here
TranslateMessage(&msg);
DispatchMessage(&msg);
}
UnhookWindowsHookEx(HKeyboard);
return 0;
}
My question is why my program doesn't go inside the loop(and instead stuck on GetMessage function)? I need it to set conditions to terminate after some seconds, so where should i put the conditions? I know the GetMessage function reads Message, but when i press keys on my keyboard it still not going in and the callback function works just fine.
The events are posted to the active window. Console windows are owned by the console subsystem, csrss.exe, and it receives the events, then translates them to characters and puts them in the console object which is your application's stdin.
If you want to process events the Win32 GUI way, you should use a Win32 window (e.g. RegisterClass and CreateWindow), not a console window.
If you just want the callbacks to work for a certain period of time, you can use an alertable wait such as SleepEx or MsgWaitForMultipleObjects, which accept a timeout.
That's not surprising, there aren't really any messages on your thread queue and you have no window so there's no window queue either.
If you want to play with values returned from your hook, put the code in the hook callback function.
I should warn you that hooks like these won't work in console applications since the console window resides in another process. Also, if you look at the MSDN page for SetWindowsHookEx, you'll see that WH_KEYBOARD_LL is a global hook only, ie you have to put your hook handler in a DLL library and inject the hook in the other applications. Then you have to handle the 32/64 bit issue yourself.
And as a last note, when you say cout << c; in your handler, that would be printing in the process's output file handle, not your own.
Related
Is there a way to disable the right-click button? I'm trying to use a mouse hook, that when you run the program, it just simply disables the right-click button.
#include <iostream>
#include <vector>
#include <algorithm>
#include <cstdlib>
#include <conio.h>
#define _WIN32_WINNT 0x0500
#define WM_RBUTTONDOWN 0x0204
#include <windows.h>
/* Disable mouse using low-level mouse hook */
HHOOK miHook;
//Starting Hook Procedure
LRESULT CALLBACK LowLevelMouseProc(int nCode, WPARAM wParam, LPARAM lParam) {
if (nCode == HC_ACTION) {
MSLLHOOKSTRUCT &msll = *(reinterpret_cast<MSLLHOOKSTRUCT*>(lParam));
if (wParam == WM_RBUTTONDOWN) {
cout << "OOO";
if (WM_RBUTTONDOWN) {
return -1; // Make this click be ignored
}
}
}
return CallNextHookEx(miHook, nCode, wParam, lParam);
}
int main() {
system("pause");
}
Anyone have any clue if I'm doing it right, or if I need to actually go into the registry to actually disable the right-click on the mouse?
Yes, you could disable mouse events by installing low level mouse hook. Your LowLevelMouseProc callback should return nonzero value if nCode is greater or equal zero. Also you should block not only WM_RBUTTONDOWN windows message, but WM_RBUTTONUP as well, or target application may work incorrectly.
This code is pretty strange:
if (wParam == WM_RBUTTONDOWN) {
cout << "OOO";
if (WM_RBUTTONDOWN) {
return -1; // Make this click be ignored
}
Second if clause will always be true. Perhaps you mean
if((WM_RBUTTONDOWN == wParam)||(WM_RBUTTONDOWN == wParam))
return(-1);
Also, callback is running in the context of your thread by processing a windows message, so your code must have a message queue, it could not be simple console application
This hook is called in the context of the thread that installed it.
The call is made by sending a message to the thread that installed the
hook. Therefore, the thread that installed the hook must have a
message loop.
However system wide hooks could be pretty dangerous. One small error could easily make entire system unstable. Install hook only for the target application by specifying its message thread id in the SetWindowsHookEx call. Your other option would be subclassing target window by replacing its message processing routine and filtering mouse event messages.
I am trying to mod an older game, more specifically I want to emulate keyboard input via Xbox controller input. I already have the gamepad input working, but the game ignores my fake input I create with PostMessage (I tried PostThreadMessage as well with worse outcome.)
So here is the core piece of my code, a detour of PeekMessage :
BOOL WINAPI MyPeekMessage(LPMSG lpMsg, HWND hWnd, UINT wMsgFilterMin, UINT wMsgFilterMax, UINT wRemoveMsg)
{
BOOL ret = RealPeekMessage(lpMsg, hWnd, wMsgFilterMin, wMsgFilterMax, wRemoveMsg);
if (lpMsg->message == WM_KEYDOWN)
{
cout << "Key press";
}
if (!ret)
{
if (joypadButtonDown)
{
LPARAM lparam = 0x00000001 | (LPARAM)(EnterScanCode << 16); // Scan code, repeat=1
BOOL res = PostMessage(mainHwnd, WM_KEYDOWN, VK_RETURN, lparam);
}
}
return ret;
}
Now the problem is that the game doesn't use its message loop to read keyboard input, but instead uses SetWindowsHookEx with WH_KEYBOARD on its own main window thread.
So on a real key press what happens is :
The game's main loop calls my detour which calls the real PeekMessage which calls the hook procedure. But if I send my fake message (with identical parameters) the game again calls my detour but the real PeekMessage doesn't call the hook procedure and therefore misses the input.
Some additional Info :
- I've checked that everything happens on the same thread (Main window creation, setting the hook and the main loop)
- I tried sending PostMessage directly from IDirectInputDevice8->GetDeviceState with the same result
- Invoking the hook procedure directly causes a crash (which makes sense).
I found a somewhat dirty workaround. I call the game's SetWindowsHookEx KeyboardProc callback directly and avoid the crash I mentioned in the OP by detouring CallNextHookEx to ignore my fake hook calls.
I was trying to make a simple keylog test, but my program doesn't work as expected and I don't know why.
In my program i had a low level keyboard hook and attach a simple process to it. The process just opens/creates a file and writes "Hello World" then closes. However it isn't creating the file, probably because my process isn't correct or because my hook wasn't established correctly.
Code:
#include<windows.h>
#include<stdio.h>
#include <iostream>
#include <fstream>
using namespace std;
LRESULT CALLBACK KeyboardProc(int code, WPARAM wParam, LPARAM lParam){
ofstream myfile;
myfile.open ("[PATH]/example.txt");
myfile << "Hello world";//((KBDLLHOOKSTRUCT *)lParam)->vkCode
myfile.close();
return CallNextHookEx(NULL,code,wParam,lParam);
}
int main(void){
HINSTANCE hInst = NULL;
HHOOK hHook = SetWindowsHookEx(WH_KEYBOARD_LL, KeyboardProc, hInst, 0);
printf("HHOOK is not null: %s\n", (hHook != NULL) ? "True" : "False");
char q;
for (cout << "q to quit\n"; q != 'q'; cin >> q);
printf("Successfully unhooked: %s", UnhookWindowsHookEx(hHook) ? "True" : "False");
}
Solution I needed to add a message loop to the main function:
LPMSG Msg;
while(GetMessage(Msg, NULL, 0, 0) > 0)
{
TranslateMessage(Msg);
DispatchMessage(Msg);
}
Thre are two kind of hooks:
Global Hooks
Global hook procedures should be placed into a separate DLL, then in your main process you load the hook dll and it's hooking procedure and set the hook.
A global hook monitors messages for all threads in the same desktop as
the calling thread. A thread-specific hook monitors messages for only
an individual thread. A global hook procedure can be called in the
context of any application in the same desktop as the calling thread,
so the procedure must be in a separate DLL module.
That said: KeyboardProc goes into a separate DLL (e.g. myhookdll.dll).
In your process you do something like this:
HOOKPROC hkprc;
static HINSTANCE hhookDLL ;
static HHOOK hhook ;
hhookDLL = LoadLibrary(TEXT("c:\\...\\myhookdll.dll"));
hkprc = (HOOKPROC)GetProcAddress(hhookDLL, "KeyboardProc");
hhook = SetWindowsHookEx(
WH_KEYBOARD,
hkprc,
hhookDLL,
0);
Here a good reference: http://msdn.microsoft.com/en-us/library/windows/desktop/ms644960(v=vs.85).aspx
Thread Level Hooks about this specific 'WH_KEYBOARD_LL' that hooks at thread level, it does not need a separate DLL.
A thread-specific
hook procedure is called only in the context of the associated thread.
If an application installs a hook procedure for one of its own
threads, the hook procedure can be in either the same module as the
rest of the application's code or in a DLL. If the application
installs a hook procedure for a thread of a different application, the
procedure must be in a DLL. For information, see Dynamic-Link
Libraries.
But thread level hook needs a message pump:
This hook is called in the context of the thread that installed it.
The call is made by sending a message to the thread that installed the
hook. Therefore, the thread that installed the hook must have a
message loop.
Here a basic message loop:
while((bRet = GetMessage(&msg, NULL, 0, 0)) != 0)
{
if(bRet == -1)
{
// Handle Error
}
else
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
I am making a little aplication and I need to make a click over a position in a word document.
I am using "sendMessage, although I also was using "postMessage" getting the same result.
#include <Windows.h>
int _tmain(int argc, _TCHAR* argv[])
{
HWND win_handle = FindWindow(L"OpusApp", NULL);
if (win_handle != NULL)
{
POINT win_coords = {1310, 360};
POINT ctrl_coords = win_coords;
ScreenToClient(win_handle, &win_coords);
WCHAR windowsText1[200];
GetWindowText(win_handle, windowsText1, 200);
//SetCapture(win_handle);
LPARAM lParam = MAKELPARAM(win_coords.x, win_coords.y);
LRESULT hr_d = SendMessage(win_handle, WM_LBUTTONDOWN, 0, lParam);
LRESULT hr_u = SendMessage(win_handle, WM_LBUTTONUP, 0, lParam);
}
return 0;
}
Any suggestion?
Regards.
First, you shouldn't use SendMessage or PostMessage to send input. It may work for some programs, but directly sending or posting the message doesn't update the internal state that's associated with input, which can make odd things happen, such as not detecting the input.
That's why the function SendInput exists. This injects input on the same level that the mouse driver uses, so Windows will correctly maintain its state. Of course, this is for global input. If there's no way to ensure that the window will be in the foreground, you may want to look into UI Automation.
#include <iostream>
#include <fstream>
#define _WIN32_WINNT 0x501
#include <windows.h>
using namespace std;
HHOOK hKeyboardHook = 0;
LRESULT CALLBACK KeyboardCallback(int code,WPARAM wParam,LPARAM lParam) {
cout << "a key was pressed" << endl;
ofstream myfile;
myfile.open ("hookcheck.txt", ios::ate | ios::app);
myfile << "a key was pressed\n";
myfile.close();
return CallNextHookEx(hKeyboardHook,code,wParam,lParam);
}
int main() {
HWND consoleWindow = GetConsoleWindow();
HINSTANCE hInstCons = (HINSTANCE)GetWindowLong( consoleWindow, GWL_HINSTANCE );
hKeyboardHook = SetWindowsHookEx( WH_KEYBOARD, (HOOKPROC)KeyboardCallback, (HINSTANCE)consoleWindow, GetCurrentThreadId());
MessageBox(NULL, "It is keyboard time!", "Let's Go", MB_OK);
}
This code on every key press while the loop is going should print message on console and create a file, but nothing is happening. What do I wrong ?
I will quote from another topic:
Console windows are handled entirely by CSRSS, which is a system
process. Installing a hook into a process means injecting your DLL
into it. Since CSRSS is so important (it's vital for running of the
system, and code within runs as LocalSystem, which is the local
super-admin user), you're not allowed to inject code into it. So you
can't hook any of its windows.
There are no real window messages taking place in your simple console application, so your hook does not have to be called, and in your case you are not even injecting your hook but using thread mode hook only. Per MSDN documentation it is called when messages are about to be processed:
An application-defined or library-defined callback function used with
the SetWindowsHookEx function. The system calls this function whenever
an application calls the GetMessage or PeekMessage function and there
is a keyboard message (WM_KEYUP or WM_KEYDOWN) to be processed.
Now let me show you what you can do to start receiving calls on your hook:
MessageBox(NULL, _T("It is keyboard time!"), _T("Let's Go"), MB_OK);
//for(int i=0; i<=10; i++) {
// cout << i << endl;
// Sleep(1000);
//}
Do MessageBox and before closing it start typing - you will start getting hook calls.
Read the documentation for SetWindowsHookEx. Is it working, it will return NULL if it fails and GetLastError() can be called to get an error code to help diagnose what is wrong.
http://msdn.microsoft.com/en-us/library/windows/desktop/ms644990(v=vs.85).aspx
Sleep(1000) suspends the execution of the current thread until the time-out interval elapses. It means that your program is not actually running (ie. processing messages) during this sleep.
You need to use a different kind of command, that will keep the message loop running. The simplest thing would be to wait for user input
while(true)
std::cin.get();
I have created a dll that hooked the keyboard and in there I used the DllMainfunction to retrieve a HINSTANCE that can be used in SetWindowsHookEx.
Next to that I also used 0 as the threadid so all threads get hooked.
Perhaps you could try a similar tactic as well.