Browse Source

Respect IME preedit cursor position on Win32 (#21632)

pull/21644/head
Shun-ichi Goto 3 months ago
committed by GitHub
parent
commit
bdc8314235
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 80
      src/Windows/Avalonia.Win32/Input/Imm32InputMethod.cs

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

@ -25,6 +25,7 @@ namespace Avalonia.Win32.Input
private const int CaretMargin = 1; private const int CaretMargin = 1;
private bool _ignoreComposition; private bool _ignoreComposition;
private int? _compositionCursorPosition;
public TextInputMethodClient? Client { get; private set; } public TextInputMethodClient? Client { get; private set; }
@ -110,6 +111,7 @@ namespace Avalonia.Win32.Input
_langId = 0; _langId = 0;
IsComposing = false; IsComposing = false;
_compositionCursorPosition = null;
} }
//Dependant on CurrentThread. When Avalonia will support Multiple Dispatchers - //Dependant on CurrentThread. When Avalonia will support Multiple Dispatchers -
@ -118,6 +120,8 @@ namespace Avalonia.Win32.Input
public void Reset() public void Reset()
{ {
_compositionCursorPosition = null;
Dispatcher.UIThread.Post(() => Dispatcher.UIThread.Post(() =>
{ {
var himc = ImmGetContext(Hwnd); var himc = ImmGetContext(Hwnd);
@ -141,6 +145,7 @@ namespace Avalonia.Win32.Input
IsComposing = false; IsComposing = false;
Composition = null; Composition = null;
_compositionCursorPosition = null;
} }
}); });
} }
@ -150,8 +155,9 @@ namespace Avalonia.Win32.Input
if(Client != null) if(Client != null)
{ {
Composition = null; Composition = null;
_compositionCursorPosition = null;
Client.SetPreeditText(null); Client.SetPreeditText(null, null);
} }
Client = client; Client = client;
@ -266,16 +272,17 @@ namespace Avalonia.Win32.Input
// we're skipping this. not usable on windows // we're skipping this. not usable on windows
} }
public void CompositionChanged(string? composition) public void CompositionChanged(string? composition, int? cursorPosition)
{ {
Composition = composition; Composition = composition;
_compositionCursorPosition = cursorPosition;
if (!IsActive || !Client.SupportsPreedit) if (!IsActive || !Client.SupportsPreedit)
{ {
return; return;
} }
Client.SetPreeditText(composition); Client.SetPreeditText(composition, cursorPosition);
} }
public string? GetCompositionString(GCS flag) public string? GetCompositionString(GCS flag)
@ -290,13 +297,40 @@ namespace Avalonia.Win32.Input
return ImmGetCompositionString(himc, flag); return ImmGetCompositionString(himc, flag);
} }
private int? GetCompositionCursorPosition()
{
if (!IsComposing)
{
return null;
}
var himc = ImmGetContext(Hwnd);
if (himc == IntPtr.Zero)
{
return null;
}
try
{
var cursorPosition = ImmGetCompositionString(himc, GCS.GCS_CURSORPOS, IntPtr.Zero, 0);
return cursorPosition >= 0 ? cursorPosition : null;
}
finally
{
ImmReleaseContext(Hwnd, himc);
}
}
public void HandleCompositionStart() public void HandleCompositionStart()
{ {
Composition = null; Composition = null;
_compositionCursorPosition = null;
if (IsActive) if (IsActive)
{ {
Client.SetPreeditText(null); Client.SetPreeditText(null, null);
if (Client.SupportsSurroundingText && Client.Selection.Start != Client.Selection.End) if (Client.SupportsSurroundingText && Client.Selection.Start != Client.Selection.End)
{ {
@ -325,10 +359,11 @@ namespace Avalonia.Win32.Input
} }
Composition = null; Composition = null;
_compositionCursorPosition = null;
if (IsActive) if (IsActive)
{ {
Client.SetPreeditText(null); Client.SetPreeditText(null, null);
} }
} }
@ -342,25 +377,27 @@ namespace Avalonia.Win32.Input
} }
var flags = (GCS)ToInt32(lParam); var flags = (GCS)ToInt32(lParam);
var resultChanged = (flags & GCS.GCS_RESULTSTR) != 0;
if (flags == 0) if (flags == 0)
{ {
CompositionChanged(""); CompositionChanged("", null);
} }
if ((flags & GCS.GCS_RESULTSTR) != 0) if (resultChanged)
{ {
var resultString = GetCompositionString(GCS.GCS_RESULTSTR); var resultString = GetCompositionString(GCS.GCS_RESULTSTR);
if (_parent != null && !string.IsNullOrEmpty(resultString)) Composition = null;
{ _compositionCursorPosition = null;
Composition = null;
if (IsActive) if (IsActive)
{ {
Client.SetPreeditText(null); Client.SetPreeditText(null, null);
} }
if (_parent != null && !string.IsNullOrEmpty(resultString))
{
var e = new RawTextInputEventArgs(WindowsKeyboardDevice.Instance, timestamp, _parent.Owner, resultString); var e = new RawTextInputEventArgs(WindowsKeyboardDevice.Instance, timestamp, _parent.Owner, resultString);
if (_parent.Input != null) if (_parent.Input != null)
@ -372,11 +409,20 @@ namespace Avalonia.Win32.Input
} }
} }
if ((flags & GCS.GCS_COMPSTR) != 0) var compositionChanged = (flags & GCS.GCS_COMPSTR) != 0;
var cursorPositionChanged = (flags & GCS.GCS_CURSORPOS) != 0;
if (compositionChanged || (cursorPositionChanged && !resultChanged))
{ {
var compositionString = GetCompositionString(GCS.GCS_COMPSTR); var compositionString = compositionChanged
? GetCompositionString(GCS.GCS_COMPSTR)
: Composition;
var cursorPosition = cursorPositionChanged
? GetCompositionCursorPosition()
: _compositionCursorPosition;
CompositionChanged(compositionString); CompositionChanged(compositionString, cursorPosition);
} }
} }

Loading…
Cancel
Save