I need to catch and cancel any drag-and-drop event, and instead trigger a normal click on the initial coordinates where the mouse was clicked.
This is to help a disabled person with loss of motor function. Whenever she clicks on something, she keeps the button pressed and moves, registering a drag-and-drop event instead of a click.
I already tried software solutions (SteadyMouse, X-Mouse Button Control) but to no avail. Behavior modification is no longer an option due to her dementia.
I'm a webdev so not very familiar with Windows programming but I'm willing to learn if it can help her. Thanks for any ideas.
I suggest that you can immediately return to the release message event when the user presses the left mouse button.
Using SendInput and mouse hook,
C++ code sample,
#include <Windows.h>
#include <iostream>
#include <thread>
using namespace std;
HHOOK MouseHook;
BOOL WINAPI HandlerRoutine(_In_ DWORD dwCtrlType)
{
if (dwCtrlType == CTRL_CLOSE_EVENT)
{
UnhookWindowsHookEx(MouseHook);
}
return 1;
}
LRESULT __stdcall MouseHookCallback(int nCode, WPARAM wParam, LPARAM lParam)
{
INPUT input{};
input.type = INPUT_MOUSE;
input.mi.dwFlags = MOUSEEVENTF_LEFTUP;
if (nCode >= 0)
{
switch (wParam)
{
case WM_LBUTTONDOWN:
{
SendInput(1, &input, sizeof(INPUT));
break;
}
}
}
return CallNextHookEx(MouseHook, nCode, wParam, lParam);
}
void SetHook()
{
if (!(MouseHook = SetWindowsHookEx(WH_MOUSE_LL, MouseHookCallback, NULL, 0)))
{
cout << "Failed to install MouseHook hook!" << endl;
}
}
int main()
{
SetConsoleCtrlHandler(HandlerRoutine, 1);
SetHook();
MSG msg;
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}
Updated:
Here is quick gif demo and I have updated part of the code.
Newly added code:
BOOL WINAPI HandlerRoutine(_In_ DWORD dwCtrlType)
{
if (dwCtrlType == CTRL_CLOSE_EVENT)
{
UnhookWindowsHookEx(MouseHook);
}
return 1;
}
This callback function will be called when you close the console window, and the function contains the unhook code.
Note: After installing the hook, you need to uninstall the hook if you not need it. If you don't uninstall the hook in time, it will cause mouse stuck.
With this app, drag events will be blocked because the mouse will receive a release event immediately after it is pressed.
Related
I took this example code from here that hooks a function to intercept keyboard events, and it works:
#include <Windows.h>
// variable to store the HANDLE to the hook. Don't declare it anywhere else then globally
// or you will get problems since every function uses this variable.
HHOOK _hook;
// This struct contains the data received by the hook callback. As you see in the callback function
// it contains the thing you will need: vkCode = virtual key code.
KBDLLHOOKSTRUCT kbdStruct;
// This is the callback function. Consider it the event that is raised when, in this case,
// a key is pressed.
LRESULT __stdcall HookCallback(int nCode, WPARAM wParam, LPARAM lParam)
{
if (nCode >= 0)
{
// the action is valid: HC_ACTION.
if (wParam == WM_KEYDOWN)
{
// lParam is the pointer to the struct containing the data needed, so cast and assign it to kdbStruct.
kbdStruct = *((KBDLLHOOKSTRUCT*)lParam);
// a key (non-system) is pressed.
if (kbdStruct.vkCode == VK_F1)
{
// F1 is pressed!
MessageBox(NULL, "F1 is pressed!", "key pressed", MB_ICONINFORMATION);
}
}
}
// call the next hook in the hook chain. This is nessecary or your hook chain will break and the hook stops
return CallNextHookEx(_hook, nCode, wParam, lParam);
}
void SetHook()
{
// Set the hook and set it to use the callback function above
// WH_KEYBOARD_LL means it will set a low level keyboard hook. More information about it at MSDN.
// The last 2 parameters are NULL, 0 because the callback function is in the same thread and window as the
// function that sets and releases the hook. If you create a hack you will not need the callback function
// in another place then your own code file anyway. Read more about it at MSDN.
if (!(_hook = SetWindowsHookEx(WH_KEYBOARD_LL, HookCallback, NULL, 0)))
{
MessageBox(NULL, "Failed to install hook!", "Error", MB_ICONERROR);
}
}
void ReleaseHook()
{
UnhookWindowsHookEx(_hook);
}
void main()
{
// Set the hook
SetHook();
// Don't mind this, it is a meaningless loop to keep a console application running.
// I used this to test the keyboard hook functionality. If you want to test it, keep it in ;)
MSG msg;
while (GetMessage(&msg, NULL, 0, 0))
{
}
}
I am trying to make the similar code works for WH_GETMESSAGE to intercept WH_CREATE and WH_DESTROY messages, but it didn't work:
#include "stdafx.h"
#include <windows.h>
#include <tchar.h>
#include <stdio.h>
#include <psapi.h>
#include <iostream>
HHOOK _hook;
LRESULT CALLBACK GetMsgProc(_In_ int nCode, _In_ WPARAM wParam, _In_ LPARAM lParam)
{
std::cout << "Enter hook\n";
if (nCode >= 0)
{
// the action is valid: HC_ACTION.
std::cout << "HC_ACtION\n";
if (wParam != PM_REMOVE) return NULL;
MSG m = *((MSG*)lParam);
std::cout << "Message received\n";
TCHAR Buffer[MAX_PATH];
if (GetModuleFileNameEx(m.hwnd, 0, Buffer, MAX_PATH))
{
// At this point, buffer contains the full path to the executable
MessageBox(NULL, Buffer, L"key pressed", MB_ICONINFORMATION);
}
else
{
// You better call GetLastError() here
}
//CloseHandle(Hand);
}
// call the next hook in the hook chain. This is nessecary or your hook chain will break and the hook stops
return CallNextHookEx(_hook, nCode, wParam, lParam);
}
void SetHook()
{
if (!(_hook = SetWindowsHookEx(WH_GETMESSAGE, GetMsgProc, NULL, 0)))
{
MessageBox(NULL, L"Failed to install hook!", L"Error", MB_ICONERROR);
}
}
void ReleaseHook()
{
UnhookWindowsHookEx(_hook);
}
void main()
{
// Set the hook
SetHook();
// Don't mind this, it is a meaningless loop to keep a console application running.
// I used this to test the keyboard hook functionality. If you want to test it, keep it in ;)
MSG msg;
while (GetMessage(&msg, NULL, 0, 0))
{
}
}
MSDN specifies to use the function GetMsgProc with a predefined signature, but I don't see it does anything.
I have set a SetWindowsHookEx on the Edit class of notepad, but I am not sure how to continue from here.
I wish to subclass the Edit class to my own procedure, then manipulate the text or just save it to a file, then it must be send back the notepad control/class.
There are easier ways to get the text from notepad, but I am trying to learn WINAPI and Subclassing so this is a good way for me to learn it.
My SetWindowsHookEx looks like this:
SetWindowsHookEx(WH_GETMESSAGE, GetMsgProc, g_hInstDll, npThreadId);
How do I use the hook type : WH_GETMESSAGE to get the text from the Edit class in notepad and transfer it to my GetMsgProc(I think) function?
Is it the right hook type at all?
Do I send it a message? If yes, how do I do that?
My code look like this:
dllHeader.h:
#ifdef DLLAPI
#else
#define DLLAPI extern "C" __declspec(dllimport)
#endif
DLLAPI bool hookNotepad();
dll.cpp:
#include "stdafx.h"
#include <windows.h>
#define DLLAPI extern "C" __declspec(dllexport)
#include "dllHeader.h"
// Forward references
LRESULT WINAPI GetMsgProc(int nCode, WPARAM wParam, LPARAM lParam);
// Global variables
HHOOK g_hHook = NULL; // Hook for Notepad 'EDIT' class
HINSTANCE g_hInstDll = NULL; // DllMain entry (DLL_PROCESS_ATTACH)
HWND npHWND = NULL; // Notepad handle
DWORD npThreadId = NULL; // Notepad thread ID
HWND npeHWND = NULL; // Notepad 'EDIT' class handle
BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
g_hInstDll = hModule;
break;
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
bool hookNotepad ()
{
npHWND = FindWindow(TEXT("Notepad"), NULL); // Finds Notepad
if (npHWND) //Notepad found
{
npeHWND = FindWindowEx(npHWND, NULL, L"Edit", NULL); // Finds the 'EDIT' class in notepad
npThreadId = GetWindowThreadProcessId(npeHWND, NULL); //Find ThreadID for Notepad 'EDIT' class
g_hHook = SetWindowsHookEx(WH_GETMESSAGE, GetMsgProc, g_hInstDll, npThreadId); //Set hook in Notepad 'EDIT' class
if (g_hHook) //if the hook is a succes then...
{
MessageBox(NULL,TEXT("Hook set in Notepad EDIT class!"), NULL, MB_OK);
// Now what? How to subclass the npeHWND (The 'EDIT' class of Notepad) to my own procedure?
}
else
{
MessageBox(NULL,TEXT("SetWindowsHookEx error!"), NULL, MB_OK); //If the hook fails.
}
}
return 0;
}
LRESULT CALLBACK GetMsgProc(int nCode, WPARAM wParam, LPARAM lParam)
{
if (nCode >= 0)
{
MessageBox(NULL,TEXT("This never get called. Why?"), NULL, MB_OK);
}
return(CallNextHookEx(g_hHook, nCode, wParam, lParam));
}
exe.cpp
#include <stdlib.h>
#include "stdafx.h"
#include <strsafe.h>
#include "C:\Users\Kristensen\Documents\Visual Studio 2012\Projects\dll\dll\dllHeader.h"
int WINAPI _tWinMain(HINSTANCE, HINSTANCE, LPTSTR, int)
{
hookNotepad();
return 0;
}
I am a bit a lost on how to proceed from here… Any hints? Links? Tips?
I have read the documentation on MSDN regarding the SetWindowsHookEx function – but I did not find a clear answer there.
WH_GETMESSAGE is called when the hooked thread calls GetMessage() or PeekMessage() to retrieve a message from its message queue, but not all messages go through the message queue, so you may have to use the WH_CALLWNDPROC/RET hooks as well, depending on what kind of messages you are trying to intercept.
Your global variables need to be stored in a block of shared memory or else they will only be accessible to the process that installs the hook, since a new copy of the DLL gets loaded when hooking other processes.
You cannot subclass an HWND that is owned by another process. You would have to inject code into that process and then that code can subclass locally as needed. SetWindowsHookEx() can be used to inject code into other processes, but CreateRemoteThread() may be better to use for that, depending on your needs.
How to select all text in edit control by pressing Ctrl+A?
I can catch Ctrl+A for parent window in WndProc.
But I don't know how to catch ctrl+a which are applied for edit control.
Also I tried to use accelerators, but again it applies only for parent window.
Thanks.
EDIT: 1-st the simplest method
This method Based on #phord's answers in this question:
win32 select all on edit ctrl (textbox)
while( (bRet = GetMessage( &msg, NULL, 0, 0 )) != 0)
{
if (bRet == -1)
{
// handle the error and possibly exit
}
else
{
if (msg.message == WM_KEYDOWN && msg.wParam == 'A' && GetKeyState(VK_CONTROL) < 0)
{
HWND hFocused = GetFocus();
wchar_t className[6];
GetClassName(hFocused, className, 6);
if (hFocused && !wcsicmp(className, L"edit"))
SendMessage(hFocused, EM_SETSEL, 0, -1);
}
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
EDIT: 2-nd method
Need to use CreateAcceleratorTable + TranslateAccelerator functions:
//global variables:
enum {ID_CTRL_A = 1};
HACCEL accel;
//main procedure
ACCEL ctrl_a;
ctrl_a.cmd = ID_CTRL_A; // Hotkey ID
ctrl_a.fVirt = FCONTROL | FVIRTKEY;
ctrl_a.key = 0x41; //'A' key
accel = CreateAcceleratorTable(&ctrl_a, 1); //we have only one hotkey
//How GetMessage loop looks
while( (bRet = GetMessage( &msg, NULL, 0, 0 )) != 0)
{
if (bRet == -1)
{
// handle the error and possibly exit
}
else
{
if (!TranslateAccelerator(hWnd, accel, &msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
}
//in WndProc we must add next cases
case WM_COMMAND:
{
if (LOWORD(wParam) == ID_CTRL_A && HIWORD(wParam) == 1)
{
//on which control there was pressed Ctrl+A
//there is no way of getting HWND through wParam and lParam
//so we get HWND which currently has focus.
HWND hFocused = GetFocus();
wchar_t className[6];
GetClassName(hFocused, className, 6);
if (hFocudsed && !wcsicmp(className, L"edit"))
SendMessage(hFocused, EM_SETSEL, 0, -1);
}
}
break;
case WM_DESTROY:
{
DestroyAcceleratorTable(accel);
PostQuitMessage(0);
}
break;
As you can see this is pretty simple.
No need to handle WM_KEYDOWN! I know that most examples here (and CodeProject and many other places) all say there is, but it does not cure the beep that results whenever a WM_CHAR arises that is not handled.
Instead, try this:
LRESULT CALLBACK Edit_Prc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam){
if(msg==WM_CHAR&&wParam==1){SendMessage(hwnd,EM_SETSEL,0,-1); return 1;}
else return CallWindowProc((void*)WPA,hwnd,msg,wParam,lParam);
}
Remember to subclass the EDIT control to this Edit_Prc() using WPA=SetWindowLong(...) where WPA is the window procedure address for CallWindowProc(...)
First change the WindowProc for the edit control:
if (!(pEditProc = (WNDPROC)SetWindowLong(hEdit, GWL_WNDPROC, (LONG)&EditProc)))
{
assert(false);
return false;
}
Then in the new window proc, process the ctrl+a:
LRESULT CALLBACK EditProc( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam )
{
if (msg == WM_KEYDOWN) {
if (GetKeyState(VK_CONTROL) & 0x8000 && wParam == 'A') {
SendMessage(hwnd, EM_SETSEL, 0, -1);
}
}
return CallWindowProc(pEditProc, hwnd, msg, wParam, lParam);
}
Good News!
It seems Edit Controls (not multiline) now support Ctrl + A natively on Win10.
My current Windows SDK version is 10.0.17763.0.
Only tested on simple GUI APPs created with pure Windows API.
MFC APPs should have the same result.
The test binary platform is x86, and OS is Win10 x64.
Noob proof version?
I have written my own version using an accelerator table aswell.
This cleans out the WinMain a bit, and I tried to make everything as n00b proof as possible (since I am one).
Also the enum is ommited, since it is not needed.
As stated I am only a beginner in using the winapi, so please by all means
correct me if I am wrong.
In "Resource.h" I define two ID's
One for the accelerator table we will be using,
and one for the selectall command we will be using.
Inside Resource.h:
#define IDR_ACCEL1 101
#define ID_SELECT_ALL 9003
Then inside of the resource file (in vs2017 this is PROJECTNAME.rc)
we define the accelerator table.
PROJECTNAME.rc:
IDR_ACCEL1 ACCELERATORS
{
0x41, ID_SELECT_ALL, VIRTKEY, CONTROL // ctrl-A
}
Description
0x41 is virtkey 'a'.
ID_SELECT_ALL (will be the ID of the command, this should be the ID we defined in the Resource.h file.
The VIRTKEY keyword indicated that the 0x41 should be interpreted as a virtual key.
CONTROL is the modifier needed to combine the a with (ctrl+a).
Then inside the WinMain function load the accelerator:
HACCEL hAccel = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDR_ACCEL1));
if (hAccel == NULL)
{
MessageBox(NULL, _T("Failed to load accelerator table!"),_T("Error"), MB_OK | MB_ICONEXCLAMATION);
return 0;
}
Note: after trying to define hAccel we do a check to see if a valid handle has be assigned.
While this is not needed, I believe it's better convention.
After this we add the TranslateAccelerator function to the message loop, so the command can be processed in the window procedure:
BOOL bRet;
while (bRet = GetMessage(&Msg, NULL, 0, 0) > 0)
{
if (bRet == -1)
{
// Error handling can be done here.
}
else if (!TranslateAccelerator(hwnd, hAccel, &Msg))
{
TranslateMessage(&Msg);
DispatchMessage(&Msg);
}
}
Then finally inside the Window procedure
We add the code as follows:
switch(msg)
{
case WM_COMMAND:
{
switch (LOWORD(wParam))
{
case ID_SELECT_ALL:
{
HWND hEdit;
hEdit = GetDlgItem(hwnd, IDC_MAIN_EDIT) // Define IDC_MAIN_EDIT with an integer value in "Resource.h".
}
break;
}
break;
}
}
Note: The message passed to WM_COMMAND is the ID we defined for the ctrl+a accel.
I hope this will help fellow n00bies.
I have looked at the Microsoft documentation but it says that there should be no difference.
Note that this is a virtual ListView, so I supply the state icon index in the code implementing the LVN_GETDISPINFO message, if the LVIF_STATE flag is set in LV_ITEM::mask.
Does anyone know of any subtle differences which may cause this difference in behavior?
Not posting any sample code in your question does not exactly help...
This code works for me:
#include <Windows.h>
#include <commctrl.h>
#pragma comment(lib, "comctl32.lib")
typedef struct {
LPTSTR text;
UINT icon;
UINT stateicon;
} MYITEM;
HWND g_hLV=NULL;
MYITEM g_myitems[2]={{"item1",0,0},{"item2",2,2}};
LRESULT CALLBACK WndProc(HWND hwnd,UINT msg,WPARAM wp,LPARAM lp)
{
switch(msg)
{
case WM_NOTIFY:
if (lp)
{
NMLVDISPINFO*pLVDI=(NMLVDISPINFO*)lp;
NMLISTVIEW*&pLV=(NMLISTVIEW*&)pLVDI;
switch(pLVDI->hdr.code)
{
case LVN_GETDISPINFO:
if (LVIF_TEXT&pLVDI->item.mask) pLVDI->item.pszText=g_myitems[pLVDI->item.iItem].text;
if (LVIF_IMAGE&pLVDI->item.mask) pLVDI->item.iImage=g_myitems[pLVDI->item.iItem].icon;
if (LVIF_STATE&pLVDI->item.mask)
{
pLVDI->item.state=INDEXTOSTATEIMAGEMASK(1+g_myitems[pLVDI->item.iItem].stateicon);
pLVDI->item.stateMask=pLVDI->item.state;
}
return 0;
}
}
break;
case WM_CREATE:
{
g_hLV=CreateWindowEx(WS_EX_CLIENTEDGE,WC_LISTVIEW,0,WS_VISIBLE|WS_CHILD|LVS_OWNERDATA|LVS_REPORT|LVS_SHAREIMAGELISTS,0,0,0,0,hwnd,0,0,0);
LVCOLUMN lvc={LVCF_TEXT|LVCF_WIDTH};
lvc.pszText="dummy";
lvc.cx=99;
ListView_InsertColumn(g_hLV,0,&lvc);
SHFILEINFO sfi;
HIMAGELIST hil=(HIMAGELIST)SHGetFileInfo(".\\",FILE_ATTRIBUTE_DIRECTORY,&sfi,0,SHGFI_SMALLICON|SHGFI_SYSICONINDEX|SHGFI_USEFILEATTRIBUTES);
ListView_SetImageList(g_hLV,hil,LVSIL_SMALL);
ListView_SetImageList(g_hLV,hil,LVSIL_STATE);
g_myitems[1].stateicon=g_myitems[1].icon=sfi.iIcon;//assuming the imagelist has icons is wrong, so set at least one of them to a valid index
ListView_SetCallbackMask(g_hLV,LVIS_STATEIMAGEMASK);
ListView_SetItemCount(g_hLV,2);
}
return 0;
case WM_SIZE:
SetWindowPos(g_hLV,0,0,0,LOWORD(lp),HIWORD(lp),SWP_NOZORDER|SWP_NOACTIVATE);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
}
return DefWindowProc(hwnd,msg,wp,lp);
}
int WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdLine,int nShowCmd)
{
InitCommonControls();
//This dialog subclassing is a ugly hack, but this is just sample code!
HWND hwnd=CreateWindowEx(0,WC_DIALOG,"LVTest",WS_OVERLAPPEDWINDOW,0,0,99,99,0,0,0,0);
SetWindowLongPtr(hwnd,GWLP_WNDPROC,(LONG_PTR)WndProc);
SendMessage(hwnd,WM_CREATE,0,0);
ShowWindow(hwnd,nShowCmd);
MSG msg;
while (GetMessage(&msg,0,0,0) > 0)
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}
I got this idea a long time ago when i saw an app do this for a game.
i want to catch certain keystrokes. Something like /s myCommand. I had ppl msg me and mess me up through msn so my first command would be something like killmsn. I looked up the resource on msdn and got this far. This doesnt work, why doesnt it? is it BC of sleep? how else should i do this, note i dont have a window and i want this to be a console app. my KeyboardProc is NEVER called
#include <windows.h>
#include <stdio.h>
HHOOK hook;
LRESULT CALLBACK KeyboardProc(int code, WPARAM wParam, LPARAM lParam)
{
printf("%c", wParam);
return CallNextHookEx(hook, code, wParam, lParam);
}
int main()
{
hook = SetWindowsHookEx(WH_KEYBOARD, KeyboardProc, GetModuleHandle(0), 0);
Sleep(10000);
UnhookWindowsHookEx(hook);
return 0;
}
Solution
//Sleep(10000);
MSG msg;
while(GetMessage(&msg, NULL, 0, 0) > 0)
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
UnhookWindowsHookEx(hook);