You are not logged in.

#1 2012-03-22 22:48:51

PL_kolek
Member
Registered: 2012-02-21
Posts: 41

Grabbing keys while playing games

Hello!
I'm trying to write an application, that could capture screenshots and then display them on the screen. This would be useful for playing games not translated to native language - you could just capture the dialogues and then read them slowly.

I use java, as it is very convenient laguage, but for grabbing keys I used JNI and c code with XGrabKey function. First problem encountered is that my application doesn't crash or exit, when I try to grab already grabbed key. I can live with, but if anyone has any solution, i would like to hear it. But more important flaw of my code is that it works perfectly to capture screenshots of desktop or normal apps, but when it comes to games - they take whole keyboard and I can't do anything.

Is there any way to grab keys, while other program grabs whole keyboard? Without that feature, I wrote useless piece of code.

I read about packages from AUR that prevent games from grabbing everything, but I wouldn't like to force anyone using my app to repeat that trick.

Offline

#2 2012-03-22 23:05:49

Trilby
Inspector Parrot
Registered: 2011-11-29
Posts: 29,523
Website

Re: Grabbing keys while playing games

I'm not sure what games would capture all keys - I have not experienced this yet ... nor would I like to.  X and your window manager should get first dibs on keys.  If a game takes that control away and the game freezes you'd then have to reset with the power switch.

I may be a bit naive of some games, but this would seem to be a very big flaw in the games that allegedly do this.

As for the screenshots - I'm curious what you're trying to do that something like scrot doesn't already do.


"UNIX is simple and coherent..." - Dennis Ritchie, "GNU's Not UNIX" -  Richard Stallman

Offline

#3 2012-03-22 23:12:16

Cloudef
Member
Registered: 2010-10-12
Posts: 636

Re: Grabbing keys while playing games

Games that do real fullscreen (not maximized borderless window), gain all control of the system. The game works bit faster this way, but IMO. I think it's bad thing as well.

Offline

#4 2012-03-23 09:56:43

Blµb
Member
Registered: 2008-02-10
Posts: 224

Re: Grabbing keys while playing games

As a linux specific solution you could read from /dev/input/event*, though that wouldn't take keyboard layouts into account, but maybe XKeycodeToKeysym can be used somehow...
For windows, there's a way to add "lowlevel keyboard hooks". I used it once, but I don't have the code here on this machine so I can't look up the exact function names you need.
For mac - no idea.


You know you're paranoid when you start thinking random letters while typing a password.
A good post about vim
Python has no multithreading.

Offline

#5 2012-03-23 10:03:09

PL_kolek
Member
Registered: 2012-02-21
Posts: 41

Re: Grabbing keys while playing games

Firstly - I checked my program, that grabs F2 and F3 while running VVVVVV or CaveStory+. I don't see any point in those games utilising those keys, but my app doesn't react in any way. Here is the problem, and I'm looking for some kind of workaround. I think any fullscreen SDL game does that, because I can check any keyevent (when programming a game), not only those I'm interested in.

And let me explain a little bit more what I'm trying to develop. Let's assume you are learning Polish, and for that purpose you combine learning and fun and play polish games. (Or you found a cool polish game, but it isn't translated to English. Not sure if that's possible). (Or you would like to see the original The Witcher dialogues, not the simplified and a little censored english translation). Whatever. While playing, the subtitles go too fast for you to read them. Solution - capture screen, and read it later. But who would like to switch windows all the time to view some dialogues? In my plans, my app would let you take the screenshots with one key, and then view them on the screen with another. And some other features, if I work it out.

I don't really care if it's reinventing the wheel, because I would also like to learn something from that wink

Offline

#6 2012-03-23 12:14:03

Trilby
Inspector Parrot
Registered: 2011-11-29
Posts: 29,523
Website

Re: Grabbing keys while playing games

PL_kolek wrote:

I can check any keyevent (when programming a game), not only those I'm interested in.

This doesn't mean they haven't already been processed by X and the window manager.

Any app with a menu responds to the alt key, but a window manager or X can also grab the alt key.  Generally the WM will do what it wants to respond to the alt key then pass it on to the running apps.

The fact that I can use a command like getch or getchar to get a keypress does not mean that the system will no longer see that key.

Is there really no way to exit these games without using the within game exit, or change to another app while the game is still running?


"UNIX is simple and coherent..." - Dennis Ritchie, "GNU's Not UNIX" -  Richard Stallman

Offline

#7 2012-03-23 13:04:15

Cloudef
Member
Registered: 2010-10-12
Posts: 636

Re: Grabbing keys while playing games

You can patch SDL to not allow real fullscreen. If you think all of the games are using SDL. If the game has it's own implementation of SDL or statically compiled, it might be harder. I've done similar patches to wine, for games to not allow resolution switching, and the ability to fake resolution for application. Which is really useful for this kind of thing and especially for dualhead setup.

Another way is to create application that listens to keys on low-level (reads /dev/input/event*), and kills the running process when certain key is pressed. However detecting the process that is real fullscreen might be harder.

Last edited by Cloudef (2012-03-23 13:05:27)

Offline

#8 2012-03-23 13:15:50

PL_kolek
Member
Registered: 2012-02-21
Posts: 41

Re: Grabbing keys while playing games

Hm... I'm going to read about reading /dev/input/event*, that might be what I'm going to achieve. The solution it by definition Linux specific, as grabbing kjeys is different on different systems. Patching SDL is not that kind of solution I'm looking for - I found AUR packages that allow me to prevent grabbing ketyboard by games, but I would like my application to run on different machine or distro, whatever, without need to patch anything.

Trilby - you're right that those keys get processed before the game has access to them, but when I use XGrabKey, I don't receive any events, so the game must grab it somehow. The problem is not with alt-tab or exiting game, but with my app.

Offline

#9 2012-03-23 13:17:08

Trilby
Inspector Parrot
Registered: 2011-11-29
Posts: 29,523
Website

Re: Grabbing keys while playing games

But if you can alt-tab to change applications, then you could set another keymap in your window manager to run your app.


"UNIX is simple and coherent..." - Dennis Ritchie, "GNU's Not UNIX" -  Richard Stallman

Offline

#10 2012-03-23 13:28:56

PL_kolek
Member
Registered: 2012-02-21
Posts: 41

Re: Grabbing keys while playing games

I looked at reading /dev/input but it seems too complicated for my simple problem. Either I resolve that problem with XGrabKey, or I give up:/

Sorry, I don't get your solution Trilby. Could provide some more details or a link to see how that could work? I have no idea

Offline

#11 2012-03-23 14:23:04

Trilby
Inspector Parrot
Registered: 2011-11-29
Posts: 29,523
Website

Re: Grabbing keys while playing games

Well ... it depends on your WM for the syntax and the file it'd go in.  Or you could use xbindkeys to bind a key to run your program.

But perhaps I'm missing something as this seems to straitforward.

xbindkeys could use something like

"myScreenShotProgram --take"
    m:0x8 + c:32
    Alt + o

"myScreenShotProgram --show"
<some other key>

Last edited by Trilby (2012-03-23 14:26:35)


"UNIX is simple and coherent..." - Dennis Ritchie, "GNU's Not UNIX" -  Richard Stallman

Offline

#12 2012-03-23 18:02:52

Cloudef
Member
Registered: 2010-10-12
Posts: 636

Re: Grabbing keys while playing games

PL_kolek wrote:

I looked at reading /dev/input but it seems too complicated for my simple problem. Either I resolve that problem with XGrabKey, or I give up:/

Sorry, I don't get your solution Trilby. Could provide some more details or a link to see how that could work? I have no idea

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <stropts.h>
#include <string.h>
#include <stdarg.h>
#include <signal.h>
#include <linux/input.h>

const char *scrot[] = { "scrot", NULL };

/* runs program */
static void run(const char **exel)
{
   /* rest is for forked process only */
   if (fork() != 0)
      return;

   setsid();
   execvp(exel[0], (char**)exel);
   _exit(0);
}

/* code:    keycode of key
 * value:   1: press 0: release
 *
 * You can use KEY_ defines to compare against keycode */
static void key_ev(unsigned int code, int value)
{
   printf("got key with code %d and value %d\n", code, value);

   /* we are only interested on presses here */
   if (value != 1)
      return;

   /* take screenshot with scrot when F12 is pressed */
   if (code == KEY_F12)
      run(scrot);
}

int main(int argc, char **argv)
{
   int fd, id, ret, rd, i; fd_set set;
   char event[64], device[256] = {0};
   struct input_event ev[64];

   /* don't wait for child processes */
   (void)signal(SIGCHLD, SIG_IGN);

   for (id = 0;; id++) {
      snprintf(event, sizeof(event), "/dev/input/event%i", id);
      fd = open(event, O_RDONLY);
      if (fd == -1)
         break;

      if (ioctl(fd, EVIOCGNAME(sizeof(device)), device) < 0)
         device[0] = '\0';

      /* crappy device detect code */
      if (strstr(device, "Keyboard"))
         break;

      /* print name */
      puts(device);
      close(fd);
   }

   if (fd == -1) {
      puts("fuuuu--- (aka could not find keyboard)");
      exit(EXIT_FAILURE);
   }

   /* found keyboard */
   printf("found: %s\n", device);

   /* enter input loop */
   while (1) {
      FD_ZERO(&set);
      FD_SET(fd, &set);

      /* block until ready for read */
      if ((ret = select(fd+1, &set, NULL, NULL, NULL)) == -1) {
         /* select failed, just continue from begining */
         continue;
      } else if (ret == 0) {
         puts("timeout?");
      } else {
         FD_ISSET(fd, &set);
      }

      /* read key */
      rd = read(fd, ev, sizeof(struct input_event) * 64);

      /* this input event is weird, discard it */
      if (rd < (int) sizeof(struct input_event))
         continue;

      for (i = 0; i < rd / sizeof(struct input_event); ++i) {
         /* we are only interested on key events */
         if (ev[i].type != EV_KEY)
            continue;

         /* pass key */
         key_ev(ev[i].code, ev[i].value);
      }
   }

   /* close keyboard */
   close(fd);
   exit(EXIT_SUCCESS);
} 

Maybe this quick example I whipped for you will help. You can modify the key_ev function to suit your needs.
You obviously need to run this as root user to get access to /dev/input/event*.

Edit: Heck, I even went the whole way and added application launching there for you, if you press F12 it takes screenshot with 'scrot' program.
However, if your program runs on framebuffer, this won't work. You need to use 'fbgrab' instead wink

Last edited by Cloudef (2012-03-23 20:47:21)

Offline

#13 2012-03-23 19:54:58

PL_kolek
Member
Registered: 2012-02-21
Posts: 41

Re: Grabbing keys while playing games

Wow! Thank you very much. I will take a look into that code tomorrow I hope. But that looks cool wink

Offline

Board footer

Powered by FluxBB