I'm using the full class provided as best answer in: C# Hook Global Keyboard Events - .net 4.0 without any changes to it. However, when pressing a key when focussed on the powerpoint, I get the following error:
Exception thrown: 'System.Runtime.InteropServices.COMException'
I open the powerpoint by:
PowerPoint.Presentation presentation = (PowerPoint.Presentation)PowerPointItems[0];
PowerPoint.Application application = presentation.Application;
PowerPoint.SlideShowSettings settings = presentation.SlideShowSettings;
settings.ShowType = (PowerPoint.PpSlideShowType)1;
settings.ShowPresenterView = MsoTriState.msoFalse;
PowerPoint.SlideShowWindow sw = settings.Run();
sw.View.AcceleratorsEnabled = MsoTriState.msoFalse;
presentation.SlideShowWindow.View.GotoSlide(1);
presentation.SlideShowWindow.View.FirstAnimationIsAutomatic();
The callback function looks like:
private static void Kh_KeyDown(Keys key, bool Shift, bool Ctrl, bool Alt)
{
Console.WriteLine("a");
PowerPoint.Presentation presentation = (PowerPoint.Presentation)PowerPointItems[0];
Console.WriteLine("b");
int nr_slides = presentation.Slides.Count;
Console.WriteLine("c");
}
However, while a and b are printed in the output, c is not but the exception is. This makes me think for some reason the exception is thrown because of the line
int nr_slides = presentation.Slides.Count;
Any thought on why this could be the case?
The code provided on C# Hook Global Keyboard Events - .net 4.0:
public class KeyboardHook : IDisposable
{
bool Global = false;
public delegate void ErrorEventHandler(Exception e);
public delegate void LocalKeyEventHandler(Keys key, bool Shift, bool Ctrl, bool Alt);
public event LocalKeyEventHandler KeyDown;
public event LocalKeyEventHandler KeyUp;
public event ErrorEventHandler OnError;
public delegate int CallbackDelegate(int Code, IntPtr W, IntPtr L);
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct KBDLLHookStruct
{
public Int32 vkCode;
public Int32 scanCode;
public Int32 flags;
public Int32 time;
public Int32 dwExtraInfo;
}
[DllImport("user32", CallingConvention = CallingConvention.StdCall)]
private static extern IntPtr SetWindowsHookEx(HookType idHook, CallbackDelegate lpfn, IntPtr hInstance, int threadId);
[DllImport("user32", CallingConvention = CallingConvention.StdCall)]
private static extern bool UnhookWindowsHookEx(IntPtr idHook);
[DllImport("user32", CallingConvention = CallingConvention.StdCall)]
private static extern int CallNextHookEx(IntPtr idHook, int nCode, IntPtr wParam, IntPtr lParam);
[DllImport("kernel32.dll", CallingConvention = CallingConvention.StdCall)]
private static extern int GetCurrentThreadId();
[DllImport("kernel32.dll")]
static extern IntPtr LoadLibrary(string lpFileName);
public enum HookType : int
{
WH_JOURNALRECORD = 0,
WH_JOURNALPLAYBACK = 1,
WH_KEYBOARD = 2,
WH_GETMESSAGE = 3,
WH_CALLWNDPROC = 4,
WH_CBT = 5,
WH_SYSMSGFILTER = 6,
WH_MOUSE = 7,
WH_HARDWARE = 8,
WH_DEBUG = 9,
WH_SHELL = 10,
WH_FOREGROUNDIDLE = 11,
WH_CALLWNDPROCRET = 12,
WH_KEYBOARD_LL = 13,
WH_MOUSE_LL = 14
}
private IntPtr HookID = IntPtr.Zero;
CallbackDelegate TheHookCB = null;
//Start hook
public KeyboardHook(bool Global)
{
this.Global = Global;
TheHookCB = new CallbackDelegate(KeybHookProc);
if (Global)
{
IntPtr hInstance = LoadLibrary("User32");
HookID = SetWindowsHookEx(HookType.WH_KEYBOARD_LL, TheHookCB,
hInstance, //0 for local hook. or hwnd to user32 for global
0); //0 for global hook. eller thread for hooken
}
else
{
HookID = SetWindowsHookEx(HookType.WH_KEYBOARD, TheHookCB,
IntPtr.Zero, //0 for local hook. or hwnd to user32 for global
GetCurrentThreadId()); //0 for global hook. or thread for the hook
}
}
public void test()
{
if (OnError != null) OnError(new Exception("test"));
}
bool IsFinalized = false;
~KeyboardHook()
{
if (!IsFinalized)
{
UnhookWindowsHookEx(HookID);
IsFinalized = true;
}
}
public void Dispose()
{
if (!IsFinalized)
{
UnhookWindowsHookEx(HookID);
IsFinalized = true;
}
}
[STAThread]
//The listener that will trigger events
private int KeybHookProc(int Code, IntPtr W, IntPtr L)
{
KBDLLHookStruct LS = new KBDLLHookStruct();
if (Code < 0)
{
return CallNextHookEx(HookID, Code, W, L);
}
try
{
if (!Global)
{
if (Code == 3)
{
IntPtr ptr = IntPtr.Zero;
int keydownup = L.ToInt32() >> 30;
if (keydownup == 0)
{
if (KeyDown != null) KeyDown((Keys)W, GetShiftPressed(), GetCtrlPressed(), GetAltPressed());
}
if (keydownup == -1)
{
if (KeyUp != null) KeyUp((Keys)W, GetShiftPressed(), GetCtrlPressed(), GetAltPressed());
}
//System.Diagnostics.Debug.WriteLine("Down: " + (Keys)W);
}
}
else
{
KeyEvents kEvent = (KeyEvents)W;
Int32 vkCode = Marshal.ReadInt32((IntPtr)L); //Leser vkCode som er de første 32 bits hvor L peker.
if (kEvent != KeyEvents.KeyDown && kEvent != KeyEvents.KeyUp && kEvent != KeyEvents.SKeyDown && kEvent != KeyEvents.SKeyUp)
{
}
if (kEvent == KeyEvents.KeyDown || kEvent == KeyEvents.SKeyDown)
{
if (KeyDown != null) KeyDown((Keys)vkCode, GetShiftPressed(), GetCtrlPressed(), GetAltPressed());
}
if (kEvent == KeyEvents.KeyUp || kEvent == KeyEvents.SKeyUp)
{
if (KeyUp != null) KeyUp((Keys)vkCode, GetShiftPressed(), GetCtrlPressed(), GetAltPressed());
}
}
}
catch (Exception e)
{
if (OnError != null) OnError(e);
//Ignore all errors...
}
return CallNextHookEx(HookID, Code, W, L);
}
public enum KeyEvents
{
KeyDown = 0x0100,
KeyUp = 0x0101,
SKeyDown = 0x0104,
SKeyUp = 0x0105
}
[DllImport("user32.dll")]
static public extern short GetKeyState(System.Windows.Forms.Keys nVirtKey);
public static bool GetCapslock()
{
return Convert.ToBoolean(GetKeyState(System.Windows.Forms.Keys.CapsLock)) & true;
}
public static bool GetNumlock()
{
return Convert.ToBoolean(GetKeyState(System.Windows.Forms.Keys.NumLock)) & true;
}
public static bool GetScrollLock()
{
return Convert.ToBoolean(GetKeyState(System.Windows.Forms.Keys.Scroll)) & true;
}
public static bool GetShiftPressed()
{
int state = GetKeyState(System.Windows.Forms.Keys.ShiftKey);
if (state > 1 || state < -1) return true;
return false;
}
public static bool GetCtrlPressed()
{
int state = GetKeyState(System.Windows.Forms.Keys.ControlKey);
if (state > 1 || state < -1) return true;
return false;
}
public static bool GetAltPressed()
{
int state = GetKeyState(System.Windows.Forms.Keys.Menu);
if (state > 1 || state < -1) return true;
return false;
}
}
In general, you need to catch the COMException, interrogate ErrorCode (HRESULT) property, and search for the error code definition; this will provide direction on how to troubleshoot the issue further.
Reference: COMException Class: Handling a COMException exception on MSDN
One idea, without knowing the error code, is this interaction might need to occur on the thread which instantiated the control. You might be able to resolve this by using Invoke or BeginInvoke.
Control.BeginInvoke Method
If you add more details to the question I will try to provide a better answer.
Related
I m developing a Multi choices Exam System and needed to disable all the keyboard and just use mouse click, but I got this issue
A callback was made on a garbage collected delegate of type
'UI!UI.Forms.frmExamHome+LowLevelKeyboardProcDelegate::Invoke'. This
may cause application crashes, corruption and data loss. When passing
delegates to unmanaged code, they must be kept alive by the managed
application until it is guaranteed that they will never be called.'
My code:
void wniDisable()
{
intLLKey = SetWindowsHookEx(WH_KEYBOARD_LL, LowLevelKeyboardProc, System.Runtime.InteropServices.Marshal.GetHINSTANCE(System.Reflection.Assembly.GetExecutingAssembly().GetModules()[0]).ToInt32(), 0);
}
[DllImport("user32", EntryPoint = "SetWindowsHookExA", CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)]
public static extern int SetWindowsHookEx(int idHook, LowLevelKeyboardProcDelegate lpfn, int hMod, int dwThreadId);
[DllImport("user32", EntryPoint = "UnhookWindowsHookEx", CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)]
public static extern int UnhookWindowsHookEx(int hHook);
public delegate int LowLevelKeyboardProcDelegate(int nCode, int wParam, ref KBDLLHOOKSTRUCT lParam);
[DllImport("user32", EntryPoint = "CallNextHookEx", CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)]
public static extern int CallNextHookEx(int hHook, int nCode, int wParam, ref KBDLLHOOKSTRUCT lParam);
public const int WH_KEYBOARD_LL = 13;
/*code needed to disable start menu*/
[DllImport("user32.dll")]
private static extern int FindWindow(string className, string windowText);
[DllImport("user32.dll")]
private static extern int ShowWindow(int hwnd, int command);
private const int SW_HIDE = 0;
private const int SW_SHOW = 1;
public struct KBDLLHOOKSTRUCT
{
public int vkCode;
public int scanCode;
public int flags;
public int time;
public int dwExtraInfo;
}
public static int intLLKey;
public int LowLevelKeyboardProc(int nCode, int wParam, ref KBDLLHOOKSTRUCT lParam)
{
bool blnEat = false;
switch (wParam)
{
case 256:
case 257:
case 260:
case 261:
//Alt+Tab, Alt+Esc, Ctrl+Esc, Windows Key,
blnEat = ((lParam.vkCode == 9) && (lParam.flags == 32)) | ((lParam.vkCode == 27) && (lParam.flags == 32)) | ((lParam.vkCode == 27) && (lParam.flags == 0)) | ((lParam.vkCode == 91) && (lParam.flags == 1)) | ((lParam.vkCode == 92) && (lParam.flags == 1)) | ((lParam.vkCode == 73) && (lParam.flags == 0));
break;
}
if (blnEat == true)
{
return 1;
}
else
{
return CallNextHookEx(0, nCode, wParam, ref lParam);
}
}
public void KillStartMenu()
{
int hwnd = FindWindow("Shell_TrayWnd", "");
ShowWindow(hwnd, SW_HIDE);
}
You need to store the hook delegate as class member or the delegate instance will be method local and be garbage collected after you have left the method.
Check out https://github.com/Alois-xx/etwcontroller/blob/master/ETWController/Hooking/Hooker.cs
for a working sample.
class Hooker : IDisposable
{
int MouseHookHandle;
int KeyboardHookHandle;
HookProc MouseHookGCRootedDelegate;
HookProc KeyboardHookGCRootedDelegate;
..
public Hooker()
{
// HookEvents.RegisterItself();
MouseHookGCRootedDelegate = MouseHook;
KeyboardHookGCRootedDelegate = KeyboardHook;
}
void HookKeyboard(bool bHook)
{
if (KeyboardHookHandle == 0 && bHook)
{
using (var mainMod = Process.GetCurrentProcess().MainModule)
KeyboardHookHandle = HookNativeDefinitions.SetWindowsHookEx(HookNativeDefinitions.WH_KEYBOARD_LL, KeyboardHookGCRootedDelegate, HookNativeDefinitions.GetModuleHandle(mainMod.ModuleName), 0);
//If the SetWindowsHookEx function fails.
if (KeyboardHookHandle == 0)
{
System.Windows.MessageBox.Show("SetWindowsHookEx Failed " + new Win32Exception(Marshal.GetLastWin32Error()));
return;
}
}
else if(bHook == false)
{
Debug.Print("Unhook keyboard");
HookNativeDefinitions.UnhookWindowsHookEx(KeyboardHookHandle);
KeyboardHookHandle = 0;
}
}
I'm writing an application that binds custom actions to my mouse buttons. For example, I connected the volume up to one of the thumb buttons. Everything works fine as long as I stay in one window because every other windows and the taskbar seems to freeze and it will take some time before the windows are activated again or if I kill my application or the window I am working in.
In the code below I capture the mouse events and check with the settings in the application if the button action is still default or if it has changed. If the action has changed, then the application should for example turn the volume up with two.
[DllImport("kernel32.dll")]
public static extern IntPtr GetModuleHandle(string name);
public delegate int HookProc(int nCode, IntPtr wParam, IntPtr lParam);
public static bool usingKeyboard = false;
public static bool leftButtonDown = false;
static int hMHook;
public const int WH_MOUSE_LL = 14;
//Declare MouseHookProcedure as a HookProc type.
static HookProc MouseHookProcedure;
private enum MouseMessages
{
WM_LBUTTONDOWN = 0x0201,
WM_LBUTTONUP = 0x0202,
WM_MOUSEMOVE = 0x0200,
WM_MOUSEWHEEL = 0x020A,
WM_RBUTTONDOWN = 0x0204,
WM_RBUTTONUP = 0x0205,
WM_XBUTTONDOWN = 0x020B,
WM_XBUTTONUP = 0x020C,
WM_MBUTTONUP = 0x0208,
WM_MBUTTONDOWN = 0x0207
}
[StructLayout(LayoutKind.Sequential)]
public class POINT
{
public int x;
public int y;
}
[StructLayout(LayoutKind.Sequential)]
public class MouseHookStruct
{
public POINT pt;
public int hwnd;
public int wHitTestCode;
public int dwExtraInfo;
}
[DllImport("kernel32.dll")]
static extern uint GetLastError();
[DllImport("user32.dll", CharSet = CharSet.Auto,
CallingConvention = CallingConvention.StdCall)]
public static extern int SetWindowsHookEx(int idHook, HookProc lpfn,
IntPtr hInstance, int threadId);
[DllImport("user32.dll", CharSet = CharSet.Auto,
CallingConvention = CallingConvention.StdCall)]
public static extern bool UnhookWindowsHookEx(int idHook);
[DllImport("user32.dll", CharSet = CharSet.Auto,
CallingConvention = CallingConvention.StdCall)]
public static extern int CallNextHookEx(int idHook, int nCode,
IntPtr wParam, IntPtr lParam);
private int MouseHookProc(int nCode, IntPtr wParam, IntPtr lParam)
{
MouseHookStruct MyMouseHookStruct = (MouseHookStruct)Marshal.PtrToStructure(lParam, typeof(MouseHookStruct));
MouseUsageMessage message = new MouseUsageMessage(1);
MouseUsageManager.mouseUsageMessageQueue.Add(message);
if (nCode >= 0)
{
if (MouseMessages.WM_LBUTTONDOWN == (MouseMessages)wParam)
{
leftButtonDown = true;
} else if (MouseMessages.WM_LBUTTONUP == (MouseMessages)wParam)
{
leftButtonDown = false;
} else if (MouseMessages.WM_RBUTTONDOWN == (MouseMessages)wParam)
{
} else if (MouseMessages.WM_RBUTTONUP == (MouseMessages) wParam) {
} else if (MouseMessages.WM_XBUTTONUP == (MouseMessages)wParam)
{
switch (MyMouseHookStruct.hwnd)
{
case 65536:
if (Settings.Default.thumbClick1User != Settings.Default.thumbClick1Default)
{
ExecuteAction(Settings.Default.thumbClick1User);
return 1;
}
break;
case 131072:
if (Settings.Default.thumbClick2User != Settings.Default.thumbClick2Default)
{
ExecuteAction(Settings.Default.thumbClick2User);
return 1;
}
break;
}
} else if (MouseMessages.WM_MBUTTONDOWN == (MouseMessages)wParam)
{
}
}
return CallNextHookEx(hMHook, nCode, wParam, lParam);
}
Why are the other windows freezing or why can't I use my mouse on the other windows after I've clicked the thumb buttons?
EDIT: Additional code
private void ExecuteAction(string setting)
{
VolumeControl vc = new VolumeControl();
Keybindings kb = new Keybindings();
switch (setting)
{
case "volUp":
vc.VolUp();
break;
case "volDown":
vc.VolDown();
break;
case "cut":
kb.Cut();
break;
case "selectAll":
kb.SelectAll();
break;
case "copy":
kb.Copy();
break;
default:
break;
}
}
The setting string that is sended to the ExecuteAction function is just a string with the action to be performed, i.e. copy, volume up, volume down etc.
VolumeControl class:
public class VolumeControl
{
private const int APPCOMMAND_VOLUME_MUTE = 0x80000;
private const int APPCOMMAND_VOLUME_UP = 0xA0000;
private const int APPCOMMAND_VOLUME_DOWN = 0x90000;
private const int WM_APPCOMMAND = 0x319;
IntPtr handle = Process.GetCurrentProcess().MainWindowHandle;
[DllImport("user32.dll")]
public static extern IntPtr SendMessageW(IntPtr hWnd, int Msg,
IntPtr wParam, IntPtr lParam);
public void VolDown()
{
SendMessageW(handle, WM_APPCOMMAND, handle,
(IntPtr)APPCOMMAND_VOLUME_DOWN);
}
public void VolUp()
{
SendMessageW(handle, WM_APPCOMMAND, handle,
(IntPtr)APPCOMMAND_VOLUME_UP);
}
}
Create Hook function, the function that is called when the class is initialized:
private void createHook()
{
while (hMHook == 0) //|| hKHook == 0)
{
//if (hMHook == 0)
//{
//hMHook = SetWindowsHookEx(WH_MOUSE_LL,
//MouseHookProcedure,
//GetModuleHandle(Process.GetCurrentProcess().MainModule.ModuleName),
//(IntPtr)0,
//0);
//}
if (hMHook == 0)
{
hMHook = SetWindowsHookEx(WH_MOUSE_LL,
MouseHookProcedure,
GetModuleHandle(Process.GetCurrentProcess().MainModule.ModuleName),
0);
}
if (hMHook == 0) //|| hKHook == 0)
{
Console.WriteLine("SetWindowsHookEx Failed");
return;
}
Console.WriteLine("Hooked");
}
}
My solution, i have built a simple console project
when you launch program, the hook is activated, and you can toggle with middle mouse button. the right button up and letf button up play with system volume..
the main program:
using HookInput.API;
using HookInput.Mouse;
using System;
using System.Diagnostics;
using System.Windows.Forms;
namespace ConsoleApp3
{
public class Program
{
private static MouseInput mouseInputHook = null;
static void Main(string[] args)
{
var vc = new VolumeControl();
mouseInputHook = new MouseInput(vc);
mouseInputHook.setHook(true);
Console.WriteLine("hook activated");
Application.Run(new ApplicationContext());
}
}
public class VolumeControl
{
private const int APPCOMMAND_VOLUME_MUTE = 0x80000;
private const int APPCOMMAND_VOLUME_UP = 0xA0000;
private const int APPCOMMAND_VOLUME_DOWN = 0x90000;
private const int WM_APPCOMMAND = 0x319;
public IntPtr handle = Process.GetCurrentProcess().MainWindowHandle;
public void VolDown()
{
WindowsHookAPI.SendMessageW(handle, WM_APPCOMMAND, handle, (IntPtr)APPCOMMAND_VOLUME_DOWN);
}
public void VolUp()
{
WindowsHookAPI.SendMessageW(handle, WM_APPCOMMAND, handle, (IntPtr)APPCOMMAND_VOLUME_UP);
}
}
}
the APIs:
using System;
using System.Runtime.InteropServices;
namespace HookInput.API
{
public class WindowsHookAPI
{
//public delegate IntPtr HookDelegate(
// Int32 Code, IntPtr wParam, IntPtr lParam);
public delegate IntPtr HookDelegate(Int32 Code, IntPtr wParam, IntPtr lParam);
[DllImport("User32.dll")]
public static extern IntPtr CallNextHookEx(IntPtr hHook, Int32 nCode, IntPtr wParam, IntPtr lParam);
[DllImport("User32.dll")]
public static extern IntPtr UnhookWindowsHookEx(IntPtr hHook);
[DllImport("User32.dll")]
public static extern IntPtr SetWindowsHookEx(Int32 idHook, HookDelegate lpfn, IntPtr hmod, Int32 dwThreadId);
[DllImport("user32.dll")]
public static extern IntPtr SendMessageW(IntPtr hWnd, int Msg, IntPtr wParam, IntPtr lParam);
}
}
the hook and structures:
using HookInput.API;
using System;
using System.IO.MemoryMappedFiles;
using System.Runtime.InteropServices;
using ConsoleApp3;
namespace HookInput.Mouse
{
public class MouseInput
{
private const Int32 WM_MOUSEMOVE = 0x0200;
private const Int32 WM_LBUTTONDOWN = 0x0201;
private const Int32 WM_LBUTTONUP = 0x0202;
private const Int32 WM_LBUTTONDBLCLK = 0x0203;
private const Int32 WM_RBUTTONDOWN = 0x0204;
private const Int32 WM_RBUTTONUP = 0x0205;
private const Int32 WM_RBUTTONDBLCLK = 0x0206;
private const Int32 WM_MBUTTONDOWN = 0x0207;
private const Int32 WM_MBUTTONUP = 0x0208;
private const Int32 WM_MBUTTONDBLCLK = 0x0209;
private const Int32 WM_MOUSEWHEEL = 0x020A;
private const Int32 WM_XBUTTONDOWN = 0x020B;
private const Int32 WM_XBUTTONUP = 0x020C;
private const Int32 WM_XBUTTONDBLCLK = 0x020D;
private MemoryMappedViewAccessor accessor;
private bool hooked = false;
private WindowsHookAPI.HookDelegate mouseDelegate;
private IntPtr mouseHandle;
private const Int32 WH_MOUSE_LL = 14;
private readonly VolumeControl vc;
public MouseInput(VolumeControl vc)
{
this.vc = vc;
}
public void setHook(bool on)
{
if (hooked == on) return;
if (on)
{
mouseDelegate = MouseHookDelegate;
mouseHandle = WindowsHookAPI.SetWindowsHookEx(WH_MOUSE_LL, mouseDelegate, IntPtr.Zero, 0);
if (mouseHandle != IntPtr.Zero) hooked = true;
}
else
{
WindowsHookAPI.UnhookWindowsHookEx(mouseHandle);
hooked = false;
}
}
private IntPtr MouseHookDelegate(Int32 Code, IntPtr wParam, IntPtr lParam)
{
//mouseData:
//If the message is WM_MOUSEWHEEL, the high-order word of this member is the wheel delta.The low-order word is reserved.
// A positive value indicates that the wheel was rotated forward, away from the user;
// a negative value indicates that the wheel was rotated backward, toward the user.
// One wheel click is defined as WHEEL_DELTA, which is 120.(0x78 or 0xFF88)
//If the message is WM_XBUTTONDOWN, WM_XBUTTONUP, WM_XBUTTONDBLCLK, WM_NCXBUTTONDOWN, WM_NCXBUTTONUP, or WM_NCXBUTTONDBLCLK,
// the high - order word specifies which X button was pressed or released,
// and the low - order word is reserved.This value can be one or more of the following values.Otherwise, mouseData is not used.
//XBUTTON1 = 0x0001 The first X button was pressed or released.
//XBUTTON2 = 0x0002 The second X button was pressed or released.
MSLLHOOKSTRUCT lparam = (MSLLHOOKSTRUCT)Marshal.PtrToStructure(lParam, typeof(MSLLHOOKSTRUCT));
int command = (int)wParam;
if (Code < 0 || command == WM_LBUTTONDBLCLK || command == WM_RBUTTONDBLCLK)
return WindowsHookAPI.CallNextHookEx(mouseHandle, Code, wParam, lParam);
else if (command == WM_XBUTTONDOWN || command == WM_XBUTTONUP)
{
int numbutton = ((int)lparam.mouseData >> 16) - 1;
//return (IntPtr)1;
}
else if (command == WM_LBUTTONDOWN || command == WM_LBUTTONUP)
{
if (command == WM_LBUTTONUP)
{
vc.VolDown();
Console.WriteLine("L down");
}
}
else if (command == WM_RBUTTONDOWN || command == WM_RBUTTONUP)
{
if (command == WM_RBUTTONUP)
{
vc.VolUp();
Console.WriteLine("L Up");
}
}
else if (command == WM_MBUTTONDOWN || command == WM_MBUTTONUP)
{
if (hooked)
{
setHook(false);
Console.WriteLine("hook deactivated");
}
else
{
setHook(true);
Console.WriteLine("hook activated");
}
}
else if (command == WM_MOUSEWHEEL)
{
}
return WindowsHookAPI.CallNextHookEx(mouseHandle, Code, wParam, lParam);
}
~MouseInput()
{
}
[StructLayout(LayoutKind.Sequential)]
private struct POINT
{
public int x;
public int y;
}
[StructLayout(LayoutKind.Sequential)]
private struct MSLLHOOKSTRUCT
{
public POINT pt;
public uint mouseData;
public uint flags;
public uint time;
public IntPtr dwExtraInfo;
}
}
}
using System;
using System.ComponentModel;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Windows.Forms;
namespace ScreenYos
{
public class KeyboardHook : IDisposable
{
private bool Global = false;
public delegate void LocalKeyEventHandler(Keys key, bool Printscreen);
public event LocalKeyEventHandler KeyDown;
public event LocalKeyEventHandler KeyUp;
public delegate int CallbackDelegate(int Code, int W, int L);
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct KBDLLHookStruct
{
public Int32 vkCode;
public Int32 scanCode;
public Int32 flags;
public Int32 time;
public Int32 dwExtraInfo;
}
[DllImport("user32", CallingConvention = CallingConvention.StdCall)]
private static extern int SetWindowsHookEx(HookType idHook, CallbackDelegate lpfn, int hInstance, int threadId);
[DllImport("user32", CallingConvention = CallingConvention.StdCall)]
private static extern bool UnhookWindowsHookEx(int idHook);
[DllImport("user32", CallingConvention = CallingConvention.StdCall)]
private static extern int CallNextHookEx(int idHook, int nCode, int wParam, int lParam);
[DllImport("kernel32.dll", CallingConvention = CallingConvention.StdCall)]
private static extern int GetCurrentThreadId();
public enum HookType : int
{
WH_JOURNALRECORD = 0,
WH_JOURNALPLAYBACK = 1,
WH_KEYBOARD = 2,
WH_GETMESSAGE = 3,
WH_CALLWNDPROC = 4,
WH_CBT = 5,
WH_SYSMSGFILTER = 6,
WH_MOUSE = 7,
WH_HARDWARE = 8,
WH_DEBUG = 9,
WH_SHELL = 10,
WH_FOREGROUNDIDLE = 11,
WH_CALLWNDPROCRET = 12,
WH_KEYBOARD_LL = 13,
WH_MOUSE_LL = 14
}
private int HookID = 0;
private CallbackDelegate TheHookCB = null;
public KeyboardHook(bool Global)
{
this.Global = Global;
TheHookCB = new CallbackDelegate(KeybHookProc);
if (Global)
{
HookID = SetWindowsHookEx(HookType.WH_KEYBOARD_LL, TheHookCB,
0,
0);
}
else
{
HookID = SetWindowsHookEx(HookType.WH_KEYBOARD, TheHookCB,
0,
GetCurrentThreadId());
}
}
private bool IsFinalized;
~KeyboardHook()
{
if (!IsFinalized)
{
UnhookWindowsHookEx(HookID);
IsFinalized = true;
}
}
public void Dispose()
{
if (!IsFinalized)
{
UnhookWindowsHookEx(HookID);
IsFinalized = true;
}
}
private int KeybHookProc(int Code, int W, int L)
{
KBDLLHookStruct LS = new KBDLLHookStruct();
if (Code < 0)
{
return CallNextHookEx(HookID, Code, W, L);
}
try
{
if (!Global)
{
if (Code == 3)
{
IntPtr ptr = IntPtr.Zero;
int keydownup = L >> 30;
if (keydownup == 0)
{
if (KeyDown != null)
KeyDown((Keys) W, GetPrintscreenPressed());
}
if (keydownup == -1)
{
if (KeyUp != null) KeyUp((Keys) W, GetPrintscreenPressed());
}
//System.Diagnostics.Debug.WriteLine("KeyDown: " + (Keys)W);
}
}
else
{
KeyEvents kEvent = (KeyEvents) W;
Int32 vkCode = Marshal.ReadInt32((IntPtr) L);
if (kEvent != KeyEvents.KeyDown && kEvent != KeyEvents.KeyUp && kEvent != KeyEvents.SKeyDown &&
kEvent != KeyEvents.SKeyUp)
{
}
if (kEvent == KeyEvents.KeyDown || kEvent == KeyEvents.SKeyDown)
{
if (KeyDown != null)
KeyDown((Keys) vkCode, GetPrintscreenPressed());
}
if (kEvent == KeyEvents.KeyUp || kEvent == KeyEvents.SKeyUp)
{
if (KeyUp != null) KeyUp((Keys) vkCode, GetPrintscreenPressed());
}
}
}
catch (Exception e)
{
//Console.WriteLine(e.Message);
}
return CallNextHookEx(HookID, Code, W, L);
}
public enum KeyEvents
{
KeyDown = 0x0100,
KeyUp = 0x0101,
SKeyDown = 0x0104,
SKeyUp = 0x0105
}
[DllImport("user32.dll")]
public static extern short GetKeyState(Keys nVirtKey);
public static bool GetPrintscreenPressed()
{
int state = GetKeyState(Keys.PrintScreen);
if (state > 1 || state < -1) return true;
return false;
}
}
}
My usage:
private static void Kh_KeyDown(Keys key, bool Printscreen)
{
if (new Form1().ShowDialog() == DialogResult.OK)
{
Application.Run(new Form1());
}
}
So program runs in system tray and the aim of the code is capture keys globally and when printscreen is pressed run Form1 yet it captures every key and no matter what key i press, it runs form1.
I assume that's because you initialized a general callback for all Keys on KeyDown.
You must either filter by Keys.PrintScreen when you call the event
or
Filter by Keys.PrintScreen in your Eventhandler.
private static void Kh_KeyDown(Keys key, bool Printscreen)
{
if (key == Keys.PrintScreen && new Form1().ShowDialog() == DialogResult.OK)
{
Application.Run(new Form1());
}
}
Thomas
i have my program that Captures weighing and send it to a open window.
its work excellent , except with a single software - Microsoft Word
I have tried everything and have no idea why.
my code:
this is the GlobalKeyBoardHook.cs class
public class GlobalKeyboardHook
{
[DllImport("user32.dll")]
static extern int CallNextHookEx(IntPtr hhk, int code, int wParam, ref keyBoardHookStruct lParam);
[DllImport("user32.dll")]
static extern IntPtr SetWindowsHookEx(int idHook, LLKeyboardHook callback, IntPtr hInstance, uint theardID);
[DllImport("user32.dll")]
static extern bool UnhookWindowsHookEx(IntPtr hInstance);
[DllImport("kernel32.dll")]
static extern IntPtr LoadLibrary(string lpFileName);
public delegate int LLKeyboardHook(int Code, int wParam, ref keyBoardHookStruct lParam);
public struct keyBoardHookStruct
{
public int vkCode;
public int scanCode;
public int flags;
public int time;
public int dwExtraInfo;
}
const int WH_KEYBOARD_LL = 13;
const int WM_KEYDOWN = 0x0100;
const int WM_KEYUP = 0x0101;
const int WM_SYSKEYDOWN = 0x0104;
const int WM_SYSKEYUP = 0x0105;
LLKeyboardHook llkh;
public List<Keys> HookedKeys = new List<Keys>();
IntPtr Hook = IntPtr.Zero;
public event KeyEventHandler KeyDown;
public event KeyEventHandler KeyUp;
// This is the Constructor. This is the code that runs every time you create a new GlobalKeyboardHook object
public GlobalKeyboardHook()
{
llkh = new LLKeyboardHook(HookProc);
// This starts the hook. You can leave this as comment and you have to start it manually (the thing I do in the tutorial, with the button)
// Or delete the comment mark and your hook will start automatically when your program starts (because a new GlobalKeyboardHook object is created)
// That's why there are duplicates, because you start it twice! I'm sorry, I haven't noticed this...
// hook(); <-- Choose!
}
~GlobalKeyboardHook()
{ unhook(); }
public void hook()
{
IntPtr hInstance = LoadLibrary("User32");
Hook = SetWindowsHookEx(WH_KEYBOARD_LL, llkh, hInstance, 0);
}
public void unhook()
{
UnhookWindowsHookEx(Hook);
}
public int HookProc(int Code, int wParam, ref keyBoardHookStruct lParam)
{
if (Code >= 0)
{
Keys key = (Keys)lParam.vkCode;
if (HookedKeys.Contains(key))
{
KeyEventArgs kArg = new KeyEventArgs(key);
if ((wParam == WM_KEYDOWN || wParam == WM_SYSKEYDOWN) && (KeyDown != null))
KeyDown(this, kArg);
else if ((wParam == WM_KEYUP || wParam == WM_SYSKEYUP) && (KeyUp != null))
KeyUp(this, kArg);
if (kArg.Handled)
return 1;
}
}
return CallNextHookEx(Hook, Code, wParam, ref lParam);
}
// --- from here start the program --
GlobalKeyboardHook gHook;
gHook = new GlobalKeyboardHook(); // Create a new GlobalKeyboardHook
gHook.KeyDown += new KeyEventHandler(gHook_KeyDown);
foreach (Keys key in Enum.GetValues(typeof(Keys)))
{
gHook.HookedKeys.Add(key);
}
gHook.hook();
public void gHook_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyValue == KeyPressg) //Pause-Break //19
{
ProccName = (GetActiveWindowTitle().ToString());
Start(ProccName);
gHook.unhook();
gHook.hook();
}
else
{
}
}
private string GetActiveWindowTitle()
{
const int nChars = 256;
StringBuilder Buff = new StringBuilder(nChars);
IntPtr handle = GetForegroundWindow();
if (GetWindowText(handle, Buff, nChars) > 0)
{
return Buff.ToString();
}
return null;
}
[DllImport("user32.dll")]
static extern IntPtr GetForegroundWindow();
[DllImport("user32.dll", CharSet = CharSet.Auto)]
static extern int GetWindowText(IntPtr hWnd, StringBuilder text, int count);
[DllImport("user32.dll")]
private static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
[DllImport("user32.dll")]
private static extern bool SetForegroundWindow(IntPtr hWnd);
public void Start(string NAME)
{
MSG = lblMSG.Text.Trim();
IntPtr zero = IntPtr.Zero;
for (int i = 0; (i < 60) && (zero == IntPtr.Zero); i++)
{
Thread.Sleep(500);
zero = FindWindow(null, NAME);
}
if (zero != IntPtr.Zero)
{
try
{
string text = lblMSG.Text.Trim();
text = text.Replace("gHook", "");
//OLD
//foreach (char c in text)
// SendKeys.SendWait(c.ToString());
//NEW
if (text.Length == 0) return;
SendKeys.SendWait(text);
if (MyParam._KeyAfter == "Enter")
{
MyParam.FromKEY = true;
SendKeys.SendWait("{ENTER}");
}
else if (MyParam._KeyAfter == "TAB")
{
SendKeys.SendWait("{TAB}");
}
else if (MyParam._KeyAfter == "Key Down")
{
SendKeys.SendWait("{DOWN}");
}
SendKeys.Flush();
}
catch { }
}
}
Any ideas why ?
thanks
EDIT
i fount the problem place:
public void Start(string NAME)
{
// --> NAME Contain --> Word - 123.docx for example when Word window open
MSG = lblMSG.Text.Trim();
IntPtr zero = IntPtr.Zero;
for (int i = 0; (i < 60) && (zero == IntPtr.Zero); i++)
{
Thread.Sleep(500);
zero = FindWindow(null, NAME); // <-- in Word zero Always Contain 0 And never goes on in the code so stuck
}
// <--- the program stops here and stuck
if (zero != IntPtr.Zero)
{
I encounter a problem to make my Office Addin works with my global keyboard on Powerpoint 2013 but not on the previous versions (2007 and 2010).
I do not get any exception but it seems that the OnKeyDown event is never triggered on Powerpoint 2013, and I don't know why.
I get the same problems on all versions of Windows (XP, 7, 8 & 8.1), on 32 & 64 bits environments. The version of Microsoft Office is 32 bits.
Here is a code sample :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Linq;
using PowerPoint = Microsoft.Office.Interop.PowerPoint;
using Office = Microsoft.Office.Core;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using System.Diagnostics;
namespace testHook
{
public partial class ThisAddIn
{
Hook hook;
private void ThisAddIn_Startup(object sender, System.EventArgs e)
{
hook = new Hook(Hook.HookType.KeyBoard, Hook.HookVisibility.Global);
hook.OnKeyDown += new KeyEventHandler(hook_OnKeyDown);
hook.Start();
}
void hook_OnKeyDown(object sender, KeyEventArgs e)
{
MessageBox.Show(e.KeyCode.ToString());
}
private void ThisAddIn_Shutdown(object sender, System.EventArgs e)
{
hook.Stop();
hook = null;
}
#region VSTO generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InternalStartup()
{
this.Startup += new System.EventHandler(ThisAddIn_Startup);
this.Shutdown += new System.EventHandler(ThisAddIn_Shutdown);
}
#endregion
class Hook
{
private IntPtr m_Hook = (IntPtr)0;
private HookVisibility m_Visibility;
private HookType m_HookType;
private HookProc m_Proc;
public enum HookType { KeyBoard };
public enum KeyBoardEventType { KeyDown, KeyUp, SysKeyDown, SysKeyUp, KeyShift, KeyCapital, NumLock };
public enum HookVisibility { Global, Local };
private delegate IntPtr HookProc(int nCode, int wParam, IntPtr lParam);
private KeyPressEventHandler m_onKeyPress;
private KeyEventHandler m_onKeyUp;
private KeyEventHandler m_onKeyDown;
public event KeyPressEventHandler OnKeyPress
{
add
{
m_onKeyPress += value;
}
remove
{
m_onKeyPress -= value;
}
}
public event KeyEventHandler OnKeyUp
{
add
{
m_onKeyUp += value;
}
remove
{
m_onKeyUp -= value;
}
}
public event KeyEventHandler OnKeyDown
{
add
{
m_onKeyDown += value;
}
remove
{
m_onKeyDown -= value;
}
}
#region DLLImport
[DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall, SetLastError = true)]
private static extern IntPtr SetWindowsHookEx(int idHook, HookProc lpfn, IntPtr hmod, int dwThreadId);
[DllImport("user32.dll")]
private static extern IntPtr CallNextHookEx(IntPtr hHook, int nCode, IntPtr wParam, IntPtr lParam);
[DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall, SetLastError = true)]
private static extern bool UnhookWindowsHookEx(IntPtr hHook);
[DllImport("Kernel32.dll", SetLastError = true)]
private static extern IntPtr GetModuleHandle(IntPtr lpModuleName);
[DllImport("Kernel32.dll", SetLastError = true)]
private static extern IntPtr GetModuleHandle(String lpModuleName);
[DllImport("Kernel32.dll")]
private static extern IntPtr GetCurrentThreadId();
[DllImport("user32")]
private static extern int ToAscii(int uVirtKey, int uScanCode, byte[] lpbKeyState, byte[] lpwTransKey, int fuState);
[DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
private static extern short GetKeyState(int vKey);
[DllImport("user32")]
private static extern int GetKeyboardState(byte[] pbKeyState);
#endregion
[StructLayout(LayoutKind.Sequential)]
private class KeyboardHookStruct
{
public int vkCode;
public int scanCode;
public int flags;
public int time;
public int dwExtraInfo;
}
public Hook(HookType H, HookVisibility H2)
{
m_HookType = H;
m_Visibility = H2;
}
public bool Start()
{
if (m_HookType == HookType.KeyBoard)
m_Proc = new HookProc(KeyProc);
if (m_Visibility == HookVisibility.Global)
m_Hook = SetWindowsHookEx(getHookType(m_HookType, m_Visibility), m_Proc, GetModuleHandle(Process.GetCurrentProcess().MainModule.ModuleName), 0);
else if (m_Visibility == HookVisibility.Local)
m_Hook = SetWindowsHookEx(getHookType(m_HookType, m_Visibility), m_Proc, GetModuleHandle((IntPtr)0), (int)GetCurrentThreadId());
if (m_Hook == (IntPtr)0)
return false;
return true;
}
public bool Stop()
{
return UnhookWindowsHookEx(m_Hook);
}
private int getHookType(HookType H, HookVisibility V)
{
if (H == HookType.KeyBoard && V == HookVisibility.Local)
return 2;
if (H == HookType.KeyBoard && V == HookVisibility.Global)
return 13;
else return -1;
}
private int getKeyBoardEventType(KeyBoardEventType K)
{
if (K == KeyBoardEventType.KeyDown)
return 0x100;
if (K == KeyBoardEventType.KeyUp)
return 0x101;
if (K == KeyBoardEventType.SysKeyDown)
return 0x104;
if (K == KeyBoardEventType.SysKeyUp)
return 0x105;
if (K == KeyBoardEventType.KeyShift)
return 0x10;
if (K == KeyBoardEventType.KeyCapital)
return 0x14;
if (K == KeyBoardEventType.NumLock)
return 0x90;
else return -1;
}
private IntPtr KeyProc(int nCode, int wParam, IntPtr lParam)
{
bool handled = false;
if ((nCode >= 0) && (m_onKeyDown != null || m_onKeyUp != null || m_onKeyPress != null))
{
KeyboardHookStruct MyKeyboardHookStruct = (KeyboardHookStruct)Marshal.PtrToStructure(lParam, typeof(KeyboardHookStruct));
if (m_onKeyDown != null && (wParam == 0x100 || wParam == 0x104))
{
Keys keyData = (Keys)MyKeyboardHookStruct.vkCode;
KeyEventArgs e = new KeyEventArgs(keyData);
m_onKeyDown(this, e);
handled = handled || e.Handled;
}
if (m_onKeyPress != null && wParam == 0x100)
{
bool isShift = ((GetKeyState(0x10) & 0x80) == 0x80 ? true : false);
bool isCapslock = (GetKeyState(0x14) != 0 ? true : false);
byte[] keyState = new byte[256];
GetKeyboardState(keyState);
byte[] inBuffer = new byte[2];
if (ToAscii(MyKeyboardHookStruct.vkCode, MyKeyboardHookStruct.scanCode, keyState, inBuffer, MyKeyboardHookStruct.flags) == 1)
{
char key = (char)inBuffer[0];
if ((isCapslock ^ isShift) && Char.IsLetter(key))
key = Char.ToUpper(key);
KeyPressEventArgs e = new KeyPressEventArgs(key);
m_onKeyPress(this, e);
handled = handled || e.Handled;
}
}
if (m_onKeyUp != null && (wParam == 0x101 || wParam == 0x105))
{
Keys keyData = (Keys)MyKeyboardHookStruct.vkCode;
KeyEventArgs e = new KeyEventArgs(keyData);
m_onKeyUp(this, e);
handled = handled || e.Handled;
}
}
if (handled)
return (IntPtr)1;
else
return CallNextHookEx(m_Hook, nCode, (IntPtr)wParam, (IntPtr)lParam);
}
}
}
My application need to fire events during the slideshow because I have some others windows which are displayed during the presentation, and I have to update them according to the keys that the user presses. I have tried a lot of solutions but the hook is the only one that can do perfectly the job.
I tried too a local keyboard hook instead of a global one. I actually think that it is the only way to make it works because it is a bug from Microsoft, and not from the code. However, I can't make the local one works properly on any version of Powerpoint.
The issue is not Powerpoint specific, it occurs with any Office product.
I'm working on a Outlook addin and fancing this problem.
It has been reported (without any answer unfortunely) to Microsoft:
https://social.msdn.microsoft.com/Forums/office/en-US/93d08ccc-9e77-4f72-9c51-477468d89681/keyboardhook-will-not-work-in-word-2013?forum=worddev
I have been able to make a "workaround": i have register a Global Hook AND a Local one ("Thread"). It works, but the keyProc is called "weirdly" when it's local, not respecting documented parameters:
- wParam is not one of WM_*, but contains directly the vkCode
- lParam cannot be accessed (AccessViolation)
As I understood, it's because some "TranslateMessage" processing.
I have also adapted your code to be able to catch ALT combination.
private bool wParamAlt;
private IntPtr KeyProc(int nCode, int wParam, IntPtr lParam)
{
bool handled = false;
if ((nCode == 0) && (m_onKeyDown != null || m_onKeyUp != null || m_onKeyPress != null))
{
KeyboardHookStruct MyKeyboardHookStruct;
if (wParam >= 0x100)
{
MyKeyboardHookStruct = (KeyboardHookStruct)Marshal.PtrToStructure(lParam, typeof(KeyboardHookStruct));
wParamAlt = false;
}
else
{
MyKeyboardHookStruct = new KeyboardHookStruct();
MyKeyboardHookStruct.vkCode = wParam;
if (wParamAlt)
{
wParamAlt = (wParam == 18);
wParam = 0x104;
}
else
{
wParamAlt = (wParam == 18);
wParam = 0x100;
}
}
if (m_onKeyDown != null && (wParam == 0x100 || wParam == 0x104))
{
Keys keyData = (Keys)MyKeyboardHookStruct.vkCode;
if (wParam == 0x104)
keyData |= Keys.Alt;
KeyEventArgs e = new KeyEventArgs(keyData);
m_onKeyDown(this, e);
handled = handled || e.Handled;
}
if (m_onKeyPress != null && wParam == 0x100)
{
bool isShift = ((GetKeyState(0x10) & 0x80) == 0x80 ? true : false);
bool isCapslock = (GetKeyState(0x14) != 0 ? true : false);
byte[] keyState = new byte[256];
GetKeyboardState(keyState);
byte[] inBuffer = new byte[2];
if (ToAscii(MyKeyboardHookStruct.vkCode, MyKeyboardHookStruct.scanCode, keyState, inBuffer, MyKeyboardHookStruct.flags) == 1)
{
char key = (char)inBuffer[0];
if ((isCapslock ^ isShift) && Char.IsLetter(key))
key = Char.ToUpper(key);
KeyPressEventArgs e = new KeyPressEventArgs(key);
m_onKeyPress(this, e);
handled = handled || e.Handled;
}
}
if (m_onKeyUp != null && (wParam == 0x101 || wParam == 0x105))
{
Keys keyData = (Keys)MyKeyboardHookStruct.vkCode;
if (wParam == 0x105)
keyData |= Keys.Alt;
KeyEventArgs e = new KeyEventArgs(keyData);
m_onKeyUp(this, e);
handled = handled || e.Handled;
}
}
if (handled)
return (IntPtr)1;
else
return CallNextHookEx(m_Hook, nCode, (IntPtr)wParam, (IntPtr)lParam);
}