make GlobalKeyboardHook class read string comes from 2D barcode scanner - c#

I am using GlobalKeyboardHook class to make my application listen to keyboard keydown event and it works fine
but when a barcode scanner scan an image, it return a string with a "DOS-720" encodeing
which is like that "ÃÍãÏ", The GlobalKeyboardHook class return some thing like this "¤aii¤",
How to make GlobalKeyboardHook class return the original string??
the GlobalKeyboardHook class
public class GlobalKeyboardHook
{
[DllImport("user32.dll")]
private static extern int CallNextHookEx(IntPtr hhk, int code, int wParam, ref keyBoardHookStruct lParam);
[DllImport("user32.dll")]
private static extern IntPtr SetWindowsHookEx(int idHook, LLKeyboardHook callback, IntPtr hInstance,
uint theardID);
[DllImport("user32.dll")]
private static extern bool UnhookWindowsHookEx(IntPtr hInstance);
[DllImport("kernel32.dll")]
private static extern IntPtr LoadLibrary(string lpFileName);
public delegate int LLKeyboardHook(int Code, int wParam, ref keyBoardHookStruct lParam);
public struct keyBoardHookStruct
{
public int vkCode;
public int scanCode;
public int flags;
public int time;
public int dwExtraInfo;
}
private const int WH_KEYBOARD_LL = 13;
private const int WM_KEYDOWN = 0x0100;
private const int WM_KEYUP = 0x0101;
private const int WM_SYSKEYDOWN = 0x0104;
private const int WM_SYSKEYUP = 0x0105;
private LLKeyboardHook llkh;
public List<Keys> HookedKeys = new List<Keys>();
private IntPtr Hook = IntPtr.Zero;
public event KeyEventHandler KeyDown;
public event KeyEventHandler KeyUp;
public GlobalKeyboardHook()
{
llkh = new LLKeyboardHook(HookProc);
hook();
}
~GlobalKeyboardHook()
{
unhook();
}
public void hook()
{
IntPtr hInstance = LoadLibrary("User32");
Hook = SetWindowsHookEx(WH_KEYBOARD_LL, llkh, hInstance, 0);
}
public void unhook()
{
UnhookWindowsHookEx(Hook);
}
public int HookProc(int Code, int wParam, ref keyBoardHookStruct lParam)
{
if (Code >= 0)
{
Keys key = (Keys) lParam.vkCode;
if (HookedKeys.Contains(key))
{
KeyEventArgs kArg = new KeyEventArgs(key);
if ((wParam == WM_KEYDOWN || wParam == WM_SYSKEYDOWN) && (KeyDown != null))
KeyDown(this, kArg);
else if ((wParam == WM_KEYUP || wParam == WM_SYSKEYUP) && (KeyUp != null))
KeyUp(this, kArg);
if (kArg.Handled)
return 1;
}
}
return CallNextHookEx(Hook, Code, wParam, ref lParam);
}
}
and the use of it in the form
GlobalKeyboardHook gHook;
public Form1()
{
InitializeComponent();
//new Thread(SampleFunction).Start();
}
private void Form1_Load(object sender, EventArgs e)
{
gHook = new GlobalKeyboardHook(); // Create a new GlobalKeyboardHook
// Declare a KeyDown Event
gHook.KeyDown += new KeyEventHandler(gHook_KeyDown);
// Add the keys you want to hook to the HookedKeys list
foreach (Keys key in Enum.GetValues(typeof(Keys)))
gHook.HookedKeys.Add(key);
}
// Handle the KeyDown Event
public void gHook_KeyDown(object sender, KeyEventArgs e)
{
textBox1.Text += ((char)e.KeyValue).ToString();
}
private void button1_Click(object sender, EventArgs e)
{
gHook.hook();
}
private void button2_Click(object sender, EventArgs e)
{
gHook.unhook();
}
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
gHook.unhook();
}

Related

Every other window freezes after replacing mouse action - c#

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;
}
}
}

How to detect CTRL+keypress shortcut at any time in C#

In a C# Windows Form I would like transcode information:
when user press CTRL+I, the app detect the key press combination, it takes the code in the clipboard and transcode it.
I find out this code:
protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
{
switch (msg.Msg)
{
case 0x100:
case 0x104:
switch (keyData)
{
case Keys.Control | Keys.I:
MessageBox.Show("Ctrl + I pressed");
break;
}
break;
}
return base.ProcessCmdKey(ref msg, keyData);
}
This works fine when windows form has focus.
I would like detect the combination when the app is minimized as tray icon.
SOLUTION:
keyboardhook.cs:
using System;
using System.Runtime.InteropServices;
using System.Windows.Forms;
namespace TrayIconForm
{
public static class Constants
{
public const int NOMOD = 0x0000;
public const int ALT = 0x0001;
public const int CTRL = 0x0002;
public const int SHIFT = 0x0004;
public const int WIN = 0x0008;
public const int WM_HOTKEY_MSG_ID = 0x0312;
}
public class KeyHandler
{
[DllImport("user32.dll")]
private static extern bool RegisterHotKey(IntPtr hWnd, int id, int fsModifiers, int vk);
[DllImport("user32.dll")]
private static extern bool UnregisterHotKey(IntPtr hWnd, int id);
private int modifier;
private int key;
private IntPtr hWnd;
private int id;
public KeyHandler(int modifier, Keys key, Form form)
{
this.modifier = modifier;
this.key = (int)key;
this.hWnd = form.Handle;
id = this.GetHashCode();
}
public override int GetHashCode()
{
return modifier ^ key ^ hWnd.ToInt32();
}
public bool Register()
{
return RegisterHotKey(hWnd, id, modifier, key);
}
public bool Unregiser()
{
return UnregisterHotKey(hWnd, id);
}
}
}
Information.cs (Form):
using System;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace TrayIconForm
{
public partial class Information : Form
{
private KeyHandler ghk;
public Information()
{
InitializeComponent();
ghk = new KeyHandler(Constants.CTRL, Keys.I, this);
ghk.Register();
}
private void HandleHotkey()
{
string s = Get_Copy();
notifyIcon1.BalloonTipText = s;
notifyIcon1.BalloonTipTitle = "You have pressed CTRL+i";
notifyIcon1.BalloonTipIcon = ToolTipIcon.Info;
notifyIcon1.Visible = true;
notifyIcon1.ShowBalloonTip(500);
}
protected override void WndProc(ref Message m)
{
if (m.Msg == Constants.WM_HOTKEY_MSG_ID)
HandleHotkey();
base.WndProc(ref m);
}
private string Get_Copy()
{
string r;
// Retrieves data from Clipboard
IDataObject iData = Clipboard.GetDataObject();
// Is Data Text?
if (iData.GetDataPresent(DataFormats.Text))
r = (String)iData.GetData(DataFormats.Text);
else
r = "nothing";
return r;
}
private void Information_Resize(object sender, EventArgs e)
{
if (FormWindowState.Minimized == this.WindowState)
{
notifyIcon1.BalloonTipText = "My application still working...";
notifyIcon1.BalloonTipTitle = "My Sample Application";
notifyIcon1.BalloonTipIcon = ToolTipIcon.Info;
notifyIcon1.Visible = true;
notifyIcon1.ShowBalloonTip(500);
this.Hide();
}
else if (FormWindowState.Normal == this.WindowState)
{
notifyIcon1.Visible = false;
}
}
}
}
This works just instantiate it, subscibe to the event and you are done. It s not my script. A while ago I searched long for this but I found it and it works great. There were you subscribed to the event you can look if the pressed key (stored in the event args) is your key and when it is you can look with Keyboard.iskeydown(key.lctrl) if control is pressed to and then you can do what the combination should do.
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Windows.Input;
namespace <yournamespace>
{
public class LowLevelKeyboardListener
{
private const int WH_KEYBOARD_LL = 13;
private const int WM_KEYDOWN = 0x0100;
private const int WM_SYSKEYDOWN = 0x0104;
[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 IntPtr LowLevelKeyboardProc(int nCode, IntPtr wParam, IntPtr lParam);
public event EventHandler<KeyPressedArgs> OnKeyPressed;
private LowLevelKeyboardProc _proc;
private IntPtr _hookID = IntPtr.Zero;
public LowLevelKeyboardListener()
{
_proc = HookCallback;
}
public void HookKeyboard()
{
_hookID = SetHook(_proc);
}
public void UnHookKeyboard()
{
UnhookWindowsHookEx(_hookID);
}
private IntPtr SetHook(LowLevelKeyboardProc proc)
{
using (Process curProcess = Process.GetCurrentProcess())
using (ProcessModule curModule = curProcess.MainModule)
{
return SetWindowsHookEx(WH_KEYBOARD_LL, proc, GetModuleHandle(curModule.ModuleName), 0);
}
}
private IntPtr HookCallback(int nCode, IntPtr wParam, IntPtr lParam)
{
if (nCode >= 0 && wParam == (IntPtr)WM_KEYDOWN || wParam == (IntPtr)WM_SYSKEYDOWN)
{
int vkCode = Marshal.ReadInt32(lParam);
if (OnKeyPressed != null) { OnKeyPressed(this, new KeyPressedArgs(KeyInterop.KeyFromVirtualKey(vkCode))); }
}
return CallNextHookEx(_hookID, nCode, wParam, lParam);
}
}
public class KeyPressedArgs : EventArgs
{
public Key KeyPressed { get; private set; }
public KeyPressedArgs(Key key)
{
KeyPressed = key;
}
}
}
[DllImport("user32.dll")]
public static extern int GetAsyncKeyState(Keys vKeys);
then
var ctrl = GetAsyncKeyState(Keys.ControlKey) & 0x8000;
var key = GetAsyncKeyState(Keys.F10) & 0x8000; //F10 for example
if(ctrl != 0 && key != 0)
{
//do sth
}

cant send key stroke only to Word Through my program that use KeyboardHook

i have my program that Captures weighing and send it to a open window.
its work excellent , except with a single software - Microsoft Word
I have tried everything and have no idea why.
my code:
this is the GlobalKeyBoardHook.cs class
public class GlobalKeyboardHook
{
[DllImport("user32.dll")]
static extern int CallNextHookEx(IntPtr hhk, int code, int wParam, ref keyBoardHookStruct lParam);
[DllImport("user32.dll")]
static extern IntPtr SetWindowsHookEx(int idHook, LLKeyboardHook callback, IntPtr hInstance, uint theardID);
[DllImport("user32.dll")]
static extern bool UnhookWindowsHookEx(IntPtr hInstance);
[DllImport("kernel32.dll")]
static extern IntPtr LoadLibrary(string lpFileName);
public delegate int LLKeyboardHook(int Code, int wParam, ref keyBoardHookStruct lParam);
public struct keyBoardHookStruct
{
public int vkCode;
public int scanCode;
public int flags;
public int time;
public int dwExtraInfo;
}
const int WH_KEYBOARD_LL = 13;
const int WM_KEYDOWN = 0x0100;
const int WM_KEYUP = 0x0101;
const int WM_SYSKEYDOWN = 0x0104;
const int WM_SYSKEYUP = 0x0105;
LLKeyboardHook llkh;
public List<Keys> HookedKeys = new List<Keys>();
IntPtr Hook = IntPtr.Zero;
public event KeyEventHandler KeyDown;
public event KeyEventHandler KeyUp;
// This is the Constructor. This is the code that runs every time you create a new GlobalKeyboardHook object
public GlobalKeyboardHook()
{
llkh = new LLKeyboardHook(HookProc);
// This starts the hook. You can leave this as comment and you have to start it manually (the thing I do in the tutorial, with the button)
// Or delete the comment mark and your hook will start automatically when your program starts (because a new GlobalKeyboardHook object is created)
// That's why there are duplicates, because you start it twice! I'm sorry, I haven't noticed this...
// hook(); <-- Choose!
}
~GlobalKeyboardHook()
{ unhook(); }
public void hook()
{
IntPtr hInstance = LoadLibrary("User32");
Hook = SetWindowsHookEx(WH_KEYBOARD_LL, llkh, hInstance, 0);
}
public void unhook()
{
UnhookWindowsHookEx(Hook);
}
public int HookProc(int Code, int wParam, ref keyBoardHookStruct lParam)
{
if (Code >= 0)
{
Keys key = (Keys)lParam.vkCode;
if (HookedKeys.Contains(key))
{
KeyEventArgs kArg = new KeyEventArgs(key);
if ((wParam == WM_KEYDOWN || wParam == WM_SYSKEYDOWN) && (KeyDown != null))
KeyDown(this, kArg);
else if ((wParam == WM_KEYUP || wParam == WM_SYSKEYUP) && (KeyUp != null))
KeyUp(this, kArg);
if (kArg.Handled)
return 1;
}
}
return CallNextHookEx(Hook, Code, wParam, ref lParam);
}
// --- from here start the program --
GlobalKeyboardHook gHook;
gHook = new GlobalKeyboardHook(); // Create a new GlobalKeyboardHook
gHook.KeyDown += new KeyEventHandler(gHook_KeyDown);
foreach (Keys key in Enum.GetValues(typeof(Keys)))
{
gHook.HookedKeys.Add(key);
}
gHook.hook();
public void gHook_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyValue == KeyPressg) //Pause-Break //19
{
ProccName = (GetActiveWindowTitle().ToString());
Start(ProccName);
gHook.unhook();
gHook.hook();
}
else
{
}
}
private string GetActiveWindowTitle()
{
const int nChars = 256;
StringBuilder Buff = new StringBuilder(nChars);
IntPtr handle = GetForegroundWindow();
if (GetWindowText(handle, Buff, nChars) > 0)
{
return Buff.ToString();
}
return null;
}
[DllImport("user32.dll")]
static extern IntPtr GetForegroundWindow();
[DllImport("user32.dll", CharSet = CharSet.Auto)]
static extern int GetWindowText(IntPtr hWnd, StringBuilder text, int count);
[DllImport("user32.dll")]
private static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
[DllImport("user32.dll")]
private static extern bool SetForegroundWindow(IntPtr hWnd);
public void Start(string NAME)
{
MSG = lblMSG.Text.Trim();
IntPtr zero = IntPtr.Zero;
for (int i = 0; (i < 60) && (zero == IntPtr.Zero); i++)
{
Thread.Sleep(500);
zero = FindWindow(null, NAME);
}
if (zero != IntPtr.Zero)
{
try
{
string text = lblMSG.Text.Trim();
text = text.Replace("gHook", "");
//OLD
//foreach (char c in text)
// SendKeys.SendWait(c.ToString());
//NEW
if (text.Length == 0) return;
SendKeys.SendWait(text);
if (MyParam._KeyAfter == "Enter")
{
MyParam.FromKEY = true;
SendKeys.SendWait("{ENTER}");
}
else if (MyParam._KeyAfter == "TAB")
{
SendKeys.SendWait("{TAB}");
}
else if (MyParam._KeyAfter == "Key Down")
{
SendKeys.SendWait("{DOWN}");
}
SendKeys.Flush();
}
catch { }
}
}
Any ideas why ?
thanks
EDIT
i fount the problem place:
public void Start(string NAME)
{
// --> NAME Contain --> Word‪ - 123.docx for example when Word window open
MSG = lblMSG.Text.Trim();
IntPtr zero = IntPtr.Zero;
for (int i = 0; (i < 60) && (zero == IntPtr.Zero); i++)
{
Thread.Sleep(500);
zero = FindWindow(null, NAME); // <-- in Word zero Always Contain 0 And never goes on in the code so stuck
}
// <--- the program stops here and stuck
if (zero != IntPtr.Zero)
{

Textbox not clickable but editable

I have a small form with 10 textboxes, I have them set in the right Tab Order currently the way I want them to Tab To. I was wondering if there is a way to set the textboxes up so they cannot be selected for editing unless they are Tabbed into. ie... I don't want the end user to be able to click on the textbox to edit them, I only want them editable through Tabbing.
This should do the trick
public partial class PoorTextBox : TextBox
{
protected override void WndProc(ref Message m)
{
if (m.Msg == (int) WM.LBUTTONDOWN)
{
return;//Eat mouse down events
}
base.WndProc(ref m);
}
}
Window messages enum can be found here.
How to do it without inheriting TextBox :
class EatMouseDown : NativeWindow
{
protected override void WndProc(ref Message m)
{
if (m.Msg == (int)WM.LBUTTONDOWN)
{
return;
}
base.WndProc(ref m);
}
}
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
new EatMouseDown().AssignHandle(textBox1.Handle);//Subclass a Handle
}
How to do it without any inheritance:
Clean up part omitted, which is also important. This may be buggy but that works. Recommended way is to use inheritance. Required methods pulled from .net fw src.
class EatMouseDown
{
public delegate IntPtr WndProc(IntPtr hWnd, int msg, IntPtr wParam, IntPtr lParam);
#region External methods...
[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern IntPtr SetWindowLong(HandleRef hWnd, int nIndex, WndProc wndproc);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern IntPtr SetWindowLongPtr(HandleRef hWnd, int nIndex, WndProc wndproc);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern IntPtr GetWindowLong(HandleRef hWnd, int nIndex);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern IntPtr GetWindowLongPtr(HandleRef hWnd, int nIndex);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern IntPtr DefWindowProc(IntPtr hWnd, int msg, IntPtr wParam, IntPtr lParam);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern IntPtr CallWindowProc(IntPtr wndProc, IntPtr hWnd, int msg, IntPtr wParam, IntPtr lParam);
#endregion
private const int GWLP_WNDPROC = -4;
private IntPtr handle;
private IntPtr originalWndProc;
private IntPtr currentWndProc;
public static IntPtr SetWindowLongHelper(HandleRef hWnd, int nIndex, WndProc wndProc)
{
return IntPtr.Size == 4
? SetWindowLong(hWnd, nIndex, wndProc)
: SetWindowLongPtr(hWnd, nIndex, wndProc);
}
public static IntPtr GetWindowLongHelper(HandleRef hWnd, int nIndex)
{
return IntPtr.Size == 4
? GetWindowLong(hWnd, nIndex)
: GetWindowLongPtr(hWnd, nIndex);
}
internal void SubclassHandle(IntPtr handle)
{
this.handle = handle;
this.originalWndProc = GetWindowLongHelper(new HandleRef(this, handle), GWLP_WNDPROC);
SetWindowLongHelper(new HandleRef(this, handle), GWLP_WNDPROC, new WndProc(this.Callback));
this.currentWndProc = GetWindowLongHelper(new HandleRef(this, handle), GWLP_WNDPROC);
}
private IntPtr Callback(IntPtr hwnd, int msg, IntPtr wparam, IntPtr lparam)
{
var m = Message.Create(hwnd, msg, wparam, lparam);
if (m.Msg == (int)WM.LBUTTONDOWN)
{
return IntPtr.Zero;
}
return CallWindowProc(originalWndProc, hwnd, msg, wparam, lparam);
}
}
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
new EatMouseDown().SubclassHandle(textBox1.Handle);//Subclass a Handle
}
Here's a similar approach to what Sriram Sakthivel had done, but using IMessageFilter instead:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
List<TextBox> TextBoxes = new List<TextBox>();
FindTextBoxes(this, TextBoxes);
Application.AddMessageFilter(new SuppressTextBoxClicks(TextBoxes));
}
private void FindTextBoxes(Control ctl, List<TextBox> TBs)
{
foreach(Control childCtl in ctl.Controls)
{
if (childCtl is TextBox)
{
TBs.Add((TextBox)childCtl);
}
else if(childCtl.HasChildren)
{
FindTextBoxes(childCtl, TBs);
}
}
}
}
public class SuppressTextBoxClicks : IMessageFilter
{
private List<TextBox> _TextBoxes = null;
private const int WM_LBUTTONDOWN = 0x201;
public SuppressTextBoxClicks(List<TextBox> TextBoxes)
{
_TextBoxes = TextBoxes;
}
public bool PreFilterMessage(ref Message m)
{
switch (m.Msg)
{
case WM_LBUTTONDOWN:
if (_TextBoxes != null)
{
foreach(TextBox TB in _TextBoxes)
{
if (TB.Handle.Equals(m.HWnd))
{
return true;
}
}
}
break;
default:
break;
}
return false;
}
}
Set all textboxes' Enabled property to false except the first one. On the TextChanged Event, check if it the Text is empty or not. if it was not empty, Enable the next TextBox and so on...
You can also try this one with the Enter event foreach TextBox
private void textBox2_Enter(object sender, EventArgs e)
{
if (textBox1.Text == "")
textBox1.Focus();
}
private void textBox3_Enter(object sender, EventArgs e)
{
if (textBox1.Text == "")
textBox1.Focus();
else
if (textBox2.Text == "")
textBox2.Focus();
}
private void textBox4_Enter(object sender, EventArgs e)
{
if (textBox1.Text == "")
textBox1.Focus();
else
if (textBox2.Text == "")
textBox2.Focus();
else
if (textBox3.Text == "")
textBox3.Focus();
}

Global hotkey in console application

Does anyone know how to use the RegisterHotKey/UnregisterHotKey API calls in a console application? I assume that setting up/removing the hotkey is the same, but how do I get the call back when the key was pressed?
Every example I see is for Winforms, and uses protected override void WndProc(ref Message m){...}, which isn't available to me.
update: what I have is below, but the event is never hit. I thought it could be because when you load ConsoleShell it does block further execution, but even if I put SetupHotkey into a different thread nothing happens. Any thoughts?
class Program
{
static void Main(string[] args)
{
new Hud().Init(args);
}
}
class Hud
{
int keyHookId;
public void Init(string[] args)
{
SetupHotkey();
InitPowershell(args);
Cleanup();
}
private void Cleanup()
{
HotKeyManager.UnregisterHotKey(keyHookId);
}
private void SetupHotkey()
{
keyHookId = HotKeyManager.RegisterHotKey(Keys.Oemtilde, KeyModifiers.Control);
HotKeyManager.HotKeyPressed += new EventHandler<HotKeyEventArgs>(HotKeyManager_HotKeyPressed);
}
void HotKeyManager_HotKeyPressed(object sender, HotKeyEventArgs e)
{
//never executed
System.IO.File.WriteAllText("c:\\keyPressed.txt", "Hotkey pressed");
}
private static void InitPowershell(string[] args)
{
var config = RunspaceConfiguration.Create();
ConsoleShell.Start(config, "", "", args);
}
}
What you can do is Create a hidden window in your Console application which is used to handle the hotkey notification and raise an event.
The code HERE demonstrates the principal. HERE is an article on handling messages in a Console application, using this you should be able to enhance HotKeyManager to run in a Console Application.
The following update to the HotKeyManager creates a background thread which runs the message loop and handles the windows messages.
using System;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using System.Threading;
namespace ConsoleHotKey
{
public static class HotKeyManager
{
public static event EventHandler<HotKeyEventArgs> HotKeyPressed;
public static int RegisterHotKey(Keys key, KeyModifiers modifiers)
{
_windowReadyEvent.WaitOne();
int id = System.Threading.Interlocked.Increment(ref _id);
_wnd.Invoke(new RegisterHotKeyDelegate(RegisterHotKeyInternal), _hwnd, id, (uint)modifiers, (uint)key);
return id;
}
public static void UnregisterHotKey(int id)
{
_wnd.Invoke(new UnRegisterHotKeyDelegate(UnRegisterHotKeyInternal), _hwnd, id);
}
delegate void RegisterHotKeyDelegate(IntPtr hwnd, int id, uint modifiers, uint key);
delegate void UnRegisterHotKeyDelegate(IntPtr hwnd, int id);
private static void RegisterHotKeyInternal(IntPtr hwnd, int id, uint modifiers, uint key)
{
RegisterHotKey(hwnd, id, modifiers, key);
}
private static void UnRegisterHotKeyInternal(IntPtr hwnd, int id)
{
UnregisterHotKey(_hwnd, id);
}
private static void OnHotKeyPressed(HotKeyEventArgs e)
{
if (HotKeyManager.HotKeyPressed != null)
{
HotKeyManager.HotKeyPressed(null, e);
}
}
private static volatile MessageWindow _wnd;
private static volatile IntPtr _hwnd;
private static ManualResetEvent _windowReadyEvent = new ManualResetEvent(false);
static HotKeyManager()
{
Thread messageLoop = new Thread(delegate()
{
Application.Run(new MessageWindow());
});
messageLoop.Name = "MessageLoopThread";
messageLoop.IsBackground = true;
messageLoop.Start();
}
private class MessageWindow : Form
{
public MessageWindow()
{
_wnd = this;
_hwnd = this.Handle;
_windowReadyEvent.Set();
}
protected override void WndProc(ref Message m)
{
if (m.Msg == WM_HOTKEY)
{
HotKeyEventArgs e = new HotKeyEventArgs(m.LParam);
HotKeyManager.OnHotKeyPressed(e);
}
base.WndProc(ref m);
}
protected override void SetVisibleCore(bool value)
{
// Ensure the window never becomes visible
base.SetVisibleCore(false);
}
private const int WM_HOTKEY = 0x312;
}
[DllImport("user32", SetLastError=true)]
private static extern bool RegisterHotKey(IntPtr hWnd, int id, uint fsModifiers, uint vk);
[DllImport("user32", SetLastError = true)]
private static extern bool UnregisterHotKey(IntPtr hWnd, int id);
private static int _id = 0;
}
public class HotKeyEventArgs : EventArgs
{
public readonly Keys Key;
public readonly KeyModifiers Modifiers;
public HotKeyEventArgs(Keys key, KeyModifiers modifiers)
{
this.Key = key;
this.Modifiers = modifiers;
}
public HotKeyEventArgs(IntPtr hotKeyParam)
{
uint param = (uint)hotKeyParam.ToInt64();
Key = (Keys)((param & 0xffff0000) >> 16);
Modifiers = (KeyModifiers)(param & 0x0000ffff);
}
}
[Flags]
public enum KeyModifiers
{
Alt = 1,
Control = 2,
Shift = 4,
Windows = 8,
NoRepeat = 0x4000
}
}
Here is an example of using HotKeyManager from a Console application
using System;
using System.Windows.Forms;
namespace ConsoleHotKey
{
class Program
{
static void Main(string[] args)
{
HotKeyManager.RegisterHotKey(Keys.A, KeyModifiers.Alt);
HotKeyManager.HotKeyPressed += new EventHandler<HotKeyEventArgs>(HotKeyManager_HotKeyPressed);
Console.ReadLine();
}
static void HotKeyManager_HotKeyPressed(object sender, HotKeyEventArgs e)
{
Console.WriteLine("Hit me!");
}
}
}
I just wanted to offer an alternative solution.
I was answering a question for someone who was using this script and I figured this might help someone else who has trouble setting up a global key hook.
Edit: Don't forget to add a reference to System.Windows.Forms
You can do this by selecting Project🢂Add Reference and checking System.Windows.Forms
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Windows.Forms;
namespace ConsoleKeyhook
{
class Hooky
{
///////////////////////////////////////////////////////////
//A bunch of DLL Imports to set a low level keyboard hook
///////////////////////////////////////////////////////////
[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);
////////////////////////////////////////////////////////////////
//Some constants to make handling our hook code easier to read
////////////////////////////////////////////////////////////////
private const int WH_KEYBOARD_LL = 13; //Type of Hook - Low Level Keyboard
private const int WM_KEYDOWN = 0x0100; //Value passed on KeyDown
private const int WM_KEYUP = 0x0101; //Value passed on KeyUp
private static LowLevelKeyboardProc _proc = HookCallback; //The function called when a key is pressed
private static IntPtr _hookID = IntPtr.Zero;
private static bool CONTROL_DOWN = false; //Bool to use as a flag for control key
public static void Main()
{
_hookID = SetHook(_proc); //Set our hook
Application.Run(); //Start a standard application method loop
}
private 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);
}
}
private delegate IntPtr LowLevelKeyboardProc(int nCode, IntPtr wParam, IntPtr lParam);
private static IntPtr HookCallback(int nCode, IntPtr wParam, IntPtr lParam)
{
if (nCode >= 0 && wParam == (IntPtr)WM_KEYDOWN) //A Key was pressed down
{
int vkCode = Marshal.ReadInt32(lParam); //Get the keycode
string theKey = ((Keys)vkCode).ToString(); //Name of the key
Console.Write(theKey); //Display the name of the key
if (theKey.Contains("ControlKey")) //If they pressed control
{
CONTROL_DOWN = true; //Flag control as down
}
else if (CONTROL_DOWN && theKey == "B") //If they held CTRL and pressed B
{
Console.WriteLine("\n***HOTKEY PRESSED***"); //Our hotkey was pressed
}
else if (theKey == "Escape") //If they press escape
{
UnhookWindowsHookEx(_hookID); //Release our hook
Environment.Exit(0); //Exit our program
}
}
else if (nCode >= 0 && wParam == (IntPtr)WM_KEYUP) //KeyUP
{
int vkCode = Marshal.ReadInt32(lParam); //Get Keycode
string theKey = ((Keys)vkCode).ToString(); //Get Key name
if (theKey.Contains("ControlKey")) //If they let go of control
{
CONTROL_DOWN = false; //Unflag control
}
}
return CallNextHookEx(_hookID, nCode, wParam, lParam); //Call the next hook
}
}
}
I came up with a solution based on Chris' answer that uses WPF instead of WinForms:
public sealed class GlobalHotkeyRegister : IGlobalHotkeyRegister, IDisposable
{
private const int WmHotkey = 0x0312;
private Application _app;
private readonly Dictionary<Hotkey, Action> _hotkeyActions;
public GlobalHotkeyRegister()
{
_hotkeyActions = new Dictionary<Hotkey, Action>();
var startupTcs = new TaskCompletionSource<object>();
Task.Run(() =>
{
ComponentDispatcher.ThreadPreprocessMessage += OnThreadPreProcessMessage;
_app = new Application();
_app.Startup += (s, e) => startupTcs.SetResult(null);
_app.Run();
});
startupTcs.Task.Wait();
}
public void Add(Hotkey hotkey, Action action)
{
_hotkeyActions.Add(hotkey, action);
var keyModifier = (int) hotkey.KeyModifier;
var key = KeyInterop.VirtualKeyFromKey(hotkey.Key);
_app.Dispatcher.Invoke(() =>
{
if (!RegisterHotKey(IntPtr.Zero, hotkey.GetHashCode(), keyModifier, key))
throw new Win32Exception(Marshal.GetLastWin32Error());
});
}
public void Remove(Hotkey hotkey)
{
_hotkeyActions.Remove(hotkey);
_app.Dispatcher.Invoke(() =>
{
if (!UnregisterHotKey(IntPtr.Zero, hotkey.GetHashCode()))
throw new Win32Exception(Marshal.GetLastWin32Error());
});
}
private void OnThreadPreProcessMessage(ref MSG msg, ref bool handled)
{
if (msg.message != WmHotkey)
return;
var key = KeyInterop.KeyFromVirtualKey(((int) msg.lParam >> 16) & 0xFFFF);
var keyModifier = (KeyModifier) ((int) msg.lParam & 0xFFFF);
var hotKey = new Hotkey(keyModifier, key);
_hotkeyActions[hotKey]();
}
public void Dispose()
{
_app.Dispatcher.InvokeShutdown();
}
[DllImport("user32.dll", SetLastError = true)]
private static extern bool RegisterHotKey(IntPtr hWnd, int id, int fsModifiers, int vlc);
[DllImport("user32.dll", SetLastError = true)]
private static extern bool UnregisterHotKey(IntPtr hWnd, int id);
}
public class Hotkey
{
public Hotkey(KeyModifier keyModifier, Key key)
{
KeyModifier = keyModifier;
Key = key;
}
public KeyModifier KeyModifier { get; }
public Key Key { get; }
#region ToString(), Equals() and GetHashcode() overrides
}
[Flags]
public enum KeyModifier
{
None = 0x0000,
Alt = 0x0001,
Ctrl = 0x0002,
Shift = 0x0004,
Win = 0x0008,
NoRepeat = 0x4000
}
To use this, you need to add references to PresentationFramework.dll and WindowsBase.dll.
public static void Main()
{
using (var hotkeyManager = new GlobalHotkeyManager())
{
var hotkey = new Hotkey(KeyModifier.Ctrl | KeyModifier.Alt, Key.S);
hotkeyManager.Add(hotkey, () => System.Console.WriteLine(hotkey));
System.Console.ReadKey();
}
}
Changed the HotKeyManager class
public static class HotKeyManager
{
public static event EventHandler<HotKeyEventArgs> HotKeyPressed;
public static int RegisterHotKey(Keys key, HotKeyEventArgs.KeyModifiers modifiers)
{
_windowReadyEvent.WaitOne();
_wnd.Invoke(new RegisterHotKeyDelegate(RegisterHotKeyInternal), _hwnd, Interlocked.Increment(ref _id), (uint)modifiers, (uint)key);
return Interlocked.Increment(ref _id);
}
public static void UnregisterHotKey(int id)
{
_wnd.Invoke(new UnRegisterHotKeyDelegate(UnRegisterHotKeyInternal), _hwnd, id);
}
private delegate void RegisterHotKeyDelegate(IntPtr hwnd, int id, uint modifiers, uint key);
private delegate void UnRegisterHotKeyDelegate(IntPtr hwnd, int id);
private static void RegisterHotKeyInternal(IntPtr hwnd, int id, uint modifiers, uint key)
{
RegisterHotKey(hWnd: hwnd, id: id, fsModifiers: modifiers, vk: key);
}
private static void UnRegisterHotKeyInternal(IntPtr hwnd, int id)
{
UnregisterHotKey(_hwnd, id);
}
private static void OnHotKeyPressed(HotKeyEventArgs e)
{
HotKeyPressed?.Invoke(null, e);
}
private static volatile MessageWindow _wnd;
private static volatile IntPtr _hwnd;
private static ManualResetEvent _windowReadyEvent = new ManualResetEvent(false);
static HotKeyManager()
{
new Thread(delegate ()
{
Application.Run(new MessageWindow());
})
{
Name = "MessageLoopThread",
IsBackground = true
}.Start();
}
private class MessageWindow : Form
{
public MessageWindow()
{
_wnd = this;
_hwnd = Handle;
_windowReadyEvent.Set();
}
protected override void WndProc(ref Message m)
{
if (m.Msg == WM_HOTKEY)
{
var e = new HotKeyEventArgs(hotKeyParam: m.LParam);
OnHotKeyPressed(e);
}
base.WndProc(m: ref m);
}
protected override void SetVisibleCore(bool value)
{
// Ensure the window never becomes visible
base.SetVisibleCore(false);
}
private const int WM_HOTKEY = 0x312;
}
[DllImport("user32", SetLastError = true)]
private static extern bool RegisterHotKey(IntPtr hWnd, int id, uint fsModifiers, uint vk);
[DllImport("user32", SetLastError = true)]
private static extern bool UnregisterHotKey(IntPtr hWnd, int id);
private static int _id = 0;
}
Class HotKeyEventArgs:
public partial class HotKeyEventArgs : EventArgs
{
public readonly Keys Key;
public readonly KeyModifiers Modifiers;
public HotKeyEventArgs(Keys key, KeyModifiers modifiers)
{
Key = key;
Modifiers = modifiers;
}
public HotKeyEventArgs(IntPtr hotKeyParam)
{
Key = (Keys)(((uint)hotKeyParam.ToInt64() & 0xffff0000) >> 16);
Modifiers = (KeyModifiers)((uint)hotKeyParam.ToInt64() & 0x0000ffff);
}
}
And class: HotKeyEventArgs
public partial class HotKeyEventArgs
{
[Flags]
public enum KeyModifiers
{
Alt = 1,
Control = 2,
Shift = 4,
Windows = 8,
NoRepeat = 0x4000
}
}

Categories