diff --git a/stardew-access/ModEntry.cs b/stardew-access/ModEntry.cs index b66f4d0..6de2c27 100644 --- a/stardew-access/ModEntry.cs +++ b/stardew-access/ModEntry.cs @@ -6,6 +6,7 @@ using HarmonyLib; using StardewValley.Menus; using Microsoft.Xna.Framework.Graphics; using stardew_access.Patches; +using AutoHotkey.Interop; namespace stardew_access { @@ -14,6 +15,7 @@ namespace stardew_access { private Harmony? harmony; public static IMonitor? monitor; + AutoHotkeyEngine ahk; /********* ** Public methods @@ -23,12 +25,27 @@ namespace stardew_access public override void Entry(IModHelper helper) { #region Initializations - // Inititalize monitor - monitor = Monitor; - // Initialize the screen reader - ScreenReader.initializeScreenReader(); - // Init harmony - harmony = new Harmony(ModManifest.UniqueID); + + monitor = Monitor; // Inititalize monitor + Game1.options.setGamepadMode("force_on"); + + // Initialize AutoHotKey + try + { + ahk = AutoHotkeyEngine.Instance; + ahk.ExecRaw("^j::\nSend {LButton}"); + ahk.ExecRaw("^l::\nSend {RButton}"); + } + catch (Exception e) + { + + monitor.Log($"Unable to initialize AutoHotKey:\n{e.Message}\n{e.StackTrace}", LogLevel.Error); + } + + ScreenReader.initializeScreenReader(); // Initialize the screen reader + + harmony = new Harmony(ModManifest.UniqueID); // Init harmony + #endregion #region Harmony Patches @@ -63,6 +80,11 @@ namespace stardew_access postfix: new HarmonyMethod(typeof(MenuPatch), nameof(MenuPatch.ExitPagePatch)) ); + harmony.Patch( + original: AccessTools.Method(typeof(CharacterCustomization), nameof(CharacterCustomization.draw), new Type[] { typeof(SpriteBatch) }), + postfix: new HarmonyMethod(typeof(MenuPatch), nameof(MenuPatch.NewGameMenuPatch)) + ); + #endregion helper.Events.Input.ButtonPressed += this.OnButtonPressed; @@ -70,22 +92,31 @@ namespace stardew_access private void OnButtonPressed(object sender, ButtonPressedEventArgs e) { - // ignore if player hasn't loaded a save yet - if (!Context.IsWorldReady) - return; - - // Narrate Health And Energy - if (Equals(e.Button, SButton.I)) + if (Game1.activeClickableMenu == null) { - string toSpeak = $"Health is {CurrentPlayer.getHealth()} and Stamina is {CurrentPlayer.getStamina()}"; - ScreenReader.say(toSpeak, true); - } + // Narrate health and stamina + if (Equals(e.Button, SButton.H)) + { + string toSpeak = $"Health is {CurrentPlayer.getHealth()} and Stamina is {CurrentPlayer.getStamina()}"; + ScreenReader.say(toSpeak, true); + } - // Narrate Position - if (Equals(e.Button, SButton.K)) - { - string toSpeak = $"X: {CurrentPlayer.getPositionX()} , Y: {CurrentPlayer.getPositionX()}"; - ScreenReader.say(toSpeak, true); + // Narrate Position + if (Equals(e.Button, SButton.K)) + { + string toSpeak = $"X: {CurrentPlayer.getPositionX()} , Y: {CurrentPlayer.getPositionX()}"; + ScreenReader.say(toSpeak, true); + } + + if (Equals(e.Button, SButton.J)) + { + Game1.pressActionButton(Game1.input.GetKeyboardState(), Game1.input.GetMouseState(), Game1.input.GetGamePadState()); + } + + if (Equals(e.Button, SButton.L)) + { + Game1.pressUseToolButton(); + } } } diff --git a/stardew-access/Patches/DialoguePatcher.cs b/stardew-access/Patches/DialoguePatcher.cs index 4413270..572ec77 100644 --- a/stardew-access/Patches/DialoguePatcher.cs +++ b/stardew-access/Patches/DialoguePatcher.cs @@ -24,7 +24,6 @@ namespace stardew_access.Patches string speakerName = dialogue.speaker.Name; List dialogues = dialogue.dialogues; int dialogueIndex = dialogue.currentDialogueIndex; - MainClass.monitor.Log("" + dialogue.isCurrentStringContinuedOnNextScreen, LogLevel.Debug); string toSpeak = $"{speakerName} said, {dialogues[dialogueIndex]}"; if (currentDialogue != toSpeak) @@ -138,7 +137,6 @@ namespace stardew_access.Patches try { int count = int.Parse(buffName.Substring(0, buffName.IndexOf(' '))); - MainClass.monitor.Log("" + count); if (count != 0) toSpeak.Append($"{buffName}\n"); } diff --git a/stardew-access/Patches/MenuPatch.cs b/stardew-access/Patches/MenuPatch.cs index 2593a4e..3ba5957 100644 --- a/stardew-access/Patches/MenuPatch.cs +++ b/stardew-access/Patches/MenuPatch.cs @@ -1,4 +1,5 @@ -using StardewModdingAPI; +using Microsoft.Xna.Framework; +using StardewModdingAPI; using StardewValley; using StardewValley.Menus; @@ -6,6 +7,8 @@ namespace stardew_access.Patches { internal class MenuPatch { + private static int saveGameIndex = -1; + private static bool isRunning = false; internal static void TitleMenuPatch(TitleMenu __instance) { @@ -93,6 +96,95 @@ namespace stardew_access.Patches } } + internal static void NewGameMenuPatch(CharacterCustomization __instance, TextBox ___nameBox, TextBox ___farmnameBox, TextBox ___favThingBox, ClickableTextureComponent ___skipIntroButton, ClickableTextureComponent ___okButton, ClickableComponent ___backButton) + { + try + { + if (__instance.source != CharacterCustomization.Source.NewGame) + return; + + + bool isNextArrowPressed = Game1.input.GetKeyboardState().IsKeyDown(Microsoft.Xna.Framework.Input.Keys.Right); + bool isPrevArrowPressed = Game1.input.GetKeyboardState().IsKeyDown(Microsoft.Xna.Framework.Input.Keys.Left); + if (isNextArrowPressed && !isRunning) + { + _ = CycleThroughItems(true, ___nameBox, ___farmnameBox, ___favThingBox, ___skipIntroButton, ___okButton, ___backButton); + } + else if (isPrevArrowPressed && !isRunning) + { + _ = CycleThroughItems(false, ___nameBox, ___farmnameBox, ___favThingBox, ___skipIntroButton, ___okButton, ___backButton); + } + } + catch (Exception e) + { + MainClass.monitor.Log($"Unable to narrate Text:\n{e.Message}\n{e.StackTrace}", LogLevel.Error); + } + } + + private static async Task CycleThroughItems(bool increase, TextBox ___nameBox, TextBox ___farmnameBox, TextBox ___favThingBox, ClickableTextureComponent ___skipIntroButton, ClickableTextureComponent ___okButton, ClickableComponent ___backButton) + { + isRunning = true; + if (increase) + { + saveGameIndex++; + if (saveGameIndex > 6) + saveGameIndex = 0; + } else + { + saveGameIndex--; + if (saveGameIndex < 0) + saveGameIndex = 6; + } + + await Task.Delay(200); + + switch (saveGameIndex) + { + case 0: + { + Rectangle bounds = new Rectangle(___nameBox.X, ___nameBox.Y, ___nameBox.Width, ___nameBox.Height); + Game1.input.SetMousePosition(bounds.Center.X, bounds.Center.Y); + ScreenReader.say("Enter Farmer's Name", true); + } + break; + + case 1: + { + Rectangle bounds = new Rectangle(___farmnameBox.X, ___farmnameBox.Y, ___farmnameBox.Width, ___farmnameBox.Height); + Game1.input.SetMousePosition(bounds.Center.X, bounds.Center.Y); + ScreenReader.say("Enter Farm's Name", true); + } + break; + case 3: + { + Rectangle bounds = new Rectangle(___favThingBox.X, ___favThingBox.Y, ___favThingBox.Width, ___favThingBox.Height); + Game1.input.SetMousePosition(bounds.Center.X, bounds.Center.Y); + ScreenReader.say("Enter Favourite Thing", true); + } + break; + case 4: + { + ___skipIntroButton.snapMouseCursor(); + ScreenReader.say("Skip Intro Button", true); + } + break; + case 5: + { + ___okButton.snapMouseCursor(); + ScreenReader.say("Ok Button", true); + } + break; + case 6: + { + ___backButton.snapMouseCursor(); + ScreenReader.say("Back Button", true); + } + break; + } + + isRunning = false; + } + internal static void ExitPagePatch(ExitPage __instance) { try diff --git a/stardew-access/manifest.json b/stardew-access/manifest.json index 4fd5751..ea63c2c 100644 --- a/stardew-access/manifest.json +++ b/stardew-access/manifest.json @@ -1,10 +1,12 @@ { "Name": "Stardew Access", "Author": "Mohammad Shoaib", - "Version": "1.0.0", - "Description": "", + "Version": "1.0.1-beta", + "Description": "An accessibility mod with screen reader support!", "UniqueID": "shoaib.stardewaccess", "EntryDll": "stardew-access.dll", "MinimumApiVersion": "3.0.0", - "UpdateKeys": [] + "UpdateKeys": [ + "Github:stardew-access/stardew-access" + ] } \ No newline at end of file diff --git a/stardew-access/stardew-access.csproj b/stardew-access/stardew-access.csproj index 210f6b7..b988097 100644 --- a/stardew-access/stardew-access.csproj +++ b/stardew-access/stardew-access.csproj @@ -11,6 +11,7 @@ +