[C#][WindowsAPI][WinForm] 空視窗啟用輸入法輸入

  • 7257
  • 0

[C#][WindowsAPI][WinForm] 空視窗啟用輸入法輸入

    其實這個功能很久以前就想做了,只是一直找不到就去找別的替代方案。這次又有構想想用到這種設計,於是就決定死都不妥協一定要做到,別人做得到沒道理我寫不出來。一開始當然是先Google搜尋相關,但卻是跟以前一樣的結果。後來就決定往Windows API的方向去查,找到了ImmGetContext還有ImmAssociateContext這兩個API,用於提取輸入資料和讓輸入的資料與視窗進行關聯來啟動輸入法。依照慣例我也把它寫成了一個類別以供日後方便使用,以下的類別將協助處理Windows Message來使視窗與輸入法建立起關係。

未命名 - 1

 

[完整範例程式碼下載: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;
        }
    }

分享