WindowsInputPane.cs 2.7 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677
  1. using System;
  2. using Avalonia.Controls.Platform;
  3. using Avalonia.MicroCom;
  4. using Avalonia.Win32.Interop;
  5. using Avalonia.Win32.Win32Com;
  6. namespace Avalonia.Win32.Input;
  7. internal unsafe class WindowsInputPane : IInputPane, IDisposable
  8. {
  9. // GUID: D5120AA3-46BA-44C5-822D-CA8092C1FC72
  10. private static readonly Guid CLSID_FrameworkInputPane = new(0xD5120AA3, 0x46BA, 0x44C5, 0x82, 0x2D, 0xCA, 0x80, 0x92, 0xC1, 0xFC, 0x72);
  11. // GUID: 5752238B-24F0-495A-82F1-2FD593056796
  12. private static readonly Guid SID_IFrameworkInputPane = new(0x5752238B, 0x24F0, 0x495A, 0x82, 0xF1, 0x2F, 0xD5, 0x93, 0x05, 0x67, 0x96);
  13. private readonly WindowImpl _windowImpl;
  14. private readonly IFrameworkInputPane _inputPane;
  15. private readonly uint _cookie;
  16. public WindowsInputPane(WindowImpl windowImpl)
  17. {
  18. _windowImpl = windowImpl;
  19. _inputPane = UnmanagedMethods.CreateInstance<IFrameworkInputPane>(in CLSID_FrameworkInputPane, in SID_IFrameworkInputPane);
  20. using (var handler = new Handler(this))
  21. {
  22. uint cookie = 0;
  23. _inputPane.AdviseWithHWND(windowImpl.Handle.Handle, handler, &cookie);
  24. _cookie = cookie;
  25. }
  26. }
  27. public InputPaneState State { get; private set; }
  28. public Rect OccludedRect { get; private set; }
  29. public event EventHandler<InputPaneStateEventArgs>? StateChanged;
  30. private void OnStateChanged(bool showing, UnmanagedMethods.RECT? prcInputPaneScreenLocation)
  31. {
  32. var oldState = (OccludedRect, State);
  33. OccludedRect = prcInputPaneScreenLocation.HasValue
  34. ? ScreenRectToClient(prcInputPaneScreenLocation.Value)
  35. : default;
  36. State = showing ? InputPaneState.Open : InputPaneState.Closed;
  37. if (oldState != (OccludedRect, State))
  38. {
  39. StateChanged?.Invoke(this, new InputPaneStateEventArgs(State, null, OccludedRect));
  40. }
  41. }
  42. private Rect ScreenRectToClient(UnmanagedMethods.RECT screenRect)
  43. {
  44. var position = new PixelPoint(screenRect.left, screenRect.top);
  45. var size = new PixelSize(screenRect.Width, screenRect.Height);
  46. return new Rect(_windowImpl.PointToClient(position), size.ToSize(_windowImpl.DesktopScaling));
  47. }
  48. public void Dispose()
  49. {
  50. if (_cookie != 0)
  51. {
  52. _inputPane.Unadvise(_cookie);
  53. }
  54. _inputPane.Dispose();
  55. }
  56. private class Handler : CallbackBase, IFrameworkInputPaneHandler
  57. {
  58. private readonly WindowsInputPane _pane;
  59. public Handler(WindowsInputPane pane) => _pane = pane;
  60. public void Showing(UnmanagedMethods.RECT* rect, int _) => _pane.OnStateChanged(true, *rect);
  61. public void Hiding(int fEnsureFocusedElementInView) => _pane.OnStateChanged(false, null);
  62. }
  63. }