namespace Mibo.Input open System open System.Numerics open Raylib_cs open Mibo.Elmish // ───────────────────────────────────────────────────────────────────────────── // Raylib ↔ Core input translation. // // This is the ONLY place in the raylib backend where Raylib_cs.KeyboardKey / // MouseButton / GamepadButton / Gesture touch the Core-neutral code types. // Everything else in the backend works in Core codes. // ───────────────────────────────────────────────────────────────────────────── /// Functions for translating between raylib's KeyboardKey and Mibo's backend-neutral KeyCode. module KeyCode = /// Maps a raylib KeyboardKey to the backend-neutral . /// Returns for any raylib key with no logical equivalent. let ofRaylibKey(k: KeyboardKey) : KeyCode = match k with // Letters | KeyboardKey.A -> KeyCode.A | KeyboardKey.B -> KeyCode.B | KeyboardKey.C -> KeyCode.C | KeyboardKey.D -> KeyCode.D | KeyboardKey.E -> KeyCode.E | KeyboardKey.F -> KeyCode.F | KeyboardKey.G -> KeyCode.G | KeyboardKey.H -> KeyCode.H | KeyboardKey.I -> KeyCode.I | KeyboardKey.J -> KeyCode.J | KeyboardKey.K -> KeyCode.K | KeyboardKey.L -> KeyCode.L | KeyboardKey.M -> KeyCode.M | KeyboardKey.N -> KeyCode.N | KeyboardKey.O -> KeyCode.O | KeyboardKey.P -> KeyCode.P | KeyboardKey.Q -> KeyCode.Q | KeyboardKey.R -> KeyCode.R | KeyboardKey.S -> KeyCode.S | KeyboardKey.T -> KeyCode.T | KeyboardKey.U -> KeyCode.U | KeyboardKey.V -> KeyCode.V | KeyboardKey.W -> KeyCode.W | KeyboardKey.X -> KeyCode.X | KeyboardKey.Y -> KeyCode.Y | KeyboardKey.Z -> KeyCode.Z // Digits | KeyboardKey.Zero -> KeyCode.D0 | KeyboardKey.One -> KeyCode.D1 | KeyboardKey.Two -> KeyCode.D2 | KeyboardKey.Three -> KeyCode.D3 | KeyboardKey.Four -> KeyCode.D4 | KeyboardKey.Five -> KeyCode.D5 | KeyboardKey.Six -> KeyCode.D6 | KeyboardKey.Seven -> KeyCode.D7 | KeyboardKey.Eight -> KeyCode.D8 | KeyboardKey.Nine -> KeyCode.D9 // Function keys | KeyboardKey.F1 -> KeyCode.F1 | KeyboardKey.F2 -> KeyCode.F2 | KeyboardKey.F3 -> KeyCode.F3 | KeyboardKey.F4 -> KeyCode.F4 | KeyboardKey.F5 -> KeyCode.F5 | KeyboardKey.F6 -> KeyCode.F6 | KeyboardKey.F7 -> KeyCode.F7 | KeyboardKey.F8 -> KeyCode.F8 | KeyboardKey.F9 -> KeyCode.F9 | KeyboardKey.F10 -> KeyCode.F10 | KeyboardKey.F11 -> KeyCode.F11 | KeyboardKey.F12 -> KeyCode.F12 // Arrows / navigation | KeyboardKey.Right -> KeyCode.Right | KeyboardKey.Left -> KeyCode.Left | KeyboardKey.Down -> KeyCode.Down | KeyboardKey.Up -> KeyCode.Up | KeyboardKey.PageUp -> KeyCode.PageUp | KeyboardKey.PageDown -> KeyCode.PageDown | KeyboardKey.Home -> KeyCode.Home | KeyboardKey.End -> KeyCode.End | KeyboardKey.Insert -> KeyCode.Insert | KeyboardKey.Delete -> KeyCode.Delete // Editing / control | KeyboardKey.Space -> KeyCode.Space | KeyboardKey.Enter -> KeyCode.Enter | KeyboardKey.Escape -> KeyCode.Escape | KeyboardKey.Tab -> KeyCode.Tab | KeyboardKey.Backspace -> KeyCode.Backspace | KeyboardKey.CapsLock -> KeyCode.CapsLock // Modifiers | KeyboardKey.LeftShift -> KeyCode.LeftShift | KeyboardKey.RightShift -> KeyCode.RightShift | KeyboardKey.LeftControl -> KeyCode.LeftControl | KeyboardKey.RightControl -> KeyCode.RightControl | KeyboardKey.LeftAlt -> KeyCode.LeftAlt | KeyboardKey.RightAlt -> KeyCode.RightAlt | KeyboardKey.LeftSuper -> KeyCode.LeftSuper | KeyboardKey.RightSuper -> KeyCode.RightSuper // Punctuation / symbols (US layout) | KeyboardKey.Grave -> KeyCode.Grave | KeyboardKey.Minus -> KeyCode.Minus | KeyboardKey.Equal -> KeyCode.Equal | KeyboardKey.LeftBracket -> KeyCode.LeftBracket | KeyboardKey.RightBracket -> KeyCode.RightBracket | KeyboardKey.Backslash -> KeyCode.Backslash | KeyboardKey.Semicolon -> KeyCode.Semicolon | KeyboardKey.Apostrophe -> KeyCode.Apostrophe | KeyboardKey.Comma -> KeyCode.Comma | KeyboardKey.Period -> KeyCode.Period | KeyboardKey.Slash -> KeyCode.Slash // Keypad | KeyboardKey.Kp0 -> KeyCode.Kp0 | KeyboardKey.Kp1 -> KeyCode.Kp1 | KeyboardKey.Kp2 -> KeyCode.Kp2 | KeyboardKey.Kp3 -> KeyCode.Kp3 | KeyboardKey.Kp4 -> KeyCode.Kp4 | KeyboardKey.Kp5 -> KeyCode.Kp5 | KeyboardKey.Kp6 -> KeyCode.Kp6 | KeyboardKey.Kp7 -> KeyCode.Kp7 | KeyboardKey.Kp8 -> KeyCode.Kp8 | KeyboardKey.Kp9 -> KeyCode.Kp9 | KeyboardKey.KpDecimal -> KeyCode.KpDecimal | KeyboardKey.KpDivide -> KeyCode.KpDivide | KeyboardKey.KpMultiply -> KeyCode.KpMultiply | KeyboardKey.KpSubtract -> KeyCode.KpSubtract | KeyboardKey.KpAdd -> KeyCode.KpAdd | KeyboardKey.KpEnter -> KeyCode.KpEnter | KeyboardKey.KpEqual -> KeyCode.KpEqual // Media / system | KeyboardKey.PrintScreen -> KeyCode.PrintScreen | KeyboardKey.ScrollLock -> KeyCode.ScrollLock | KeyboardKey.Pause -> KeyCode.Pause | KeyboardKey.Menu -> KeyCode.Menu // Locks | KeyboardKey.NumLock -> KeyCode.NumLock | _ -> KeyCode.Unknown /// Maps a backend-neutral back to raylib's KeyboardKey. /// Returns KeyboardKey.Null for . let toRaylibKey(k: KeyCode) : KeyboardKey = match k with | KeyCode.A -> KeyboardKey.A | KeyCode.B -> KeyboardKey.B | KeyCode.C -> KeyboardKey.C | KeyCode.D -> KeyboardKey.D | KeyCode.E -> KeyboardKey.E | KeyCode.F -> KeyboardKey.F | KeyCode.G -> KeyboardKey.G | KeyCode.H -> KeyboardKey.H | KeyCode.I -> KeyboardKey.I | KeyCode.J -> KeyboardKey.J | KeyCode.K -> KeyboardKey.K | KeyCode.L -> KeyboardKey.L | KeyCode.M -> KeyboardKey.M | KeyCode.N -> KeyboardKey.N | KeyCode.O -> KeyboardKey.O | KeyCode.P -> KeyboardKey.P | KeyCode.Q -> KeyboardKey.Q | KeyCode.R -> KeyboardKey.R | KeyCode.S -> KeyboardKey.S | KeyCode.T -> KeyboardKey.T | KeyCode.U -> KeyboardKey.U | KeyCode.V -> KeyboardKey.V | KeyCode.W -> KeyboardKey.W | KeyCode.X -> KeyboardKey.X | KeyCode.Y -> KeyboardKey.Y | KeyCode.Z -> KeyboardKey.Z | KeyCode.D0 -> KeyboardKey.Zero | KeyCode.D1 -> KeyboardKey.One | KeyCode.D2 -> KeyboardKey.Two | KeyCode.D3 -> KeyboardKey.Three | KeyCode.D4 -> KeyboardKey.Four | KeyCode.D5 -> KeyboardKey.Five | KeyCode.D6 -> KeyboardKey.Six | KeyCode.D7 -> KeyboardKey.Seven | KeyCode.D8 -> KeyboardKey.Eight | KeyCode.D9 -> KeyboardKey.Nine | KeyCode.F1 -> KeyboardKey.F1 | KeyCode.F2 -> KeyboardKey.F2 | KeyCode.F3 -> KeyboardKey.F3 | KeyCode.F4 -> KeyboardKey.F4 | KeyCode.F5 -> KeyboardKey.F5 | KeyCode.F6 -> KeyboardKey.F6 | KeyCode.F7 -> KeyboardKey.F7 | KeyCode.F8 -> KeyboardKey.F8 | KeyCode.F9 -> KeyboardKey.F9 | KeyCode.F10 -> KeyboardKey.F10 | KeyCode.F11 -> KeyboardKey.F11 | KeyCode.F12 -> KeyboardKey.F12 | KeyCode.Right -> KeyboardKey.Right | KeyCode.Left -> KeyboardKey.Left | KeyCode.Down -> KeyboardKey.Down | KeyCode.Up -> KeyboardKey.Up | KeyCode.PageUp -> KeyboardKey.PageUp | KeyCode.PageDown -> KeyboardKey.PageDown | KeyCode.Home -> KeyboardKey.Home | KeyCode.End -> KeyboardKey.End | KeyCode.Insert -> KeyboardKey.Insert | KeyCode.Delete -> KeyboardKey.Delete | KeyCode.Space -> KeyboardKey.Space | KeyCode.Enter -> KeyboardKey.Enter | KeyCode.Escape -> KeyboardKey.Escape | KeyCode.Tab -> KeyboardKey.Tab | KeyCode.Backspace -> KeyboardKey.Backspace | KeyCode.CapsLock -> KeyboardKey.CapsLock | KeyCode.LeftShift -> KeyboardKey.LeftShift | KeyCode.RightShift -> KeyboardKey.RightShift | KeyCode.LeftControl -> KeyboardKey.LeftControl | KeyCode.RightControl -> KeyboardKey.RightControl | KeyCode.LeftAlt -> KeyboardKey.LeftAlt | KeyCode.RightAlt -> KeyboardKey.RightAlt | KeyCode.LeftSuper -> KeyboardKey.LeftSuper | KeyCode.RightSuper -> KeyboardKey.RightSuper | KeyCode.Grave -> KeyboardKey.Grave | KeyCode.Minus -> KeyboardKey.Minus | KeyCode.Equal -> KeyboardKey.Equal | KeyCode.LeftBracket -> KeyboardKey.LeftBracket | KeyCode.RightBracket -> KeyboardKey.RightBracket | KeyCode.Backslash -> KeyboardKey.Backslash | KeyCode.Semicolon -> KeyboardKey.Semicolon | KeyCode.Apostrophe -> KeyboardKey.Apostrophe | KeyCode.Comma -> KeyboardKey.Comma | KeyCode.Period -> KeyboardKey.Period | KeyCode.Slash -> KeyboardKey.Slash | KeyCode.Kp0 -> KeyboardKey.Kp0 | KeyCode.Kp1 -> KeyboardKey.Kp1 | KeyCode.Kp2 -> KeyboardKey.Kp2 | KeyCode.Kp3 -> KeyboardKey.Kp3 | KeyCode.Kp4 -> KeyboardKey.Kp4 | KeyCode.Kp5 -> KeyboardKey.Kp5 | KeyCode.Kp6 -> KeyboardKey.Kp6 | KeyCode.Kp7 -> KeyboardKey.Kp7 | KeyCode.Kp8 -> KeyboardKey.Kp8 | KeyCode.Kp9 -> KeyboardKey.Kp9 | KeyCode.KpDecimal -> KeyboardKey.KpDecimal | KeyCode.KpDivide -> KeyboardKey.KpDivide | KeyCode.KpMultiply -> KeyboardKey.KpMultiply | KeyCode.KpSubtract -> KeyboardKey.KpSubtract | KeyCode.KpAdd -> KeyboardKey.KpAdd | KeyCode.KpEnter -> KeyboardKey.KpEnter | KeyCode.KpEqual -> KeyboardKey.KpEqual | KeyCode.PrintScreen -> KeyboardKey.PrintScreen | KeyCode.ScrollLock -> KeyboardKey.ScrollLock | KeyCode.Pause -> KeyboardKey.Pause | KeyCode.Menu -> KeyboardKey.Menu | KeyCode.NumLock -> KeyboardKey.NumLock | KeyCode.Unknown -> KeyboardKey.Null /// Functions for translating between raylib's MouseButton and Mibo's backend-neutral MouseButtonCode. module MouseButtonCode = let ofRaylibButton(b: MouseButton) : MouseButtonCode = match b with | MouseButton.Left -> MouseButtonCode.Left | MouseButton.Right -> MouseButtonCode.Right | MouseButton.Middle -> MouseButtonCode.Middle | MouseButton.Side -> MouseButtonCode.Extra1 | MouseButton.Extra -> MouseButtonCode.Extra2 | MouseButton.Forward -> MouseButtonCode.Extra3 | MouseButton.Back -> MouseButtonCode.Extra4 | _ -> MouseButtonCode.Unknown let toRaylibButton(b: MouseButtonCode) : MouseButton = match b with | MouseButtonCode.Left -> MouseButton.Left | MouseButtonCode.Right -> MouseButton.Right | MouseButtonCode.Middle -> MouseButton.Middle | MouseButtonCode.Extra1 -> MouseButton.Side | MouseButtonCode.Extra2 -> MouseButton.Extra | MouseButtonCode.Extra3 -> MouseButton.Forward | MouseButtonCode.Extra4 -> MouseButton.Back | MouseButtonCode.Unknown -> MouseButton.Left /// Functions for translating between raylib's GamepadButton and Mibo's backend-neutral GamepadButtonCode. /// /// raylib's GamepadButton enum uses "left face" for the D-pad cluster and /// "right face" for the action-button cluster (Xbox: Y/B/A/X). The Core codes /// abstract that naming so backends with different conventions (e.g. MonoGame / /// XNA) can map onto the same logical buttons. /// module GamepadButtonCode = let ofRaylibButton(b: GamepadButton) : GamepadButtonCode = match b with // raylib's "left face" cluster IS the D-pad | GamepadButton.LeftFaceUp -> GamepadButtonCode.DPadUp | GamepadButton.LeftFaceRight -> GamepadButtonCode.DPadRight | GamepadButton.LeftFaceDown -> GamepadButtonCode.DPadDown | GamepadButton.LeftFaceLeft -> GamepadButtonCode.DPadLeft // raylib's "right face" cluster is the action buttons (Y/B/A/X on Xbox) | GamepadButton.RightFaceUp -> GamepadButtonCode.FaceUp | GamepadButton.RightFaceRight -> GamepadButtonCode.FaceRight | GamepadButton.RightFaceDown -> GamepadButtonCode.FaceDown | GamepadButton.RightFaceLeft -> GamepadButtonCode.FaceLeft | GamepadButton.LeftTrigger1 -> GamepadButtonCode.LeftShoulder | GamepadButton.LeftTrigger2 -> GamepadButtonCode.LeftTrigger | GamepadButton.RightTrigger1 -> GamepadButtonCode.RightShoulder | GamepadButton.RightTrigger2 -> GamepadButtonCode.RightTrigger | GamepadButton.LeftThumb -> GamepadButtonCode.LeftStick | GamepadButton.RightThumb -> GamepadButtonCode.RightStick | GamepadButton.MiddleLeft -> GamepadButtonCode.Select | GamepadButton.Middle -> GamepadButtonCode.Home | GamepadButton.MiddleRight -> GamepadButtonCode.Start | _ -> GamepadButtonCode.Unknown let toRaylibButton(b: GamepadButtonCode) : GamepadButton = match b with | GamepadButtonCode.DPadUp -> GamepadButton.LeftFaceUp | GamepadButtonCode.DPadRight -> GamepadButton.LeftFaceRight | GamepadButtonCode.DPadDown -> GamepadButton.LeftFaceDown | GamepadButtonCode.DPadLeft -> GamepadButton.LeftFaceLeft | GamepadButtonCode.FaceUp -> GamepadButton.RightFaceUp | GamepadButtonCode.FaceRight -> GamepadButton.RightFaceRight | GamepadButtonCode.FaceDown -> GamepadButton.RightFaceDown | GamepadButtonCode.FaceLeft -> GamepadButton.RightFaceLeft | GamepadButtonCode.LeftShoulder -> GamepadButton.LeftTrigger1 | GamepadButtonCode.RightShoulder -> GamepadButton.RightTrigger1 | GamepadButtonCode.LeftTrigger -> GamepadButton.LeftTrigger2 | GamepadButtonCode.RightTrigger -> GamepadButton.RightTrigger2 | GamepadButtonCode.LeftStick -> GamepadButton.LeftThumb | GamepadButtonCode.RightStick -> GamepadButton.RightThumb | GamepadButtonCode.Select -> GamepadButton.MiddleLeft | GamepadButtonCode.Home -> GamepadButton.Middle | GamepadButtonCode.Start -> GamepadButton.MiddleRight | GamepadButtonCode.Unknown -> GamepadButton.Unknown /// Functions for translating between raylib's Gesture and Mibo's backend-neutral GestureKind. module GestureKind = let ofRaylibGesture(g: Gesture) : GestureKind = match g with | Gesture.Tap -> GestureKind.Tap | Gesture.DoubleTap -> GestureKind.DoubleTap | Gesture.Hold -> GestureKind.Hold | Gesture.Drag -> GestureKind.Drag | Gesture.SwipeRight -> GestureKind.SwipeRight | Gesture.SwipeLeft -> GestureKind.SwipeLeft | Gesture.SwipeUp -> GestureKind.SwipeUp | Gesture.SwipeDown -> GestureKind.SwipeDown | Gesture.PinchIn | Gesture.PinchOut -> GestureKind.Pinch | _ -> GestureKind.Unknown let toRaylibGesture(g: GestureKind) : Gesture = match g with | GestureKind.Tap -> Gesture.Tap | GestureKind.DoubleTap -> Gesture.DoubleTap | GestureKind.Hold -> Gesture.Hold | GestureKind.Drag -> Gesture.Drag | GestureKind.SwipeRight -> Gesture.SwipeRight | GestureKind.SwipeLeft -> Gesture.SwipeLeft | GestureKind.SwipeUp -> Gesture.SwipeUp | GestureKind.SwipeDown -> Gesture.SwipeDown | GestureKind.Pinch -> Gesture.PinchOut | GestureKind.Unknown -> Gesture.None // ───────────────────────────────────────────────────────────────────────────── // Input polling (raylib). Emits Core-neutral delta values. // ───────────────────────────────────────────────────────────────────────────── module InputPolling = // Only iterate over keys that are likely to produce a meaningful KeyCode — // the translation function returns Unknown for the rest, which we filter out. let private allKeyboardKeys = Enum.GetValues(typeof) :?> KeyboardKey[] |> Array.filter(fun k -> k <> KeyboardKey.Null && int k >= 32 && int k <= 348) let private allMouseButtons = Enum.GetValues(typeof) :?> MouseButton[] let private allGamepadButtons = Enum.GetValues(typeof) :?> GamepadButton[] |> Array.filter(fun b -> b <> GamepadButton.Unknown) let pollKeyboard (pressedBuf: ResizeArray) (releasedBuf: ResizeArray) (trigger: KeyboardDelta -> unit) = pressedBuf.Clear() releasedBuf.Clear() for k in allKeyboardKeys do if Raylib.IsKeyPressed(k).AsBool() then let code = KeyCode.ofRaylibKey k if code <> KeyCode.Unknown then pressedBuf.Add(code) elif Raylib.IsKeyReleased(k).AsBool() then let code = KeyCode.ofRaylibKey k if code <> KeyCode.Unknown then releasedBuf.Add(code) if pressedBuf.Count > 0 || releasedBuf.Count > 0 then trigger { Pressed = pressedBuf.ToArray() Released = releasedBuf.ToArray() } let pollMouse (pressedBuf: ResizeArray) (releasedBuf: ResizeArray) (trigger: MouseDelta -> unit) = pressedBuf.Clear() releasedBuf.Clear() for btn in allMouseButtons do if Raylib.IsMouseButtonPressed(btn).AsBool() then let code = MouseButtonCode.ofRaylibButton btn if code <> MouseButtonCode.Unknown then pressedBuf.Add code elif Raylib.IsMouseButtonReleased(btn).AsBool() then let code = MouseButtonCode.ofRaylibButton btn if code <> MouseButtonCode.Unknown then releasedBuf.Add code let pos = Raylib.GetMousePosition() let delta = Raylib.GetMouseDelta() let scroll = Raylib.GetMouseWheelMove() let scrollV = Raylib.GetMouseWheelMoveV() let hasButtonChange = pressedBuf.Count > 0 || releasedBuf.Count > 0 let hasMove = delta.X <> 0.0f || delta.Y <> 0.0f let hasScroll = scroll <> 0.0f || scrollV.X <> 0.0f || scrollV.Y <> 0.0f if hasButtonChange || hasMove || hasScroll then trigger { Position = pos PositionDelta = delta Buttons = { Pressed = pressedBuf.ToArray() Released = releasedBuf.ToArray() } ScrollDelta = scroll ScrollDeltaV = scrollV } let pollTouch (prevTouchIds: ResizeArray) (trigger: TouchDelta -> unit) = let count = Raylib.GetTouchPointCount() if count > 0 then let currentIds = ResizeArray(count) let points = Array.zeroCreate count for i = 0 to count - 1 do let id = Raylib.GetTouchPointId(i) let pos = Raylib.GetTouchPosition(i) currentIds.Add(id) let state = if prevTouchIds.Contains(id) then TouchState.Moved else TouchState.Pressed points[i] <- { Id = id Position = pos State = state } let releasedIds = prevTouchIds |> Seq.filter(not << currentIds.Contains) let releasedPoints = releasedIds |> Seq.map(fun id -> { Id = id Position = Vector2.Zero State = TouchState.Released }) |> Seq.toArray trigger { Touches = Array.append points releasedPoints } prevTouchIds.Clear() prevTouchIds.AddRange(currentIds) else if prevTouchIds.Count > 0 then let releasedPoints = prevTouchIds |> Seq.map(fun id -> { Id = id Position = Vector2.Zero State = TouchState.Released }) |> Seq.toArray trigger { Touches = releasedPoints } prevTouchIds.Clear() let pollGamepad (prevConnected: bool[]) (pressedBuf: ResizeArray) (releasedBuf: ResizeArray) (triggerDelta: GamepadDelta -> unit) (triggerConnection: GamepadConnection -> unit) = for i = 0 to 3 do let isConnected = Raylib.IsGamepadAvailable(i).AsBool() if prevConnected[i] <> isConnected then triggerConnection { PlayerIndex = i IsConnected = isConnected } prevConnected[i] <- isConnected if isConnected then pressedBuf.Clear() releasedBuf.Clear() for btn in allGamepadButtons do if Raylib.IsGamepadButtonPressed(i, btn).AsBool() then let code = GamepadButtonCode.ofRaylibButton btn if code <> GamepadButtonCode.Unknown then pressedBuf.Add(code) elif Raylib.IsGamepadButtonReleased(i, btn).AsBool() then let code = GamepadButtonCode.ofRaylibButton btn if code <> GamepadButtonCode.Unknown then releasedBuf.Add(code) let hasButtonChange = pressedBuf.Count > 0 || releasedBuf.Count > 0 let leftStick = Vector2( Raylib.GetGamepadAxisMovement(i, GamepadAxis.LeftX), Raylib.GetGamepadAxisMovement(i, GamepadAxis.LeftY) ) let rightStick = Vector2( Raylib.GetGamepadAxisMovement(i, GamepadAxis.RightX), Raylib.GetGamepadAxisMovement(i, GamepadAxis.RightY) ) let leftTrigger = Raylib.GetGamepadAxisMovement(i, GamepadAxis.LeftTrigger) let rightTrigger = Raylib.GetGamepadAxisMovement(i, GamepadAxis.RightTrigger) let hasAnalogChange = leftStick.X <> 0.0f || leftStick.Y <> 0.0f || rightStick.X <> 0.0f || rightStick.Y <> 0.0f || leftTrigger <> 0.0f || rightTrigger <> 0.0f if hasButtonChange || hasAnalogChange then triggerDelta { PlayerIndex = i Buttons = { Pressed = pressedBuf.ToArray() Released = releasedBuf.ToArray() } Analog = { LeftThumbstick = leftStick RightThumbstick = rightStick LeftTrigger = leftTrigger RightTrigger = rightTrigger } } let pollGestures(trigger: GestureDelta -> unit) = let detected = Raylib.GetGestureDetected() if detected <> Gesture.None then let kind = GestureKind.ofRaylibGesture detected if kind <> GestureKind.Unknown then trigger { Gesture = kind HoldDuration = Raylib.GetGestureHoldDuration() DragVector = Raylib.GetGestureDragVector() DragAngle = Raylib.GetGestureDragAngle() PinchVector = Raylib.GetGesturePinchVector() PinchAngle = Raylib.GetGesturePinchAngle() } // ───────────────────────────────────────────────────────────────────────────── // IInput factory (raylib implementation). // // Input.getService / tryGetService and the Keyboard/Mouse/Touch/Gamepad/Gesture // subscription modules all live in Core now; only the polling + factory stays here. // ───────────────────────────────────────────────────────────────────────────── module Input = let internal create(gestures: Gesture list) : IInput = let keyboardDelta = Event() let mouseDelta = Event() let touchDelta = Event() let gamepadDelta = Event() let gamepadConnection = Event() let gestureDelta = Event() let pressedKeysBuf = ResizeArray(8) let releasedKeysBuf = ResizeArray(8) let pressedMouseBuf = ResizeArray(4) let releasedMouseBuf = ResizeArray(4) let pressedGpBuf = ResizeArray(8) let releasedGpBuf = ResizeArray(8) let prevTouchIds = ResizeArray(8) let prevConnected = Array.create 4 false // Enable requested gestures (bitwise OR of flags) let gestureFlags = match gestures with | [] -> Gesture.None | _ -> gestures |> List.reduce(fun acc g -> acc ||| g) if gestures.Length > 0 then Raylib.SetGesturesEnabled(gestureFlags) { new IInput with member _.Poll() = InputPolling.pollKeyboard pressedKeysBuf releasedKeysBuf keyboardDelta.Trigger InputPolling.pollMouse pressedMouseBuf releasedMouseBuf mouseDelta.Trigger InputPolling.pollTouch prevTouchIds touchDelta.Trigger InputPolling.pollGamepad prevConnected pressedGpBuf releasedGpBuf gamepadDelta.Trigger gamepadConnection.Trigger InputPolling.pollGestures gestureDelta.Trigger member _.KeyboardDelta = keyboardDelta.Publish member _.MouseDelta = mouseDelta.Publish member _.TouchDelta = touchDelta.Publish member _.GamepadDelta = gamepadDelta.Publish member _.GamepadConnection = gamepadConnection.Publish member _.GestureDelta = gestureDelta.Publish member _.SetMouseCapture(capture) = match capture with | MouseCapture.Captured -> Raylib.DisableCursor() | MouseCapture.Free -> Raylib.EnableCursor() }