From cee712105850ac3385cd0091a923438167433f9f Mon Sep 17 00:00:00 2001
From: TSR Berry <20988865+TSRBerry@users.noreply.github.com>
Date: Sat, 8 Apr 2023 01:22:00 +0200
Subject: Move solution and projects to src
---
.../HOS/Applets/SoftwareKeyboard/TimedAction.cs | 186 +++++++++++++++++++++
1 file changed, 186 insertions(+)
create mode 100644 src/Ryujinx.HLE/HOS/Applets/SoftwareKeyboard/TimedAction.cs
(limited to 'src/Ryujinx.HLE/HOS/Applets/SoftwareKeyboard/TimedAction.cs')
diff --git a/src/Ryujinx.HLE/HOS/Applets/SoftwareKeyboard/TimedAction.cs b/src/Ryujinx.HLE/HOS/Applets/SoftwareKeyboard/TimedAction.cs
new file mode 100644
index 00000000..0de78a0e
--- /dev/null
+++ b/src/Ryujinx.HLE/HOS/Applets/SoftwareKeyboard/TimedAction.cs
@@ -0,0 +1,186 @@
+using System;
+using System.Threading;
+
+namespace Ryujinx.HLE.HOS.Applets.SoftwareKeyboard
+{
+ ///
+ /// A threaded executor of periodic actions that can be cancelled. The total execution time is optional
+ /// and, in this case, a progress is reported back to the action.
+ ///
+ class TimedAction
+ {
+ public const int MaxThreadSleep = 100;
+
+ private class SleepSubstepData
+ {
+ public readonly int SleepMilliseconds;
+ public readonly int SleepCount;
+ public readonly int SleepRemainderMilliseconds;
+
+ public SleepSubstepData(int sleepMilliseconds)
+ {
+ SleepMilliseconds = Math.Min(sleepMilliseconds, MaxThreadSleep);
+ SleepCount = sleepMilliseconds / SleepMilliseconds;
+ SleepRemainderMilliseconds = sleepMilliseconds - SleepCount * SleepMilliseconds;
+ }
+ }
+
+ private TRef _cancelled = null;
+ private Thread _thread = null;
+ private object _lock = new object();
+
+ public bool IsRunning
+ {
+ get
+ {
+ lock (_lock)
+ {
+ if (_thread == null)
+ {
+ return false;
+ }
+
+ return _thread.IsAlive;
+ }
+ }
+ }
+
+ public void RequestCancel()
+ {
+ lock (_lock)
+ {
+ if (_cancelled != null)
+ {
+ Volatile.Write(ref _cancelled.Value, true);
+ }
+ }
+ }
+
+ public TimedAction() { }
+
+ private void Reset(Thread thread, TRef cancelled)
+ {
+ lock (_lock)
+ {
+ // Cancel the current task.
+ if (_cancelled != null)
+ {
+ Volatile.Write(ref _cancelled.Value, true);
+ }
+
+ _cancelled = cancelled;
+
+ _thread = thread;
+ _thread.IsBackground = true;
+ _thread.Start();
+ }
+ }
+
+ public void Reset(Action action, int totalMilliseconds, int sleepMilliseconds)
+ {
+ // Create a dedicated cancel token for each task.
+ var cancelled = new TRef(false);
+
+ Reset(new Thread(() =>
+ {
+ var substepData = new SleepSubstepData(sleepMilliseconds);
+
+ int totalCount = totalMilliseconds / sleepMilliseconds;
+ int totalRemainder = totalMilliseconds - totalCount * sleepMilliseconds;
+
+ if (Volatile.Read(ref cancelled.Value))
+ {
+ action(-1);
+
+ return;
+ }
+
+ action(0);
+
+ for (int i = 1; i <= totalCount; i++)
+ {
+ if (SleepWithSubstep(substepData, cancelled))
+ {
+ action(-1);
+
+ return;
+ }
+
+ action((float)(i * sleepMilliseconds) / totalMilliseconds);
+ }
+
+ if (totalRemainder > 0)
+ {
+ if (SleepWithSubstep(substepData, cancelled))
+ {
+ action(-1);
+
+ return;
+ }
+
+ action(1);
+ }
+ }), cancelled);
+ }
+
+ public void Reset(Action action, int sleepMilliseconds)
+ {
+ // Create a dedicated cancel token for each task.
+ var cancelled = new TRef(false);
+
+ Reset(new Thread(() =>
+ {
+ var substepData = new SleepSubstepData(sleepMilliseconds);
+
+ while (!Volatile.Read(ref cancelled.Value))
+ {
+ action();
+
+ if (SleepWithSubstep(substepData, cancelled))
+ {
+ return;
+ }
+ }
+ }), cancelled);
+ }
+
+ public void Reset(Action action)
+ {
+ // Create a dedicated cancel token for each task.
+ var cancelled = new TRef(false);
+
+ Reset(new Thread(() =>
+ {
+ while (!Volatile.Read(ref cancelled.Value))
+ {
+ action();
+ }
+ }), cancelled);
+ }
+
+ private static bool SleepWithSubstep(SleepSubstepData substepData, TRef cancelled)
+ {
+ for (int i = 0; i < substepData.SleepCount; i++)
+ {
+ if (Volatile.Read(ref cancelled.Value))
+ {
+ return true;
+ }
+
+ Thread.Sleep(substepData.SleepMilliseconds);
+ }
+
+ if (substepData.SleepRemainderMilliseconds > 0)
+ {
+ if (Volatile.Read(ref cancelled.Value))
+ {
+ return true;
+ }
+
+ Thread.Sleep(substepData.SleepRemainderMilliseconds);
+ }
+
+ return Volatile.Read(ref cancelled.Value);
+ }
+ }
+}
--
cgit v1.2.3