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)
|
stdout.write(prompt)
|
||||||
result = readLine(stdin, line)
|
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):
|
proc readPasswordFromStdin*(prompt: string, password: var TaintedString):
|
||||||
bool {.tags: [ReadIOEffect, WriteIOEffect].} =
|
bool {.tags: [ReadIOEffect, WriteIOEffect].} =
|
||||||
## Reads a `password` from stdin without printing it. `password` must not
|
## Reads a `password` from stdin without printing it. `password` must not
|
||||||
## be ``nil``! Returns ``false`` if the end of the file has been reached,
|
## be ``nil``! Returns ``false`` if the end of the file has been reached,
|
||||||
## ``true`` otherwise.
|
## ``true`` otherwise.
|
||||||
proc getch(): cint {.header: "<conio.h>", importc: "_getch".}
|
|
||||||
|
|
||||||
password.setLen(0)
|
password.setLen(0)
|
||||||
var c: char
|
|
||||||
stdout.write(prompt)
|
stdout.write(prompt)
|
||||||
while true:
|
while true:
|
||||||
c = getch().char
|
let c = getch()
|
||||||
case c
|
case c.char
|
||||||
of '\r', chr(0xA):
|
of '\r', chr(0xA):
|
||||||
break
|
break
|
||||||
of '\b':
|
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:
|
else:
|
||||||
password.add(c)
|
password.add(toUTF8(c.Rune))
|
||||||
stdout.write "\n"
|
stdout.write "\n"
|
||||||
# TODO: How to detect EOF on Windows?
|
|
||||||
|
|
||||||
else:
|
else:
|
||||||
import readline, history, termios, unsigned
|
import readline, history, termios, unsigned
|
||||||
|
|
|
||||||
|
|
@ -45,7 +45,6 @@ when defined(windows):
|
||||||
var
|
var
|
||||||
oldAttr = getAttributes()
|
oldAttr = getAttributes()
|
||||||
|
|
||||||
proc winGetch(): cint {.header: "<conio.h>", importc: "_getch".}
|
|
||||||
else:
|
else:
|
||||||
import termios, unsigned
|
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"write", bindSym"stdout", newStrLitNode("\n")))
|
||||||
result.add(newCall(bindSym"resetAttributes"))
|
result.add(newCall(bindSym"resetAttributes"))
|
||||||
|
|
||||||
proc getch*(): char =
|
when not defined(windows):
|
||||||
|
proc getch*(): char =
|
||||||
## Read a single character from the terminal, blocking until it is entered.
|
## Read a single character from the terminal, blocking until it is entered.
|
||||||
## The character is not printed to the terminal.
|
## The character is not printed to the terminal. This is not available for
|
||||||
when defined(windows):
|
## Windows.
|
||||||
result = winGetch().char
|
|
||||||
else:
|
|
||||||
let fd = getFileHandle(stdin)
|
let fd = getFileHandle(stdin)
|
||||||
var oldMode: Termios
|
var oldMode: Termios
|
||||||
discard fd.tcgetattr(addr oldMode)
|
discard fd.tcgetattr(addr oldMode)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue