Excel VSTO Key hook

后端 未结 1 1235
名媛妹妹
名媛妹妹 2020-12-18 13:05

I want to change cell color when Enter key is pressed. Everything is fine except, that code doesn\'t work in active Excel 2013, only when it is in background. H

相关标签:
1条回答
  • 2020-12-18 13:48

    The main mistake you made in your code is using WH_KEYBOARD_LL. It will not work well in Excel, use WH_KEYBOARD instead. The code below allows you to catch any key pressed, check modifiers and invoke some action.

    using System;
    using System.Runtime.InteropServices;
    using System.Windows.Forms;
    using Microsoft.Office.Interop.Excel;
    
    namespace SimpleExcelAddIn {
        static class ShortcutManager {
            delegate int LowLevelKeyboardProc(int nCode, IntPtr wParam, IntPtr lParam);
            static readonly LowLevelKeyboardProc _proc = HookCallback;
            static IntPtr _hookID = IntPtr.Zero;
            const int WH_KEYBOARD = 2;
            const int HC_ACTION = 0;
            [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
            static extern IntPtr SetWindowsHookEx(int idHook, LowLevelKeyboardProc lpfn, IntPtr hMod, uint dwThreadId);
            [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
            static extern bool UnhookWindowsHookEx(IntPtr idHook);
            [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
            static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode, IntPtr wParam, IntPtr lParam);
            [DllImport("user32.dll")]
            static extern short GetKeyState(int nVirtKey);
    
            static bool _keyHookingStarted;
            public static void Start() {
                if (!_keyHookingStarted) {
    #pragma warning disable 0618
                    _hookID = SetWindowsHookEx(WH_KEYBOARD, _proc, IntPtr.Zero, (uint) AppDomain.GetCurrentThreadId());
    #pragma warning restore 0618
                    _keyHookingStarted = true;
                }
            }
            public static void Stop() {
                if (_keyHookingStarted) {
                    UnhookWindowsHookEx(_hookID);
                    _hookID = IntPtr.Zero;
                    _keyHookingStarted = false;
                }
            }
            static void OnKeyPress(uint keys) {
                Func<Keys, bool> checkKey = key => keys == (uint) key && IsKeyDown(key);
    
                //checks that shift, alt, ctrl and win keys are not pressed
                Func<bool> checkModifiers = () => !IsKeyDown(Keys.ShiftKey)
                    && !IsKeyDown(Keys.Menu) // Keys.Menu is Alt button code
                    && !IsKeyDown(Keys.LWin) && !IsKeyDown(Keys.RWin);
    
                if (checkModifiers() && (checkKey(Keys.Enter) || checkKey(Keys.Return))) {
                    // Make you actions here. If it is some long action, do it in background thread
                    // this code is just and example
                    Worksheet ws = Globals.ThisAddIn.Application.ActiveSheet;
                    Range cell = ws.Cells[1, 1];
                    cell.Interior.Color = 0xFF0000;
                }
            }
            static bool IsKeyDown(Keys keys) {
                return (GetKeyState((int) keys) & 0x8000) == 0x8000;
            }
            static int HookCallback(int nCode, IntPtr wParam, IntPtr lParam) {
                if (nCode < 0) {
                    return (int) CallNextHookEx(_hookID, nCode, wParam, lParam);
                }
                if (nCode == HC_ACTION) {
                    OnKeyPress((uint) wParam);
                }
                return (int) CallNextHookEx(_hookID, nCode, wParam, lParam);
            }
        }
    }
    

    To use this class, call Start() and Stop() methods.

    0 讨论(0)
提交回复
热议问题