SetWindowsHookEx WH_KEYBOARD_LL not responding on right shift - c++

I try to use the Windows API in c++ and SetWindowsHookEx WH_KEYBOARD_LL does not seem to get events from the right Shift key (the Shift key at the right side of a qwerty keyboard, below the Enter key). It does work with the left Shift key. How do I troubleshoot this problem???
#include "stdafx.h"
#include <cstdlib>
#include <fstream>
#include <iostream>
#include <string>
#include <windows.h>
#include <string>
#include <shlobj.h>
#include <Shlwapi.h>
#include <stdio.h>
#include <aclapi.h>
#include <tchar.h>
#include <iostream>
#include <fstream>
#include <future>
#include <stdlib.h>
#include <random>
#include <ctime>
#include <time.h>
#include <Lmcons.h>
HHOOK kbdhook; /* Keyboard hook handle */
bool running; /* Used in main loop */
__declspec(dllexport) LRESULT CALLBACK handlekeys(int code, WPARAM wp, LPARAM lp)
{
static bool capslock = false;
static bool shift = false;
char tmp[0xFF] = {0};
std::string str;
DWORD msg = 1;
KBDLLHOOKSTRUCT st_hook = *((KBDLLHOOKSTRUCT*)lp);
msg += (st_hook.scanCode << 16);
msg += ((st_hook.flags & LLKHF_EXTENDED) << 24);
GetKeyNameText(msg, tmp, 0xFF);
str = std::string(tmp);
if (code == HC_ACTION && (wp == WM_SYSKEYDOWN || wp == WM_KEYDOWN )) {
MessageBox(NULL,str.c_str(),NULL,MB_OK);
}
return CallNextHookEx(kbdhook, code, wp, lp);
}
LRESULT CALLBACK windowprocedure(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp)
{
switch (msg) {
case WM_CLOSE: case WM_DESTROY:
running = false;
break;
default:
/* Call default message handler */
return DefWindowProc(hwnd, msg, wp, lp);
}
return 0;
}
int WINAPI WinMain(HINSTANCE thisinstance, HINSTANCE previnstance,
LPSTR cmdline, int ncmdshow)
{
HWND hwnd;
HWND fgwindow = GetForegroundWindow();
MSG msg;
WNDCLASSEX windowclass;
HINSTANCE modulehandle;
modulehandle = GetModuleHandle(NULL);
kbdhook = SetWindowsHookEx(WH_KEYBOARD_LL, (HOOKPROC)handlekeys, modulehandle, NULL);
running = true;
while (running) {
if (!GetMessage(&msg, NULL, 0, 0))
running = false;
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return 0;
}
Right shift shows a blanco string in the alert. Left shift however shows a "SHIFT" string in the alert. Anyone a clue???
PS:
If I remove the line with " msg += ((st_hook.flags & LLKHF_EXTENDED) << 24);" -> "RIGHT SHIFT" does show up now, but undefined shows up, when pressing the "Windows key"

Left vs. right shift shows up in the vkCode field of KBDLLHOOKSTRUCT. You're using the key name of the scancode; the right shift key is named 'Shift', just like it says on the keyboard.
Apparently, right shift ends up with the extended flag set, which causes GetKeyNameText to look in the wrong table. Removing the extended flag ends up with a key name of "right shift".
msg += (st_hook.scanCode << 16);
if (st_hook.scanCode != 0x3a)
{
msg += ((st_hook.flags & LLKHF_EXTENDED) << 24);
}
GetKeyNameText(msg, tmp, 0xFF);

This solution does not rely on a specific code
if (st_hook.vkCode != VK_RSHIFT)
msg += ((st_hook.flags & LLKHF_EXTENDED) << 24);

Related

Why SetWinEventHook do not work with EVENT_SYSTEM_SWITCHSTART?

#define UNICODE
#define _UNICODE
#include <iostream>
#include <Windows.h>
#include <fstream>
using namespace std;
void CALLBACK Wineventproc(HWINEVENTHOOK hWinEventHook,DWORD event,
HWND hwnd,
LONG idObject,
LONG idChild,
DWORD idEventThread,
DWORD dwmsEventTime
){
cout<<"EventId:"<<idEventThread<<endl;
}
int main() {
CoInitialize(nullptr);
HWINEVENTHOOK hEventHook = SetWinEventHook(EVENT_SYSTEM_SWITCHSTART, EVENT_SYSTEM_SWITCHEND, nullptr, Wineventproc, 0, 0,
WINEVENT_OUTOFCONTEXT | WINEVENT_SKIPOWNPROCESS);
if(hEventHook==NULL){
cout<<"hook fail"<<endl;
return 0;
}
MSG mess;
BOOL bRet;
cout<<"1"<<endl;
while ((bRet=GetMessage(&mess, nullptr,0,0))!=0){
cout<<"2"<<endl;
if(bRet == -1){
}else {
TranslateMessage(&mess);
DispatchMessage(&mess);
}
}
if(!UnhookWinEvent(hEventHook)){
return 0;
}
CoUninitialize();
return 0;
}
Just an easy demo that I want to use SetWinEventHook() to get program switch event. But, when I input Alt+Tab (EVENT_SYSTEM_SWITCHSTART), the GetMessage() is still blocked. What's wrong?
Finally, I change to use EVENT_SYSTEM_FOREGROUND .

Keylogger and mousetracker: should I use non-blocking I/O?

I'm writing a simple keylogger/mouselogger in C/C++ for Windows. To do that, I use the Win32 functions LowLevelMouseProc and LowLevelKeyboardProc.
If relevant, here is a GitHub gist with my code, which is ultra-elementary: define the event callback and register it along with a callback for SIGINT. I'll add a summarized version at the end of the question.
My question is the following: in order to minimize overhead, how should I save these events to disk?
Answers in both C or C++ are welcome.
Is it a good practice to simply write to a buffered file each time I get a new event and let the file handle flushing when the buffer is full? I heard about non-blocking I/O but microsoft's doc says that there is an additional overhead. And finally, I'm not sure wether I should create a second thread for this.
I'd like to use some sort of buffering to avoid many little disk I/O. Ideally I would write to disk once before my process is killed. But I have no idea how to achieve this.
CODE:
#include "pch.h"
#include <stdio.h>
#include <Windows.h>
HHOOK handle;
LRESULT CALLBACK lowLevelMouseProc(
_In_ int nCode,
_In_ WPARAM wParam,
_In_ LPARAM lParam
)
{
MSLLHOOKSTRUCT* lp = (MSLLHOOKSTRUCT*)lParam;
if (wParam == WM_MOUSEMOVE) {
// Best way to save pt.x and pt.y to disk?
printf("%d %d \n", lp->pt.x, lp->pt.y);
}
return CallNextHookEx(0, nCode, wParam, lParam);
}
int main()
{
handle = SetWindowsHookExA(WH_MOUSE_LL, &lowLevelMouseProc, NULL, 0);
MSG msg;
while (GetMessage(&msg, NULL, 0, 0));
UnhookWindowsHookEx(handle)
return 0;
}
Use 2 buffers. One for writing, one for reading (flushing to disk). Once some condition is met (buffer full, program shutdown, ...), swap the buffers and start flushing to disk in a seperate thread.
This might look something like:
#include <Windows.h>
#include <vector>
#include <thread>
#include <fstream>
#include <atomic>
struct Point
{
long x, y;
};
class Buffer
{
public:
Buffer(std::string _file = "log.txt", const size_t _buffer_size = 100000) : buffer_size(_buffer_size), file(_file)
{
points1.reserve(_buffer_size);
points2.reserve(_buffer_size);
}
void write(Point p)
{
buf->push_back(p);
if (buf->size() >= buffer_size && !thread_running.load())
to_disk();
}
private:
const size_t buffer_size;
const std::string file;
std::atomic<bool> thread_running{ false };
std::vector<Point> points1, points2;
std::vector<Point> *buf = &points1, *other = &points2;
void swap_buffer()
{
std::swap(buf, other);
}
void to_disk()
{
swap_buffer();
auto tmp_buf = other;
auto tmp_file = file;
auto tmp_flag = &thread_running;
auto fn = [tmp_buf, tmp_file, tmp_flag]() {
tmp_flag->store(true);
std::fstream f(tmp_file, std::ios::app);
for (auto &v : *tmp_buf)
f << v.x << ' ' << v.y << '\n';
tmp_buf->clear();
tmp_flag->store(false);
};
std::thread t(fn);
t.detach();
}
};
Buffer buffer("log.txt");
HHOOK handle;
LRESULT CALLBACK lowLevelMouseProc(
_In_ int nCode,
_In_ WPARAM wParam,
_In_ LPARAM lParam
)
{
MSLLHOOKSTRUCT* lp = (MSLLHOOKSTRUCT*)lParam;
if (wParam == WM_MOUSEMOVE) {
buffer.write({ lp->pt.x, lp->pt.y });
}
return CallNextHookEx(0, nCode, wParam, lParam);
}
int main()
{
handle = SetWindowsHookExA(WH_MOUSE_LL, &lowLevelMouseProc, NULL, 0);
MSG msg;
while (GetMessage(&msg, NULL, 0, 0));
UnhookWindowsHookEx(handle);
return 0;
}
In this case, the buffer gets written to disk when a certain size limit is reached. This could be further optimized, by not checking the size on every write for example.
Note: In this example, error handling is omitted and the lifetime of the internal buffers should be managed accordingly.

random lost key input on hooks

i have an HID usb rfid reader that act like a keyboard,
i don't want to put a textbox on my form (WPF) to recieve the text from it because i have other requirements .
instead i am trying to capture the key pressed events and process them . for that i have tried three differents methods :
Windows Hook (c++)
this is the most simple testcase example that illustrate the issue
#include <iostream>
#include <fstream>
#include <Windows.h>
#pragma comment(lib, "user32.lib")
HHOOK keyboardHook{ NULL };
DWORD lastkey = 0;
LRESULT CALLBACK MyLowLevelKeyBoardProc(const int nCode, const WPARAM wParam, const LPARAM lParam)
{
KBDLLHOOKSTRUCT *kb = (KBDLLHOOKSTRUCT *)lParam;
switch (wParam)
{
case WM_KEYUP:
if (lastkey == 13)
system("cls");
std::cout << "KeyUp event : " << kb->vkCode << std::endl;
lastkey = kb->vkCode;
break;
}
return CallNextHookEx(keyboardHook, nCode, wParam, lParam);
}
int main(int argc, char* argv[])
{
keyboardHook = SetWindowsHookEx(WH_KEYBOARD_LL, MyLowLevelKeyBoardProc, NULL, 0);
if (keyboardHook == NULL) {
std::cout << "Keyboard hook failed!" << std::endl;
}
while (GetMessage(NULL, NULL, 0, 0));
return 0;
}
Raw input API
by handling the WM_INPUT message (too many code to show)
oblita interception library
the most interesting solution that i will use if i fix the problem
#include "stdafx.h"
#include "C:\Dev\WPF\Interception\library\interception.h"
#include "C:\Dev\WPF\Interception\Interception-1.0.0\samples\utils.h"
#include <string>
#include <iostream>
enum ScanCode
{
SCANCODE_X = 0x2D,
SCANCODE_Y = 0x15,
SCANCODE_ESC = 0x01
};
int main()
{
using namespace std;
InterceptionContext context;
InterceptionDevice device;
InterceptionStroke stroke;
wchar_t hardware_id[500];
string buffer = "";
//raise_process_priority();
context = interception_create_context();
interception_set_filter(context, interception_is_keyboard, INTERCEPTION_FILTER_KEY_UP | INTERCEPTION_FILTER_KEY_UP);
while (interception_receive(context, device = interception_wait(context), &stroke, 1) > 0)
{
if (interception_is_keyboard(device))
{
InterceptionKeyStroke &keystroke = *(InterceptionKeyStroke *)&stroke;
if (keystroke.code == SCANCODE_ESC) break;
size_t length = interception_get_hardware_id(context, device, hardware_id, sizeof(hardware_id));
if (wcsstr(hardware_id, L"04F3&PID_0009") == 0)
interception_send(context, device, &stroke, 1); // Real Keyboard
else
{
// RFID reader
if (keystroke.code == 28)
{
std::cout << buffer << endl;
buffer = "";
}
else
buffer = buffer + std::to_string(keystroke.code);
}
}
}
interception_destroy_context(context);
return 0;
}
all the three methods gave me the same problem :
some keys are randomly lost during the read, instead of having the 10 characters i my have 8/9 only .
if i use the rfid reader on blocnote no character is lost so there is no problem with the reader .
so my question is : how to ensure that no message/key is lost by windows on the hooks , even if the read operation may take 10 seconds .
thanks and good day .

C++ - How can I exit a program that has no window?

I'm new to C++, and I made myself a little program that can launch program through typing a command on the keyboard. In order to be able to launch a program whenever I want, I decided to set up a Low Level Keyboard Hook, which keep tracking key strokes and launch the specific program when the specific command was detected. The simple windows program was used to install the hook, the windows is not showed because all I need is the hook to listen in the background.
So far it works fine, however, the minor but annoying problem is I have to terminate the program through Windows Task Manager, and it's quite inconvenient. I have managed to uninstall the hook by pressing F7 key, but it seems that the windows program which is not showed is the Parent of the hook, so the hook cannot exit the windows program. While I want them both terminated through pressing a key. Hopefully I have made myself clear.
Is there any way that I could send a message from the hook to the windows program to ask it to exit? Or somehow I can terminate both of them in the hook program?
Thanks in advance.
Here is the code of the window program:
#include <windows.h>
#include "shortcut.h"
#pragma comment( lib, "libhook.dll.a") // Link Hook.lib to the project
long WINAPI WndProc(HWND hWnd, UINT wMessage, WPARAM wParam, LPARAM lParam)
{
switch(wMessage)
{
case WM_DESTROY:
InstallHook(FALSE); // Unhook
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, wMessage, wParam, lParam);
}
return 0;
}
BOOL FileExists(LPCTSTR szPath)
{
DWORD dwAttrib = GetFileAttributes(szPath);
return (dwAttrib != INVALID_FILE_ATTRIBUTES &&
!(dwAttrib & FILE_ATTRIBUTE_DIRECTORY));
}
int WINAPI WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance, LPSTR lpszCmdLine, int nCmdShow)
{
MSG msg;
WNDCLASS wndclass;
HANDLE hMutex = NULL;
char szAppName[20] = "shortcut";
hMutex = CreateMutex(NULL,TRUE,szAppName); //启动多线程
int dwRet = GetLastError();
if (hMutex)
{
if (dwRet == ERROR_ALREADY_EXISTS)
{
MessageBox(NULL, "Program is already runing.", "Oops!", MB_OK | MB_ICONINFORMATION);
CloseHandle(hMutex);
return FALSE;
}
}
wndclass.style=0;
wndclass.lpfnWndProc=(WNDPROC)WndProc;
wndclass.cbClsExtra=0;
wndclass.cbWndExtra=0;
wndclass.hInstance=hInstance;
wndclass.hIcon=NULL;
wndclass.hCursor=LoadCursor(NULL, IDC_ARROW);
wndclass.hbrBackground=(HBRUSH)GetStockObject(GRAY_BRUSH);
wndclass.lpszMenuName=NULL;
wndclass.lpszClassName=(LPSTR)szAppName;
if(!RegisterClass(&wndclass))
return FALSE;
if (!FileExists("\\ShortCuts.txt"))
{
MessageBox(NULL, "Missing file: cannot load shortcut settings file.(Shortcuts.txt)", "ERROR",MB_OK|MB_ICONINFORMATION);
exit(1);
}
if (!InstallHook(TRUE))
exit(1);
while(GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}
Here is the code of the hook program:
// Hook- a project to create the DLL and LIB files.
// Microsoft Visual C++ 6.0 and above steps:
// 1. Create a new Win32 Dynamic Link - Library project.
// 2. Add hook.cpp and hook.h to the project.
// 3. There is no step 3 :-). Just build your project and you will find
// a Hook.dll and Hook.lib file in your map.
#include <windows.h>
#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include <ctime>
#include <map>
#include <process.h>
using namespace std;
HHOOK hHook;
HINSTANCE ghDLLInst=0;
const char startChar = ';';
bool bChecking = false;
string cmd;
typedef map<string,string> COMMANDMAP;
COMMANDMAP mShortcut;
string logfilename="log.txt";
ofstream LOG;
__declspec(dllexport)int InstallHook(BOOL bCode);
BOOL APIENTRY DllMain(HANDLE hModule, DWORD dwFunction, LPVOID lpNot)
{
ghDLLInst=(HINSTANCE)hModule;
return TRUE;
}
DWORD WINAPI Runsystem(LPVOID lpParam)
{
WinExec((LPCSTR)lpParam, SW_SHOW);
}
string gettime()
{
time_t curTime;
struct tm *locTime;
char buf[80];
time(&curTime);
locTime=localtime(&curTime);
strftime(buf,80,"%Y-%m-%d %H:%M:%S",locTime);
string s=buf;
return s;
}
ostream& tout()
{
return LOG<< gettime()<< ": ";
}
void StartCheck()
{
bChecking=true;
cmd.clear();
}
void EndCheck()
{
bChecking=false;
cmd.clear();
}
LRESULT CALLBACK KeyboardProc(int nCode, WPARAM wParam, LPARAM lParam)
{
if ((wParam == WM_KEYDOWN) && (nCode >= HC_ACTION)) // Only record when key pressed
{
KBDLLHOOKSTRUCT *pStruct = (KBDLLHOOKSTRUCT*)lParam;
switch (pStruct->vkCode)
{
case VK_RETURN:
{
if (bChecking)
{
COMMANDMAP::iterator it;
it=mShortcut.find(cmd);
if (it!=mShortcut.end())
{
tout()<<"received command \'"<<cmd<<"\', executing \'"<<it->second.c_str()<<endl;
CreateThread(NULL, 0, Runsystem, (void*)it->second.c_str(),0,NULL);
}
else {
tout()<<"received command \'" <<cmd<<"\', no matching."<<endl;
}
}
EndCheck();
break;
}
case VK_F7:
{
InstallHook(false);
break;
}
default: // Normal keys, convert them
{
BYTE KeyboardState[256];
GetKeyboardState(KeyboardState);
WORD CharValue;
if(ToAscii(pStruct->vkCode, pStruct->scanCode,KeyboardState,&CharValue,0) > 0) // Convert to char.
{
char character=char(CharValue);
// tout()<<"received keyCode: "<<pStruct->vkCode<< " char: "<< character<<endl;
if (bChecking)
{
cmd+=character;
}
if (!bChecking && (character == startChar))
{
// tout()<<"Start checking..."<<endl;
StartCheck();
}
}
break;
}
}
}
return (int)CallNextHookEx(hHook, nCode, wParam, lParam);
}
bool readline(ifstream &fin,string &sline)
{
do
{
getline(fin,sline);
} while (!fin.eof() && ((sline[0]=='/' && sline[1]=='/') || sline.empty()));
return fin.eof()?false:true;
}
// __declspec(dllexport) means that this function must be exported to a dll file.
__declspec(dllexport)int InstallHook(BOOL bCode)
{
if(bCode)
{
// initialize shortcuts
ifstream fin;
LOG.open(logfilename.c_str(),ios_base::app);
tout()<<"Reading config file."<<endl;
fin.open("ShortCuts.txt");
if (fin)
{
string scmd,spath;
char oneline[256];
while(readline(fin,scmd)&&readline(fin,spath))
{
mShortcut[scmd]=spath;
// LOG<<scmd<<','<<spath<<endl;
}
fin.close();
tout()<<"OK, "<<mShortcut.size()<<" shortcuts loaded."<<endl;
}
else
{
tout()<<"ERROR"<<endl;
LOG.close();
exit(0);
}
hHook=(HHOOK)SetWindowsHookEx(WH_KEYBOARD_LL, (HOOKPROC)KeyboardProc, // Start the keyboard hook.
(HINSTANCE)GetModuleHandle(NULL), NULL);
if(!hHook)
{
tout()<<"Install hook failed."<<endl;
return 0;
}
else
{
tout()<<"Install hook successful."<<endl;
return 1;
}
}
else
{
if (MessageBox(NULL,"Are you sure to exit KeyShortcut?","Exit",MB_YESNO|MB_ICONWARNING)==IDYES)
{
tout()<<"Uninstall hook successful."<<endl;
LOG.close();
return UnhookWindowsHookEx(hHook); // Unhook the keyboardhook.
}
}
}
For instance, you can use RegisterHotKey API function to set your own hotkey to a system and then handle this hotkey's message in your program(windowless)
Added:
If you want to send quit message from one process to another then your friend is PostThreadMessage(dwThreadId, WM_DESTROY, 0, 0);

Is it possible to use Win32 Hooks in Qt applications

I like to know if its possible to use win32 keyboard hook function (SetWindowsHookEx , SetWindowsHookEx ) in a Qt application.
If possible pls provide a sample code on using SetWindowsHookEx , SetWindowsHookEx functions in Qt.
//Update as of 18 Feb 2010 //
I havent figured out how to do that in QT yet.
But as a workaround I have created a win32 dll using vc++ express edition and placed my hook commands inside the dll functions.
And I call that dll functions from Qt using QLibrary class
/* hearder file code*/
QLibrary *myLib;
typedef HHOOK (*MyPrototype)(HINSTANCE);
/* source file code */
myLib = new QLibrary( "ekhook.dll" );
MyPrototype myFunction;
myFunction = (MyPrototype) myLib->resolve( "Init" );
init() is the function in ekhook.dll thats being called
I was wondering the same thing and found this finally.. Credit goes to Voidrealms.
The video explains enough to make a working application with the following code below.
//Copied Code from YouTube Video
#include <QtCore/QCoreApplication>
#include <QDebug>
#include <QTime>
#include <QChar>
#include <iostream>
#include <windows.h>
#pragma comment(lib, "user32.lib")
HHOOK hHook = NULL;
using namespace std;
void UpdateKeyState(BYTE *keystate, int keycode)
{
keystate[keycode] = GetKeyState(keycode);
}
LRESULT CALLBACK MyLowLevelKeyBoardProc(int nCode, WPARAM wParam, LPARAM lParam)
{
//WPARAM is WM_KEYDOWn, WM_KEYUP, WM_SYSKEYDOWN, or WM_SYSKEYUP
//LPARAM is the key information
qDebug() << "Key Pressed!";
if (wParam == WM_KEYDOWN)
{
//Get the key information
KBDLLHOOKSTRUCT cKey = *((KBDLLHOOKSTRUCT*)lParam);
wchar_t buffer[5];
//get the keyboard state
BYTE keyboard_state[256];
GetKeyboardState(keyboard_state);
UpdateKeyState(keyboard_state, VK_SHIFT);
UpdateKeyState(keyboard_state, VK_CAPITAL);
UpdateKeyState(keyboard_state, VK_CONTROL);
UpdateKeyState(keyboard_state, VK_MENU);
//Get keyboard layout
HKL keyboard_layout = GetKeyboardLayout(0);
//Get the name
char lpszName[0X100] = {0};
DWORD dwMsg = 1;
dwMsg += cKey.scanCode << 16;
dwMsg += cKey.flags << 24;
int i = GetKeyNameText(dwMsg, (LPTSTR)lpszName, 255);
//Try to convert the key information
int result = ToUnicodeEx(cKey.vkCode, cKey.scanCode, keyboard_state, buffer, 4, 0, keyboard_layout);
buffer[4] = L'\0';
//Print the output
qDebug() << "Key: " << cKey.vkCode << " " << QString::fromUtf16((ushort*)buffer) << " " << QString::fromUtf16((ushort*)lpszName);
}
return CallNextHookEx(hHook, nCode, wParam, lParam);
}
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
hHook = SetWindowsHookEx(WH_KEYBOARD_LL, MyLowLevelKeyBoardProc, NULL, 0);
if (hHook == NULL)
{
qDebug() << "Hook Failed" << endl;
}
return a.exec();
}
You don't need to do anything with Qt. Just follow the windows examples:
http://msdn.microsoft.com/en-us/library/ms644960(VS.85).aspx
I believe it is possible, yes. Use QWidget::winId.