/* 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" 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), 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 de 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 TestBit(bit uint, array []linux.UnsignedLong) bool { elem := array[ bit / ( 8 * SIZEOF_LONG)] flag := linux.UnsignedLong(1) << linux.UnsignedLong(bit % (8 * SIZEOF_LONG)) return (elem & flag ) != 0 } 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 (d * Device) SupportedEvents() ([]uint, error) { size := BitsToLong(linux.EV_MAX) bits := make([]linux.UnsignedLong, size) for i := uint(0); i < size; i ++ { bits[i] = 0 } 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 := []uint{} for i := uint(0); i < uint(linux.EV_MAX); i++ { if (TestBit(i, bits)) { result = append(result, uint(i)) } } 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); } } } */