I'm searching a way to disable alt and ctrl key input while I'm pressing it.
I'm actually developping a Macro Configurer and when I press my macro (for example Alt+Ctrl+NumPad0) and I want that the keys H+E+L+L+O are sent, it won't work because I'm pressing Alt. The computer probably tries to execute unknown shortcuts for Alt+Ctrl+H, Alt+Ctrl+E ...
So I want that when I press my macro and the program detects I pressed it, it disable temporary alt while the output keys are sent, and enable again Alt when it's finished.
I use a LowLevelKeyboardProc to detect when i press a key, but I can't prevent the Alt pressing because i'm actually pressing it to execute my macro.
//The code from my form
private void Listener_OnKeyUp(object sender, KeyUpArgs e)
{
KeyAction.RemoveKeyDown(e.KeyUp);
}
private void Listener_OnKeyPressed(object sender, KeyPressedArgs e)
{
try
{
KeyAction.PutKeyDown(e.KeyPressed);
foreach (MacroEntree macro in macros)
{
if (macro.Activated)
if (macro.Action != null)
if (macro.isMacroDown())
{
listener.OnKeyPressed -= new EventHandler<KeyPressedArgs>(Listener_OnKeyPressed);
new Thread(delegate ()
{
while (IsAltCtrlDown()) ;
macro.ExecuteAction();
Thread.Sleep(100);
listener.OnKeyPressed += new EventHandler<KeyPressedArgs>(Listener_OnKeyPressed);
}).Start();
}
}
}
catch (Exception ex)
{
MessageBox.Show("Erreur : " + ex.Message);
}
}
private bool IsAltCtrlDown()
{
if (KeyAction.isKeyDown(Key.LeftAlt) || KeyAction.isKeyDown(Key.RightAlt))
return true;
if (KeyAction.isKeyDown(Key.LeftCtrl) || KeyAction.isKeyDown(Key.RightCtrl))
return true;
return false;
}
//the code from my class that checks if the macro is down
public class KeyAction
{
static List<Key> keyDown = new List<Key>();
public static bool isKeyDown(Key k)
{
return keyDown.Contains(k);
}
public static void PutKeyDown(Key k)
{
if (!keyDown.Contains(k))
keyDown.Add(k);
}
public static void RemoveKeyDown(Key k)
{
keyDown.Remove(k);
}
}
You could set a low-level keyboard hook to swallow keyboard input messages in windows.
Every native Windows program bases on a so called message loop that is basicly this.
MSG msg;
while(GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
With an low-level keyboard hook you can handle messages in this loop on the desktop process and with that prevent keys from being pressed.
public delegate IntPtr LowLevelKeyboardProc(int nCode, IntPtr wParam, IntPtr lParam);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr SetWindowsHookEx(
int idHook, LowLevelKeyboardProc lpfn, IntPtr hMod, uint dwThreadId);
private const int WH_KEYBOARD_LL = 13;
private static IntPtr SetHook(LowLevelKeyboardProc proc)
{
return SetWindowsHookEx(
WH_KEYBOARD_LL,
proc,
0, // hook on all input (https://stackoverflow.com/questions/7715480/is-zero-ever-a-valid-handle)
0); // for all threads
}
You can use the code like the following. When you do not call CallNextHookEx the key event will not have any impact.
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode,
IntPtr wParam, IntPtr lParam);
private const int WM_KEYDOWN = 0x0100;
private static IntPtr HookCallback(
int nCode, IntPtr wParam, IntPtr lParam)
{
// check if it is a key down message
if (nCode >= 0 && wParam == (IntPtr)WM_KEYDOWN)
{
int vkCode = Marshal.ReadInt32(lParam);
// check if the pressed key is the `Alt` key
if((Keys)vkCode == Keys.Alt)
{
// return 1 for handled if its the alt key
return (IntPtr) 1;
}
}
// let the message bubble if its not a keydown message or it wasn't the alt key which was pressed
return CallNextHookEx(_hookID, nCode, wParam, lParam);
}
// with this line you can set the `HookCallback` into the message loop
IntPtr hookID = SetHook(HookCallback);
And don't forget to unset the hook.
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool UnhookWindowsHookEx(IntPtr hhk);
UnhookWindowsHookEx(hookID);
Thanks to #Manfred Radlwimmer I solved the problem. I send a Alt and Ctrl key up before executing my action and it works fine.
private void Listener_OnKeyPressed(object sender, KeyPressedArgs e)
{
try
{
KeyAction.PutKeyDown(e.KeyPressed);
foreach (MacroEntree macro in macros)
{
if (macro.Activated)
if (macro.Action != null)
if (macro.isMacroDown())
{
listener.OnKeyPressed -= new EventHandler<KeyPressedArgs>(Listener_OnKeyPressed);
new Thread(delegate ()
{
KeyboardOperations.SendKeyUp(KeyboardOperations.KeyCode.LALT);
KeyboardOperations.SendKeyUp(KeyboardOperations.KeyCode.LCONTROL);
macro.ExecuteAction();
Thread.Sleep(100);
listener.OnKeyPressed += new EventHandler<KeyPressedArgs>(Listener_OnKeyPressed);
}).Start();
}
}
}
catch (Exception ex)
{
MessageBox.Show("Erreur : " + ex.Message);
}
}
Related
I have a keyboard hook that works great but has one issue I can't resolve. I want the hook to run on async and I'm not able to do it. Normally I use it like this
private void button1_Click(object sender, EventArgs e)
{
var res = new InterceptKeys();
res.startHook();
}
When I click button 1 the hooks starts and works correctly. But when i click the button 2 ...
private void button2_Click(object sender, EventArgs e)
{
Thread.Sleep(100000) //simulates an operation that keeps form busy
}
Now the hook doesn't work anymore and have to wait for the sleep to finish. My question is, it is possible to make the hook async? I tried to call it like a task, but the hook doesn't work.
public class InterceptKeys
{
[DllImport("user32.dll")]
static extern IntPtr GetForegroundWindow();
[DllImport("user32.dll")]
static extern int GetWindowText(IntPtr hwnd, StringBuilder ss, int count);
[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);
private const int WH_KEYBOARD_LL = 13;
private const int WM_KEYDOWN = 0x0100;
private IntPtr _hookID = IntPtr.Zero;
public void startHook()
{
if(_hookID == IntPtr.Zero)
{
_hookID = SetHook();
}
}
public void endHook()
{
UnhookWindowsHookEx(_hookID);
}
private IntPtr SetHook()
{
return SetWindowsHookEx(WH_KEYBOARD_LL, HookCallback, IntPtr.Zero, 0);
}
private delegate IntPtr LowLevelKeyboardProc(int nCode, IntPtr wParam, IntPtr lParam);
int cont = 0;
Dictionary<cKeyLogger.VK, Tuple<int, string>> combinacions = new Dictionary<cKeyLogger.VK, Tuple<int, string>> { { cKeyLogger.VK.F3, new Tuple<int, string>(2,"{r}{UP}") }, { cKeyLogger.VK.F4, new Tuple<int, string>(2, "{R}{DOWN}") } };
private IntPtr HookCallback(int nCode, IntPtr wParam, IntPtr lParam)
{
if (nCode >= 0)
{
cKeyLogger.VK vkCode = (cKeyLogger.VK)Marshal.ReadInt32(lParam);
string window = ActiveWindowTitle();
if(wParam == (IntPtr)WM_KEYDOWN)
{
Console.WriteLine(vkCode + " _ " + window);
if (window.ToLower().Contains("excel")) //just applies to excel to do some testing
{
//Do something
}
}
}
return CallNextHookEx(_hookID, nCode, wParam, lParam);
}
private static string ActiveWindowTitle()
{
//Create the variable
const int nChar = 256;
StringBuilder ss = new StringBuilder(nChar);
//Run GetForeGroundWindows and get active window informations
//assign them into handle pointer variable
IntPtr handle = IntPtr.Zero;
handle = GetForegroundWindow();
if (GetWindowText(handle, ss, nChar) > 0) return ss.ToString();
else return "";
}
}
I'd be wary of trying to tackle this problem by moving the hook to a separate thread. If you use a separate thread for the keyboard hook, when your code eventually hits the point where it needs to do something here:
if (window.ToLower().Contains("excel")) //just applies to excel to do some testing
{
//Do something
}
If there is a chance that the UI thread is still going to be blocked at this point, the code to "do something" is still going to be delayed. That delay in calling CallNextHookEx will actually get your keyboard hook removed by the OS.
I try to visualise hooks as chain links, when your application installs a hook it has a duty to do what it needs to as fast as possible before calling CallNextHookEx so that the next application can process the hook and Windows messages can keep flowing. If the OS detects an application is destabilising this it will remove the hook.
My question to you is: can move the blocking process from the UI thread into a separate thread? Rather than trying to move the hook into a separate thread. I've written many applications which use hooks and this is the way I've always done it.
Hope this helps.
My problem is that I'm trying to run a self-contained c# console application specifically published for linux, intended to run on a Raspberry.
The use scenario is in public transport where passengers will use a RFID keycard, I'll read the ID via a sensor and this sensor is recognized as a keyboard.
Since this application must run all time it will be running as a service, that's why I need a keyboard hook so no matter what happens, the service will read the sensor.
I was wondering if there is something like this example that would work for linux (warning: its an http website): Low Level Global Keyboard Hook
Here is the code so you don't need to go to the website:
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Windows.Input;
namespace DesktopWPFAppLowLevelKeyboardHook
{
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;
}
}
}
I found a way to do this without using any dll files, instead I read /dev/input/eventX which is a file that's generated when a keyboard or any other peripheral device is connected, it is used by the system to know the events generated by the device.
Here is the code in c#
public static string EvdevReader()
{
string readMessage = "";
try
{
FileStream stream = new FileStream("/dev/input/event0", FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
byte[] buffer = new byte[24];
while (true)
{
stream.Read(buffer, 0, buffer.Length);
// parse timeval (8 bytes)
int offset = 8;
short type = BitConverter.ToInt16(new byte[] { buffer[offset], buffer[++offset] }, 0);
short code = BitConverter.ToInt16(new byte[] { buffer[++offset], buffer[++offset] }, 0);
int value = BitConverter.ToInt32(
new byte[] { buffer[++offset], buffer[++offset], buffer[++offset], buffer[++offset] }, 0);
if (value == 1 && code != 28)
{
Console.WriteLine("Code={1}, Value={2}", type, code, value);
var key = (((KEY_CODE)code).ToString()).Replace("KEY_", "");
key = key.Replace("MINUS", "-");
key = key.Replace("EQUAL", "=");
key = key.Replace("SEMICOLON", ";");
key = key.Replace("COMMA", ",");
key = key.Replace("SLASH", "/");
Console.WriteLine(key);
readMessage += key;
}
if (code == 28)
{
return readMessage;
}
}
}
catch (Exception ex)
{
Debug.WriteLine(ex.ToString());
Main();
}
return readMessage;
}
The code opens a FileStream of the event0 which is normally where you want to listen for the input, the events that are generated have a standard structure (you can find more info here: https://thehackerdiary.wordpress.com/2017/04/21/exploring-devinput-1/), according with the documentation I found it's supposed that the timeval is 16 bytes but In this case it works with 8.
Events have type which is the type of event, code of the pressed key and value, this one is the state of the key pressed = 1, unpressed = 0 (Find more info here: https://github.com/torvalds/linux/blob/master/include/uapi/linux/input-event-codes.h#L38-L51).
For each of this codes we need to find it's readable form, for this I created an enumerator with the keys that I need to read (28 is the enter key). This codes can be found in the link above.
public enum KEY_CODE
{
KEY_1 = 2,
KEY_2,
KEY_3,
KEY_4,
KEY_5,
KEY_6,
KEY_7,
KEY_8,
KEY_9,
KEY_0,
KEY_MINUS,
KEY_EQUAL,
KEY_BACKSPACE,
KEY_TAB,
KEY_Q,
KEY_W,
KEY_E,
KEY_R,
KEY_T,
KEY_Y,
KEY_U,
KEY_I,
KEY_O,
KEY_P,
KEY_LEFTBRACE,
KEY_RIGHTBRACE,
KEY_ENTER,
KEY_LEFTCTRL,
KEY_A,
KEY_S,
KEY_D,
KEY_F,
KEY_G,
KEY_H,
KEY_J,
KEY_K,
KEY_L,
KEY_SEMICOLON,
KEY_APOSTROPHE,
KEY_GRAVE,
KEY_LEFTSHIFT,
KEY_BACKSLASH,
KEY_Z,
KEY_X,
KEY_C,
KEY_V,
KEY_B,
KEY_N,
KEY_M,
KEY_COMMA,
KEY_DOT,
KEY_SLASH,
KEY_RIGHTSHIFT,
KEY_KPASTERISK,
KEY_LEFTALT,
KEY_SPACE,
KEY_CAPSLOCK,
KEY_F1,
KEY_F2,
KEY_F3,
KEY_F4,
KEY_F5,
KEY_F6,
KEY_F7,
KEY_F8,
KEY_F9,
KEY_F10,
KEY_NUMLOCK,
KEY_SCROLLLOCK,
KEY_KP7,
KEY_KP8,
KEY_KP9,
KEY_KPMINUS,
KEY_KP4,
KEY_KP5,
KEY_KP6,
KEY_KPPLUS,
KEY_KP1,
KEY_KP2,
KEY_KP3,
KEY_KP0,
KEY_KPDOT
}
I am trying to listen to keyboard input in my Word AddIn with the MouseKeyboardActivityMonitor Nugget. When I register the KeyboardHookListener I am able to receive every keyboard input on every programm except Word.
Is this maybe couse of some Word internal protection or am I missing something?
I have Windows 7 64bit and Word 2016 32bit.
k_keyListener = new KeyboardHookListener(new GlobalHooker());
k_keyListener.Enabled = true;
k_keyListener.KeyDown += new System.Windows.Forms.KeyEventHandler(hook_OnKeyDown);
public void hook_OnKeyDown(object sender, System.Windows.Forms.KeyEventArgs e)
{
log.Info("Pressed key: " + e.KeyCode.ToString());
}
I don't use the Global Hooker and my code works. I explicitly tested it in Word (and know it works in Excel, PowerPoint, Access, etc).
For what its worth, Microsoft is forever worried about Office app hacks and its possible your security software could actually be the reason. It is a KeyLogger after all and susceptible to being labelled a virus injection attack.
public partial class ThisAddIn
{
private void ThisAddIn_Startup(object sender, System.EventArgs e)
{
//enable keyboard intercepts
KeyboardHooking.SetHook();
}
private void ThisAddIn_Shutdown(object sender, System.EventArgs e)
{
//disable keyboard intercepts
KeyboardHooking.ReleaseHook();
}
}
Add this Keyboard class:
using System;
using System.Runtime.InteropServices;
using System.Windows.Forms;
namespace WordAddInKeyHandler
{
class KeyboardHooking
{
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr SetWindowsHookEx(int idHook, LowLevelKeyboardProc lpfn, IntPtr hMod,
uint dwThreadId);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool UnhookWindowsHookEx(IntPtr hhk);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode, IntPtr wParam, IntPtr lParam);
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr GetModuleHandle(string lpModuleName);
public delegate int LowLevelKeyboardProc(int nCode, IntPtr wParam, IntPtr lParam);
private static LowLevelKeyboardProc _proc = HookCallback;
private static IntPtr _hookID = IntPtr.Zero;
//declare the mouse hook constant.
//For other hook types, you can obtain these values from Winuser.h in the Microsoft SDK.
private const int WH_KEYBOARD = 2; // mouse
private const int HC_ACTION = 0;
private const int WH_KEYBOARD_LL = 13; // keyboard
private const int WM_KEYDOWN = 0x0100;
public static void SetHook()
{
// Ignore this compiler warning, as SetWindowsHookEx doesn't work with ManagedThreadId
#pragma warning disable 618
_hookID = SetWindowsHookEx(WH_KEYBOARD, _proc, IntPtr.Zero, (uint)AppDomain.GetCurrentThreadId());
#pragma warning restore 618
}
public static void ReleaseHook()
{
UnhookWindowsHookEx(_hookID);
}
//Note that the custom code goes in this method the rest of the class stays the same.
//It will trap if BOTH keys are pressed down.
private static int HookCallback(int nCode, IntPtr wParam, IntPtr lParam)
{
if (nCode < 0)
{
return (int)CallNextHookEx(_hookID, nCode, wParam, lParam);
}
else
{
if (nCode == HC_ACTION)
{
Keys keyData = (Keys)wParam;
// CTRL + SHIFT + 7
if ((BindingFunctions.IsKeyDown(Keys.ControlKey) == true)
&& (BindingFunctions.IsKeyDown(Keys.ShiftKey) == true)
&& (BindingFunctions.IsKeyDown(keyData) == true) && (keyData == Keys.D7))
{
// DO SOMETHING HERE
}
// CTRL + 7
if ((BindingFunctions.IsKeyDown(Keys.ControlKey) == true)
&& (BindingFunctions.IsKeyDown(keyData) == true) && (keyData == Keys.D7))
{
// DO SOMETHING HERE
}
}
return (int)CallNextHookEx(_hookID, nCode, wParam, lParam);
}
}
}
public class BindingFunctions
{
[DllImport("user32.dll")]
static extern short GetKeyState(int nVirtKey);
public static bool IsKeyDown(Keys keys)
{
return (GetKeyState((int)keys) & 0x8000) == 0x8000;
}
}
}
If you have time you can check why the Global Hooker isn't working (specifically with Word) by comparing the Global Hooker source code to mine.
Reference to my answer here: https://stackoverflow.com/a/10257266/495455 also see the answer by Govert the author of XNA.
I need to ignore all right clicks within my application and Chromium Embedded Framework.
Now I had this working great on an old version which used the WebBrowser widget, but now after switching over to CEF browser, the KeyMessageFilter does not get the message when the CEF browser is in focus. The first related post seems to say that the CEF keeps hold of the event and does not pass it on to the application.
However, I don't understand the answer. It seems to be in Basic or something....
Here is my KeyMessageFilter code
public class KeyMessageFilter : IMessageFilter
{
private enum KeyMessages
{
WM_KEYFIRST = 0x100,
WM_KEYDOWN = 0x100,
WM_KEYUP = 0x101,
WM_CHAR = 0x102,
WM_SYSKEYDOWN = 0x0104,
WM_SYSKEYUP = 0x0105,
WM_SYSCHAR = 0x0106,
WM_MOUSEWHEEL = 0x20a
}
[DllImport("user32.dll")]
private static extern IntPtr GetParent(IntPtr hwnd);
// We check the events agains this control to only handle
// key event that happend inside this control.
Control _control;
public KeyMessageFilter()
{ }
public KeyMessageFilter(Control c)
{
_control = c;
}
public bool PreFilterMessage(ref Message m)
{
Console.WriteLine(m.Msg);
// Filter out WM_NCRBUTTONDOWN/UP/DBLCLK
if (m.Msg == 0xA4 || m.Msg == 0xA5 || m.Msg == 0xA6) return true;
// Filter out WM_RBUTTONDOWN/UP/DBLCLK
if (m.Msg == 0x204 || m.Msg == 0x205 || m.Msg == 0x206) return true;
if (m.Msg == (int)KeyMessages.WM_MOUSEWHEEL)
{
if (Control.ModifierKeys == Keys.Control)
{
return true;
}
}
if (m.Msg == (int)KeyMessages.WM_KEYDOWN)
{
if (_control != null)
{
IntPtr hwnd = m.HWnd;
IntPtr handle = _control.Handle;
while (hwnd != IntPtr.Zero && handle != hwnd)
{
hwnd = GetParent(hwnd);
}
if (hwnd == IntPtr.Zero) // Didn't found the window. We are not interested in the event.
return false;
}
Keys key = (Keys)m.WParam;
if (key.Equals(Keys.Tab))
{
return true;
}
if (Control.ModifierKeys == Keys.Control)
{
switch (key)
{
case Keys.Oemplus:
return true;
case Keys.OemMinus:
return true;
}
}
}
return false;
}
}
Related Posts
Ignoring keys in winAPi: Stack Overflow question Override mouse using Chromium embedded framework
Ignoring keys: Stack Overflow question How to detect the currently pressed key?
Okay here is how I did it.
I used a low level hook for the mouse in the Program.cs file.
I then used a Setting to say wether my App is focused or not this uses the Form.Activated / Deactivated events (other wise it would swallow all right clicks on the computer while the App is running, BAD EXPERIENCE).
Relevant Links:Global mouse event handler
Program.cs
private static LowLevelMouseProc _proc = HookCallback;
private static IntPtr _hookID = IntPtr.Zero;
Main(string[] args){
.......
_hookID = SetHook(_proc);
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new ContainerForm());
UnhookWindowsHookEx(_hookID);
}
private static IntPtr SetHook(LowLevelMouseProc proc)
{
using (Process curProcess = Process.GetCurrentProcess())
using (ProcessModule curModule = curProcess.MainModule)
{
return SetWindowsHookEx(WH_MOUSE_LL, proc,
GetModuleHandle(curModule.ModuleName), 0);
}
}
private delegate IntPtr LowLevelMouseProc(int nCode, IntPtr wParam, IntPtr lParam);
private static IntPtr HookCallback(
int nCode, IntPtr wParam, IntPtr lParam)
{
if (nCode >= 0 &&
(MouseMessages.WM_RBUTTONDOWN == (MouseMessages)wParam || MouseMessages.WM_RBUTTONUP == (MouseMessages)wParam))
{
//If the app has focuse swallow event
if (Properties.Settings.Default.AppFocus) {
return new IntPtr(-1);
}
else
{
return CallNextHookEx(_hookID, nCode, wParam, lParam);
}
}
return CallNextHookEx(_hookID, nCode, wParam, lParam);
}
private const int WH_MOUSE = 7;
private const int WH_MOUSE_LL = 14;
private enum MouseMessages
{
WM_LBUTTONDOWN = 0x0201,
WM_LBUTTONUP = 0x0202,
WM_MOUSEMOVE = 0x0200,
WM_MOUSEWHEEL = 0x020A,
WM_RBUTTONDOWN = 0x0204,
WM_RBUTTONUP = 0x0205
}
[StructLayout(LayoutKind.Sequential)]
private struct POINT
{
public int x;
public int y;
}
[StructLayout(LayoutKind.Sequential)]
private struct MSLLHOOKSTRUCT
{
public POINT pt;
public uint mouseData;
public uint flags;
public uint time;
public IntPtr dwExtraInfo;
}
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr SetWindowsHookEx(int idHook,
LowLevelMouseProc lpfn, IntPtr hMod, uint dwThreadId);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool UnhookWindowsHookEx(IntPtr hhk);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode,
IntPtr wParam, IntPtr lParam);
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr GetModuleHandle(string lpModuleName);
}
Form.cs
private void onActivated(object sender, EventArgs e)
{
Properties.Settings.Default.AppFocus = true;
}
private void onDeactivated(object sender, EventArgs e)
{
Properties.Settings.Default.AppFocus = false;
}
This likely isn't the best way to do this, however I was unable to get the CEFBrowser object to ignore right clicks, just as I was unable to get the Form as a whole to ignore right clicks, or even the Application to ignore (non-low level) Mouse Events. This is the work around of someone who is completely new to Windows so don't take this as the best code ever but it is working for me.
Feel free to edit title.
Ok so i'm trying to create a short key button that skips to the next song of any media player? like what some keyboards have as in FN + F11 and it goes to next song is there anyway to integrate that into c# for my own keyboard? i have this code so far but all its doing is posting a msg onto the textbox1.
// 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));
// Keys
if (objKeyInfo.key == Keys.F10 && ModifierKeys == Keys.Alt)
{
textBox1.Focus();
a += 1;
c += 1;
textBox1.Text += Convert.ToString(c) + ". " + "Previous Song" + Environment.NewLine;
PrevSongCount.Text = Convert.ToString(a);
AllUpCount.Text = Convert.ToString(c);
return (IntPtr)1;
}
if (objKeyInfo.key == Keys.F11 && ModifierKeys == Keys.Alt)
{
textBox1.Focus();
b += 1;
c += 1;
textBox1.Text += Convert.ToString(c) + ". " + "Next Song" + Environment.NewLine;
NextSongCount.Text = Convert.ToString(b);
AllUpCount.Text = Convert.ToString(c);
return (IntPtr)1;
}
}
return CallNextHookEx(ptrHook, nCode, wp, lp);
}
bool HasAltModifier(int flags)
{
return (flags & 0x20) == 0x20;
}
This was not as easy as I thought. But finally I managed to do it and the solution was shockingly simple.
After compiling this you are using the venerable virtual media keyboard codes.
http://msdn.microsoft.com/en-us/library/dd375731%28v=VS.85%29.aspx
I used this cmd line prog for my microsoft natural keyboard which does not have media keys but has 5 programmable keys and to get it to work you hack the registry
HKEY_CURRENT_USER\Software\Microsoft\IntelliType Pro\EventMapping\82 or
HKEY_CURRENT_USER\Software\Microsoft\IntelliType Pro\ModelSpecific\1016\EventMapping\82
where the 81 is just one of the dynamic keys (78-82)
and put the value previous or next into the Arguments key.
using System;
using System.Runtime.InteropServices;
namespace NxtTrack
{
class Program
{
[DllImport("user32.dll")]
private static extern bool PostMessage(IntPtr hWnd, uint Msg, UIntPtr wParam, IntPtr lParam);
[DllImport("user32.dll")]
public static extern void keybd_event(byte vkCode, byte scanCode, int flags, IntPtr extraInfo);
enum TrackMove
{
Previous,Next
}
static void Main(string[] args)
{
TrackMove trackMove;
try
{
if(args[0].ToLower().Contains("previous"))
trackMove = TrackMove.Previous;
else if(args[0].ToLower().Contains("next"))
trackMove = TrackMove.Next;
else
{
throw new Exception("wrong param");
}
}
catch
{
Console.WriteLine("Params needed: Next or Previous");
return;
}
TrackKeys(trackMove);
}
private static void TrackKeys(TrackMove trackMove)
{
//http://msdn.microsoft.com/en-us/library/dd375731%28v=VS.85%29.aspx
byte msg = trackMove == TrackMove.Previous ? (byte)0xB1 : (byte)0xB0;
keybd_event(msg, 0x45, 0, IntPtr.Zero);
}
}
}