package door import ( "fmt" "log" "strconv" "strings" "time" "unicode" ) // For debugging input reader routines. const DEBUG_INPUT = false var ErrInactivity error = fmt.Errorf("Inactivity") var ErrTimeout error = fmt.Errorf("Timeout") var ErrDisconnected error = fmt.Errorf("Disconnected") var DefaultTimeout time.Duration = time.Duration(60) * time.Second func (d *Door) WaitKey(timeout time.Duration) (rune, Extended, error) { /* d.readerMutex.Lock() if d.ReaderClosed { d.readerMutex.Unlock() return 0, NOP, ErrDisconnected } d.readerMutex.Unlock() */ // Probably faster to just read from closed channel and get ok = false. select { case r, ok := <-d.readerChannel: if ok { if DEBUG_INPUT { log.Println("WaitKey:", r) } // return bio.GetKey() return r.R, r.Ex, r.Err } else { log.Println("WaitKey: Disconnected") // Reader has closed. // Disconnected = true return 0, NOP, ErrDisconnected } case <-time.After(timeout): return 0, NOP, ErrTimeout } } // Outputs spaces and backspaces // If you have set a background color, this shows the input area. func DisplayInput(max int) string { return strings.Repeat(" ", max) + strings.Repeat("\x08", max) } // Input a string of max length. // This displays the input area if a bg color was set. // This handles timeout, input, backspace, and enter. func (d *Door) Input(max int) string { var line []rune = make([]rune, 0, max) var length int // draw input area d.Write(DisplayInput(max)) var r rune var ex Extended var err error for { r, ex, err = d.WaitKey(DefaultTimeout) if err != nil { // timeout/hangup return "" } if ex != NOP { continue } uw := UnicodeWidth(r) if strconv.IsPrint(r) { if length+uw <= max { d.Write(string(r)) line = append(line, r) length += uw } else { d.Write("\x07") } } else { // Non-print switch r { case 0x7f, 0x08: if len(line) > 0 { d.Write("\x08 \x08") rlen := len(line) if UnicodeWidth(line[rlen-1]) == 2 { d.Write("\x08 \x08") length -= 2 } else { length-- } line = line[0 : rlen-1] } case 0x0d: return string(line) } } } } func (d *Door) GetOneOf(possible string) rune { var r rune var err error for { r, _, err = d.WaitKey(DefaultTimeout) if err != nil { return rune(0) } r := unicode.ToUpper(r) if strings.ContainsRune(possible, r) { // return upper case rune return r } } }