Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Get Keyboard input for Word process in VSTO AddIn

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());
}
like image 804
ninjaxelite Avatar asked Aug 22 '19 08:08

ninjaxelite


Video Answer


1 Answers

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.

like image 190
Jeremy Thompson Avatar answered Oct 27 '22 13:10

Jeremy Thompson