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); }
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; }
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); }
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(); }
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); }