Rebol 2 禁用控制台回显
Rebol 2 disable console echo
我有一个 Rebol2 控制台应用程序 (Rebol Core),我想禁用键盘字符回显到控制台。该应用程序是 运行 来自最小 Linux kernel/initramfs,并由 busybox inittab(不是从终端)启动。它有一个最小的控制台用户界面,使用颜色等 ansi 代码,并通过单键响应菜单选择。对于 'quiet' 控制台,我关闭了光标,并且看不到按键的输出(直到最近)。
我之前以为我已经通过在 Rebol 中调用 'stty -echo' 解决了问题,但它实际上并没有像我刚刚发现的那样工作 - 有一个函数需要 5-10 秒并且可以看到回显键在等待功能完成时按下。
我不太清楚为什么我只看到回显的字符,而这个函数是 运行ning,但它是唯一一个需要任何时间的函数。通过以二进制模式打开 console:// 来轮询键盘,等待按键,然后是 switch 语句来选择功能。 binary/console中的按键读取好像是'consume'中的按键echo-
minimal example, pressing 'a'-
cons: open/binary console://
first cons
== 97
(按我的意愿返回值,并且不回显 char,这很好-我认为在大多数函数中,我的键在 get-key 循环中是 'consumed',但较长的函数确实没有机会 'consume' 他们,最终回显到控制台)
有没有办法在 Rebol2 中禁用控制台字符回显?我查看了 system/console 和 system/ports/input 的输出,但没有看到任何明显的东西。我目前的解决方法是简单地更改文本颜色以匹配背景,这样在特定功能 运行s.
时任何按键都不可见
这是我正在做的一个最小例子-
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 ]
]
]
永远的循环似乎 'consume' 键盘输入(没有回显),但是如果其中一个函数花费任何时间,任何键盘输入都会在光标恰好位于的任何地方回显到屏幕上.在大多数情况下,我从来没有看到任何回显字符,因为调用 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 ]
]
]
我发现我的 'long' 函数正在使用调用,这可能需要几秒钟,所以当使用调用时就会出现问题。
以上代码,when 运行会显示keys被回显只是因为在get-key函数(括号)中打印了keys,当long-func为运行ning时,则键在 get-key 之外回显(没有括号),完成后 get-key 也会处理这些键。或者简单地 运行 'call/wait {sleep 10}' 并且您将在等待时得到回显键,并且在调用 returns 时也会得到 Rebol 回显的相同键。 reb-func 运行s 时不会回显密钥,并且 get-key 将在 reb-func 完成时处理所有缓冲的密钥。使用调用时,键盘输入正在处理两次。
我已经尝试在调用命令中重定向 stdin/stdout(在调用字符串命令中,例如在 bash 提示符下),但没有找到有效的组合。 (我的实际代码 运行s 使用 /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' 选项,我可以在其中执行 'wait [ cons t ]' 和 return 字符串(对于扩展键代码,如向上箭头)或 none ,这意味着我还可以在我的 switch get-key 之前刷新控制台输入(因此在刷新 运行ning 功能时按下的任何键)。
forever [
while [ get-key/timeout 0.1 ][] ;flush
switch get-key [ ;wait for key
...
'stty -echo' 在给定的示例中运行良好,似乎可以解决我的问题,但是如果我在长函数 [=28= 时按下一堆键,我仍然看到一些字符回显]ning(我在所有命令中插入了 {stty -echo; })。不知何故,在创建进程的 Rebol 调用中(fork/exec 我假设),tty input/output 仍然可以 'leak' 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
]
这行得通,因为我无法像以前那样在屏幕上显示任何(不需要的)字符(我想这证明这些字符来自被调用的进程)。
我有一个 Rebol2 控制台应用程序 (Rebol Core),我想禁用键盘字符回显到控制台。该应用程序是 运行 来自最小 Linux kernel/initramfs,并由 busybox inittab(不是从终端)启动。它有一个最小的控制台用户界面,使用颜色等 ansi 代码,并通过单键响应菜单选择。对于 'quiet' 控制台,我关闭了光标,并且看不到按键的输出(直到最近)。
我之前以为我已经通过在 Rebol 中调用 'stty -echo' 解决了问题,但它实际上并没有像我刚刚发现的那样工作 - 有一个函数需要 5-10 秒并且可以看到回显键在等待功能完成时按下。
我不太清楚为什么我只看到回显的字符,而这个函数是 运行ning,但它是唯一一个需要任何时间的函数。通过以二进制模式打开 console:// 来轮询键盘,等待按键,然后是 switch 语句来选择功能。 binary/console中的按键读取好像是'consume'中的按键echo-
minimal example, pressing 'a'-
cons: open/binary console://
first cons
== 97
(按我的意愿返回值,并且不回显 char,这很好-我认为在大多数函数中,我的键在 get-key 循环中是 'consumed',但较长的函数确实没有机会 'consume' 他们,最终回显到控制台)
有没有办法在 Rebol2 中禁用控制台字符回显?我查看了 system/console 和 system/ports/input 的输出,但没有看到任何明显的东西。我目前的解决方法是简单地更改文本颜色以匹配背景,这样在特定功能 运行s.
时任何按键都不可见这是我正在做的一个最小例子-
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 ]
]
]
永远的循环似乎 'consume' 键盘输入(没有回显),但是如果其中一个函数花费任何时间,任何键盘输入都会在光标恰好位于的任何地方回显到屏幕上.在大多数情况下,我从来没有看到任何回显字符,因为调用 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 ]
]
]
我发现我的 'long' 函数正在使用调用,这可能需要几秒钟,所以当使用调用时就会出现问题。
以上代码,when 运行会显示keys被回显只是因为在get-key函数(括号)中打印了keys,当long-func为运行ning时,则键在 get-key 之外回显(没有括号),完成后 get-key 也会处理这些键。或者简单地 运行 'call/wait {sleep 10}' 并且您将在等待时得到回显键,并且在调用 returns 时也会得到 Rebol 回显的相同键。 reb-func 运行s 时不会回显密钥,并且 get-key 将在 reb-func 完成时处理所有缓冲的密钥。使用调用时,键盘输入正在处理两次。
我已经尝试在调用命令中重定向 stdin/stdout(在调用字符串命令中,例如在 bash 提示符下),但没有找到有效的组合。 (我的实际代码 运行s 使用 /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' 选项,我可以在其中执行 'wait [ cons t ]' 和 return 字符串(对于扩展键代码,如向上箭头)或 none ,这意味着我还可以在我的 switch get-key 之前刷新控制台输入(因此在刷新 运行ning 功能时按下的任何键)。
forever [
while [ get-key/timeout 0.1 ][] ;flush
switch get-key [ ;wait for key
...
'stty -echo' 在给定的示例中运行良好,似乎可以解决我的问题,但是如果我在长函数 [=28= 时按下一堆键,我仍然看到一些字符回显]ning(我在所有命令中插入了 {stty -echo; })。不知何故,在创建进程的 Rebol 调用中(fork/exec 我假设),tty input/output 仍然可以 'leak' 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
]
这行得通,因为我无法像以前那样在屏幕上显示任何(不需要的)字符(我想这证明这些字符来自被调用的进程)。