Example #1
0
 private void ClearContext()
 {
     if (_hwndSource == null)
     {
         return;
     }
     IMENative.ImmAssociateContext(_hwndSource.Handle, _previousContext);
     IMENative.ImmReleaseContext(_defaultImeWnd, _currentContext);
     _currentContext = IntPtr.Zero;
     _defaultImeWnd  = IntPtr.Zero;
     _hwndSource.RemoveHook(WndProc);
     _hwndSource = null;
 }
Example #2
0
        private void CreateContext()
        {
            ClearContext();
            _hwndSource = (HwndSource)(PresentationSource.FromVisual(Editor) ??
                                       throw new ArgumentNullException(nameof(Editor)));

            _defaultImeWnd = IMENative.ImmGetDefaultIMEWnd(IntPtr.Zero);
            Log($"_defaultImeWnd={_defaultImeWnd}");
            if (_defaultImeWnd == IntPtr.Zero)
            {
                // 如果拿到了空的默认 IME 窗口了,那么此时也许是作为嵌套窗口放入到另一个进程的窗口
                // 拿不到就需要刷新一下。否则微软拼音输入法将在屏幕的左上角上
                RefreshInputMethodEditors();

                // 尝试通过 _hwndSource 也就是文本所在的窗口去获取
                _defaultImeWnd = IMENative.ImmGetDefaultIMEWnd(_hwndSource.Handle);
                Log($"_defaultImeWnd2={_defaultImeWnd}");

                if (_defaultImeWnd == IntPtr.Zero)
                {
                    // 如果依然获取不到,那么使用当前激活的窗口,在准备输入的时候
                    // 当前的窗口大部分都是对的
                    // 进入这里,是尽可能恢复输入法,拿到的 GetForegroundWindow 虽然预计是不对的
                    // 也好过没有输入法
                    _defaultImeWnd = IMENative.ImmGetDefaultIMEWnd(Win32.User32.GetForegroundWindow());
                    Log($"_defaultImeWnd3={_defaultImeWnd}");
                }
            }

            // 使用 DefaultIMEWnd 可以比较好解决微软拼音的输入法到屏幕左上角的问题
            _currentContext = IMENative.ImmGetContext(_defaultImeWnd);
            Log($"_currentContext={_currentContext}");
            if (_currentContext == IntPtr.Zero)
            {
                _currentContext = IMENative.ImmGetContext(_hwndSource.Handle);
                Log($"_currentContext2={_currentContext}");
            }

            // 对 Win32 使用第二套输入法框架的输入法,可以采用 ImmAssociateContext 关联
            // 但是对实现 TSF 第三套输入法框架的输入法,在应用程序对接第三套输入法框架
            // 就需要调用 ITfThreadMgr 的 SetFocus 方法。刚好 WPF 对接了
            _previousContext = IMENative.ImmAssociateContext(_hwndSource.Handle, _currentContext);
            _hwndSource.AddHook(WndProc);

            // 尽管文档说传递null是无效的,但这似乎有助于在与WPF共享的默认输入上下文中激活IME输入法
            // 这里需要了解的是,在 WPF 的逻辑,是需要传入 DefaultTextStore.Current.DocumentManager 才符合预期
            var threadMgr = IMENative.GetTextFrameworkThreadManager();

            threadMgr?.SetFocus(IntPtr.Zero);
        }