Skip to content

Conversation

fancidev
Copy link
Contributor

@fancidev fancidev commented Aug 7, 2025

Closes gh-5969.

Summary

gh-5969 reports that running ESC key presses are not processed immediately when running textual in the web under Windows. This is due to the InputReader under Windows performing a blocking read without honouring the timeout. This PR fixes the InputReader, which in turn fixes gh-5969.

Checklist

  • Docstrings on all new or modified functions / classes
  • Updated documentation
  • Updated CHANGELOG.md (where appropriate)

Remarks

An InputReader is used by the web driver of the launched app to read user input from stdin, which is redirected to an anonymous pipe under Windows. Unlike Linux, anonymous pipes under Windows support just a limited set of operations: (blocking) read, (non-blocking) peek, and close. In particular, the OS provides no way to select/wait an anonymous pipe, perform asynchronous read, or interrupt/cancel a blocking read.

Therefore, to support read with timeout, this PR creates a background thread to read from the pipe and pass on the data through a Queue to the thread where the InputReader is iterated. Timeout is achieved via Queue.get().

While this workaround is straightforward, it does have a semantic difference from the InputReader under Linux: the background thread reads data in advance of being iterated. This is not a problem for Textual because only one InputReader instance is created and it is used throughout the lifetime of the app. However, the implementation is not suitable for general use.

An alternative (not pursued by this PR) could be to redirect stdin to a named pipe under Windows, which supports timeout and asynchronous operations. That requires making changes in the textual-serve repo in addition to this one.

@fancidev fancidev marked this pull request as ready for review August 9, 2025 12:34
@fancidev
Copy link
Contributor Author

I made a new commit that properly implements cancellation for blocking read of anonymous pipe under Windows. The code follows the approach of DotNET, where the key is to use the CancelSynchronuousIo function. This seems to be the only way to support asynchronous operation on anonymous pipe properly. (An alternative is busy-polling using PeekNamedPipe, which wastes CPU time.)

@fancidev fancidev marked this pull request as draft August 16, 2025 23:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

On Windows 11, pressing the 'escape' key in browser via textual-serve doesn't register until the mouse is moved or the 'escape' key is pressed again
1 participant