package main import ( "bytes" "fmt" "os" "strconv" "strings" "time" "golang.org/x/sys/unix" "golang.org/x/term" ) func main() { st, err := term.MakeRaw(0) if err != nil { os.Exit(1) } var column int select { case <-time.After(100 * time.Millisecond): case column = <-awaitColumn(): } term.Restore(0, st) if column > 1 { unix.Write(1, []byte("🚫\n")) // U+1F6AB } } func awaitColumn() <-chan int { ch := make(chan int) go func() { row, col := readDSR() _ = row ch <- col }() return ch } func readDSR() (row, col int) { unix.Write(1, []byte{ '\033', '[', // ANSI escape code: CSI '6', 'n', // DSR / device status report }) buf := make([]byte, 64) n, err := unix.Read(0, buf) if err != nil { return 0, 0 } buf = buf[:n] if len(buf) < 6 || buf[0] != '\033' || buf[1] != '[' || buf[len(buf)-1] != 'R' { return 0, 0 } s := string(buf[2 : len(buf)-1]) pos := strings.IndexByte(s, ';') if pos == -1 { return 0, 0 } row, err = strconv.Atoi(s[:pos]) if err != nil { return 0, 0 } col, err = strconv.Atoi(s[pos+1:]) if err != nil { return 0, 0 } return row, col } func processit(b []byte) { if !bytes.HasPrefix(b, []byte{'\033', '['}) { return } if !bytes.HasSuffix(b, []byte{'R'}) { return } s := string(b[2 : len(b)-1]) pos := strings.IndexByte(s, ';') if pos == -1 { return } x, err := strconv.Atoi(s[pos+1:]) if err != nil { return } if x != 1 { fmt.Println("🚫") // U+1F6AB } } func readit() chan []byte { q := make(chan []byte) go func() { b := make([]byte, 1024) n, _ := os.Stdin.Read(b) q <- b[:n] }() return q }