diff --git a/clientloop.c b/clientloop.c
index 9ab56b4..001b77b 100644
--- a/clientloop.c
+++ b/clientloop.c
@@ -163,6 +163,7 @@ static int session_closed = 0;	/* In SSH2: login session closed. */
 
 static void client_init_dispatch(void);
 int	session_ident = -1;
+static int stdin_fd;
 
 int	session_resumed = 0;
 
@@ -515,15 +516,45 @@ server_alive_check(void)
 	client_register_global_confirm(NULL, NULL);
 }
 
+/* This wrapper to select(2) allows the user to supply a list of sleep times
+ * to be woken up on.  The process is woken up either after activity on the
+ * fds, or when the soonest sleep time arrives.  In the latter case, the
+ * index of the relevant sleep event is recorded in *active_time.
+ */
+static int
+select_times(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
+	int ntimes, struct timeval **times, int *active_time)
+{
+	struct timeval *tvp;
+	int i, retval;
+	int soonest_index = -1;
+
+	for (i = 0; i < ntimes; i++) {
+		if (!times[i])
+			continue;
+		if (soonest_index == -1)
+			soonest_index = i;
+		else if (timercmp(times[i], times[soonest_index], <))
+			soonest_index = i;
+	}
+	tvp = (soonest_index == -1) ? NULL : times[soonest_index];
+	retval = select(nfds, readfds, writefds, exceptfds, tvp);
+	*active_time = (retval == 0) ? soonest_index : -1;
+	return retval;
+}
+
 /*
  * Waits until the client can do something (some data becomes available on
  * one of the file descriptors).
  */
 static void
 client_wait_until_can_do_something(fd_set **readsetp, fd_set **writesetp,
-    int *maxfdp, u_int *nallocp, int rekeying)
+    int *maxfdp, u_int *nallocp, int rekeying, struct timeval *hidden_input_time)
 {
-	struct timeval tv, *tvp;
+	struct timeval *times[2];
+	struct timeval keepalive_wait, hidden_input_wait, hidden_input_interval;
+	struct timeval now;
+	int active_time;
 	int ret;
 
 	/* Add any selections by the channel mechanism. */
@@ -570,14 +601,47 @@ client_wait_until_can_do_something(fd_set **readsetp, fd_set **writesetp,
 	 * event pending.
 	 */
 
-	if (options.server_alive_interval == 0 || !compat20)
-		tvp = NULL;
+	if (options.server_alive_interval == 0)
+		times[0] = NULL;
+	else {
+		keepalive_wait.tv_sec = options.server_alive_interval;
+		keepalive_wait.tv_usec = 0;
+		times[0] = &keepalive_wait;
+	}
+	if (options.hide_input_timing == 0)
+		times[1] = NULL;
 	else {
-		tv.tv_sec = options.server_alive_interval;
-		tv.tv_usec = 0;
-		tvp = &tv;
+		gettimeofday(&now, NULL);
+		if (timercmp(hidden_input_time, &now, <))
+			timerclear(&hidden_input_wait);
+		else
+			timersub(hidden_input_time, &now, &hidden_input_wait);
+		times[1] = &hidden_input_wait;
+		FD_CLR(stdin_fd, *readsetp);
+	}
+
+	ret = select_times((*maxfdp)+1, *readsetp, *writesetp, NULL,
+		2, times, &active_time);
+	gettimeofday(&now, NULL);
+
+	/* Did we stop waiting because it's time to ping the server? */
+	if (active_time == 0)
+		server_alive_check();
+
+	/* Did we stop waiting because it's time to check for keyboard input? */
+	if (active_time == 1
+	    || (hidden_input_time && timercmp(hidden_input_time, &now, <))) {
+		hidden_input_interval.tv_sec = 0;
+		hidden_input_interval.tv_usec = options.hide_input_timing;
+		timeradd(hidden_input_time, &hidden_input_interval,
+			 hidden_input_time);
+		FD_SET(stdin_fd, *readsetp);
+		times[0] = &hidden_input_wait;
+		timerclear(times[0]);
+		ret = select_times((*maxfdp)+1, *readsetp, *writesetp, NULL,
+			1, times, &active_time);
 	}
-	ret = select((*maxfdp)+1, *readsetp, *writesetp, NULL, tvp);
+
 	if (ret < 0) {
 		char buf[100];
 
@@ -595,8 +659,7 @@ client_wait_until_can_do_something(fd_set **readsetp, fd_set **writesetp,
 		snprintf(buf, sizeof buf, "select: %s\r\n", strerror(errno));
 		buffer_append(&stderr_buffer, buf, strlen(buf));
 		quit_pending = 1;
-	} else if (ret == 0)
-		server_alive_check();
+	}
 }
 
 static void
@@ -1311,6 +1374,7 @@ client_loop(int have_pty, int escape_char_arg, int ssh2_chan_id)
 	u_int64_t ibytes, obytes;
 	u_int nalloc = 0;
 	char buf[100];
+	struct timeval hidden_input_time, *hidden_input_time_ptr = NULL;
 
 	debug("Entering interactive session.");
 
@@ -1367,6 +1431,7 @@ client_loop(int have_pty, int escape_char_arg, int ssh2_chan_id)
 
 	if (compat20) {
 		session_ident = ssh2_chan_id;
+		stdin_fd = channel_by_id(session_ident)->rfd;
 		if (escape_char_arg != SSH_ESCAPECHAR_NONE)
 			channel_register_filter(session_ident,
 			    client_simple_escape_filter, NULL,
@@ -1376,10 +1441,18 @@ client_loop(int have_pty, int escape_char_arg, int ssh2_chan_id)
 			channel_register_cleanup(session_ident,
 			    client_channel_closed, 0);
 	} else {
+		stdin_fd = fileno(stdin);
+
 		/* Check if we should immediately send eof on stdin. */
 		client_check_initial_eof_on_stdin();
 	}
 
+	if (options.hide_input_timing != 0)
+	{
+		gettimeofday(&hidden_input_time, NULL);
+		hidden_input_time_ptr = &hidden_input_time;
+	}
+
 	/* Main loop of the client for the interactive session mode. */
 	while (!quit_pending) {
 
@@ -1423,7 +1496,7 @@ client_loop(int have_pty, int escape_char_arg, int ssh2_chan_id)
 		 */
 		max_fd2 = max_fd;
 		client_wait_until_can_do_something(&readset, &writeset,
-		    &max_fd2, &nalloc, rekeying);
+		    &max_fd2, &nalloc, rekeying, hidden_input_time_ptr);
 
 		if (quit_pending)
 			break;
diff --git a/readconf.c b/readconf.c
index 8bdc8ca..42069d5 100644
--- a/readconf.c
+++ b/readconf.c
@@ -118,7 +118,8 @@ typedef enum {
 	oUser, oHost, oEscapeChar, oRhostsRSAAuthentication, oProxyCommand,
 	oGlobalKnownHostsFile, oUserKnownHostsFile, oConnectionAttempts,
 	oBatchMode, oCheckHostIP, oStrictHostKeyChecking, oCompression,
-	oCompressionLevel, oTCPKeepAlive, oNumberOfPasswordPrompts,
+	oCompressionLevel, oTCPKeepAlive, oHideInputTiming,
+	oNumberOfPasswordPrompts,
 	oUsePrivilegedPort, oLogLevel, oCiphers, oProtocol, oMacs,
 	oGlobalKnownHostsFile2, oUserKnownHostsFile2, oPubkeyAuthentication,
 	oKbdInteractiveAuthentication, oKbdInteractiveDevices, oHostKeyAlias,
@@ -198,6 +199,7 @@ static struct {
 	{ "compression", oCompression },
 	{ "compressionlevel", oCompressionLevel },
 	{ "tcpkeepalive", oTCPKeepAlive },
+	{ "hideinputtiming", oHideInputTiming },
 	{ "keepalive", oTCPKeepAlive },				/* obsolete */
 	{ "numberofpasswordprompts", oNumberOfPasswordPrompts },
 	{ "loglevel", oLogLevel },
@@ -336,6 +338,7 @@ process_config_line(Options *options, const char *host,
 {
 	char *s, **charptr, *endofnumber, *keyword, *arg, *arg2, fwdarg[256];
 	int opcode, *intptr, value, value2, scale;
+	float val_float;
 	LogLevel *log_level_ptr;
 	long long orig, val64;
 	size_t len;
@@ -500,6 +503,16 @@ parse_yesnoask:
 		intptr = &options->tcp_keep_alive;
 		goto parse_flag;
 
+	case oHideInputTiming:
+		arg = strdelim(&s);
+		if (!arg || *arg == '\0')
+			arg = "0.1";
+		if (!isdigit(arg[0]) && arg[0] != '.')
+			fatal("%.200s line %d: Bad number.", filename, linenum);
+		sscanf(arg, "%f", &val_float);
+		options->hide_input_timing = val_float * 1000000;
+		break;
+
 	case oNoHostAuthenticationForLocalhost:
 		intptr = &options->no_host_authentication_for_localhost;
 		goto parse_flag;
@@ -1026,6 +1039,7 @@ initialize_options(Options * options)
 	options->strict_host_key_checking = -1;
 	options->compression = -1;
 	options->tcp_keep_alive = -1;
+	options->hide_input_timing = -1;
 	options->compression_level = -1;
 	options->port = -1;
 	options->address_family = -1;
@@ -1127,6 +1141,8 @@ fill_default_options(Options * options)
 		options->compression = 0;
 	if (options->tcp_keep_alive == -1)
 		options->tcp_keep_alive = 1;
+	if (options->hide_input_timing == -1)
+		options->hide_input_timing = 100000;
 	if (options->compression_level == -1)
 		options->compression_level = 6;
 	if (options->port == -1)
diff --git a/readconf.h b/readconf.h
index 4264751..2bf65cc 100644
--- a/readconf.h
+++ b/readconf.h
@@ -57,6 +57,7 @@ typedef struct {
 	int     compression_level;	/* Compression level 1 (fast) to 9
 					 * (best). */
 	int     tcp_keep_alive;	/* Set SO_KEEPALIVE. */
+	long	hide_input_timing;	/* Frequency of reading keyboard data */
 	LogLevel log_level;	/* Level for logging. */
 
 	int     port;		/* Port to connect. */
