''[DKF], 8-Sep-2005'' How to read a single character from the keyboard using ''just'' [Tcl]? (It's pretty easy using a Tk GUI, of course!) Why doesn't just doing [['''[read] stdin 1''']] work? Well, in fact it ''does'' work, but only if the terminal isn't working in line-editing mode. In line-editing mode, the OS terminal engine only sends the text to the applications once the user presses the return key. Guess what mode the terminal is in by default? :^/ (A little terminology. We're trying to switch things to ''raw'' mode here so we can read the "raw" keystrokes, with the default line-editing mode often called ''cooked'' mode by contrast.) ---- '''Raw Mode on Unix''' On [Unix] platforms (e.g. [Linux], [Solaris], [Mac OSX], [AIX], etc.) you can use the '''stty''' program to turn raw mode on and off, like this: exec /bin/stty raw <@stdin set c [read stdin 1] exec /bin/stty -raw <@stdin (We use the '''<@stdin''' because stty works out what terminal to work with using standard input on some platforms. On others it prefers /dev/tty instead, but putting in the redirection makes the code more portable.) However, it is usually a good idea to turn off echoing of characters in raw mode. It means that you're responsible for everything, but that's often what you want anyway. Wrapping things up in some procedures, we get this: proc enableRaw {{channel stdin}} { exec /bin/stty raw -echo <@stdin } proc disableRaw {{channel stdin}} { exec /bin/stty -raw echo <@stdin } enableRaw set c [read stdin 1] puts -nonewline $c disableRaw ---- '''Raw Mode on Windows''' A different approach is needed on WinNT. This requires the [twapi] extension. package require twapi proc enableRaw {{channel stdin}} { set console_handle [twapi::GetStdHandle -10] set oldmode [twapi::GetConsoleMode $console_handle] set newmode [expr {$oldmode & ~6}] ;# Turn off the echo and line-editing bits twapi::SetConsoleMode $console_handle $newmode } proc disableRaw {{channel stdin}} { set console_handle [twapi::GetStdHandle -10] set oldmode [twapi::GetConsoleMode $console_handle] set newmode [expr {$oldmode | 6}] ;# Turn on the echo and line-editing bits twapi::SetConsoleMode $console_handle $newmode } enableRaw set c [read stdin 1] puts -nonewline $c disableRaw This code was adapted from the [Echo-free password entry] page with the help of the appropriate page on MSDN[http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dllproc/base/getconsolemode.asp]. ---- [[Category ?]]