Rebol 2 禁用控制台回显



我有一个 Rebol2 控制台应用程序(Rebol Core),我想禁用键盘字符回显到控制台。该应用程序从最小的Linux内核/initramfs运行,并由busybox inittab(而不是从终端)启动。它具有最小的控制台用户界面,使用ansi代码进行颜色等,并通过单键响应菜单选择。为了"安静"控制台,我关闭了光标,并且看不到按键的输出(直到最近)。

我以前以为我已经通过在 Rebol 中调用"stty -echo"解决了这个问题,但它实际上并不像我刚刚发现的那样有效 - 有一个函数需要 5-10 秒,并且可以在等待功能完成时看到回显的按键。

不太确定为什么我只看到这个函数运行时的回声字符,但它是唯一需要任何时间的函数。通过在二进制模式下打开 console://来轮询键盘,等待按键,然后等待 switch 语句来选择功能。二进制/控制台中键的读取似乎"消耗"了键回声-

minimal example, pressing 'a'-
    cons: open/binary console://
    first cons
    == 97

(值是随心所欲地返回的,并且字符没有回显,这很好 - 我认为在大多数函数中,我的键在 get-key 循环中被"消耗",但较长的函数没有机会"消费"它们,并最终回显到控制台)

有没有办法禁用 Rebol2 中的控制台字符回显?我已经查看了系统/控制台和系统/端口/输入,输出,但没有看到任何明显的东西。我目前的解决方法是简单地更改文本颜色以匹配背景,以便在特定功能运行时看不到任何按键。

这是我正在做的事情的一个最小例子——

get-key: func [ /local cons ch ][
    cons: open/binary console://
    ch: lowercase to-string to-char first cons
    all [ equal? ch "^["   append ch copy/part cons 2 ]
    close cons
    ch
]
forever [
    switch get-key [
        ;up arrow
        "^[[A" [ some-function1 ]
        ;down arrow
        "^[[B" [ some-function2 ]
        ;enter
        "^M" [ some-function3 ]
        ;quit
        "q" [ break ]
    ]
]

永久循环似乎"消耗"键盘输入(没有回声),但如果其中一个函数花费任何时间,任何键盘输入都会回显到屏幕上,无论光标在哪里。在大多数情况下,我从未看到任何回显字符,因为调用 get-key 之间的时间很短。我还要注意,回显的字符也不会出现在随后的 get-key 调用中。

更新-

这是一个更好的代码示例来查看问题-

get-key: has [ cons ch ][
  cons: open/binary console://
  ch: lowercase to-string to-char first cons
  prin rejoin [ "<" ch ">" ] ;show get-key chars
  ch
]
long-func: does [ call/wait {sleep 10} ]
reb-func: does [ wait 10 ]
forever [
  switch get-key [
   "f" [ long-func ]
   "r" [ reb-func ]
   "q" [ break ]
  ]
]

我发现我的"长"函数正在使用可能需要几秒钟的调用,因此使用调用时会出现问题。

上面的代码,当运行时将显示键被回显只是因为它们打印在 get-key 函数(括号)中,当 long-func 运行时,键会在 get-key 之外回显(没有括号),完成后 get-key 也将处理这些键。或者只需运行"呼叫/等待{睡眠 10}",您将在等待时获得回显键,并在调用返回时获得 Rebol 回显的相同键。当 reb-func 运行时,密钥不会回显,get-key 将在 reb-func 完成后处理所有缓冲的密钥。使用呼叫时,键盘输入被处理两次。

我尝试在调用命令中

重定向 stdin/stdout(在调用字符串命令中,如在 bash 提示符下),但没有找到有效的组合。(我的实际代码使用/output/error 运行调用以捕获所有输出)。

无需通过等待端口和唤醒函数来优化代码,我想您的问题可以通过在 get-key 函数之外打开和关闭控制台端口来解决,如

get-key: func [ /local ch ][
    ch: lowercase to-string to-char first cons
    all [ equal? ch "^["   append ch copy/part cons 2 ]
    ch
]
cons: open/binary [scheme: 'console]
forever [
    switch get-key [
        ;up arrow
        "^[[A" [ some-function1 ]
        ;down arrow
        "^[[B" [ some-function2 ]
        ;enter
        "^M" [ some-function3 ]
        ;quit
        "q" [ break ]
    ]
]
close cons

好的,这是一个优化版本,包括您的第二个示例

long-func: does [ call/wait {stty -echo ; sleep 10} ]
reb-func: does [ wait 10 ]
 cons: open/binary [scheme: 'console]
 cons/awake: func [port] [
    key: to-char first port
    print ["<" key ">"]
    switch key [
        #"f" [long-func]
        #"r" [reb-func]
        #"q" [break]
    ]
 ]
forever [ 
    wait [cons]
]

您可以看到,所有键都被捕获而没有额外的回声

重新排列的控制台代码不是必需的(无论使用哪种排列方式,所有键都会被缓存),尽管很高兴知道添加唤醒函数的能力。在我的真实代码中,get-key 有一个"/timeout t"选项,我可以在其中执行"等待 [ cons t ]"并返回一个字符串(对于向上箭头等扩展键代码)或 none,这意味着我也可以在切换 get-key 之前刷新控制台输入(因此在运行函数时按下的任何键都会被刷新)。

forever [
  while [ get-key/timeout 0.1 ][] ;flush
  switch get-key [ ;wait for key
...

"stty -echo"在给出的示例中运行良好,似乎可以解决我的问题,但是如果我在长函数运行时按下一堆键,我仍然会看到一些字符回显(我在所有命令中插入了{stty -echo; })。不知何故,在进程的 Rebol 调用创建中(我假设 fork/exec),tty 输入/输出仍然可以"泄漏"I/O 字符。或者,也许调用的程序之一正在打开 tty,即使它继承了父级的文件描述符。

这就是我最终要做的事情 - 更改我调用命令的方式,以便它们在后台运行,但仍等待它们完成。

;used by other funcs to parse output of commands
set 'cmd-output "" ;output from 'call' commands
set 'cmd-error "" ;error from 'call commands
set 'cmd func [ str [string!] /local ret ][
  --old--
  ;clear previous
  cmd-output: copy ""
  cmd-error: copy ""
  ;--new--
  write %out ""
  write %err ""
  attempt [ delete %ret ]
  ;--old--
  ;ret: call/wait/output/error str cmd-output cmd-error
  ;--new--  stdout->out stderr->err exitcode->ret
  call rejoin [ str { >out 2>err; echo -n $? > ret} ]
  ;wait for return code, (up to 20 seconds, should be plenty)
  loop 200 [ all [ exists? %ret  break ] wait 0.1 ]
  cmd-output: read %out
  cmd-error: read %err
  ret: to-integer read %ret
  --old--
  ;debug-cmd writes info to a logfile
  debug-cmd str ret
  ret
]

有效,因为我无法像以前一样让任何(不需要的)字符显示在屏幕上(我想这证明这些字符来自调用的进程)。

相关内容

  • 没有找到相关文章

最新更新