Browse Source

Merge pull request #11723 from Gillibald/windowsImeFixes

[Windows] IME Fixes
pull/11809/head
Max Katz 3 years ago
committed by GitHub
parent
commit
8933e8ff0c
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 10
      src/Avalonia.Base/Input/TextInput/InputMethodManager.cs
  2. 104
      src/Windows/Avalonia.Win32/Input/Imm32InputMethod.cs
  3. 56
      src/Windows/Avalonia.Win32/WindowImpl.AppWndProc.cs
  4. 4
      src/Windows/Avalonia.Win32/WindowImpl.cs

10
src/Avalonia.Base/Input/TextInput/InputMethodManager.cs

@ -22,11 +22,18 @@ namespace Avalonia.Input.TextInput
set
{
if(_client == value)
{
return;
}
if (_client != null)
{
_client.CursorRectangleChanged -= OnCursorRectangleChanged;
_client.TextViewVisualChanged -= OnTextViewVisualChanged;
_client = null;
_im?.Reset();
}
_client = value;
@ -35,8 +42,6 @@ namespace Avalonia.Input.TextInput
{
_client.CursorRectangleChanged += OnCursorRectangleChanged;
_client.TextViewVisualChanged += OnTextViewVisualChanged;
_im?.Reset();
if (_focusedElement is StyledElement target)
{
@ -50,6 +55,7 @@ namespace Avalonia.Input.TextInput
_transformTracker.SetVisual(_client?.TextViewVisual);
_im?.SetClient(_client);
UpdateCursorRect();
}
else

104
src/Windows/Avalonia.Win32/Input/Imm32InputMethod.cs

@ -1,6 +1,8 @@
using System;
using System.Diagnostics.CodeAnalysis;
using System.Text;
using Avalonia.Input;
using Avalonia.Input.Raw;
using Avalonia.Input.TextInput;
using Avalonia.Threading;
@ -22,6 +24,8 @@ namespace Avalonia.Win32.Input
private ushort _langId;
private const int CaretMargin = 1;
private bool _ignoreComposition;
public ITextInputMethodClient? Client { get; private set; }
[MemberNotNullWhen(true, nameof(Client))]
@ -121,19 +125,35 @@ namespace Avalonia.Win32.Input
{
var himc = ImmGetContext(Hwnd);
if (IsComposing)
if (himc != IntPtr.Zero)
{
_ignoreComposition = true;
if (_parent != null)
{
_parent._ignoreWmChar = true;
}
ImmNotifyIME(himc, NI_COMPOSITIONSTR, CPS_COMPLETE, 0);
ImmReleaseContext(Hwnd, himc);
IsComposing = false;
}
ImmReleaseContext(Hwnd, himc);
Composition = null;
}
});
}
public void SetClient(ITextInputMethodClient? client)
{
if(Client != null)
{
Composition = null;
Client.SetPreeditText(null);
}
Client = client;
Dispatcher.UIThread.Post(() =>
@ -297,6 +317,82 @@ namespace Avalonia.Win32.Input
return ImmGetCompositionString(himc, flag);
}
public void HandleCompositionStart()
{
Composition = null;
if (IsActive)
{
Client.SetPreeditText(null);
}
IsComposing = true;
}
public void HandleCompositionEnd()
{
//Cleanup composition state.
IsComposing = false;
Composition = null;
if (IsActive)
{
Client.SetPreeditText(null);
}
}
public void HandleComposition(IntPtr wParam, IntPtr lParam, uint timestamp)
{
if (_ignoreComposition)
{
_ignoreComposition = false;
return;
}
var flags = (GCS)ToInt32(lParam);
if ((flags & GCS.GCS_RESULTSTR) != 0)
{
var resultString = GetCompositionString(GCS.GCS_RESULTSTR);
if (_parent != null && !string.IsNullOrEmpty(resultString))
{
Composition = null;
if (IsActive)
{
Client.SetPreeditText(null);
}
var e = new RawTextInputEventArgs(WindowsKeyboardDevice.Instance, timestamp, _parent.Owner, resultString);
if (_parent.Input != null)
{
_parent.Input(e);
_parent._ignoreWmChar = true;
}
}
}
if ((flags & GCS.GCS_COMPSTR) != 0)
{
var compositionString = GetCompositionString(GCS.GCS_COMPSTR);
CompositionChanged(compositionString);
}
}
private static int ToInt32(IntPtr ptr)
{
if (IntPtr.Size == 4)
return ptr.ToInt32();
return (int)(ptr.ToInt64() & 0xffffffff);
}
~Imm32InputMethod()
{
_caretManager.TryDestroy();

56
src/Windows/Avalonia.Win32/WindowImpl.AppWndProc.cs

@ -87,7 +87,7 @@ namespace Avalonia.Win32
{
// The first and foremost thing to do - notify the TopLevel
Closed?.Invoke();
if (UiaCoreTypesApi.IsNetComInteropAvailable)
{
UiaCoreProviderApi.UiaReturnRawElementProvider(_hwnd, IntPtr.Zero, IntPtr.Zero, null);
@ -98,7 +98,7 @@ namespace Avalonia.Win32
{
Imm32InputMethod.Current.ClearLanguageAndWindow();
}
// Cleanup render targets
(_gl as IDisposable)?.Dispose();
@ -724,26 +724,7 @@ namespace Avalonia.Win32
}
case WindowsMessage.WM_IME_COMPOSITION:
{
var flags = (GCS)ToInt32(lParam);
if ((flags & GCS.GCS_COMPSTR) != 0)
{
var currentComposition = Imm32InputMethod.Current.GetCompositionString(GCS.GCS_COMPSTR);
Imm32InputMethod.Current.CompositionChanged(currentComposition);
}
if ((flags & GCS.GCS_RESULTSTR) != 0)
{
var result = Imm32InputMethod.Current.GetCompositionString(GCS.GCS_RESULTSTR);
if (!string.IsNullOrEmpty(result))
{
Imm32InputMethod.Current.Composition = result;
_ignoreWmChar = true;
}
}
Imm32InputMethod.Current.HandleComposition(wParam, lParam, timestamp);
break;
}
@ -757,35 +738,16 @@ namespace Avalonia.Win32
case WindowsMessage.WM_IME_NOTIFY:
break;
case WindowsMessage.WM_IME_STARTCOMPOSITION:
Imm32InputMethod.Current.Composition = null;
if (Imm32InputMethod.Current.IsActive)
{
Imm32InputMethod.Current.Client.SetPreeditText(null);
}
Imm32InputMethod.Current.HandleCompositionStart();
Imm32InputMethod.Current.IsComposing = true;
return IntPtr.Zero;
return IntPtr.Zero;
}
case WindowsMessage.WM_IME_ENDCOMPOSITION:
{
var currentComposition = Imm32InputMethod.Current.Composition;
//In case composition has not been comitted yet we need to do that here.
if (!string.IsNullOrEmpty(currentComposition))
{
e = new RawTextInputEventArgs(WindowsKeyboardDevice.Instance, timestamp, Owner, currentComposition);
}
//Cleanup composition state.
Imm32InputMethod.Current.IsComposing = false;
Imm32InputMethod.Current.Composition = null;
Imm32InputMethod.Current.HandleCompositionEnd();
if (Imm32InputMethod.Current.IsActive)
{
Imm32InputMethod.Current.Client.SetPreeditText(null);
}
break;
return IntPtr.Zero;
}
case WindowsMessage.WM_GETOBJECT:
if ((long)lParam == uiaRootObjectId && UiaCoreTypesApi.IsNetComInteropAvailable && _owner is Control control)
@ -830,7 +792,7 @@ namespace Avalonia.Win32
return IntPtr.Zero;
}
}
return DefWindowProc(hWnd, msg, wParam, lParam);
}

4
src/Windows/Avalonia.Win32/WindowImpl.cs

@ -97,7 +97,7 @@ namespace Avalonia.Win32
private bool _shown;
private bool _hiddenWindowIsParent;
private uint _langid;
private bool _ignoreWmChar;
internal bool _ignoreWmChar;
private WindowTransparencyLevel _transparencyLevel;
private const int MaxPointerHistorySize = 512;
@ -186,7 +186,7 @@ namespace Avalonia.Win32
s_instances.Add(this);
}
private IInputRoot Owner
internal IInputRoot Owner
=> _owner ?? throw new InvalidOperationException($"{nameof(SetInputRoot)} must have been called");
public Action? Activated { get; set; }

Loading…
Cancel
Save