2011-05-27 72 views
2

我正在编写一个需要获取系统输入语言的应用程序,而应用程序窗口是没有关注输入语言钩子

在搜索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); 
     } 
    } 
} 
+0

这实际上是你使用的代码吗?它看起来像你在钩它,然后立即解开它。 – 2011-05-27 16:46:33

+1

你失败了什么?请描述您期望看到的行为,以及您在上述代码中看到的行为。 – 2011-05-27 16:46:42

+0

是这个班的作品。这段代码返回被按下的键。但是我试图在系统语言发生变化时使它适应返回消息 – Sergey1991 2011-05-27 16:50:54

回答

0

从我的一个项目此代码的工作对我来说,它看起来像我们可能会使用相同的例子:

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()调用应该解决这个问题。

+0

你可以通过使用这个钩子来获得系统输入语言吗? – Sergey1991 2011-05-27 17:05:05

+0

我认为我对你所问的内容感到困惑,因为你发布的代码是钩住按键。只要你将'WM_INPUTLANGUAGE'定义为'0x0051' – 2011-05-27 17:09:24

+0

我试过了,但是它仍然不起作用,所以你可以将'WM_KEYUP'的检查改为检查'WM_INPUTLANGCHANGE'。 – Sergey1991 2011-05-27 18:16:17