aboutsummaryrefslogtreecommitdiff
path: root/src/input.scm
diff options
context:
space:
mode:
Diffstat (limited to 'src/input.scm')
-rw-r--r--src/input.scm192
1 files changed, 192 insertions, 0 deletions
diff --git a/src/input.scm b/src/input.scm
new file mode 100644
index 0000000..f48518b
--- /dev/null
+++ b/src/input.scm
@@ -0,0 +1,192 @@
+(module input
+ (create-input-state
+ input-state-update!
+ input-pressed?
+ input-held?
+ input-released?
+ input-any-pressed?)
+
+(import scheme
+ (chicken base)
+ (chicken module)
+ (only srfi-1 any)
+ (prefix sdl2 sdl2:))
+
+;; Input state record - tracks current and previous frame state
+(define-record input-state
+ up down left right a b start select
+ prev-up prev-down prev-left prev-right prev-a prev-b prev-start prev-select)
+
+;; Create a new input state with all buttons released
+(define (create-input-state)
+ (make-input-state #f #f #f #f #f #f #f #f
+ #f #f #f #f #f #f #f #f))
+
+;; Button name to keyboard scancode mapping
+(define *keyboard-map*
+ '((up . w)
+ (down . s)
+ (left . a)
+ (right . d)
+ (a . j)
+ (b . k)
+ (start . return)
+ (select . backspace)))
+
+;; Button name to gamepad button mapping
+(define *gamepad-button-map*
+ '((a . 0) ; Button 0 (typically A/Cross)
+ (b . 1) ; Button 1 (typically B/Circle)
+ (start . 9) ; Button 9 (Start)
+ (select . 8))) ; Button 8 (Select)
+
+;; Update input state based on SDL2 events
+;; This should be called once per frame AFTER processing events
+;; Pass the event list from your game loop
+(define (input-state-update! state events)
+ ;; Save previous frame state
+ (input-state-prev-up-set! state (input-state-up state))
+ (input-state-prev-down-set! state (input-state-down state))
+ (input-state-prev-left-set! state (input-state-left state))
+ (input-state-prev-right-set! state (input-state-right state))
+ (input-state-prev-a-set! state (input-state-a state))
+ (input-state-prev-b-set! state (input-state-b state))
+ (input-state-prev-start-set! state (input-state-start state))
+ (input-state-prev-select-set! state (input-state-select state))
+
+ ;; Process events to update current state
+ (for-each
+ (lambda (event)
+ (let ((type (sdl2:event-type event)))
+ (cond
+ ;; Keyboard events
+ ((eq? type 'key-down)
+ (let ((key (sdl2:keyboard-event-sym event)))
+ (cond
+ ((eq? key 'w) (input-state-up-set! state #t))
+ ((eq? key 's) (input-state-down-set! state #t))
+ ((eq? key 'a) (input-state-left-set! state #t))
+ ((eq? key 'd) (input-state-right-set! state #t))
+ ((eq? key 'j) (input-state-a-set! state #t))
+ ((eq? key 'k) (input-state-b-set! state #t))
+ ((eq? key 'return) (input-state-start-set! state #t))
+ ((eq? key 'backspace) (input-state-select-set! state #t)))))
+
+ ((eq? type 'key-up)
+ (let ((key (sdl2:keyboard-event-sym event)))
+ (cond
+ ((eq? key 'w) (input-state-up-set! state #f))
+ ((eq? key 's) (input-state-down-set! state #f))
+ ((eq? key 'a) (input-state-left-set! state #f))
+ ((eq? key 'd) (input-state-right-set! state #f))
+ ((eq? key 'j) (input-state-a-set! state #f))
+ ((eq? key 'k) (input-state-b-set! state #f))
+ ((eq? key 'return) (input-state-start-set! state #f))
+ ((eq? key 'backspace) (input-state-select-set! state #f)))))
+
+ ;; Joystick button events
+ ((eq? type 'joy-button-down)
+ (let ((button (sdl2:joy-button-event-button event)))
+ (cond
+ ((= button 0) (input-state-a-set! state #t))
+ ((= button 1) (input-state-b-set! state #t))
+ ((= button 8) (input-state-select-set! state #t))
+ ((= button 9) (input-state-start-set! state #t)))))
+
+ ((eq? type 'joy-button-up)
+ (let ((button (sdl2:joy-button-event-button event)))
+ (cond
+ ((= button 0) (input-state-a-set! state #f))
+ ((= button 1) (input-state-b-set! state #f))
+ ((= button 8) (input-state-select-set! state #f))
+ ((= button 9) (input-state-start-set! state #f)))))
+
+ ;; Joystick hat (d-pad) events
+ ((eq? type 'joy-hat-motion)
+ (let ((value (sdl2:joy-hat-event-value event)))
+ (input-state-up-set! state (or (= value 1) (= value 9) (= value 5))) ; UP, LEFT-UP, RIGHT-UP
+ (input-state-down-set! state (or (= value 4) (= value 6) (= value 10))) ; DOWN, LEFT-DOWN, RIGHT-DOWN
+ (input-state-left-set! state (or (= value 8) (= value 9) (= value 6))) ; LEFT, LEFT-UP, LEFT-DOWN
+ (input-state-right-set! state (or (= value 2) (= value 5) (= value 10))))) ; RIGHT, RIGHT-UP, RIGHT-DOWN
+
+ ;; Joystick axis (analog stick as d-pad)
+ ((eq? type 'joy-axis-motion)
+ (let ((axis (sdl2:joy-axis-event-axis event))
+ (value (sdl2:joy-axis-event-value event)))
+ (cond
+ ((= axis 0) ; X-axis
+ (input-state-left-set! state (< value -8000))
+ (input-state-right-set! state (> value 8000)))
+ ((= axis 1) ; Y-axis
+ (input-state-up-set! state (< value -8000))
+ (input-state-down-set! state (> value 8000)))))))))
+ events))
+
+;; Check if a button was just pressed this frame
+(define (input-pressed? state button)
+ (let ((current (case button
+ ((up) (input-state-up state))
+ ((down) (input-state-down state))
+ ((left) (input-state-left state))
+ ((right) (input-state-right state))
+ ((a) (input-state-a state))
+ ((b) (input-state-b state))
+ ((start) (input-state-start state))
+ ((select) (input-state-select state))
+ (else #f)))
+ (previous (case button
+ ((up) (input-state-prev-up state))
+ ((down) (input-state-prev-down state))
+ ((left) (input-state-prev-left state))
+ ((right) (input-state-prev-right state))
+ ((a) (input-state-prev-a state))
+ ((b) (input-state-prev-b state))
+ ((start) (input-state-prev-start state))
+ ((select) (input-state-prev-select state))
+ (else #f))))
+ (and current (not previous))))
+
+;; Check if a button is currently held down
+(define (input-held? state button)
+ (case button
+ ((up) (input-state-up state))
+ ((down) (input-state-down state))
+ ((left) (input-state-left state))
+ ((right) (input-state-right state))
+ ((a) (input-state-a state))
+ ((b) (input-state-b state))
+ ((start) (input-state-start state))
+ ((select) (input-state-select state))
+ (else #f)))
+
+;; Check if a button was just released this frame
+(define (input-released? state button)
+ (let ((current (case button
+ ((up) (input-state-up state))
+ ((down) (input-state-down state))
+ ((left) (input-state-left state))
+ ((right) (input-state-right state))
+ ((a) (input-state-a state))
+ ((b) (input-state-b state))
+ ((start) (input-state-start state))
+ ((select) (input-state-select state))
+ (else #f)))
+ (previous (case button
+ ((up) (input-state-prev-up state))
+ ((down) (input-state-prev-down state))
+ ((left) (input-state-prev-left state))
+ ((right) (input-state-prev-right state))
+ ((a) (input-state-prev-a state))
+ ((b) (input-state-prev-b state))
+ ((start) (input-state-prev-start state))
+ ((select) (input-state-prev-select state))
+ (else #f))))
+ (and (not current) previous)))
+
+;; Check if any button was pressed this frame
+(define (input-any-pressed? state)
+ (any (lambda (button)
+ (input-pressed? state button))
+ '(up down left right a b start select)))
+
+) ; end module