| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164 |
- using Ryujinx.HLE.Ui;
- using Ryujinx.Memory;
- using System;
- using System.Threading;
- namespace Ryujinx.HLE.HOS.Applets.SoftwareKeyboard
- {
- /// <summary>
- /// Class that manages the renderer base class and its state in a multithreaded context.
- /// </summary>
- internal class SoftwareKeyboardRenderer : IDisposable
- {
- private const int TextBoxBlinkSleepMilliseconds = 100;
- private const int RendererWaitTimeoutMilliseconds = 100;
- private readonly object _stateLock = new object();
- private SoftwareKeyboardUiState _state = new SoftwareKeyboardUiState();
- private SoftwareKeyboardRendererBase _renderer;
- private TimedAction _textBoxBlinkTimedAction = new TimedAction();
- private TimedAction _renderAction = new TimedAction();
- public SoftwareKeyboardRenderer(IHostUiTheme uiTheme)
- {
- _renderer = new SoftwareKeyboardRendererBase(uiTheme);
- StartTextBoxBlinker(_textBoxBlinkTimedAction, _state, _stateLock);
- StartRenderer(_renderAction, _renderer, _state, _stateLock);
- }
- private static void StartTextBoxBlinker(TimedAction timedAction, SoftwareKeyboardUiState state, object stateLock)
- {
- timedAction.Reset(() =>
- {
- lock (stateLock)
- {
- // The blinker is on half of the time and events such as input
- // changes can reset the blinker.
- state.TextBoxBlinkCounter = (state.TextBoxBlinkCounter + 1) % (2 * SoftwareKeyboardRendererBase.TextBoxBlinkThreshold);
- // Tell the render thread there is something new to render.
- Monitor.PulseAll(stateLock);
- }
- }, TextBoxBlinkSleepMilliseconds);
- }
- private static void StartRenderer(TimedAction timedAction, SoftwareKeyboardRendererBase renderer, SoftwareKeyboardUiState state, object stateLock)
- {
- SoftwareKeyboardUiState internalState = new SoftwareKeyboardUiState();
- bool canCreateSurface = false;
- bool needsUpdate = true;
- timedAction.Reset(() =>
- {
- lock (stateLock)
- {
- if (!Monitor.Wait(stateLock, RendererWaitTimeoutMilliseconds))
- {
- return;
- }
- needsUpdate = UpdateStateField(ref state.InputText, ref internalState.InputText);
- needsUpdate |= UpdateStateField(ref state.CursorBegin, ref internalState.CursorBegin);
- needsUpdate |= UpdateStateField(ref state.CursorEnd, ref internalState.CursorEnd);
- needsUpdate |= UpdateStateField(ref state.AcceptPressed, ref internalState.AcceptPressed);
- needsUpdate |= UpdateStateField(ref state.CancelPressed, ref internalState.CancelPressed);
- needsUpdate |= UpdateStateField(ref state.OverwriteMode, ref internalState.OverwriteMode);
- needsUpdate |= UpdateStateField(ref state.TypingEnabled, ref internalState.TypingEnabled);
- needsUpdate |= UpdateStateField(ref state.ControllerEnabled, ref internalState.ControllerEnabled);
- needsUpdate |= UpdateStateField(ref state.TextBoxBlinkCounter, ref internalState.TextBoxBlinkCounter);
- canCreateSurface = state.SurfaceInfo != null && internalState.SurfaceInfo == null;
- if (canCreateSurface)
- {
- internalState.SurfaceInfo = state.SurfaceInfo;
- }
- }
- if (canCreateSurface)
- {
- renderer.CreateSurface(internalState.SurfaceInfo);
- }
- if (needsUpdate)
- {
- renderer.DrawMutableElements(internalState);
- renderer.CopyImageToBuffer();
- needsUpdate = false;
- }
- });
- }
- private static bool UpdateStateField<T>(ref T source, ref T destination) where T : IEquatable<T>
- {
- if (!source.Equals(destination))
- {
- destination = source;
- return true;
- }
- return false;
- }
- #pragma warning disable CS8632
- public void UpdateTextState(string? inputText, int? cursorBegin, int? cursorEnd, bool? overwriteMode, bool? typingEnabled)
- #pragma warning restore CS8632
- {
- lock (_stateLock)
- {
- // Update the parameters that were provided.
- _state.InputText = inputText != null ? inputText : _state.InputText;
- _state.CursorBegin = cursorBegin.GetValueOrDefault(_state.CursorBegin);
- _state.CursorEnd = cursorEnd.GetValueOrDefault(_state.CursorEnd);
- _state.OverwriteMode = overwriteMode.GetValueOrDefault(_state.OverwriteMode);
- _state.TypingEnabled = typingEnabled.GetValueOrDefault(_state.TypingEnabled);
- // Reset the cursor blink.
- _state.TextBoxBlinkCounter = 0;
- // Tell the render thread there is something new to render.
- Monitor.PulseAll(_stateLock);
- }
- }
- public void UpdateCommandState(bool? acceptPressed, bool? cancelPressed, bool? controllerEnabled)
- {
- lock (_stateLock)
- {
- // Update the parameters that were provided.
- _state.AcceptPressed = acceptPressed.GetValueOrDefault(_state.AcceptPressed);
- _state.CancelPressed = cancelPressed.GetValueOrDefault(_state.CancelPressed);
- _state.ControllerEnabled = controllerEnabled.GetValueOrDefault(_state.ControllerEnabled);
- // Tell the render thread there is something new to render.
- Monitor.PulseAll(_stateLock);
- }
- }
- public void SetSurfaceInfo(RenderingSurfaceInfo surfaceInfo)
- {
- lock (_stateLock)
- {
- _state.SurfaceInfo = surfaceInfo;
- // Tell the render thread there is something new to render.
- Monitor.PulseAll(_stateLock);
- }
- }
- internal bool DrawTo(IVirtualMemoryManager destination, ulong position)
- {
- return _renderer.WriteBufferToMemory(destination, position);
- }
- public void Dispose()
- {
- _textBoxBlinkTimedAction.RequestCancel();
- _renderAction.RequestCancel();
- }
- }
- }
|