Use sensor timestamps for Mini 2 volume taps

This commit is contained in:
2026-11-13 12:04:19 +03:00
parent f81e53ef85
commit 20e45056c8
2 changed files with 57 additions and 9 deletions
+25 -9
View File
@@ -157,6 +157,7 @@ func (g *panelGesture) key(now time.Time, code uint16, value uint32) {
}
type panelEvent struct {
at time.Time
kind, code uint16
value uint32
}
@@ -170,6 +171,7 @@ func readPanel(device io.Reader, events chan<- panelEvent) error {
return err
}
events <- panelEvent{
at: time.Unix(int64(binary.LittleEndian.Uint64(raw[:8])), int64(binary.LittleEndian.Uint64(raw[8:16]))*1000),
kind: binary.LittleEndian.Uint16(raw[16:18]),
code: binary.LittleEndian.Uint16(raw[18:20]),
value: binary.LittleEndian.Uint32(raw[20:24]),
@@ -177,6 +179,27 @@ func readPanel(device io.Reader, events chan<- panelEvent) error {
}
}
func (g *panelGesture) applyEvent(event panelEvent) panelAction {
switch {
case event.kind == 0 && event.code == 3: // SYN_DROPPED
*g = panelGesture{ignoreToSync: true}
case event.kind == 0 && event.code == 0:
g.ignoreToSync = false
case event.kind == 1 && !g.ignoreToSync:
var action panelAction
// Separate repeated volume taps before waiting for another swipe zone.
if event.value == 1 && event.code != panelCenter &&
g.down == 0 && g.count == 1 && g.path[0] == event.code {
action = g.finish(event.at)
} else {
action = g.tick(event.at)
}
g.key(event.at, event.code, event.value)
return action
}
return ""
}
func listenPanel(playback string, dialog *conversation) {
names, _ := filepath.Glob("/sys/class/input/event*/device/name")
for _, path := range names {
@@ -221,6 +244,7 @@ func runPanel(events <-chan panelEvent, playback string, dialog *conversation) {
continue
}
lights.showVolume(level)
log.Printf("panel volume: %d%%", level)
go playVolumeTone(playback, level)
}
}()
@@ -279,15 +303,7 @@ func runPanel(events <-chan panelEvent, playback string, dialog *conversation) {
if !ok {
return
}
now := time.Now()
if event.kind == 0 && event.code == 3 { // SYN_DROPPED
gesture = panelGesture{ignoreToSync: true}
} else if event.kind == 0 && event.code == 0 {
gesture.ignoreToSync = false
} else if event.kind == 1 {
emit(gesture.tick(now))
gesture.key(now, event.code, event.value)
}
emit(gesture.applyEvent(event))
case now := <-ticker.C:
emit(gesture.tick(now))
}
+32
View File
@@ -1,10 +1,42 @@
package main
import (
"bytes"
"encoding/binary"
"testing"
"time"
)
func TestPanelBatchedVolumeTapsUseEventTime(t *testing.T) {
for _, tc := range []struct {
code uint16
want panelAction
}{{panelMinus, panelQuieter}, {panelPlus, panelLouder}} {
var raw bytes.Buffer
for i, micros := range []uint64{1000, 52000, 125000, 151000} {
var event [24]byte
binary.LittleEndian.PutUint64(event[:8], 100)
binary.LittleEndian.PutUint64(event[8:16], micros)
binary.LittleEndian.PutUint16(event[16:18], 1)
binary.LittleEndian.PutUint16(event[18:20], tc.code)
binary.LittleEndian.PutUint32(event[20:24], uint32(1-i%2))
raw.Write(event[:])
}
events := make(chan panelEvent, 4)
_ = readPanel(&raw, events)
var gesture panelGesture
var actions []panelAction
for event := range events {
if action := gesture.applyEvent(event); action != "" {
actions = append(actions, action)
}
}
if len(actions) != 1 || actions[0] != tc.want || gesture.tick(time.Unix(101, 0)) != tc.want {
t.Fatalf("zone %d: expected two steps in the same direction, first actions %v", tc.code, actions)
}
}
}
func TestPanelSwipeAndPartialSwipeAreExclusive(t *testing.T) {
for _, tc := range []struct {
zones []uint16