input_windows.go 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362
  1. package door
  2. import (
  3. "log"
  4. "strconv"
  5. "strings"
  6. "syscall"
  7. "time"
  8. )
  9. // This is the current list of Extended keys we support:
  10. const (
  11. XKEY_UP_ARROW = 0x1001
  12. XKEY_DOWN_ARROW = 0x1002
  13. XKEY_RIGHT_ARROW = 0x1003
  14. XKEY_LEFT_ARROW = 0x1004
  15. XKEY_HOME = 0x1010
  16. XKEY_END = 0x1011
  17. XKEY_PGUP = 0x1012
  18. XKEY_PGDN = 0x1023
  19. XKEY_INSERT = 0x1024
  20. XKEY_DELETE = 0x7f
  21. XKEY_F1 = 0x1021
  22. XKEY_F2 = 0x1022
  23. XKEY_F3 = 0x1023
  24. XKEY_F4 = 0x1024
  25. XKEY_F5 = 0x1025
  26. XKEY_F6 = 0x1026
  27. XKEY_F7 = 0x1027
  28. XKEY_F8 = 0x1028
  29. XKEY_F9 = 0x1029
  30. XKEY_F10 = 0x102a
  31. XKEY_F11 = 0x102b
  32. XKEY_F12 = 0x102c
  33. XKEY_UNKNOWN = 0x1111
  34. )
  35. // go routine to read from the socket
  36. var readerChannel chan byte
  37. func Reader(handle syscall.Handle) {
  38. buffer := make([]byte, 1)
  39. WSA_Buffer := syscall.WSABuf{Len: 1, Buf: &buffer[0]}
  40. read := uint32(0)
  41. flags := uint32(0)
  42. for {
  43. err := syscall.WSARecv(handle, &WSA_Buffer, 1, &read, &flags, nil, nil)
  44. if err != nil {
  45. log.Printf("Reader ERR: %#v\n", err)
  46. break
  47. }
  48. if read == 1 {
  49. readerChannel <- buffer[0]
  50. } else {
  51. log.Printf("READ FAILED %d\n", read)
  52. close(readerChannel)
  53. break
  54. }
  55. }
  56. }
  57. // Low level read key function.
  58. // This gets the raw keys from the client, it doesn't handle extended keys,
  59. // functions, arrows.
  60. // Return key, or -1 (Timeout/No key available), -2 hangup
  61. func (d *Door) getch() int {
  62. select {
  63. case res, ok := <-readerChannel:
  64. if ok {
  65. return int(res)
  66. } else {
  67. d.Disconnected = true
  68. return -2
  69. }
  70. case <-time.After(time.Duration(100) * time.Millisecond):
  71. return -1
  72. }
  73. }
  74. func (d *Door) getkey_or_pushback() int {
  75. if !d.Pushback.Empty() {
  76. return d.Pushback.Pop()
  77. }
  78. if false {
  79. key := d.getch()
  80. log.Printf("%d / %X\n", key, key)
  81. return key
  82. } else {
  83. return d.getch()
  84. }
  85. }
  86. // Return key received, or XKEY_* values.
  87. // -1 timeout/no key
  88. // -2 hangup
  89. // -3 out of time
  90. func (d *Door) GetKey() int {
  91. var c, c2 int
  92. if d.Disconnected {
  93. return -2
  94. }
  95. if d.TimeLeft() < 0 {
  96. return -3
  97. }
  98. c = d.getkey_or_pushback()
  99. if c < 0 {
  100. return c
  101. }
  102. // We get 0x0d 0x00, or 0x0d 0x0a from syncterm.
  103. if c == 0x0d {
  104. c2 = d.getkey_or_pushback()
  105. if c2 > 0 {
  106. // wasn't an error
  107. if c2 != 0x00 && c2 != 0x0a {
  108. // wasn't 0x00 or 0x0a
  109. d.Pushback.Push(c2)
  110. // log.Printf("Push 0x0d trailer %d / %x\n", c2, c2)
  111. }
  112. }
  113. return c
  114. }
  115. if c == 0 {
  116. // possibly doorway mode
  117. tries := 0
  118. c2 = d.getkey_or_pushback()
  119. for c2 < 0 {
  120. if tries > 7 {
  121. return c
  122. }
  123. c2 = d.getkey_or_pushback()
  124. tries++
  125. }
  126. switch c2 {
  127. case 0x50:
  128. return XKEY_DOWN_ARROW
  129. case 0x48:
  130. return XKEY_UP_ARROW
  131. case 0x4b:
  132. return XKEY_LEFT_ARROW
  133. case 0x4d:
  134. return XKEY_RIGHT_ARROW
  135. case 0x47:
  136. return XKEY_HOME
  137. case 0x4f:
  138. return XKEY_END
  139. case 0x49:
  140. return XKEY_PGUP
  141. case 0x51:
  142. return XKEY_PGDN
  143. case 0x3b:
  144. return XKEY_F1
  145. case 0x3c:
  146. return XKEY_F2
  147. case 0x3d:
  148. return XKEY_F3
  149. case 0x3e:
  150. return XKEY_F4
  151. case 0x3f:
  152. return XKEY_F5
  153. case 0x40:
  154. return XKEY_F6
  155. case 0x41:
  156. return XKEY_F7
  157. case 0x42:
  158. return XKEY_F8
  159. case 0x43:
  160. return XKEY_F9
  161. case 0x44:
  162. return XKEY_F10
  163. /*
  164. case 0x45:
  165. return XKEY_F11
  166. case 0x46:
  167. return XKEY_F12
  168. */
  169. case 0x52:
  170. return XKEY_INSERT
  171. case 0x53:
  172. return XKEY_DELETE
  173. default:
  174. log.Printf("ERROR Doorway mode: 0x00 %x\n", c2)
  175. return XKEY_UNKNOWN
  176. }
  177. }
  178. if c == 0x1b {
  179. // Escape key?
  180. c2 = d.getkey_or_pushback()
  181. if c2 < 0 {
  182. // Just escape key
  183. return c
  184. }
  185. var extended string = string(byte(c2))
  186. c2 = d.getkey_or_pushback()
  187. for c2 > 0 {
  188. if c2 == 0x1b {
  189. d.Pushback.Push(c2)
  190. break
  191. }
  192. extended += string(byte(c2))
  193. c2 = d.getkey_or_pushback()
  194. }
  195. switch extended {
  196. case "[A":
  197. return XKEY_UP_ARROW
  198. case "[B":
  199. return XKEY_DOWN_ARROW
  200. case "[C":
  201. return XKEY_RIGHT_ARROW
  202. case "[D":
  203. return XKEY_LEFT_ARROW
  204. case "[H":
  205. return XKEY_HOME
  206. case "[F":
  207. return XKEY_END // terminal
  208. case "[K":
  209. return XKEY_END
  210. case "[V":
  211. return XKEY_PGUP
  212. case "[U":
  213. return XKEY_PGDN
  214. case "[@":
  215. return XKEY_INSERT
  216. case "[1":
  217. // Syncterm is lost, could be F1..F5?
  218. log.Printf("ERROR (Syncterm) Extended %#v\n", extended)
  219. return XKEY_UNKNOWN
  220. case "[2~":
  221. return XKEY_INSERT // terminal
  222. case "[3~":
  223. return XKEY_DELETE // terminal
  224. case "[5~":
  225. return XKEY_PGUP // terminal
  226. case "[6~":
  227. return XKEY_PGDN // terminal
  228. case "[15~":
  229. return XKEY_F5 // terminal
  230. case "[17~":
  231. return XKEY_F6 // terminal
  232. case "[18~":
  233. return XKEY_F7 // terminal
  234. case "[19~":
  235. return XKEY_F8 // terminal
  236. case "[20~":
  237. return XKEY_F9 // terminal
  238. case "[21~":
  239. return XKEY_F10 // terminal
  240. case "[23~":
  241. return XKEY_F11
  242. case "[24~":
  243. return XKEY_F12 // terminal
  244. case "OP":
  245. return XKEY_F1
  246. case "OQ":
  247. return XKEY_F2
  248. case "OR":
  249. return XKEY_F3
  250. case "OS":
  251. return XKEY_F4
  252. case "Ot":
  253. return XKEY_F5 // syncterm
  254. default:
  255. log.Printf("ERROR Extended %#v\n", extended)
  256. return XKEY_UNKNOWN
  257. }
  258. }
  259. return c
  260. }
  261. func (d *Door) Key() int {
  262. return d.WaitKey(Inactivity, 0)
  263. }
  264. func (d *Door) WaitKey(secs int64, usecs int64) int {
  265. if d.Disconnected {
  266. return -2
  267. }
  268. if !d.Pushback.Empty() {
  269. return d.GetKey()
  270. }
  271. timeout := time.Duration(secs)*time.Second + time.Duration(usecs)*time.Millisecond
  272. select {
  273. case res, ok := <-readerChannel:
  274. if ok {
  275. d.Pushback.Push(int(res))
  276. return d.GetKey()
  277. } else {
  278. d.Disconnected = true
  279. return -2
  280. }
  281. case <-time.After(timeout):
  282. return -1
  283. }
  284. }
  285. // Outputs spaces and backspaces
  286. // If you have set a background color, this shows the input area.
  287. func DisplayInput(max int) string {
  288. return strings.Repeat(" ", max) + strings.Repeat("\x08", max)
  289. }
  290. // Input a string of max length.
  291. // This displays the input area if a bg color was set.
  292. // This handles timeout, input, backspace, and enter.
  293. func (d *Door) Input(max int) string {
  294. var line string
  295. // draw input area
  296. d.Write(DisplayInput(max))
  297. var c int
  298. for true {
  299. c = d.WaitKey(Inactivity, 0)
  300. if c < 0 {
  301. // timeout/hangup
  302. return ""
  303. }
  304. if c > 1000 {
  305. continue
  306. }
  307. if strconv.IsPrint(rune(c)) {
  308. if len(line) < max {
  309. d.Write(string(byte(c)))
  310. line += string(byte(c))
  311. } else {
  312. d.Write("\x07")
  313. }
  314. } else {
  315. // Non-print
  316. switch c {
  317. case 0x7f, 0x08:
  318. if len(line) > 0 {
  319. d.Write("\x08 \x08")
  320. line = line[:len(line)-1]
  321. }
  322. case 0x0d:
  323. return line
  324. }
  325. }
  326. }
  327. // this is never reached
  328. return line
  329. }