Browse Source

Imm32 preedit

feature/ImePreeditText
Benedikt Stebner 4 years ago
parent
commit
f009c316e2
  1. 144
      src/Avalonia.Controls/Presenters/TextPresenter.cs
  2. 2
      src/Avalonia.Controls/TextBox.cs
  3. 8
      src/Windows/Avalonia.Win32/Input/Imm32CaretManager.cs
  4. 205
      src/Windows/Avalonia.Win32/Input/Imm32InputMethod.cs
  5. 71
      src/Windows/Avalonia.Win32/Interop/UnmanagedMethods.cs
  6. 44
      src/Windows/Avalonia.Win32/WindowImpl.AppWndProc.cs

144
src/Avalonia.Controls/Presenters/TextPresenter.cs

@ -34,7 +34,7 @@ namespace Avalonia.Controls.Presenters
public static readonly StyledProperty<IBrush?> CaretBrushProperty =
AvaloniaProperty.Register<TextPresenter, IBrush?>(nameof(CaretBrush));
public static readonly DirectProperty<TextPresenter, int> SelectionStartProperty =
TextBox.SelectionStartProperty.AddOwner<TextPresenter>(
o => o.SelectionStart,
@ -44,7 +44,7 @@ namespace Avalonia.Controls.Presenters
TextBox.SelectionEndProperty.AddOwner<TextPresenter>(
o => o.SelectionEnd,
(o, v) => o.SelectionEnd = v);
/// <summary>
/// Defines the <see cref="Text"/> property.
/// </summary>
@ -80,7 +80,7 @@ namespace Avalonia.Controls.Presenters
/// </summary>
public static readonly StyledProperty<double> LineHeightProperty =
TextBlock.LineHeightProperty.AddOwner<TextPresenter>();
/// <summary>
/// Defines the <see cref="Background"/> property.
/// </summary>
@ -114,7 +114,7 @@ namespace Avalonia.Controls.Presenters
}
public event EventHandler? CaretBoundsChanged;
/// <summary>
/// Gets or sets a brush used to paint the control's background.
/// </summary>
@ -202,7 +202,7 @@ namespace Avalonia.Controls.Presenters
get => GetValue(TextWrappingProperty);
set => SetValue(TextWrappingProperty, value);
}
/// <summary>
/// Gets or sets the line height. By default, this is set to <see cref="double.NaN"/>, which determines the appropriate height automatically.
/// </summary>
@ -232,11 +232,11 @@ namespace Avalonia.Controls.Presenters
{
return _textLayout;
}
_textLayout = CreateTextLayout();
UpdateCaret(_lastCharacterHit);
return _textLayout;
}
}
@ -285,7 +285,7 @@ namespace Avalonia.Controls.Presenters
get => GetValue(CaretBrushProperty);
set => SetValue(CaretBrushProperty, value);
}
public int SelectionStart
{
get
@ -313,7 +313,7 @@ namespace Avalonia.Controls.Presenters
SetAndRaise(SelectionEndProperty, ref _selectionEnd, value);
}
}
protected override bool BypassFlowDirectionPolicies => true;
/// <summary>
@ -330,9 +330,9 @@ namespace Avalonia.Controls.Presenters
var foreground = Foreground;
var maxWidth = MathUtilities.IsZero(constraint.Width) ? double.PositiveInfinity : constraint.Width;
var maxHeight = MathUtilities.IsZero(constraint.Height) ? double.PositiveInfinity : constraint.Height;
var textLayout = new TextLayout(text, typeface, FontSize, foreground, TextAlignment,
TextWrapping, maxWidth: maxWidth, maxHeight: maxHeight, textStyleOverrides: textStyleOverrides,
TextWrapping, maxWidth: maxWidth, maxHeight: maxHeight, textStyleOverrides: textStyleOverrides,
flowDirection: FlowDirection, lineHeight: LineHeight);
return textLayout;
@ -398,7 +398,7 @@ namespace Avalonia.Controls.Presenters
{
return;
}
var caretBrush = CaretBrush?.ToImmutable();
if (caretBrush is null)
@ -423,13 +423,13 @@ namespace Avalonia.Controls.Presenters
context.DrawLine(new ImmutablePen(caretBrush), p1, p2);
}
private (Point, Point) GetCaretPoints()
{
var x = Math.Floor(_caretBounds.X) + 0.5;
var y = Math.Floor(_caretBounds.Y) + 0.5;
var b = Math.Ceiling(_caretBounds.Bottom) - 0.5;
var caretIndex = _lastCharacterHit.FirstCharacterIndex + _lastCharacterHit.TrailingLength;
var lineIndex = TextLayout.GetLineIndexFromCharacterIndex(caretIndex, _lastCharacterHit.TrailingLength > 0);
var textLine = TextLayout.TextLines[lineIndex];
@ -438,7 +438,7 @@ namespace Avalonia.Controls.Presenters
{
x -= 1;
}
return (new Point(x, y), new Point(x, b));
}
@ -524,17 +524,7 @@ namespace Avalonia.Controls.Presenters
var start = Math.Min(selectionStart, selectionEnd);
var length = Math.Max(selectionStart, selectionEnd) - start;
List<ValueSpan<TextRunProperties>>? textStyleOverrides = null;
if (length > 0 && SelectionForegroundBrush != null)
{
textStyleOverrides = new List<ValueSpan<TextRunProperties>>
{
new ValueSpan<TextRunProperties>(start, length,
new GenericTextRunProperties(typeface, FontSize,
foregroundBrush: SelectionForegroundBrush))
};
}
IReadOnlyList<ValueSpan<TextRunProperties>>? textStyleOverrides = null;
var foreground = Foreground;
@ -542,20 +532,26 @@ namespace Avalonia.Controls.Presenters
{
var preeditHighlight = new ValueSpan<TextRunProperties>(_caretIndex, _preeditText.Length,
new GenericTextRunProperties(typeface, FontSize,
foregroundBrush: foreground,
textDecorations: TextDecorations.Underline));
foregroundBrush: Foreground,
textDecorations: TextDecorations.Underline,
backgroundBrush: SelectionBrush));
if (textStyleOverrides == null)
textStyleOverrides = new[]
{
preeditHighlight
};
}
else
{
if (length > 0 && SelectionForegroundBrush != null)
{
textStyleOverrides = new List<ValueSpan<TextRunProperties>>
textStyleOverrides = new[]
{
preeditHighlight
new ValueSpan<TextRunProperties>(start, length,
new GenericTextRunProperties(typeface, FontSize,
foregroundBrush: SelectionForegroundBrush))
};
}
else
{
textStyleOverrides.Add(preeditHighlight);
}
}
if (PasswordChar != default(char) && !RevealPassword)
@ -574,7 +570,7 @@ namespace Avalonia.Controls.Presenters
protected virtual void InvalidateTextLayout()
{
_textLayout = null;
InvalidateMeasure();
}
@ -623,7 +619,7 @@ namespace Avalonia.Controls.Presenters
private void CaretTimerTick(object? sender, EventArgs e)
{
_caretBlink = !_caretBlink;
InvalidateVisual();
}
@ -633,7 +629,7 @@ namespace Avalonia.Controls.Presenters
var textLine = TextLayout.TextLines[lineIndex];
var characterHit = textLine.GetPreviousCaretCharacterHit(new CharacterHit(textPosition));
var nextCaretCharacterHit = textLine.GetNextCaretCharacterHit(characterHit);
if (nextCaretCharacterHit.FirstCharacterIndex <= textPosition)
@ -653,8 +649,8 @@ namespace Avalonia.Controls.Presenters
_navigationPosition = _caretBounds.Position;
CaretChanged();
}
}
public void MoveCaretToPoint(Point point)
{
var hit = TextLayout.HitTestPoint(point);
@ -685,7 +681,7 @@ namespace Avalonia.Controls.Presenters
}
var textLine = TextLayout.TextLines[lineIndex];
currentY += textLine.Height;
}
else
@ -701,9 +697,9 @@ namespace Avalonia.Controls.Presenters
}
var navigationPosition = _navigationPosition;
MoveCaretToPoint(new Point(currentX, currentY));
_navigationPosition = navigationPosition.WithY(_caretBounds.Y);
CaretChanged();
@ -714,11 +710,11 @@ namespace Avalonia.Controls.Presenters
if (Text is null)
{
return default;
}
}
var characterHit = _lastCharacterHit;
var caretIndex = characterHit.FirstCharacterIndex + characterHit.TrailingLength;
var lineIndex = TextLayout.GetLineIndexFromCharacterIndex(caretIndex, false);
if (lineIndex < 0)
@ -740,11 +736,11 @@ namespace Avalonia.Controls.Presenters
{
characterHit = new CharacterHit(caretIndex);
}
if (caretIndex >= Text.Length)
{
characterHit = new CharacterHit(Text.Length);
break;
}
@ -756,10 +752,10 @@ namespace Avalonia.Controls.Presenters
if (caretIndex <= CaretIndex)
{
lineIndex++;
continue;
}
break;
}
}
@ -786,7 +782,7 @@ namespace Avalonia.Controls.Presenters
return characterHit;
}
public void MoveCaretHorizontal(LogicalDirection direction = LogicalDirection.Forward)
{
if (FlowDirection == FlowDirection.RightToLeft)
@ -808,9 +804,9 @@ namespace Avalonia.Controls.Presenters
private void UpdateCaret(CharacterHit characterHit)
{
_lastCharacterHit = characterHit;
var caretIndex = characterHit.FirstCharacterIndex + characterHit.TrailingLength;
var lineIndex = TextLayout.GetLineIndexFromCharacterIndex(caretIndex, characterHit.TrailingLength > 0);
var textLine = TextLayout.TextLines[lineIndex];
var distanceX = textLine.GetDistanceFromCharacterHit(characterHit);
@ -825,7 +821,7 @@ namespace Avalonia.Controls.Presenters
}
var caretBounds = new Rect(distanceX, distanceY, 0, textLine.Height);
if (caretBounds != _caretBounds)
{
_caretBounds = caretBounds;
@ -846,40 +842,40 @@ namespace Avalonia.Controls.Presenters
base.OnDetachedFromVisualTree(e);
_caretTimer.Stop();
_caretTimer.Tick -= CaretTimerTick;
}
protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change)
{
base.OnPropertyChanged(change);
switch (change.Property.Name)
{
case nameof (Foreground):
case nameof (FontSize):
case nameof (FontStyle):
case nameof (FontWeight):
case nameof (FontFamily):
case nameof (FontStretch):
case nameof(Foreground):
case nameof(FontSize):
case nameof(FontStyle):
case nameof(FontWeight):
case nameof(FontFamily):
case nameof(FontStretch):
case nameof (Text):
case nameof (PreeditText):
case nameof (TextAlignment):
case nameof (TextWrapping):
case nameof(Text):
case nameof(PreeditText):
case nameof(TextAlignment):
case nameof(TextWrapping):
case nameof (SelectionStart):
case nameof (SelectionEnd):
case nameof (SelectionForegroundBrush):
case nameof(SelectionStart):
case nameof(SelectionEnd):
case nameof(SelectionForegroundBrush):
case nameof (PasswordChar):
case nameof (RevealPassword):
case nameof(PasswordChar):
case nameof(RevealPassword):
case nameof(FlowDirection):
{
InvalidateTextLayout();
break;
}
{
InvalidateTextLayout();
break;
}
}
}
}

2
src/Avalonia.Controls/TextBox.cs

@ -1142,7 +1142,7 @@ namespace Avalonia.Controls
protected override void OnPointerPressed(PointerPressedEventArgs e)
{
if (_presenter == null)
if (_presenter == null || !string.IsNullOrEmpty(_presenter.PreeditText))
{
return;
}

8
src/Windows/Avalonia.Win32/Input/Imm32CaretManager.cs

@ -7,14 +7,11 @@ namespace Avalonia.Win32.Input
{
private bool _isCaretCreated;
public void TryCreate(int _langId, IntPtr hwnd)
public void TryCreate(IntPtr hwnd)
{
if (!_isCaretCreated)
{
if (_langId == LANG_ZH || _langId == LANG_JA)
{
_isCaretCreated = CreateCaret(hwnd, IntPtr.Zero, 2, 10);
}
_isCaretCreated = CreateCaret(hwnd, IntPtr.Zero, 2, 2);
}
}
@ -31,6 +28,7 @@ namespace Avalonia.Win32.Input
if (_isCaretCreated)
{
DestroyCaret();
_isCaretCreated = false;
}
}

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

@ -1,4 +1,6 @@
using System;
using System.Runtime.InteropServices;
using System.Text;
using Avalonia.Input.TextInput;
using Avalonia.Threading;
@ -12,102 +14,125 @@ namespace Avalonia.Win32.Input
class Imm32InputMethod : ITextInputMethodImpl
{
public IntPtr HWND { get; private set; }
private IntPtr _defaultImc;
private IntPtr _currentHimc;
private WindowImpl _parent;
private bool _active;
private bool _showCompositionWindow;
private ITextInputMethodClient _client;
private Imm32CaretManager _caretManager = new();
private bool _showCandidateList;
private ushort _langId;
private const int _caretMargin = 1;
public void SetLanguageAndWindow(WindowImpl parent, IntPtr hwnd, IntPtr HKL)
public bool IsActive => _client != null;
public bool IsComposing { get; set; }
public bool ShowCompositionWindow => false;
public void CreateCaret()
{
_caretManager.TryCreate(HWND);
}
public void EnableImm()
{
if (HWND != hwnd)
var himc = ImmGetContext(HWND);
if(himc == IntPtr.Zero)
{
himc = ImmCreateContext();
}
if(himc != _currentHimc)
{
_defaultImc = IntPtr.Zero;
if(_currentHimc != IntPtr.Zero)
{
DisableImm();
}
ImmAssociateContext(HWND, himc);
ImmReleaseContext(HWND, himc);
_currentHimc = himc;
_caretManager.TryCreate(HWND);
}
}
public void DisableImm()
{
_caretManager.TryDestroy();
Reset();
ImmAssociateContext(HWND, IntPtr.Zero);
_caretManager.TryDestroy();
_currentHimc = IntPtr.Zero;
}
public void SetLanguageAndWindow(WindowImpl parent, IntPtr hwnd, IntPtr HKL)
{
HWND = hwnd;
_parent = parent;
_active = false;
_langId = PRIMARYLANGID(LGID(HKL));
_showCompositionWindow = true;
_showCandidateList = true;
IsComposing = false;
var langId= PRIMARYLANGID(LGID(HKL));
if(langId != _langId)
{
DisableImm();
}
_langId = langId;
EnableImm();
}
public void ClearLanguageAndWindow()
{
if (HWND != IntPtr.Zero && _defaultImc != IntPtr.Zero)
{
ImmReleaseContext(HWND, _defaultImc);
}
DisableImm();
_defaultImc = IntPtr.Zero;
HWND = IntPtr.Zero;
_parent = null;
_active = false;
_client = null;
_langId = 0;
_showCompositionWindow = false;
_showCandidateList = false;
IsComposing = false;
}
//Dependant on CurrentThread. When Avalonia will support Multiple Dispatchers -
//every Dispatcher should have their own InputMethod.
public static Imm32InputMethod Current { get; } = new Imm32InputMethod();
public static Imm32InputMethod Current { get; } = new Imm32InputMethod();
private IntPtr DefaultImc
public void Reset()
{
get
Dispatcher.UIThread.Post(() =>
{
if (_defaultImc == IntPtr.Zero &&
HWND != IntPtr.Zero)
{
_defaultImc = ImmGetContext(HWND);
ImmReleaseContext(HWND, _defaultImc);
}
var himc = ImmGetContext(HWND);
if (_defaultImc == IntPtr.Zero)
if (IsComposing)
{
_defaultImc = ImmCreateContext();
ImmNotifyIME(himc, NI_COMPOSITIONSTR, CPS_COMPLETE, 0);
IsComposing = false;
}
return _defaultImc;
}
}
public void Reset()
{
if (IsComposing)
{
Dispatcher.UIThread.Post(() =>
{
ImmNotifyIME(DefaultImc, NI_COMPOSITIONSTR, CPS_COMPLETE, 0);
ImmReleaseContext(HWND, DefaultImc);
IsComposing = false;
});
}
ImmReleaseContext(HWND, himc);
});
}
public void SetClient(ITextInputMethodClient client)
{
_active = client is { };
_client = client;
Dispatcher.UIThread.Post(() =>
{
if (_active)
if (IsActive)
{
if (DefaultImc != IntPtr.Zero)
{
_caretManager.TryCreate(_langId, HWND);
// Load the default IME context.
// NOTE(hbono)
// IMM ignores this call if the IME context is loaded. Therefore, we do
// not have to check whether or not the IME context is loaded.
ImmAssociateContext(HWND, _defaultImc);
}
EnableImm();
}
else
{
@ -116,14 +141,8 @@ namespace Avalonia.Win32.Input
// mouse button and selected a password input while composing a text.
// For this case, we have to complete the ongoing composition and
// clean up the resources attached to this object BEFORE DISABLING THE IME.
if (IsComposing)
{
ImmNotifyIME(DefaultImc, NI_COMPOSITIONSTR, CPS_COMPLETE, 0);
ImmReleaseContext(HWND, DefaultImc);
IsComposing = false;
}
ImmAssociateContext(HWND, IntPtr.Zero);
_caretManager.TryDestroy();
DisableImm();
}
});
}
@ -131,19 +150,23 @@ namespace Avalonia.Win32.Input
public void SetCursorRect(Rect rect)
{
var focused = GetActiveWindow() == HWND;
if (!focused)
{
return;
}
Dispatcher.UIThread.Post(() =>
{
IntPtr himc = DefaultImc;
var himc = ImmGetContext(HWND);
if (himc == IntPtr.Zero)
{
return;
}
MoveImeWindow(rect, himc);
ImmReleaseContext(HWND, himc);
});
}
@ -157,8 +180,7 @@ namespace Avalonia.Win32.Input
var s = _parent?.DesktopScaling ?? 1;
var (x1, y1, x2, y2) = ((int) (p1.X * s), (int) (p1.Y * s), (int) (p2.X * s), (int) (p2.Y * s));
if (!_showCompositionWindow &&
_langId == LANG_ZH)
if (!ShowCompositionWindow && _langId == LANG_ZH)
{
// Chinese IMEs ignore function calls to ::ImmSetCandidateWindow()
// when a user disables TSF (Text Service Framework) and CUAS (Cicero
@ -175,12 +197,13 @@ namespace Avalonia.Win32.Input
dwStyle = CFS_CANDIDATEPOS,
ptCurrentPos = new POINT {X = x2, Y = y2}
};
ImmSetCandidateWindow(himc, ref candidateForm);
}
_caretManager.TryMove(x2, y2);
if (_showCompositionWindow)
if (ShowCompositionWindow)
{
ConfigureCompositionWindow(x1, y1, himc, y2 - y1);
// Don't need to set the position of candidate window.
@ -214,6 +237,7 @@ namespace Avalonia.Win32.Input
ptCurrentPos = new POINT {X = x1, Y = y1},
rcArea = new RECT {left = x1, top = y1, right = x2, bottom = y2 + _caretMargin}
};
ImmSetCandidateWindow(himc, ref excludeRectangle);
}
@ -224,6 +248,7 @@ namespace Avalonia.Win32.Input
dwStyle = CFS_POINT,
ptCurrentPos = new POINT {X = x1, Y = y1},
};
ImmSetCompositionWindow(himc, ref compForm);
var logFont = new LOGFONT()
@ -231,6 +256,7 @@ namespace Avalonia.Win32.Input
lfHeight = height,
lfQuality = 5 //CLEARTYPE_QUALITY
};
ImmSetCompositionFont(himc, ref logFont);
}
@ -238,8 +264,43 @@ namespace Avalonia.Win32.Input
{
// we're skipping this. not usable on windows
}
public void CompositionChanged()
{
if (!IsComposing)
{
return;
}
if(!IsActive || !_client.SupportsPreedit)
{
return;
}
var composition = GetCompositionString();
_client.SetPreeditText(composition);
}
public bool IsComposing { get; set; }
private string GetCompositionString()
{
var himc = ImmGetContext(HWND);
var length = ImmGetCompositionString(himc, GCS.GCS_COMPSTR, IntPtr.Zero, 0);
var buffer = new byte[length];
unsafe
{
fixed (byte* bufferPtr = buffer)
{
var error = ImmGetCompositionString(himc, GCS.GCS_COMPSTR, (IntPtr)bufferPtr, (uint)length);
return Encoding.Unicode.GetString(buffer, 0, buffer.Length);
}
}
}
~Imm32InputMethod()
{

71
src/Windows/Avalonia.Win32/Interop/UnmanagedMethods.cs

@ -1766,6 +1766,46 @@ namespace Avalonia.Win32.Interop
[DllImport("user32.dll")]
internal static extern int SetWindowCompositionAttribute(IntPtr hwnd, ref WindowCompositionAttributeData data);
[Flags]
public enum GCS : uint
{
/// <summary>Retrieve or update the attribute of the composition string.</summary>
GCS_COMPATTR = 0x0010,
/// <summary>Retrieve or update clause information of the composition string.</summary>
GCS_COMPCLAUSE = 0x0020,
/// <summary>Retrieve or update the attributes of the reading string of the current composition.</summary>
GCS_COMPREADATTR = 0x0002,
/// <summary>Retrieve or update the clause information of the reading string of the composition string.</summary>
GCS_COMPREADCLAUSE = 0x0004,
/// <summary>Retrieve or update the reading string of the current composition.</summary>
GCS_COMPREADSTR = 0x0001,
/// <summary>Retrieve or update the current composition string.</summary>
GCS_COMPSTR = 0x0008,
/// <summary>Retrieve or update the cursor position in composition string.</summary>
GCS_CURSORPOS = 0x0080,
/// <summary>Retrieve or update the starting position of any changes in composition string.</summary>
GCS_DELTASTART = 0x0100,
/// <summary>Retrieve or update clause information of the result string.</summary>
GCS_RESULTCLAUSE = 0x1000,
/// <summary>Retrieve or update clause information of the reading string.</summary>
GCS_RESULTREADCLAUSE = 0x0400,
/// <summary>Retrieve or update the reading string.</summary>
GCS_RESULTREADSTR = 0x0200,
/// <summary>Retrieve or update the string of the composition result.</summary>
GCS_RESULTSTR = 0x0800,
}
[DllImport("imm32.dll", SetLastError = true)]
public static extern IntPtr ImmGetContext(IntPtr hWnd);
[DllImport("imm32.dll", SetLastError = true)]
@ -1788,6 +1828,29 @@ namespace Avalonia.Win32.Interop
public static extern bool ImmSetCompositionWindow(IntPtr hIMC, ref COMPOSITIONFORM lpComp);
[DllImport("imm32.dll")]
public static extern bool ImmSetCompositionFont(IntPtr hIMC, ref LOGFONT lf);
[DllImport("imm32.dll", SetLastError = false, CharSet = CharSet.Unicode)]
public static extern int ImmGetCompositionString(IntPtr hIMC, GCS dwIndex, [Out, Optional] IntPtr lpBuf, uint dwBufLen);
public static string ImmGetCompositionString(IntPtr hIMC, GCS dwIndex)
{
int bufferLength = ImmGetCompositionString(hIMC, dwIndex, IntPtr.Zero, 0);
if (bufferLength > 0)
{
var buffer = new byte[bufferLength];
fixed(byte* bufferPtr = buffer)
{
var error = ImmGetCompositionString(hIMC, dwIndex, (IntPtr)bufferPtr, (uint)bufferLength);
return Marshal.PtrToStringUni((IntPtr)bufferPtr);
}
}
return null;
}
[DllImport("imm32.dll")]
public static extern bool ImmNotifyIME(IntPtr hIMC, int dwAction, int dwIndex, int dwValue);
[DllImport("user32.dll")]
@ -1827,7 +1890,13 @@ namespace Avalonia.Win32.Interop
public const int CFS_EXCLUDE = 0x0080;
public const int CFS_POINT = 0x0002;
public const int CFS_RECT = 0x0001;
public const uint ISC_SHOWUICOMPOSITIONWINDOW = 0x80000000;
// lParam for WM_IME_SETCONTEXT
public const long ISC_SHOWUICANDIDATEWINDOW = 0x00000001;
public const long ISC_SHOWUICOMPOSITIONWINDOW = 0x80000000;
public const long ISC_SHOWUIGUIDELINE = 0x40000000;
public const long ISC_SHOWUIALLCANDIDATEWINDOW = 0x0000000F;
public const long ISC_SHOWUIALL = 0xC000000F;
public const int NI_COMPOSITIONSTR = 21;
public const int CPS_COMPLETE = 1;

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

@ -527,22 +527,22 @@ namespace Avalonia.Win32
}
case WindowsMessage.WM_PAINT:
{
using(NonPumpingSyncContext.Use())
using (_rendererLock.Lock())
{
if (BeginPaint(_hwnd, out PAINTSTRUCT ps) != IntPtr.Zero)
using (NonPumpingSyncContext.Use())
using (_rendererLock.Lock())
{
var f = RenderScaling;
var r = ps.rcPaint;
Paint?.Invoke(new Rect(r.left / f, r.top / f, (r.right - r.left) / f,
(r.bottom - r.top) / f));
EndPaint(_hwnd, ref ps);
if (BeginPaint(_hwnd, out PAINTSTRUCT ps) != IntPtr.Zero)
{
var f = RenderScaling;
var r = ps.rcPaint;
Paint?.Invoke(new Rect(r.left / f, r.top / f, (r.right - r.left) / f,
(r.bottom - r.top) / f));
EndPaint(_hwnd, ref ps);
}
}
}
return IntPtr.Zero;
}
return IntPtr.Zero;
}
case WindowsMessage.WM_ENTERSIZEMOVE:
@ -551,7 +551,7 @@ namespace Avalonia.Win32
case WindowsMessage.WM_SIZE:
{
using(NonPumpingSyncContext.Use())
using (NonPumpingSyncContext.Use())
using (_rendererLock.Lock())
{
// Do nothing here, just block until the pending frame render is completed on the render thread
@ -651,13 +651,19 @@ namespace Avalonia.Win32
}
case WindowsMessage.WM_IME_SETCONTEXT:
{
// TODO if we implement preedit, disable the composition window:
// lParam = new IntPtr((int)(((uint)lParam.ToInt64()) & ~ISC_SHOWUICOMPOSITIONWINDOW));
DefWindowProc(Hwnd, msg, wParam, (IntPtr)(lParam.ToInt64() & ~ISC_SHOWUICOMPOSITIONWINDOW));
UpdateInputMethod(GetKeyboardLayout(0));
return IntPtr.Zero;
}
case WindowsMessage.WM_IME_COMPOSITION:
{
Imm32InputMethod.Current.CompositionChanged();
break;
}
case WindowsMessage.WM_IME_CHAR:
case WindowsMessage.WM_IME_COMPOSITION:
case WindowsMessage.WM_IME_COMPOSITIONFULL:
case WindowsMessage.WM_IME_CONTROL:
case WindowsMessage.WM_IME_KEYDOWN:
@ -667,6 +673,7 @@ namespace Avalonia.Win32
break;
case WindowsMessage.WM_IME_STARTCOMPOSITION:
Imm32InputMethod.Current.IsComposing = true;
return IntPtr.Zero;
break;
case WindowsMessage.WM_IME_ENDCOMPOSITION:
Imm32InputMethod.Current.IsComposing = false;
@ -687,7 +694,7 @@ namespace Avalonia.Win32
return UnmanagedMethods.DefWindowProc(hWnd, msg, wParam, lParam);
#endif
if(shouldTakeFocus)
if (shouldTakeFocus)
{
SetFocus(_hwnd);
}
@ -916,14 +923,15 @@ namespace Avalonia.Win32
{
// note: for non-ime language, also create it so that emoji panel tracks cursor
var langid = LGID(hkl);
if (langid == _langid && Imm32InputMethod.Current.HWND == Hwnd)
{
return;
}
_langid = langid;
Imm32InputMethod.Current.SetLanguageAndWindow(this, Hwnd, hkl);
}
private static int ToInt32(IntPtr ptr)

Loading…
Cancel
Save