Skip to content

Instantly share code, notes, and snippets.

@jay
Last active November 4, 2020 07:31
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
Star You must be signed in to star a gist
Embed
What would you like to do?
Monitor *raw* mouse buttons and keypresses in Windows
/* hooktest2
Monitor *raw* mouse buttons, keypresses, everything but MOUSEMOVE via low level
mouse and keyboard hooks. I wrote this to help identify some bugs in Chrome and
software running on Dell laptops.
The program will exit when the caps lock key is pressed. You can change that in
the LowLevelKeyboardProc function.
Windows will auto detach the hooks if there's a delay processing them. This is
especially apparent with the mouse hook, so if you attempt to select and copy
the console output from this program that may cause the mouse hook to be
detached.
g++ -Wall -o hooktest2 hooktest2.cpp && hooktest2
Copyright (C) 2020 Jay Satiro <raysatiro@yahoo.com>
All rights reserved. License GPLv3+: GNU GPL version 3 or later
<http://www.gnu.org/licenses/gpl.html>.
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
https://gist.github.com/jay/2c2cd67534595615bc81ec0c8440f95f
*/
#define _WIN32_WINNT 0x0501
#include <windows.h>
#include <stdio.h>
#include <time.h>
#include <iomanip>
#include <iostream>
#include <sstream>
#include <string>
#ifndef GET_X_LPARAM
#define GET_X_LPARAM(lp) ((int)(short)LOWORD(lp))
#endif
#ifndef GET_Y_LPARAM
#define GET_Y_LPARAM(lp) ((int)(short)HIWORD(lp))
#endif
#ifndef WM_MOUSEHWHEEL
#define WM_MOUSEHWHEEL 0x020E
#endif
#ifndef LLKHF_INJECTED
#define LLKHF_INJECTED 0x00000010
#endif
#ifndef LLKHF_LOWER_IL_INJECTED
#define LLKHF_LOWER_IL_INJECTED 0x00000002
#endif
#ifndef LLMHF_INJECTED
#define LLMHF_INJECTED 0x00000001
#endif
#ifndef LLMHF_LOWER_IL_INJECTED
#define LLMHF_LOWER_IL_INJECTED 0x00000002
#endif
using namespace std;
/* system time in format: Tue May 16 03:24:31.123 PM */
string SystemTimeStr(const SYSTEMTIME *t)
{
const char *dow[] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" };
const char *mon[] = { NULL, "Jan", "Feb", "Mar", "Apr", "May", "Jun",
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
stringstream ss;
unsigned t_12hr = (t->wHour > 12 ? t->wHour - 12 : t->wHour ? t->wHour : 12);
const char *t_ampm = (t->wHour < 12 ? "AM" : "PM");
ss.fill('0');
ss << dow[t->wDayOfWeek] << " "
<< mon[t->wMonth] << " "
<< setw(2) << t->wDay << " "
<< setw(2) << t_12hr << ":"
<< setw(2) << t->wMinute << ":"
<< setw(2) << t->wSecond << "."
<< setw(3) << t->wMilliseconds << " "
<< t_ampm;
return ss.str();
}
string now()
{
SYSTEMTIME st;
GetLocalTime(&st);
return SystemTimeStr(&st);
}
/* The timestamp style in default mode: [Sun May 28 07:00:27.999 PM]: text */
#define TIMESTAMP \
"[" << now() << "]: "
std::string get_wm_name(WPARAM wParam)
{
switch(wParam) {
case WM_KEYDOWN: return "WM_KEYDOWN";
case WM_SYSKEYDOWN: return "WM_SYSKEYDOWN";
case WM_KEYUP: return "WM_KEYUP";
case WM_SYSKEYUP: return "WM_SYSKEYUP";
case WM_MOUSEMOVE: return "WM_MOUSEMOVE";
case WM_MOUSEWHEEL: return "WM_MOUSEWHEEL";
case WM_MOUSEHWHEEL: return "WM_MOUSEHWHEEL";
case WM_LBUTTONDOWN: return "WM_LBUTTONDOWN";
case WM_LBUTTONUP: return "WM_LBUTTONUP";
case WM_MBUTTONDOWN: return "WM_MBUTTONDOWN";
case WM_MBUTTONUP: return "WM_MBUTTONUP";
case WM_RBUTTONDOWN: return "WM_RBUTTONDOWN";
case WM_RBUTTONUP: return "WM_RBUTTONUP";
case WM_XBUTTONDOWN: return "WM_XBUTTONDOWN";
case WM_XBUTTONUP: return "WM_XBUTTONUP";
}
stringstream ss;
ss << "<Unknown wParam: 0x" << std::hex << wParam << std::dec << ">";
return ss.str();
}
LRESULT CALLBACK LowLevelMouseProc(int nCode, WPARAM wParam, LPARAM lParam)
{
DWORD flags = ((MSLLHOOKSTRUCT *) lParam)->flags;
bool injected = flags & (LLMHF_INJECTED | LLMHF_LOWER_IL_INJECTED);
POINT pt = ((MSLLHOOKSTRUCT *) lParam)->pt;
if(nCode == HC_ACTION) {
switch(wParam) {
case WM_MOUSEMOVE:
break;
default:
case WM_MOUSEWHEEL:
case WM_MOUSEHWHEEL:
case WM_LBUTTONDOWN:
case WM_LBUTTONUP:
case WM_MBUTTONDOWN:
case WM_MBUTTONUP:
case WM_RBUTTONDOWN:
case WM_RBUTTONUP:
case WM_XBUTTONDOWN:
case WM_XBUTTONUP:
stringstream ss;
ss << "\n" << TIMESTAMP
<< "{M" << (injected ? ", injected" : "") << "} "
<< get_wm_name(wParam);
size_t fillcount;
const int col = 55;
long pos = ss.tellp();
if(0 < pos && pos < col)
fillcount = col - pos;
else
fillcount = 1;
ss << string(fillcount, ' ')
<< pt.x << "," << pt.y << "\n";
cerr << ss.rdbuf();
break;
}
}
return CallNextHookEx(NULL, nCode, wParam, lParam );
}
LRESULT CALLBACK LowLevelKeyboardProc(int nCode, WPARAM wParam, LPARAM lParam)
{
KBDLLHOOKSTRUCT *pkh = (KBDLLHOOKSTRUCT *)lParam;
DWORD flags = ((KBDLLHOOKSTRUCT *) lParam)->flags;
bool injected = flags & (LLKHF_INJECTED | LLKHF_LOWER_IL_INJECTED);
if(nCode == HC_ACTION) {
switch(wParam) {
case WM_KEYDOWN:
case WM_SYSKEYDOWN:
if(pkh->scanCode == 0x3a) { // EXIT ON CAPS LOCK
Beep(750, 300);
exit(1);
}
default:
case WM_KEYUP:
case WM_SYSKEYUP:
DWORD key = ((pkh->scanCode << 16) & 0xFFFF0000);
// Right Shift: Ignore extended flag so GetKeyNameText will recognize it.
// https://stackoverflow.com/a/18901844
if((pkh->flags & LLKHF_EXTENDED) && (pkh->vkCode != VK_RSHIFT))
key |= (1 << 24);
char keyname[256] = { 0 };
GetKeyNameTextA(key, keyname, sizeof(keyname));
stringstream ss;
ss << "\n" << TIMESTAMP
<< "{K" << (injected ? ", injected" : "") << "} "
<< get_wm_name(wParam) << " '" << keyname << "'";
size_t fillcount;
const int col = 72;
long pos = ss.tellp();
if(0 < pos && pos < col)
fillcount = col - pos;
else
fillcount = 1;
ss << string(fillcount, ' ')
<< std::hex << "0x" << pkh->scanCode << std::dec << "\n";
cerr << ss.rdbuf();
break;
}
}
return CallNextHookEx(NULL, nCode, wParam, lParam);
}
int main(int argc, char *argv[])
{
MSG msg;
HINSTANCE hinstExe = GetModuleHandle(NULL);
// Force creation of message queue
PeekMessageA(&msg, NULL, WM_USER, WM_USER, PM_NOREMOVE);
for(int i = 0; !SetThreadPriority(GetCurrentThread(), 15) && (i < 100); ++i)
Sleep(1);
SetWindowsHookEx(WH_KEYBOARD_LL, LowLevelKeyboardProc, hinstExe, 0);
SetWindowsHookExW(WH_MOUSE_LL, LowLevelMouseProc, hinstExe, 0 );
cerr << "To exit the program hit caps lock key at any time." << endl;
while(GetMessageA(&msg, NULL, 0, 0))
;
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment