runereader_windows.go 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142
  1. package terminal
  2. import (
  3. "bytes"
  4. "syscall"
  5. "unsafe"
  6. )
  7. var (
  8. dll = syscall.NewLazyDLL("kernel32.dll")
  9. setConsoleMode = dll.NewProc("SetConsoleMode")
  10. getConsoleMode = dll.NewProc("GetConsoleMode")
  11. readConsoleInput = dll.NewProc("ReadConsoleInputW")
  12. )
  13. const (
  14. EVENT_KEY = 0x0001
  15. // key codes for arrow keys
  16. // https://msdn.microsoft.com/en-us/library/windows/desktop/dd375731(v=vs.85).aspx
  17. VK_DELETE = 0x2E
  18. VK_END = 0x23
  19. VK_HOME = 0x24
  20. VK_LEFT = 0x25
  21. VK_UP = 0x26
  22. VK_RIGHT = 0x27
  23. VK_DOWN = 0x28
  24. RIGHT_CTRL_PRESSED = 0x0004
  25. LEFT_CTRL_PRESSED = 0x0008
  26. ENABLE_ECHO_INPUT uint32 = 0x0004
  27. ENABLE_LINE_INPUT uint32 = 0x0002
  28. ENABLE_PROCESSED_INPUT uint32 = 0x0001
  29. )
  30. type inputRecord struct {
  31. eventType uint16
  32. padding uint16
  33. event [16]byte
  34. }
  35. type keyEventRecord struct {
  36. bKeyDown int32
  37. wRepeatCount uint16
  38. wVirtualKeyCode uint16
  39. wVirtualScanCode uint16
  40. unicodeChar uint16
  41. wdControlKeyState uint32
  42. }
  43. type runeReaderState struct {
  44. term uint32
  45. }
  46. func newRuneReaderState(input FileReader) runeReaderState {
  47. return runeReaderState{}
  48. }
  49. func (rr *RuneReader) Buffer() *bytes.Buffer {
  50. return nil
  51. }
  52. func (rr *RuneReader) SetTermMode() error {
  53. r, _, err := getConsoleMode.Call(uintptr(rr.stdio.In.Fd()), uintptr(unsafe.Pointer(&rr.state.term)))
  54. // windows return 0 on error
  55. if r == 0 {
  56. return err
  57. }
  58. newState := rr.state.term
  59. newState &^= ENABLE_ECHO_INPUT | ENABLE_LINE_INPUT | ENABLE_PROCESSED_INPUT
  60. r, _, err = setConsoleMode.Call(uintptr(rr.stdio.In.Fd()), uintptr(newState))
  61. // windows return 0 on error
  62. if r == 0 {
  63. return err
  64. }
  65. return nil
  66. }
  67. func (rr *RuneReader) RestoreTermMode() error {
  68. r, _, err := setConsoleMode.Call(uintptr(rr.stdio.In.Fd()), uintptr(rr.state.term))
  69. // windows return 0 on error
  70. if r == 0 {
  71. return err
  72. }
  73. return nil
  74. }
  75. func (rr *RuneReader) ReadRune() (rune, int, error) {
  76. ir := &inputRecord{}
  77. bytesRead := 0
  78. for {
  79. rv, _, e := readConsoleInput.Call(rr.stdio.In.Fd(), uintptr(unsafe.Pointer(ir)), 1, uintptr(unsafe.Pointer(&bytesRead)))
  80. // windows returns non-zero to indicate success
  81. if rv == 0 && e != nil {
  82. return 0, 0, e
  83. }
  84. if ir.eventType != EVENT_KEY {
  85. continue
  86. }
  87. // the event data is really a c struct union, so here we have to do an usafe
  88. // cast to put the data into the keyEventRecord (since we have already verified
  89. // above that this event does correspond to a key event
  90. key := (*keyEventRecord)(unsafe.Pointer(&ir.event[0]))
  91. // we only care about key down events
  92. if key.bKeyDown == 0 {
  93. continue
  94. }
  95. if key.wdControlKeyState&(LEFT_CTRL_PRESSED|RIGHT_CTRL_PRESSED) != 0 && key.unicodeChar == 'C' {
  96. return KeyInterrupt, bytesRead, nil
  97. }
  98. // not a normal character so look up the input sequence from the
  99. // virtual key code mappings (VK_*)
  100. if key.unicodeChar == 0 {
  101. switch key.wVirtualKeyCode {
  102. case VK_DOWN:
  103. return KeyArrowDown, bytesRead, nil
  104. case VK_LEFT:
  105. return KeyArrowLeft, bytesRead, nil
  106. case VK_RIGHT:
  107. return KeyArrowRight, bytesRead, nil
  108. case VK_UP:
  109. return KeyArrowUp, bytesRead, nil
  110. case VK_DELETE:
  111. return SpecialKeyDelete, bytesRead, nil
  112. case VK_HOME:
  113. return SpecialKeyHome, bytesRead, nil
  114. case VK_END:
  115. return SpecialKeyEnd, bytesRead, nil
  116. default:
  117. // not a virtual key that we care about so just continue on to
  118. // the next input key
  119. continue
  120. }
  121. }
  122. r := rune(key.unicodeChar)
  123. return r, bytesRead, nil
  124. }
  125. }