Язык ввода - PullRequest
       24

Язык ввода

2 голосов
/ 27 мая 2011

Я пишу приложение, которое должно получить язык ввода системы, в то время как окно приложения не сфокусировано .

После поиска в Google я обнаружил, что способ сделать это - перехватить сообщение WM_INPUTLANGCHANGE.

Но я не смог найти пример синтаксиса хука.

Я нашел следующий код и попытался адаптировать его под свои нужды, но мне не удалось:

Изменить: Я заменил WM_KEYUP на WM_INPUTLANGCHANGE, но он не работает.

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Windows.Forms;

namespace KeyHook
{
    class LenHook
    {

        private const int WM_INPUTLANGCHANGE = 0x0051;
        private static LowLevelKeyboardProc _proc = HookCallback;
        private static IntPtr _hookID = IntPtr.Zero;


        [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)]
        public static extern bool UnhookWindowsHookEx(IntPtr hhk);

        [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        public static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode, IntPtr wParam, IntPtr lParam);

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


        private delegate IntPtr LowLevelKeyboardProc(int nCode, IntPtr wParam, IntPtr lParam);


        public LenHook()
        {


            _hookID = SetHook(_proc);
            UnhookWindowsHookEx(_hookID);
            System.Windows.Forms.Application.Run();


        }
        //Install hook
        private static IntPtr SetHook(LowLevelKeyboardProc proc)
        {
            using (var curProcess = Process.GetCurrentProcess())
            {
                using (var curModule = curProcess.MainModule)
                {
                    return SetWindowsHookEx(WM_INPUTLANGCHANGE, proc, GetModuleHandle(curModule.ModuleName), 0);
                }
            }
        }

        //Do it when key press
        private static IntPtr HookCallback(int nCode, IntPtr wParam, IntPtr lParam)
        {

            MessageBox.Show(wParam.ToString());
            return CallNextHookEx(_hookID, nCode, wParam, lParam);
        }
     }
}

1 Ответ

0 голосов
/ 27 мая 2011

Этот код из моего проекта работает для меня, похоже, мы могли использовать тот же пример:

private static IntPtr _hookId = IntPtr.Zero;
private readonly External.LowLevelKeyboardProc _proc;

public FrmMain()
{
    _proc = HookCallback;
    _hookId = SetHook(_proc);
    InitializeComponent();
}

private static IntPtr SetHook(External.LowLevelKeyboardProc proc)
{
    using(var curProcess = Process.GetCurrentProcess())
    {
        using(var curModule = curProcess.MainModule)
        {
            return External.SetWindowsHookEx(External.WH_KEYBOARD_LL, proc, External.GetModuleHandle(curModule.ModuleName), 0);
        }
    }
}

private IntPtr HookCallback(int nCode, IntPtr wParam, IntPtr lParam)
{
    // You can change this to WM_KEYDOWN
    if (nCode >= 0 && wParam == (IntPtr)External.WM_KEYUP)
    {
         // Code you want to run when a button is pressed.
    }
    return External.CallNextHookEx(_hookId, nCode, wParam, lParam);
}

Кроме того, это мой External класс.

public static class External
{
    public delegate IntPtr LowLevelKeyboardProc(int nCode, IntPtr wParam, IntPtr lParam);

    public const int WH_KEYBOARD_LL = 13;
    public const int WM_KEYDOWN = 0x0100;
    public const int WM_KEYUP = 0x0101;
    public const uint WM_GETTEXT = 0x0D;
    public const uint WM_GETTEXTLENGTH = 0x0E;
    public const uint EM_GETSEL = 0xB0;

    [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    public static extern IntPtr GetForegroundWindow();

    [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    public static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId);

    [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    public static extern uint GetCurrentThreadId();

    [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    public static extern bool AttachThreadInput(uint idAttach, uint idAttachTo, bool fAttach);

    [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    public static extern IntPtr GetFocus();

    [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    public static extern int SendMessage(IntPtr hWnd, uint Msg, int wParam, StringBuilder lParam);

    [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    public static extern int SendMessage(IntPtr hWnd, uint Msg, out int wParam, out int lParam);

    [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    public static extern IntPtr SetWindowsHookEx(int idHook, LowLevelKeyboardProc lpfn, IntPtr hMod, uint dwThreadId);

    [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    [return: MarshalAs(UnmanagedType.Bool)]
    public static extern bool UnhookWindowsHookEx(IntPtr hhk);

    [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    public static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode, IntPtr wParam, IntPtr lParam);

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

    [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    public static extern bool GetCaretPos(out Point lPoint);

    [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    public static extern int GetClassName(IntPtr hWnd, StringBuilder lpClassName, int nMaxCount);
}

Я читал, что у вас будут проблемы, если вы попытаетесь выполнить эти перехваты из консольного приложения, хотя ваш вызов Application.Run() должен это исправить.

...