Global hotkeys in WPF working from every window - c#

I have to use hotkeys which will be working from every window and pulpit. In winforms I used:
RegisterHotKey(this.Handle, 9000, 0x0002, (int)Keys.F10);
and
UnregisterHotKey(this.Handle, 9000);
and
protected override void WndProc(ref Message m)
{
base.WndProc(ref m);
switch (m.Msg)
{
case 0x312:
switch (m.WParam.ToInt32())
{
case 9000:
//function to do
break;
}
break;
}
}
In my WPF aplication I tried do:
AddHandler(Keyboard.KeyDownEvent, (KeyEventHandler)HandleKeyDownEvent);
and
private void HandleKeyDownEvent(object sender, KeyEventArgs e)
{
if (e.Key == Key.F11 && (Keyboard.Modifiers & ModifierKeys.Control) == ModifierKeys.Control)
{
//function to do
}
}
But it works only when my application is active and on the top, but it doesn't work when the application is minimized (for example). Is any method to do it?

You can use the same approach as in WinForms with some adaptation:
use WindowInteropHelper to get HWND (instead of Handle property of a form)
use HwndSource to handle window messages (instead of overriding WndProc of a form)
don't use Key enumeration from WPF - it's values are not the ones you want
Complete code:
[DllImport("User32.dll")]
private static extern bool RegisterHotKey(
[In] IntPtr hWnd,
[In] int id,
[In] uint fsModifiers,
[In] uint vk);
[DllImport("User32.dll")]
private static extern bool UnregisterHotKey(
[In] IntPtr hWnd,
[In] int id);
private HwndSource _source;
private const int HOTKEY_ID = 9000;
protected override void OnSourceInitialized(EventArgs e)
{
base.OnSourceInitialized(e);
var helper = new WindowInteropHelper(this);
_source = HwndSource.FromHwnd(helper.Handle);
_source.AddHook(HwndHook);
RegisterHotKey();
}
protected override void OnClosed(EventArgs e)
{
_source.RemoveHook(HwndHook);
_source = null;
UnregisterHotKey();
base.OnClosed(e);
}
private void RegisterHotKey()
{
var helper = new WindowInteropHelper(this);
const uint VK_F10 = 0x79;
const uint MOD_CTRL = 0x0002;
if(!RegisterHotKey(helper.Handle, HOTKEY_ID, MOD_CTRL, VK_F10))
{
// handle error
}
}
private void UnregisterHotKey()
{
var helper = new WindowInteropHelper(this);
UnregisterHotKey(helper.Handle, HOTKEY_ID);
}
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:
OnHotKeyPressed();
handled = true;
break;
}
break;
}
return IntPtr.Zero;
}
private void OnHotKeyPressed()
{
// do stuff
}

Related

How can I register multiple hotkeys?

I am developing a WPF app, and searched how to register multiple hotkeys for hours. Ex) 1. Pressing CTRL+F1->mouse right click
2. Pressing CTRL+F2->mouse left click
However, I got no clear solutions for it.
I tried:
[DllImport("user32.dll")]
public static extern void mouse_event(int dwFlags, int dx, int dy, int cButtons, int dwExtraInfo);
[DllImport("user32.dll")]
private static extern bool RegisterHotKey(IntPtr hwnd, int id, uint fsModifiers, uint vk);
private HwndSource _source;
protected override void OnSourceInitialized(EventArgs e)
{
base.OnSourceInitialized(e);
var helper = new WindowInteropHelper(this);
_source = HwndSource.FromHwnd(helper.Handle);
_source.AddHook(HwndHook);
RegisterHotKey(helper.Handle, HOTKEY_ID, MOD_CTRL, VK_F10);
}
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:
//Something to do
handled = true;
break;
}
break;
}
return IntPtr.Zero;
}
Are you searching for something like this?
<Window.InputBindings>
<KeyBinding Key="F1" Modifiers="Ctrl" Command="{Binding MyCommand}" />
</Window.InputBindings>
Add handling for the command in your code behind.
Please refer to this blog post for an example of how to implement global hot keys in WPF:
private const uint VK_F1 = 0x70;
private const uint VK_F2 = 0x71;
protected override void OnSourceInitialized(EventArgs e)
{
base.OnSourceInitialized(e);
IntPtr handle = new WindowInteropHelper(this).Handle;
source = HwndSource.FromHwnd(handle);
source.AddHook(HwndHook);
const int HOTKEY_ID = 9000;
const uint MOD_CONTROL = 0x0002;
RegisterHotKey(handle, HOTKEY_ID, MOD_CONTROL, VK_F1); //CTRL + F1
}
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_F1)
{
//handle...
}
handled = true;
break;
}
break;
}
return 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();
}

make GlobalKeyboardHook class read string comes from 2D barcode scanner

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

c# Register Global Hotkeys without hook library (Keyboard Hooks)

I try to configure some global Hotkeys in a C# WinForm Application that should work with and without focus. For this I played a little bit with some Hooking Librarys like: Link
But these Libraries are not working really reliable so that I decided to look for a different way. And I found one but there is one problem: With the new method posted below I can catch a keypress, but I like to catch also the keydown (WM_KEYDOWN/0x100) and keyup event... But this is not working. Any ideas?
Code:
public Form1()
{
InitializeComponent();
}
[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);
const int MOD_CONTROL = 0x0002;
const int MOD_SHIFT = 0x0004;
const int WM_HOTKEY = 0x0312;
const int WM_KEYDOWN = 0x0100;
private void Form1_Load(object sender, EventArgs e)
{
// Hook Keys
RegisterHotKey(this.Handle, 1, MOD_CONTROL, (int)0);
RegisterHotKey(this.Handle, 2, MOD_CONTROL, (int)Keys.X);
}
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
UnregisterHotKey(this.Handle, 1);
}
protected override void WndProc(ref Message m)
{
if (m.Msg == WM_HOTKEY && (int)m.WParam == 1)
{
MessageBox.Show("here");
}
if (m.Msg == WM_KEYDOWN && (int)m.WParam == 2)
this.Opacity = 100;
base.WndProc(ref m);
}

Detect & Differentiate Clipboard Events (Cut,Copy and Paste)

is it possible for it to detect and differentiate cut,copy, or paste of files? I only can detect a change in the clipboard to far.
public partial class Form1 : Form
{
[DllImport("User32.dll", CharSet = CharSet.Auto)]
public static extern IntPtr SetClipboardViewer(IntPtr hWnd);
[DllImport("User32.dll", CharSet = CharSet.Auto)]
public static extern IntPtr ChangeClipboardChain(IntPtr hWndRemove, IntPtr hWndNewNext);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern int SendMessage(IntPtr hwnd, int wMsg, IntPtr wParam, IntPtr lParam);
private IntPtr _ClipboardViewerNext;
private const int WM_DRAWCLIPBOARD = 0x0308;
// private const int WM_CUT = 0x0301;
public Form1()
{
InitializeComponent();
}
private void StartClipboardViewer()
{
_ClipboardViewerNext = SetClipboardViewer(this.Handle);
}
private void StopClipboardViewer()
{
ChangeClipboardChain(this.Handle, _ClipboardViewerNext);
}
protected override void WndProc(ref Message m)
{
base.WndProc(ref m);
if (m.Msg == WM_DRAWCLIPBOARD)
{
MessageBox.Show("Copied");
SendMessage(_ClipboardViewerNext, m.Msg, m.WParam, m.LParam);
}
else
{
base.WndProc(ref m);
}
}
private void Form1_Load(object sender, EventArgs e)
{
StartClipboardViewer();
}
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
StopClipboardViewer();
}
}
No, but you could write a wrapper for the Clipboard (as it's a sealed class you can't derive from it) to keep track of the get/set operations.
The clipboard does not differentiate between cut and copy. It's a semantic difference in the way that the source application treats the data (or files).

Categories