How to stop further processing global hotkeys in C# - c#

I am trying to create a C# application that will react on a global hotkey; ALT+H and then when I release the ALT key. This actually does work very well but my problem is that when my application has done whatever it should do with the hotkey then it should stop this hotkey from being processed by other applications. I got most of my code below from this StackOverflow post, Global keyboard capture in C# application, but I have seen somewhere else that return (IntPtr)1; should be able to stop further processing of the key.
But... when I am in e.g. Word or Wordpad and I press ALT+H then Word shows all kind of menus - I don't want it to as I only want my application to do something :-)
I am sorry for this rather long code but I assume it is important so you can get the full overview. There is only 1 place where I use return (IntPtr)1;.
My code:
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using System.Windows.Input;
namespace MyNewProgram
{
static class Program
{
// Enable hotkeys
// https://stackoverflow.com/a/604417/2028935
private const int WH_KEYBOARD_LL = 13;
private const int WM_KEYDOWN = 0x0100;
private const int WM_KEYUP = 0x0101;
private const int WM_SYSKEYUP = 0x0105;
private const int VK_SHIFT = 0x10;
private const int VK_MENU = 0x12;
private static LowLevelKeyboardProc _proc = HookCallback;
private static IntPtr _hookID = IntPtr.Zero;
// Other variables
public static bool isAltPressedInThisApp = false;
private static MainWindow MyMainWindow;
// --------------------------------------------------------------------------------------
[STAThread] // STAThreadAttribute indicates that the COM threading model for the application is single-threaded apartment, https://stackoverflow.com/a/1361048/2028935
static void Main()
{
// Hook application to keyboard
_hookID = SetHook(_proc);
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
MyMainWindow = new MainWindow();
Application.Run(MyMainWindow);
// Unhook application from keyboard
UnhookWindowsHookEx(_hookID);
}
// --------------------------------------------------------------------------------------
// Required functions for globally hooking the keyboard
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern short GetKeyState(int keyCode);
[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);
private delegate IntPtr LowLevelKeyboardProc(int nCode, IntPtr wParam, IntPtr lParam);
// --------------------------------------------------------------------------------------
// Hook the keyboard - action
private static IntPtr HookCallback(int nCode, IntPtr wParam, IntPtr lParam)
{
// React on KEYDOWN
if (nCode >= 0 && ((wParam == (IntPtr)WM_KEYDOWN) || (wParam == (IntPtr)WM_SYSKEYUP)))
{
int vkCode = Marshal.ReadInt32(lParam);
// H
if ((Keys)vkCode == Keys.H)
{
isAltPressedInThisApp = true;
// Is ALT pressed down
if ((GetKeyState(VK_MENU) & 0x8000) != 0)
{
Console.WriteLine("ALT + H");
return (IntPtr)1; // do not allow others to hook this key combo
}
}
}
// React on KEYUP
if (nCode >= 0 && wParam == (IntPtr)WM_KEYUP)
{
int vkCode = Marshal.ReadInt32(lParam);
// Is ALT not pressed down
if ((Keys)vkCode == Keys.LMenu)
{
Console.WriteLine("ALT UP");
}
}
return CallNextHookEx(_hookID, nCode, wParam, lParam);
}
// --------------------------------------------------------------------------------------
// Hook the keyboard
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);
}
}
}
}
I am not a solid C# developer as I am taking my first few babysteps here - so why would I throw myself in the deep waters of global hotkeys as one of the first things ;-) Is there anyone that can give some hints here as I probably have a silly mistake somewhere?

The idea behind, whenever the alt key pressed, it starts to swallow keys into one local list. if the pattern we need to see has been seen, it won't send, but for the every other pattern, it starts to send the keys again in the order it receives.
the code for examination phase:
enum WM
{
WM_KEYDOWN = 0x0100,
WM_KEYUP = 0x0101,
WM_SYSKEYUP = 0x0105,
WM_SYSKEYDOWN = 0x0104,
}
private static IntPtr HookCallback(int nCode, IntPtr wParam, IntPtr lParam)
{
if (nCode < 0)
return CallNextHookEx(_hookID, nCode, wParam, lParam);
KBDLLHOOKSTRUCT kbd = (KBDLLHOOKSTRUCT)Marshal.PtrToStructure(lParam, typeof(KBDLLHOOKSTRUCT));
Enum.TryParse<Keys>($"{kbd.vkCode}", out Keys key);
Enum.TryParse<WM>($"{wParam}", out WM message);
Console.WriteLine($"{message}:{key}");
return CallNextHookEx(_hookID, nCode, wParam, lParam);
}
when pressing alt+h and releasing, output:
WM_SYSKEYDOWN:LMenu
WM_SYSKEYDOWN:H
WM_SYSKEYUP:H
WM_KEYUP:LMenu
as you can see, windows sent both alt and h key. the code you provided only catch H key, so the window which receives keyboard messages think that alt pressed.
no one can fetch and filter out previously pressed key, so we need to catch alt key whenever we see it is pressed. if the next key not H, we should send the keys we have fetched in the order we received.
i have written the below code to handle the situation, but i can not be pretty sure how it works on the real windows machine cause i have an osx operating system just because of that i am running windows in the virtual machine which is also change key strokes when i'm pressing.
if it's still not enough, you can wait and i may be able to try and figure it out at my office in the real windows machine. but i think you get the idea and work it out on your own.
[StructLayout(LayoutKind.Sequential)]
public class KBDLLHOOKSTRUCT
{
public uint vkCode;
public uint scanCode;
public KBDLLHOOKSTRUCTFlags flags;
public uint time;
public UIntPtr dwExtraInfo;
}
[Flags]
public enum KBDLLHOOKSTRUCTFlags : uint
{
LLKHF_EXTENDED = 0x01,
LLKHF_INJECTED = 0x10,
LLKHF_ALTDOWN = 0x20,
LLKHF_UP = 0x80,
}
[DllImport("user32.dll")]
static extern void keybd_event(byte bVk, byte bScan, uint dwFlags, UIntPtr dwExtraInfo);
enum WM
{
WM_KEYDOWN = 0x0100,
WM_KEYUP = 0x0101,
WM_SYSKEYUP = 0x0105,
WM_SYSKEYDOWN = 0x0104,
}
private static void ReSendKeys(int index = -1)
{
_index = -1;
var copiedKeys = _swallowedKeys.ToArray();
for (int i = 0; i < copiedKeys.Length; ++i)
{
bool up = copiedKeys[i].Item1 == (IntPtr)WM.WM_SYSKEYUP || copiedKeys[i].Item1 == (IntPtr)WM.WM_KEYUP;
keybd_event((byte)copiedKeys[i].Item2.vkCode, (byte)copiedKeys[i].Item2.scanCode, up ? 2u : 0u, UIntPtr.Zero);
}
_index = index;
_swallowedKeys.Clear();
}
private static List<Tuple<IntPtr, KBDLLHOOKSTRUCT>> _swallowedKeys = new List<Tuple<IntPtr, KBDLLHOOKSTRUCT>>();
private static int _index = 0;
private static IntPtr HookCallback(int nCode, IntPtr wParam, IntPtr lParam)
{
if (nCode < 0)
return CallNextHookEx(_hookID, nCode, wParam, lParam);
KBDLLHOOKSTRUCT kbd = (KBDLLHOOKSTRUCT)Marshal.PtrToStructure(lParam, typeof(KBDLLHOOKSTRUCT));
Enum.TryParse<Keys>($"{kbd.vkCode}", out Keys key);
Enum.TryParse<WM>($"{wParam}", out WM message);
Console.Write($"{message}:{key}");
// we know that when _index is -1, ReSendKeys function has been called
// so do not filter out first alt key
if (_index == -1)
{
_index++;
Console.WriteLine();
return CallNextHookEx(_hookID, nCode, wParam, lParam);
}
// we are at the beginning of the sequence we will catch
// if it's alt key filter it out, and increment the variable
if (_index == 0)
{
_swallowedKeys.Add(new Tuple<IntPtr, KBDLLHOOKSTRUCT>(wParam, kbd));
if (message == WM.WM_SYSKEYDOWN && key == Keys.LMenu)
{
_index++;
Console.WriteLine(" filtered out");
return (IntPtr)1;
}
else
{
_swallowedKeys.Clear();
// do nothing
}
}
if (_index == 1)
{
_swallowedKeys.Add(new Tuple<IntPtr, KBDLLHOOKSTRUCT>(wParam, kbd));
// if the next key is H, then filter it out also
if (message == WM.WM_SYSKEYDOWN && key == Keys.H)
{
_index++;
_swallowedKeys.RemoveAt(_swallowedKeys.Count - 1);
Console.WriteLine(" filtered out");
return (IntPtr)1;
}
// if not, we filtered out wrong sequence, we need to resend them
else
{
Console.WriteLine();
ReSendKeys();
return (IntPtr)1;
}
}
if (_index == 2)
{
_swallowedKeys.Add(new Tuple<IntPtr, KBDLLHOOKSTRUCT>(wParam, kbd));
if (message == WM.WM_SYSKEYUP && key == Keys.H)
{
_index++;
_swallowedKeys.RemoveAt(_swallowedKeys.Count - 1);
Console.WriteLine(" filtered out");
return (IntPtr)1;
}
else
{
// if user pressed H but not released and pressed another key at the same time
// i will pass that situation, if u need to handle something like that, you got the idea, please fill that block of code
}
}
if (_index == 3)
{
_swallowedKeys.Add(new Tuple<IntPtr, KBDLLHOOKSTRUCT>(wParam, kbd));
if (message == WM.WM_KEYUP && key == Keys.LMenu)
{
_index = 0;
_swallowedKeys.Clear();
Console.WriteLine(" filtered out");
Console.WriteLine("shortcut disabled");
return (IntPtr)1;
}
else
{
Console.WriteLine();
// user has been pressed Alt + H, H released but not alt, so we can expect one H again, but we need to send this pressed key with Alt prefixed
ReSendKeys(1);
return (IntPtr)1;
}
}
Console.WriteLine();
return CallNextHookEx(_hookID, nCode, wParam, lParam);
}

Related

Bring calculator window to front in Windows 10

I would like to ask you a question about bringing calculator window to front in Windows 10. I have tested a lot of codes, but nothing is really working. I think the main problem is, that Calculator is part of "ApplicationFrameHost".
In my application (C# WinForm), I would like to start system Calculator, if it's not running. If it's running bring the window to front even if it's minimized or not.
public static class WindowHelper
{
[DllImport("user32.dll")]
private static extern void keybd_event(byte bVk, byte bScan, uint dwFlags, int dwExtraInfo);
[DllImport("user32.dll")]
private static extern bool SetForegroundWindow(IntPtr hWnd);
[DllImport("user32.dll")]
private static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
private const int ALT = 0xA4;
private const int EXTENDEDKEY = 0x01;
private const int KEYUP = 0x02;
private const int SW_MINIMIZE = 0x06;
private const int SW_RESTORE = 0x09;
public static void BringProcessToFront(IntPtr mainWindowHandle)
{
// check if window has focus already
//if (mainWindowHandle == GetForegroundWindow()) return;
ShowWindow(mainWindowHandle, SW_RESTORE);
// simulate ALT key down
keybd_event((byte)ALT, 0x45, EXTENDEDKEY | 0, 0);
// simulate ALT key up
keybd_event((byte)ALT, 0x45, EXTENDEDKEY | KEYUP, 0);
// bring window into foreground
SetForegroundWindow(mainWindowHandle);
}
}
private void btnCalc_Click(object sender, EventArgs e)
{
// get all processes
System.Diagnostics.Process[] processes = System.Diagnostics.Process.GetProcesses();
// get ApplicationFrameHost for win10
System.Diagnostics.Process[] appFH = System.Diagnostics.Process.GetProcessesByName("ApplicationFrameHost");
IntPtr mWHandle = IntPtr.Zero;
foreach (System.Diagnostics.Process proc in processes)
{
if (proc.ProcessName == "calc" || proc.ProcessName == "Calculator" || proc.ProcessName == "win32calc")
{
// non-ApplicationFrameHost case
mWHandle = proc.MainWindowHandle;
if (appFH.Length > 0)
{
// if ApplicationFrameHost is running, find calculator MainWindowHandle
foreach (System.Diagnostics.Process app in appFH)
{
if ((app.MainWindowTitle == proc.MainWindowTitle) || (proc.MainWindowTitle.Length == 0))
mWHandle = app.MainWindowHandle;
}
}
// bring window to front
WindowHelper.BringProcessToFront(mWHandle);
return;
}
}
// calculator was not found, starts new one
System.Diagnostics.Process.Start("calc");
}
This code is working on Windows 7 as well, but not for 10 with no-english localization. There is a problem, when Calculator is minimized, it can't be restored.
As I said, I have tried lot of codes like:
public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
public static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpszClass, string lpszWindow);
private static extern bool GetWindowPlacement(IntPtr hWnd, ref WINDOWPLACEMENT lpwndpl);
// this was working to bring focus on already displayed window
WindowHelper.FindWindowEx(app.MainWindowHandle, IntPtr.Zero, "Windows.UI.Core.CoreWindow", null);
The main problem is, that I didn't find the solution, which could unminimize window on non-english localized windows.
Do you have some example, how to deal with that?
Thank you.
EDIT:
After some testing, I have identified, why is not possible to bring this window to front. Win7 and Win10 with en (Maybe it isn't related to locale) has Calculator still activated even if it's minimized or not. On the other hand a second Win10 has process suspended when it's minimized (see picture attachment). So now the question is, how to un-suspend it. Then hopefully window could be bring to front.
You cannot force the foreground window if you are not the foreground window. There are actually a bunch of conditions that determine when you can force the foreground window. From the docs: (bottom one applies to you)
The system restricts which processes can set the foreground window.
A process can set the foreground window only if one of the following
conditions is true:
The process is the foreground process.
The process was started by the foreground process.
The process received the last input event.
There is no foreground process.
The process is being debugged.
The foreground process is not a Modern Application or the Start Screen. The foreground is not locked (see LockSetForegroundWindow)
The foreground lock time-out has expired (see SPI_GETFOREGROUNDLOCKTIMEOUT in SystemParametersInfo).
No menus are active.
An application cannot force a window to the foreground while the user is
working with another window. Instead, Windows flashes the taskbar button of the
window to notify the user.
After some time (little bit occupied by another projects) I have founded the solution, which is working for me.
public static class WindowHelper
{
public static Dictionary<IntPtr, String> appWins;
public static bool ThreadWindows(IntPtr handle, IntPtr param)
{
int size = WindowHelper.GetWindowTextLength(handle);
if (size > 0)
{
StringBuilder strbTitle = new StringBuilder(size + 1);
WindowHelper.GetWindowText(handle, strbTitle, strbTitle.Capacity);
if (strbTitle.Length > 0)
{
appWins.Add(handle, strbTitle.ToString());
return true;
}
}
return false;
}
public static void BringProcessToFront(IntPtr mainWindowHandle)
{
// check if window has focus already
//if (mainWindowHandle == GetForegroundWindow()) return;
ShowWindow(mainWindowHandle, SW_RESTORE);
// simulate ALT key down
keybd_event((byte)ALT, 0x45, EXTENDEDKEY | 0, 0);
// simulate ALT key up
keybd_event((byte)ALT, 0x45, EXTENDEDKEY | KEYUP, 0);
// bring window into foreground
SetForegroundWindow(mainWindowHandle);
}
//[DllImport("user32.dll")]
//private static extern IntPtr GetForegroundWindow();
[DllImport("user32.dll", CharSet = CharSet.Unicode)]
public static extern int GetWindowTextLength(IntPtr hWnd);
[DllImport("user32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
public static extern int GetWindowText(IntPtr hWnd, StringBuilder lpString, int nMaxCount);
public delegate bool EnumThreadDelegate(IntPtr hWnd, IntPtr lParam);
[DllImport("user32.dll")]
public static extern bool EnumThreadWindows(int dwThreadId, EnumThreadDelegate lpfn, IntPtr lParam);
[DllImport("User32.dll")]
public static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpszClass, string lpszWindow);
[DllImport("user32.dll")]
private static extern void keybd_event(byte bVk, byte bScan, uint dwFlags, int dwExtraInfo);
[DllImport("user32.dll")]
private static extern bool SetForegroundWindow(IntPtr hWnd);
[DllImport("user32.dll")]
private static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
private const int ALT = 0xA4;
private const int EXTENDEDKEY = 0x01;
private const int KEYUP = 0x02;
private const int SW_RESTORE = 0x09;
}
private void btnCalc_Click(object sender, EventArgs e)
{
// get all processes
System.Diagnostics.Process[] processes = System.Diagnostics.Process.GetProcesses();
// get ApplicationFrameHost for win10
System.Diagnostics.Process[] appFH = System.Diagnostics.Process.GetProcessesByName("ApplicationFrameHost");
IntPtr mWHandle = IntPtr.Zero;
foreach (System.Diagnostics.Process proc in processes)
{
if (proc.ProcessName == "calc" || proc.ProcessName == "Calculator" || proc.ProcessName == "win32calc")
{
// save first handle
mWHandle = proc.MainWindowHandle;
// if ApplicationFrameHost is running, find calculator MainWindowHandle
foreach (System.Diagnostics.Process app in appFH)
{
// calculator is already running
if (mWHandle == (IntPtr)0x00)
{
mWHandle = WindowHelper.FindWindowEx(app.MainWindowHandle, IntPtr.Zero, "Windows.UI.Core.CoreWindow", null);
} else
{
// create new windows dictionary
WindowHelper.appWins = new Dictionary<IntPtr, String>();
// enumerate all windows in all AFH threads
foreach (System.Diagnostics.ProcessThread thread in app.Threads)
WindowHelper.EnumThreadWindows(thread.Id, new WindowHelper.EnumThreadDelegate(WindowHelper.ThreadWindows), IntPtr.Zero);
// check if proc window was found
if (WindowHelper.appWins.ContainsValue(proc.MainWindowTitle))
{
IntPtr hwnd;
// get key from value
if ((hwnd = WindowHelper.appWins.First(x => x.Value == proc.MainWindowTitle).Key) != (IntPtr)0)
mWHandle = hwnd;
}
// clear list
WindowHelper.appWins.Clear();
}
}
if (mWHandle != (IntPtr)(0x00))
{
// bring already running calc to front
WindowHelper.BringProcessToFront(mWHandle);
return;
}
// do not search for other processes
break;
}
}
// start new calc instance
System.Diagnostics.Process.Start("calc");
}
This solution is locale independent.
Thanks to everyone who pointing me to the right direction.

C# .NET - Detecting and handling "extended" USB HID keyboard codes

I'm looking to detect and handle keycodes from a USB HID keyboard that fall outside the "normal" set of codes, i.e. codes above 100 (0x64) in a .NET Windows Forms application (.NET Framework 4.5).
Specifically, in my case I need to detect codes between 0x68 and 0x78, but I'd like to be able to detect anything up to 0xA4, which seems to be the upper limit of HID keyboard codes (aside from things like Ctrl, Alt, Win, etc.)
This question here seemed to be exactly what I was looking for, but I have had no success getting the advice on that answer to work. I have KeyPreview set to true for the form, and event handlers registered for KeyDown, KeyPress, and PreviewKeyDown, but none of them fire on reception of an 0x68 (F13) code. For now I'd just like to print the pressed key to a richtextbox control:
public mainFrm()
{
InitializeComponent();
this.KeyPreview = true;
this.KeyDown += new KeyEventHandler(KeyDownHandler);
this.KeyPress += new KeyPressEventHandler(KeyPressHandler);
this.PreviewKeyDown += new PreviewKeyDownEventHandler(PreviewKeyHandler);
}
private void KeyPressHandler(object sender, KeyPressEventArgs e)
{
rtb_hidLog.AppendText("Press: " + e.KeyChar.ToString() + "\r\n");
}
private void KeyDownHandler(object sender, KeyEventArgs e)
{
rtb_hidLog.AppendText("KeyDown: "+ e.KeyCode.ToString() + "\r\n");
}
private void PreviewKeyHandler(object sender, PreviewKeyDownEventArgs e)
{
rtb_hidLog.AppendText("Preview: " + e.KeyCode.ToString() + "\r\n");
}
I even tried overriding ProcessCmdKey (as per this question) and that also does not fire on 0x68:
protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
{
rtb_hidLog.AppendText("CmdKey: " + keyData.ToString() + "\r\n");
return base.ProcessCmdKey(ref msg, keyData);
}
I have a USB HID Keyboard device connected (a PSoC microcontroller as a HID keyboard) that sends the 0x68 (F13) keycode when I press a button, but it doesn't fire the PreviewKeyHander. A standard 'A' code (0x04) from the PSoC device fires the KeyDownHandler and KeyPressHandler events with no problem. I have confirmed via USB Analyzer that the 0x68 code is being sent correctly, I just can't seem to force .NET to recognize it and fire an event. Is there something I'm missing or a trick I need to do to force my application to fire an event on these codes?
I've now also tried using Interop to use the win32 API (User32.dll) to hook into the keyboard input, and that also does not work. I get the same results; the hooked event will fire for all the keys on my keyboard, but anything not in that range does not fire a key pressed event.
My USB HID descriptor for the keyboard device, in case there is some issue there:
You can use a keyboard interceptor "in a separate DLL project that is referenced in your application" that is used by Form like this:
public delegate IntPtr KeyBoardHook( int nCode, IntPtr wParam, IntPtr lParam);
public class InterceptKeys : IDisposable
{
private const int WH_KEYBOARD_LL = 13;
private const int WM_KEYDOWN = 0x0100;
private KeyBoardHook _proc;
public event KeyBoardHook OnKeyBoardKeyClicked;
private static IntPtr _hookID = IntPtr.Zero;
public InterceptKeys()
{
_proc = HookCallback;
_hookID = SetHook(_proc);
if(_hookID == IntPtr.Zero)
{
throw new Exception($"Error Happened [{Marshal.GetLastWin32Error()}]");
}
}
public void Dispose()
{
UnhookWindowsHookEx(_hookID);
}
private IntPtr SetHook(KeyBoardHook 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)
{
OnKeyBoardKeyClicked?.Invoke(nCode, wParam, lParam);
//if (nCode >= 0 && wParam == (IntPtr)WM_KEYDOWN)
//{
// int vkCode = Marshal.ReadInt32(lParam);
// Console.WriteLine((char)vkCode);
//}
return CallNextHookEx(_hookID, nCode, wParam, lParam);
}
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr SetWindowsHookEx(int idHook,
KeyBoardHook 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);
}
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr GetModuleHandle(string lpModuleName);
}

Detecting specific key in low level keyboard hook

I'm creating an application that places an icon on the system tray that changes its appearance based on the state of the Caps Lock key. The issue I'm facing is that the hook only works correctly after a key other than Caps Lock is pressed, since that key flips the check after the hook is passed through, making the icon display the wrong state incorrectly.
I would need a way to detect when the Caps Lock key is pressed inside the hook to flip the detected state.
private static NotifyIcon notifyIcon = new NotifyIcon();
private static bool CapsPressed = Control.IsKeyLocked(Keys.CapsLock);
static Icon
AppIcon = CapsIndicator.Properties.Resources.AppIcon,
OnIcon = CapsIndicator.Properties.Resources.OnIcon,
OffIcon = CapsIndicator.Properties.Resources.OffIcon;
static void UpdateIcon() {
notifyIcon.Icon = CapsPressed ? OnIcon : OffIcon;
}
// Hook initializing & other stuff here
private static IntPtr HookCallback(int nCode, IntPtr wParam, IntPtr lParam) {
if (nCode >= 0 && wParam == (IntPtr) WM_KEYDOWN) {
CapsPressed = Control.IsKeyLocked(Keys.CapsLock);
UpdateIcon();
}
return CallNextHookEx(_hookID, nCode, wParam, lParam);
}
The solution isn't very straight-forward, but the key code can be revealed using the lParam pointer argument. You can do this by accessing the 32-bit integer it's pointing to with Marshal.ReadInt32, then, you need to cast it to the Keys type, and finally compare this value with Keys.CapsLock (or any other key you like):
private static IntPtr HookCallback(int nCode, IntPtr wParam, IntPtr lParam) {
if (nCode >= 0 && wParam == (IntPtr) WM_KEYDOWN) {
int vkCode = Marshal.ReadInt32(lParam);
CapsPressed = Control.IsKeyLocked(Keys.CapsLock);
// Flip the detected value if CapsLock is pressed
if ((Keys) vkCode == Keys.CapsLock) CapsPressed = !CapsPressed;
UpdateIcon();
}
return CallNextHookEx(_hookID, nCode, wParam, lParam);
}

True minimizing for another application

I just want to do real minimized, all public codes are not minimizing in right way! It just minimize it as shown, but not minimize like if I click on Minimize button. How did I know that? Or what benefit will I get from that? When I press on minimize button, it reduce from CPU usage! (It's a game anyway.)
My code is :
[DllImport("User32.Dll", EntryPoint = "PostMessageA", SetLastError = true)]
public static extern bool PostMessage(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam);
List<int> ProcIDs = new List<int>();
private void timer1_Tick(object sender, EventArgs e)
{
foreach (Process process in Process.GetProcesses())
{
if (process.ProcessName == "League of Legends")
{
// MinimizeWindow((IntPtr)hProcess);
if (!ProcIDs.Contains(process.Id))
{
IntPtr hProcess = GetProcessWindow(process.Id);
ProcIDs.Add(process.Id);
PostMessage(hProcess, WM_SYSCOMMAND, (IntPtr)SC_MINIMIZE, IntPtr.Zero);
}
}
}
}
const int WM_SYSCOMMAND = 274;
const int SC_MINIMIZE = 0xF020;
I also tried other methods and it does the same, just minimize as show, but not real minimize! :)
You can try this
[DllImport("user32.dll")]
private static extern bool ShowWindow(IntPtr hWnd, WindowShowStyle nCmdShow);
with window style as ShowMinimized = 2,
http://www.pinvoke.net/default.aspx/user32.showwindow

How to Suppress task switch keys (winkey, alt-tab, alt-esc, ctrl-esc) using low-level keyboard hook in c#

Can anyone please tell me how to disable the task switch keys using c#
I've got the complete code to disable Windows Key , Alt + Tab and so on..
And now I'm providing the following code as a reference for others:
/* Code to Disable WinKey, Alt+Tab, Ctrl+Esc Starts Here */
// Structure contain information about low-level keyboard input event
[StructLayout(LayoutKind.Sequential)]
private struct KBDLLHOOKSTRUCT
{
public Keys key;
public int scanCode;
public int flags;
public int time;
public IntPtr extra;
}
//System level functions to be used for hook and unhook keyboard input
private delegate IntPtr LowLevelKeyboardProc(int nCode, IntPtr wParam, IntPtr lParam);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr SetWindowsHookEx(int id, LowLevelKeyboardProc callback, IntPtr hMod, uint dwThreadId);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern bool UnhookWindowsHookEx(IntPtr hook);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr CallNextHookEx(IntPtr hook, int nCode, IntPtr wp, IntPtr lp);
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr GetModuleHandle(string name);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
private static extern short GetAsyncKeyState(Keys key);
//Declaring Global objects
private IntPtr ptrHook;
private LowLevelKeyboardProc objKeyboardProcess;
private IntPtr captureKey(int nCode, IntPtr wp, IntPtr lp)
{
if (nCode >= 0)
{
KBDLLHOOKSTRUCT objKeyInfo = (KBDLLHOOKSTRUCT)Marshal.PtrToStructure(lp, typeof(KBDLLHOOKSTRUCT));
// Disabling Windows keys
if (objKeyInfo.key == Keys.RWin || objKeyInfo.key == Keys.LWin || objKeyInfo.key == Keys.Tab && HasAltModifier(objKeyInfo.flags) || objKeyInfo.key == Keys.Escape && (ModifierKeys & Keys.Control) == Keys.Control)
{
return (IntPtr)1; // if 0 is returned then All the above keys will be enabled
}
}
return CallNextHookEx(ptrHook, nCode, wp, lp);
}
bool HasAltModifier(int flags)
{
return (flags & 0x20) == 0x20;
}
/* Code to Disable WinKey, Alt+Tab, Ctrl+Esc Ends Here */
Then Inside the Form_Load();
private void Form_Load(object sender, EventArgs e)
{
ProcessModule objCurrentModule = Process.GetCurrentProcess().MainModule;
objKeyboardProcess = new LowLevelKeyboardProc(captureKey);
ptrHook = SetWindowsHookEx(13, objKeyboardProcess, GetModuleHandle(objCurrentModule.ModuleName), 0);
}
You can use the OnKeyDown event to capture the keys pressed and suppress the ones you don't want to allow.
Scott Hanselman's BabySmash application does disable most key strokes like alt-tab alt-esc, etc. Most of the source and development can be found on his blog. The source is on GitHub. In the source, you will see he InterceptKeys class that uses many win32 calls to get low level hooks to the keys pressed. He then handles these in HookCallback in the App.xaml.cs file. Hope this helps.
Similar Question
Another Similar

Categories

Resources