aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAkshay Nair <phenax5@gmail.com>2024-12-28 14:13:47 +0530
committerAkshay Nair <phenax5@gmail.com>2024-12-28 14:15:10 +0530
commit9a5453aa190834b01e78cd971c445f1f0e34ee41 (patch)
treef1b3f99b34f3f508bb98ac527f7b5d51f2b69dcf
parentd6dbe32df6f1a01c95f9293023e2d73872fa39fe (diff)
downloadchelleport-9a5453aa190834b01e78cd971c445f1f0e34ee41.tar.gz
chelleport-9a5453aa190834b01e78cd971c445f1f0e34ee41.zip
Add update flushing to allow showing loading state after showing window
-rw-r--r--TODO.norg1
-rw-r--r--bin/Main.hs2
-rw-r--r--specs/Specs/AppStateSpec.hs95
-rw-r--r--src/Chelleport.hs1
-rw-r--r--src/Chelleport/AppShell.hs22
-rw-r--r--src/Chelleport/AppState.hs56
-rw-r--r--src/Chelleport/Types.hs3
-rw-r--r--src/Chelleport/View.hs5
8 files changed, 105 insertions, 80 deletions
diff --git a/TODO.norg b/TODO.norg
index 4254e49..c5902e6 100644
--- a/TODO.norg
+++ b/TODO.norg
@@ -2,6 +2,7 @@
- ( ) Sort ocr match result by position on screen (top to bottom, left to right)
- ( ) TextStyle for drawText
- ( ) Middle click
+ - ( ) Separate state for hint modes into ModeHint constructor
- (-) Optimize speed of ocr
* Later
diff --git a/bin/Main.hs b/bin/Main.hs
index 007fb5e..03c0904 100644
--- a/bin/Main.hs
+++ b/bin/Main.hs
@@ -1,8 +1,8 @@
module Main where
import qualified Chelleport
-import Chelleport.Args (Configuration (configShowHelp))
import qualified Chelleport.Args as Args
+import Chelleport.Types
import qualified System.Environment
import System.Exit (exitFailure)
diff --git a/specs/Specs/AppStateSpec.hs b/specs/Specs/AppStateSpec.hs
index 9864a0e..44da414 100644
--- a/specs/Specs/AppStateSpec.hs
+++ b/specs/Specs/AppStateSpec.hs
@@ -1,7 +1,6 @@
module Specs.AppStateSpec where
import Chelleport.AppState (initialState, update)
-import Chelleport.Args (Configuration (configMode))
import Chelleport.Types
import Chelleport.Utils (uniq)
import Control.Monad (join)
@@ -12,6 +11,7 @@ import TestUtils
test :: SpecWith ()
test = do
+ let flush = pure ()
describe "#initialState" $ do
let config = def
@@ -46,11 +46,11 @@ test = do
let currentState = defaultState {stateRepetition = 1}
it "hides window, triggers mouse click and shows the window again" $ do
- (_, mock) <- runWithMocks $ update currentState $ ChainMouseClick LeftClick
+ (_, mock) <- runWithMocks $ update flush currentState $ ChainMouseClick LeftClick
mock `shouldContainCalls` [Mock_hideWindow, Mock_clickMouseButton LeftClick, Mock_showWindow]
it "continues with action ResetKeys without updating state" $ do
- ((nextState, action), _) <- runWithMocks $ update currentState $ ChainMouseClick LeftClick
+ ((nextState, action), _) <- runWithMocks $ update flush currentState $ ChainMouseClick LeftClick
action `shouldBe` Just ResetKeys
nextState `shouldBe` currentState
@@ -58,11 +58,11 @@ test = do
let currentState = defaultState {stateRepetition = 3}
it "resets repetition back to 1" $ do
- ((nextState, _), _) <- runWithMocks $ update currentState $ ChainMouseClick LeftClick
+ ((nextState, _), _) <- runWithMocks $ update flush currentState $ ChainMouseClick LeftClick
nextState `shouldBe` currentState {stateRepetition = 1}
it "clicks multiple times" $ do
- (_, mock) <- runWithMocks $ update currentState $ ChainMouseClick LeftClick
+ (_, mock) <- runWithMocks $ update flush currentState $ ChainMouseClick LeftClick
mock
`shouldContainCalls` [ Mock_hideWindow,
Mock_clickMouseButton LeftClick,
@@ -84,11 +84,11 @@ test = do
it "continues with MoveMousePosition" $ do
((_, action), _) <- runWithMocks $ do
Mock_getMousePointerPosition `mockReturns` (42, 42)
- update currentState $ IncrementMouseCursor (10, -5)
+ update flush currentState $ IncrementMouseCursor (10, -5)
action `shouldBe` Just (MoveMousePosition (52, 37))
it "does update state" $ do
- ((state, _), _) <- runWithMocks $ update currentState $ IncrementMouseCursor (10, -5)
+ ((state, _), _) <- runWithMocks $ update flush currentState $ IncrementMouseCursor (10, -5)
state `shouldBe` currentState
context "when repetition is more than 1" $ do
@@ -97,29 +97,29 @@ test = do
it "multiplies increment" $ do
((_, action), _) <- runWithMocks $ do
Mock_getMousePointerPosition `mockReturns` (42, 42)
- update currentState $ IncrementMouseCursor (10, -5)
+ update flush currentState $ IncrementMouseCursor (10, -5)
action `shouldBe` Just (MoveMousePosition (92, 17))
context "with action MouseDragEnd" $ do
let currentState = defaultState
it "hides window, stops dragging and shows the window again" $ do
- (_, mock) <- runWithMocks $ update currentState MouseDragEnd
+ (_, mock) <- runWithMocks $ update flush currentState MouseDragEnd
mock `shouldContainCalls` [Mock_hideWindow, Mock_releaseMouseButton, Mock_showWindow]
it "does not continue or update state" $ do
- (result, _) <- runWithMocks $ update currentState MouseDragStart
+ (result, _) <- runWithMocks $ update flush currentState MouseDragStart
result `shouldBe` (currentState, Nothing)
context "with action MouseDragStart" $ do
let currentState = defaultState
it "hides window, starts dragging and shows the window again" $ do
- (_, mock) <- runWithMocks $ update currentState MouseDragStart
+ (_, mock) <- runWithMocks $ update flush currentState MouseDragStart
mock `shouldContainCalls` [Mock_hideWindow, Mock_pressMouseButton, Mock_showWindow]
it "does not continue or update state" $ do
- (result, _) <- runWithMocks $ update currentState MouseDragStart
+ (result, _) <- runWithMocks $ update flush currentState MouseDragStart
result `shouldBe` (currentState, Nothing)
context "with action MouseDragToggle" $ do
@@ -127,22 +127,22 @@ test = do
let currentState = defaultState {stateIsDragging = True}
it "toggles dragging state" $ do
- ((state, _), _) <- runWithMocks $ update currentState MouseDragToggle
+ ((state, _), _) <- runWithMocks $ update flush currentState MouseDragToggle
state `shouldBe` state {stateIsDragging = False}
it "continues with action MouseDragEnd" $ do
- ((_, action), _) <- runWithMocks $ update currentState MouseDragToggle
+ ((_, action), _) <- runWithMocks $ update flush currentState MouseDragToggle
action `shouldBe` Just MouseDragEnd
context "when is dragging is false" $ do
let currentState = defaultState {stateIsDragging = False}
it "toggles dragging state" $ do
- ((state, _), _) <- runWithMocks $ update currentState MouseDragToggle
+ ((state, _), _) <- runWithMocks $ update flush currentState MouseDragToggle
state `shouldBe` state {stateIsDragging = True}
it "continues with action MouseDragStart" $ do
- ((_, action), _) <- runWithMocks $ update currentState MouseDragToggle
+ ((_, action), _) <- runWithMocks $ update flush currentState MouseDragToggle
action `shouldBe` Just MouseDragStart
context "with action HandleKeyInput" $ do
@@ -156,13 +156,13 @@ test = do
context "when input key sequence has matching values in grid" $ do
it "does not update" $ do
- ((nextState, action), _) <- runWithMocks $ update currentState $ HandleKeyInput SDL.KeycodeZ
+ ((nextState, action), _) <- runWithMocks $ update flush currentState $ HandleKeyInput SDL.KeycodeZ
action `shouldBe` Nothing
nextState `shouldBe` currentState
context "when input key sequence does not have matching values in grid" $ do
it "adds key to key sequence" $ do
- ((nextState, action), _) <- runWithMocks $ update currentState $ HandleKeyInput SDL.KeycodeE
+ ((nextState, action), _) <- runWithMocks $ update flush currentState $ HandleKeyInput SDL.KeycodeE
action `shouldBe` Nothing
nextState `shouldBe` currentState {stateKeySequence = "DE"}
@@ -171,14 +171,14 @@ test = do
context "when input key sequence does not have matching values in grid" $ do
it "adds key to key sequence and enables isMatched" $ do
- ((nextState, _), _) <- runWithMocks $ update currentState $ HandleKeyInput SDL.KeycodeF
+ ((nextState, _), _) <- runWithMocks $ update flush currentState $ HandleKeyInput SDL.KeycodeF
nextState `shouldBe` currentState {stateKeySequence = "DEF", stateIsMatched = True}
it "continues with MoveMousePosition action at center of matched cell" $ do
((_, action), _) <- runWithMocks $ do
Mock_windowSize `mockReturns` mockWindowSize
Mock_windowPosition `mockReturns` mockWindowPosition
- update currentState $ HandleKeyInput SDL.KeycodeF
+ update flush currentState $ HandleKeyInput SDL.KeycodeF
action `shouldBe` Just (MoveMousePosition (1640, 370))
context "with action MoveMouseInDirection" $ do
@@ -188,64 +188,74 @@ test = do
it "continues to increment movement" $ do
((_, action), _) <- runWithMocks $ do
Mock_windowSize `mockReturns` mockWindowSize
- update currentState $ MoveMouseInDirection DirUp
+ update flush currentState $ MoveMouseInDirection DirUp
action `shouldBe` Just (IncrementMouseCursor (0, -33))
context "when direction is down" $ do
it "continues to increment movement" $ do
((_, action), _) <- runWithMocks $ do
Mock_windowSize `mockReturns` mockWindowSize
- update currentState $ MoveMouseInDirection DirDown
+ update flush currentState $ MoveMouseInDirection DirDown
action `shouldBe` Just (IncrementMouseCursor (0, 33))
context "when direction is left" $ do
it "continues to increment movement" $ do
((_, action), _) <- runWithMocks $ do
Mock_windowSize `mockReturns` mockWindowSize
- update currentState $ MoveMouseInDirection DirLeft
+ update flush currentState $ MoveMouseInDirection DirLeft
action `shouldBe` Just (IncrementMouseCursor (-60, 0))
context "when direction is right" $ do
it "continues to increment movement" $ do
((_, action), _) <- runWithMocks $ do
Mock_windowSize `mockReturns` mockWindowSize
- update currentState $ MoveMouseInDirection DirRight
+ update flush currentState $ MoveMouseInDirection DirRight
action `shouldBe` Just (IncrementMouseCursor (60, 0))
context "with action MoveMousePosition" $ do
let currentState = defaultState
it "moves mouse pointer to the given coordinates" $ do
- (_, mock) <- runWithMocks $ update currentState $ MoveMousePosition (23, 320)
+ (_, mock) <- runWithMocks $ update flush currentState $ MoveMousePosition (23, 320)
mock `shouldHaveCalled` Mock_moveMousePointer 23 320
it "does not continue or update state" $ do
- (result, _) <- runWithMocks $ update currentState $ MoveMousePosition (0, 0)
+ (result, _) <- runWithMocks $ update flush currentState $ MoveMousePosition (0, 0)
result `shouldBe` (currentState, Nothing)
context "with action ResetKeys" $ do
let currentState = defaultState {stateRepetition = 5}
it "resets state without any action" $ do
- ((nextState, action), _) <- runWithMocks $ update currentState ResetKeys
+ ((nextState, action), _) <- runWithMocks $ update flush currentState ResetKeys
action `shouldBe` Nothing
nextState `shouldBe` currentState {stateKeySequence = [], stateIsMatched = False, stateRepetition = 1}
context "with action SetMode" $ do
let currentState = defaultState
+ it "updates mode in state and continues to initialize mode" $ do
+ ((nextState, action), _) <- runWithMocks $ update flush currentState $ SetMode defaultHintsMode
+ nextState `shouldBe` currentState {stateMode = defaultHintsMode, stateIsModeInitialized = False}
+ action `shouldBe` Just InitializeMode
+
+ context "with action InitializeMode" $ do
context "when mode is ModeHints" $ do
- it "updates mode in state" $ do
- ((nextState, action), _) <- runWithMocks $ update currentState $ SetMode defaultHintsMode
- nextState `shouldBe` currentState {stateMode = defaultHintsMode}
+ let currentState = defaultState {stateMode = defaultHintsMode, stateIsModeInitialized = False}
+
+ it "updates initialization state to true" $ do
+ ((nextState, action), _) <- runWithMocks $ update flush currentState InitializeMode
+ nextState `shouldBe` currentState {stateIsModeInitialized = True}
action `shouldBe` Nothing
context "when mode is ModeSearch" $ do
+ let currentState = defaultState {stateMode = defaultSearchMode, stateIsModeInitialized = False}
+
it "captures screenshot for word search" $ do
((_, _), mock) <- runWithMocks $ do
Mock_windowSize `mockReturns` mockWindowSize
Mock_windowPosition `mockReturns` mockWindowPosition
- update currentState $ SetMode defaultSearchMode
+ update flush currentState InitializeMode
mock `shouldHaveCalled` Mock_captureScreenshot (mockWindowOffsetX, mockWindowOffsetY) (mockWindowWidth, mockWindowHeight)
it "updates mode in state with ocr words" $ do
@@ -255,10 +265,11 @@ test = do
Mock_windowPosition `mockReturns` mockWindowPosition
Mock_captureScreenshot mockWindowPosition mockWindowSize `mockReturns` "mock-filename"
Mock_getWordsInImage "mock-filename" `mockReturns` [matchWord]
- update currentState $ SetMode defaultSearchMode
+ update flush currentState InitializeMode
nextState
`shouldBe` currentState
- { stateMode =
+ { stateIsModeInitialized = True,
+ stateMode =
defaultSearchMode
{ searchWords = [matchWord],
searchFilteredWords = [matchWord]
@@ -269,11 +280,11 @@ test = do
let currentState = defaultState
it "shuts down app" $ do
- (_, mock) <- runWithMocks $ update currentState ShutdownApp
+ (_, mock) <- runWithMocks $ update flush currentState ShutdownApp
mock `shouldHaveCalled` Mock_shutdownApp
it "does not continue or update state" $ do
- (result, _) <- runWithMocks $ update currentState ShutdownApp
+ (result, _) <- runWithMocks $ update flush currentState ShutdownApp
result `shouldBe` (currentState, Nothing)
context "with action TriggerMouseClick" $ do
@@ -281,11 +292,11 @@ test = do
let currentState = defaultState {stateRepetition = 1}
it "hides window and triggers mouse click" $ do
- (_, mock) <- runWithMocks $ update currentState $ TriggerMouseClick LeftClick
+ (_, mock) <- runWithMocks $ update flush currentState $ TriggerMouseClick LeftClick
mock `shouldContainCalls` [Mock_hideWindow, Mock_clickMouseButton LeftClick]
it "continues with action ShutdownApp without updating state" $ do
- ((nextState, action), _) <- runWithMocks $ update currentState $ TriggerMouseClick LeftClick
+ ((nextState, action), _) <- runWithMocks $ update flush currentState $ TriggerMouseClick LeftClick
action `shouldBe` Just ShutdownApp
nextState `shouldBe` currentState
@@ -293,11 +304,11 @@ test = do
let currentState = defaultState {stateRepetition = 3}
it "resets repetition back to 1" $ do
- ((nextState, _), _) <- runWithMocks $ update currentState $ TriggerMouseClick LeftClick
+ ((nextState, _), _) <- runWithMocks $ update flush currentState $ TriggerMouseClick LeftClick
nextState `shouldBe` currentState {stateRepetition = 1}
it "clicks multiple times" $ do
- (_, mock) <- runWithMocks $ update currentState $ TriggerMouseClick LeftClick
+ (_, mock) <- runWithMocks $ update flush currentState $ TriggerMouseClick LeftClick
mock
`shouldContainCalls` [ Mock_hideWindow,
Mock_clickMouseButton LeftClick,
@@ -309,13 +320,13 @@ test = do
let currentState = defaultState
it "updates repetition without any action" $ do
- ((nextState, action), _) <- runWithMocks $ update currentState $ UpdateRepetition 7
+ ((nextState, action), _) <- runWithMocks $ update flush currentState $ UpdateRepetition 7
action `shouldBe` Nothing
nextState `shouldBe` currentState {stateRepetition = 7}
context "when count is 0" $ do
it "updates repetition to 1" $ do
- ((nextState, action), _) <- runWithMocks $ update currentState $ UpdateRepetition 0
+ ((nextState, action), _) <- runWithMocks $ update flush currentState $ UpdateRepetition 0
action `shouldBe` Nothing
nextState `shouldBe` currentState {stateRepetition = 1}
@@ -323,6 +334,6 @@ test = do
let currentState = defaultState
it "updates shift state without any action" $ do
- ((nextState, action), _) <- runWithMocks $ update currentState $ UpdateShiftState True
+ ((nextState, action), _) <- runWithMocks $ update flush currentState $ UpdateShiftState True
action `shouldBe` Nothing
nextState `shouldBe` currentState {stateIsShiftPressed = True}
diff --git a/src/Chelleport.hs b/src/Chelleport.hs
index 02977c9..029821e 100644
--- a/src/Chelleport.hs
+++ b/src/Chelleport.hs
@@ -2,7 +2,6 @@ module Chelleport where
import Chelleport.AppShell (setupAppShell)
import qualified Chelleport.AppState as AppState
-import Chelleport.Args (Configuration)
import Chelleport.Context (initializeContext)
import Chelleport.Control (anyAlphabetic, anyDigit, checkKey, ctrl, eventToKeycode, hjkl, hjklDirection, key, pressed, released, shift)
import Chelleport.KeySequence (keycodeToInt, toKeyChar)
diff --git a/src/Chelleport/AppShell.hs b/src/Chelleport/AppShell.hs
index d48e06b..06ffa1a 100644
--- a/src/Chelleport/AppShell.hs
+++ b/src/Chelleport/AppShell.hs
@@ -1,9 +1,8 @@
-module Chelleport.AppShell (setupAppShell, MonadAppShell (..)) where
+module Chelleport.AppShell where
import Chelleport.Config
import Chelleport.Control (MonadControl (releaseMouseButton))
import Chelleport.Types
-import Control.Monad (foldM)
import Control.Monad.IO.Class (MonadIO (liftIO))
import Control.Monad.RWS (MonadReader (ask), asks)
import qualified Graphics.X11 as X11
@@ -29,7 +28,9 @@ instance (MonadIO m) => MonadAppShell (AppM m) where
X11.closeDisplay $ ctxX11Display ctx
exitSuccess
-type Update m state appAction = state -> appAction -> m (state, Maybe appAction)
+type Flush m = m ()
+
+type Update m state appAction = Flush m -> state -> appAction -> m (state, Maybe appAction)
type EventHandler state appAction = state -> SDL.Event -> Maybe appAction
@@ -38,7 +39,7 @@ type View m state = state -> m ()
type Initializer m state appAction = m (state, Maybe appAction)
setupAppShell ::
- (MonadIO m) =>
+ (MonadIO m, Show state) =>
DrawContext ->
Initializer m state appAction ->
Update m state appAction ->
@@ -50,20 +51,21 @@ setupAppShell (DrawContext {ctxRenderer = renderer}) getInitState update eventHa
appLoop state
where
appLoop currentState = do
+ renderScreen currentState
+ newState <- SDL.waitEvent >>= evaluateEvent currentState
+ appLoop newState
+
+ renderScreen state = do
SDL.rendererDrawColor renderer $= colorBackground
SDL.clear renderer
- draw currentState
+ draw state
SDL.present renderer
- newState <- SDL.pollEvents >>= foldM evaluateEvent currentState
-
- appLoop newState
-
evaluateEvent state event =
maybe (pure state) (updateState state) (eventHandler state event)
updateState state action =
- update state action >>= evalUpdateResult
+ update (renderScreen state) state action >>= evalUpdateResult
evalUpdateResult (state, Nothing) = pure state
evalUpdateResult (state, Just action) = updateState state action
diff --git a/src/Chelleport/AppState.hs b/src/Chelleport/AppState.hs
index 168cacf..6c2de9c 100644
--- a/src/Chelleport/AppState.hs
+++ b/src/Chelleport/AppState.hs
@@ -1,7 +1,6 @@
module Chelleport.AppState (initialState, update) where
-import Chelleport.AppShell (MonadAppShell (hideWindow, showWindow, shutdownApp))
-import Chelleport.Args (Configuration (configMode))
+import Chelleport.AppShell (MonadAppShell (hideWindow, showWindow, shutdownApp), Update)
import Chelleport.Control (MonadControl (..), directionalIncrement, hjklDirection)
import Chelleport.Draw (MonadDraw (windowPosition, windowSize), pointerPositionIncrement, screenPositionFromCellPosition, wordPosition)
import Chelleport.KeySequence (findMatchPosition, generateGrid, nextChars, toKeyChar)
@@ -23,16 +22,16 @@ initialState config = do
columns = 16
hintKeys = ['A' .. 'Z']
-update :: (MonadAppShell m, MonadDraw m, MonadControl m, MonadOCR m) => State -> AppAction -> m (State, Maybe AppAction)
+update :: (MonadAppShell m, MonadDraw m, MonadControl m, MonadOCR m) => Update m State AppAction
-- Chain clicks
-update state (ChainMouseClick btn) = do
+update _ state (ChainMouseClick btn) = do
hideWindow
replicateM_ (stateRepetition state) $ clickMouseButton btn
showWindow
pure (state {stateRepetition = 1}, Just ResetKeys)
-- HINTS MODE: Act on key inputs
-update state@(State {stateMode = ModeHints}) (HandleKeyInput keycode) = do
+update _ state@(State {stateMode = ModeHints}) (HandleKeyInput keycode) = do
case (toKeyChar keycode, validNextKeys) of
(Just keyChar, Just validChars')
| stateIsMatched state && keyChar `elem` ("HJKL" :: String) -> do
@@ -48,7 +47,7 @@ update state@(State {stateMode = ModeHints}) (HandleKeyInput keycode) = do
validNextKeys = nextChars (stateKeySequence state) (stateGrid state)
-- SEARCH MODE: Act on key inputs
-update state@(State {stateMode = ModeSearch {searchWords, searchInputText}}) (HandleKeyInput keycode) = do
+update _ state@(State {stateMode = ModeSearch {searchWords, searchInputText}}) (HandleKeyInput keycode) = do
case toKeyChar keycode of
Just keyChar -> do
let searchText = searchInputText ++ [toLower keyChar]
@@ -72,7 +71,7 @@ update state@(State {stateMode = ModeSearch {searchWords, searchInputText}}) (Ha
| otherwise = Fuzzy.original <$> Fuzzy.filter text searchWords "" "" matchText False
-- Increment highlighted index for search mode
-update state (IncrementHighlightIndex n) = do
+update _ state (IncrementHighlightIndex n) = do
case stateMode state of
ModeSearch {} -> do
action <- traverse (fmap MoveMousePosition . wordPosition) highlightedWord
@@ -88,43 +87,43 @@ update state (IncrementHighlightIndex n) = do
_ -> pure (state, Nothing)
-- Move mouse incrementally
-update state (IncrementMouseCursor (incX, incY)) = do
+update _ state (IncrementMouseCursor (incX, incY)) = do
(curX, curY) <- getMousePointerPosition
let count = stateRepetition state
let pos = (cIntToInt curX + count * incX, cIntToInt curY + count * incY)
pure (state {stateRepetition = 1}, Just $ MoveMousePosition pos)
-- Mouse button release
-update state MouseDragEnd = do
+update _ state MouseDragEnd = do
hideWindow
releaseMouseButton
showWindow
pure (state {stateRepetition = 1}, Nothing)
-- Mouse button press
-update state MouseDragStart = do
+update _ state MouseDragStart = do
hideWindow
pressMouseButton
showWindow
pure (state {stateRepetition = 1}, Nothing)
-- Mouse dragging
-update state MouseDragToggle
+update _ state MouseDragToggle
| stateIsDragging state = pure (state {stateIsDragging = False}, Just MouseDragEnd)
| otherwise = do pure (state {stateIsDragging = True}, Just MouseDragStart)
-- Apply movement in given direction
-update state (MoveMouseInDirection direction) = do
+update _ state (MoveMouseInDirection direction) = do
incr <- pointerPositionIncrement state
pure (state, Just $ IncrementMouseCursor $ directionalIncrement incr direction)
-- Move mouse to given position
-update state (MoveMousePosition (x, y)) = do
+update _ state (MoveMousePosition (x, y)) = do
moveMousePointer (intToCInt x) (intToCInt y)
pure (state, Nothing)
-- Reset entered key sequence and state
-update state ResetKeys = do
+update _ state ResetKeys = do
pure
( state
{ stateKeySequence = [],
@@ -139,33 +138,40 @@ update state ResetKeys = do
resetMode (ModeSearch {searchWords}) =
defaultSearchMode {searchWords = searchWords, searchFilteredWords = searchWords}
--- Set mode
-update state (SetMode mode) = do
- case mode of
- ModeHints -> pure (state {stateMode = mode}, Nothing)
+-- Initialize current mode
+update flush state InitializeMode =
+ case stateMode state of
+ ModeHints -> pure (state {stateIsModeInitialized = True}, Nothing)
ModeSearch {} -> do
position <- windowPosition
size <- windowSize
- screenshot <- hideWindow >> captureScreenshot position size <* showWindow
+ hideWindow
+ screenshot <- captureScreenshot position size
+ showWindow
+ flush
matches <- getWordsInImage screenshot
- let updatedMode = mode {searchWords = matches, searchFilteredWords = matches}
- pure (state {stateMode = updatedMode}, Nothing)
+ let updatedMode = (stateMode state) {searchWords = matches, searchFilteredWords = matches}
+ pure (state {stateMode = updatedMode, stateIsModeInitialized = True}, Nothing)
+
+-- Set mode
+update _ state (SetMode mode) = do
+ pure (state {stateMode = mode, stateIsModeInitialized = False}, Just InitializeMode)
-- Cleanup everything and exit
-update state ShutdownApp = do
+update _ state ShutdownApp = do
shutdownApp
pure (state, Nothing)
-- Trigger click
-update state (TriggerMouseClick btn) = do
+update _ state (TriggerMouseClick btn) = do
hideWindow
replicateM_ (stateRepetition state) $ clickMouseButton btn
pure (state {stateRepetition = 1}, Just ShutdownApp)
-- Set repetition count
-update state (UpdateRepetition count) = do
+update _ state (UpdateRepetition count) = do
pure (state {stateRepetition = max 1 count}, Nothing)
-- Set/unset whether shift is pressed
-update state (UpdateShiftState shiftPressed) =
+update _ state (UpdateShiftState shiftPressed) =
pure (state {stateIsShiftPressed = shiftPressed}, Nothing)
diff --git a/src/Chelleport/Types.hs b/src/Chelleport/Types.hs
index ae05dad..cc1a4c3 100644
--- a/src/Chelleport/Types.hs
+++ b/src/Chelleport/Types.hs
@@ -47,6 +47,7 @@ data State = State
stateIsShiftPressed :: Bool,
stateIsDragging :: Bool,
stateRepetition :: Int,
+ stateIsModeInitialized :: Bool,
stateMode :: Mode
}
deriving (Show, Eq)
@@ -60,6 +61,7 @@ defaultAppState =
stateIsShiftPressed = False,
stateIsDragging = False,
stateRepetition = 1,
+ stateIsModeInitialized = False,
stateMode = ModeHints
}
@@ -71,6 +73,7 @@ data AppAction
| HandleKeyInput SDL.Keycode
| IncrementHighlightIndex Int
| IncrementMouseCursor (Int, Int)
+ | InitializeMode
| MouseDragEnd
| MouseDragStart
| MouseDragToggle
diff --git a/src/Chelleport/View.hs b/src/Chelleport/View.hs
index 202c636..790b3f7 100644
--- a/src/Chelleport/View.hs
+++ b/src/Chelleport/View.hs
@@ -19,8 +19,11 @@ getSearchText :: State -> String
getSearchText state = case stateMode state of
ModeHints -> ""
ModeSearch {searchInputText, searchFilteredWords, searchHighlightedIndex} ->
- "Searching (" ++ matchCount ++ "): " ++ searchInputText
+ searchText
where
+ searchText
+ | stateIsModeInitialized state = "Searching (" ++ matchCount ++ "): " ++ searchInputText
+ | otherwise = "Loading..."
matchCount
| isEmpty searchFilteredWords = "0/0"
| otherwise = show (searchHighlightedIndex + 1) ++ "/" ++ show (length searchFilteredWords)