-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathTerminal.fs
144 lines (118 loc) · 4.03 KB
/
Terminal.fs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
module Terminal
#nowarn "9"
open System
open System.Runtime.InteropServices
open Microsoft.FSharp.NativeInterop
#if INTERACTIVE
#else
type OS =
| Linux
| MacOS
| Windows
let currentOS =
if RuntimeInformation.IsOSPlatform(OSPlatform.Linux) then
Linux
else if RuntimeInformation.IsOSPlatform(OSPlatform.OSX) then
MacOS
else if RuntimeInformation.IsOSPlatform(OSPlatform.Windows) then
Windows
else
raise (PlatformNotSupportedException ("Couldn't detect your OS"))
//#region DisableEcho
[<DllImport("Kernel32")>]
extern void* GetStdHandle(int nStdHandle)
[<DllImport("Kernel32")>]
extern bool GetConsoleMode(void* hConsoleHandle, int* lpMode)
[<DllImport("Kernel32")>]
extern bool SetConsoleMode(void* hConsoleHandle, int lpMode)
let private disableTerminalEchoWindows () =
let INVALID_HANDLE_VALUE = nativeint -1
let STD_OUTPUT_HANDLE = -11
let ENABLE_VIRTUAL_TERMINAL_PROCESSING = 0x0004
let ENABLE_ECHO_INPUT = 0x0004
let handle = GetStdHandle(STD_OUTPUT_HANDLE)
if handle <> INVALID_HANDLE_VALUE then
let mode = NativePtr.stackalloc<int> 1
if GetConsoleMode(handle, mode) then
let value = NativePtr.read mode
let value = value &&& (~~~ENABLE_ECHO_INPUT)
if SetConsoleMode (handle, value) |> not then
failwith "Couldn't set console mode"
else
failwith "Couldn't get"
else
failwith "Couldn't get handle"
[<DllImport("libc")>]
extern int tcgetattr(int fd, void* termios_data);
[<DllImport("libc")>]
extern int tcsetattr(int fd, int optional_actions, void* termios_data);
// 4 * 4 + 20 * 4 + 2 * 4
[<Struct>]
[<StructLayout(LayoutKind.Sequential, Size = 104)>]
type private Termios =
//[<MarshalAs(UnmanagedType.ByValArray, SizeConst=128)>]
[<MarshalAs(UnmanagedType.U4)>]
val c_iflag : System.UInt32
[<MarshalAs(UnmanagedType.U4)>]
val c_oflag : System.UInt32
[<MarshalAs(UnmanagedType.U4)>]
val c_cflag : System.UInt32
[<MarshalAs(UnmanagedType.U4)>]
// 20 * 4
val mutable c_lflag : System.UInt32
[<MarshalAs(UnmanagedType.ByValArray, SizeConst = 80)>]
val c_cc : System.Byte []
[<MarshalAs(UnmanagedType.U4)>]
val c_ispeed : System.UInt32
[<MarshalAs(UnmanagedType.U4)>]
val c_ospeed : System.UInt32
let private disableTerminalEchoLinux () =
let ECHO = 8u
let TCSANOW = 0
let TCSAFLUSH = 2
let ptr = Marshal.AllocHGlobal(Marshal.SizeOf(typeof<Termios>))
Marshal.StructureToPtr (Termios (), ptr, false)
tcgetattr(0, ptr) |> ignore
let mutable str : Termios = Marshal.PtrToStructure ptr
str.c_lflag <- str.c_lflag &&& (~~~ECHO)
//let pt2 = Marshal.AllocHGlobal(Marshal.SizeOf(typeof<Termios>))
Marshal.StructureToPtr (str, ptr, true)
tcsetattr (0, TCSAFLUSH, ptr) |> ignore
Marshal.FreeHGlobal (ptr)
let disableTerminalEcho () =
match currentOS with
| Linux
| MacOS -> disableTerminalEchoLinux ()
| Windows -> disableTerminalEchoWindows ()
#endif
let draw x y (fg: System.ConsoleColor) (bg:System.ConsoleColor) (symbol: string option) =
Console.SetCursorPosition (x, y)
Console.BackgroundColor <- bg
Console.ForegroundColor <- fg
match symbol with
| Some s ->
printf "%s" s
| None ->
printf " "
System.Console.SetCursorPosition (0, 24)
let print (bg: System.ConsoleColor option) (fg: System.ConsoleColor option) (s : string) =
match (fg, bg) with
| (Some fg, Some bg) ->
Console.ForegroundColor <- fg
Console.BackgroundColor <- bg
| (None, Some bg) ->
Console.ResetColor ()
Console.BackgroundColor <- bg
| (Some fg, None) ->
Console.ResetColor ()
Console.ForegroundColor <- fg
| (None, None) ->
Console.ResetColor ()
s
|> printf "%s"
let printDefault = print None None
let printWithBackground bg = print (Some bg) None
let printWithForeground fg = print None (Some fg)
let flush () =
while (Console.KeyAvailable) do
Console.ReadKey(true) |> ignore