I'm trying to disable windows keys for a window that uses RawInput to process keyboard events. The usual way to do this is to install a low-level keyboard hook and filter out windows key events there. In order for it to work with RawInput, I have to initialize the keyboard device with RIDEV_NOHOTKEYS. However, when I do that, if I then Alt+Tab from the app, for some reason Windows 10 displays the classic Alt+Tab thing:
I'm not filtering out Alt or Tab events in the low-level keyboard hook, and this also happens if I don't install a low-level keyboard hook at all, just initializing the keyboard device with RIDEV_NOHOTKEYS does it. I tried returning 0 for WM_INPUT messages, and I tried calling the default window proc, nothing seems to be helping... Has anyone had this issue before?
Add a low level hook (WH_KEYBOARD_LL) can prevent Alt key message to pass to other windows. Refer to "LowLevelKeyboardProc callback function".
WH_KEYBOARD_LL hook can be set only with global scope.
// Register hook
hinstDLL = LoadLibrary(TEXT("sysmsg.dll"));
hkprcSysMsg = (SYSMESSAGEPROC)GetProcAddress(hinstDLL, "SysMessageProc");
HHOOK hook = SetWindowsHookEx(WH_KEYBOARD_LL, (HOOKPROC)hkprcSysMsg, hinstDLL, 0);
Hook callback function in DLL:
__declspec(dllexport)
LRESULT __cdecl SysMessageProc(int nCode, WPARAM wParam, LPARAM lParam)
{
if (nCode < 0) // do not process message
return CallNextHookEx(NULL, nCode,
wParam, lParam);
if (wParam == WM_SYSKEYDOWN)
{
if(((tagKBDLLHOOKSTRUCT*)lParam)->vkCode == VK_LMENU || ((tagKBDLLHOOKSTRUCT*)lParam)->vkCode == VK_RMENU)
return 1;
}
return CallNextHookEx(NULL, nCode, wParam, lParam);
}
More reference: "Using Hooks" "Keyboard Input" "WM_SYSKEYDOWN message" "KBDLLHOOKSTRUCT structure" "Virtual-Key Codes"
Note
Hooks tend to slow down the system because they increase the amount of
processing the system must perform for each message. You should
install a hook only when necessary, and remove it as soon as possible.
You should use global hooks only for debugging purposes; otherwise,
you should avoid them. Global hooks hurt system performance and cause
conflicts with other applications that implement the same type of
global hook.
Related
I have a window which serves as an overlay, and only has some part of it non-transparent. The window has extended styles
WS_EX_TOOLWINDOW | WS_EX_TOPMOST | WS_EX_TRANSPARENT | WS_EX_LAYERED
And the transparency is set with:
SetLayeredWindowAttributes(hwnd, RGB(255, 255, 255), 0, LWA_COLORKEY);
I do want to read the mouse events to implement the interactive part of the overlay.
So far i tried catching messages like
WM_MOUSEMOVE,
WM_KEYDOWN,
WM_NCLBUTTONDOWN,
in my WNDPROC and there they didn't fire. I assumed that was due to some of the window extended styles, and by removing one at a time i found out that it was layered window attribute which caused it. Sadly my app does depend on this attribute for its transparency.
Then i tried registering a windows hook for that very process and thread to intercept the mouse events. I don't know the internals of hooks at all - but i thought they get access to the messages before they enter the application's queue hence i hoped i could read them before whatever interferes passes them on. That didn't work sadly.
I registered the hook like so:
app_state.hhook = SetWindowsHookExW(WH_MOUSE,
Some(Self::HOOKPROC),
GetModuleHandleW(null_mut()),
GetCurrentThreadId();
And the actual HOOKPROC was defined like this:
pub unsafe extern "system" fn HOOKPROC(ncode: c_int, wparam: WPARAM, lparam: LPARAM) -> LRESULT {
println!("fired!");
CallNextHookEx(null_mut(), ncode, wparam, lparam)
}
Sadly this didn't output anything to STDOUT, but I do think that hook was registered as unhook function didn't return 0.
My next idea was to put the hook in the process which manages the previous window. However the below doesn't work.
app_state.hhook = SetWindowsHookExW(WH_MOUSE,
Some(Self::HOOKPROC),
GetModuleHandleW(null_mut()),
GetWindowThreadProcessId(
GetWindow(hwnd, GW_HWNDPREV), null_mut())
);
I think that it's due to the fact that i need to place the hook in a separate dll but event if it does work - this solution seem to be very dirty and will probably work in very few cases without requiring elevated privileges. What can i do to achieve the desired via accepted and cohesive code?
Just get rid of the WS_EX_TRANSPARENT style and use WS_EX_LAYERED by itself, and let the OS handle mouse input normally (no hook needed). Fully transparent pixels will fall-through as expected, and the window will receive input messages on non-transparent pixels.
I'm a bit confused by the MSDN page for WM_PRINTCLIENT and related functionality in a few ways:
What value should I return from my window procedure? The documentation is missing a "Return value" section entirely. (It is also missing in the Visual Studio 2012 offline documentation disc's version of the page.) Raymond Chen's original scratch program returns zero; is this the preferred option?
The summary and Remarks section for WM_PRINTCLIENT indicates that I should only draw the client area, but the LPARAM lists all the possible WM_PRINT flags — so what should I do, ignore it and unconditionally draw just the client area or draw everything requested? (My intention with this question is not to second-guess the documentation; I'm just looking to implement this message correctly.)
I want to, as a convenience/kindness, provide the WM_PAINT with DC in wParam functionality mentioned in the WM_PAINT documentation as an option as well. How should I interpret LPARAM in this case? Or is there a reason I shouldn't provide this alternative route? (Corollary: if LPARAM is to be ignored, should I draw the entire client area unconditionally?)
Thanks.
Update Rephrasing the third part:
The documentation for WM_PAINT includes the paragraph
For some common controls, the default WM_PAINT message processing checks the wParam parameter. If wParam is non-NULL, the control assumes that the value is an HDC and paints using that device context.
I would like to provide this behavior in my control in addition to WM_PRINTCLIENT for completeness's sake. Is there a reason I should NOT do so? And if doing so wouldn't hurt, how should I interpret the lParam, and should I draw the entire client rect?
What value should I return from my window procedure?
You return 0 to indicate that the message was handled. Do not call DefWindowProc().
but the LPARAM lists all the possible WM_PRINT flags
That was a bit sloppy, a copy/paste fumble from the WM_PRINT article. The only flags you should test are PRF_ERASEBKGND, but only if you draw method requires having the background painted, and PRF_CLIENT, which will always be set in common usage of the message.
How should I interpret LPARAM in this case?
Hard to decode that question, WM_PAINT doesn't use the lparam argument. But yes, you want a common function that implements the painting so you can call it both from your WM_PAINT and your WM_PRINTCLIENT message handlers. Boilerplate code in your window procedure ought to look like:
case WM_PAINT: {
HDC hdc = BeginPaint(hWnd, &ps);
Draw(hdc);
EndPaint(hWnd, &ps);
break;
}
case WM_PRINTCLIENT: {
HDC hdc = (HDC)wParam;
DWORD flags = (DWORD)lParam;
if (flags & PRF_ERASEBKGND) SendMessage(hWnd, WM_ERASEBKGND, (WPARAM)hdc, NULL);
if (flags & PRF_CLIENT) Draw(hdc);
break;
}
Where void Draw(HDC hdc) is your common paint function.
I am working on Windows GUI Application.There are 20 Push Buttons on my Window. Against each button click, I want to open up a new window for displaying some information. It can be anything which can display some information but since I am new to all this and I didn’t want to try anything complicated, I decided to go with the idea of creating a pop up window against each button click.
Now the problem that I am facing is that since there are 20 different windows, do I need to create 20 different window callback functions? Though there is only one control in the pop up window i.e. a Close sign, but even for that I need to have a CALLBACK function.
I had been trying with this but now this idea looks senseless. Is there any other option in which I can achieve the desired functionality?
Waiting for help.
If all of the windows should behave the same way, then you can create a single window procedure (what you're calling the CALLBACK function) that is shared by all of the pop-up windows.
Window procedures do not have to be unique to individual windows, but if multiple windows share the same window procedure, they will react identically to all messages that they receive.
For example:
// Message procedure for all pop-up windows.
LRESULT CALLBACK MyPopupWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch (msg)
{
// handle any messages you want here in order to
// customize the behavior of your pop-up window
}
return DefWindowProc(hwnd, msg, wParam, lParam);
}
You specify a pointer to the MyPopupWndProc function when you register the window class for your pop-up windows (using the RegisterClassEx function), and then you pass the name of the registered window class when you call CreateWindowEx to create/display a pop-up window whenever one of the buttons on your main window is clicked.
Of course, if you're just wanting something simple for testing purposes, remember that you can always call the MessageBox function! No window procedures or class registration required.
On Win32, I wonder how to detect whether Left Shift or Right ALT is pressed using Perl, Python, or Ruby (or even in C)?
Not just for the current window, but the global environment overall. Example: when I am typing a document, I can press Right ALT to start the music player written in Ruby, and then press Right ALT again and it can pause or stop the program. thanks.
You need to setup a Low Level Keyboard Hook. You do this by calling SetWindowsHookEx with a LowLevelKeyboardProc, and then watch for the appropriate virtual key code.
There are key codes for left and right shift and alt keys.
If you want to know the current state of the keys right now, you can use GetAsyncKeyState() with an argument of VK_LSHIFT or VK_RMENU for left shift and right alt respectively. Make sure to test the most significant bit of the result, since the result contains more than one bit of information, e.g.
if(GetAsyncKeyState(VK_LSHIFT) & 0x8000)
; // left shift is currently down
If you instead want to be notified of keypresses instead of polling them asynchronously, you should listen for the WM_KEYDOWN window notification. Put something like this in your window's message handler:
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
{
switch(msg)
{
...
case WM_KEYDOWN:
if(wparam == VK_LSHIFT)
; // left shift was pressed
// etc.
break;
}
}
You'll also have to handle the WM_KEYUP message to know when keys are released.
I believe you can also get at the status of a virtual key through GetKeyState e.g. GetKeyState(VK_RSHIFT). Though using a hook as described by Reed Copsey is probably better suited to your purposes rather than polling this function.
Instead of WM_KEYDOWN and WM_KEYUP, use WM_SYSKEYDOWN and WM_SYSKEYUP; then you can check if it's VK_LSHIFT or VK_MENU etc and it will catch those events as they occur.
CoInitialize(NULL) creates an STA by creating a hidden window. How to get an HWND handle for this window?
Function EnumThreadWindows does not work, in an example I tried:
...
CoInitialize(NULL);
EnumThreadWindows(GetCurrentThreadId(), EnumThreadWndProc, 0);
...
BOOL CALLBACK EnumThreadWndProc(HWND hwnd, LPARAM lParam)
{
m_hwnd = hwnd;
return FALSE;
}
Nothing ever enters the EnumThreadWndProc.
Any ideas?
This hidden window is Message-Only Window, It is not visible, has no z-order, cannot be enumerated, and does not receive broadcast messages. The window simply dispatches messages.
To find message-only windows, specify HWND_MESSAGE in the hwndParent parameter of the FindWindowEx function. In addition, FindWindowEx searches message-only windows as well as top-level windows if both the hwndParent and hwndChildAfter parameters are NULL.
Source:
MSDN
Btw, I would be VERY careful here - you really shouldn't be sending window messages to windows you don't own. Your code is highly likely to break in a future version of Windows.