[C#][WindowsAPI][WinForm] 空視窗啟用輸入法輸入
其實這個功能很久以前就想做了,只是一直找不到就去找別的替代方案。這次又有構想想用到這種設計,於是就決定死都不妥協一定要做到,別人做得到沒道理我寫不出來。一開始當然是先Google搜尋相關,但卻是跟以前一樣的結果。後來就決定往Windows API的方向去查,找到了ImmGetContext還有ImmAssociateContext這兩個API,用於提取輸入資料和讓輸入的資料與視窗進行關聯來啟動輸入法。依照慣例我也把它寫成了一個類別以供日後方便使用,以下的類別將協助處理Windows Message來使視窗與輸入法建立起關係。
[完整範例程式碼下載:ImeWinMessageHandlerDemo.zip]
原生方法的宣告請參考[常用Windows原生方法整理(Windows API)]。
原生方法用到的常數請參考[Windows 原生指令常數 (Windows API Constansts)]。
※全文歡迎轉載但請註明出處,謝謝。※
/// <summary>
/// 提供Unmanaged方法處理Windows Message並接收輸入法的輸入訊號。
/// </summary>
public class ImeWinMessageHandler
{
private Form _tarForm = null;
private IntPtr _tarHandle = IntPtr.Zero;
private IntPtr _hIMC = IntPtr.Zero;
/// <summary>
/// 取得一個值。這個值會指示哪一個輔助按鍵 (Modifier Key) (SHIFT、CTRL 和 ALT) 處於按下的狀態。
/// </summary>
public static Keys ModifierKeys
{
get
{
Keys m_Result = Keys.None;
if (NativeMethods.GetKeyState(0x10) < 0)
m_Result |= Keys.Shift;
if (NativeMethods.GetKeyState(0x11) < 0)
m_Result |= Keys.Control;
if (NativeMethods.GetKeyState(0x12) < 0)
m_Result |= Keys.Alt;
return m_Result;
}
}
/// <summary>
/// 初始化 OptimistSutdioDll.Win32APIs.ImeWinMessageHandler 的執行個體。
/// </summary>
/// <param name="form">用於處理Windows Message的 System.Windows.Forms.Form 執行個體。</param>
public ImeWinMessageHandler(Form form)
{
_tarForm = form;
}
private Boolean _Enabled = false;
/// <summary>
/// 取得或設定Handler是否啟用。
/// </summary>
public Boolean Enabled
{
get { return _Enabled; }
set
{
if (Enabled != value)
{
_Enabled = value;
if (value)
{
_tarHandle = _tarForm.Handle;
_hIMC = NativeMethods.ImmGetContext(_tarHandle);
}
else
{
NativeMethods.ImmReleaseContext(_tarHandle, _hIMC);
_tarHandle = IntPtr.Zero;
_hIMC = IntPtr.Zero;
}
}
}
}
/// <summary>
/// 將Windows Message資料送入處理器進行處理。
/// </summary>
/// <param name="m">要處理的 System.Windows.Forms.Message。</param>
public void InputMessage(ref Message m)
{
bool m_handled = false;
WndProc(m.HWnd, m.Msg, m.WParam, m.LParam, ref m_handled);
}
private IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
{
if (Enabled)
{
if (msg == NativeContansts.WM_IME_SETCONTEXT && wParam.ToInt32() == 1)
NativeMethods.ImmAssociateContext(_tarHandle, _hIMC);
else if (msg == NativeContansts.WM_CHAR)
{
char m_Reult = (char)(new KeyEventArgs(((Keys)((int)(wParam))) | ImeWinMessageHandler.ModifierKeys).KeyData);
this.OnCharacterInputted(m_Reult);
}
}
return IntPtr.Zero;
}
private void OnCharacterInputted(char c)
{
if (this.CharacterInputted != null)
this.CharacterInputted(this, new CharacterInputtedEventArgs(c));
}
/// <summary>
/// 當Handler收到輸入法輸入字元進入應用程式時引發此事件。
/// </summary>
public event EventHandler<CharacterInputtedEventArgs> CharacterInputted;
}
/// <summary>
/// 提供 CharacterInputted的事件資料。
/// </summary>
public class CharacterInputtedEventArgs : EventArgs
{
/// <summary>
/// 取得輸入法輸入的字元。
/// </summary>
public Char Character { get; private set; }
internal CharacterInputtedEventArgs(char c)
{
this.Character = c;
}
}