Ejemplo n.º 1
0
        private void SetCompositionFont()
        {
            var lf = new IMENative.LOGFONT();

            lf.lfFaceName = Editor.GetFontFamilyName();
            lf.lfHeight   = Editor.GetFontSize();

            var hIMC = _currentContext;

            var GCS_COMPSTR = 8;

            var length = IMENative.ImmGetCompositionString(hIMC, GCS_COMPSTR, null, 0);

            if (length > 0)
            {
                var target = new byte[length];
                var count  = IMENative.ImmGetCompositionString(hIMC, GCS_COMPSTR, target, length);
                if (count > 0)
                {
                    var inputString = Encoding.Default.GetString(target);
                    if (string.IsNullOrWhiteSpace(inputString))
                    {
                        lf.lfWidth = 1;
                    }
                }
            }

            Log($"ImmSetCompositionFont");
            IMENative.ImmSetCompositionFont(hIMC, ref lf);
        }
Ejemplo n.º 2
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;
 }
Ejemplo n.º 3
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);
        }
Ejemplo n.º 4
0
        private void Editor_LostKeyboardFocus(object sender, KeyboardFocusChangedEventArgs e)
        {
            Log($"LostKeyboardFocus");
            if (_isUpdatingCompositionWindow)
            {
                return;
            }
            if (Equals(e.OldFocus, Editor) && _currentContext != IntPtr.Zero)
            {
                IMENative.ImmNotifyIME(_currentContext, IMENative.NI_COMPOSITIONSTR, IMENative.CPS_CANCEL);
            }

            ClearContext();
        }
Ejemplo n.º 5
0
        private void SetCompositionWindow()
        {
            var        hIMC   = _currentContext;
            HwndSource source = _hwndSource ?? throw new ArgumentNullException(nameof(_hwndSource));

            var textEditorLeftTop = Editor.GetTextEditorLeftTop();
            var caretLeftTop      = Editor.GetCaretLeftTop();

            var transformToAncestor = Editor.TransformToAncestor(source.RootVisual);

            var textEditorLeftTopForRootVisual = transformToAncestor.Transform(textEditorLeftTop);
            var caretLeftTopForRootVisual      = transformToAncestor.Transform(caretLeftTop);

            //解决surface上输入法光标位置不正确
            //现象是surface上光标的位置需要乘以2才能正确,普通电脑上没有这个问题
            //且此问题与DPI无关,目前用CaretWidth可以有效判断
            caretLeftTopForRootVisual = new Point(caretLeftTopForRootVisual.X / SystemParameters.CaretWidth,
                                                  caretLeftTopForRootVisual.Y / SystemParameters.CaretWidth);

            //const int CFS_DEFAULT = 0x0000;
            //const int CFS_RECT = 0x0001;
            const int CFS_POINT = 0x0002;
            //const int CFS_FORCE_POSITION = 0x0020;
            //const int CFS_EXCLUDE = 0x0080;
            //const int CFS_CANDIDATEPOS = 0x0040;

            var form = new IMENative.CompositionForm();

            form.dwStyle        = CFS_POINT;
            form.ptCurrentPos.x = (int)Math.Max(caretLeftTopForRootVisual.X, textEditorLeftTopForRootVisual.X);
            form.ptCurrentPos.y = (int)Math.Max(caretLeftTopForRootVisual.Y, textEditorLeftTopForRootVisual.Y);
            //if (_isSoftwarePinYinOverWin7)
            //{
            //    form.ptCurrentPos.y += (int) characterBounds.Height;
            //}

            Log($"ImmSetCompositionWindow x={form.ptCurrentPos.x} y={form.ptCurrentPos.y}");
            IMENative.ImmSetCompositionWindow(hIMC, ref form);
        }