问题
If I am working in an application and I press key from keyboard, how can I capture that key (or string), including the source application's name, in C, under GNU/LINUX, in userland, without X11 :)
Thanks.
回答1:
Well, without X11 this problem is way more difficult.
For the keystroke part you can use a code similar to this one, but you have to pass as an argument the device that you are reading (keyboard, usually /dev/input/event0 )
#include <linux/input.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
int main(int argc, char **argv)
{
int fd;
if(argc < 2) {
printf("usage: %s <device>\n", argv[0]);
return 1;
}
fd = open(argv[1], O_RDONLY);
struct input_event ev;
while (1)
{
read(fd, &ev, sizeof(struct input_event));
if(ev.type == 1)
printf("key %i state %i\n", ev.code, ev.value);
}
}
Credits do not go to me, this code is taken from the Ventriloctrl hack to get keystrokes. http://public.callutheran.edu/~abarker/ventriloctrl-0.4.tar.gz
Hope I am of some help.
回答2:
You can read data from one of the files in /dev/input. Which one depends on your system. It might be /dev/input/event0 or /dev/input/by-path/platform-i8042-serio-0-event-kbd or something else. The format is specified in the kernel header input.h. It is
struct input_event {
struct timeval time;
__u16 type;
__u16 code;
__s32 value;
};
You can run
od -tx2 FILENAME
and type something to see what happens.
As for finding out which application received the key event, I'm not sure. You could try checking which one is reading from the main tty.
回答3:
One possibility: find and take a look at the source for 'sudosh', the 'sudo shell' (or one of its replacements since that has not been modified in a while; Google is your friend).
It messes with pseudo-ttys and tracks all the input and output by also recording the information to file.
Whether that is precise enough for you is perhaps more debatable; it would log all keystrokes for all applications. I'm also not certain how it works with X11 - if it works with X11.
回答4:
For a pretty good example, have a look at showkey's code.
In particular, here's the main loop. All it does is get the terminal, copy it, turn the copied one to raw mode, and until a 'quit' or 'interrupt' key sequence is given, it merely prints out what key was given to the terminal.
/*
* showkey.c -- display cooked key sequences
*
* Invoke this (no arguments needed) to see keycap-to-keystrokes mappings.
*
* by Eric S. Raymond <esr@snark.thyrsus.com>, 1 Nov 88
* - fix for little-endian machines (version 1.1), 21 Oct 1996.
* - cleanup and modern packaging (version 1.2), 1 Aug 2002.
* - changed to use termios (version 1.3), 26 Aug 2002.
* See the RPM spec file changelog for more recent stuff.
*/
#include <stdio.h>
#include <termios.h>
#include <signal.h>
#include <string.h>
#include <stdbool.h>
static int signalled;
// ...
main()
{
struct termios cooked, raw;
unsigned char c;
unsigned int i, timeouts;
char intrchar[32], quitchar[32];
for (i = SIGHUP; i <= SIGIO; i++)
(void) signal(c, catcher);
// Get the state of the tty
(void) tcgetattr(0, &cooked);
// Make a copy we can mess with
(void) memcpy(&raw, &cooked, sizeof(struct termios));
// Turn off echoing, linebuffering, and special-character processing,
// but not the SIGINT or SIGQUIT keys.
raw.c_lflag &=~ (ICANON | ECHO);
// Ship the raw control blts
(void) tcsetattr(0, TCSANOW, &raw);
(void) printf("Type any key to see the sequence it sends.\n");
visualize(raw.c_cc[VINTR], intrchar);
visualize(raw.c_cc[VQUIT], quitchar);
(void) printf("Terminate with your shell interrupt %s or quit %s character.\n",
intrchar, quitchar);
signalled = 0;
while (!signalled)
{
char cbuf[32];
read(0, &c, 1);
visualize(c, cbuf);
(void)fputs(cbuf, stdout);
(void) fflush(stdout);
}
(void) printf("\nBye...\n");
// Restore the cooked state
(void) tcsetattr(0, TCSANOW, &cooked);
}
来源:https://stackoverflow.com/questions/1485116/capturing-keystrokes-in-gnu-linux-in-c-without-x11