我想解决当我按住箭头键时屏幕闪烁的问题。

huangapple go评论47阅读模式
英文:

I want to deal with the screen flickering when I hold down the arrow keys

问题

我使用了OCaml并创建了一个命令行工具。

以下是我编写的代码。
主要函数是[list_question],它接受当前索引和字符串列表,并返回所选项。

我刚开始学习函数类型,如果有关如何更好地完成此任务的建议,将不胜感激。

我目前的目标是防止屏幕闪烁!

(* 语言列表 *)
let languages = ["Java"; "C#"; "C++"; "C"; "Python"; "Ruby"; "Perl";]

let get1char =
  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码表示的换行符 *)

let read_arrow_key () =
  let esc = get1char() in
  if is_enter esc then
    Some "Enter"
  else
  if esc = '\027' then (* 转义字符 *)
    let lb = get1char() in
    if lb = '[' then (* 左方括号 *)
      let c = get1char() in
      match c with
      | 'A' -> Some "Up"
      | 'B' -> Some "Down"
      | 'C' -> Some "Right"
      | 'D' -> Some "Left"
      | _ -> None
    else
      None
  else
    None

let clear_screen () =
  print_endline "\027[2J \027[1;1H"

let prevIndex currentIndex listLength =
  match currentIndex with
  | 1 -> listLength
  | _ -> currentIndex - 1

let nextIndex currentIndex listLength =
  if currentIndex = listLength then
    1
  else
    currentIndex + 1

let next_index current_index nextOrPrev list_length =
  if nextOrPrev then
    nextIndex current_index list_length
  else
    prevIndex current_index list_length

let rec list_question (num : int) (list : string list)  =
  let selected = ref num in

  let rec print_list list index =
    if index = !selected then
      print_endline ("\027[32m❯\027[0m" ^ string_of_int index ^ ":" ^ List.nth list (index - 1))
    else
      print_endline (" " ^ string_of_int index ^ ":" ^ List.nth list (index - 1));
    if index < List.length list then
      print_list list (index + 1)
  in
  clear_screen ();

  print_endline "Choose your favorite language:";

  print_list languages 1;

  let key = read_arrow_key () in
  match key with
  | Some "Up" | Some "Left" -> 
      selected :=  next_index !selected false (List.length languages);
      print_int !selected;
      print_list languages 1;
    list_question !selected list
  | Some "Down" | Some "Right" -> 
      selected :=  next_index !selected true (List.length languages);
      print_list languages 1;
    list_question !selected list
  | Some "Enter" -> 
    List.nth languages (!selected - 1)
  | _ -> 
    list_question !selected list

let sss = list_question 1 languages ;;
print_string sss;;

我已经尝试更改ANSI转义代码,但没有改进。我认为在重新绘制时有一些问题。

英文:

I use ocaml and have created a cli tool.

Below is the code I wrote.
The main function is [list_question], which takes the current index and list of strings and returns the selected item.

I am just starting to learn about function types, so any advice on how to do this better would be appreciated.

My current goal is to keep the screen from flickering!

(* language list *)
let languages = [&quot;Java&quot;; &quot;C#&quot;; &quot;C++&quot;; &quot;C&quot;; &quot;Python&quot;; &quot;Ruby&quot;; &quot;Perl&quot;;]

let get1char =
  let termio = Unix.tcgetattr Unix.stdin in
  let () =
    termio.Unix.c_icanon &lt;- false;
    termio.Unix.c_vmin &lt;- 1;
    termio.Unix.c_vtime &lt;- 0;
    termio.Unix.c_echo &lt;- false;
    Unix.tcsetattr Unix.stdin Unix.TCSADRAIN termio
  in
  fun () -&gt; input_char stdin

let is_enter c = Char.code c = 10 (* ASCII code for &#39;\n&#39; *)

let read_arrow_key () =
  let esc = get1char() in
  if is_enter esc then
    Some &quot;Enter&quot;
  else
  if esc = &#39;\027&#39; then (* escape character *)
    let lb = get1char() in
    if lb = &#39;[&#39; then (* left bracket *)
      let c = get1char() in
      match c with
      | &#39;A&#39; -&gt; Some &quot;Up&quot;
      | &#39;B&#39; -&gt; Some &quot;Down&quot;
      | &#39;C&#39; -&gt; Some &quot;Right&quot;
      | &#39;D&#39; -&gt; Some &quot;Left&quot;
      | _ -&gt; None
    else
      None
  else
    None


let clear_screen () =
  print_endline &quot;\027[2J \027[1;1H&quot;

let prevIndex currentIndex listLength =
  match currentIndex with
  | 1 -&gt; listLength
  | _ -&gt; currentIndex - 1

  
let nextIndex currentIndex listLength =
  if currentIndex = listLength then
    1
  else
    currentIndex + 1


let next_index current_index nextOrPrev list_length =
  if nextOrPrev then
    nextIndex current_index list_length
  else
    prevIndex current_index list_length

let rec list_question (num : int) (list : string list)  =
  let selected = ref num in

  let rec print_list list index =
    if index = !selected then
      print_endline (&quot;\027[32m❯\027[0m&quot; ^ string_of_int index ^ &quot;:&quot; ^ List.nth list (index - 1))
    else
      print_endline (&quot; &quot; ^ string_of_int index ^ &quot;:&quot; ^ List.nth list (index - 1));
    if index &lt; List.length list then
      print_list list (index + 1)
  in
  clear_screen ();

  print_endline &quot;Choose your favorite language:&quot;;

  print_list languages 1;

  let key = read_arrow_key () in
  match key with
  | Some &quot;Up&quot; | Some &quot;Left&quot; -&gt; 
      selected :=  next_index !selected false (List.length languages);
      print_int !selected;
      print_list languages 1;
    list_question !selected list
  | Some &quot;Down&quot; | Some &quot;Right&quot; -&gt; 
      selected :=  next_index !selected true (List.length languages);
      print_list languages 1;
    list_question !selected list
  | Some &quot;Enter&quot; -&gt; 
    List.nth languages (!selected - 1)
  | _ -&gt; 
    list_question !selected list

let sss = list_question 1 languages ;;
print_string sss;;

I have tried changing the code for ansi escape but no improvement. I think there is something wrong with the process when it is redrawn.

答案1

得分: 1

以下是翻译好的内容:

"The flickering was improved by grouping them into a single string before outputting them, instead of displaying them one line at a time."
"将它们分组成一个单独的字符串,而不是逐行显示,从而改善了闪烁。"

"The following is the improved code."
"以下是改进后的代码。"

(* language array... *)
let languages = ["Java"; "C#"; "C++"; "C"; "Python"; "Ruby"; "Perl";]

(* util: *)
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


let clear_screen () =
  print_endline "\027[1;1H\027[2J"

let prevIndex currentIndex listLength =
  match currentIndex with
  | 1 -> listLength
  | _ -> currentIndex - 1

  
let next_index currentIndex listLength =
  if currentIndex = listLength then
    1
  else
    currentIndex + 1


let get_index current_index nextOrPrev list_length =
  if nextOrPrev then
    next_index current_index list_length
  else
    prevIndex current_index list_length


(*
  print_list function
  Takes a list and currentIndex.
  Separates each line with \n and returns a single string.
*)
let list_to_string (list:string list) (currentIndex:int) =
  let rec loop list currentIndex index result =
    match list with
    | [] -> result
    | head :: tail ->
      if index = currentIndex then
        loop tail currentIndex (index + 1) (result ^ "\027[32m❯\027[0m" ^ string_of_int index ^ ":" ^ head ^ "\n")
      else
        loop tail currentIndex (index + 1) (result ^ " " ^ string_of_int index ^ ":" ^ head ^ "\n")
  in
  print_endline "Choose your favorite language:";
  print_endline "Use arrow keys to navigate, Enter to select.";
  print_endline  (loop list currentIndex 1 "")


    

let rec list_question (num : int) (list : string list)  =
  let selected = ref num in

  let key = read_arrow_key () in


  match key with
  | Some "Up" | Some "Left" ->
      clear_screen (); 
      selected :=  get_index !selected false (List.length list);
      list_to_string list !selected;
    list_question !selected list
  | Some "Down" | Some "Right" -> 
      clear_screen ();
      selected :=  get_index !selected true (List.length list);
      list_to_string list !selected;
    list_question !selected list
  | Some "Enter" -> 
    List.nth list (!selected - 1)
  | _ -> 
    list_question !selected list;;

clear_screen();;
list_to_string languages 1;;
let result_string = list_question 1 languages ;;
print_string result_string;;
英文:

The flickering was improved by grouping them into a single string before outputting them, instead of displaying them one line at a time.
The following is the improved code.

(* language array... *)
let languages = [&quot;Java&quot;; &quot;C#&quot;; &quot;C++&quot;; &quot;C&quot;; &quot;Python&quot;; &quot;Ruby&quot;; &quot;Perl&quot;;]

(* util: *)
let get_1_char =
  let termio = Unix.tcgetattr Unix.stdin in
  let () =
    termio.Unix.c_icanon &lt;- false;
    termio.Unix.c_vmin &lt;- 1;
    termio.Unix.c_vtime &lt;- 0;
    termio.Unix.c_echo &lt;- false;
    Unix.tcsetattr Unix.stdin Unix.TCSADRAIN termio
  in
  fun () -&gt; input_char stdin

let is_enter c = Char.code c = 10 (* ASCII code for &#39;\n&#39; *)

let read_arrow_key () =
  let esc = get_1_char() in
  if is_enter esc then
    Some &quot;Enter&quot;
  else
  if esc = &#39;\027&#39; then (* escape character *)
    let lb = get_1_char() in
    if lb = &#39;[&#39; then (* left bracket *)
      let c = get_1_char() in
      match c with
      | &#39;A&#39; -&gt; Some &quot;Up&quot;
      | &#39;B&#39; -&gt; Some &quot;Down&quot;
      | &#39;C&#39; -&gt; Some &quot;Right&quot;
      | &#39;D&#39; -&gt; Some &quot;Left&quot;
      | _ -&gt; None
    else
      None
  else
    None


let clear_screen () =
  print_endline &quot;\027[1;1H\027[2J&quot;

let prevIndex currentIndex listLength =
  match currentIndex with
  | 1 -&gt; listLength
  | _ -&gt; currentIndex - 1

  
let next_index currentIndex listLength =
  if currentIndex = listLength then
    1
  else
    currentIndex + 1


let get_index current_index nextOrPrev list_length =
  if nextOrPrev then
    next_index current_index list_length
  else
    prevIndex current_index list_length


(*
  print_list関数
  listとcurrentIndexを受け取る。
  1行ずつ\nで改行し、ひとつの文字列を返す。
*)
let list_to_string (list:string list) (currentIndex:int) =
  let rec loop list currentIndex index result =
    match list with
    | [] -&gt; result
    | head :: tail -&gt;
      if index = currentIndex then
        loop tail currentIndex (index + 1) (result ^ &quot;\027[32m❯\027[0m&quot; ^ string_of_int index ^ &quot;:&quot; ^ head ^ &quot;\n&quot;)
      else
        loop tail currentIndex (index + 1) (result ^ &quot; &quot; ^ string_of_int index ^ &quot;:&quot; ^ head ^ &quot;\n&quot;)
  in
  print_endline &quot;Choose your favorite language:&quot;;
  print_endline &quot;Use arrow keys to navigate, Enter to select.&quot;;
  print_endline  (loop list currentIndex 1 &quot;&quot;)


    

let rec list_question (num : int) (list : string list)  =
  let selected = ref num in

  let key = read_arrow_key () in


  match key with
  | Some &quot;Up&quot; | Some &quot;Left&quot; -&gt;
      clear_screen (); 
      selected :=  get_index !selected false (List.length list);
      list_to_string list !selected;
    list_question !selected list
  | Some &quot;Down&quot; | Some &quot;Right&quot; -&gt; 
      clear_screen ();
      selected :=  get_index !selected true (List.length list);
      list_to_string list !selected;
    list_question !selected list
  | Some &quot;Enter&quot; -&gt; 
    List.nth list (!selected - 1)
  | _ -&gt; 
    list_question !selected list;;


clear_screen();;
list_to_string languages 1;;
let result_string = list_question 1 languages ;;
print_string result_string;;

huangapple
  • 本文由 发表于 2023年4月19日 21:29:59
  • 转载请务必保留本文链接:https://go.coder-hub.com/76055133.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定