Get pressed key linux

Check keypress in C++ on Linux

Is there an easy way to check if a key is being pressed so I can loop through that in a thread? Preferred not to use a library and definitely not ncurses. There isn’t a single thing working that I have found over the internet.

2 Answers 2

#include #include #include #include #include #include #include int main() < struct termios oldSettings, newSettings; tcgetattr( fileno( stdin ), &oldSettings ); newSettings = oldSettings; newSettings.c_lflag &= (~ICANON & ~ECHO); tcsetattr( fileno( stdin ), TCSANOW, &newSettings ); while ( 1 ) < fd_set set; struct timeval tv; tv.tv_sec = 10; tv.tv_usec = 0; FD_ZERO( &set ); FD_SET( fileno( stdin ), &set ); int res = select( fileno( stdin )+1, &set, NULL, NULL, &tv ); if( res >0 ) < char c; printf( "Input available\n" ); read( fileno( stdin ), &c, 1 ); >else if( res < 0 ) < perror( "select error" ); break; >else < printf( "Select timeout\n" ); >> tcsetattr( fileno( stdin ), TCSANOW, &oldSettings ); return 0; > 

commonly known as kbhit in windows!os/2!dos land. Keep in mind you have to get the key or this will continue to report there’s a keypress available. Call getch() when this indicates a key is ready.

#include #include #include "X11/keysym.h" /** * * @param ks like XK_Shift_L, see /usr/include/X11/keysymdef.h * @return */ bool key_is_pressed(KeySym ks) < Display *dpy = XOpenDisplay(":0"); char keys_return[32]; XQueryKeymap(dpy, keys_return); KeyCode kc2 = XKeysymToKeycode(dpy, ks); bool isPressed = !!(keys_return[kc2 >> 3] & (1 bool ctrl_is_pressed() < return key_is_pressed(XK_Control_L) || key_is_pressed(XK_Control_R); >int main(int argc, char **argv) < std::cout ; 

Nice, but I assume this will only work if you're in an X environment (in other words, won't work on a pure tty or under Wayland, for example)?

What's the hell is this: !!(keys_return[kc2 >> 3] & (1

keys_return is an array of 32*8 bits, where every bit with the number kc2 is a status of the corresponding key with keycode kc2 . Our goal is to convert kc2 to somewhat of coordinates in "two-dimensional array" keys_return . To achieve that, we first need to get correct row by dividing kc2 / 8 (remember each "row" is 8 bits. kc2 >> 3 does the same as kc2 / 8 . Then we get "column" kc2 % 8 , which is the same as kc2 & 7 . Hovewer, since it's a bit, we need to shift 1 to get it.

Источник

Detecting keyboard key press and release on Linux

I'm trying to write a simple program that does a specific task when no key is pressed and does another task when any key is pressed. This is what I have so far:

#include #include #include #include #include #include #include #include #include int kbhit (void); int main() < char c; while(1) < while (!kbhit()) < printf("%d", 0); >c = getchar(); printf("%c", c); if(c == 'x' || c == 'X') break; sleep(0); > return 0; > int kbhit (void)

This implementation is good for detecting a single key press over and over, but if you keep the keyboard key pressed, there are significant gaps between detecting the key press. Even though the key is pressed all the time, 0 is printed to console anyway. For example, output looks something like this if I keep 'W' pressed: 000000000000000WWWWWWWW00000000000000000WWWWWWWW00000000.
How can I fix this so that when a keyboard key is kept pressed, kbhit() always returns 0?

Читайте также:  Linux echo current path

2 Answers 2

Your kbhit (and, apparently, even Windows' original kbhit ) doesn't detect whether a key is pressed, but only whether there is something new to read on stdin . This will only be the case 25 times a second or so, depending on your autorepeat setting. Making stdout unbuffered in your example code will make that more obvious ( 000000W00000000W000000000W )

How can I fix this so that when a keyboard key is kept pressed, kbhit() always returns 0?

This is impossible to do portably. In Linux, it can be done using the device files under /dev/input See the example program below. It will register all keys, even a lone SHIFT Note that this is effectively a keylogger, so you will have to run as root (or make the program setuid). It will then register all keystrokes, even when it doesn't have keyboard focus. Yikes!

Note: the example below is based on keystate.c by Kevin Cox

#include #include #include #include #include #include #include #include /* Return -1 if no key is being pressed, or else the lowest keycode (c.f. linux/input-event-codes.h) of all the keys that are being pressed */ int keycode_of_key_being_pressed() < FILE *kbd; glob_t kbddev; // Glob structure for keyboard devices glob("/dev/input/by-path/*-kbd", 0, 0, &kbddev); // Glob select all keyboards int keycode = -1; // keycode of key being pressed for (int i = 0; i < kbddev.gl_pathc ; i++ ) < // Loop through all the keyboard devices . if (!(kbd = fopen(kbddev.gl_pathv[i], "r"))) < // . and open them in turn (slow!) perror("Run as root to read keyboard devices"); exit(1); >char key_map[KEY_MAX/8 + 1]; // Create a bit array the size of the number of keys memset(key_map, 0, sizeof(key_map)); // Fill keymap[] with zero's ioctl(fileno(kbd), EVIOCGKEY(sizeof(key_map)), key_map); // Read keyboard state into keymap[] for (int k = 0; k < KEY_MAX/8 + 1 && keycode < 0; k++) < // scan bytes in key_map[] from left to right for (int j = 0; j > > fclose(kbd); if (keycode) break; // don't scan for any other keyboards > return keycode; > void main() < setvbuf(stdout, NULL, _IONBF, 0); // Set stdout unbuffered while (1) < int key = keycode_of_key_being_pressed(); printf((key < 0 ? "no key\n" : "keycode: %d\n"), key); if (key == KEY_X) exit(0); >> 

Источник

How to check if a key was pressed in Linux? [closed]

I'm assuming that you want this on a terminal emulator (and not on an X client), and that you don't care about key release.

The Linux way to do this would be to use termios(3) to set the terminal to non-canonical or to raw mode, then read stdin using the usual libc functions.

System call numbers on Linux are on /usr/include/asm/unistd.h (or unistd_64.h), but the termios functions end up getting converted to ioctl()'s. So, if you can't call libc for some strange and unusual reason, you'll have to lookup the syscall number for ioctl, and the ioctl's corresponding to termios functions.

Читайте также:  Help on linux command line

Apparently, you're assuming that Linux uses the same model as DOS, in which the console input is an abstraction of a keyboard (with functions like KEYPRESSED, GETC, . ) and the console output is an abstraction of a character-oriented display.

Unix/Linux abstraction is about terminals, which can be the physical console, a terminal (or terminal emulator) on a serial port, an xterm, . An important point here is that by default, input lines are not made available to programs until the terminal (or terminal emulator) sees a line delimiter.

On POSIX, these terminals are controlled by the termios(3) functions. Linux ends up translating those to ioctl() calls, as follows (see tty_ioctl(4) ):

  • tcgetattr(fd, arg) => ioctl(fd, TCGETS, arg)
  • tcsetattr(fd, TCSANOW, arg) => ioctl(fd, TCSETS, arg)
  • tcsetattr(fd, TCSADRAIN, arg) => ioctl(fd, TCSETSW, arg)
  • tcsetattr(fd, TCSAFLUSH, arg) => ioctl(fd, TCSETSF, arg)
  • .

So, a C program to do what you asked for, using termios(3) and poll(2) (error checking stripped for brevity and clarity):

#include #include #include #include #include #include #include #include static sig_atomic_t end = 0; static void sighandler(int signo) < end = 1; >int main() < struct termios oldtio, curtio; struct sigaction sa; /* Save stdin terminal attributes */ tcgetattr(0, &oldtio); /* Make sure we exit cleanly */ memset(&sa, 0, sizeof(struct sigaction)); sa.sa_handler = sighandler; sigaction(SIGINT, &sa, NULL); sigaction(SIGQUIT, &sa, NULL); sigaction(SIGTERM, &sa, NULL); /* This is needed to be able to tcsetattr() after a hangup (Ctrl-C) * see tcsetattr() on POSIX */ memset(&sa, 0, sizeof(struct sigaction)); sa.sa_handler = SIG_IGN; sigaction(SIGTTOU, &sa, NULL); /* Set non-canonical no-echo for stdin */ tcgetattr(0, &curtio); curtio.c_lflag &= ~(ICANON | ECHO); tcsetattr(0, TCSANOW, &curtio); /* main loop */ while (!end) < struct pollfd pfds[1]; int ret; char c; /* See if there is data available */ pfds[0].fd = 0; pfds[0].events = POLLIN; ret = poll(pfds, 1, 0); /* Consume data */ if (ret >0) < printf("Data available\n"); read(0, &c, 1); >> /* restore terminal attributes */ tcsetattr(0, TCSANOW, &oldtio); return 0; > 

Now, ioctl and poll are syscalls, and you can find their numbers on /usr/include/asm/unistd.h (54 and 168 on x86), and /usr/include/asm/ioctls.h has the ioctl constants you need (on x86: TCGETS=0x5401, TCSETS=0x5402, TCSETSW=0x5403, TCSETSF=0x5404).

Источник

Ubuntu: show what keys are pressed in real-time [duplicate]

I am looking for a tool that tells what keys (including Alt, Shift, Ctrl, etc) are pressed now. Need it to do a health-check on a possibly faulty keyboard.

4 Answers 4

Install keymon . It's in the Universe repository and run it using key-mon (not keymon !).

Keymon - Keyboard and mouse monitor window for GTK.

Do read man keymon for all the options available.

You should also right-click on it to check that the settings are appropriate for you.

And if you don't like the default location, drag it to a more suitable position on your screen.

An alternative is screenkey , also in the Universe repository. A feature of screenkey is that it's interface only when you type something and disappears after a few seconds if the keyboard is inactive. However, unlike keymon, screenkey doesn't register mouse clicks.

Читайте также:  Remote linux command from windows

There's a YouTube video on both keymon and screenkey . The video's in German but still is easy to follow.

A search for keymon of key-mon currently returns no results from the Universe. You might need to expand your answer.

To test a possibly faulty keyboard it's best to go as low-level as possible. One of the easiest ways to do this without diving into kernel space is to work almost directly with /dev/input/event* device files. Namely, you can use evtest to see all the keyboard input. If you run it in grabbing mode, this will let you intercept everything—even Magic SysRq combos (funnily, even SAK)!

Here's how I'd go about it. First, get a list of input devices by running sudo evtest :

$ sudo evtest No device specified, trying to scan all of /dev/input/event* Available devices: /dev/input/event0: Power Button /dev/input/event1: Power Button /dev/input/event2: PC Speaker /dev/input/event3: Video Bus /dev/input/event4: HDA Intel HDMI HDMI/DP,pcm=3 /dev/input/event5: HDA Intel HDMI HDMI/DP,pcm=7 /dev/input/event6: HDA Intel HDMI HDMI/DP,pcm=8 /dev/input/event7: HDA Intel HDMI HDMI/DP,pcm=9 /dev/input/event8: HDA Intel HDMI HDMI/DP,pcm=10 /dev/input/event9: HDA Intel PCH Front Mic /dev/input/event10: HDA Intel PCH Rear Mic /dev/input/event11: HDA Intel PCH Line /dev/input/event12: HDA Intel PCH Line Out /dev/input/event13: HDA Intel PCH Front Headphone /dev/input/event14: HDA NVidia HDMI/DP,pcm=3 /dev/input/event15: HDA NVidia HDMI/DP,pcm=7 /dev/input/event16: HDA NVidia HDMI/DP,pcm=8 /dev/input/event17: ImExPS/2 Generic Explorer Mouse /dev/input/event18: AT Translated Set 2 keyboard Select the device event number 10: 

Don't choose anything here yet: just press Ctrl + C . This run of evtest was in a simple non-grabbing mode, which won't let you intercept everything. But you now know the device file you need (in my case given above, it's /dev/input/event18 ).

Now you can actually run evtest in grabbing mode, using the --grab option, so that it intercepts all events from the keyboard—including the release of Return after you submit your command to the shell, subsequent Ctrl + C , Magic SysRq, VT switch shortcuts etc.. To avoid being locked out of the system, we'll set up a timeout for evtest .

sudo su -c 'sleep 1; timeout -k5 10 evtest --grab /dev/input/event18' 

This command does the following:

  • Waits 1 second so that you can release Return before the keyboard is grabbed (otherwise you'll get autorepeats rapidly scrolling the console)
  • Starts evtest in grabbing mode on my keyboard's device file (replace it with yours).
  • evtest is run with a timeout of 10 seconds, and additional grace period of 5 seconds in (unlikely) case it hangs, after which it's killed by SIGKILL , hopefully returning keyboard control to you.
  • sudo is wrapped around the whole command instead of only evtest to make sure that you enter the password (if needed) before sleep 1 , otherwise this sleep will be useless

During the timeout of 10 seconds (which you can, of course, change to something that suits you better) you can press anything on your keyboard—aside maybe from Fn -driven keys, which might work in a nonstandard way—and see what it inputs.

Источник

Оцените статью
Adblock
detector