You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
182 lines
3.1 KiB
182 lines
3.1 KiB
package evdev
|
|
|
|
/*
|
|
#include <linux/input.h>
|
|
|
|
static int _EVIOCGBIT(int ev, int len) {return EVIOCGBIT(ev, len);}
|
|
*/
|
|
import "C"
|
|
import (
|
|
"bytes"
|
|
"encoding/binary"
|
|
"os"
|
|
"syscall"
|
|
"unsafe"
|
|
)
|
|
|
|
const (
|
|
EVIOCGRAB = C.EVIOCGRAB // grab/release device
|
|
)
|
|
|
|
var keyMap = map[uint16]rune{
|
|
41: '`',
|
|
2: '1',
|
|
3: '2',
|
|
4: '3',
|
|
5: '4',
|
|
6: '5',
|
|
7: '6',
|
|
8: '7',
|
|
9: '8',
|
|
10: '9',
|
|
11: '0',
|
|
12: '-',
|
|
13: '=',
|
|
98: '/',
|
|
55: '*',
|
|
74: '-',
|
|
16: 'Q',
|
|
17: 'W',
|
|
18: 'E',
|
|
19: 'R',
|
|
20: 'T',
|
|
21: 'Y',
|
|
22: 'U',
|
|
23: 'I',
|
|
24: 'O',
|
|
25: 'P',
|
|
26: '[',
|
|
27: ']',
|
|
71: '7',
|
|
72: '8',
|
|
73: '9',
|
|
78: '+',
|
|
30: 'A',
|
|
31: 'S',
|
|
32: 'D',
|
|
33: 'F',
|
|
34: 'G',
|
|
35: 'H',
|
|
36: 'J',
|
|
37: 'K',
|
|
38: 'L',
|
|
39: ';',
|
|
40: '\'',
|
|
75: '4',
|
|
76: '5',
|
|
77: '6',
|
|
44: 'Z',
|
|
45: 'X',
|
|
46: 'C',
|
|
47: 'V',
|
|
48: 'B',
|
|
49: 'N',
|
|
50: 'M',
|
|
51: ',',
|
|
52: '.',
|
|
53: '/',
|
|
43: '\\',
|
|
79: '1',
|
|
80: '2',
|
|
81: '3',
|
|
57: ' ',
|
|
82: '0',
|
|
83: '.',
|
|
}
|
|
|
|
var eventSize = int(unsafe.Sizeof(InputEvent{}))
|
|
|
|
type InputEvent struct {
|
|
Time syscall.Timeval // time in seconds since epoch at which event occurred
|
|
Type uint16 // event type - one of ecodes.EV_*
|
|
Code uint16 // event code related to the event type
|
|
Value int32 // event value related to the event type
|
|
}
|
|
|
|
// InputDevice A Linux input device from which events can be read.
|
|
type InputDevice struct {
|
|
Fn string // path to input device (devnode)
|
|
bufLen int // read buffer size
|
|
|
|
Name string // device name
|
|
Phys string // physical topology of device
|
|
File *os.File // an open file handle to the input device
|
|
}
|
|
|
|
func EVIOCGBIT(ev, l int) int { return int(C._EVIOCGBIT(C.int(ev), C.int(l))) } // get event bits
|
|
|
|
// Open an evdev input device.
|
|
func Open(devNode string, bufLen int) (*InputDevice, error) {
|
|
f, err := os.Open(devNode)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
dev := InputDevice{}
|
|
dev.Fn = devNode
|
|
dev.File = f
|
|
|
|
dev.bufLen = bufLen
|
|
|
|
return &dev, nil
|
|
}
|
|
|
|
func (dev *InputDevice) Close() {
|
|
if dev.File != nil {
|
|
dev.File.Close()
|
|
}
|
|
}
|
|
|
|
func ioctl(fd uintptr, name uintptr, data unsafe.Pointer) syscall.Errno {
|
|
_, _, err := syscall.RawSyscall(syscall.SYS_IOCTL, fd, name, uintptr(data))
|
|
return err
|
|
}
|
|
|
|
// Grab the input device exclusively.
|
|
func (dev *InputDevice) Grab() error {
|
|
grab := int(1)
|
|
if err := ioctl(dev.File.Fd(), uintptr(EVIOCGRAB), unsafe.Pointer(&grab)); err != 0 {
|
|
return err
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// Release a grabbed input device.
|
|
func (dev *InputDevice) Release() error {
|
|
if err := ioctl(dev.File.Fd(), uintptr(EVIOCGRAB), unsafe.Pointer(nil)); err != 0 {
|
|
return err
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// Read and return a slice of input events from device.
|
|
func (dev *InputDevice) Read() ([]InputEvent, error) {
|
|
buffer := make([]byte, eventSize*dev.bufLen)
|
|
|
|
count, err := dev.File.Read(buffer)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
events := make([]InputEvent, count/eventSize)
|
|
|
|
b := bytes.NewBuffer(buffer)
|
|
err = binary.Read(b, binary.LittleEndian, &events)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return events, err
|
|
}
|
|
|
|
// GetKey Return appropriate key rune if present
|
|
func (event *InputEvent) GetKey() (rune, bool) {
|
|
if event.Type != 1 || event.Value != 1 {
|
|
return 0, false
|
|
}
|
|
|
|
r, ok := keyMap[event.Code]
|
|
return r, ok
|
|
}
|
|
|