Raw Mode on Unix edit
Use the term module in tcllibpackage require term ::term::ansi::ctrl::unix::raw
Alternatively, Unix platforms (e.g. Linux, Solaris, MacOS X, AIX, and even Cygwin, 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 <@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 <@$channel } proc disableRaw {{channel stdin}} { exec /bin/stty -raw echo <@$channel } enableRaw set c [read stdin 1] puts -nonewline $c disableRaw
Raw Mode on Windows edit
A different approach is needed on Microsoft Windows NT-based systems. With Cygwin installed, exec stty works well (tested on Windows XP SP2). Otherwise, 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 disableRawThis code was adapted from the Echo-free password entry page with the help of the MSDN reference page for GetConsoleMode.If you are using TWAPI 0.7 or above, you can use modify_console_input_mode[1] to simplify the above code.(Apparently, you're stuck on 95/98/ME.)
schlenk 2005-09-8: 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 2005-09-10:Whats wrong with using fileevents:
JMN 2005-09-28:So how would one go about getting the non-ascii keypresses such as arrow keys from a console app under windows?For Unix systems (I tried it on FreeBSD) the script on determining scan codes for key sequences works ok. On windows however - even if I put the console in raw mode using either the cygwin stty utility or using twapi - various keys such as arrow keys never seem to result in any data on stdin.2005-10-03Answering my own question.. I've reached a satisfactory result using Yet another dll caller to call the kernel32 functions: CreateFileA & ReadConsoleInputW. Declared using:
I tried to use the script given as an example in the paragraph titled Raw Mode on Unix, but I am getting exception like,
proc readsingle {} {puts "I read '[read stdin 1]' char"} fileevent stdin read readsingleThis should work on all platforms
- DKF: Once you're in raw mode, using fileevent is exactly the way to do it (assuming you want to keep the event loop active, of course). In cooked mode, the data only ever comes to Tcl in the first place by whole lines, so fileevent works, but isn't too useful for when you want to read less than a line (e.g. a single char).
- DKF: That has no effect; the -buffering option is for output not input (and thus isn't useful on stdin at all).
JMN 2005-09-28:So how would one go about getting the non-ascii keypresses such as arrow keys from a console app under windows?For Unix systems (I tried it on FreeBSD) the script on determining scan codes for key sequences works ok. On windows however - even if I put the console in raw mode using either the cygwin stty utility or using twapi - various keys such as arrow keys never seem to result in any data on stdin.2005-10-03Answering my own question.. I've reached a satisfactory result using Yet another dll caller to call the kernel32 functions: CreateFileA & ReadConsoleInputW. Declared using:
dll::load kernel32 -> k ::k::cmd "int ReadConsoleInputW(int, char *, int, int*)" ::k::cmd "int CreateFileA(char *, int, int, int *, int, int, int)"ReadConsoleInput allows you to supply a buffer which gets filled with various events including keypresses (keyup & keydown) & window focus events. Of course - you have to work out what bytes in the buffer correspond to what parts of the Windows API structures - and you may end up having to map your keyboard scan-codes to ascii values or in the case of arrow-keys etc - to ansi escape sequences.It's a lot of work because you also have to do things such as track the state of modifier keys such as shift & ctrl to change the values you send. http://vt100.net can be helpful for working out some of the sequences and general ideas behind terminals.I then use the Memchan package to create a fifo2. One end of the fifo2 can then be transferred to another thread using thread::transfer (Thread package)This allows you to have the ReadConsoleInput handler running in its own thread, pumping keypress information to your main thread over a channel which you can read instead of stdin. i.e the net result is that you can get basically the same information (and more if needed) you'd get from a raw-mode stdin on a unix platform.Using CreateFileA on the special file name {conin$} you get a handle for console input (instead of 'GetStdHandle -10' to get stdin). Personally I like the idea of having console data available from a channel other than stdin - so stdin can be used for other data whilst allowing interaction on the console.Next question... How do I intercept console keypress events on unix platforms so I can keep stdin free?
I tried to use the script given as an example in the paragraph titled Raw Mode on Unix, but I am getting exception like,
/bin/stty: standard input: Invalid argumentAm I missing something? Do I need to add anything to script other than the one given here?LV: What version of unix are you using?