2011-05-27 100 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