console/raw_console
Code
main.odin ¶92 linesSource
1package main
2
3import "core:fmt"
4import "core:io"
5import "core:os"
6import "core:time"
7import "core:unicode/utf8"
8
9get_password :: proc(allocator := context.allocator) -> string {
10
11 fmt.print("Enter password: ")
12
13 buf := make([dynamic]byte, allocator)
14 in_stream := os.to_stream(os.stdin)
15
16 for {
17 // Read a single character at a time.
18 ch, sz, err := io.read_rune(in_stream)
19 switch {
20 case err != nil:
21 fmt.eprintfln("\nError: %v", err)
22 os.exit(1)
23
24 // End line
25 case ch == '\n': // Posix
26 fallthrough
27 case ch == '\r': // Windows
28 fmt.println()
29 return string(buf[:])
30
31 // Backspace
32 case ch == '\u007f': // Posix
33 fallthrough
34 case ch == '\b': // Windows
35 _, bs_sz := utf8.decode_last_rune(buf[:])
36 if bs_sz > 0 {
37 resize(&buf, len(buf)-bs_sz)
38 // Replace last star with a space.
39 fmt.print("\b \b")
40 }
41 case:
42 bytes, _ := utf8.encode_rune(ch)
43 append(&buf, ..bytes[:sz])
44
45 fmt.print('*')
46 }
47 }
48}
49
50draw_progress_bar :: proc(title: string, percent: int, width := 25) {
51 fmt.printf("\r%v[", title, flush=false) // Put cursor back at the start of the line
52
53 done := percent * width / 100
54 left := width - done
55 for _ in 0..<done {
56 fmt.printf("|", flush=false)
57 }
58 for _ in 0..<left {
59 fmt.printf(" ", flush=false)
60 }
61 fmt.printf("] %d%%", percent)
62}
63
64main :: proc() {
65 set_utf8_terminal()
66
67 enable_raw_mode()
68 defer disable_raw_mode()
69
70 password := get_password()
71 defer delete(password)
72
73 for i in 0..=100 {
74 draw_progress_bar("Processing login: ", i)
75 time.sleep(50 * time.Millisecond)
76 }
77 fmt.println("\nDone")
78
79 fmt.printfln("\nYour password was: \"%s\"", password)
80}
81
82enable_raw_mode :: proc() {
83 _enable_raw_mode()
84}
85
86disable_raw_mode :: proc "c" () {
87 _disable_raw_mode()
88}
89
90set_utf8_terminal :: proc() {
91 _set_utf8_terminal()
92}
raw_posix.odin ¶ !windows30 linesSource
1#+build !windows
2package main
3
4import psx "core:sys/posix"
5
6@(private="file")
7orig_mode: psx.termios
8
9_enable_raw_mode :: proc() {
10 // Get the original terminal attributes.
11 res := psx.tcgetattr(psx.STDIN_FILENO, &orig_mode)
12 assert(res == .OK)
13
14 // Reset to the original attributes at the end of the program.
15 psx.atexit(disable_raw_mode)
16
17 // Copy, and remove the
18 // ECHO (so what is typed is not shown) and
19 // ICANON (so we get each input instead of an entire line at once) flags.
20 raw := orig_mode
21 raw.c_lflag -= {.ECHO, .ICANON}
22 res = psx.tcsetattr(psx.STDIN_FILENO, .TCSANOW, &raw)
23 assert(res == .OK)
24}
25
26_disable_raw_mode :: proc "c" () {
27 psx.tcsetattr(psx.STDIN_FILENO, .TCSANOW, &orig_mode)
28}
29
30_set_utf8_terminal :: proc() {}
raw_windows.odin ¶41 linesSource
1package main
2
3import "core:c/libc"
4import win32 "core:sys/windows"
5
6@(private="file")
7orig_mode: win32.DWORD
8
9_enable_raw_mode :: proc() {
10 // Get a handle to the standard input.
11 stdin := win32.GetStdHandle(win32.STD_INPUT_HANDLE)
12 assert(stdin != win32.INVALID_HANDLE_VALUE)
13
14 // Get the original terminal mode.
15 ok := win32.GetConsoleMode(stdin, &orig_mode)
16 assert(ok == true)
17
18 // Reset to the original attributes at the end of the program.
19 libc.atexit(disable_raw_mode)
20
21 // Copy, and remove the
22 // ENABLE_ECHO_INPUT (so what is typed is not shown) and
23 // ENABLE_LINE_INPUT (so we get each input instead of an entire line at once) flags.
24 raw := orig_mode
25 raw &= ~win32.ENABLE_ECHO_INPUT
26 raw &= ~win32.ENABLE_LINE_INPUT
27 ok = win32.SetConsoleMode(stdin, raw)
28 assert(ok == true)
29}
30
31_disable_raw_mode :: proc "c" () {
32 stdin := win32.GetStdHandle(win32.STD_INPUT_HANDLE)
33 assert_contextless(stdin != win32.INVALID_HANDLE_VALUE)
34
35 win32.SetConsoleMode(stdin, orig_mode)
36}
37
38_set_utf8_terminal :: proc() {
39 win32.SetConsoleOutputCP(.UTF8)
40 win32.SetConsoleCP(.UTF8)
41}
Declarations Used 29
- core:c/libc atexit
- core:fmt eprintfln · print · printf · printfln · println
- core:io read_rune
- core:os exit · stdin · to_stream
- core:sys/posix atexit · STDIN_FILENO · tcgetattr · tcsetattr · termios
- core:sys/windows DWORD · ENABLE_ECHO_INPUT · ENABLE_LINE_INPUT · GetConsoleMode · GetStdHandle · INVALID_HANDLE_VALUE · SetConsoleCP · SetConsoleMode · SetConsoleOutputCP · STD_INPUT_HANDLE
- core:time Millisecond · sleep
- core:unicode/utf8 decode_last_rune · encode_rune