| 1 | // Copyright (c) 2019-2024 Alexander Medvednikov. All rights reserved. |
| 2 | // Use of this source code is governed by an MIT license |
| 3 | // that can be found in the LICENSE file. |
| 4 | // |
| 5 | // Serves as more advanced input method |
| 6 | // based on the work of https://github.com/AmokHuginnsson/replxx |
| 7 | // |
| 8 | module termios |
| 9 | |
| 10 | #include <termios.h> |
| 11 | #include <sys/ioctl.h> |
| 12 | |
| 13 | // https://web.mit.edu/freebsd/head/sys/sys/_termios.h |
| 14 | |
| 15 | const cclen = 20 |
| 16 | |
| 17 | type TcFlag = int |
| 18 | type Speed = int |
| 19 | type Cc = u8 |
| 20 | |
| 21 | // Termios stores the terminal options |
| 22 | pub struct C.termios { |
| 23 | mut: |
| 24 | c_iflag TcFlag |
| 25 | c_oflag TcFlag |
| 26 | c_cflag TcFlag |
| 27 | c_lflag TcFlag |
| 28 | c_cc [cclen]Cc |
| 29 | } |
| 30 | |
| 31 | fn C.tcgetattr(fd i32, termios_p &C.termios) i32 |
| 32 | |
| 33 | fn C.tcsetattr(fd i32, optional_actions i32, const_termios_p &C.termios) i32 |
| 34 | |
| 35 | fn C.ioctl(fd i32, request u64, args ...voidptr) i32 |
| 36 | |
| 37 | // flag provides a termios flag of the correct size |
| 38 | // for the underlying C.termios structure |
| 39 | @[inline] |
| 40 | pub fn flag(value int) TcFlag { |
| 41 | return int(value) |
| 42 | } |
| 43 | |
| 44 | // invert is a platform dependant way to bitwise NOT (~) TcFlag |
| 45 | // as its length varies across platforms |
| 46 | @[inline] |
| 47 | pub fn invert(value TcFlag) TcFlag { |
| 48 | return ~int(value) |
| 49 | } |
| 50 | |
| 51 | pub struct Termios { |
| 52 | pub mut: |
| 53 | c_iflag TcFlag |
| 54 | c_oflag TcFlag |
| 55 | c_cflag TcFlag |
| 56 | c_lflag TcFlag |
| 57 | c_cc [cclen]Cc |
| 58 | } |
| 59 | |
| 60 | // tcgetattr is an unsafe wrapper around C.termios and keeps its semantic |
| 61 | @[inline] |
| 62 | pub fn tcgetattr(fd int, mut termios_p Termios) int { |
| 63 | unsafe { |
| 64 | return C.tcgetattr(fd, &C.termios(termios_p)) |
| 65 | } |
| 66 | } |
| 67 | |
| 68 | // tcsetattr is an unsafe wrapper around C.termios and keeps its semantic |
| 69 | @[inline] |
| 70 | pub fn tcsetattr(fd int, optional_actions int, mut termios_p Termios) int { |
| 71 | unsafe { |
| 72 | return C.tcsetattr(fd, optional_actions, &C.termios(termios_p)) |
| 73 | } |
| 74 | } |
| 75 | |
| 76 | // ioctl is an unsafe wrapper around C.ioctl and keeps its semantic |
| 77 | @[inline] |
| 78 | pub fn ioctl(fd int, request u64, arg voidptr) int { |
| 79 | unsafe { |
| 80 | return C.ioctl(fd, request, arg) |
| 81 | } |
| 82 | } |
| 83 | |
| 84 | // set_state applies the flags in the `new_state` to the descriptor `fd`. |
| 85 | pub fn set_state(fd int, new_state Termios) int { |
| 86 | mut x := new_state |
| 87 | return tcsetattr(0, C.TCSANOW, mut x) |
| 88 | } |
| 89 | |
| 90 | // disable_echo disables echoing characters as they are typed, when that Termios state is later set with termios.set_state(fd,t). |
| 91 | pub fn (mut t Termios) disable_echo() { |
| 92 | t.c_lflag &= invert(C.ECHO) |
| 93 | } |
| 94 | |