jroimartin / gocui

Minimalist Go package aimed at creating Console User Interfaces.
BSD 3-Clause "New" or "Revised" License
9.91k stars 610 forks source link

Detect any key press event? #126

Open dbubel-rm opened 7 years ago

dbubel-rm commented 7 years ago

Is there a way to detect if any key is pressed? Something similar to this:

if err := g.SetKeybinding("", gocui.AnyKey, gocui.ModNone, onEnterEvt(c)); err != nil {
    log.Panicln(err)
}
moribellamy commented 7 years ago

I think I want the same thing as @engineerbeard, but if not I apologize for hijacking.

Basically I would like my application to run its own logic as a result of any user keypress. Right now it looks like gocui processes keypresses only by tbEvents chan termbox.Event.

I want to say "on any keypress, run my function on the updated contents of the buffer". I could poll with a sleep, but that's not idea.

middlehut commented 6 years ago

@engineerbeard @moribellamy If you peek inside the g.SetKeybindings function, you will notice that it calls another small function called getKey(key) which receives as input the value that you have provided for key bindings.

func getKey(key interface{}) (Key, rune, error) {
    switch t := key.(type) {
    case Key:
        return t, 0, nil
    case rune:
        return 0, t, nil
    default:
        return 0, 0, errors.New("unknown type")
    }
}

It casts the value to either e predefined Key in the library, or a Go rune. Using the rune value, you can provide whatever keyboard key you like by using its Hex value.

For example, the gocui library does not define bindings for keyboard numbers 0-9. If we want to assign the key for number 5, we can use the ASCII value which is 0x35 and it will work.

err = g.SetKeybinding("", rune(0x35), gocui.ModNone, quit)
if err != nil {
    return err
}
bokwoon95 commented 5 years ago

@dbubel I managed to achieve it in a roundabout way, by declaring g.SetKeybinding for every rune in a string along with a partially applied function

// Handle all legal javascript characters
for _, c := range "{};.=<>()[]'\"/\\-+!@#$%^&*~:abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" {
    g.SetKeybinding("", c, gocui.ModNone, mkEvtHandler(c)) 
    //              ^^^ this is similar to what you suggested
}

func mkEvtHandler(ch rune) func(g *gocui.Gui, v *gocui.View) error {
    return func(g *gocui.Gui, v *gocui.View) error {
        fmt.Fprintln(v, fmt.Sprintf("The character is %c\n", ch))
        return nil
    }
}
dbubel-rm commented 5 years ago

@bokwoon95 Very cool. I haven't worked on my project that uses this in some time. But ill give your method a try.