'Complex keyboard input to child process in C, Linux
Ive been trying to solve this one for some time but im unable to come up with a solution. I need a child process to understand complex WASD keyboard input (with complex I mean detect that both W and A or many other keys are being pressed at the same time) but I think that this is impossible in C due to the way characters are read from the terminal. My parent process only best result (taken from another post) is the following:
int kbhit(){
struct timeval tv;
fd_set fds;
tv.tv_sec = 0;
tv.tv_usec = 0;
FD_ZERO(&fds);
FD_SET(STDIN_FILENO, &fds);
select(STDIN_FILENO+1, &fds, NULL, NULL, &tv);
return FD_ISSET(STDIN_FILENO, &fds);
}
int main(){
system("stty raw -echo"); //No need to newline to read key and disables showing pressed key
char command;
unsigned short count = 0;
while(1){
while(1){
if(kbhit()){count = 0; command = getchar(); break;}
if(count > 5) {count = 0; command = 'f'; break;}
count++;
//Add code to somehow wait a few milliseconds
}
//Use read key/command...
//If a certain key is read break out of loop
}
system("stty sane echo"); //Return terminal to normal state
return EXIT_SUCCESS;
}
This is way too "hacky" and it does not detect multiple simultaneous key presses and I need a child process to read these keys, this code does not work under a fork since the keyboard is being sent to the parent, the child has no new STDIN (I think). I cant rewrite my entire program in another language due to many low level things im doing elsewhere. Ive thought of the following solutions but im unsure of which one to go for:
- Have the child process use system("xterm") to open a new terminal and send keys over this one, this does not solve the multiple keys same time problem and from my first tests im unable to link this new terminal to the running process as this terminal just runs a fresh bash session. Code blocks until this terminal is closed.
- Use another language like c++ or java that does support easily reading simultaneous key presses and somehow "pipe" this to the child process. I guess the child would fork and have the other process run this new code with a system call. Im unsure of how to send this to the other process (sockets maybe?).
Are there other better ways of doing this? Would option 2 work? Im lost and stuck, any help is welcome!
Solution 1:[1]
The simplest way to do it will be by creating events. for example
struct SKeyEvent
{
char key;
uint8_t pressed;
};
so when a key is pressed you can use a callback function to update the structure with the key and 0, 1, 2 1 and 2. 1 = pressed, 2=released and followed right away by 0 = idle. so when I pressed A the function callback will be called with {key:'A', 1} if you press W same {'W', 1} so you know that A and W are pressed simultaneously. when a touch is released you will receive 2 calls for example {'A' : 2}, {'A' :0}
Solution 2:[2]
I solved this instead of reading characters from the terminal (does not work since you can only input one char a time...) by reading the actual keyboard device (/dev/...). There are some examples of this around.
The downside is that it captures all keyboard input and you now need to run the program as superuser but it works...
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | lilington |
Solution 2 | i8_sum_Pi |