Как отцепить клавиатуру с помощью c # для разработки программного обеспечения для изменения нажатий клавиш - PullRequest
3 голосов
/ 01 декабря 2010

Я пытаюсь разработать программное обеспечение, которое будет принимать ввод с клавиатуры, потреблять ввод и возвращать некоторые другие символы, заменяющие типизированный ввод. Например, если я наберу: «abcd» и определю правило обмена как любой русский алфавит, то я буду ожидать вывода как: «ский».

Код, который я использую, выглядит следующим образом:

namespace hook_form
{
    public partial class Form1 : Form
    {
        //Keyboard API constants

        private const int WH_KEYBOARD_LL = 13;
        private const int WM_KEYDOWN = 0x0100;
        private const int WM_KEYUP = 0x0101;
        private const int WM_SYSKEYUP = 0x0105;
        private const int WM_SYSKEYDOWN = 0x0104;
        private HookHandlerDelegate proc;
        private IntPtr hookID = IntPtr.Zero;
        private delegate IntPtr HookHandlerDelegate(int nCode, IntPtr wParam, ref KBDLLHOOKSTRUCT lParam);

        private struct KBDLLHOOKSTRUCT
        {
            public int vkCode;
            int scanCode;
            public int flags;
            int time;
            int dwExtraInfo;
        }

        private IntPtr HookCallback(int nCode, IntPtr wParam, ref KBDLLHOOKSTRUCT lParam)
        {
            bool AllowKey = false;

            switch (lParam.vkCode)
            {
                case (65|97|66|98): // key codes for "a/b/c/d" etc. goes here
                    //Alt+Tab, Alt+Esc, Ctrl+Esc, Windows Key
                    AllowKey = true;
                    SendKeys.Send("\u0997"); // code for russian letters here....
                    break;
            }

            MessageBox.Show(lParam.vkCode.ToString());

            if (AllowKey == false)
                return (System.IntPtr)1;

            return CallNextHookEx(hookID, nCode, wParam, ref lParam);
        }
        #region DllImports

        [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        private static extern IntPtr SetWindowsHookEx(int idHook, 
        HookHandlerDelegate 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, ref KBDLLHOOKSTRUCT lParam);

        [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        private static extern IntPtr GetModuleHandle(string lpModuleName); 
        #endregion

        private void buttonStart_Click(object sender, EventArgs e)
        {
            proc = new HookHandlerDelegate(HookCallback);
            using (Process curProcess = Process.GetCurrentProcess())
            using (ProcessModule curModule = curProcess.MainModule)
            {
                hookID = SetWindowsHookEx(WH_KEYBOARD_LL, proc,
                GetModuleHandle(curModule.ModuleName), 0);
            }
        }

        private void btnEnd_Click(object sender, EventArgs e)
        {
            UnhookWindowsHookEx(hookID);
        }
    }
}

Я получаю вывод как: "aсbкcиdй", я имею в виду, что напечатанные буквы (английские) не потребляются кодом (я имею в виду, что они не должны появляться в выводе), даже если я вернул (System.IntPtr)1.

Я думаю, что это проблема отцепления. Может ли кто-нибудь помочь мне решить эту проблему?

Если это невозможно, может кто-нибудь посоветовать мне какое-нибудь программное обеспечение с открытым исходным кодом, использующее клавиатуру?

Ответы [ 2 ]

1 голос
/ 01 декабря 2010

Старайтесь не вызывать CallNextHookEx для событий, которые вы хотите проглотить.

Редактировать: Итак, я вижу одну проблему - нажатие клавиши генерирует два сообщения WM_KEYDOWN и WM_KEYUP.Вы вводите новое сообщение клавиатуры для обоих случаев, дублируя его.Пример ссылки Тима Баррасса показывает, как сделать это лучше.Это, однако, не полностью объясняет поведение, которое вы видите.

0 голосов
/ 01 декабря 2010

Как насчет отправки клавиши возврата на клавишу перед отправкой нового нужного вам символа?

AllowKey = true;
SendKeys.Send("{BS}");
SendKeys.Send("\u0997"); // code for russian letters here....
break;
...