My Solution
[DllImport("user32.dll")]
public static extern bool RegisterHotKey(IntPtr hWnd, int id, uint fsModifiers, int vk);
[DllImport("user32.dll")]
public static extern bool UnregisterHotKey(IntPtr hWnd, int id);
public enum KeyModifiers : uint { None = 0, Alt = 1, Control = 2, Shift = 4, Windows = 8, }
Actions<int, string> Directories = new Dictionary<int, string>();
const string MessageTitle = "Opps, Somthing Happened!";
const MessageBoxButtons msgButtons = MessageBoxButtons.OK;
const MessageBoxIcon msgIcon = MessageBoxIcon.Information;
private void btnCreateShortcut_Click(object sender, EventArgs e)
{
if (cboModifier.SelectedIndex > 0)
{
uint key = (uint)Enum.Parse(typeof(KeyModifiers), cboModifier.SelectedItem.ToString());
if (txtShortcutKey.Text != "")
CreateHotKey(key, txtShortcutKey.Text.ToString());
else
MessageBox.Show("Please enter a Hot key to use", MessageTitle, msgButtons, msgIcon);
}
else
MessageBox.Show("Please Select a Base Key", MessageTitle, msgButtons, msgIcon);
}
private void btnDestroyShortcuts_Click(object sender, EventArgs e)
{
destroyShortcuts();
}
private void quickActions_FormClosing(object sender, FormClosingEventArgs e)
{
destroyShortcuts();
}
protected override void WndProc(ref Message msg)
{
switch (msg.Msg)
{
case 0x0312:
if (Actions.ContainsKey((int)msg.WParam))
// Preform Action
break;
}
base.WndProc(ref msg);
}
public void destroyShortcuts()
{
foreach (KeyValuePair<int, string> pair in Actions)
UnregisterHotKey(this.Handle, pair.Key);
lstActiveKeys.Items.Clear();
Actions.Clear();
}
public void CreateHotKey(uint modifier, string key)
{
int keyID = (Actions.Count + 1) * 100;
Actions.Add(keyID, txtAction.Text.ToString());
lstActiveKeys.Items.Add(modifier + "+" + key[0] + " - " + txtAction.Text.ToString());
RegisterHotKey(this.Handle, keyID, modifier, (int)((char)key[0]));
}
I would like to know how to make it so that my users could define their own hot keys given the options for select a control key and a letter.
All of the code I found showed how to define one single hot key, but one users could have 3 and another could have 5 and they may not be the same keys.
What I would like, is given a control key and a alphanumeric key I can create a Windows Hot Key.
I also need to be able to destroy the registered keys when the application is closed.
PS: These needs to be system-wide not just within the application. Thanks #scott-chapman for pointing that out
This is a link to a VS2010 project that does just that. I wrote it last year. File is hosted on SkyDrive.
http://sdrv.ms/Wc2R5H
Here is the solution I developed this is a C# method that appears to be working rather nicely.
[DllImport("user32.dll")]
public static extern bool RegisterHotKey(IntPtr hWnd, int id, uint fsModifiers, int vk);
[DllImport("user32.dll")]
public static extern bool UnregisterHotKey(IntPtr hWnd, int id);
public enum KeyModifiers : uint { None = 0, Alt = 1, Control = 2, Shift = 4, Windows = 8, }
Actions<int, string> Directories = new Dictionary<int, string>();
const string MessageTitle = "Opps, Somthing Happened!";
const MessageBoxButtons msgButtons = MessageBoxButtons.OK;
const MessageBoxIcon msgIcon = MessageBoxIcon.Information;
private void btnCreateShortcut_Click(object sender, EventArgs e)
{
if (cboModifier.SelectedIndex > 0)
{
uint key = (uint)Enum.Parse(typeof(KeyModifiers), cboModifier.SelectedItem.ToString());
if (txtShortcutKey.Text != "")
CreateHotKey(key, txtShortcutKey.Text.ToString());
else
MessageBox.Show("Please enter a Hot key to use", MessageTitle, msgButtons, msgIcon);
}
else
MessageBox.Show("Please Select a Base Key", MessageTitle, msgButtons, msgIcon);
}
private void btnDestroyShortcuts_Click(object sender, EventArgs e)
{
destroyShortcuts();
}
private void quickActions_FormClosing(object sender, FormClosingEventArgs e)
{
destroyShortcuts();
}
protected override void WndProc(ref Message msg)
{
switch (msg.Msg)
{
case 0x0312:
if (Actions.ContainsKey((int)msg.WParam))
// Preform Action
break;
}
base.WndProc(ref msg);
}
public void destroyShortcuts()
{
foreach (KeyValuePair<int, string> pair in Actions)
UnregisterHotKey(this.Handle, pair.Key);
lstActiveKeys.Items.Clear();
Actions.Clear();
}
public void CreateHotKey(uint modifier, string key)
{
int keyID = (Actions.Count + 1) * 100;
Actions.Add(keyID, txtAction.Text.ToString());
lstActiveKeys.Items.Add(modifier + "+" + key[0] + " - " + txtAction.Text.ToString());
RegisterHotKey(this.Handle, keyID, modifier, (int)((char)key[0]));
}
Related
I'm making a windows form application and I need to detect if a key is pressed (Globally), so I ended up with using hotkeys and everything works fine. I registered key 'V' as the hotkey and when I press it my app can detect it. But the problem is when I press V while I'm holding 'Shift' or 'Control' , my app won't detect the key press anymore.
I found a way to also register modifier keys, but I can only register one combination , and if I register multiple combinations like :"V" ,"Control + V" ,and "Shift + V" , only the last one works but I want my app to detect 'V' in any combination.
Here is the code I use for Registering hotkeys(Found on the internet)
private class KeyHandler
{
[DllImport("user32.dll")]
private static extern bool RegisterHotKey(IntPtr hWnd, int id, int fsModifiers, int vk);
private readonly int _key;
private readonly IntPtr _hWnd;
private readonly int _id;
private readonly int _modifier;
public KeyHandler(Keys key, KeyModifiers modifier, Form form)
{
_key = (int)key;
_modifier = (int)modifier;
_hWnd = form.Handle;
_id = GetHashCode();
}
public sealed override int GetHashCode()
{
return _key ^ _hWnd.ToInt32();
}
public void Register()
{
RegisterHotKey(_hWnd, _id, _modifier, _key);
}
}
public enum KeyModifiers : int
{
None = 0,
Alt = 1,
Control = 2,
Shift = 4,
Win = 8
}
private static int WM_HOTKEY = 0x0312;
protected override void WndProc(ref Message m)
{
if (m.Msg == WM_HOTKEY)
{
HandleHotkey();
}
base.WndProc(ref m);
}
//On Press
private void HandleHotkey()
{
}
private void Form1_Load(object sender, EventArgs e)
{
//Register hotkey
new KeyHandler(Keys.V, 0, this).Register();
}
Is there any way to detect a key press globally even if the key is pressed with modifiers?
Thanks to Hans Passant's comment, I found this source code on Github which allows you to capture keyboard events.
https://github.com/rvknth043/Global-Low-Level-Key-Board-And-Mouse-Hook
I just start C# and I wanted to make a Form App which gets a key from user, within the TextBox, then somehow bind that key and with SendKeys(), spam a specific key that I set in codes e.g(e), I use this code but the Keyboard.isKeyDown(Key.key) wants me an enum of "Key" and TexBox returns a string and even I converted the string to an enum but it just want me a key from its own Key enum, my question is how to pass a variable key to the Keyboard.isKeyDown(Key.key) maybe totally my way is not right, can you help me with these codes or suggest another way to make this app?
Here's the code:
using System;
using System.Windows.Forms;
using System.Windows.Input;
using System.Threading;
using System.Runtime.InteropServices;
namespace WindowsFormsApp1
{
public partial class Form1 : Form
{
[DllImport("USER32.DLL", CharSet = CharSet.Unicode)]
public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
[DllImport("USER32.DLL")]
public static extern bool SetForegroundWindow(IntPtr hWnd);
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
Thread TH = new Thread(PressBind);
TH.SetApartmentState(ApartmentState.STA);
CheckForIllegalCrossThreadCalls = false;
TH.Start();
}
//i want to get the key from this textbox
public void TxBxKTB_TextChanged(object sender, EventArgs e)
{
label2.Text = $"The binded key is : {TxBxKTB.Text.ToString()}";
TextBox objTextBox = (TextBox)sender;
string text = objTextBox.Text;
var TextBoxText = Enum.Parse(typeof(Keys), text);
}
//void setforground()
//{
// IntPtr Calculator = FindWindow("Windows.UI.Core.CoreWindow", "Calculator");
// SetForegroundWindow(Calculator);
//}
bool isRunning = true;
void Keyboard()
{
while (isRunning)
{
Thread.Sleep(40);
if (Keyboard.IsKeyDown(Key.I want to set the users input key here))
{
label1.Text = "pressed";
Thread.Sleep(40);
SendKeys.SendWait("e");
}
}
}
private void Form1_FormClosed(object sender, FormClosedEventArgs e)
{
isRunning = false;
}
}
}
UPDATE
You could use Enum.Parse method to convert string to Key enum. It's safer to use TryParse to handle situations when string can't be converted to Key.
void Z()
{
string key_string = "F10";
if (Enum.TryParse(key_string, out Key key))
{
if (Keyboard.IsKeyDown(key))
{
// some logic
}
}
else
{
// ERROR: the string couldn't be converted to Key
}
}
I have a problem about restore state of window when I maximized it on secondary monitor.
I maximized window on the not primary screen and then close.
When reopen window, it also maximized, but it is maximized on primary screen.
I want is maximized on the not primary screen (the screen display window when close).
Please help me if you know.
Note: if state of window is normal, window will be restored correct screen.
My code as below:
if (ShellState == WindowState.Maximized)
{
ShellState = WindowState.Normal;
LeftPosition = Screen.AllScreens[selectedScreen].WorkingArea.Left;
TopPosition = Screen.AllScreens[selectedScreen].WorkingArea.Top;
ShellHeight = Screen.AllScreens[selectedScreen].WorkingArea.Height;
ShellWidth = Screen.AllScreens[selectedScreen].WorkingArea.Width;
ShellState = WindowState.Maximized;
}
We had many problems on multi-screen systems using the standard WPF tools for storing and restoring the window state and size, as long as the screen assignment.
We endet with creating a custom behavior that uses the native WinAPI functions.
Here is the (simplified) source code of our behavior. You can use it in your application instead of the WPF tools.
You have to change the way the window placement will be stored. This can be a dependency property providing a container, a static Properties.Settings reference or something else. In the code below, a static ApplicationSettings reference is used as an example.
class WindowPlacementPersistenceBehavior : Behavior<Window>
{
protected override void OnAttached()
{
base.OnAttached();
this.AssociatedObject.SourceInitialized += this.AssociatedObject_SourceInitialized;
this.AssociatedObject.Closing += this.AssociatedObject_Closing;
}
protected override void OnDetaching()
{
this.AssociatedObject.SourceInitialized -= this.AssociatedObject_SourceInitialized;
this.AssociatedObject.Closing -= this.AssociatedObject_Closing;
base.OnDetaching();
}
private void AssociatedObject_Closing(object sender, CancelEventArgs e)
{
WINDOWPLACEMENT wp;
NativeMethods.GetWindowPlacement(new WindowInteropHelper(this.AssociatedObject).Handle, out wp);
// Here you can store the window placement
ApplicationSettings.WindowPlacement = wp.ToString();
}
private void AssociatedObject_SourceInitialized(object sender, EventArgs e)
{
// Here you can load the window placement
WINDOWPLACEMENT wp = WINDOWPLACEMENT.Parse(ApplicationSettings.WindowPlacement);
if (wp.ShowCmd == NativeMethods.SW_SHOWMINIMIZED)
{
// Don't start in the minimized state
wp.ShowCmd = NativeMethods.SW_SHOWNORMAL;
}
try
{
NativeMethods.SetWindowPlacement(new WindowInteropHelper(this.AssociatedObject).Handle, ref wp);
}
catch
{
}
}
[Serializable]
[StructLayout(LayoutKind.Sequential)]
private struct RECT
{
public int Left;
public int Top;
public int Right;
public int Bottom;
public static RECT Parse(string input)
{
RECT result;
string[] items = input.Split(';');
result.Left = int.Parse(items[0]);
result.Top = int.Parse(items[1]);
result.Right = int.Parse(items[2]);
result.Bottom = int.Parse(items[3]);
return result;
}
public override string ToString()
{
return this.Left + ";" + this.Top + ";" + this.Right + ";" + this.Bottom;
}
}
[Serializable]
[StructLayout(LayoutKind.Sequential)]
private struct POINT
{
public int X;
public int Y;
public static POINT Parse(string input)
{
POINT result;
string[] items = input.Split(';');
result.X = int.Parse(items[0]);
result.Y = int.Parse(items[1]);
return result;
}
public override string ToString()
{
return this.X + ";" + this.Y;
}
}
[Serializable]
[StructLayout(LayoutKind.Sequential)]
private struct WINDOWPLACEMENT
{
public int Length;
public int Flags;
public int ShowCmd;
public POINT MinPosition;
public POINT MaxPosition;
public RECT NormalPosition;
public static WINDOWPLACEMENT Parse(string input)
{
WINDOWPLACEMENT result = default(WINDOWPLACEMENT);
result.Length = Marshal.SizeOf(typeof(WINDOWPLACEMENT));
try
{
string[] items = input.Split('/');
result.Flags = int.Parse(items[0]);
result.ShowCmd = int.Parse(items[1]);
result.MinPosition = POINT.Parse(items[2]);
result.MaxPosition = POINT.Parse(items[3]);
result.NormalPosition = RECT.Parse(items[4]);
}
catch
{
}
return result;
}
public override string ToString()
{
return this.Flags + "/" + this.ShowCmd + "/" + this.MinPosition.ToString() + "/" + this.MaxPosition.ToString() + "/" + this.NormalPosition.ToString();
}
}
private static class NativeMethods
{
public const int SW_SHOWNORMAL = 1;
public const int SW_SHOWMINIMIZED = 2;
[DllImport("user32.dll")]
public static extern bool SetWindowPlacement(IntPtr hWnd, [In] ref WINDOWPLACEMENT lpwndpl);
[DllImport("user32.dll")]
public static extern bool GetWindowPlacement(IntPtr hWnd, [Out] out WINDOWPLACEMENT lpwndpl);
}
}
To use this behavior, just add it to your window in XAML:
<Window
xmlns:v="clr-namespace:YourNameSpace"
xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity">
<i:Interaction.Behaviors>
<v:WindowPlacementPersistenceBehavior />
</i:Interaction.Behaviors>
</Window>
I have searched online for this, but can't find nothing at all.
What I would like to do is to create a keyboard shortcut that I would be able to use in all applications. A universal keyboard shortcut, so that when I press, say Ctrl+Shift+X in any application, it would execute a piece of code I created in C#. For example, when I'm in Skype, I would select text and press Ctrl+Shift+X (or whatever other key combination), it would change the color of the text from black to blue. That is just an example to try and explain what I want to do. I'm thinking I would have to import a DLL and edit that (maybe user32.dll?) I'm just guessing. I have no clue how to do this, so any help will be greatly appreciated!
Thanks a lot in advance :)
PS: I am using Windows Forms Application, .NET Framework 4.0. Unclear about something I am trying to do/say? Please feel free to comment and I will get back to you right away.
Win32 has a RegisterHotKey function as part of the Win32 API. To use it in managed code (C#), you'd have to pInvoke it. Here is an example:
public class WindowsShell
{
#region fields
public static int MOD_ALT = 0x1;
public static int MOD_CONTROL = 0x2;
public static int MOD_SHIFT = 0x4;
public static int MOD_WIN = 0x8;
public static int WM_HOTKEY = 0x312;
#endregion
[DllImport("user32.dll")]
private static extern bool RegisterHotKey(IntPtr hWnd, int id, int fsModifiers, int vlc);
[DllImport("user32.dll")]
private static extern bool UnregisterHotKey(IntPtr hWnd, int id);
private static int keyId;
public static void RegisterHotKey(Form f, Keys key)
{
int modifiers = 0;
if ((key & Keys.Alt) == Keys.Alt)
modifiers = modifiers | WindowsShell.MOD_ALT;
if ((key & Keys.Control) == Keys.Control)
modifiers = modifiers | WindowsShell.MOD_CONTROL;
if ((key & Keys.Shift) == Keys.Shift)
modifiers = modifiers | WindowsShell.MOD_SHIFT;
Keys k = key & ~Keys.Control & ~Keys.Shift & ~Keys.Alt;
keyId = f.GetHashCode(); // this should be a key unique ID, modify this if you want more than one hotkey
RegisterHotKey((IntPtr)f.Handle, keyId, (uint)modifiers, (uint)k);
}
private delegate void Func();
public static void UnregisterHotKey(Form f)
{
try
{
UnregisterHotKey(f.Handle, keyId); // modify this if you want more than one hotkey
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}
}
}
public partial class Form1 : Form, IDisposable
{
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
Keys k = Keys.A | Keys.Control;
WindowsShell.RegisterHotKey(this, k);
}
// CF Note: The WndProc is not present in the Compact Framework (as of vers. 3.5)! please derive from the MessageWindow class in order to handle WM_HOTKEY
protected override void WndProc(ref Message m)
{
base.WndProc(ref m);
if (m.Msg == WindowsShell.WM_HOTKEY)
this.Visible = !this.Visible;
}
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
WindowsShell.UnregisterHotKey(this);
}
}
This code came from this article. Read that article for more information and more examples.
I my program I need to capture when the Print Screen key is pressed down but it is not working (however it works with other keys).
I guess this has something to do with windows hijacking my authority and since im still new at this I'd love to know how I can get around this issue.
Here's my current code:
namespace Boom_Screenshot_
{
/// <summary>
/// Interaction logic for Window1.xaml
/// </summary>
public partial class Window1 : Window
{
//SETTINGS
Key TRIGGER_KEY = Key.PrintScreen;
public Window1()
{
InitializeComponent();
}
private void Window_KeyDown(object sender, KeyEventArgs e)
{
if (e.Key == TRIGGER_KEY)
{
MessageBox.Show("'PrintScreen' was pressed.");
}
}
}
}
I have an answer for you that I found here (I don't speak Chinese so don't ask me what it says :). You have to set a hook. He provides a wrapper class. I repeat some code here without the Chinese characters. RegisterHotKey.cs ...
using System;
using System.Runtime.InteropServices;
using System.Windows.Forms;
namespace TestKeydown
{
public class RegisterHotKeyClass
{
private IntPtr m_WindowHandle = IntPtr.Zero;
private MODKEY m_ModKey = MODKEY.MOD_CONTROL;
private Keys m_Keys = Keys.A;
private int m_WParam = 10000;
private bool Star = false;
private HotKeyWndProc m_HotKeyWnd = new HotKeyWndProc();
public IntPtr WindowHandle
{
get { return m_WindowHandle; }
set { if (Star)return; m_WindowHandle = value; }
}
public MODKEY ModKey
{
get { return m_ModKey; }
set { if (Star)return; m_ModKey = value; }
}
public Keys Keys
{
get { return m_Keys; }
set { if (Star)return; m_Keys = value; }
}
public int WParam
{
get { return m_WParam; }
set { if (Star)return; m_WParam = value; }
}
public void StarHotKey()
{
if (m_WindowHandle != IntPtr.Zero)
{
if (!RegisterHotKey(m_WindowHandle, m_WParam, m_ModKey, m_Keys))
{
throw new Exception("");
}
try
{
m_HotKeyWnd.m_HotKeyPass = new HotKeyPass(KeyPass);
m_HotKeyWnd.m_WParam = m_WParam;
m_HotKeyWnd.AssignHandle(m_WindowHandle);
Star = true;
}
catch
{
StopHotKey();
}
}
}
private void KeyPass()
{
if (HotKey != null) HotKey();
}
public void StopHotKey()
{
if (Star)
{
if (!UnregisterHotKey(m_WindowHandle, m_WParam))
{
throw new Exception("");
}
Star = false;
m_HotKeyWnd.ReleaseHandle();
}
}
public delegate void HotKeyPass();
public event HotKeyPass HotKey;
private class HotKeyWndProc : NativeWindow
{
public int m_WParam = 10000;
public HotKeyPass m_HotKeyPass;
protected override void WndProc(ref Message m)
{
if (m.Msg == 0x0312 && m.WParam.ToInt32() == m_WParam)
{
if (m_HotKeyPass != null) m_HotKeyPass.Invoke();
}
base.WndProc(ref m);
}
}
public enum MODKEY
{
MOD_ALT = 0x0001,
MOD_CONTROL = 0x0002,
MOD_SHIFT = 0x0004,
MOD_WIN = 0x0008,
}
[DllImport("user32.dll")]
public static extern bool RegisterHotKey(IntPtr wnd, int id, MODKEY mode, Keys vk);
[DllImport("user32.dll")]
public static extern bool UnregisterHotKey(IntPtr wnd, int id);
}
}
Calling code in a Form ...
private RegisterHotKeyClass _RegisKey = new RegisterHotKeyClass();
void _Regis_HotKey()
{
MessageBox.Show("ok");
}
private void Form1_Load(object sender, EventArgs e)
{
_RegisKey.Keys = Keys.PrintScreen;
_RegisKey.ModKey = 0;
_RegisKey.WindowHandle = this.Handle;
_RegisKey.HotKey += new RegisterHotKeyClass.HotKeyPass(_Regis_HotKey);
_RegisKey.StarHotKey();
}
Below is my pure WPF solution.
We can achieve this in xaml by using NavigationCommands (Namespace: System.Window.Input) class which provides a standard set of navigation commands (e.g. NextPage, PreviousPage, Refresh, Search etc.)
Implementation Approach:
So we can call any custom code to execute on application refresh using NavigationCommands.Refresh as
<UserControl.CommandBindings>
<CommandBinding Command='NavigationCommands.Refresh'
Executed="ApplicationRefresh_Executed">
</CommandBinding>
</UserControl.CommandBindings>
Now in code behind class of UserControl we can define method as
private void ApplicationRefresh_Executed(object sender, ExecutedRoutedEventArgs e)
{
// Implementation goes here.
}