Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    text
    copied!<p>As outlined <a href="http://social.msdn.microsoft.com/Forums/en-CA/csharpgeneral/thread/3a048d00-2dbd-4b07-a860-c09bd1e254e9" rel="nofollow">here</a> there is a problem with Windows Forms' ActiveX container support. The keyboard message does not get passed to the Flash player. </p> <p>The solution I've come up with (based on code from <a href="http://social.msdn.microsoft.com/Forums/en-US/winforms/thread/8f573d2c-7ba5-480e-a25d-b2ce608d8b5f/" rel="nofollow">here</a>) is to write a keyboard hook to catch the Escape key and to pass a message to the Flash window to close if it's active.</p> <p>First, there's the <code>KeyHook</code> class which provides the plumbing to listen for the Escape key. </p> <pre><code>using System; using System.Collections.Generic; using System.Diagnostics; using System.Runtime.InteropServices; using System.Windows.Forms; namespace Your.Utility { public class KeyBordHook { private const int WM_KEYDOWN = 0x100; private const int WM_KEYUP = 0x101; private const int WM_SYSKEYDOWN = 0x104; private const int WM_SYSKEYUP = 0x105; //Global event public event KeyEventHandler OnKeyDownEvent; public event KeyEventHandler OnKeyUpEvent; public event KeyPressEventHandler OnKeyPressEvent; private static int hKeyboardHook = 0; private const int WH_KEYBOARD_LL = 13; //keyboard hook constant private HookProc KeyboardHookProcedure; // declare keyhook event type //declare keyhook struct [StructLayout(LayoutKind.Sequential)] public class KeyboardHookStruct { public int vkCode; public int scanCode; public int flags; public int time; public int dwExtraInfo; } [DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)] private static extern int SetWindowsHookEx(int idHook, HookProc lpfn, IntPtr hInstance, int threadId); [DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)] private static extern bool UnhookWindowsHookEx(int idHook); [DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)] private static extern int CallNextHookEx(int idHook, int nCode, Int32 wParam, IntPtr lParam); [DllImport("user32")] private static extern int ToAscii(int uVirtKey, int uScanCode, byte[] lpbKeyState, byte[] lpwTransKey, int fuState); [DllImport("user32")] private static extern int GetKeyboardState(byte[] pbKeyState); [DllImport("kernel32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)] private static extern IntPtr GetModuleHandle(string lpModuleName); private delegate int HookProc(int nCode, Int32 wParam, IntPtr lParam); private List&lt;Keys&gt; preKeys = new List&lt;Keys&gt;(); public KeyBordHook() { Start(); } ~KeyBordHook() { Stop(); } public void Start() { //install keyboard hook if (hKeyboardHook == 0) { KeyboardHookProcedure = new HookProc(KeyboardHookProc); //hKeyboardHook = SetWindowsHookEx(WH_KEYBOARD_LL, KeyboardHookProcedure, Marshal.GetHINSTANCE(Assembly.GetExecutingAssembly().GetModules()[0]), 0); Process curProcess = Process.GetCurrentProcess(); ProcessModule curModule = curProcess.MainModule; hKeyboardHook = SetWindowsHookEx(WH_KEYBOARD_LL, KeyboardHookProcedure, GetModuleHandle(curModule.ModuleName), 0); if (hKeyboardHook == 0) { Stop(); throw new Exception("SetWindowsHookEx ist failed."); } } } public void Stop() { bool retKeyboard = true; if (hKeyboardHook != 0) { retKeyboard = UnhookWindowsHookEx(hKeyboardHook); hKeyboardHook = 0; } //if unhook failed if (!(retKeyboard)) throw new Exception("UnhookWindowsHookEx failed."); } private int KeyboardHookProc(int nCode, Int32 wParam, IntPtr lParam) { if ((nCode &gt;= 0) &amp;&amp; (OnKeyDownEvent != null || OnKeyUpEvent != null || OnKeyPressEvent != null)) { KeyboardHookStruct MyKeyboardHookStruct = (KeyboardHookStruct)Marshal.PtrToStructure(lParam, typeof(KeyboardHookStruct)); if ((OnKeyDownEvent != null || OnKeyPressEvent != null) &amp;&amp; (wParam == WM_KEYDOWN || wParam == WM_SYSKEYDOWN)) { Keys keyData = (Keys)MyKeyboardHookStruct.vkCode; if (IsCtrlAltShiftKeys(keyData) &amp;&amp; preKeys.IndexOf(keyData) == -1) { preKeys.Add(keyData); } } if (OnKeyDownEvent != null &amp;&amp; (wParam == WM_KEYDOWN || wParam == WM_SYSKEYDOWN)) { Keys keyData = (Keys)MyKeyboardHookStruct.vkCode; KeyEventArgs e = new KeyEventArgs(GetDownKeys(keyData)); OnKeyDownEvent(this, e); } if (OnKeyPressEvent != null &amp;&amp; wParam == WM_KEYDOWN) { byte[] keyState = new byte[256]; GetKeyboardState(keyState); byte[] inBuffer = new byte[2]; if (ToAscii(MyKeyboardHookStruct.vkCode, MyKeyboardHookStruct.scanCode, keyState, inBuffer, MyKeyboardHookStruct.flags) == 1) { KeyPressEventArgs e = new KeyPressEventArgs((char)inBuffer[0]); OnKeyPressEvent(this, e); } } if ((OnKeyDownEvent != null || OnKeyPressEvent != null) &amp;&amp; (wParam == WM_KEYUP || wParam == WM_SYSKEYUP)) { Keys keyData = (Keys)MyKeyboardHookStruct.vkCode; if (IsCtrlAltShiftKeys(keyData)) { for (int i = preKeys.Count - 1; i &gt;= 0; i--) { if (preKeys[i] == keyData) { preKeys.RemoveAt(i); } } } } if (OnKeyUpEvent != null &amp;&amp; (wParam == WM_KEYUP || wParam == WM_SYSKEYUP)) { Keys keyData = (Keys)MyKeyboardHookStruct.vkCode; KeyEventArgs e = new KeyEventArgs(GetDownKeys(keyData)); OnKeyUpEvent(this, e); } } return CallNextHookEx(hKeyboardHook, nCode, wParam, lParam); } private Keys GetDownKeys(Keys key) { Keys rtnKey = Keys.None; foreach (Keys keyTemp in preKeys) { switch (keyTemp) { case Keys.LControlKey: case Keys.RControlKey: rtnKey = rtnKey | Keys.Control; break; case Keys.LMenu: case Keys.RMenu: rtnKey = rtnKey | Keys.Alt; break; case Keys.LShiftKey: case Keys.RShiftKey: rtnKey = rtnKey | Keys.Shift; break; default: break; } } rtnKey = rtnKey | key; return rtnKey; } private Boolean IsCtrlAltShiftKeys(Keys key) { switch (key) { case Keys.LControlKey: case Keys.RControlKey: case Keys.LMenu: case Keys.RMenu: case Keys.LShiftKey: case Keys.RShiftKey: return true; default: return false; } } } } </code></pre> <p>Next, you need to create an instance of the <code>KeyHook</code> class in your Windows Form ...</p> <pre><code>// inside Form class ... private readonly KeyBordHook _keyBordHook = new KeyBordHook(); private void InitKeyHook() { _keyBordHook.OnKeyPressEvent += new KeyPressEventHandler(_KeyBordHook_OnKeyPressEvent); _keyBordHook.Start(); } void _KeyBordHook_OnKeyPressEvent(object sender, KeyPressEventArgs e) { if (e.KeyChar == Convert.ToChar(Keys.Escape)) WindowHelper.CloseWindowIfActive("Flash"); } public void StartKeyListening() { InitKeyHook(); } public void StopKeyListening() { _keyBordHook.Stop(); } </code></pre> <p>And, the code to actually close the Flash Window...</p> <pre><code>public sealed class WindowHelper { [DllImport("USER32.dll", SetLastError = true)] private static extern IntPtr GetForegroundWindow(); [DllImport("USER32.dll", SetLastError = true)] private static extern int GetWindowText(IntPtr hWnd, StringBuilder text, int count); static uint WM_CLOSE = 0x10; [return: MarshalAs(UnmanagedType.Bool)] [DllImport("USER32.dll", SetLastError = true)] static extern bool PostMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam); private static bool CloseWindow(IntPtr hWnd) { bool returnValue = PostMessage(hWnd, WM_CLOSE, IntPtr.Zero, IntPtr.Zero); if (!returnValue) throw new Win32Exception(Marshal.GetLastWin32Error()); return true; } public static void CloseWindowIfActive(string windowTitle) { const int nChars = 256; StringBuilder buff = new StringBuilder(nChars); IntPtr handle = GetForegroundWindow(); if (GetWindowText(handle, buff, nChars) &lt;= 0) return; if (buff.ToString().ToLower().IndexOf(windowTitle.ToLower()) &gt; -1) CloseWindow(handle); } } </code></pre> <p>I'm sure there's improvements to be made in all of the above but so far, this solution appears to work for me.</p> <p><strong>Note</strong> that this code allows you to <em>record all key strokes</em> across all apps so it's definitely overkill and may not be desirable to integrate into a customer bound application!</p>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload