Rebol 2禁用控制台回显

时间:2016-03-21 21:37:53

标签: rebol rebol2

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

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

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

minimal example, pressing 'a'-

    cons: open/binary console://
    first cons
    == 97

(该值按我的意愿返回,并且char没有回显,这很好 - 我认为在大多数函数中我的键在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 ]
    ]
]

永远的循环似乎消费了#39;键盘输入(没有回音),但如果其中一个功能需要花费任何时间,任何键盘输入都会回显到光标所在的屏幕。在大多数情况下,我从来没有看到任何回显的字符,因为调用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 ]
  ]
]

我发现我的长期&#39;功能正在使用呼叫,这可能需要几秒钟,因此在使用呼叫时会出现问题。

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

我已经尝试在call命令中重定向stdin / stdout(在调用字符串命令中,就像在bash提示符下一样),但是没有找到一个有效的组合。 (我的实际代码运行调用/ output / error来捕获所有输出)。

2 个答案:

答案 0 :(得分:2)

在没有优化代码的情况下等待端口和唤醒功能我猜你的问题可以通过在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]
]

你可以看到,所有的密钥都没有额外的回声

答案 1 :(得分:1)

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

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

&#39; stty -echo&#39;在给出的示例中运行良好,似乎可以解决我的问题,但是如果在长函数运行时按下一堆键,我仍然会看到一些字符回显(我在所有命令中插入了{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
]

这样可行,因为我不能像以前那样在屏幕上显示任何(不需要的)字符(我猜它证明这些字符来自被调用的进程)。