sonite
Posts: 14
Joined: Fri Aug 17, 2012 3:31 pm

In a program detect keyboard char

Fri Aug 17, 2012 3:40 pm

Hi,

I can't get a infinit loop carry out just a delay and printf function to work. If I use te function getchar the program just stops and wait until something is pressed. I tried two approches

The first:

Code: Select all

#include <stdio.h> 
#include <stdlib.h> 
#include <stdint.h> 
#include <unistd.h> 
#include <termios.h> 
 
int getch(void); // Declare of new function 
 
int main (void) 
{ 
char x; 
 
do  
{  
   if (x = getch()) 
      printf ("Got It! \n!);  
   else  
   {  
      delay(2000); 
      printf ("Not yet\n!);  
   } 
 
}while x != 'q'); 
 
return 0; 
} 
 
int getch(void) 
{ 
int ch; 
struct termios oldt; 
struct termios newt; 
 
tcgetattr(STDIN_FILENO, &oldt); 
newt = oldt; 
newt.c_lflag &= ~(ICANON | ECHO); 
tcsetattr(STDIN_FILENO, TCSANOW, &newt); 
ch = getchar(); 
tcsetattr(STDIN_FILENO, TCSANOW, &oldt); 
return ch; 
} 
Well, the above makes the new getch function read a charcter but won't wait for an Enter, it's good
becuse it's the right direction. But it still waits for an input, I want the loop to continue.

The second:

Code: Select all

#define INPUT_QUEUE "/dev/input/event0" 
#define EVENT_LEN 16 
 
void readEventLine(FILE * in, char * data) {    //read input key stream 
  int i; 
  for(i = 0; i <= 15; i++) {    //each key press will trigger 16 characters of data,    describing the event 
    data[i] = (char) fgetc(in); 
  } 
} 
 
int readKeyPress() { 
 
  FILE * input; 
  char data[EVENT_LEN]; 
 
  input = fopen(INPUT_QUEUE, "r+"); 
  readEventLine(input, data); 
} 

int main (void) 
{ 
char x; 
 
do  
{  
   x = readKeyPress();
   if (x != 0)
      printf ("Got It! \n!);  
   else  
   {  
      delay(2000); 
      printf ("Not yet\n!);  
   } 
 
}while x != 'q'); 
 
return 0; 
} 

Wont work.....help please

AndyInSurrey
Posts: 24
Joined: Mon Mar 05, 2012 8:45 am

Re: In a program detect keyboard char

Sat Aug 18, 2012 9:28 am

It might be better if you were to explain exactly what you are trying to do. If you put a function that requires user input in a condition inside a loop, like you have done, then of course execution of the program will halt at that point and wait for user input before continuing.

User avatar
jojopi
Posts: 3142
Joined: Tue Oct 11, 2011 8:38 pm

Re: In a program detect keyboard char

Sat Aug 18, 2012 12:02 pm

As well as putting the terminal into non-canonical mode, you also need to make the file descriptor non-blocking with fcntl():

Code: Select all

#include <stdio.h>
#include <unistd.h>
#include <termios.h>
#include <fcntl.h>

int getch(void);

int main(void)
{
    int x;
    do {
       if ((x = getch()) != EOF)
          printf("Got it: '%c'\n", x);
       else {
          usleep(500000);
          printf("Not yet!\n");
       }
    } while (x != 'q');
    return 0;
}

int getch(void)
{
    int ch;
    struct termios oldt, newt;
    long oldf, newf;

    tcgetattr(STDIN_FILENO, &oldt);
    newt = oldt;
    newt.c_lflag &= ~(ICANON | ECHO);
    tcsetattr(STDIN_FILENO, TCSANOW, &newt);
    oldf = fcntl(STDIN_FILENO, F_GETFL, 0);
    newf = oldf | O_NONBLOCK;
    fcntl(STDIN_FILENO, F_SETFL, newf);
    ch = getchar();
    fcntl(STDIN_FILENO, F_SETFL, oldf);
    tcsetattr(STDIN_FILENO, TCSANOW, &oldt);
    return ch;
}
However, it is unusual to mix this low-level stuff with stdio. Normally you would use read() instead of getchar(). Also you will notice that the usleep() actually delays the recognition of the characters. You can avoid this by using poll() or select() to delay only until there is input available:

Code: Select all

#include <stdio.h>
#include <unistd.h>
#include <termios.h>
#include <poll.h>

int getch(int ms);

int main(void)
{
    int x;
    do {
       if ((x = getch(500)))
          printf("Got it: '%c'\n", x);
       else
          printf("Not yet!\n");
    } while (x != 'q');
    return 0;
}

int getch(int ms)
{
    int ret;
    struct termios oldt, newt;
    struct pollfd pfds[1];

    tcgetattr(STDIN_FILENO, &oldt);
    newt = oldt;
    newt.c_lflag &= ~(ICANON | ECHO);
    tcsetattr(STDIN_FILENO, TCSANOW, &newt);
    pfds[0].fd = STDIN_FILENO;
    pfds[0].events = POLLIN;
    poll(pfds, 1, ms);
    if (pfds[0].revents & POLLIN) {
        char ch;
        read(STDIN_FILENO, &ch, 1);
        ret = ch;
    } else {
        ret = 0;
    }
    tcsetattr(STDIN_FILENO, TCSANOW, &oldt);
    return ret;
}
"apt-get install manpages-dev" and "man 2 poll" for info.

In reality, you probably need to put the terminal in the right modes at the start and restore it only on exit. Otherwise you will get occasional rogue echoes when a key arrives at the wrong time.

sonite
Posts: 14
Joined: Fri Aug 17, 2012 3:31 pm

Re: In a program detect keyboard char

Sun Aug 19, 2012 8:58 pm

Wonderful help. This is the first time I program this kind of device/os. Usually I only have some experience with uC (PIC18).

First I wanted to toggle the GPIO pins, later I discovered when closing the terminal with ctrl - C the program continues. Therefor I wanted a push of a button on the keybord to kill the process.
(is this the best approach? please don't suggest python).

I do lack a lot of knowledge in unix os and the way I should program this device.

Later on I might try to construct a graphical program for controlling the low level stuff, but
it's a hard road for me to wander. Kind Regards!

Return to “C/C++”