packages feed

mischief-input-0.1.0.0: src/Mischief/Input/Keys.hs

{-# OPTIONS_GHC -Wno-missing-pattern-synonym-signatures #-}

module Mischief.Input.Keys
  ( -- * Resource
    Keys,

    -- * Functions
    pressed,
    released,
    justPressed,
    justReleased,

    -- * Plugin
    KeysPlugin,

    -- * Keys
    -- $keys
    pattern Mischief.Input.Keys.A,
    pattern Mischief.Input.Keys.B,
    pattern Mischief.Input.Keys.C,
    pattern Mischief.Input.Keys.D,
    pattern Mischief.Input.Keys.E,
    pattern Mischief.Input.Keys.F,
    pattern Mischief.Input.Keys.G,
    pattern Mischief.Input.Keys.H,
    pattern Mischief.Input.Keys.I,
    pattern Mischief.Input.Keys.J,
    pattern Mischief.Input.Keys.K,
    pattern Mischief.Input.Keys.L,
    pattern Mischief.Input.Keys.M,
    pattern Mischief.Input.Keys.N,
    pattern Mischief.Input.Keys.O,
    pattern Mischief.Input.Keys.P,
    pattern Mischief.Input.Keys.Q,
    pattern Mischief.Input.Keys.R,
    pattern Mischief.Input.Keys.S,
    pattern Mischief.Input.Keys.T,
    pattern Mischief.Input.Keys.U,
    pattern Mischief.Input.Keys.V,
    pattern Mischief.Input.Keys.W,
    pattern Mischief.Input.Keys.X,
    pattern Mischief.Input.Keys.Y,
    pattern Mischief.Input.Keys.Z,
    pattern Mischief.Input.Keys.Key0,
    pattern Mischief.Input.Keys.Key1,
    pattern Mischief.Input.Keys.Key2,
    pattern Mischief.Input.Keys.Key3,
    pattern Mischief.Input.Keys.Key4,
    pattern Mischief.Input.Keys.Key5,
    pattern Mischief.Input.Keys.Key6,
    pattern Mischief.Input.Keys.Key7,
    pattern Mischief.Input.Keys.Key8,
    pattern Mischief.Input.Keys.Key9,
    pattern Mischief.Input.Keys.Enter,
    pattern Mischief.Input.Keys.Escape,
    pattern Mischief.Input.Keys.Backspace,
    pattern Mischief.Input.Keys.Tab,
    pattern Mischief.Input.Keys.Space,
    pattern Mischief.Input.Keys.Minus,
    pattern Mischief.Input.Keys.Equals,
    pattern Mischief.Input.Keys.LeftBracket,
    pattern Mischief.Input.Keys.RightBracket,
    pattern Mischief.Input.Keys.BackSlash,
    pattern Mischief.Input.Keys.Semicolon,
    pattern Mischief.Input.Keys.Apostrophe,
    pattern Mischief.Input.Keys.Grave,
    pattern Mischief.Input.Keys.Comma,
    pattern Mischief.Input.Keys.Period,
    pattern Mischief.Input.Keys.Slash,
    pattern Mischief.Input.Keys.Capslock,
    pattern Mischief.Input.Keys.F1,
    pattern Mischief.Input.Keys.F2,
    pattern Mischief.Input.Keys.F3,
    pattern Mischief.Input.Keys.F4,
    pattern Mischief.Input.Keys.F5,
    pattern Mischief.Input.Keys.F6,
    pattern Mischief.Input.Keys.F7,
    pattern Mischief.Input.Keys.F8,
    pattern Mischief.Input.Keys.F9,
    pattern Mischief.Input.Keys.F10,
    pattern Mischief.Input.Keys.F11,
    pattern Mischief.Input.Keys.F12,
    pattern Mischief.Input.Keys.Printscreen,
    pattern Mischief.Input.Keys.Scrolllock,
    pattern Mischief.Input.Keys.Pause,
    pattern Mischief.Input.Keys.Insert,
    pattern Mischief.Input.Keys.Home,
    pattern Mischief.Input.Keys.PageUp,
    pattern Mischief.Input.Keys.PageDown,
    pattern Mischief.Input.Keys.Delete,
    pattern Mischief.Input.Keys.End,
    pattern Mischief.Input.Keys.Right,
    pattern Mischief.Input.Keys.Left,
    pattern Mischief.Input.Keys.Down,
    pattern Mischief.Input.Keys.Up,
    pattern Mischief.Input.Keys.Numlockclear,
    pattern Mischief.Input.Keys.KeypadDivide,
    pattern Mischief.Input.Keys.KeypadMultiply,
    pattern Mischief.Input.Keys.Keypad0,
    pattern Mischief.Input.Keys.Keypad1,
    pattern Mischief.Input.Keys.Keypad2,
    pattern Mischief.Input.Keys.Keypad3,
    pattern Mischief.Input.Keys.Keypad4,
    pattern Mischief.Input.Keys.Keypad5,
    pattern Mischief.Input.Keys.Keypad6,
    pattern Mischief.Input.Keys.Keypad7,
    pattern Mischief.Input.Keys.Keypad8,
    pattern Mischief.Input.Keys.Keypad9,
    pattern Mischief.Input.Keys.KeypadPeriod,
    pattern Mischief.Input.Keys.KeypadComma,
    pattern Mischief.Input.Keys.KeypadEnter,
    pattern Mischief.Input.Keys.KeypadEquals,
    pattern Mischief.Input.Keys.KeypadMinus,
    pattern Mischief.Input.Keys.KeypadPlus,
    pattern Mischief.Input.Keys.LCtrl,
    pattern Mischief.Input.Keys.LShift,
    pattern Mischief.Input.Keys.LAlt,
    pattern Mischief.Input.Keys.RCtrl,
    pattern Mischief.Input.Keys.RShift,
    pattern Mischief.Input.Keys.RAlt,
    pattern Mischief.Input.Keys.Application,
  )
where

import Control.Monad.IO.Class
import Data.List ((!?))
import Foreign (nullPtr, peekArray, toBool)
import Foreign.C (CBool)
import Foreign.C.ConstPtr
import GHC.Generics
import Mischief.ECS
import Mischief.ECS.App.Schedules (First)
import Mischief.SDL (SDLPlugin)
import SDL3.Sys qualified as SDL3

data Keys = Keys
  { currentKeys :: [CBool],
    previousKeys :: [CBool]
  }
  deriving (Generic, Default, Component)

-- newtype HotKeys = HotKeys [((SDL3.SDL_Scancode, SDL3.SDL_Keycode), KeyState)] deriving (Generic, Default, Component)

-- setStatePhysical :: KeyState -> SDL3.SDL_Scancode -> IORef Keys -> IO ()
-- setStatePhysical state scancode keys =
--   modifyIORef' keys (\Keys {physical, virtual} -> Keys {physical = Map.insert scancode state physical, virtual})

-- setStateVirtual :: KeyState -> SDL3.SDL_Keycode -> IORef Keys -> IO ()
-- setStateVirtual state keycode keys =
--   modifyIORef' keys (\Keys {physical, virtual} -> Keys {physical, virtual = Map.insert keycode state virtual})

pressed :: Keys -> SDL3.SDL_Scancode -> Bool
pressed Keys {currentKeys} code = maybe False toBool $ currentKeys !? unwrapScancode code

justPressed :: Keys -> SDL3.SDL_Scancode -> Bool
justPressed Keys {currentKeys, previousKeys} code = do
  let c = unwrapScancode code
  maybe False toBool (currentKeys !? c) && not (maybe False toBool $ previousKeys !? c)

released :: Keys -> SDL3.SDL_Scancode -> Bool
released Keys {currentKeys} code = not $ maybe False toBool $ currentKeys !? unwrapScancode code

justReleased :: Keys -> SDL3.SDL_Scancode -> Bool
justReleased Keys {currentKeys, previousKeys} code = do
  let c = unwrapScancode code
  not (maybe False toBool (currentKeys !? c)) && maybe False toBool (previousKeys !? c)

-- | Plugin which keeps track of key inputs and updates the 'Keys' resource.
data KeysPlugin

instance Plugin KeysPlugin where
  init = do
    systems updateKeys
      & schedule @First

    insertRes $ Keys [] []

  deps = [dep @SDLPlugin]

unwrapScancode :: SDL3.SDL_Scancode -> Int
unwrapScancode (SDL3.SDL_Scancode i) = fromIntegral i

updateKeys :: System ()
updateKeys = do
  Just keys <- res @Keys
  ConstPtr a <- liftIO $ SDL3.getKeyboardState nullPtr
  b <- liftIO $ peekArray (unwrapScancode SDL3.SDL_SCANCODE_COUNT) a
  insertRes Keys {currentKeys = b, previousKeys = keys.currentKeys}

pattern A = SDL3.SDL_SCANCODE_A

pattern B = SDL3.SDL_SCANCODE_B

pattern C = SDL3.SDL_SCANCODE_C

pattern D = SDL3.SDL_SCANCODE_D

pattern E = SDL3.SDL_SCANCODE_E

pattern F = SDL3.SDL_SCANCODE_F

pattern G = SDL3.SDL_SCANCODE_G

pattern H = SDL3.SDL_SCANCODE_H

pattern I = SDL3.SDL_SCANCODE_I

pattern J = SDL3.SDL_SCANCODE_J

pattern K = SDL3.SDL_SCANCODE_K

pattern L = SDL3.SDL_SCANCODE_L

pattern M = SDL3.SDL_SCANCODE_M

pattern N = SDL3.SDL_SCANCODE_N

pattern O = SDL3.SDL_SCANCODE_O

pattern P = SDL3.SDL_SCANCODE_P

pattern Q = SDL3.SDL_SCANCODE_Q

pattern R = SDL3.SDL_SCANCODE_R

pattern S = SDL3.SDL_SCANCODE_S

pattern T = SDL3.SDL_SCANCODE_T

pattern U = SDL3.SDL_SCANCODE_U

pattern V = SDL3.SDL_SCANCODE_V

pattern W = SDL3.SDL_SCANCODE_W

pattern X = SDL3.SDL_SCANCODE_X

pattern Y = SDL3.SDL_SCANCODE_Y

pattern Z = SDL3.SDL_SCANCODE_Z

pattern Key1 = SDL3.SDL_SCANCODE_1

pattern Key2 = SDL3.SDL_SCANCODE_2

pattern Key3 = SDL3.SDL_SCANCODE_3

pattern Key4 = SDL3.SDL_SCANCODE_4

pattern Key5 = SDL3.SDL_SCANCODE_5

pattern Key6 = SDL3.SDL_SCANCODE_6

pattern Key7 = SDL3.SDL_SCANCODE_7

pattern Key8 = SDL3.SDL_SCANCODE_8

pattern Key9 = SDL3.SDL_SCANCODE_9

pattern Key0 = SDL3.SDL_SCANCODE_0

pattern Enter = SDL3.SDL_SCANCODE_RETURN

pattern Escape = SDL3.SDL_SCANCODE_ESCAPE

pattern Backspace = SDL3.SDL_SCANCODE_BACKSPACE

pattern Tab = SDL3.SDL_SCANCODE_TAB

pattern Space = SDL3.SDL_SCANCODE_SPACE

pattern Minus = SDL3.SDL_SCANCODE_MINUS

pattern Equals = SDL3.SDL_SCANCODE_EQUALS

pattern LeftBracket = SDL3.SDL_SCANCODE_LEFTBRACKET

pattern RightBracket = SDL3.SDL_SCANCODE_RIGHTBRACKET

pattern BackSlash = SDL3.SDL_SCANCODE_BACKSLASH

pattern Semicolon = SDL3.SDL_SCANCODE_SEMICOLON

pattern Apostrophe = SDL3.SDL_SCANCODE_APOSTROPHE

pattern Grave = SDL3.SDL_SCANCODE_GRAVE

pattern Comma = SDL3.SDL_SCANCODE_COMMA

pattern Period = SDL3.SDL_SCANCODE_PERIOD

pattern Slash = SDL3.SDL_SCANCODE_SLASH

pattern Capslock = SDL3.SDL_SCANCODE_CAPSLOCK

pattern F1 = SDL3.SDL_SCANCODE_F1

pattern F2 = SDL3.SDL_SCANCODE_F2

pattern F3 = SDL3.SDL_SCANCODE_F3

pattern F4 = SDL3.SDL_SCANCODE_F4

pattern F5 = SDL3.SDL_SCANCODE_F5

pattern F6 = SDL3.SDL_SCANCODE_F6

pattern F7 = SDL3.SDL_SCANCODE_F7

pattern F8 = SDL3.SDL_SCANCODE_F8

pattern F9 = SDL3.SDL_SCANCODE_F9

pattern F10 = SDL3.SDL_SCANCODE_F10

pattern F11 = SDL3.SDL_SCANCODE_F11

pattern F12 = SDL3.SDL_SCANCODE_F12

pattern Printscreen = SDL3.SDL_SCANCODE_PRINTSCREEN

pattern Scrolllock = SDL3.SDL_SCANCODE_SCROLLLOCK

pattern Pause = SDL3.SDL_SCANCODE_PAUSE

pattern Insert = SDL3.SDL_SCANCODE_INSERT

pattern Home = SDL3.SDL_SCANCODE_HOME

pattern PageUp = SDL3.SDL_SCANCODE_PAGEUP

pattern Delete = SDL3.SDL_SCANCODE_DELETE

pattern End = SDL3.SDL_SCANCODE_END

pattern PageDown = SDL3.SDL_SCANCODE_PAGEDOWN

pattern Right = SDL3.SDL_SCANCODE_RIGHT

pattern Left = SDL3.SDL_SCANCODE_LEFT

pattern Down = SDL3.SDL_SCANCODE_DOWN

pattern Up = SDL3.SDL_SCANCODE_UP

pattern Numlockclear = SDL3.SDL_SCANCODE_NUMLOCKCLEAR

pattern KeypadDivide = SDL3.SDL_SCANCODE_KP_DIVIDE

pattern KeypadMultiply = SDL3.SDL_SCANCODE_KP_MULTIPLY

pattern KeypadMinus = SDL3.SDL_SCANCODE_KP_MINUS

pattern KeypadPlus = SDL3.SDL_SCANCODE_KP_PLUS

pattern KeypadEnter = SDL3.SDL_SCANCODE_KP_ENTER

pattern Keypad1 = SDL3.SDL_SCANCODE_KP_1

pattern Keypad2 = SDL3.SDL_SCANCODE_KP_2

pattern Keypad3 = SDL3.SDL_SCANCODE_KP_3

pattern Keypad4 = SDL3.SDL_SCANCODE_KP_4

pattern Keypad5 = SDL3.SDL_SCANCODE_KP_5

pattern Keypad6 = SDL3.SDL_SCANCODE_KP_6

pattern Keypad7 = SDL3.SDL_SCANCODE_KP_7

pattern Keypad8 = SDL3.SDL_SCANCODE_KP_8

pattern Keypad9 = SDL3.SDL_SCANCODE_KP_9

pattern Keypad0 = SDL3.SDL_SCANCODE_KP_0

pattern KeypadPeriod = SDL3.SDL_SCANCODE_KP_PERIOD

pattern KeypadEquals = SDL3.SDL_SCANCODE_KP_EQUALS

pattern KeypadComma = SDL3.SDL_SCANCODE_KP_COMMA

pattern LCtrl = SDL3.SDL_SCANCODE_LCTRL

pattern LShift = SDL3.SDL_SCANCODE_LSHIFT

pattern LAlt = SDL3.SDL_SCANCODE_LALT

pattern RCtrl = SDL3.SDL_SCANCODE_RCTRL

pattern RShift = SDL3.SDL_SCANCODE_RSHIFT

pattern RAlt = SDL3.SDL_SCANCODE_RALT

pattern Application = SDL3.SDL_SCANCODE_APPLICATION

-- $keys
-- Below is an opinionated collection of keys selected from SDL3's scancodes. These can be used with 'pressed', 'justPressed', and so on.
--
-- Most key names are the same as SDL's, the only significant exception is @Return@ which has been renamed to @Enter@.
--
-- If you wish to access a key that's not defined here, you can grab it directly from "SDL3.Sys.Bindgen.Scancode".