Legend:
Page
Library
Module
Module type
Parameter
Class
Class type
Source
Page
Library
Module
Module type
Parameter
Class
Class type
Source
terminal_util.ml
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
open Ochalk let get_1_char = let termio = Unix.tcgetattr Unix.stdin in let () = termio.Unix.c_icanon <- false; termio.Unix.c_vmin <- 1; termio.Unix.c_vtime <- 0; termio.Unix.c_echo <- false; Unix.tcsetattr Unix.stdin Unix.TCSADRAIN termio in fun () -> input_char stdin let is_enter c = Char.code c = 10 (* ASCII code for '\n' *) let read_arrow_key () = let esc = get_1_char () in if is_enter esc then Some "Enter" else if esc = '\027' then (* escape character *) let lb = get_1_char () in if lb = '[' then (* left bracket *) let c = get_1_char () in match c with | 'A' -> Some "Up" | 'B' -> Some "Down" | 'C' -> Some "Right" | 'D' -> Some "Left" | _ -> None else None else None (* x方向の画面中央 *) let clear_screen () = print_endline "\027[1;1H\027[2J" let read_and_print () = (* 最初に改行する *) print_newline (); (* 入力を受け付ける *) let rec loop chars finished count = (* 入力が終了したらリストの内容を逆順にして文字列に変換して返す *) if finished then String.concat "" (List.map (String.make 1) (List.rev chars)) else (* 標準入力から1文字読み込む *) let c = input_char stdin in (* 文字に応じて処理する *) match c with | '\n' -> (* Enterキーが押されたとき *) (* 入力を終了する *) let finished = true in (* ここで\rと\027[2Kを同時に使用するとおかしくなった *) (* カーソルを行頭に戻す *) print_string "\r"; (* 行全体を消去する *) print_string "\027[2K"; (* 現在の行を消す *) print_string (to_emerald (String.concat "" (List.map (String.make 1) (List.rev chars)))); (* 改行を出力する *) print_newline (); (* 再帰呼び出しする *) loop chars finished count | '\b' | '\127' -> (* BSかdelが押されたとき *) (* 保存したリストから1文字削除する *) let chars = match chars with [] -> [] (* リストが空なら何もしない *) | _ :: rest -> rest in (* リストの先頭要素を捨てる *) (* コンソールに表示されている文字数を減らす *) let count = max 0 (count - 1) in (* BSと空白とBSを出力して1文字消す *) if count >= 0 then ( print_string "\b \b"; flush stdout); (* 再帰呼び出しする *) loop chars finished count | '\027' -> (* エスケープ記号が出たとき *) (* エスケープシーケンスを読み飛ばす関数を定義する *) let rec skip_escape () = let c = input_char stdin in match c with | 'A' .. 'Z' | 'a' .. 'z' -> () (* エスケープシーケンスの終わりを見つけたら何もしない *) | _ -> skip_escape () in (* それ以外の文字は読み飛ばす *) skip_escape (); loop chars finished count (* 再帰呼び出しする *) | _ -> (* それ以外の文字が出たとき *) (* 保存したリストに追加する *) let chars = c :: chars in (* コンソールに表示する *) let next_count = List.length chars in print_char c; flush stdout; (* コンソールに表示されている文字数を増やす *) (* 再帰呼び出しする *) loop chars finished next_count in loop [] false 0