| // +build windows |
| |
| package readline |
| |
| import "unsafe" |
| |
| const ( |
| VK_CANCEL = 0x03 |
| VK_BACK = 0x08 |
| VK_TAB = 0x09 |
| VK_RETURN = 0x0D |
| VK_SHIFT = 0x10 |
| VK_CONTROL = 0x11 |
| VK_MENU = 0x12 |
| VK_ESCAPE = 0x1B |
| VK_LEFT = 0x25 |
| VK_UP = 0x26 |
| VK_RIGHT = 0x27 |
| VK_DOWN = 0x28 |
| VK_DELETE = 0x2E |
| VK_LSHIFT = 0xA0 |
| VK_RSHIFT = 0xA1 |
| VK_LCONTROL = 0xA2 |
| VK_RCONTROL = 0xA3 |
| ) |
| |
| // RawReader translate input record to ANSI escape sequence. |
| // To provides same behavior as unix terminal. |
| type RawReader struct { |
| ctrlKey bool |
| altKey bool |
| } |
| |
| func NewRawReader() *RawReader { |
| r := new(RawReader) |
| return r |
| } |
| |
| // only process one action in one read |
| func (r *RawReader) Read(buf []byte) (int, error) { |
| ir := new(_INPUT_RECORD) |
| var read int |
| var err error |
| next: |
| err = kernel.ReadConsoleInputW(stdin, |
| uintptr(unsafe.Pointer(ir)), |
| 1, |
| uintptr(unsafe.Pointer(&read)), |
| ) |
| if err != nil { |
| return 0, err |
| } |
| if ir.EventType != EVENT_KEY { |
| goto next |
| } |
| ker := (*_KEY_EVENT_RECORD)(unsafe.Pointer(&ir.Event[0])) |
| if ker.bKeyDown == 0 { // keyup |
| if r.ctrlKey || r.altKey { |
| switch ker.wVirtualKeyCode { |
| case VK_RCONTROL, VK_LCONTROL: |
| r.ctrlKey = false |
| case VK_MENU: //alt |
| r.altKey = false |
| } |
| } |
| goto next |
| } |
| |
| if ker.unicodeChar == 0 { |
| var target rune |
| switch ker.wVirtualKeyCode { |
| case VK_RCONTROL, VK_LCONTROL: |
| r.ctrlKey = true |
| case VK_MENU: //alt |
| r.altKey = true |
| case VK_LEFT: |
| target = CharBackward |
| case VK_RIGHT: |
| target = CharForward |
| case VK_UP: |
| target = CharPrev |
| case VK_DOWN: |
| target = CharNext |
| } |
| if target != 0 { |
| return r.write(buf, target) |
| } |
| goto next |
| } |
| char := rune(ker.unicodeChar) |
| if r.ctrlKey { |
| switch char { |
| case 'A': |
| char = CharLineStart |
| case 'E': |
| char = CharLineEnd |
| case 'R': |
| char = CharBckSearch |
| case 'S': |
| char = CharFwdSearch |
| } |
| } else if r.altKey { |
| switch char { |
| case VK_BACK: |
| char = CharBackspace |
| } |
| return r.writeEsc(buf, char) |
| } |
| return r.write(buf, char) |
| } |
| |
| func (r *RawReader) writeEsc(b []byte, char rune) (int, error) { |
| b[0] = '\033' |
| n := copy(b[1:], []byte(string(char))) |
| return n + 1, nil |
| } |
| |
| func (r *RawReader) write(b []byte, char rune) (int, error) { |
| n := copy(b, []byte(string(char))) |
| return n, nil |
| } |
| |
| func (r *RawReader) Close() error { |
| return nil |
| } |