Let's summarize things:

  *  **UTF-16** works for input in Windows console, **UTF-8** does not.
  * We must use a **" W"** function in order to get correct input from the 
Windows console. This function uses **UTF-16** and does not actually depend on 
**SetConsoleCP**.
  * **SetConsoleCP(65001)** actually breaks input for **" A"** functions. In 
the following link it is described very well why using **SetConsoleCP(65001)** 
is a bad idea:



[https://stackoverflow.com/questions/14109024/how-to-make-unicode-charset-in-cmd-exe-by-default](https://stackoverflow.com/questions/14109024/how-to-make-unicode-charset-in-cmd-exe-by-default)

  * On the other hand **SetConsoleOutputCP(65001)** is necessary for correct 
output of **UTF-8** strings.
  * **System** module uses binary mode for **stdin** on Windows. This is not 
necessary; in fact it is bad, but it is easily overridden.



Bellow I present a piece of code similar to yours, but which does not utilize 
the Windows API. I hope you will find it interesting:
    
    
    #console.nim
    
    when defined(windows):
      import system/widestrs
      
      proc setMode(fd: int, mode: int): int
           {.importc: "_setmode", header: "io.h".}
      
      proc fgetws(str: WideCString, numChars: int, stream: File): bool
           {.importc, header: "stdio.h".}
      
      discard setMode(getFileHandle(stdin), 0x00020000)  #_O_U16TEXT
      
      proc consoleReadLine(line: var string): bool =
        let buffer = newWideCString("", 256)
        result = fgetws(buffer, 256, stdin)
        if buffer[buffer.len - 1].int16 == 10:  #discard '\n'
          buffer[buffer.len - 1] = Utf16Char(0)
        line = $buffer
      
      proc consoleReadLine(): string =
        discard consoleReadLine(result)
    
    else:
      proc consoleReadLine(line: var string): bool =
        result = stdin.readLine(line)
      
      proc consoleReadLine(): string =
        result = stdin.readLine()
    
    Run

 **setMode(getFileHandle(stdin), 0x00020000)** does the overriding necessary 
for **fgetws** to work.

Now the test code:
    
    
    import console
    
    let s = consoleReadLine()
    echo s.len, ' ', s
    
    Run

Reply via email to