diff options
author | Araq <rumpf_a@web.de> | 2015-03-08 14:45:06 +0100 |
---|---|---|
committer | Araq <rumpf_a@web.de> | 2015-03-08 14:45:06 +0100 |
commit | 419199bf9ae507c104d497e1714ceedf300dc38e (patch) | |
tree | 9312e43b63a42c07234cb0a484389e07157ea2c3 | |
parent | c40aac8e2036924ec88bec9c44a33a044f346baa (diff) | |
download | Nim-419199bf9ae507c104d497e1714ceedf300dc38e.tar.gz |
don't use conio.h on windows (#2137)
-rw-r--r-- | lib/impure/rdstdin.nim | 66 | ||||
-rw-r--r-- | lib/pure/terminal.nim | 18 |
2 files changed, 63 insertions, 21 deletions
diff --git a/lib/impure/rdstdin.nim b/lib/impure/rdstdin.nim index aaf2ed1ca..f64f9ccb2 100644 --- a/lib/impure/rdstdin.nim +++ b/lib/impure/rdstdin.nim @@ -8,16 +8,16 @@ # ## This module contains code for reading from `stdin`:idx:. On UNIX the GNU -## readline library is wrapped and set up to provide default key bindings +## readline library is wrapped and set up to provide default key bindings ## (e.g. you can navigate with the arrow keys). On Windows ``system.readLine`` -## is used. This suffices because Windows' console already provides the +## is used. This suffices because Windows' console already provides the ## wanted functionality. {.deadCodeElim: on.} when defined(Windows): proc readLineFromStdin*(prompt: string): TaintedString {. - tags: [ReadIOEffect, WriteIOEffect].} = + tags: [ReadIOEffect, WriteIOEffect].} = ## Reads a line from stdin. stdout.write(prompt) result = readLine(stdin) @@ -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 diff --git a/lib/pure/terminal.nim b/lib/pure/terminal.nim index e0e2aa247..df637dcb6 100644 --- a/lib/pure/terminal.nim +++ b/lib/pure/terminal.nim @@ -45,7 +45,6 @@ when defined(windows): var oldAttr = getAttributes() - proc winGetch(): cint {.header: "<conio.h>", importc: "_getch".} else: import termios, unsigned @@ -344,7 +343,7 @@ proc isatty*(f: File): bool = else: proc isatty(fildes: FileHandle): cint {. importc: "_isatty", header: "<io.h>".} - + result = isatty(getFileHandle(f)) != 0'i32 proc styledEchoProcessArg(s: string) = write stdout, s @@ -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) @@ -387,5 +385,5 @@ when isMainModule: setForeGroundColor(fgBlue) writeln(stdout, "ordinary text") - styledEcho("styled text ", {styleBright, styleBlink, styleUnderscore}) - + styledEcho("styled text ", {styleBright, styleBlink, styleUnderscore}) + |