123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260 |
- /* package input is a thing Go wrapper around the Linux kernel input event
- * system. */
- package input
- import "gitlab.com/beoran/galago/os/linux"
- import "os"
- import "unsafe"
- import syscall "golang.org/x/sys/unix"
- import "fmt"
- import "path/filepath"
- // Device models an input device
- type Device struct {
- *os.File
- }
- const Directory = "/dev/input"
- func Open(name string) (*Device, error) {
- f, err := os.OpenFile(filepath.Join(Directory, name),
- syscall.O_ASYNC|syscall.O_NONBLOCK|os.O_RDWR, 0666)
- if err != nil {
- return nil, err
- }
- return &Device{File: f}, nil
- }
- func List() ([]string, error) {
- dir, err := os.Open(Directory)
- if err != nil {
- return nil, err
- }
- return dir.Readdirnames(-1)
- }
- // Icotl performs an ioctl on the given device
- func (d * Device) Ioctl(code uint32, pointer unsafe.Pointer) error {
- fmt.Printf("ioctl: %d %d %d\n", uintptr(d.Fd()), uintptr(code), uintptr(pointer))
- _, _, errno := syscall.Syscall(
- syscall.SYS_IOCTL,
- uintptr(d.Fd()),
- uintptr(code),
- uintptr(pointer))
- if (errno != 0) {
- return errno
- }
- return nil
- }
- func (d * Device) DriverVersion() (int32, error) {
- res := int32(0)
- data := unsafe.Pointer(&res)
- err := d.Ioctl(linux.EVIOCGVERSION, data)
- return res, err
- }
- func (d * Device) Name() (string, error) {
- buffer := [256]byte{}
- err := d.Ioctl(linux.EVIOCGNAME(uintptr(len(buffer))), unsafe.Pointer(&buffer))
- return string(buffer[0:len(buffer)]), err
- }
- func (d * Device) Id() (linux.INPUT_id, error) {
- var result linux.INPUT_id
- err := d.Ioctl(linux.EVIOCGID, unsafe.Pointer(&result))
- return result, err
- }
- // The Linux developers thought it was a great idea a to use an array of
- // unsigned longs for the bit flags of input devices. Of course, the length
- // of an unsigned long is platform dependent which then entails all sorts of
- // gymnastics to extract the bits from the array...
- const SIZEOF_LONG = uint(unsafe.Sizeof(*((*linux.UnsignedLong)(nil))))
- const BITS_PER_LONG = SIZEOF_LONG * 8
- func BitsToLong(bits uint) uint {
- return ((bits) + (8 * SIZEOF_LONG) - 1) / (8 * SIZEOF_LONG)
- }
- func (d * Device) Topology() (string, error) {
- buffer := [256]byte{}
- err := d.Ioctl(linux.EVIOCGPHYS(uintptr(len(buffer))), unsafe.Pointer(&buffer))
- return string(buffer[0:len(buffer)]), err
- }
- func TestBit(array []uint8, bit uint) bool {
- elem := uint(array[ bit / 8 ])
- flag := uint(1) << uint(bit % 8)
- return (elem & flag ) != 0
- }
- type SupportedEvent uint
- func (se SupportedEvent) Name() string {
- return linux.EvToString(uint(se))
- }
- func (se SupportedEvent) String() string {
- return se.Name()
- }
- func (d * Device) SupportedEvents() ([]SupportedEvent, error) {
- var bits [linux.EV_MAX / 8 + 1]uint8
- size := unsafe.Sizeof(bits)
- err := d.Ioctl(linux.EVIOCGBIT(0, uintptr(size)), unsafe.Pointer(&bits));
- if err != nil {
- return nil, err
- }
- fmt.Printf("size %d, bits: %v\n", size, bits)
- result := []SupportedEvent{}
- for i := uint(0); i < uint(linux.EV_MAX); i++ {
- if (TestBit(bits[0:len(bits)],i)) {
- result = append(result, SupportedEvent(uint(i)))
- }
- }
-
- return result, nil
- }
- // More Go-like names for the low leve kernel api structs
- type InputAbsinfo linux.INPUT_absinfo
- type InputEvent linux.INPUT_event
- type AbsoluteAxis struct {
- Index uint
- InputAbsinfo
- }
- func (ax AbsoluteAxis) Name() string {
- return linux.AbsToString(ax.Index)
- }
- func (ax AbsoluteAxis) String() string {
- return fmt.Sprintf("%s %d (min:%d max:%d flat:%d fuzz:%d)",
- ax.Name(),
- ax.Value,
- ax.Minimum,
- ax.Maximum,
- ax.Flat,
- ax.Fuzz)
- }
- func (ev InputEvent) String() string {
- return fmt.Sprintf("Event: Time: %d Type: %s, Code: %d, Value:%d",
- ev.Time,
- linux.EvToString(uint(ev.Type)),
- ev.Code,
- ev.Value)
- }
- // Read performs a read syscall on the given device
- func (d * Device) Read(pointer unsafe.Pointer, size uintptr) (uintptr, error) {
- fmt.Printf("read: %d %d %d\n", uintptr(d.Fd()), uintptr(pointer), uintptr(size))
- read, _, errno := syscall.Syscall(
- syscall.SYS_READ,
- uintptr(d.Fd()),
- uintptr(pointer),
- uintptr(size))
- if (errno != 0) {
- return read, errno
- }
- return read, nil
- }
- const READ_EVENTS_MAX = 64
- func (d * Device) ReadEvents() ([]InputEvent, error) {
- var events [READ_EVENTS_MAX]InputEvent
- size := unsafe.Sizeof(events)
- read, err := d.Read(unsafe.Pointer(&events), size)
- if err != nil {
- return nil, err
- }
- len := read / unsafe.Sizeof(events[0])
- return events[0:len], nil
- }
- func (d * Device) SupportedAxes() ([]AbsoluteAxis, error) {
- var abs_feat InputAbsinfo;
- var abs_b [linux.ABS_MAX/8 + 1]uint8;
- size := unsafe.Sizeof(abs_b)
- err := d.Ioctl(linux.EVIOCGBIT(linux.EV_ABS, size), unsafe.Pointer(&abs_b))
- if err != nil {
- return nil, err
- }
- result := []AbsoluteAxis{}
- fmt.Printf("Supported Absolute axes:\n");
- for yalv := uint(0); yalv < linux.ABS_MAX; yalv++ {
- if TestBit(abs_b[0:len(abs_b)], uint(yalv)) {
- fmt.Printf(" Absolute axis 0x%02x %s", yalv, linux.AbsToString(yalv))
- err = d.Ioctl(linux.EVIOCGABS(uint32(yalv)), unsafe.Pointer(&abs_feat))
- if err != nil {
- return result, err
- }
- axis := AbsoluteAxis{Index: yalv, InputAbsinfo: abs_feat}
- result = append(result, axis)
- }
- }
- return result, nil
- }
- /*
- printf("Supported events:\n");
- for (i = 0; i < EV_MAX; i++)
- if (TestBit(i, bit[0])) {
-
- }
-
- printf("Testing ... (interrupt to exit)\n");
- while (1) {
- rd = read(fd, ev, sizeof(struct input_event) * 64);
- if (rd < (int) sizeof(struct input_event)) {
- printf("yyy\n");
- perror("\nevtest: error reading");
- return 1;
- }
- for (i = 0; i < rd / sizeof(struct input_event); i++)
- if (ev[i].type == EV_SYN) {
- printf("Event: time %ld.%06ld, -------------- %s ------------\n",
- ev[i].time.tv_sec, ev[i].time.tv_usec, ev[i].code ? "Config Sync" : "Report Sync" );
- } else if (ev[i].type == EV_MSC && (ev[i].code == MSC_RAW || ev[i].code == MSC_SCAN)) {
- printf("Event: time %ld.%06ld, type %d (%s), code %d (%s), value %02x\n",
- ev[i].time.tv_sec, ev[i].time.tv_usec, ev[i].type,
- events[ev[i].type] ? events[ev[i].type] : "?",
- ev[i].code,
- names[ev[i].type] ? (names[ev[i].type][ev[i].code] ? names[ev[i].type][ev[i].code] : "?") : "?",
- ev[i].value);
- } else {
- printf("Event: time %ld.%06ld, type %d (%s), code %d (%s), value %d\n",
- ev[i].time.tv_sec, ev[i].time.tv_usec, ev[i].type,
- events[ev[i].type] ? events[ev[i].type] : "?",
- ev[i].code,
- names[ev[i].type] ? (names[ev[i].type][ev[i].code] ? names[ev[i].type][ev[i].code] : "?") : "?",
- ev[i].value);
- }
- }
- }
- */
|