From f2ba3e8793e594c187cc476733b78e51455e82d1 Mon Sep 17 00:00:00 2001
From: Mohammad Shoaib Khan <shoaib.khan20@outlook.com>
Date: Mon, 24 Oct 2022 12:12:53 +0530
Subject: [PATCH] Implemented Tolk library for screen reader in windows

---
 .gitignore                                    |   2 +
 stardew-access/CustomCommands.cs              | 120 +++++++++---------
 stardew-access/ModEntry.cs                    |   9 ++
 .../ScreenReader/ScreenReaderLinux.cs         |  17 ++-
 .../ScreenReader/ScreenReaderWindows.cs       |  58 ++++-----
 stardew-access/stardew-access.csproj          |   2 +-
 6 files changed, 114 insertions(+), 94 deletions(-)

diff --git a/.gitignore b/.gitignore
index 2c855eb..45acc76 100644
--- a/.gitignore
+++ b/.gitignore
@@ -3,6 +3,8 @@
 ##
 ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
 
+*.dll
+
 .vscode/*
 .git-old/
 bin/
diff --git a/stardew-access/CustomCommands.cs b/stardew-access/CustomCommands.cs
index df18be3..a3f748a 100644
--- a/stardew-access/CustomCommands.cs
+++ b/stardew-access/CustomCommands.cs
@@ -21,7 +21,7 @@ namespace stardew_access
                             MainClass.Config.ReadTile = !MainClass.Config.ReadTile;
                             helper.WriteConfig(MainClass.Config);
 
-                            MainClass.DebugLog("Read Tile is " + (MainClass.Config.ReadTile ? "on" : "off"));
+                            MainClass.InfoLog("Read Tile is " + (MainClass.Config.ReadTile ? "on" : "off"));
                         });
 
             helper.ConsoleCommands.Add("flooring", "Toggle flooring in read tile.", (string commmand, string[] args) =>
@@ -29,7 +29,7 @@ namespace stardew_access
                 MainClass.Config.ReadFlooring = !MainClass.Config.ReadFlooring;
                 helper.WriteConfig(MainClass.Config);
 
-                MainClass.DebugLog("Flooring is " + (MainClass.Config.ReadFlooring ? "on" : "off"));
+                MainClass.InfoLog("Flooring is " + (MainClass.Config.ReadFlooring ? "on" : "off"));
             });
 
             helper.ConsoleCommands.Add("watered", "Toggle speaking watered or unwatered for crops.", (string commmand, string[] args) =>
@@ -37,7 +37,7 @@ namespace stardew_access
                 MainClass.Config.WateredToggle = !MainClass.Config.WateredToggle;
                 helper.WriteConfig(MainClass.Config);
 
-                MainClass.DebugLog("Watered toggle is " + (MainClass.Config.WateredToggle ? "on" : "off"));
+                MainClass.InfoLog("Watered toggle is " + (MainClass.Config.WateredToggle ? "on" : "off"));
             });
             #endregion
 
@@ -47,14 +47,14 @@ namespace stardew_access
                 MainClass.Config.Radar = !MainClass.Config.Radar;
                 helper.WriteConfig(MainClass.Config);
 
-                MainClass.DebugLog("Radar " + (MainClass.Config.Radar ? "on" : "off"));
+                MainClass.InfoLog("Radar " + (MainClass.Config.Radar ? "on" : "off"));
             });
 
             helper.ConsoleCommands.Add("rdebug", "Toggle debugging in radar feature.", (string commmand, string[] args) =>
             {
                 MainClass.radarDebug = !MainClass.radarDebug;
 
-                MainClass.DebugLog("Radar debugging " + (MainClass.radarDebug ? "on" : "off"));
+                MainClass.InfoLog("Radar debugging " + (MainClass.radarDebug ? "on" : "off"));
             });
 
             helper.ConsoleCommands.Add("rstereo", "Toggle stereo sound in radar feature.", (string commmand, string[] args) =>
@@ -62,14 +62,14 @@ namespace stardew_access
                 MainClass.Config.RadarStereoSound = !MainClass.Config.RadarStereoSound;
                 helper.WriteConfig(MainClass.Config);
 
-                MainClass.DebugLog("Stereo sound is " + (MainClass.Config.RadarStereoSound ? "on" : "off"));
+                MainClass.InfoLog("Stereo sound is " + (MainClass.Config.RadarStereoSound ? "on" : "off"));
             });
 
             helper.ConsoleCommands.Add("rfocus", "Toggle focus mode in radar feature.", (string commmand, string[] args) =>
             {
                 bool focus = MainClass.RadarFeature.ToggleFocus();
 
-                MainClass.DebugLog("Focus mode is " + (focus ? "on" : "off"));
+                MainClass.InfoLog("Focus mode is " + (focus ? "on" : "off"));
             });
 
             helper.ConsoleCommands.Add("rdelay", "Set the delay of radar feature in milliseconds.", (string commmand, string[] args) =>
@@ -88,19 +88,19 @@ namespace stardew_access
                     {
                         MainClass.RadarFeature.delay = delay;
                         if (delay >= 1000)
-                            MainClass.DebugLog($"Delay set to {MainClass.RadarFeature.delay} milliseconds.");
+                            MainClass.InfoLog($"Delay set to {MainClass.RadarFeature.delay} milliseconds.");
                         else
-                            MainClass.DebugLog($"Delay should be atleast 1 second or 1000 millisecond long.");
+                            MainClass.InfoLog($"Delay should be atleast 1 second or 1000 millisecond long.");
                     }
                     else
                     {
-                        MainClass.DebugLog("Invalid delay amount, it can only be in numeric form.");
+                        MainClass.InfoLog("Invalid delay amount, it can only be in numeric form.");
                     }
 
                 }
                 else
                 {
-                    MainClass.DebugLog("Enter the delay amount (in milliseconds)!");
+                    MainClass.InfoLog("Enter the delay amount (in milliseconds)!");
                 }
 
             });
@@ -121,19 +121,19 @@ namespace stardew_access
                     {
                         MainClass.RadarFeature.range = range;
                         if (range >= 2 && range <= 10)
-                            MainClass.DebugLog($"Range set to {MainClass.RadarFeature.range}.");
+                            MainClass.InfoLog($"Range set to {MainClass.RadarFeature.range}.");
                         else
-                            MainClass.DebugLog($"Range should be atleast 2 and maximum 10.");
+                            MainClass.InfoLog($"Range should be atleast 2 and maximum 10.");
                     }
                     else
                     {
-                        MainClass.DebugLog("Invalid range amount, it can only be in numeric form.");
+                        MainClass.InfoLog("Invalid range amount, it can only be in numeric form.");
                     }
 
                 }
                 else
                 {
-                    MainClass.DebugLog("Enter the range amount!");
+                    MainClass.InfoLog("Enter the range amount!");
                 }
 
             });
@@ -152,16 +152,16 @@ namespace stardew_access
                         if (!MainClass.RadarFeature.exclusions.Contains(keyToAdd))
                         {
                             MainClass.RadarFeature.exclusions.Add(keyToAdd);
-                            MainClass.DebugLog($"Added {keyToAdd} key to exclusions list.");
+                            MainClass.InfoLog($"Added {keyToAdd} key to exclusions list.");
                         }
                         else
                         {
-                            MainClass.DebugLog($"{keyToAdd} key already present in the list.");
+                            MainClass.InfoLog($"{keyToAdd} key already present in the list.");
                         }
                     }
                     else
                     {
-                        MainClass.DebugLog("Unable to add the key to exclusions list.");
+                        MainClass.InfoLog("Unable to add the key to exclusions list.");
                     }
                 });
 
@@ -177,16 +177,16 @@ namespace stardew_access
                     if (MainClass.RadarFeature.exclusions.Contains(keyToAdd))
                     {
                         MainClass.RadarFeature.exclusions.Remove(keyToAdd);
-                        MainClass.DebugLog($"Removed {keyToAdd} key from exclusions list.");
+                        MainClass.InfoLog($"Removed {keyToAdd} key from exclusions list.");
                     }
                     else
                     {
-                        MainClass.DebugLog($"Cannot find {keyToAdd} key in exclusions list.");
+                        MainClass.InfoLog($"Cannot find {keyToAdd} key in exclusions list.");
                     }
                 }
                 else
                 {
-                    MainClass.DebugLog("Unable to remove the key from exclusions list.");
+                    MainClass.InfoLog("Unable to remove the key from exclusions list.");
                 }
             });
 
@@ -199,23 +199,23 @@ namespace stardew_access
                     {
                         toPrint = $"{toPrint}\t{i + 1}: {MainClass.RadarFeature.exclusions[i]}";
                     }
-                    MainClass.DebugLog(toPrint);
+                    MainClass.InfoLog(toPrint);
                 }
                 else
                 {
-                    MainClass.DebugLog("No exclusions found.");
+                    MainClass.InfoLog("No exclusions found.");
                 }
             });
 
             helper.ConsoleCommands.Add("reclear", "Clear the focus exclusions in the radar featrure.", (string commmand, string[] args) =>
             {
                 MainClass.RadarFeature.exclusions.Clear();
-                MainClass.DebugLog($"Cleared the focus list in the exclusions feature.");
+                MainClass.InfoLog($"Cleared the focus list in the exclusions feature.");
             });
 
             helper.ConsoleCommands.Add("recount", "Number of exclusions in the radar feature.", (string commmand, string[] args) =>
             {
-                MainClass.DebugLog($"There are {MainClass.RadarFeature.exclusions.Count} exclusiond in the radar feature.");
+                MainClass.InfoLog($"There are {MainClass.RadarFeature.exclusions.Count} exclusiond in the radar feature.");
             });
             #endregion
 
@@ -232,16 +232,16 @@ namespace stardew_access
                         if (!MainClass.RadarFeature.focus.Contains(keyToAdd))
                         {
                             MainClass.RadarFeature.focus.Add(keyToAdd);
-                            MainClass.DebugLog($"Added {keyToAdd} key to focus list.");
+                            MainClass.InfoLog($"Added {keyToAdd} key to focus list.");
                         }
                         else
                         {
-                            MainClass.DebugLog($"{keyToAdd} key already present in the list.");
+                            MainClass.InfoLog($"{keyToAdd} key already present in the list.");
                         }
                     }
                     else
                     {
-                        MainClass.DebugLog("Unable to add the key to focus list.");
+                        MainClass.InfoLog("Unable to add the key to focus list.");
                     }
                 });
 
@@ -257,16 +257,16 @@ namespace stardew_access
                     if (MainClass.RadarFeature.focus.Contains(keyToAdd))
                     {
                         MainClass.RadarFeature.focus.Remove(keyToAdd);
-                        MainClass.DebugLog($"Removed {keyToAdd} key from focus list.");
+                        MainClass.InfoLog($"Removed {keyToAdd} key from focus list.");
                     }
                     else
                     {
-                        MainClass.DebugLog($"Cannot find {keyToAdd} key in focus list.");
+                        MainClass.InfoLog($"Cannot find {keyToAdd} key in focus list.");
                     }
                 }
                 else
                 {
-                    MainClass.DebugLog("Unable to remove the key from focus list.");
+                    MainClass.InfoLog("Unable to remove the key from focus list.");
                 }
             });
 
@@ -279,23 +279,23 @@ namespace stardew_access
                     {
                         toPrint = $"{toPrint}\t{i + 1}): {MainClass.RadarFeature.focus[i]}";
                     }
-                    MainClass.DebugLog(toPrint);
+                    MainClass.InfoLog(toPrint);
                 }
                 else
                 {
-                    MainClass.DebugLog("No objects found in the focus list.");
+                    MainClass.InfoLog("No objects found in the focus list.");
                 }
             });
 
             helper.ConsoleCommands.Add("rfclear", "Clear the focus list in the radar featrure.", (string commmand, string[] args) =>
             {
                 MainClass.RadarFeature.focus.Clear();
-                MainClass.DebugLog($"Cleared the focus list in the radar feature.");
+                MainClass.InfoLog($"Cleared the focus list in the radar feature.");
             });
 
             helper.ConsoleCommands.Add("rfcount", "Number of list in the radar feature.", (string commmand, string[] args) =>
             {
-                MainClass.DebugLog($"There are {MainClass.RadarFeature.focus.Count} objects in the focus list in the radar feature.");
+                MainClass.InfoLog($"There are {MainClass.RadarFeature.focus.Count} objects in the focus list in the radar feature.");
             });
             #endregion
 
@@ -306,14 +306,14 @@ namespace stardew_access
             {
                 if (Game1.currentLocation is not Farm)
                 {
-                    MainClass.DebugLog("Can only use this command in the farm");
+                    MainClass.InfoLog("Can only use this command in the farm");
                     return;
                 }
 
                 string? indexInString = args.ElementAtOrDefault(0);
                 if (indexInString == null)
                 {
-                    MainClass.DebugLog("Enter the index too!");
+                    MainClass.InfoLog("Enter the index too!");
                     return;
                 }
 
@@ -322,12 +322,12 @@ namespace stardew_access
 
                 if (!isParsable || !(index >= 0 && index <= 9))
                 {
-                    MainClass.DebugLog("Index can only be a number and from 0 to 9 only");
+                    MainClass.InfoLog("Index can only be a number and from 0 to 9 only");
                     return;
                 }
 
                 BuildingNAnimalMenuPatches.marked[index] = new Vector2((int)Game1.player.getTileX(), (int)Game1.player.getTileY());
-                MainClass.DebugLog($"Location {(int)Game1.player.getTileX()}x {(int)Game1.player.getTileY()}y added at {index} index.");
+                MainClass.InfoLog($"Location {(int)Game1.player.getTileX()}x {(int)Game1.player.getTileY()}y added at {index} index.");
             });
 
             helper.ConsoleCommands.Add("marklist", "List all marked positions.", (string commmand, string[] args) =>
@@ -342,16 +342,16 @@ namespace stardew_access
                 }
 
                 if (toPrint == "")
-                    MainClass.DebugLog("No positions marked!");
+                    MainClass.InfoLog("No positions marked!");
                 else
-                    MainClass.DebugLog($"Marked positions:{toPrint}\nOpen command menu and use pageup and pagedown to check the list");
+                    MainClass.InfoLog($"Marked positions:{toPrint}\nOpen command menu and use pageup and pagedown to check the list");
             });
 
             helper.ConsoleCommands.Add("buildlist", "List all buildings for selection for upgrading/demolishing/painting", (string commmand, string[] args) =>
             {
                 if ((Game1.activeClickableMenu is not CarpenterMenu && Game1.activeClickableMenu is not PurchaseAnimalsMenu && Game1.activeClickableMenu is not AnimalQueryMenu) || !BuildingNAnimalMenuPatches.isOnFarm)
                 {
-                    MainClass.DebugLog($"Cannot list buildings.");
+                    MainClass.InfoLog($"Cannot list buildings.");
                     return;
                 }
 
@@ -372,11 +372,11 @@ namespace stardew_access
 
                 if (toPrint == "")
                 {
-                    MainClass.DebugLog("No appropriate buildings to list");
+                    MainClass.InfoLog("No appropriate buildings to list");
                 }
                 else
                 {
-                    MainClass.DebugLog($"Available buildings:{toPrint}\nOpen command menu and use pageup and pagedown to check the list");
+                    MainClass.InfoLog($"Available buildings:{toPrint}\nOpen command menu and use pageup and pagedown to check the list");
                 }
             });
 
@@ -384,14 +384,14 @@ namespace stardew_access
             {
                 if ((Game1.activeClickableMenu is not CarpenterMenu && Game1.activeClickableMenu is not PurchaseAnimalsMenu && Game1.activeClickableMenu is not AnimalQueryMenu) || !BuildingNAnimalMenuPatches.isOnFarm)
                 {
-                    MainClass.DebugLog($"Cannot select building.");
+                    MainClass.InfoLog($"Cannot select building.");
                     return;
                 }
 
                 string? indexInString = args.ElementAtOrDefault(0);
                 if (indexInString == null)
                 {
-                    MainClass.DebugLog("Enter the index of the building too! Use buildlist");
+                    MainClass.InfoLog("Enter the index of the building too! Use buildlist");
                     return;
                 }
 
@@ -400,7 +400,7 @@ namespace stardew_access
 
                 if (!isParsable)
                 {
-                    MainClass.DebugLog("Index can only be a number.");
+                    MainClass.InfoLog("Index can only be a number.");
                     return;
                 }
 
@@ -414,13 +414,13 @@ namespace stardew_access
                     {
                         if (BuildingNAnimalMenuPatches.availableBuildings[index] == null)
                         {
-                            MainClass.DebugLog($"No building found with index {index}. Use buildlist.");
+                            MainClass.InfoLog($"No building found with index {index}. Use buildlist.");
                             return;
                         }
 
                         if (positionIndexInString == null)
                         {
-                            MainClass.DebugLog("Enter the index of marked place too! Use marklist.");
+                            MainClass.InfoLog("Enter the index of marked place too! Use marklist.");
                             return;
                         }
 
@@ -428,7 +428,7 @@ namespace stardew_access
 
                         if (!isParsable)
                         {
-                            MainClass.DebugLog("Index can only be a number.");
+                            MainClass.InfoLog("Index can only be a number.");
                             return;
                         }
                     }
@@ -437,7 +437,7 @@ namespace stardew_access
                 {
                     if (BuildingNAnimalMenuPatches.marked[index] == Vector2.Zero)
                     {
-                        MainClass.DebugLog($"No marked position found at {index} index.");
+                        MainClass.InfoLog($"No marked position found at {index} index.");
                         return;
                     }
                 }
@@ -445,7 +445,7 @@ namespace stardew_access
                 {
                     if (BuildingNAnimalMenuPatches.availableBuildings[index] == null)
                     {
-                        MainClass.DebugLog($"No building found with index {index}. Use buildlist.");
+                        MainClass.InfoLog($"No building found with index {index}. Use buildlist.");
                         return;
                     }
                 }
@@ -471,7 +471,7 @@ namespace stardew_access
 
                 if (response != null)
                 {
-                    MainClass.DebugLog(response);
+                    MainClass.InfoLog(response);
                 }
             });
             #endregion
@@ -481,21 +481,21 @@ namespace stardew_access
                         {
                             MainClass.ScreenReader.InitializeScreenReader();
 
-                            MainClass.DebugLog("Screen Reader refreshed!");
+                            MainClass.InfoLog("Screen Reader refreshed!");
                         });
 
             helper.ConsoleCommands.Add("refmc", "Refresh mod config", (string commmand, string[] args) =>
             {
                 MainClass.Config = helper.ReadConfig<ModConfig>();
 
-                MainClass.DebugLog("Mod Config refreshed!");
+                MainClass.InfoLog("Mod Config refreshed!");
             });
 
             helper.ConsoleCommands.Add("refst", "Refresh static tiles", (string commmand, string[] args) =>
             {
                 MainClass.STiles = new Features.StaticTiles();
 
-                MainClass.DebugLog("Static tiles refreshed!");
+                MainClass.InfoLog("Static tiles refreshed!");
             });
 
             helper.ConsoleCommands.Add("hnspercent", "Toggle between speaking in percentage or full health and stamina.", (string commmand, string[] args) =>
@@ -503,7 +503,7 @@ namespace stardew_access
                 MainClass.Config.HealthNStaminaInPercentage = !MainClass.Config.HealthNStaminaInPercentage;
                 helper.WriteConfig(MainClass.Config);
 
-                MainClass.DebugLog("Speaking in percentage is " + (MainClass.Config.HealthNStaminaInPercentage ? "on" : "off"));
+                MainClass.InfoLog("Speaking in percentage is " + (MainClass.Config.HealthNStaminaInPercentage ? "on" : "off"));
             });
 
             helper.ConsoleCommands.Add("snapmouse", "Toggle snap mouse feature.", (string commmand, string[] args) =>
@@ -511,7 +511,7 @@ namespace stardew_access
                 MainClass.Config.SnapMouse = !MainClass.Config.SnapMouse;
                 helper.WriteConfig(MainClass.Config);
 
-                MainClass.DebugLog("Snap Mouse is " + (MainClass.Config.SnapMouse ? "on" : "off"));
+                MainClass.InfoLog("Snap Mouse is " + (MainClass.Config.SnapMouse ? "on" : "off"));
             });
 
             helper.ConsoleCommands.Add("warning", "Toggle warnings feature.", (string commmand, string[] args) =>
@@ -519,7 +519,7 @@ namespace stardew_access
                 MainClass.Config.Warning = !MainClass.Config.Warning;
                 helper.WriteConfig(MainClass.Config);
 
-                MainClass.DebugLog("Warnings is " + (MainClass.Config.Warning ? "on" : "off"));
+                MainClass.InfoLog("Warnings is " + (MainClass.Config.Warning ? "on" : "off"));
             });
 
             helper.ConsoleCommands.Add("tts", "Toggles the screen reader/tts", (string commmand, string[] args) =>
@@ -527,7 +527,7 @@ namespace stardew_access
                 MainClass.Config.TTS = !MainClass.Config.TTS;
                 helper.WriteConfig(MainClass.Config);
 
-                MainClass.DebugLog("TTS is " + (MainClass.Config.TTS ? "on" : "off"));
+                MainClass.InfoLog("TTS is " + (MainClass.Config.TTS ? "on" : "off"));
             });
             #endregion
         }
diff --git a/stardew-access/ModEntry.cs b/stardew-access/ModEntry.cs
index 03cdc36..05858f1 100644
--- a/stardew-access/ModEntry.cs
+++ b/stardew-access/ModEntry.cs
@@ -114,6 +114,7 @@ namespace stardew_access
             Game1.options.setGamepadMode("force_on");
 
             ScreenReader = new ScreenReaderController().Initialize();
+            ScreenReader.Say("Initializing Stardew Access", true);
 
             CustomSoundEffects.Initialize();
 
@@ -346,6 +347,14 @@ namespace stardew_access
             monitor.Log(message, LogLevel.Error);
         }
 
+        public static void InfoLog(string message)
+        {
+            if (monitor == null)
+                return;
+
+            monitor.Log(message, LogLevel.Info);
+        }
+
         public static void DebugLog(string message)
         {
             if (monitor == null)
diff --git a/stardew-access/ScreenReader/ScreenReaderLinux.cs b/stardew-access/ScreenReader/ScreenReaderLinux.cs
index 7e58c69..03f5afd 100644
--- a/stardew-access/ScreenReader/ScreenReaderLinux.cs
+++ b/stardew-access/ScreenReader/ScreenReaderLinux.cs
@@ -41,10 +41,16 @@ namespace stardew_access.ScreenReader
 
         public void InitializeScreenReader()
         {
+            MainClass.InfoLog("Initializing speech dispatcher...");
             int res = Initialize();
             if (res == 1)
             {
                 initialized = true;
+                MainClass.InfoLog("Successfully initialized.");
+            }
+            else
+            {
+                MainClass.ErrorLog("Unable to initialize.");
             }
         }
 
@@ -71,7 +77,16 @@ namespace stardew_access.ScreenReader
             if (text.Contains('^')) text = text.Replace('^', '\n');
 
             GoString str = new GoString(text, text.Length);
-            Speak(str, interrupt);
+            int re = Speak(str, interrupt);
+
+            if (re == 1)
+            {
+                MainClass.DebugLog($"Speaking(interrupt: {interrupt}) = {text}");
+            }
+            else
+            {
+                MainClass.ErrorLog($"Failed to output text: {text}");
+            }
         }
 
         public void SayWithChecker(string text, bool interrupt)
diff --git a/stardew-access/ScreenReader/ScreenReaderWindows.cs b/stardew-access/ScreenReader/ScreenReaderWindows.cs
index f2da4b5..e4075b5 100644
--- a/stardew-access/ScreenReader/ScreenReaderWindows.cs
+++ b/stardew-access/ScreenReader/ScreenReaderWindows.cs
@@ -1,10 +1,10 @@
-using AccessibleOutput;
+using DavyKager;
 
 namespace stardew_access.ScreenReader
 {
     public class ScreenReaderWindows : IScreenReader
     {
-        public IAccessibleOutput? screenReader = null;
+        private bool isLoaded = false;
         public string prevText = "", prevTextTile = " ", prevChatText = "", prevMenuText = "";
 
         public string PrevTextTile
@@ -15,43 +15,30 @@ namespace stardew_access.ScreenReader
 
         public void InitializeScreenReader()
         {
+            MainClass.InfoLog("Initializing Tolk...");
+            Tolk.Load();
 
-            NvdaOutput? nvdaOutput = null;
-            JawsOutput? jawsOutput = null;
-            SapiOutput? sapiOutput = null;
-
-            // Initialize NVDA
-            try
+            MainClass.InfoLog("Querying for the active screen reader driver...");
+            string name = Tolk.DetectScreenReader();
+            if (name != null)
             {
-                nvdaOutput = new NvdaOutput();
+                MainClass.InfoLog($"The active screen reader driver is: {name}");
+                isLoaded = true;
             }
-            catch (Exception) { }
-
-            // Initialize JAWS
-            try
+            else
             {
-                jawsOutput = new JawsOutput();
+                MainClass.ErrorLog("None of the supported screen readers is running");
+                isLoaded = false;
             }
-            catch (Exception) { }
-
-            // Initialize SAPI
-            try
-            {
-                sapiOutput = new SapiOutput();
-            }
-            catch (Exception) { }
-
-            if (nvdaOutput != null && nvdaOutput.IsAvailable())
-                screenReader = nvdaOutput;
-            else if (jawsOutput != null && jawsOutput.IsAvailable())
-                screenReader = jawsOutput;
-            else if (sapiOutput != null && sapiOutput.IsAvailable())
-                screenReader = sapiOutput;
         }
 
         public void CloseScreenReader()
         {
-
+            if (isLoaded)
+            {
+                Tolk.Unload();
+                isLoaded = false;
+            }
         }
 
         public void Say(string text, bool interrupt)
@@ -59,7 +46,7 @@ namespace stardew_access.ScreenReader
             if (text == null)
                 return;
 
-            if (screenReader == null)
+            if (!isLoaded)
                 return;
 
             if (!MainClass.Config.TTS)
@@ -67,7 +54,14 @@ namespace stardew_access.ScreenReader
 
             if (text.Contains('^')) text = text.Replace('^', '\n');
 
-            screenReader.Speak(text, interrupt);
+            if (Tolk.Output("Hello, World!"))
+            {
+                MainClass.DebugLog($"Speaking(interrupt: {interrupt}) = {text}");
+            }
+            else
+            {
+                MainClass.ErrorLog($"Failed to output text: {text}");
+            }
         }
 
         public void SayWithChecker(string text, bool interrupt)
diff --git a/stardew-access/stardew-access.csproj b/stardew-access/stardew-access.csproj
index b3ab566..719f9a1 100644
--- a/stardew-access/stardew-access.csproj
+++ b/stardew-access/stardew-access.csproj
@@ -12,9 +12,9 @@
   </PropertyGroup>
 
   <ItemGroup>
-    <PackageReference Include="AccessibleOutput" Version="1.0.0" />
     <PackageReference Include="Lib.Harmony" Version="2.2.0" />
     <PackageReference Include="Pathoschild.Stardew.ModBuildConfig" Version="4.0.0" />
+    <Reference Include="./TolkDotNet.dll" />
   </ItemGroup>
 
 </Project>