Почему stream_select в STDIN становится блокирующим, когда cmd.exe теряет фокус?

Цель: запустить PHP-файл в cmd, цикл скриптов x раз и на каждой итерационной проверке, чтобы узнать, ввел ли пользователь какой-либо вход ( stream_select () с STDIN ), и если это так – приостанавливает цикл до тех пор, пока пользователь не наткнется на ввод, затем распечатает ввода и продолжается с итерацией.

Проблема: сценарий работает отлично до тех пор, пока окно cmd.exe находится в фокусе – когда я нажимаю на другое окно, сценарий приостанавливается в stream_select и не продолжается до тех пор, пока я, кроме CMd-окна, не окажусь в фокусе и не отправлю ему некоторый ввод (просто введите нажатие клавиши будет делать трюк). Нет ошибок.

Вопрос: почему потеря фокуса на cmd влияет на stream_select и блокирует цикл? … и есть ли обходной путь? (например, можно ли проверить, находится ли текущее окно cmd?)

Пример кода, используемый cmd php script.php в рабочем каталоге.

 <?php $loopCount = 20; while ($loopCount) { $start = microtime(true); echo 'check on "' . $loopCount . '"' . PHP_EOL; $stream = fopen('php://stdin', 'r'); $stream_array = array($stream); $write = array(); $except = array(); if (stream_select($stream_array, $write, $except, 1, 0)) { $input = trim(fgets($stream)); if ($input) { echo 'input was "' . $input . '"' . PHP_EOL; } } fclose($stream); echo $loopCount . ' in ' . (microtime(true) - $start) . PHP_EOL; $loopCount--; } 

Вещи, которые я пробовал, не повезло:

  • перемещение fopen и fclose вне цикла
  • ignore_user_abort(1);
  • stream_set_blocking($stream, 0);
  • null , 0 и более высокие значения для параметров tv_sec и tv_usec для tv_sec stream_select()
  • проверка соединений connection_aborted () и connection_status ()

Окружающая среда: Windows 7, XAMPP для Windows, PHP 5.4.19 (cli), Zend Engine v2.4.0

Я думаю, проблема связана с тем, что stream_select () также возвращает 1 для STDIN, когда поток получает EOL, что, как мне кажется, происходит, когда cmd теряет фокус.

С http://www.php.net/manual/en/function.stream-select.php

в частности, ресурс потока также готов к концу файла, и в этом случае fread () вернет строку нулевой длины

Когда фокус не теряется и данные не вводятся, stream_select возвращает 0, а принятый массив $ read освобождается ссылкой. Когда фокус теряется ИЛИ когда ввод задан, массив $ read остается неповрежденным, и вы должны читать из каждого индекса.

Но это оставляет нам пользователей окна в плохой ситуации, потому что у нас нет способа неблокировать чтение строки нулевой длины с помощью stream_get_ (content | line) или fread или fgets. И поскольку мы не можем различать потери фокуса и поставки фактических данных, я считаю, что нам нужно подождать, пока одна из этих ошибок будет исправлена:

https://bugs.php.net/bug.php?id=36030

https://bugs.php.net/bug.php?id=34972

В настоящее время я изучаю вариант, чтобы предотвратить потерять фокус через API win32, но это выглядит непрактичным даже для моих нужд.

Вот обходной путь, который я использую сейчас …

https://gist.github.com/anonymous/80080060869f875e7214