go-temper/internal/temper/discovery_linux.go
2025-05-12 21:34:47 -05:00

70 lines
2.0 KiB
Go

package temper
import (
"context"
"os"
"path/filepath"
"strings"
"time"
)
// Function which scans /dev for temperXX devices (configured by udev)
//
// A timeout of 250ms is recommended but as YMMV, this function allows
// for an arbitrary timeout.
func FindTempersWithTimeout(timeout time.Duration) ([]*Temper, error) {
// list over dev folder for temperXX devices
dirEnts, err := os.ReadDir("/dev")
if err != nil {
return []*Temper{}, err
}
tempers := []*Temper{}
for _, d := range dirEnts {
if name := d.Name(); strings.HasPrefix(name, "temper") {
if isInputDevice(name) {
continue
}
temper, err := New(filepath.Join("/dev", name))
if err != nil {
continue
}
// attempt to take a reading from the temper
// if the reading times out, assume it's a false positive
ctx, cancel := context.WithTimeout(context.Background(), timeout)
_, err = temper.ReadCWithContext(ctx)
if err == nil {
tempers = append(tempers, temper)
} else {
// prevent file descriptor leaks
temper.Close()
}
cancel()
}
}
return tempers, nil
}
// Helper function to return list of temper devices available in /dev
//
// Uses the recommended default timeout of 250ms. See
// FindTempersWithTimeout for more details
func FindTempers() ([]*Temper, error) {
return FindTempersWithTimeout(time.Millisecond * 250)
}
// Determines if the current hidraw device also doubles as a virtual keyboard
//
// some temper devices also have a keyboard emulation mode.
// The regular discovery function can trigger data entry mode, and cause
// annoying and distracting typing to happen, so this function allows us to
// skip the check on devices we know aren't temper sensors
func isInputDevice(temperDescriptor string) bool {
hidrawDesc := strings.ReplaceAll(temperDescriptor, "temper", "hidraw")
inputPath := filepath.Join("/sys/class/hidraw", hidrawDesc, "device/input")
if _, statErr := os.Stat(inputPath); statErr == nil {
return true
}
return false
}