Take the 2-minute tour ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems.. It's 100% free, no registration required.

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

share|improve this question

3 Answers 3

up vote 2 down vote accepted

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>

Usage:

sudo writevt /dev/ttyN command 
share|improve this answer
    
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
    
Wow, that is amazing! Written in '95. –  Emanuel Berg Sep 13 '12 at 23:11

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.

share|improve this answer
    
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 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 Sep 14 '12 at 23:40

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.

share|improve this answer
    
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

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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