I need to ignore all right clicks within my application and Chromium Embedded Framework.
Now I had this working great on an old version which used the WebBrowser widget, but now after switching over to CEF browser, the KeyMessageFilter does not get the message when the CEF browser is in focus. The first related post seems to say that the CEF keeps hold of the event and does not pass it on to the application.
However, I don't understand the answer. It seems to be in Basic or something....
Here is my KeyMessageFilter code
public class KeyMessageFilter : IMessageFilter
{
private enum KeyMessages
{
WM_KEYFIRST = 0x100,
WM_KEYDOWN = 0x100,
WM_KEYUP = 0x101,
WM_CHAR = 0x102,
WM_SYSKEYDOWN = 0x0104,
WM_SYSKEYUP = 0x0105,
WM_SYSCHAR = 0x0106,
WM_MOUSEWHEEL = 0x20a
}
[DllImport("user32.dll")]
private static extern IntPtr GetParent(IntPtr hwnd);
// We check the events agains this control to only handle
// key event that happend inside this control.
Control _control;
public KeyMessageFilter()
{ }
public KeyMessageFilter(Control c)
{
_control = c;
}
public bool PreFilterMessage(ref Message m)
{
Console.WriteLine(m.Msg);
// Filter out WM_NCRBUTTONDOWN/UP/DBLCLK
if (m.Msg == 0xA4 || m.Msg == 0xA5 || m.Msg == 0xA6) return true;
// Filter out WM_RBUTTONDOWN/UP/DBLCLK
if (m.Msg == 0x204 || m.Msg == 0x205 || m.Msg == 0x206) return true;
if (m.Msg == (int)KeyMessages.WM_MOUSEWHEEL)
{
if (Control.ModifierKeys == Keys.Control)
{
return true;
}
}
if (m.Msg == (int)KeyMessages.WM_KEYDOWN)
{
if (_control != null)
{
IntPtr hwnd = m.HWnd;
IntPtr handle = _control.Handle;
while (hwnd != IntPtr.Zero && handle != hwnd)
{
hwnd = GetParent(hwnd);
}
if (hwnd == IntPtr.Zero) // Didn't found the window. We are not interested in the event.
return false;
}
Keys key = (Keys)m.WParam;
if (key.Equals(Keys.Tab))
{
return true;
}
if (Control.ModifierKeys == Keys.Control)
{
switch (key)
{
case Keys.Oemplus:
return true;
case Keys.OemMinus:
return true;
}
}
}
return false;
}
}
Related Posts
Ignoring keys in winAPi: Stack Overflow question Override mouse using Chromium embedded framework
Ignoring keys: Stack Overflow question How to detect the currently pressed key?
Okay here is how I did it.
I used a low level hook for the mouse in the Program.cs file.
I then used a Setting to say wether my App is focused or not this uses the Form.Activated / Deactivated events (other wise it would swallow all right clicks on the computer while the App is running, BAD EXPERIENCE).
Relevant Links:Global mouse event handler
Program.cs
private static LowLevelMouseProc _proc = HookCallback;
private static IntPtr _hookID = IntPtr.Zero;
Main(string[] args){
.......
_hookID = SetHook(_proc);
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new ContainerForm());
UnhookWindowsHookEx(_hookID);
}
private static IntPtr SetHook(LowLevelMouseProc proc)
{
using (Process curProcess = Process.GetCurrentProcess())
using (ProcessModule curModule = curProcess.MainModule)
{
return SetWindowsHookEx(WH_MOUSE_LL, proc,
GetModuleHandle(curModule.ModuleName), 0);
}
}
private delegate IntPtr LowLevelMouseProc(int nCode, IntPtr wParam, IntPtr lParam);
private static IntPtr HookCallback(
int nCode, IntPtr wParam, IntPtr lParam)
{
if (nCode >= 0 &&
(MouseMessages.WM_RBUTTONDOWN == (MouseMessages)wParam || MouseMessages.WM_RBUTTONUP == (MouseMessages)wParam))
{
//If the app has focuse swallow event
if (Properties.Settings.Default.AppFocus) {
return new IntPtr(-1);
}
else
{
return CallNextHookEx(_hookID, nCode, wParam, lParam);
}
}
return CallNextHookEx(_hookID, nCode, wParam, lParam);
}
private const int WH_MOUSE = 7;
private const int WH_MOUSE_LL = 14;
private enum MouseMessages
{
WM_LBUTTONDOWN = 0x0201,
WM_LBUTTONUP = 0x0202,
WM_MOUSEMOVE = 0x0200,
WM_MOUSEWHEEL = 0x020A,
WM_RBUTTONDOWN = 0x0204,
WM_RBUTTONUP = 0x0205
}
[StructLayout(LayoutKind.Sequential)]
private struct POINT
{
public int x;
public int y;
}
[StructLayout(LayoutKind.Sequential)]
private struct MSLLHOOKSTRUCT
{
public POINT pt;
public uint mouseData;
public uint flags;
public uint time;
public IntPtr dwExtraInfo;
}
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr SetWindowsHookEx(int idHook,
LowLevelMouseProc lpfn, IntPtr hMod, uint dwThreadId);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool UnhookWindowsHookEx(IntPtr hhk);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode,
IntPtr wParam, IntPtr lParam);
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr GetModuleHandle(string lpModuleName);
}
Form.cs
private void onActivated(object sender, EventArgs e)
{
Properties.Settings.Default.AppFocus = true;
}
private void onDeactivated(object sender, EventArgs e)
{
Properties.Settings.Default.AppFocus = false;
}
This likely isn't the best way to do this, however I was unable to get the CEFBrowser object to ignore right clicks, just as I was unable to get the Form as a whole to ignore right clicks, or even the Application to ignore (non-low level) Mouse Events. This is the work around of someone who is completely new to Windows so don't take this as the best code ever but it is working for me.
Related
I am trying to listen to keyboard input in my Word AddIn with the MouseKeyboardActivityMonitor Nugget. When I register the KeyboardHookListener I am able to receive every keyboard input on every programm except Word.
Is this maybe couse of some Word internal protection or am I missing something?
I have Windows 7 64bit and Word 2016 32bit.
k_keyListener = new KeyboardHookListener(new GlobalHooker());
k_keyListener.Enabled = true;
k_keyListener.KeyDown += new System.Windows.Forms.KeyEventHandler(hook_OnKeyDown);
public void hook_OnKeyDown(object sender, System.Windows.Forms.KeyEventArgs e)
{
log.Info("Pressed key: " + e.KeyCode.ToString());
}
I don't use the Global Hooker and my code works. I explicitly tested it in Word (and know it works in Excel, PowerPoint, Access, etc).
For what its worth, Microsoft is forever worried about Office app hacks and its possible your security software could actually be the reason. It is a KeyLogger after all and susceptible to being labelled a virus injection attack.
public partial class ThisAddIn
{
private void ThisAddIn_Startup(object sender, System.EventArgs e)
{
//enable keyboard intercepts
KeyboardHooking.SetHook();
}
private void ThisAddIn_Shutdown(object sender, System.EventArgs e)
{
//disable keyboard intercepts
KeyboardHooking.ReleaseHook();
}
}
Add this Keyboard class:
using System;
using System.Runtime.InteropServices;
using System.Windows.Forms;
namespace WordAddInKeyHandler
{
class KeyboardHooking
{
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr SetWindowsHookEx(int idHook, LowLevelKeyboardProc lpfn, IntPtr hMod,
uint dwThreadId);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool UnhookWindowsHookEx(IntPtr hhk);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode, IntPtr wParam, IntPtr lParam);
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr GetModuleHandle(string lpModuleName);
public delegate int LowLevelKeyboardProc(int nCode, IntPtr wParam, IntPtr lParam);
private static LowLevelKeyboardProc _proc = HookCallback;
private static IntPtr _hookID = IntPtr.Zero;
//declare the mouse hook constant.
//For other hook types, you can obtain these values from Winuser.h in the Microsoft SDK.
private const int WH_KEYBOARD = 2; // mouse
private const int HC_ACTION = 0;
private const int WH_KEYBOARD_LL = 13; // keyboard
private const int WM_KEYDOWN = 0x0100;
public static void SetHook()
{
// Ignore this compiler warning, as SetWindowsHookEx doesn't work with ManagedThreadId
#pragma warning disable 618
_hookID = SetWindowsHookEx(WH_KEYBOARD, _proc, IntPtr.Zero, (uint)AppDomain.GetCurrentThreadId());
#pragma warning restore 618
}
public static void ReleaseHook()
{
UnhookWindowsHookEx(_hookID);
}
//Note that the custom code goes in this method the rest of the class stays the same.
//It will trap if BOTH keys are pressed down.
private static int HookCallback(int nCode, IntPtr wParam, IntPtr lParam)
{
if (nCode < 0)
{
return (int)CallNextHookEx(_hookID, nCode, wParam, lParam);
}
else
{
if (nCode == HC_ACTION)
{
Keys keyData = (Keys)wParam;
// CTRL + SHIFT + 7
if ((BindingFunctions.IsKeyDown(Keys.ControlKey) == true)
&& (BindingFunctions.IsKeyDown(Keys.ShiftKey) == true)
&& (BindingFunctions.IsKeyDown(keyData) == true) && (keyData == Keys.D7))
{
// DO SOMETHING HERE
}
// CTRL + 7
if ((BindingFunctions.IsKeyDown(Keys.ControlKey) == true)
&& (BindingFunctions.IsKeyDown(keyData) == true) && (keyData == Keys.D7))
{
// DO SOMETHING HERE
}
}
return (int)CallNextHookEx(_hookID, nCode, wParam, lParam);
}
}
}
public class BindingFunctions
{
[DllImport("user32.dll")]
static extern short GetKeyState(int nVirtKey);
public static bool IsKeyDown(Keys keys)
{
return (GetKeyState((int)keys) & 0x8000) == 0x8000;
}
}
}
If you have time you can check why the Global Hooker isn't working (specifically with Word) by comparing the Global Hooker source code to mine.
Reference to my answer here: https://stackoverflow.com/a/10257266/495455 also see the answer by Govert the author of XNA.
I've been having trouble with a certain problem. I've been disabling left and right mouse clicks for a particular application and my C# code looks like below...
My problem is that even though this works fine for disabling the mouse on a low level, isn't there a way in where I could disable it on a low level just for when the application is focused and therefor running?
using System;
using System.Runtime.InteropServices;
using System.Diagnostics;
namespace GlobalLowLevelHooks
{
public class MouseHook
{
public bool enabled = false;
public delegate IntPtr MouseHookHandler(int nCode, IntPtr wParam, IntPtr lParam);
public MouseHookHandler hookHandler;
public delegate void MouseHookCallback(MSLLHOOKSTRUCT mouseStruct);
#region Events
public event MouseHookCallback LeftButtonDown;
public event MouseHookCallback LeftButtonUp;
public event MouseHookCallback RightButtonDown;
public event MouseHookCallback RightButtonUp;
public event MouseHookCallback MouseMove;
public event MouseHookCallback MouseWheel;
public event MouseHookCallback DoubleClick;
public event MouseHookCallback MiddleButtonDown;
public event MouseHookCallback MiddleButtonUp;
#endregion
public IntPtr hookID = IntPtr.Zero;
public void Enable()
{
hookHandler = HookFunc;
hookID = SetHook(hookHandler);
enabled = true;
}
public void Disable()
{
if (hookID == IntPtr.Zero)
return;
UnhookWindowsHookEx(hookID);
hookID = IntPtr.Zero;
enabled = false;
}
~MouseHook()
{
Enable();
}
private IntPtr SetHook(MouseHookHandler proc)
{
using (ProcessModule module = Process.GetCurrentProcess().MainModule)
return SetWindowsHookEx(WH_MOUSE_LL, proc, GetModuleHandle(module.ModuleName), 0);
}
private IntPtr HookFunc(int nCode, IntPtr wParam, IntPtr lParam)
{
// parse system messages
if (nCode >= 0)
{
if (MouseMessages.WM_LBUTTONDOWN == (MouseMessages)wParam)
{
return (IntPtr)1;
}
if (MouseMessages.WM_RBUTTONDOWN == (MouseMessages)wParam)
{
return (IntPtr)1;
}
if (MouseMessages.WM_MBUTTONDOWN == (MouseMessages)wParam)
{
return (IntPtr)1;
}
if (MouseMessages.WM_LBUTTONDBLCLK == (MouseMessages)wParam)
{
return (IntPtr)1;
}
}
return CallNextHookEx(hookID, nCode, wParam, lParam);
}
#region WinAPI
private const int WH_MOUSE_LL = 14;
private enum MouseMessages
{
WM_LBUTTONDOWN = 0x0201,
WM_LBUTTONUP = 0x0202,
WM_MOUSEMOVE = 0x0200,
WM_MOUSEWHEEL = 0x020A,
WM_RBUTTONDOWN = 0x0204,
WM_RBUTTONUP = 0x0205,
WM_LBUTTONDBLCLK = 0x0203,
WM_MBUTTONDOWN = 0x0207,
WM_MBUTTONUP = 0x0208
}
[StructLayout(LayoutKind.Sequential)]
public struct POINT
{
public int x;
public int y;
}
[StructLayout(LayoutKind.Sequential)]
public struct MSLLHOOKSTRUCT
{
public POINT pt;
public uint mouseData;
public uint flags;
public uint time;
public IntPtr dwExtraInfo;
}
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr SetWindowsHookEx(int idHook,
MouseHookHandler lpfn, IntPtr hMod, uint dwThreadId);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool UnhookWindowsHookEx(IntPtr hhk);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode, IntPtr wParam, IntPtr lParam);
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr GetModuleHandle(string lpModuleName);
#endregion
}
}
I'm writing an application that binds custom actions to my mouse buttons. For example, I connected the volume up to one of the thumb buttons. Everything works fine as long as I stay in one window because every other windows and the taskbar seems to freeze and it will take some time before the windows are activated again or if I kill my application or the window I am working in.
In the code below I capture the mouse events and check with the settings in the application if the button action is still default or if it has changed. If the action has changed, then the application should for example turn the volume up with two.
[DllImport("kernel32.dll")]
public static extern IntPtr GetModuleHandle(string name);
public delegate int HookProc(int nCode, IntPtr wParam, IntPtr lParam);
public static bool usingKeyboard = false;
public static bool leftButtonDown = false;
static int hMHook;
public const int WH_MOUSE_LL = 14;
//Declare MouseHookProcedure as a HookProc type.
static HookProc MouseHookProcedure;
private enum MouseMessages
{
WM_LBUTTONDOWN = 0x0201,
WM_LBUTTONUP = 0x0202,
WM_MOUSEMOVE = 0x0200,
WM_MOUSEWHEEL = 0x020A,
WM_RBUTTONDOWN = 0x0204,
WM_RBUTTONUP = 0x0205,
WM_XBUTTONDOWN = 0x020B,
WM_XBUTTONUP = 0x020C,
WM_MBUTTONUP = 0x0208,
WM_MBUTTONDOWN = 0x0207
}
[StructLayout(LayoutKind.Sequential)]
public class POINT
{
public int x;
public int y;
}
[StructLayout(LayoutKind.Sequential)]
public class MouseHookStruct
{
public POINT pt;
public int hwnd;
public int wHitTestCode;
public int dwExtraInfo;
}
[DllImport("kernel32.dll")]
static extern uint GetLastError();
[DllImport("user32.dll", CharSet = CharSet.Auto,
CallingConvention = CallingConvention.StdCall)]
public static extern int SetWindowsHookEx(int idHook, HookProc lpfn,
IntPtr hInstance, int threadId);
[DllImport("user32.dll", CharSet = CharSet.Auto,
CallingConvention = CallingConvention.StdCall)]
public static extern bool UnhookWindowsHookEx(int idHook);
[DllImport("user32.dll", CharSet = CharSet.Auto,
CallingConvention = CallingConvention.StdCall)]
public static extern int CallNextHookEx(int idHook, int nCode,
IntPtr wParam, IntPtr lParam);
private int MouseHookProc(int nCode, IntPtr wParam, IntPtr lParam)
{
MouseHookStruct MyMouseHookStruct = (MouseHookStruct)Marshal.PtrToStructure(lParam, typeof(MouseHookStruct));
MouseUsageMessage message = new MouseUsageMessage(1);
MouseUsageManager.mouseUsageMessageQueue.Add(message);
if (nCode >= 0)
{
if (MouseMessages.WM_LBUTTONDOWN == (MouseMessages)wParam)
{
leftButtonDown = true;
} else if (MouseMessages.WM_LBUTTONUP == (MouseMessages)wParam)
{
leftButtonDown = false;
} else if (MouseMessages.WM_RBUTTONDOWN == (MouseMessages)wParam)
{
} else if (MouseMessages.WM_RBUTTONUP == (MouseMessages) wParam) {
} else if (MouseMessages.WM_XBUTTONUP == (MouseMessages)wParam)
{
switch (MyMouseHookStruct.hwnd)
{
case 65536:
if (Settings.Default.thumbClick1User != Settings.Default.thumbClick1Default)
{
ExecuteAction(Settings.Default.thumbClick1User);
return 1;
}
break;
case 131072:
if (Settings.Default.thumbClick2User != Settings.Default.thumbClick2Default)
{
ExecuteAction(Settings.Default.thumbClick2User);
return 1;
}
break;
}
} else if (MouseMessages.WM_MBUTTONDOWN == (MouseMessages)wParam)
{
}
}
return CallNextHookEx(hMHook, nCode, wParam, lParam);
}
Why are the other windows freezing or why can't I use my mouse on the other windows after I've clicked the thumb buttons?
EDIT: Additional code
private void ExecuteAction(string setting)
{
VolumeControl vc = new VolumeControl();
Keybindings kb = new Keybindings();
switch (setting)
{
case "volUp":
vc.VolUp();
break;
case "volDown":
vc.VolDown();
break;
case "cut":
kb.Cut();
break;
case "selectAll":
kb.SelectAll();
break;
case "copy":
kb.Copy();
break;
default:
break;
}
}
The setting string that is sended to the ExecuteAction function is just a string with the action to be performed, i.e. copy, volume up, volume down etc.
VolumeControl class:
public class VolumeControl
{
private const int APPCOMMAND_VOLUME_MUTE = 0x80000;
private const int APPCOMMAND_VOLUME_UP = 0xA0000;
private const int APPCOMMAND_VOLUME_DOWN = 0x90000;
private const int WM_APPCOMMAND = 0x319;
IntPtr handle = Process.GetCurrentProcess().MainWindowHandle;
[DllImport("user32.dll")]
public static extern IntPtr SendMessageW(IntPtr hWnd, int Msg,
IntPtr wParam, IntPtr lParam);
public void VolDown()
{
SendMessageW(handle, WM_APPCOMMAND, handle,
(IntPtr)APPCOMMAND_VOLUME_DOWN);
}
public void VolUp()
{
SendMessageW(handle, WM_APPCOMMAND, handle,
(IntPtr)APPCOMMAND_VOLUME_UP);
}
}
Create Hook function, the function that is called when the class is initialized:
private void createHook()
{
while (hMHook == 0) //|| hKHook == 0)
{
//if (hMHook == 0)
//{
//hMHook = SetWindowsHookEx(WH_MOUSE_LL,
//MouseHookProcedure,
//GetModuleHandle(Process.GetCurrentProcess().MainModule.ModuleName),
//(IntPtr)0,
//0);
//}
if (hMHook == 0)
{
hMHook = SetWindowsHookEx(WH_MOUSE_LL,
MouseHookProcedure,
GetModuleHandle(Process.GetCurrentProcess().MainModule.ModuleName),
0);
}
if (hMHook == 0) //|| hKHook == 0)
{
Console.WriteLine("SetWindowsHookEx Failed");
return;
}
Console.WriteLine("Hooked");
}
}
My solution, i have built a simple console project
when you launch program, the hook is activated, and you can toggle with middle mouse button. the right button up and letf button up play with system volume..
the main program:
using HookInput.API;
using HookInput.Mouse;
using System;
using System.Diagnostics;
using System.Windows.Forms;
namespace ConsoleApp3
{
public class Program
{
private static MouseInput mouseInputHook = null;
static void Main(string[] args)
{
var vc = new VolumeControl();
mouseInputHook = new MouseInput(vc);
mouseInputHook.setHook(true);
Console.WriteLine("hook activated");
Application.Run(new ApplicationContext());
}
}
public class VolumeControl
{
private const int APPCOMMAND_VOLUME_MUTE = 0x80000;
private const int APPCOMMAND_VOLUME_UP = 0xA0000;
private const int APPCOMMAND_VOLUME_DOWN = 0x90000;
private const int WM_APPCOMMAND = 0x319;
public IntPtr handle = Process.GetCurrentProcess().MainWindowHandle;
public void VolDown()
{
WindowsHookAPI.SendMessageW(handle, WM_APPCOMMAND, handle, (IntPtr)APPCOMMAND_VOLUME_DOWN);
}
public void VolUp()
{
WindowsHookAPI.SendMessageW(handle, WM_APPCOMMAND, handle, (IntPtr)APPCOMMAND_VOLUME_UP);
}
}
}
the APIs:
using System;
using System.Runtime.InteropServices;
namespace HookInput.API
{
public class WindowsHookAPI
{
//public delegate IntPtr HookDelegate(
// Int32 Code, IntPtr wParam, IntPtr lParam);
public delegate IntPtr HookDelegate(Int32 Code, IntPtr wParam, IntPtr lParam);
[DllImport("User32.dll")]
public static extern IntPtr CallNextHookEx(IntPtr hHook, Int32 nCode, IntPtr wParam, IntPtr lParam);
[DllImport("User32.dll")]
public static extern IntPtr UnhookWindowsHookEx(IntPtr hHook);
[DllImport("User32.dll")]
public static extern IntPtr SetWindowsHookEx(Int32 idHook, HookDelegate lpfn, IntPtr hmod, Int32 dwThreadId);
[DllImport("user32.dll")]
public static extern IntPtr SendMessageW(IntPtr hWnd, int Msg, IntPtr wParam, IntPtr lParam);
}
}
the hook and structures:
using HookInput.API;
using System;
using System.IO.MemoryMappedFiles;
using System.Runtime.InteropServices;
using ConsoleApp3;
namespace HookInput.Mouse
{
public class MouseInput
{
private const Int32 WM_MOUSEMOVE = 0x0200;
private const Int32 WM_LBUTTONDOWN = 0x0201;
private const Int32 WM_LBUTTONUP = 0x0202;
private const Int32 WM_LBUTTONDBLCLK = 0x0203;
private const Int32 WM_RBUTTONDOWN = 0x0204;
private const Int32 WM_RBUTTONUP = 0x0205;
private const Int32 WM_RBUTTONDBLCLK = 0x0206;
private const Int32 WM_MBUTTONDOWN = 0x0207;
private const Int32 WM_MBUTTONUP = 0x0208;
private const Int32 WM_MBUTTONDBLCLK = 0x0209;
private const Int32 WM_MOUSEWHEEL = 0x020A;
private const Int32 WM_XBUTTONDOWN = 0x020B;
private const Int32 WM_XBUTTONUP = 0x020C;
private const Int32 WM_XBUTTONDBLCLK = 0x020D;
private MemoryMappedViewAccessor accessor;
private bool hooked = false;
private WindowsHookAPI.HookDelegate mouseDelegate;
private IntPtr mouseHandle;
private const Int32 WH_MOUSE_LL = 14;
private readonly VolumeControl vc;
public MouseInput(VolumeControl vc)
{
this.vc = vc;
}
public void setHook(bool on)
{
if (hooked == on) return;
if (on)
{
mouseDelegate = MouseHookDelegate;
mouseHandle = WindowsHookAPI.SetWindowsHookEx(WH_MOUSE_LL, mouseDelegate, IntPtr.Zero, 0);
if (mouseHandle != IntPtr.Zero) hooked = true;
}
else
{
WindowsHookAPI.UnhookWindowsHookEx(mouseHandle);
hooked = false;
}
}
private IntPtr MouseHookDelegate(Int32 Code, IntPtr wParam, IntPtr lParam)
{
//mouseData:
//If the message is WM_MOUSEWHEEL, the high-order word of this member is the wheel delta.The low-order word is reserved.
// A positive value indicates that the wheel was rotated forward, away from the user;
// a negative value indicates that the wheel was rotated backward, toward the user.
// One wheel click is defined as WHEEL_DELTA, which is 120.(0x78 or 0xFF88)
//If the message is WM_XBUTTONDOWN, WM_XBUTTONUP, WM_XBUTTONDBLCLK, WM_NCXBUTTONDOWN, WM_NCXBUTTONUP, or WM_NCXBUTTONDBLCLK,
// the high - order word specifies which X button was pressed or released,
// and the low - order word is reserved.This value can be one or more of the following values.Otherwise, mouseData is not used.
//XBUTTON1 = 0x0001 The first X button was pressed or released.
//XBUTTON2 = 0x0002 The second X button was pressed or released.
MSLLHOOKSTRUCT lparam = (MSLLHOOKSTRUCT)Marshal.PtrToStructure(lParam, typeof(MSLLHOOKSTRUCT));
int command = (int)wParam;
if (Code < 0 || command == WM_LBUTTONDBLCLK || command == WM_RBUTTONDBLCLK)
return WindowsHookAPI.CallNextHookEx(mouseHandle, Code, wParam, lParam);
else if (command == WM_XBUTTONDOWN || command == WM_XBUTTONUP)
{
int numbutton = ((int)lparam.mouseData >> 16) - 1;
//return (IntPtr)1;
}
else if (command == WM_LBUTTONDOWN || command == WM_LBUTTONUP)
{
if (command == WM_LBUTTONUP)
{
vc.VolDown();
Console.WriteLine("L down");
}
}
else if (command == WM_RBUTTONDOWN || command == WM_RBUTTONUP)
{
if (command == WM_RBUTTONUP)
{
vc.VolUp();
Console.WriteLine("L Up");
}
}
else if (command == WM_MBUTTONDOWN || command == WM_MBUTTONUP)
{
if (hooked)
{
setHook(false);
Console.WriteLine("hook deactivated");
}
else
{
setHook(true);
Console.WriteLine("hook activated");
}
}
else if (command == WM_MOUSEWHEEL)
{
}
return WindowsHookAPI.CallNextHookEx(mouseHandle, Code, wParam, lParam);
}
~MouseInput()
{
}
[StructLayout(LayoutKind.Sequential)]
private struct POINT
{
public int x;
public int y;
}
[StructLayout(LayoutKind.Sequential)]
private struct MSLLHOOKSTRUCT
{
public POINT pt;
public uint mouseData;
public uint flags;
public uint time;
public IntPtr dwExtraInfo;
}
}
}
I am building an application using UIAutomation which labels certain widgets on a typical Microsoft Windows user interface, e.g. Windows Explorer, control panel. I am using appropriate threading with UIA based on a Microsoft blog example and everything is working well. The labelling of the widgets is triggered by certain events and one of these events is a mouse click using a low level mousehook code shown below. The problem I have is that when the UI is updated on a mouseclick the mouse movement becomes juddery (as in not smooth) while the UI is updating. So what springs to mind is that the mouse action event needs to run in a different thread. Although I have been programming for quite a few years it has been off and on so I am far from confident when it comes to such threading issues. I have tried the code below in the mouse auction event but it makes no difference. Any help greatly appreciated. I would particularly appreciate example code with an explanation in particular.
// Setup global mouse hook to react to mouse clicks under certain conditions, see event handler
MouseHook.Start();
MouseHook.MouseAction += new EventHandler(MouseHook_MouseAction);
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
using System.Diagnostics;
using System.Threading;
namespace myapplication
{
public static class MouseHook
{
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr SetWindowsHookEx(int idHook,
LowLevelMouseProc lpfn, IntPtr hMod, uint dwThreadId);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool UnhookWindowsHookEx(IntPtr hhk);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode,
IntPtr wParam, IntPtr lParam);
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr GetModuleHandle(string lpModuleName);
public static event EventHandler MouseAction = delegate { };
private const int WH_MOUSE_LL = 14;
private enum MouseMessages
{
WM_LBUTTONDOWN = 0x0201,
// WM_LBUTTONUP = 0x0202,
// WM_MOUSEMOVE = 0x0200,
WM_MOUSEWHEEL = 0x020A,
WM_RBUTTONDOWN = 0x0204,
//WM_RBUTTONUP = 0x0205
}
[StructLayout(LayoutKind.Sequential)]
private struct POINT
{
public int x;
public int y;
}
[StructLayout(LayoutKind.Sequential)]
private struct MSLLHOOKSTRUCT
{
public POINT pt;
public uint mouseData;
public uint flags;
public uint time;
public IntPtr dwExtraInfo;
}
public static void Start()
{
_hookID = SetHook(_proc);
}
public static void stop()
{
UnhookWindowsHookEx(_hookID);
}
private static LowLevelMouseProc _proc = HookCallback;
private static IntPtr _hookID = IntPtr.Zero;
private static IntPtr SetHook(LowLevelMouseProc proc)
{
using (Process curProcess = Process.GetCurrentProcess())
using (ProcessModule curModule = curProcess.MainModule)
{
IntPtr hook = SetWindowsHookEx(WH_MOUSE_LL, proc, GetModuleHandle("user32"), 0);
if (hook == IntPtr.Zero) throw new System.ComponentModel.Win32Exception();
return hook;
}
}
private delegate IntPtr LowLevelMouseProc(int nCode, IntPtr wParam, IntPtr lParam);
private static IntPtr HookCallback(
int nCode, IntPtr wParam, IntPtr lParam)
{
if (nCode >= 0 && (MouseMessages.WM_LBUTTONDOWN == (MouseMessages)wParam || MouseMessages.WM_RBUTTONDOWN == (MouseMessages)wParam ||
MouseMessages.WM_MOUSEWHEEL == (MouseMessages)wParam))
{
MSLLHOOKSTRUCT hookStruct = (MSLLHOOKSTRUCT)Marshal.PtrToStructure(lParam, typeof(MSLLHOOKSTRUCT));
MouseAction(null, new EventArgs());
}
return CallNextHookEx(_hookID, nCode, wParam, lParam);
}
}
}
private void MouseHook_MouseAction(object sender, EventArgs e)
{
//my attempt at threading solution
Thread th = new Thread(() =>
{
UpdateUI();
Application.Run();
});
th.SetApartmentState(ApartmentState.STA);
th.Start();
}
just a quick question, can you tell me why I can't access my controls like popup or textbox or the 'this' inside the function that has a comment, please check it out. I really need to know why asap. Thank you so much!
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
DispatcherTimer timer;
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern IntPtr SetWindowsHookEx(int idHook,
LowLevelKeyboardProc lpfn, IntPtr hMod, uint dwThreadId);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool UnhookWindowsHookEx(IntPtr hhk);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode,
IntPtr wParam, IntPtr lParam);
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern IntPtr GetModuleHandle(string lpModuleName);
public const int WH_KEYBOARD_LL = 13;
public const int WM_KEYDOWN = 0x0100;
public static LowLevelKeyboardProc _proc = HookCallback;
public static IntPtr _hookID = IntPtr.Zero;
public const uint VK_NUMLOCK = 0x90;
public const uint VK_CAPITAL = 0x14;
public MainWindow()
{
MouseDown += delegate { DragMove(); };
InitializeComponent();
_hookID = SetHook(_proc);
}
public void mainForm_Loaded(object sender, RoutedEventArgs e)
{
timer = new DispatcherTimer();
timer.Interval = TimeSpan.FromMilliseconds(2000);
timer.Tick += timer_Tick;
}
public void timer_Tick(object sender, EventArgs e)
{
Popup1.IsOpen = false;
timer.Stop();
}
public static IntPtr SetHook(LowLevelKeyboardProc proc)
{
using (Process curProcess = Process.GetCurrentProcess())
using (ProcessModule curModule = curProcess.MainModule)
{
return SetWindowsHookEx(WH_KEYBOARD_LL, proc,
GetModuleHandle(curModule.ModuleName), 0);
}
}
public delegate IntPtr LowLevelKeyboardProc(int nCode, IntPtr wParam, IntPtr lParam);
public static IntPtr HookCallback(int nCode, IntPtr wParam, IntPtr lParam)
{
if (nCode >= 0 && wParam == (IntPtr)WM_KEYDOWN)
{
int vkCode = Marshal.ReadInt32(lParam);
if (vkCode == VK_CAPITAL)
{
if (Console.CapsLock == true)
{
// I WANT TO ACCESS MY CONTROLS HERE (popup, textbox, etc... this);
}
}
}
return CallNextHookEx(_hookID, nCode, wParam, lParam);
}
protected override void OnClosed(EventArgs e)
{
UnhookWindowsHookEx(_hookID);
base.OnClosed(e);
}
}
It is a static method. "this" and the controls belong to the instance and can't be seen inside of a static method.
With the use of those .dlls, I can't provide a bulletproof method of accessing it. I would not advise resorting to hopes and dreams, but in the case where the MainWindow is the active window, you could do something like the following:
public static void StaticMainWindowMethod(string incomingMessage)
{
var activeWindow = Application.Current.Windows.OfType<Window>().SingleOrDefault(x => x.IsActive);
if (activeWindow != null)
{
var mainWindow = activeWindow as MainWindow;
if (mainWindow != null)
{
mainWindow.InstanceMainWindowMethod(incomingMessage);
}
}
}
protected void InstanceMainWindowMethod(string passedFromStaticMessage)
{
this.MainTextBox.Text = passedFromStaticMessage;
}
The idea is that you need to get the instance of the window in order to get at its properties/controls. Depending on how your application is designed, you may be able to get at it through application level properties. Its reliability is really up to the design of the application.
First, add a static event to your window:
public static event EventHandler CapsLockEnabled;
Next, add a handler for this event:
public MainWindow()
{
MouseDown += delegate { DragMove(); };
InitializeComponent();
_hookID = SetHook(_proc);
CapsLockEnabled += (sender, e) => { Console.WriteLine("caps lock enabled"); };
}
Your event handler, because it's defined on an instance, has full access to all of the window's controls.
Finally, raise the event from your HookCallback method:
public static IntPtr HookCallback(int nCode, IntPtr wParam, IntPtr lParam)
{
if (nCode >= 0 && wParam == (IntPtr)WM_KEYDOWN)
{
int vkCode = Marshal.ReadInt32(lParam);
if (vkCode == VK_CAPITAL)
{
if (Console.CapsLock == true)
{
var handler = CapsLockEnabled;
if (handler != null)
{
handler(typeof(MainWindow), EventArgs.Empty);
}
}
}
}
return CallNextHookEx(_hookID, nCode, wParam, lParam);
}