【问题标题】:ruby: Sending keystrokes to PTY in raw moderuby:以原始模式将击键发送到 PTY
【发布时间】:2019-10-30 22:33:22
【问题描述】:

我正在尝试向ruby-newt 模块添加更多自动化测试。我的代码似乎可以工作,但仍需要在终端手动点击ENTER 才能完成。

例如下面的代码,\t会切换到下一个按钮,\r会按下按钮,两个命令都执行成功,但是ENTER键还是需要在终端手动按下,否则程序只是无限期挂起。

如果wr.write "\t\r"这一行被注释掉,那么程序会超时,10秒后成功退出。我试过wr.flush,但这无济于事。我也试过在命令中包含\n

我应该在write 命令中添加任何其他内容以确保子程序成功接收它吗?

require 'newt'
require 'pty'

def newt_run
  begin
    Newt::Screen.new
    Newt::Screen.centered_window(20, 15, 'Button')

    b1 = Newt::Button.new(1, 1, 'Button1')
    b2 = Newt::Button.new(1, 6, 'Button2')

    b = Newt::Button.new(1, 11, 'Exit')

    f = Newt::Form.new
    f.set_timer(10000)
    f.add(b1, b2, b) 

    rv = f.run
  ensure
    Newt::Screen.finish
  end
end

master, slave = PTY.open
rd, wr = IO.pipe

if fork.nil? then
  master.close
  wr.close

  $stdin.reopen(rd)
  $stdout.reopen(slave)
  $stderr.reopen(slave)

  newt_run
else
  slave.close
  rd.close

  wr.write "\t\r"
  Process.wait
end

【问题讨论】:

  • 注意:在def 中,您可以只使用ensure 而无需明确的begin

标签: ruby pty


【解决方案1】:

问题在于,newt C 库默认打开/dev/tty 进行输入。它不使用标准输入。这就是为什么您发送的任何内容似乎都不起作用的原因。它不是在读取您的管道,而是在读取 /dev/tty

这里是更详细的问题:

  1. Ruby newt 在 C-lib 中调用 newtInit()
  2. newtInit() 致电SLang_init_tty
  3. SLang_init_tty 默认始终将输入附加到 /dev/tty

如果你read the documentationSLang_init_tty 你会发现变量SLang_TT_Read_FD 决定了/dev/tty 是否被使用。

解决方案 1

在从 Ruby 调用 newtInit() 之前,您需要将 SLang_TT_Read_FD 设置为 stdin

解决方案 2:

使用setsidioctl(TIOCSCTTY) 重新分配分叉进程中的控制终端(请参阅docs for ioctl here)。

工作示例:

TIOCSCTTY = 0x540E
master, slave = PTY.open

if fork.nil? then
  # Child process
  # Make group leader. Required for aquiring controlling TTY.
  Process.setsid

  master.close               # Close master side    
  STDIN.reopen(slave)        # Reassign STDIN
  STDIN.ioctl(TIOCSCTTY, 0)  # Reassign controlling TTY (important part)

  # Ensure master is ready
  slave.gets

  # Now we can run the UI
  newt_run
else
  # Parent process
  slave.close

  # Sync up with slave
  master.puts 'hello'

  # Allow for UI setup
  sleep 1

  master.write "\e[B" # Arrow down
  master.write "\e[B" # Arrow down
  master.write "\t"   # Tab
  master.write "\r"   # Enter

  Process.wait 
end

【讨论】:

  • 谢谢,我相信解决方案 2 适合我的情况。
猜你喜欢
  • 2010-09-16
  • 2020-12-24
  • 1970-01-01
  • 2016-08-22
  • 1970-01-01
  • 1970-01-01
  • 2011-12-23
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多