Skip to content

Handling Input (v3)

ImplausiblyFun edited this page Jul 16, 2022 · 1 revision

Our starting point for this page is the template from A First Oak Program.

Event Bindables

Both mouse and keyboard events, which we'll cover in this page, are reacted to through the event package. Reacting to events occurs by creating a binding on a CID or Caller ID from that package, through CID.Bind, for example. In this page, however, we are not reacting in the context of a particular entity or caller, so we'll use event.GlobalBind, a function that reacts to all events triggered of the appropriate event name.

both CID.Bind and event.GlobalBind take in two arguments: an event.Bindable and an event string. When the appropriate event, named by the event string, occurs, the bindable will be called.

Bindables have the following function signature:

type Bindable func(CID, interface{}) int

The first argument to a bindable is the integer CID of the entity triggered on, or in the case of event.GlobalBind, 0. The interface{} argument is whatever data was included with the triggering event, documented by each event itself. The return value of a bindable is a success or error code. Returning 0 indicates to the event handler to do nothing. Other return results are detailed elsewhere.

Mouse Events

The set of mouse events is documented by the mouse package, in strings.go:

// Mouse events: MousePress, MouseRelease, MouseScrollDown, MouseScrollUp, MouseDrag
// Payload: (*mouse.Event) details on the mouse event
const (
    Press      = "MousePress"
    Release    = "MouseRelease"
    ScrollDown = "MouseScrollDown"
    ScrollUp   = "MouseScrollUp"
    Click      = "MouseClick"
    Drag       = "MouseDrag"
    //
    PressOn      = Press + "On"
    ReleaseOn    = Release + "On"
    ScrollDownOn = ScrollDown + "On"
    ScrollUpOn   = ScrollUp + "On"
    ClickOn      = Click + "On"
    DragOn       = Drag + "On"
)

We bind to these events in our scene start function:

(mouse.Binding handles casting the payload from a event.Bindable to a *mouse.Event.)

//...
func (*scene.Context) {
    event.GlobalBind(mouse.Press, mouse.Binding(func(no event.CID, ev *mouse.Event) int {
        return 0
    })
},
//...

For now, lets just print out the position the mouse was pressed at:

//...
func (*scene.Context) {
    event.GlobalBind(mouse.Press, mouse.Binding(func(no event.CID, ev *mouse.Event) int {
        fmt.Println("Mouse position:", me.X(), me.Y())
        return 0
    })
},
//...

Now if we go run core.go and click on the screen, we'll see print statements in the console informing us where we clicked. For more info about when each mouse event is triggered, see the Mouse Events page.

Keyboard Events

Oak tracks three keyboard events: key.Down, key.Up, and key.Held. For each of these events you can also bind it for any specific key code. The key package tracks all keys that can be bound to. When a key event is triggered, the payload data it will send is a key.Event:

//...
func (*scene.Context) {
    event.GlobalBind(key.Down, func(no int, ev interface{}) int {
        k := ev.(key.Event)
        fmt.Println("Key pressed:", k.Code)
        return 0
    })
    event.GlobalBind(key.Down + key.Spacebar, func(no int, ev interface{}) int {
        fmt.Println("Spacebar pressed")
        return 0
    }, )
},
//...

key.Down is triggered when a key is first pressed down. If the OS sends this key again because it continues to be held down, key.Held will be triggered. key.Up is triggered when a key is released.

To check how long a key has been held for, use (key.State).IsHeld(key string), which will return both whether the key is currently held and for how long it has been held. Similarly, whether a key is currently held down can be checked with (key.State).IsDown(key string). The scene context passed into a scene start contains this key state object, but if you are only using a single oak window you can also use oak.IsHeld or oak.IsDown.