SoftwareKeyboardRenderer.cs 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164
  1. using Ryujinx.HLE.Ui;
  2. using Ryujinx.Memory;
  3. using System;
  4. using System.Threading;
  5. namespace Ryujinx.HLE.HOS.Applets.SoftwareKeyboard
  6. {
  7. /// <summary>
  8. /// Class that manages the renderer base class and its state in a multithreaded context.
  9. /// </summary>
  10. internal class SoftwareKeyboardRenderer : IDisposable
  11. {
  12. private const int TextBoxBlinkSleepMilliseconds = 100;
  13. private const int RendererWaitTimeoutMilliseconds = 100;
  14. private readonly object _stateLock = new object();
  15. private SoftwareKeyboardUiState _state = new SoftwareKeyboardUiState();
  16. private SoftwareKeyboardRendererBase _renderer;
  17. private TimedAction _textBoxBlinkTimedAction = new TimedAction();
  18. private TimedAction _renderAction = new TimedAction();
  19. public SoftwareKeyboardRenderer(IHostUiTheme uiTheme)
  20. {
  21. _renderer = new SoftwareKeyboardRendererBase(uiTheme);
  22. StartTextBoxBlinker(_textBoxBlinkTimedAction, _state, _stateLock);
  23. StartRenderer(_renderAction, _renderer, _state, _stateLock);
  24. }
  25. private static void StartTextBoxBlinker(TimedAction timedAction, SoftwareKeyboardUiState state, object stateLock)
  26. {
  27. timedAction.Reset(() =>
  28. {
  29. lock (stateLock)
  30. {
  31. // The blinker is on half of the time and events such as input
  32. // changes can reset the blinker.
  33. state.TextBoxBlinkCounter = (state.TextBoxBlinkCounter + 1) % (2 * SoftwareKeyboardRendererBase.TextBoxBlinkThreshold);
  34. // Tell the render thread there is something new to render.
  35. Monitor.PulseAll(stateLock);
  36. }
  37. }, TextBoxBlinkSleepMilliseconds);
  38. }
  39. private static void StartRenderer(TimedAction timedAction, SoftwareKeyboardRendererBase renderer, SoftwareKeyboardUiState state, object stateLock)
  40. {
  41. SoftwareKeyboardUiState internalState = new SoftwareKeyboardUiState();
  42. bool canCreateSurface = false;
  43. bool needsUpdate = true;
  44. timedAction.Reset(() =>
  45. {
  46. lock (stateLock)
  47. {
  48. if (!Monitor.Wait(stateLock, RendererWaitTimeoutMilliseconds))
  49. {
  50. return;
  51. }
  52. needsUpdate = UpdateStateField(ref state.InputText, ref internalState.InputText);
  53. needsUpdate |= UpdateStateField(ref state.CursorBegin, ref internalState.CursorBegin);
  54. needsUpdate |= UpdateStateField(ref state.CursorEnd, ref internalState.CursorEnd);
  55. needsUpdate |= UpdateStateField(ref state.AcceptPressed, ref internalState.AcceptPressed);
  56. needsUpdate |= UpdateStateField(ref state.CancelPressed, ref internalState.CancelPressed);
  57. needsUpdate |= UpdateStateField(ref state.OverwriteMode, ref internalState.OverwriteMode);
  58. needsUpdate |= UpdateStateField(ref state.TypingEnabled, ref internalState.TypingEnabled);
  59. needsUpdate |= UpdateStateField(ref state.ControllerEnabled, ref internalState.ControllerEnabled);
  60. needsUpdate |= UpdateStateField(ref state.TextBoxBlinkCounter, ref internalState.TextBoxBlinkCounter);
  61. canCreateSurface = state.SurfaceInfo != null && internalState.SurfaceInfo == null;
  62. if (canCreateSurface)
  63. {
  64. internalState.SurfaceInfo = state.SurfaceInfo;
  65. }
  66. }
  67. if (canCreateSurface)
  68. {
  69. renderer.CreateSurface(internalState.SurfaceInfo);
  70. }
  71. if (needsUpdate)
  72. {
  73. renderer.DrawMutableElements(internalState);
  74. renderer.CopyImageToBuffer();
  75. needsUpdate = false;
  76. }
  77. });
  78. }
  79. private static bool UpdateStateField<T>(ref T source, ref T destination) where T : IEquatable<T>
  80. {
  81. if (!source.Equals(destination))
  82. {
  83. destination = source;
  84. return true;
  85. }
  86. return false;
  87. }
  88. #pragma warning disable CS8632
  89. public void UpdateTextState(string? inputText, int? cursorBegin, int? cursorEnd, bool? overwriteMode, bool? typingEnabled)
  90. #pragma warning restore CS8632
  91. {
  92. lock (_stateLock)
  93. {
  94. // Update the parameters that were provided.
  95. _state.InputText = inputText != null ? inputText : _state.InputText;
  96. _state.CursorBegin = cursorBegin.GetValueOrDefault(_state.CursorBegin);
  97. _state.CursorEnd = cursorEnd.GetValueOrDefault(_state.CursorEnd);
  98. _state.OverwriteMode = overwriteMode.GetValueOrDefault(_state.OverwriteMode);
  99. _state.TypingEnabled = typingEnabled.GetValueOrDefault(_state.TypingEnabled);
  100. // Reset the cursor blink.
  101. _state.TextBoxBlinkCounter = 0;
  102. // Tell the render thread there is something new to render.
  103. Monitor.PulseAll(_stateLock);
  104. }
  105. }
  106. public void UpdateCommandState(bool? acceptPressed, bool? cancelPressed, bool? controllerEnabled)
  107. {
  108. lock (_stateLock)
  109. {
  110. // Update the parameters that were provided.
  111. _state.AcceptPressed = acceptPressed.GetValueOrDefault(_state.AcceptPressed);
  112. _state.CancelPressed = cancelPressed.GetValueOrDefault(_state.CancelPressed);
  113. _state.ControllerEnabled = controllerEnabled.GetValueOrDefault(_state.ControllerEnabled);
  114. // Tell the render thread there is something new to render.
  115. Monitor.PulseAll(_stateLock);
  116. }
  117. }
  118. public void SetSurfaceInfo(RenderingSurfaceInfo surfaceInfo)
  119. {
  120. lock (_stateLock)
  121. {
  122. _state.SurfaceInfo = surfaceInfo;
  123. // Tell the render thread there is something new to render.
  124. Monitor.PulseAll(_stateLock);
  125. }
  126. }
  127. internal bool DrawTo(IVirtualMemoryManager destination, ulong position)
  128. {
  129. return _renderer.WriteBufferToMemory(destination, position);
  130. }
  131. public void Dispose()
  132. {
  133. _textBoxBlinkTimedAction.RequestCancel();
  134. _renderAction.RequestCancel();
  135. }
  136. }
  137. }