Amjith
Amjith

Reputation: 23854

How to flush the input stream?

I'm writing a simple alarm utility in Python.

#!/usr/bin/python

import time
import subprocess
import sys

alarm1 = int(raw_input("How many minutes (alarm1)? "))

while (1):
    time.sleep(60*alarm1)
    print "Alarm1"
    sys.stdout.flush()
    doit = raw_input("Continue (Y/N)?[Y]: ")
    print "Input",doit
    if doit == 'N' or doit=='n':
        print "Exiting....."
        break

I want to flush or discard all the key strokes that were entered while the script was sleeping and only accept the key strokes after the raw_input() is executed.

I'm running this on Windows XP.

Upvotes: 24

Views: 66168

Answers (6)

Six Kai
Six Kai

Reputation: 31

There is a Console API function for this task, FlushConsoleInputBuffer. A cross-platform solution would look like this:

import os

if os.name == "posix":
    import sys
    import termios
else:
    import ctypes
    from ctypes import wintypes
    
    # Dynamic link libraries aliases
    kernel32 = ctypes.windll.kernel32
    
    # Standard console devices
    STD_INPUT_HANDLE = -10
    INVALID_HANDLE_VALUE = wintypes.HANDLE(-1).value
    
    kernel32.GetStdHandle.argtypes = (wintypes.DWORD, )
    kernel32.GetStdHandle.restype = wintypes.HANDLE
    
    def get_std_handle(nStdHandle: int) -> wintypes.HANDLE | None:
        '''
        Function GetStdHandle from ProcessEnv.h
        '''
        result = kernel32.GetStdHandle(nStdHandle)
        if result == INVALID_HANDLE_VALUE or result is None:
            return None
        return result

    kernel32.FlushConsoleInputBuffer.argtypes = (wintypes.HANDLE, )
    kernel32.FlushConsoleInputBuffer.restype = wintypes.BOOL
    
    def flush_console_input_buffer(hConsoleInput: wintypes.HANDLE) -> int:
        '''
        Function FlushConsoleInputBuffer from ConsoleApi2.h
        '''
        return kernel32.FlushConsoleInputBuffer(hConsoleInput)    


def discard_input() -> bool:
    '''
    Discard all input events.

    Returns:
        bool: Execution result.
    '''
    if os.name == "posix":
        termios.tcflush(sys.stdin.fileno(), termios.TCIOFLUSH)
        return True

    if (hConsoleInput := get_std_handle(STD_INPUT_HANDLE)) is None:
        return False
    if flush_console_input_buffer(hConsoleInput):
        return True
    return False


discard_input()

Porting details

FlushConsoleInputBuffer is available since Windows 2000. The code above uses the walrus operator (PEP 572, 3.8) and union type hint (PEP 604, 3.10).

Add this import to use on Python 3.8+:

from __future__ import annotations

Upvotes: 0

Solution:

I have used (and worked in my case):

import sys

...
sys.stdin.flush()
...

Why this answer?

I have added this answer to this thread because I got here with the question "What was the syntax for flushing stdin?". I read the entries and thought that there had to be some flush method for stdin. I found it. I was surprised that it was not used in any entry and I thought that it should be.

Related documentation

Upvotes: 1

Kylar
Kylar

Reputation: 9334

#!/usr/bin/python

import time
import subprocess
import sys
import os, select

alarm1 = int(raw_input("How many minutes (alarm1)? "))

while (1):
    time.sleep(3*alarm1)
    print "Alarm1"
    sys.stdout.flush()
    while select.select([sys.stdin.fileno()], [], [], 0.0)[0]:
        os.read(sys.stdin.fileno(), 4096)
    doit = raw_input("Continue (Y/N)?[Y]: ")
    print "Input",doit
    if doit == 'N' or doit=='n':
        print "Exiting....."
        break

Upvotes: 6

kollery
kollery

Reputation: 385

From Rosetta Code

def flush_input():
    try:
        import msvcrt
        while msvcrt.kbhit():
            msvcrt.getch()
    except ImportError:
        import sys, termios    #for linux/unix
        termios.tcflush(sys.stdin, termios.TCIOFLUSH)

The try part is for Windows platform. I have not personally tested this part. But the except section works on linux terminal. termios module has some terminal interface functions. the tcflush can flush input or output buffered data. This part definitely works in my tests.

Upvotes: 20

Peter Milley
Peter Milley

Reputation: 2808

It would help to know what operating system you're using, as this is a very operating-system-specific question. For example, Kylar's answer doesn't work on Windows because sys.stdin doesn't have a fileno attribute.

I was curious and threw together a solution using curses, but this won't work on Windows either:

#!/usr/bin/python                                                               

import time
import sys
import curses

def alarmloop(stdscr):
    stdscr.addstr("How many seconds (alarm1)? ")
    curses.echo()
    alarm1 = int(stdscr.getstr())
    while (1):
        time.sleep(alarm1)
        curses.flushinp()
        stdscr.clear()
        stdscr.addstr("Alarm1\n")
        stdscr.addstr("Continue (Y/N)?[Y]:")
        doit = stdscr.getch()
        stdscr.addstr("\n")
        stdscr.addstr("Input "+chr(doit)+"\n")
        stdscr.refresh()
        if doit == ord('N') or doit == ord('n'):
            stdscr.addstr("Exiting.....\n")
            break

curses.wrapper(alarmloop)

EDIT: ah, Windows. Then you can use the msvcrt module. Note that the code below isn't perfect, and it doesn't work in IDLE at all:

#!/usr/bin/python

import time
import subprocess
import sys
import msvcrt

alarm1 = int(raw_input("How many seconds (alarm1)? "))

while (1):
    time.sleep(alarm1)
    print "Alarm1"
    sys.stdout.flush()

    # Try to flush the buffer
    while msvcrt.kbhit():
        msvcrt.getch()

    print "Continue (Y/N)?[Y]"
    doit = msvcrt.getch()
    print "Input",doit
    if doit == 'N' or doit=='n':
        print "Exiting....."
        break

Upvotes: 14

Callahad
Callahad

Reputation: 1310

On Unices, you can use termios.tcflush():

import time
import subprocess
import sys
from termios import tcflush, TCIOFLUSH

alarm1 = int(raw_input("How many minutes (alarm1)? "))

while (1):
    time.sleep(60*alarm1)
    print "Alarm1"
    sys.stdout.flush();
    tcflush(sys.stdin, TCIOFLUSH)
    doit = raw_input("Continue (Y/N)?[Y]: ")
    print "Input",doit
    if doit == 'N' or doit=='n':
        print "Exiting....."
        break

Upvotes: 10

Related Questions