一尘不染

PHP CLI:如何从TTY中读取输入的单个字符(无需等待回车键)?

php

我想一次从PHP的命令行中一次读取一个字符,但是似乎从某处阻止了某种输入缓冲。

考虑以下代码:

#!/usr/bin/php
<?php
echo "input# ";
while ($c = fread(STDIN, 1)) {
    echo "Read from STDIN: " . $c . "\ninput# ";
}
?>

输入“ foo”作为输入(并按回车键),我得到的输出是:

input# foo
Read from STDIN: f
input# Read from STDIN: o
input# Read from STDIN: o
input# Read from STDIN:

input#

期望 的输出是:

input# f
input# Read from STDIN: f

input# o
input# Read from STDIN: o

input# o
input# Read from STDIN: o

input# 
input# Read from STDIN:

input#

(即,在键入字符时对其进行读取和处理)。

但是,当前,仅在按下回车键后才能读取每个字符。我怀疑TTY正在缓冲输入。

最终,我希望能够读取按键,例如向上箭头,向下箭头等。


阅读 404

收藏
2020-05-29

共1个答案

一尘不染

我的解决方案是-icanon在TTY上设置模式(使用stty)。例如。:

stty -icanon

因此,现在可以使用的代码是:

#!/usr/bin/php
<?php
system("stty -icanon");
echo "input# ";
while ($c = fread(STDIN, 1)) {
    echo "Read from STDIN: " . $c . "\ninput# ";
}
?>

输出:

input# fRead from STDIN: f
input# oRead from STDIN: o
input# oRead from STDIN: o
input# 
Read from STDIN:

input#

完成操作后,别忘了还原TTY …

恢复tty配置

通过在更改终端状态之前保存tty状态,可以将终端重置回原来的状态。完成后,您可以恢复到该状态。

例如:

<?php

// Save existing tty configuration
$term = `stty -g`;

// Make lots of drastic changes to the tty
system("stty raw opost -ocrnl onlcr -onocr -onlret icrnl -inlcr -echo isig intr undef");

// Reset the tty back to the original configuration
system("stty '" . $term . "'");

?>

这是保存tty并将其放回用户开始之前的方式的唯一方法。

请注意,如果您不担心保留原始状态,只需执行以下操作即可将其重置回默认的“健全”配置:

<?php

// Make lots of drastic changes to the tty
system("stty raw opost -ocrnl onlcr -onocr -onlret icrnl -inlcr -echo isig intr undef");

// Reset the tty back to sane defaults
system("stty sane");

?>
2020-05-29