Convert events from a USB human interface device using C++ - c++

I have a USB HID touchpad that collects input. By default, when I press on the touchpad it generates carriage return (Enter) and when I try to use it as a mouse it actually enters a dragging state.
What I want to do is to convert the carriage return into a mouse click event and the dragging state into a cursor move without the initial clicking part.
I found the raw input alternative. However, I don't know how to convert it into mouse click and cursor move.
Here is the code responsible with the mouse 'reading':
LRESULT CALLBACK mouseProc (int nCode, WPARAM wParam, LPARAM lParam)
{
MOUSEHOOKSTRUCT * pMouseStruct = (MOUSEHOOKSTRUCT *)lParam;
if (pMouseStruct != NULL)
{
if(wParam == WM_LBUTTONDOWN)
{
cout<<"clicked"<<endl;
}
printf("Mouse position X = %d Mouse Position Y = %d\n", pMouseStruct->pt.x,pMouseStruct->pt.y);
stringstream sx, sy;
sx << (int) pMouseStruct->pt.x << endl;
sy << (int) pMouseStruct->pt.y << endl;
}
return CallNextHookEx(hMouseHook, nCode, wParam, lParam);
}
then the keyboard part:
LRESULT CALLBACK LowLevelKeyboardProc(int nCode, WPARAM wParam, LPARAM lParam)
{
if (nCode < 0)
return CallNextHookEx(NULL, nCode, wParam, lParam);
tagKBDLLHOOKSTRUCT *str = (tagKBDLLHOOKSTRUCT *)lParam;
cout<<str->vkCode<<endl;
return CallNextHookEx(NULL, nCode, wParam, lParam);
}
then the logging part:
DWORD WINAPI MyLogger(LPVOID lpParm)
{
HINSTANCE hInstance = GetModuleHandle(NULL);
hMouseHook = SetWindowsHookEx( WH_MOUSE_LL, mouseProc, hInstance, NULL );
hKeyHook = SetWindowsHookEx( WH_KEYBOARD_LL, LowLevelKeyboardProc, hInstance, NULL );
MSG message;
while (GetMessage(&message,NULL,0,0))
{
TranslateMessage( &message );
DispatchMessage( &message );
}
UnhookWindowsHookEx(hMouseHook);
return 0;
}
Note: I don't know if this is relevant, but I want to use the HID to play in a Chromium instance on a windows system.

When you register the hook with WH_MOUSE_LL, the possible values of wparam are: WM_LBUTTONDOWN, WM_LBUTTONUP, WM_MOUSEMOVE, WM_MOUSEWHEEL, WM_MOUSEHWHEEL, WM_RBUTTONDOWN, or WM_RBUTTONUP.
I'm expecting that once the WM_LBUTTONDOWN is issued, a corresponding WM_LBUTTONUP has to be issued to prevent the cursor from entering dragging state.
I don't have the device to test this but I would try the call below to prevent entering dragging state.
CallNextHookEx(hMouseHook, nCode, WM_LBUTTONUP, lParam);
or use mouse_event with MOUSEEVENTF_LEFTUP to inject the release of the left button.
I don't think that the raw input alternative is a good idea. I see it as a measure of last resort.

The touchpad is just a mouse like any other. It generates standard mouse events. Use a global WH_MOUSE hook via SetWindowsHookEx() to capture mouse events globally. To replay them, use mouse_event(). Alternatively, use WH_JOURNALRECORD and WH_JOURNALPLAYBACK hooks instead for capture and playback, respectively.

For mouse click and mouse move - when you handle the input from the HID use the SendInput method.
The click is easy, for the mouse move try to get the scaled drag coordinates and convert them to the current screen scale coordinates and also use the SendInput method.
Also you can track the displacement in x, y and make appropriate calibration to translate them to screen x, y

Related

My mouse movements are making the SendMessage autopot/autoheal to fail

I'm trying to make a game autopot/autoheal with SendMessage:
using_arrowslot = true;
// click potion
SendMessage(Window, WM_MOUSEMOVE, 0, MAKELPARAM(potx, poty));
SendMessage(Window, WM_RBUTTONDOWN, 0, MAKELPARAM(potx, poty));
SendMessage(Window, WM_RBUTTONUP, 0, MAKELPARAM(potx, poty));
// click player
SendMessage(Window, WM_MOUSEMOVE, 0, MAKELPARAM(playerx, playery));
SendMessage(Window, WM_LBUTTONDOWN, 0, MAKELPARAM(playerx, playery));
SendMessage(Window, WM_LBUTTONUP, 0, MAKELPARAM(playerx, playery));
start_manapot += std::chrono::seconds(seconds_to_cast);
using_arrowslot = false;
The problem is that those SendMessages will send clicks to wrong positions sometimes as I'm moving the mouse while playing.
So, what I've tested to make it accurate, is to take control of the mouse while the SendMessage is being processed.
The way I'm trying is hooking WndProc and try to "filter" by my params:
LRESULT __stdcall WndProc(const HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
if (ImGui_ImplWin32_WndProcHandler(hWnd, uMsg, wParam, lParam))
return true;
if (menuShow || (using_arrowslot && lParam != 29426537 && lParam != 18024234))
return 1;
return CallWindowProc(oWndProc, hWnd, uMsg, wParam, lParam);
}
I don't find any difference in results of running with the WndProc hook or without it. It's not accurate while using mouse ingame.
I'm not sure... what you guys do in this situations...
How can I make the SendMessage to work without being affected by my mouse or keyboard?

How to block mouse input from transparent window with Win32 API?

I have a main window in a process that is not owned by the program I'm creating. I'm using a Windows Hook to inject a DLL into this process for the purpose of adding a child window to this main window.
My end goal was to create a WS_EX_LAYERED window that allows me to create an internal colored border but allow the center portion to be transparent and allow mouse clicks through. This part works perfectly.
WNDCLASS wndClass = {};
wndClass.style = CS_HREDRAW | CS_VREDRAW;
wndClass.lpfnWndProc = OverlayProc;
wndClass.hInstance = g_TargetInstance;
wndClass.hbrBackground = (HBRUSH)CreateSolidBrush(RGB(0, 255, 255));
wndClass.lpszClassName = "OVERLAY";
RegisterClass(&wndClass);
g_Window = CreateWindowEx(WS_EX_LAYERED | WS_EX_TRANSPARENT, "OVERLAY", nullptr,
WS_CHILDWINDOW, rect.left, rect.top, rect.right+1, rect.bottom+1, data->hwnd, nullptr, g_TargetInstance, nullptr);
SetLayeredWindowAttributes(g_Window, RGB(0, 255, 255), 0, LWA_COLORKEY);
ShowWindow(g_Window, SW_SHOW);
UpdateWindow(g_Window);
The 2nd part to this is a I wanted to conditionally block all mouse input to the parent window. I couldn't do this with the transparent portion of the WS_EX_LAYERED window so I tried creating a 2nd transparent STATIC control as a child of the main window but this doesn't block mouse input either.
I'm also sending simulated mouse clicks to the parent window through calls to PostMessage, passing WM_LBUTTONDOWN and WM_LBUTTONUP. How could I block all mouse input to the parent window via a transparent window?
It appears this is not possible to do with a simple transparent window drawn over sibling controls. What I ended up doing was using SetWindowHookEx to add a WH_GETMESSAGE hook into the process from which I use to replace the main window's WndProc function and intercept mouse messages. I tag my simulated mouse messages with a specific value in the wParam argument so the proc will now it was simulated and removes that value, passing it along to the parent window.
If it does not detect my "tag" value in the click message, it will swallow the mouse message and not pass it along to the original WndProc function.
Injected WndProc replacement
LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData)
{
switch (uMsg)
{
case WM_LBUTTONDOWN:
wParam -= 11141008;
if (wParam != MK_LBUTTON && !g_Paused)
return 0;
break;
case WM_LBUTTONUP:
wParam -= 11141008;
if (wParam != 0 && !g_Paused)
return 0;
break;
case WM_MOUSEHOVER:
case WM_MOUSEMOVE:
if (!g_Paused)
return 0;
}
return DefSubclassProc(hWnd, uMsg, wParam, lParam);
}
Snippet from Windows Hook function
//...
switch (data->message)
{
case (WM_USER + 1):
{
g_Paused = FALSE;
//...
SetWindowSubclass(data->hwnd, WndProc, 1, 0);
break;
}
case (WM_USER + 2):
{
RemoveWindowSubclass(data->hwnd, WndProc, 1);
//...
break;
}
}
//...
The code inside the window hook function is used to subclass the main process window and inject my own WndProc function which in turn processes mouse input the way I want.
This is the code used to "simulate" mouse clicks without physically clicking in the window. Note the added value to wParam to identify this click as simulated and not generated by the user.
void Window::LeftClick(DWORD x, DWORD y, DWORD delayMillis)
{
LPARAM lparam = MAKELPARAM(x, y);
lock_guard<mutex> lock(this->m_ClickMutex);
PostMessage(this->m_Window, WM_LBUTTONDOWN, 11141008 + MK_LBUTTON, lparam);
this_thread::sleep_for(std::chrono::milliseconds(delayMillis));
PostMessage(this->m_Window, WM_LBUTTONUP, 11141008, lparam);
}
Also, just for the person in the comments who was ridiculing my choice of the word simulated and the added criticism for using PostMessage to simulate keyboard input, here is my keyboard input test method which (for my purposes) works flawlessly and very reliably
void GameWindow::KeyPress(UINT vkCode) const
{
UINT scanCode = MapVirtualKey(vkCode, MAPVK_VK_TO_VSC);
LPARAM lparam1 = MAKELPARAM(1, scanCode);
LPARAM lparam2 = MAKELPARAM(1, 0xC000 | scanCode);
PostMessage(this->m_Window, WM_KEYDOWN, vkCode, lparam1);
this_thread::sleep_for(chrono::milliseconds(25));
PostMessage(this->m_Window, WM_KEYUP, vkCode, lparam2);
}

Low level mouse hook - mouse button click vs hold

I'm using C++ and DirectD3D9 to draw a menu.
I wish to navigate the menu with the mouse.
I can get the mouse position, however, checking if the left button is clicked is proving tricky.
I am able to check if it is being held down, but not clicked.
bool LBUTTONDOWN = false;
LRESULT CALLBACK LowLevelMouseProc(int nCode, WPARAM wParam, LPARAM lParam) {
if (nCode == HC_ACTION && (wParam == WM_LBUTTONUP || wParam == WM_LBUTTONDOWN)) {
LBUTTONDOWN = wParam == WM_LBUTTONDOWN;
}
return CallNextHookEx(0, nCode, wParam, lParam);
}
How can I add a check to see if I clicked the left button?
You need to use a timing trick. Create a variable named something like 'nTime',
Set the zero for it when the LButton is up. Increase the variable value using a '+=' operator when the LButton is down and check the variable against a value something like that -
bool LBUTTONDOWN = false;
int nTime = 0;
LRESULT CALLBACK LowLevelMouseProc(int nCode, WPARAM wParam, LPARAM lParam)
{
if (nCode == HC_ACTION && (wParam == WM_LBUTTONUP || wParam == WM_LBUTTONDOWN))
{
LBUTTONDOWN = wParam == WM_LBUTTONDOWN;
if ( LBUTTONDOWN )
{
nTime += 1;
if ( nTime > 1000 /*( this value depends on you )*/ )
{
nTime = 0;
// Here is your hold event code.
}
}
else
nTime = 0;
}
return CallNextHookEx(0, nCode, wParam, lParam);
}
There is no DoubleClick message for LowLevelMouseProc. However, I suppose you can have a work around:
Record the time interval between LBUTTONDOWN and LBUTTONUP, then to check whether it is quick enough to be a click event. And because the mouse acts very fast, it is better to set a timer for the mouse capturing.
For the mouse capturing, you can still call LowLevelMouseProc. However, the DirectInput is more convenient for processing mouse movements.
In DirectX SDK samples, there is a DirectInput sample named "CustomFormat". It shows how to set up a timer to capture mouse input.
I hope this helps.

how to capture system-menu event in console application in windows?

It's easy to get system menu on console application (GetSystemMenu) and add some own entries (AppendMenu). But then these menu items are useless for the app. Is there any way to get into message stream that would identify what menu item was clicked ?
I've tried to hook to console window but without any result, I mean the WH_SYSMSGFILTER, all is compiling ok but there are no messages shown the hook function is not run by the system.
Next thing was ReadConsoleInput and this works partially, that is it shows mouse events on the system menu, but there is no information in MENU_EVENT_RECORD structure about what menu item was clicked.
These are my attempts all in one snippet, here the console should be flooded with messages, but only those from ReadConsoleInput appear, but these doesn't contain any useful information. No matter if user clicks on first or second added menu item there are only two codes shown 278 (0x116) WM_INITMENU and 287 (0x11F) WM_MENUSELECT, but there is no way I know to get to the wParam of WM_MENUSELECT message.
#include <windows.h>
#include <stdio.h>
HHOOK sysMsgFilterHook;
LRESULT CALLBACK SysMsgFilterCallback(int nCode, WPARAM wParam, LPARAM lParam) {
printf("%i\n", nCode);
return CallNextHookEx(NULL, nCode, wParam, lParam);
}
static LRESULT CALLBACK consoleWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
printf("%u\n", uMsg);
WNDPROC origProc = (WNDPROC) GetProp(hWnd, "origProc");
return CallWindowProc(origProc, hWnd, uMsg, wParam, lParam );
}
int main() {
SetLastError(0);
HWND console_hwnd = GetConsoleWindow();
HMENU console_hMenu = GetSystemMenu(console_hwnd, FALSE);
HINSTANCE console_hinstance = (HINSTANCE)GetWindowLong(console_hwnd, GWL_HINSTANCE);
DWORD console_processid = GetWindowThreadProcessId(console_hwnd, NULL);
HANDLE console_input_handle = GetStdHandle(STD_INPUT_HANDLE);
AppendMenu(console_hMenu, MF_STRING | MF_CHECKED, NULL, "test menu item");
AppendMenu(console_hMenu, MF_STRING | MF_CHECKED, NULL, "yet another menu item");
WNDPROC origProc = (WNDPROC)SetWindowLongPtr(console_hwnd, GWL_WNDPROC, (LONG_PTR)&consoleWndProc);
SetProp(console_hwnd, "origProc", (HANDLE)origProc);
sysMsgFilterHook = SetWindowsHookEx(
WH_SYSMSGFILTER,
(HOOKPROC)SysMsgFilterCallback,
console_hinstance,
console_processid
);
DWORD numEvents = 0;
INPUT_RECORD input;
while(ReadConsoleInput(console_input_handle, &input, 1, &numEvents)) {
//printf("input.EventType: %i\n", input.EventType);
if (input.EventType == MENU_EVENT) {
printf("input.Event.MenuEvent.dwCommandId %i\n", input.Event.MenuEvent.dwCommandId);
}
}
//printf("GetLastError: %lu\n", GetLastError());
UnhookWindowsHookEx(sysMsgFilterHook);
system("pause");
return 0;
}
I've succeeded with creating hook for mouse events, that is WH_MOUSE_LL. But all other hooks do not work.
What I intend to accomplish is to get some sort of WM_MENUCOMMAND message and then get rest with GetMenuItemInfo.
I've heard that the hooking procedure should be in another dll, but how to do that ? are there any working snippets ?

getting the 'name of the application' along with the key taps

To record the key taps I install the hook as :
BOOL WINAPI installHook(HINSTANCE hinstDLL, DWORD fwdReason, LPVOID lpvReserved) {
handleKeyboardHook = SetWindowsHookEx(WH_KEYBOARD_LL, LowLevelKeyboardProc, hinstDLL, 0);
MSG msg;
while(GetMessage(&msg, NULL, 0, 0)){
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}
static LRESULT CALLBACK LowLevelKeyboardProc(int nCode, WPARAM wParam, LPARAM lParam) {
// write here
}
Is there any way I can know the application name where the keys are currently being tapped ? Like I have opened notepad an writing something , can I get the name of the application which is notepad along with the key taps ? Same goes for some other application like mozilla firefox.
The inside of your hook should look like so:
static LRESULT CALLBACK LowLevelKeyboardProc(int nCode, WPARAM wParam, LPARAM lParam)
{
// if it is not a keydown event, continue the chain
if(HC_ACTION != nCode || WM_KEYDOWN != wParam)
return CallNextHookEx(0, nCode, wParam, lParam);
const KBDLLHOOKSTRUCT* messageInfo = reinterpret_cast<const KBDLLHOOKSTRUCT*>(lParam);
// add more code here...
// tell Windows we processed the hook
return 1;
}
messageinfo.vkCode will contain the key codes your looking for. The official list of these codes is at: http://msdn.microsoft.com/en-us/library/windows/desktop/dd375731%28v=vs.85%29.aspx
Keys usually get typed into the foreground window (although sometimes strange window layouts happens). You can get the title of the foreground window like this:
TCHAR title[100]; // increase size for longer titles
GetWindowText(GetForegroundWindow(), title, 100);
If you want to get the name of the program instead, use:
TCHAR title[100]; // increase size for longer program names
GetWindowModuleFileName(GetForegroundWindow(), title, 100);
And, remember to add error checking and check the documentation.