input.go 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129
  1. package door
  2. import (
  3. "fmt"
  4. "log"
  5. "strconv"
  6. "strings"
  7. "time"
  8. "unicode"
  9. )
  10. // See door.go for DEBUG_INPUT const
  11. var ErrInactivity error = fmt.Errorf("Inactivity")
  12. var ErrTimeout error = fmt.Errorf("Timeout")
  13. var ErrDisconnected error = fmt.Errorf("Disconnected")
  14. var DefaultTimeout time.Duration = time.Duration(60) * time.Second
  15. func (d *Door) WaitKey(timeout time.Duration) (rune, Extended, error) {
  16. /*
  17. d.readerMutex.Lock()
  18. if d.ReaderClosed {
  19. d.readerMutex.Unlock()
  20. return 0, NOP, ErrDisconnected
  21. }
  22. d.readerMutex.Unlock()
  23. */
  24. // Probably faster to just read from closed channel and get ok = false.
  25. select {
  26. case r, ok := <-d.readerChannel:
  27. if ok {
  28. if DEBUG_INPUT {
  29. log.Println("WaitKey:", r)
  30. }
  31. // return bio.GetKey()
  32. return r.R, r.Ex, r.Err
  33. } else {
  34. log.Println("WaitKey: Disconnected")
  35. // Reader has closed.
  36. // Disconnected = true
  37. return 0, NOP, ErrDisconnected
  38. }
  39. case <-time.After(timeout):
  40. return 0, NOP, ErrTimeout
  41. }
  42. }
  43. // Outputs spaces and backspaces
  44. // If you have set a background color, this shows the input area.
  45. func DisplayInput(max int) string {
  46. return strings.Repeat(" ", max) + strings.Repeat("\x08", max)
  47. }
  48. // Input a string of max length.
  49. // This displays the input area if a bg color was set.
  50. // This handles timeout, input, backspace, and enter.
  51. func (d *Door) Input(max int) string {
  52. var line []rune = make([]rune, 0, max)
  53. var length int
  54. // draw input area
  55. d.Write(DisplayInput(max))
  56. var r rune
  57. var ex Extended
  58. var err error
  59. for {
  60. r, ex, err = d.WaitKey(DefaultTimeout)
  61. if err != nil {
  62. // timeout/hangup
  63. return ""
  64. }
  65. if ex != NOP {
  66. continue
  67. }
  68. uw := UnicodeWidth(r)
  69. if strconv.IsPrint(r) {
  70. if length+uw <= max {
  71. d.Write(string(r))
  72. line = append(line, r)
  73. length += uw
  74. } else {
  75. d.Write("\x07")
  76. }
  77. } else {
  78. // Non-print
  79. switch r {
  80. case 0x7f, 0x08:
  81. if len(line) > 0 {
  82. d.Write("\x08 \x08")
  83. rlen := len(line)
  84. if UnicodeWidth(line[rlen-1]) == 2 {
  85. d.Write("\x08 \x08")
  86. length -= 2
  87. } else {
  88. length--
  89. }
  90. line = line[0 : rlen-1]
  91. }
  92. case 0x0d:
  93. return string(line)
  94. }
  95. }
  96. }
  97. }
  98. func (d *Door) GetOneOf(possible string) rune {
  99. var r rune
  100. var err error
  101. for {
  102. r, _, err = d.WaitKey(DefaultTimeout)
  103. if err != nil {
  104. return rune(0)
  105. }
  106. r := unicode.ToUpper(r)
  107. if strings.ContainsRune(possible, r) {
  108. // return upper case rune
  109. return r
  110. }
  111. }
  112. }