"What can I do so the characters can't be seen when a user types a password?" is a frequent question. Tk applications have a complete and simple answer: use entry's -show option. For a usage example, see A little login dialog.
nat-418 Here is a solution that works with Tcl 8.6+ in 2021:
package require term::ansi::ctrl::unix proc prompt {message {mode "normal"}} { global tcl_platform set os [lindex $tcl_platform(platform) 0] puts -nonewline "$message " if {$os ne "unix" || $mode ne "-silent"} { flush stdout return [gets stdin] } proc loop accumulator { ::term::ansi::ctrl::unix::raw flush stdout set character [read stdin 1] if {$character eq "\n" || $character eq "\r"} { puts "" ::term::ansi::ctrl::unix::cooked return $accumulator } puts -nonewline "*" append accumulator $character loop $accumulator } loop "" } set input [prompt "Password:" -silent]
A pure-Tcl solution is slightly subtler. In a Unix context, the formula is
exec stty -echo / echo
[elaborate, including signal hygiene ...--which Expect handles by itself]
"stty -echo ..." is an error-prone subject. Don Libes and marsd describe, for example, a long-standing problem that continues to plague Linux 2.4.12 [L1 ].
The Unix Terminal Extension provides the ability to disable echoing, as well as the ability to read one character at a time from stdin. See terminal:password:get for an example.
If you don't mind using the Tcl Windows API extension (which only works on Win NT platforms, not Win 98!), the following should do the trick
package require twapi set console_handle [twapi::GetStdHandle -10] set oldmode [twapi::GetConsoleMode $console_handle] set newmode [expr {$oldmode & ~4}] ;# Turn off the echo bit twapi::SetConsoleMode $console_handle $newmode gets stdin password ;#...or do whatever... twapi::SetConsoleMode $console_handle $oldmode ;# Restore echo mode
Or a slightly simpler version using the higher level console API in TWAPI 0.7:
puts -nonewline "Enter password: " flush stdout set oldmode [twapi::modify_console_input_mode stdin -echoinput false -lineinput true] gets stdin password # Restore original input mode twapi::set_console_input_mode stdin {*}$oldmode
The TWAPI extension is available from http://twapi.sf.net
drh FWIW, here is the code I am currently using to read echo-free passwords on unix:
# Read a single line of input from the terminal without echoing to the # screen. If Control-C is pressed, exit immediately. # proc tty_gets_no_echo {{prompt {}}} { if {$prompt!=""} { puts -nonewline $prompt } flush stdout global _tty_input _tty_wait tcl_platform if {$tcl_platform(platform)!="unix"} { # FIXME: This routine only works on unix. On other platforms, the # password is still echoed to the screen as it is typed. return [gets stdin] } set _tty_input {} set _tty_wait 0 fileevent stdin readable _tty_read_one_character exec /bin/stty raw -echo <@stdin vwait ::_tty_wait fileevent stdin readable {} return $_tty_input } proc _tty_read_one_character {} { set c [read stdin 1] if {$c=="\n" || $c=="\003"} { exec /bin/stty -raw echo <@stdin puts "" if {$c=="\003"} exit incr ::_tty_wait } else { append ::_tty_input $c } }
See also the slightly related app Password Gorilla