15

I managed to do this

echo -n "command" > /dev/tty1

The letters appear, and the cursor moves, but they are "ghosts" – if you hit Enter, nothing happens (they are not in stdin).

Edit:

In the middle of the below screenshot, you see why I see the use of this. (The line with a red caption, right below the line with a yellow caption.) As it is now, you are not really "editing" the note text; you are just asked to write a new text, which will replace the text of the note you are (not really) editing. Thus, I thought it could be remedied by simply pasting the old text into the tty: if the user hits enter, no modification is made. (This program is in Perl/MySQL, but I thought it would be more interesting to ask for a general solution than "how do I do this in Perl".)

example

Edit 2:

Here is the Perl code, that uses the C code below (works exactly as intended), as well as a new screenshot – hopefully this will clarify things beyond doubt :) Again, look at the middle of the screenshot, where the edit is made to the note text - this time around, the old text is there, for example if you just wanted to fix a typo, you won't have to retype the entire note text.

my $edit_note_text = $edit_note_data[2];
print BOLD, RED, " new text: ", RESET;
system("writevt /dev/tty \"$edit_note_text\"");
my $new_text = <$in>;
$new_text = fix_input($new_text);
my $set_text = "UPDATE notes SET note = \"$new_text\" WHERE id = $edit_note_id";
$db->do($set_text);

better_example

3

I just found a small C program called writevt that does the trick. Grab the source code here. To make it compile with gcc just remove the following lines first:

#include <lct/cline.h>
#include <lct/utils.h>

Update. The command is now part of console-tools, thus available in more recent systems, unless your distribution uses kbd instead of console-tools, in which case you can compile it from source (much more recent version, no modification needed).

Usage:

sudo writevt /dev/ttyN command 

Note that, for some reason, you have to use '\r' (or '\x0D') instead of '\n' (or '\x0A') to send a return.

  • This does work, but there's way more wrong than just those includes. I had to ditch the usage function, make a progname and _, and comment out a few function calls in main() – Michael Mrozek Sep 13 '12 at 22:45
  • @MichaelMrozek The _() function is usually a sign of gettext being used. Seems a bit overkill for such a simple piece of demo code but doesn't hurt I suppose. – jw013 Sep 13 '12 at 22:55
  • The link in the above answer is broken.  I found another writevt.c here (at github.com/ grawity); it appears to be essentially the same program. – G-Man Says 'Reinstate Monica' Oct 29 '18 at 16:29
  • Does not work for me - only prints command. Dending \r or \n prinst r n resperctively for whatever reasson ;/ – Antoniossss Aug 21 at 8:22
9

A terminal doubles as two things: an input device (such as a keyboard) and a display device (such as a monitor). When you read from the terminal, you get what comes from the input device. When you write to the terminal, the data goes onto the display device.

There is no general way of forcing input into a terminal. There is rarely any need to do so. If you need to interact with a program that requires a terminal, use a dedicated terminal emulator such as Expect or Empty, or a programmable terminal wrapper such as Screen or Tmux. You can force input into a Linux console with an ioctl. You can force input into an X11 terminal emulator with tools such as xdotool or xmacro.

  • Made an edit to my post. Have a look and you'll see my thinking. – Emanuel Berg Sep 14 '12 at 17:22
  • @EmanuelBerg Your edit is hard to understand. Are you trying to programmatically feed input into a program that you're also using interactively? If that's what you want, run the program in screen or tmux and use their stuff (screen) or send-key (tmux) command or their paste buffer feature. – Gilles 'SO- stop being evil' Sep 14 '12 at 18:11
  • Made a second edit with the Perl code included - the invocation of the C binary is there. I don't know... as it was so simple (just one line of code) - is it really better to do it your way (with the screen or tmux tools)? – Emanuel Berg Sep 14 '12 at 23:34
  • @EmanuelBerg So yes, you're looking for screen -X stuff 'note version one'. – Gilles 'SO- stop being evil' Sep 14 '12 at 23:40
7

At least Linux and BSDs have the TIOCSTI ioctl to push characters back to the terminal input buffer (up to a limit [4096 characters on Linux]):

#include <sys/ioctl.h>
#include <termios.h>
#include <stdio.h>
#include <stdlib.h>

void stackchar(char c)
{
  if (ioctl(0, TIOCSTI, &c) < 0) {
    perror("ioctl");
    exit(1);
  }
}
int main(int argc, char *argv[])
{
  int i, j;
  char c;

  for (i = 1; i < argc; i++) {
    if (i > 1) stackchar(' ');
    for (j=0; (c = argv[i][j]); j++) {
      stackchar(c);
    }
  }
  exit(0);
}

Compile it, and call it as:

cmd foo bar < "$some_tty"

to push characters back on some tty.

And in perl:

require "sys/ioctl.ph";
ioctl(STDIN, &TIOCSTI, $_) for split "", join " ", @ARGV;

Edit: I realise now it's the same ioctl as in the writevt solution. The comment and the name of the command is misleading as TIOCSTI works for any terminal, not just VTs.

  • Check out my second edit to the question. I already compiled the code I got from @htor - what I can see, it works great. Can you see any advantages using this code instead? (But thanks for your effort in either case.) – Emanuel Berg Sep 14 '12 at 23:38
  • Yes. See my recent edit. The point is to use the TIOCSTI ioctl. The code I gave does just that on file descriptor 0 (stdin). – Stéphane Chazelas Sep 15 '12 at 7:42
1

I have a more complete demo over on Stack Overflow.

In python you can do:

import fcntl
import sys
import termios

with open('/dev/tty1', 'w') as fd:
    for char in "ls -la\n":
        fcntl.ioctl(fd, termios.TIOCSTI, char)

That's assuming a simple "command" value of ls -la and using the tty path specified by OP.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.