Help understanding define-external-type wrap and unwrap

Hi there!

In preparation for the Spring Lisp Game Jam, I’m trying to add gamepad support to the game jam template, but I’m having trouble understanding Hoot’s FFI, especially when it comes to representing a Javascript Gamepad object. (I should also mention I’m fairly new to Scheme!)

So, I added this to user_imports in game.js:

input: {
  getGamepad: (index) => navigator.getGamepads()[index],
}

next, following the example in the documentation, I’m doing:

(define-foreign %get-gamepad
 "input" "getGamepad"
  i32 → (ref extern))

next, I’d like to use define-external-type to create a type I can use in Scheme, is that a good approach? Should I instead just create individual foreign functions for only the gamepad stuff I need?

A somewhat related question: is it possible to have foreign functions returning arrays (like navigator.getGamepads()) become lists in Scheme?

Thanks!

Your JS code for getGamepad looks good, as does the Scheme define-foreign binding. If you are careful to never pass a non-Gamepad to any of your gamepad bindings, then you don’t need a define-external-type wrapper type. Note that unwrapped external values are how everything in the game jam template works currently, for better or worse. If it’s important to be able to distinguish a gamepad from any other type of external value then yes, I think you should use define-external-type. You will still need to create bindings for each method you intend to use with the gamepad API.

Here’s some untested code to give you an idea

(define-external-type <gamepad> gamepad? wrap-gamepad unwrap-gamepad)
(define-foreign %gamepad-ref "gamepad" "get" i32 -> (ref null extern))
(define-foreign %gamepad-id "gamepad" "id" (ref extern) -> (ref string))
(define (gamepad-ref id)
  (wrap-gamepad (%gamepad-ref id)))
(define (gamepad-id gamepad)
  (%gamepad-id (unwrap-gamepad gamepad)))

It is not possible to have JS arrays automatically converted to Scheme lists since JS arrays are not a natively understood WebAssembly reference type. To iterate over all the gamepads, you would need bindings to Array.length and the [] array element accessor that you could then call from Scheme.

1 Like