''[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], [MacOS X], [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 [Microsoft Windows] NT-based systems. 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]. (Apparently, you're stuck on 95/98/ME.) ---- [schlenk] 8/Sep/2005 The same API exists on Win9x according to the MSDN article referred to above, so TWAPI may work, but it is untested and unsupported on windows 9x. '''[PWQ]''' ''10 Sept 05'' Whats wrong with using fileevents: proc readsingle {} {puts "I read '[read stdin 1]' char} fileevent stdin read readsingle This should work on all platforms [dzach] In Windows it doesn't. It waits for a newline. As it says at the begining of this page, ''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.'' Which unfortunately is true. ---- [Category Example] | [Category Device Control]