package cursor import ( "reflect" "sync" "github.com/rs/zerolog" ) type PositionListener interface { SendCursorPosition(x, y int) error } type Position interface { Shutdown() Set(x, y int) AddListener(listener PositionListener) RemoveListener(listener PositionListener) } type position struct { logger zerolog.Logger listeners map[uintptr]PositionListener listenersMu sync.RWMutex } func NewPosition(logger zerolog.Logger) *position { return &position{ logger: logger.With().Str("submodule", "cursor-position").Logger(), listeners: map[uintptr]PositionListener{}, } } func (manager *position) Shutdown() { manager.logger.Info().Msg("shutdown") manager.listenersMu.Lock() for key := range manager.listeners { delete(manager.listeners, key) } manager.listenersMu.Unlock() } func (manager *position) Set(x, y int) { manager.listenersMu.RLock() defer manager.listenersMu.RUnlock() for _, l := range manager.listeners { if err := l.SendCursorPosition(x, y); err != nil { manager.logger.Err(err).Msg("failed to set cursor position") } } } func (manager *position) AddListener(listener PositionListener) { manager.listenersMu.Lock() defer manager.listenersMu.Unlock() if listener != nil { ptr := reflect.ValueOf(listener).Pointer() manager.listeners[ptr] = listener } } func (manager *position) RemoveListener(listener PositionListener) { manager.listenersMu.Lock() defer manager.listenersMu.Unlock() if listener != nil { ptr := reflect.ValueOf(listener).Pointer() delete(manager.listeners, ptr) } }