input_windows.go 6.5 KB

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