Reputation: 11444
I have the following program which is basically reading chars from keyboard (getch() does this without the need to click 'ENTER', function is taken from here:Capture characters from standard input without waiting for enter to be pressed) , and then if the char is one of the legal moves (LEFT, RIGHT, etc) it is writing it to a pipe, which draw.out is reading from.
draw.out is reading the input it recieved and printing to screen. (assume this program works fine, I assure the problem is in the following code only).
The problem is, that:
draw.out is acting like it has recieving my input over and over again. Which means, for some reason, even though I press, for exmaple, DOWN key only once, it sends draw.out as if I clicked many times on it.
After sending one input, I cannot send anymore, as if the loop is stopping.
Tried to break my head over this for many hours... I'd really appreciate help.
int main(int argc, const char* argv[])
{
pid_t child_pid;
int fda[2];
if(pipe(fda)<0)
perror("pipe error");
if((child_pid=fork())<0)
perror("fork error");
else
{
//if we're in father
if(child_pid>0)
{
char c=' ';
//close read side
close(fda[0]);
while(c!=QUIT)
{
//get an instruction from keyboard
while(c!=ROTATE && c!=LEFT && c!=RIGHT &&
c!=DOWN && c!=QUIT)
{
c=getch();
}
//write the instruction to pipe
write(fda[1],&c,1);
//notify the child
kill(child_pid,SIGUSR2);
}
}
//if we're in child process
else
{
dup2(fda[0],0);
close(fda[0]);
close(fda[1]);
execl("./draw.out","./draw.out",NULL);
}
}
//close everything
close(fda[0]);
close(fda[1]);
return 0;
}
//this function works well in linux with tsch installed or in SSH bash shell
char getch()
{
char buf = 0;
struct termios old = {0};
if (tcgetattr(0, &old) < 0)
perror("tcsetattr()");
old.c_lflag &= ~ICANON;
old.c_lflag &= ~ECHO;
old.c_cc[VMIN] = 1;
old.c_cc[VTIME] = 0;
if (tcsetattr(0, TCSANOW, &old) < 0)
perror("tcsetattr ICANON");
if (read(0, &buf, 1) < 0)
perror ("read()");
old.c_lflag |= ICANON;
old.c_lflag |= ECHO;
if (tcsetattr(0, TCSADRAIN, &old) < 0)
perror ("tcsetattr ~ICANON");
return (buf);
}
Upvotes: 1
Views: 2633
Reputation: 361899
Change the while loop to a do/while loop to ensure getch() is always called at least once.
do
{
c = getch();
}
while (c != ROTATE && c != LEFT && c != RIGHT && c != DOWN && c != QUIT);
Upvotes: 1
Reputation: 6638
After you have sent the char c
you need to set it to a value other than ROTATE
, LEFT
, RIGHT
or DOWN
.
If you don't getch()
will never be called a second time...
So at the end of the outer while
(just after kill
) or at the start of the loop (just before the while
containing the getch()
call) add something like
if (c != QUIT)
c = ' ';
Upvotes: 1