don't use conio.h on windows (#2137)
This commit is contained in:
parent
c40aac8e20
commit
419199bf9a
2 changed files with 63 additions and 21 deletions
|
|
@ -33,27 +33,71 @@ when defined(Windows):
|
|||
stdout.write(prompt)
|
||||
result = readLine(stdin, line)
|
||||
|
||||
import winlean
|
||||
|
||||
const
|
||||
VK_SHIFT* = 16
|
||||
VK_CONTROL* = 17
|
||||
VK_MENU* = 18
|
||||
KEY_EVENT* = 1
|
||||
|
||||
type
|
||||
KEY_EVENT_RECORD = object
|
||||
bKeyDown: WinBool
|
||||
wRepeatCount: uint16
|
||||
wVirtualKeyCode: uint16
|
||||
wVirtualScanCode: uint16
|
||||
unicodeChar: uint16
|
||||
dwControlKeyState: uint32
|
||||
INPUT_RECORD = object
|
||||
eventType*: int16
|
||||
reserved*: int16
|
||||
event*: KEY_EVENT_RECORD
|
||||
safetyBuffer: array[0..5, DWORD]
|
||||
|
||||
proc readConsoleInputW*(hConsoleInput: THANDLE, lpBuffer: var INPUTRECORD,
|
||||
nLength: uint32,
|
||||
lpNumberOfEventsRead: var uint32): WINBOOL{.
|
||||
stdcall, dynlib: "kernel32", importc: "ReadConsoleInputW".}
|
||||
|
||||
proc getch(): uint16 =
|
||||
let hStdin = getStdHandle(STD_INPUT_HANDLE)
|
||||
var
|
||||
irInputRecord: INPUT_RECORD
|
||||
dwEventsRead: uint32
|
||||
|
||||
while readConsoleInputW(hStdin, irInputRecord, 1, dwEventsRead) != 0:
|
||||
if irInputRecord.eventType == KEY_EVENT and
|
||||
irInputRecord.event.wVirtualKeyCode notin {VK_SHIFT, VK_MENU, VK_CONTROL}:
|
||||
result = irInputRecord.event.unicodeChar
|
||||
discard readConsoleInputW(hStdin, irInputRecord, 1, dwEventsRead)
|
||||
return result
|
||||
|
||||
from unicode import toUTF8, Rune, runeLenAt
|
||||
|
||||
proc readPasswordFromStdin*(prompt: string, password: var TaintedString):
|
||||
bool {.tags: [ReadIOEffect, WriteIOEffect].} =
|
||||
## Reads a `password` from stdin without printing it. `password` must not
|
||||
## be ``nil``! Returns ``false`` if the end of the file has been reached,
|
||||
## ``true`` otherwise.
|
||||
proc getch(): cint {.header: "<conio.h>", importc: "_getch".}
|
||||
|
||||
password.setLen(0)
|
||||
var c: char
|
||||
stdout.write(prompt)
|
||||
while true:
|
||||
c = getch().char
|
||||
case c
|
||||
let c = getch()
|
||||
case c.char
|
||||
of '\r', chr(0xA):
|
||||
break
|
||||
of '\b':
|
||||
password.setLen(password.len - 1)
|
||||
# ensure we delete the whole UTF-8 character:
|
||||
var i = 0
|
||||
var x = 1
|
||||
while i < password.len:
|
||||
x = runeLenAt(password, i)
|
||||
inc i, x
|
||||
password.setLen(password.len - x)
|
||||
else:
|
||||
password.add(c)
|
||||
password.add(toUTF8(c.Rune))
|
||||
stdout.write "\n"
|
||||
# TODO: How to detect EOF on Windows?
|
||||
|
||||
else:
|
||||
import readline, history, termios, unsigned
|
||||
|
|
|
|||
|
|
@ -45,7 +45,6 @@ when defined(windows):
|
|||
var
|
||||
oldAttr = getAttributes()
|
||||
|
||||
proc winGetch(): cint {.header: "<conio.h>", importc: "_getch".}
|
||||
else:
|
||||
import termios, unsigned
|
||||
|
||||
|
|
@ -364,12 +363,11 @@ macro styledEcho*(m: varargs[expr]): stmt =
|
|||
result.add(newCall(bindSym"write", bindSym"stdout", newStrLitNode("\n")))
|
||||
result.add(newCall(bindSym"resetAttributes"))
|
||||
|
||||
proc getch*(): char =
|
||||
## Read a single character from the terminal, blocking until it is entered.
|
||||
## The character is not printed to the terminal.
|
||||
when defined(windows):
|
||||
result = winGetch().char
|
||||
else:
|
||||
when not defined(windows):
|
||||
proc getch*(): char =
|
||||
## Read a single character from the terminal, blocking until it is entered.
|
||||
## The character is not printed to the terminal. This is not available for
|
||||
## Windows.
|
||||
let fd = getFileHandle(stdin)
|
||||
var oldMode: Termios
|
||||
discard fd.tcgetattr(addr oldMode)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue