Example #1
0
        internal GameStateWatcher(string gameInstallFolder, string gameOptionsFolder, string journalFolder, INativeMethods nativeMethods)
        {
            var gif = new GameInstallFolder(gameInstallFolder);
            var gof = new GameOptionsFolder(gameOptionsFolder);
            var jf  = new JournalFolder(journalFolder);

            _journalWatcher             = new JournalWatcher(jf);
            _journalWatcher.Started    += JournalWatcher_Started;
            _journalWatcher.EntryAdded += JournalWatcher_EntryAdded;

            _statusWatcher          = new StatusWatcher(jf);
            _statusWatcher.Changed += StatusWatcher_Changed;

            _bindingsWatcher          = new BindingsWatcher(gif, gof);
            _bindingsWatcher.Changed += BindingsWatcher_Changed;

            _graphicsConfig          = new GraphicsConfigWatcher(gif, gof);
            _graphicsConfig.Changed += GraphicsConfig_Changed;

            _modifierKeysWatcher          = new ModifierKeysWatcher(nativeMethods);
            _modifierKeysWatcher.Changed += ModifierKeysWatcher_Changed;

            _gameProcessWatcher          = new GameProcessWatcher(gif, nativeMethods);
            _gameProcessWatcher.Changed += GameProcessWatcher_Changed;

            _gameState = new GameState();
        }
        public void WatchesForGameProcessChanges()
        {
            var nm = new NativeMethodsMock()
            {
                Processes =
                {
                    [0]    = "System",
                    [1000] = "Process 1000",
                    [2000] = _gif.MainExecutable.FullName,
                },
            };

            using var gpw = new GameProcessWatcher(_gif, nm);
            var evs = new EventCollector <GameProcessState>(h => gpw.Changed += h, h => gpw.Changed -= h, nameof(WatchesForGameProcessChanges));

            var pss = evs.Wait(3, () =>
            {
                InvokeTimerElapsed(gpw);

                nm.ForegroundWindow = new IntPtr(2000);
                InvokeTimerElapsed(gpw);

                nm.ForegroundWindow = new IntPtr(1000);
                InvokeTimerElapsed(gpw);
            });

            Assert.Equal(GameProcessState.NotRunning, pss[0]);
            Assert.Equal(GameProcessState.InForeground, pss[1]);
            Assert.Equal(GameProcessState.InBackground, pss[2]);
        }
        private static void InvokeTimerElapsed(GameProcessWatcher instance)
        {
            // HACK: Hopefully will no longer be needed when .NET 5.0 arrives (https://github.com/dotnet/runtime/issues/31204)
            var e = (ElapsedEventArgs)_ciElapsedEventArgs.Invoke(new object[] { DateTime.Now.ToFileTime() });

            _miTimerElapsed.Invoke(instance, new object[] { instance, e });
        }
        public void DoesNotThrowWhenDisposingTwice()
        {
            var pw = new GameProcessWatcher(_gif, new NativeMethodsMock());

#pragma warning disable IDISP016, IDISP017
            pw.Dispose();
            pw.Dispose();
#pragma warning restore IDISP016, IDISP017
        }
        public void StartAndStopAreNotReentrant()
        {
            using var gpw = new GameProcessWatcher(_gif, new NativeMethodsMock());

            bool IsRunning() => gpw.GetPrivateField <bool>("_running");

            Assert.False(IsRunning());

            gpw.Start();
            Assert.True(IsRunning());

            gpw.Start();
            Assert.True(IsRunning());

            gpw.Stop();
            Assert.False(IsRunning());

            gpw.Stop();
            Assert.False(IsRunning());
        }
        public void OnChangedIsNotReentrant()
        {
            var nm = new NativeMethodsMock()
            {
                Processes =
                {
                    [0]    = "System",
                    [1000] = "Process 1000",
                    [2000] = _gif.MainExecutable.FullName,
                },
            };

            using var gpw = new GameProcessWatcher(_gif, nm);

            var nOnChangedCalls = 0;

            using var mre = new ManualResetEventSlim();

            gpw.Changed += (sender, e) =>
            {
                Interlocked.Increment(ref nOnChangedCalls);
                mre.Wait();
            };

            void TimerElapsed(int pid)
            {
                nm.ForegroundWindow = new IntPtr(pid);
                InvokeTimerElapsed(gpw);
                mre.Set();
            }

            Task.WaitAll(new[]
            {
                Task.Run(() => TimerElapsed(1000)),
                Task.Run(() => TimerElapsed(2000)),
            });

            Assert.Equal(1, nOnChangedCalls);
        }