add basic keyboard driver using stty
This commit is contained in:
parent
e7beae51bd
commit
15a764d865
|
@ -0,0 +1,36 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/hybridgroup/gobot"
|
||||
"github.com/hybridgroup/gobot/platforms/keyboard"
|
||||
)
|
||||
|
||||
func main() {
|
||||
gbot := gobot.NewGobot()
|
||||
|
||||
keys := keyboard.NewKeyboardDriver("keyboard")
|
||||
|
||||
work := func() {
|
||||
gobot.On(keys.Event("key"), func(data interface{}) {
|
||||
key := data.(keyboard.KeyEvent)
|
||||
|
||||
if key.Key == keyboard.A {
|
||||
fmt.Println("A pressed!")
|
||||
} else {
|
||||
fmt.Println("keyboard event!", key, key.Char)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
robot := gobot.NewRobot("keyboardbot",
|
||||
[]gobot.Connection{},
|
||||
[]gobot.Device{keys},
|
||||
work,
|
||||
)
|
||||
|
||||
gbot.AddRobot(robot)
|
||||
|
||||
gbot.Start()
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
Copyright (c) 2014 The Hybrid Group
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
|
@ -0,0 +1,52 @@
|
|||
# Keyboard
|
||||
|
||||
This module implements support for keyboard events, wrapping the `stty` utility.
|
||||
|
||||
## How to Install
|
||||
|
||||
```
|
||||
go get github.com/hybridgroup/gobot && go install github.com/hybridgroup/gobot/platforms/ardrone
|
||||
```
|
||||
|
||||
## How to Use
|
||||
|
||||
Example parsing key events
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/hybridgroup/gobot"
|
||||
"github.com/hybridgroup/gobot/platforms/keyboard"
|
||||
)
|
||||
|
||||
func main() {
|
||||
gbot := gobot.NewGobot()
|
||||
|
||||
keys := keyboard.NewKeyboardDriver("keyboard")
|
||||
|
||||
work := func() {
|
||||
gobot.On(keys.Event("key"), func(data interface{}) {
|
||||
key := data.(keyboard.KeyEvent)
|
||||
|
||||
if key.Key == keyboard.A {
|
||||
fmt.Println("A pressed!")
|
||||
} else {
|
||||
fmt.Println("keyboard event!", key, key.Char)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
robot := gobot.NewRobot("keyboardbot",
|
||||
[]gobot.Connection{},
|
||||
[]gobot.Device{keys},
|
||||
work,
|
||||
)
|
||||
|
||||
gbot.AddRobot(robot)
|
||||
|
||||
gbot.Start()
|
||||
}
|
||||
```
|
|
@ -0,0 +1,52 @@
|
|||
/*
|
||||
Packge keyboard contains the Gobot drivers for keyboard support.
|
||||
|
||||
Installing:
|
||||
|
||||
Then you can install the package with:
|
||||
|
||||
go get github.com/hybridgroup/gobot && go install github.com/hybridgroup/gobot/platforms/keyboard
|
||||
|
||||
Example:
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/hybridgroup/gobot"
|
||||
"github.com/hybridgroup/gobot/platforms/keyboard"
|
||||
)
|
||||
|
||||
func main() {
|
||||
gbot := gobot.NewGobot()
|
||||
|
||||
keys := keyboard.NewKeyboardDriver("keyboard")
|
||||
|
||||
work := func() {
|
||||
gobot.On(keys.Event("key"), func(data interface{}) {
|
||||
key := data.(keyboard.KeyEvent)
|
||||
|
||||
if key.Key == keyboard.A {
|
||||
fmt.Println("A pressed!")
|
||||
} else {
|
||||
fmt.Println("keyboard event!", key, key.Char)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
robot := gobot.NewRobot("keyboardbot",
|
||||
[]gobot.Connection{},
|
||||
[]gobot.Device{keys},
|
||||
work,
|
||||
)
|
||||
|
||||
gbot.AddRobot(robot)
|
||||
|
||||
gbot.Start()
|
||||
}
|
||||
|
||||
For further information refer to keyboard README:
|
||||
https://github.com/hybridgroup/gobot/blob/master/platforms/keyboard/README.md
|
||||
*/
|
||||
package keyboard
|
|
@ -0,0 +1,156 @@
|
|||
package keyboard
|
||||
|
||||
import (
|
||||
"os"
|
||||
"os/exec"
|
||||
)
|
||||
|
||||
type bytes [3]byte
|
||||
|
||||
type KeyEvent struct {
|
||||
Bytes bytes
|
||||
Key int
|
||||
Char string
|
||||
}
|
||||
|
||||
const (
|
||||
Tilde = iota + 96
|
||||
A
|
||||
B
|
||||
C
|
||||
D
|
||||
E
|
||||
F
|
||||
G
|
||||
H
|
||||
I
|
||||
J
|
||||
K
|
||||
L
|
||||
M
|
||||
N
|
||||
O
|
||||
P
|
||||
Q
|
||||
R
|
||||
S
|
||||
T
|
||||
U
|
||||
V
|
||||
W
|
||||
X
|
||||
Y
|
||||
Z
|
||||
)
|
||||
|
||||
const (
|
||||
Escape = 27
|
||||
Spacebar = 32
|
||||
)
|
||||
|
||||
const (
|
||||
Zero = iota + 48
|
||||
One
|
||||
Two
|
||||
Three
|
||||
Four
|
||||
Five
|
||||
Six
|
||||
Seven
|
||||
Eight
|
||||
Nine
|
||||
)
|
||||
|
||||
const (
|
||||
ArrowUp = iota + 65
|
||||
ArrowDown
|
||||
ArrowRight
|
||||
ArrowLeft
|
||||
)
|
||||
|
||||
// used to hold the original stty state
|
||||
var originalState string
|
||||
|
||||
func Parse(input bytes) KeyEvent {
|
||||
var event = KeyEvent{Bytes: input, Char: string(input[:])}
|
||||
|
||||
var code byte
|
||||
|
||||
// basic input codes
|
||||
if input[1] == 0 && input[2] == 0 {
|
||||
code = input[0]
|
||||
|
||||
// space bar
|
||||
if code == Spacebar {
|
||||
event.Key = Spacebar
|
||||
}
|
||||
|
||||
// vanilla escape
|
||||
if code == Escape {
|
||||
event.Key = Escape
|
||||
}
|
||||
|
||||
// number keys
|
||||
if code >= 48 && code <= 57 {
|
||||
event.Key = int(code)
|
||||
}
|
||||
|
||||
// alphabet
|
||||
if code >= 97 && code <= 122 {
|
||||
event.Key = int(code)
|
||||
}
|
||||
|
||||
return event
|
||||
}
|
||||
|
||||
// arrow keys
|
||||
if input[0] == Escape && input[1] == 91 {
|
||||
code = input[2]
|
||||
|
||||
if code >= 65 && code <= 68 {
|
||||
event.Key = int(code)
|
||||
return event
|
||||
}
|
||||
}
|
||||
|
||||
return event
|
||||
}
|
||||
|
||||
// fetches original state, sets up TTY for raw (unbuffered) input
|
||||
func configure() (err error) {
|
||||
state, err := stty("-g")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
originalState = state
|
||||
|
||||
// -echo: terminal doesn't echo typed characters back to the terminal
|
||||
// -icanon: terminal doesn't interpret special characters (like backspace)
|
||||
if _, err := stty("-echo", "-icanon"); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// restores the TTY to the original state
|
||||
func restore() (errs []error) {
|
||||
if _, err := stty(originalState); err != nil {
|
||||
return []error{err}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func stty(args ...string) (string, error) {
|
||||
cmd := exec.Command("stty", args...)
|
||||
cmd.Stdin = os.Stdin
|
||||
|
||||
out, err := cmd.Output()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return string(out), nil
|
||||
}
|
|
@ -0,0 +1,81 @@
|
|||
package keyboard
|
||||
|
||||
import (
|
||||
"log"
|
||||
"os"
|
||||
|
||||
"github.com/hybridgroup/gobot"
|
||||
)
|
||||
|
||||
var _ gobot.Driver = (*KeyboardDriver)(nil)
|
||||
|
||||
type KeyboardDriver struct {
|
||||
name string
|
||||
connect func(*KeyboardDriver) (err error)
|
||||
listen func(*KeyboardDriver)
|
||||
stdin *os.File
|
||||
gobot.Eventer
|
||||
}
|
||||
|
||||
func NewKeyboardDriver(name string) *KeyboardDriver {
|
||||
k := &KeyboardDriver{
|
||||
name: name,
|
||||
connect: func(k *KeyboardDriver) (err error) {
|
||||
if err := configure(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
k.stdin = os.Stdin
|
||||
return
|
||||
},
|
||||
listen: func(k *KeyboardDriver) {
|
||||
ctrlc := bytes{3}
|
||||
|
||||
for {
|
||||
var keybuf bytes
|
||||
k.stdin.Read(keybuf[0:3])
|
||||
|
||||
if keybuf == ctrlc {
|
||||
proc, err := os.FindProcess(os.Getpid())
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
proc.Signal(os.Interrupt)
|
||||
break
|
||||
}
|
||||
|
||||
gobot.Publish(k.Event("key"), Parse(keybuf))
|
||||
|
||||
}
|
||||
},
|
||||
Eventer: gobot.NewEventer(),
|
||||
}
|
||||
|
||||
k.AddEvent("key")
|
||||
|
||||
return k
|
||||
}
|
||||
|
||||
func (k *KeyboardDriver) Name() string { return k.name }
|
||||
func (k *KeyboardDriver) Connection() gobot.Connection { return nil }
|
||||
|
||||
// Start initializes keyboard by grabbing key events as they come in and
|
||||
// publishing a key event
|
||||
func (k *KeyboardDriver) Start() (errs []error) {
|
||||
if err := k.connect(k); err != nil {
|
||||
return []error{err}
|
||||
}
|
||||
|
||||
go k.listen(k)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// Halt stops camera driver
|
||||
func (k *KeyboardDriver) Halt() (errs []error) {
|
||||
if originalState != "" {
|
||||
return restore()
|
||||
}
|
||||
return
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
package keyboard
|
||||
|
||||
import (
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/hybridgroup/gobot"
|
||||
)
|
||||
|
||||
func initTestKeyboardDriver() *KeyboardDriver {
|
||||
d := NewKeyboardDriver("keyboard")
|
||||
d.connect = func(k *KeyboardDriver) (err error) {
|
||||
k.stdin = &os.File{}
|
||||
return nil
|
||||
}
|
||||
d.listen = func(k *KeyboardDriver) {}
|
||||
return d
|
||||
}
|
||||
|
||||
func TestKeyboardDriver(t *testing.T) {
|
||||
d := initTestKeyboardDriver()
|
||||
gobot.Assert(t, d.Name(), "keyboard")
|
||||
gobot.Assert(t, d.Connection(), (gobot.Connection)(nil))
|
||||
}
|
||||
|
||||
func TestKeyboardDriverStart(t *testing.T) {
|
||||
d := initTestKeyboardDriver()
|
||||
gobot.Assert(t, len(d.Start()), 0)
|
||||
}
|
||||
|
||||
func TestKeyboardDriverHalt(t *testing.T) {
|
||||
d := initTestKeyboardDriver()
|
||||
gobot.Assert(t, len(d.Halt()), 0)
|
||||
}
|
Loading…
Reference in New Issue