I have a WPF window with disabled resize capability (WindowStyle=None, ResizeMode = CanMinimize).
It works fine, except one situation. If some application (i.e AutoHotKey) calls a WIN API function ShowWindow on my window with SW_MAXIMIZE option, then my window repositions to (0, 0) coordinate on the desktop with no size change and user is not able to move it over the screen further.
How can I disable this behavior? I want the window to ignore this call on my window.
I have tried reacting to WM_WINDOWPOSCHANGING event, but this works only until user minimizes the window. After it is minimized and restored it becomes repositioned to (0, 0) coordinate again.
private IntPtr ProcessMessage(IntPtr windowHandle, int msg, IntPtr wideParam, IntPtr leftParam, ref bool handled)
{
Msg windowsMessage = (Msg)msg;
switch (windowsMessage)
{
case Msg.WM_WINDOWPOSCHANGING:
{
WindowPos windowPos = (WindowPos)Marshal.PtrToStructure(leftParam, typeof(WindowPos));
if (IsNoClientAction(windowPos) && !IsMinimizing(windowPos) && window.WindowState == WindowState.Normal)
{
windowPos.Flags = SetWindowPosFlags.SWP_NOSIZE | SetWindowPosFlags.SWP_NOMOVE;
handled = true;
Marshal.StructureToPtr(windowPos, leftParam, true);
}
break;
}
}
return IntPtr.Zero;
}
private static bool IsNoClientAction(WindowPos windowPos)
{
return (windowPos.Flags & SetWindowPosFlags.SWP_NOCLIENTSIZE) != 0 || (windowPos.Flags & SetWindowPosFlags.SWP_NOCLIENTMOVE) != 0;
}
private static bool IsMinimizing(WindowPos windowPos)
{
return windowPos.Left == -32000 && windowPos.Top == -32000;
}
I have analyzed what user32.dll does to the window and figured out solution based on that. Before sending any messages to Wndproc it updates GWL_STYLE flags of the window enabling WS_MAXIMIZE for it. For this reason window state becomes corrupted and further behavior can hardly be handled by processing window messages only.
To disable window reaction on ShowWindow with SW_MAXIMIZE option I am setting this flag back when WM_WINDOWPOSCHANGING is processed:
private IntPtr ProcessMessage(IntPtr windowHandle, int msg, IntPtr wideParam, IntPtr leftParam, ref bool handled)
{
Msg windowsMessage = (Msg)msg;
switch (windowsMessage)
{
case Msg.WM_WINDOWPOSCHANGING:
{
WindowPos windowPos = (WindowPos)Marshal.PtrToStructure(leftParam, typeof(WindowPos));
if (IsNoClientAction(windowPos))
{
WindowStyles styles = (WindowStyles)WindowsAPI.GetWindowLongPtr(windowHandle, GWL.GWL_STYLE);
if ((styles & WindowStyles.WS_MAXIMIZE) != 0)
{
windowPos.Flags |= SetWindowPosFlags.SWP_NOSIZE | SetWindowPosFlags.SWP_NOMOVE;
WindowsAPI.SetWindowLongPtr(new HandleRef(this, windowHandle), GWL.GWL_STYLE, (IntPtr)(long)(styles ^ WindowStyles.WS_MAXIMIZE));
handled = true;
Marshal.StructureToPtr(windowPos, leftParam, true);
}
}
break;
}
}
return IntPtr.Zero;
}
private static bool IsNoClientAction(WindowPos windowPos)
{
return (windowPos.Flags & SetWindowPosFlags.SWP_NOCLIENTSIZE) != 0 || (windowPos.Flags & SetWindowPosFlags.SWP_NOCLIENTMOVE) != 0;
}
Related
I've made it so that when I hit CTRL+Capslock a WPF window shows. How would I retrieve mouse coordinates to be able to make the window pop up right next to the mouse no matter where my mouse is currently at.
So I hit CTRL+Capslock it retrieves cursor coordinates and positions window next to cursor and shows it at the same time.
I have been unable to find anything that actually works. - Thank you guys in advance. :)
private IntPtr HwndHook(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
{
const int WM_HOTKEY = 0x0312;
switch (msg)
{
case WM_HOTKEY:
switch (wParam.ToInt32())
{
case HOTKEY_ID:
int vkey = (((int)lParam >> 16) & 0xFFFF);
if (vkey == VK_CAPITAL)
{
if (Application.Current.MainWindow.WindowState == WindowState.Minimized)
{
//Application.Current.MainWindow.Left = point
//Application.Current.MainWindow.Top =
Application.Current.MainWindow.WindowState = WindowState.Normal;
}
else
{
Application.Current.MainWindow.WindowState = WindowState.Minimized;
}
}
handled = true;
break;
}
break;
}
return IntPtr.Zero;
}
If you can use P/Invoke, you can use GetCursorPos:
[DllImport("user32.dll")]
static extern bool GetCursorPos(ref Point lpPoint);
Usage:
Point cursorCoords = new();
GetCursorPos(ref cursorCoords);
// cursorCoords now holds the screen coordinates of the cursor
...with Point being a sequentially laid out structure that contains an X and a Y coordinate. You can find such a structure in the System.Drawing namespace.
Anybody knows how can disable keyboard globally developing hooks in C#?
I have a source code that implements a hook to disable the keyboard in the same application but if I execute it and the keyboard was working in an text editor don't work it (I can keep writing) in Windows 7. I would like capture/disable the keyboard globally (for all applications that are running). My intention is to lock it completely for Windows 7.
This is my hook code:
globalKeyboardHook gkh = new globalKeyboardHook();
/// <summary>
/// Installs the global hook
/// </summary>
public void hook() {
IntPtr hInstance = LoadLibrary("User32");
hhook = SetWindowsHookEx(WH_KEYBOARD_LL, hookProc, hInstance, 0);
}
public int hookProc(int code, int wParam, ref keyboardHookStruct lParam) {
//indicates if any of underlaing events set e.Handled flag
bool handled = false;
IntPtr lFakeParam = new IntPtr(lParam.vkCode);
if ((code >= 0) && (KeyDown != null || KeyUp != null || wParam == WM_SYSKEYDOWN || wParam == WM_SYSKEYUP))
{
//read structure KeyboardHookStruct at lParam
keyboardHookStruct MyKeyboardHookStruct = (keyboardHookStruct)Marshal.PtrToStructure(lFakeParam, typeof(keyboardHookStruct));
Keys keyData = (Keys)MyKeyboardHookStruct.vkCode;
KeyEventArgs e = new KeyEventArgs(keyData);
log.Debug("cached wParam = [" + wParam + "] vkCode = [" + MyKeyboardHookStruct.vkCode + "] flags = [" + MyKeyboardHookStruct.flags + "]");
if (MyKeyboardHookStruct.vkCode == 144)
{
// NUMLOCK
handled = false;
}
KeyDown(this, e);
}
//if event handled in application do not handoff to other listeners
if (handled)
{
SendKeys.Send("{NUMLOCK}");
SendKeys.Send("{NUMLOCK}");
return 1;
//return CallNextHookEx(hKeyboardHook, nCode, wParam, lFakeParam);
}
else
{
return CallNextHookEx(hhook, code, wParam, ref lParam);
}
}
Thanks in advance!
some days ago, I got my Microsoft Arc Touch Mouse Surface Edition. Unfortunately, it doesn't have Forward/Back-Buttons (it performs only Page-Up/Page-Down).
So, I've written a little program, that catches the press of the Page_Up/Page_Down Keys and sends instead the Browser-Back/-Forward Button.
On my PC (Win 8.1 Pro) this works quite well. However, on my Surface Pro 2 (for which the program primarly was written) it won't send the Browser_Back-/Forward-Buttons.
For every other key the program seems to work (like Space, letters, numbers).
Here the code for sending Keycodes:
public static uint send(short keyCode) {
INPUT structure = new INPUT();
structure.type = (int)InputType.INPUT_KEYBOARD;
structure.ki.wVk = keyCode;
structure.ki.dwFlags = (int)KEYEVENTF.KEYDOWN;
structure.ki.dwExtraInfo = GetMessageExtraInfo();
INPUT input2 = new INPUT();
structure.type = (int)InputType.INPUT_KEYBOARD;
structure.ki.wVk = keyCode;
input2.mi.dwFlags = (int)KEYEVENTF.KEYUP;
input2.ki.dwExtraInfo = GetMessageExtraInfo();
INPUT[] pInputs = new INPUT[] { structure, input2 };
return SendInput(2, pInputs, Marshal.SizeOf(structure));
}
And here the KeyboardHook:
public static int KeyHookProc(int nCode, IntPtr wParam, IntPtr lParam) {
KeyHookStruct myKeyHookStruct =
(KeyHookStruct)Marshal.PtrToStructure(lParam, typeof(KeyHookStruct));
if (nCode < 0) {
return CallNextHookEx(hHook, nCode, wParam, lParam);
} else {
if (wParam == (IntPtr)0x0100) {
int keyCode = myKeyHookStruct.vkCode;
if (keyCode == 33) {
Input.send(0xA7);
} else if (keyCode == 34) {
Input.send(0xA6);
} else {
return CallNextHookEx(hHook, nCode, wParam, lParam);
}
}
return 1;
}
}
So, if the Page-Down/page-Up button on my keyboard is pressed, the send()-Method is called.
0xA6 and 0xA7 are the Keycodes for Browser_Back and Browser_Forward.
On my Surface, the Page-Up/Page-Down buttons are recognized correctly. The send()-Method is also called, but it won'T send the correct Keycodes. According to Spy++, send() isn't sending anything if the Keycode is 0xA6 or 0xA7 (on my PC it works).
Where is the problem with the Surface Pro 2? What could I do, that it works, or how could I determine why it isn't working?
The code you posted is wrong, as you never set type for input2 (the code use structure.type)
EDIT:
From MSDN docs for SendInput:
This function fails when it is blocked by UIPI. Note that neither
GetLastError nor the return value will indicate the failure was caused
by UIPI blocking.
This function is subject to UIPI. Applications are permitted to inject
input only into applications that are at an equal or lesser integrity
level.
You also should remove the call to GetMessageExtraInfo
New Edit:
I don't like the logic of your KeyHookProc function: if the message is NOT WM_KEYDOWN (0x0100), then you return 1...
I would go for:
if (wParam != (IntPtr)0x0100) {
return CallNextHookEx(hHook, nCode, wParam, lParam);
} else {
int keyCode = myKeyHookStruct.vkCode;
if (keyCode == 33) {
Input.send(0xA7);
} else if (keyCode == 34) {
Input.send(0xA6);
} else {
return CallNextHookEx(hHook, nCode, wParam, lParam);
}
return 1;
}
My main goal is to implement a proper message loop purely with P/Invoke calls that is able to handle USB HID events. Definitely its functionality should be identical with the following code that works well in Windows Forms. This NativeWindow descendant receives the events:
public class Win32EventHandler : NativeWindow
{
public const int WM_DEVICECHANGE = 0x0219;
public Win32EventHandler()
{
this.CreateHandle(new CreateParams());
}
protected override void OnHandleChange()
{
base.OnHandleChange();
IntPtr handle = UsbHelper.RegisterForUsbEvents(this.Handle);
}
protected override void WndProc(ref Message m)
{
if (m.Msg == WM_DEVICECHANGE)
{
// Handle event
}
base.WndProc(ref m);
}
}
... powered by this event loop:
Win32EventHandler handler = new Win32EventHandler();
var context = new ApplicationContext();
Application.Run(context);
// Other thread calls:
// context.ExitThread()
I found out that implementing the event loop is rather easy:
while (true)
{
res = Win32.GetMessage(out msg, IntPtr.Zero, 0, 0);
if (res == 0)
{
break;
}
Win32.TranslateMessage(ref msg);
Win32.DispatchMessage(ref msg);
if (msg.message == WM_DEVICECHANGE)
{
// Handle event
}
}
But I have no idea how the underlying Window object should be created. The implementation of the NativeWindow class seems too complex for me.
This is my solution at the moment:
public void CustomLoop()
{
string clsName = "Class";
string wndName = "Window";
Win32.WNDCLASSEX wndClassEx = new Win32.WNDCLASSEX();
wndClassEx.cbSize = (uint)Marshal.SizeOf(wndClassEx);
wndClassEx.lpszClassName = clsName;
wndClassEx.lpfnWndProc = WndProc;
Win32.RegisterClassEx(ref wndClassEx);
IntPtr windowHandle = Win32.CreateWindowEx(0, clsName, wndName, 0, 0, 0, 0, 0, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero);
IntPtr usbEventHandle = UsbHelper.RegisterForUsbEvents(windowHandle);
Win32.MSG msg;
sbyte res = 0;
while (true)
{
res = Win32.GetMessage(out msg, IntPtr.Zero, 0, 0);
if (res == 0)
{
break;
}
if (msg.message == WM.DEVICECHANGE)
{
// Handle event (does not fire)
}
else
{
Win32.TranslateMessage(ref msg);
Win32.DispatchMessage(ref msg);
}
}
Win32.DestroyWindow(windowHandle);
Win32.UnregisterClass(clsName, IntPtr.Zero);
}
[AllowReversePInvokeCalls]
private IntPtr WndProc(IntPtr hWnd, WM msg, IntPtr wParam, IntPtr lParam)
{
switch (msg)
{
case WM.DEVICECHANGE:
// Handle event (fires)
break;
default:
return Win32.DefWindowProc(hWnd, msg, wParam, lParam);
}
return IntPtr.Zero;
}
That's an very under-powered event loop. Consider using something like MsgWaitForMultipleObjectsEx instead of GetMessage.
Anyway, creating a window requires you to first register a window class (RegisterClassEx) and then create the window (CreateWindow). Neither one is particularly difficult. And instead of using base.WndProc(), you'll need to call DefWindowProc.
Trying to handle all messages directly inside the message loop is going to be overly difficult, that's why window procedures were created. And don't call TranslateMessage or DispatchMessage for any message you choose to process directly.
You may want to check out how this guy detect USB devices: A USB Library to Detect USB Devices
I wish to write a small tool that will capture a global event when the user presses the Windows button and scrolls the mousewheel up or down. When such an event is captured, I wish to redirect said output to a virtual keystroke combination of Win-+ or Win-- (plus/minus). Can this be done?
If the windows key is reserved, ctrl-alt or such would do.
Since it uses the windows key, the key can be captured globally using a hotkey binding. RegisterHotKey at msdn.
Edit: It seems the mousewheel events are not treated as keys as I assumed and there is no way to make a global hotkey for them.
You will have to make a global window message hook and trap the WM_MOUSEWHEEL message. But you may have to do that in C/C++. A C dll to accomplish this is below, you can call Hook and Unhook from C# to enable and disable the function.
WARNING: I have not tested this code and is provided as a demonstration only.
#include <windows.h>
HINSTANCE myInstance;
HHOOK thehook = 0;
BOOL isWinKeyDown = FALSE;
extern "C" LRESULT __declspec(dllexport)__stdcall CALLBACK HookHandler(int nCode, WPARAM wParam, LPARAM lParam) {
if (nCode == WM_KEYDOWN && (wParam == VK_LWIN || wParam == VK_RWIN))
isWinKeyDown = TRUE;
else if (nCode == WM_KEYUP && (wParam == VK_LWIN || wParam == VK_RWIN))
isWinKeyDown = FALSE;
else if (nCode == WM_MOUSEHWHEEL && isWinKeyDown) {
if (HIWORD(wParam) > 0) { //mousewheel up
CallNextHookEx(thehook, WM_KEYDOWN, VK_ADD, 0);
CallNextHookEx(thehook, WM_KEYUP, VK_ADD, 0);
} else { //mousewheel down
CallNextHookEx(thehook, WM_KEYDOWN, VK_SUBTRACT, 0);
CallNextHookEx(thehook, WM_KEYUP, VK_SUBTRACT, 0);
}
return 0;
}
return CallNextHookEx(thehook, nCode, wParam, lParam);
}
BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD fwdReason, LPVOID lpvReserved) {
switch(fwdReason)
{
case DLL_PROCESS_ATTACH: {
DisableThreadLibraryCalls(hInstance);
myInstance = hInstance;
} break;
case DLL_THREAD_ATTACH:
break;
case DLL_PROCESS_DETACH:
break;
case DLL_THREAD_DETACH:
break;
}
return(TRUE); // The initialization was successful, a FALSE will abort
// the DLL attach
}
extern "C" void __declspec(dllexport) Hook() {
if (!thehook)
thehook = SetWindowsHookEx(WH_CALLWNDPROC, &HookHandler, myInstance, 0);
}
extern "C" void __declspec(dllexport) UnHook() {
if (thehook)
UnhookWindowsHookEx(thehook);
thehook = 0;
}
It can definitely be done via global hooks, here is a great CodeProject example on how to do so.