LINUX.ORG.RU

[X11] Как отлавливать события во всей системе (а не только в своем окне)?

 


0

1

Здравствуйте!


Модифицирую сейчас свой кастомный переключатель клавиатуры (мне нужен переключатель, умещий обрабатывать отжатие клавиш, ни один из существующих этого не умеет). В данный момент он работает путем отслеживания потока данных, взятого из /dev/input/event0.

Однако, читать из файла устройства может только root, поэтому приходится изголяться, чтобы запустить демон от обычного пользователя так, чтобы он взял настройки из домашней директории пользователя, и при этом получил доступ к файлу устройства клавиатуры.

Мне тут на лоре говорят, что это не тру, и советуют отслеживать поток действий клавиатуры через функции X11.

Я нашел туториал: http://www.xmission.com/~georgeps/documentation/tutorials/Xlib_Beginner.html и пытаюсь сделать по нему.

Пробный код такой:

 Display *dis;
 Window win;

 dis = XOpenDisplay(NULL);
 win = XCreateSimpleWindow(dis, RootWindow(dis, 0), 1, 1, 500, 500, 
                           0, BlackPixel (dis, 0), BlackPixel(dis, 0));
 XMapWindow(dis, win);
 XFlush(dis);
 XSelectInput (dis, win, ExposureMask | KeyPressMask | ButtonPressMask);

 // Цикл опроса
 while(true) 
  {
   XEvent xevent;
   XNextEvent(dis, &xevent);

   printf("Get next event, type: %d\n", xevent.type);
  }

Да, этот код видит события нажатия и отжатия обычных клавиш и клавиш-модификаторов. Проблема в том, что в программу попадают только те события, которые относятся к созданному окну.

А мне нужно получать весь поток клавиатурных событий, независимо от окна. Да и вообще окно мне даже ненужно.

Вопрос: как получить весь поток клавиатурных событий в X11?

Чуть более прямо это делается с xselectinput на все окна (получить список можно через querytree, например)

x3al ★★★★★
()
Ответ на: комментарий от x3al

> Получишь вообще все нажатия, даже те, которые в грабящих ввод окнах.

Не, это не то. Смотри внимательно что там предлагается (положил на paste.org.ru):

http://paste.org.ru/?71izuc

Там основной цикл не на события реагирует, а просто с какой-то частотой опрашивает данные из XQueryKeymap(). Это очень нагружающее решение, надо что-то более человеческое.

webhamster
() автор топика
Ответ на: комментарий от webhamster

Иначе твоя переключалка может не заработать в окнах gksudo и pinentry… В xinput2 что-то было на эту тему, впрочем, я его не тыкал.

x3al ★★★★★
()
Ответ на: комментарий от x3al

> Чуть более прямо это делается с xselectinput на все окна (получить список можно через querytree, например)

И что делать когда одно окно закроется, другое создасться, постоянно запрашивать дерево и перетыкать xselectinput?

Тут предлагают забиндится к какому-то главному окну в систме X11, типа в нем доступен весь клавиатурный поток. Ищу что это за окно такое, пока не нашел.

webhamster
() автор топика
Ответ на: комментарий от webhamster

>И что делать когда одно окно закроется, другое создасться

Очевидно, следить за (емнип) ConfigureNotify на root-окне. Получишь события открытия/закрытия окон.

Тут предлагают забиндится к какому-то главному окну в систме X11, типа в нем доступен весь клавиатурный поток. Ищу что это за окно такое, пока не нашел.

root же.

x3al ★★★★★
()

> Однако, читать из файла устройства может только root, поэтому приходится изголяться, чтобы запустить демон от обычного пользователя так, чтобы он взял настройки из домашней директории пользователя, и при этом получил доступ к файлу устройства клавиатуры.

если suid == «изголяться», тогда удачных приключений ;) и да, кто тебе мешает создать (или заюзать существующую) группу для обеспечения (через юдев) необходимому юзверю доступа к твоему /dev/input/event*?

arsi ★★★★★
()
Ответ на: комментарий от arsi

Есть ещё одна очевидная проблема: если слушать /dev/input/event, то в ssh -Y переключалки раскладки не будет. Угадай, почему.

x3al ★★★★★
()
Ответ на: комментарий от arsi

Да, это — вещь, не раз пользовался в том числе и с винды с xming, в котором даже XIM-софта не было запущено. Хотя кажется немного оверкиллом для задачи топикстартера (ну и определённый говнософт вроде dmenu не умеет даже XIM, не говоря о immodul'ях, но это проблемы говнософта). В DE уже достаточно давно делали прозрачную интеграцию *IM'ов.

x3al ★★★★★
()
Ответ на: комментарий от x3al

> определённый говнософт … не умеет даже XIM, не говоря о immodul'ях

вспомнился старый огнелис и мурашки по спине пробежали %)

> но это проблемы говнософта

к сожалению, это проблемы пользователей :(

arsi ★★★★★
()
Ответ на: комментарий от x3al

>> Тут предлагают забиндится к какому-то главному окну в систме X11, типа в нем доступен весь клавиатурный поток. Ищу что это за окно такое, пока не нашел.

root же.

Блин, нахожу только про root окно которое не общесистемное, а корневое для конкретного события, типа:

Window root; /* root window that the event occurred on */

в структуре XKeyEvent. То есть в каком окне оно появилось.

А мне нужен общесистемное root окно.

webhamster
() автор топика
Ответ на: комментарий от x3al

Вообще, если понадобятся более нормальные мануалы по xlib — есть http://tronche.com/gui/x/xlib/ (слегка устарело и без упоминания о стандартных расширениях, но неплохо) и http://www.sbin.org/doc/Xlib/ .

Ну и man'ы по иксовым функциям вполне себе работают.

x3al ★★★★★
()
Ответ на: комментарий от x3al

> Вообще, если понадобятся более нормальные мануалы по xlib — есть http://tronche.com/gui/x/xlib/ (слегка устарело и без упоминания о стандартных расширениях, но неплохо)

Я вот понять не могу, почему в инете нет официальных док по X11? Искал-искал, только на tronche.com и нашел. Но у меня нет доверя к этому человеку:

http://tronche.com/images/front.gif

webhamster
() автор топика

> Модифицирую сейчас свой кастомный переключатель клавиатуры (мне нужен переключатель, умещий обрабатывать отжатие клавиш, ни один из существующих этого не умеет).

Таки молодец. Хоть один не стал плакаться «иксы такие, иксы сякие», а сел и начал делать.

По теме: проще всего нужную тебе функциональность дописать в xneur. Неглючное слежение за вводом там уже сделано, надо только твои функции в нужных местах добавить, и всё.

geekless ★★
()
Ответ на: комментарий от geekless

Еще добавлю.

У xneur есть поддержка плагинов. Плагины, в числе прочего, могут получать и уведомления о key press и key release. Вот, например, из кода тестового плагина:

int on_key_press(KeySym key, int modifier_mask)
{
	printf("[PLG] Plugin receive KeyPress '%s' with mask %d\n", XKeysymToString(key), modifier_mask);
	return (0);
}

int on_key_release(KeySym key, int modifier_mask)
{
	printf("[PLG] Plugin receive KeyRelease '%s' with mask %d\n", XKeysymToString(key), modifier_mask);
	return (0);
}

Так что твоя задач сводится к созданию простейшего плагина для xneur.

geekless ★★
()
Ответ на: комментарий от x3al

Тут предлагают забиндится к какому-то главному окну в систме X11, типа в нем доступен весь клавиатурный поток. Ищу что это за окно такое, пока не нашел.

В структуре Display. Есть и макро для его получения.

Вот нашел определение Display в X11/Xlib.h. Какое из полей является корневым окном? По мне, так тут вообще никакого корневого окна нет.

/*
 * Display datatype maintaining display specific data.
 * The contents of this structure are implementation dependent.
 * A Display should be treated as opaque by application code.
 */
#ifndef XLIB_ILLEGAL_ACCESS
typedef struct _XDisplay Display;
#endif

struct _XPrivate;		/* Forward declare before use for C++ */
struct _XrmHashBucketRec;

typedef struct 
#ifdef XLIB_ILLEGAL_ACCESS
_XDisplay
#endif
{
	XExtData *ext_data;	/* hook for extension to hang data */
	struct _XPrivate *private1;
	int fd;			/* Network socket. */
	int private2;
	int proto_major_version;/* major version of server's X protocol */
	int proto_minor_version;/* minor version of servers X protocol */
	char *vendor;		/* vendor of the server hardware */
        XID private3;
	XID private4;
	XID private5;
	int private6;
	XID (*resource_alloc)(	/* allocator function */
		struct _XDisplay*
	);
	int byte_order;		/* screen byte order, LSBFirst, MSBFirst */
	int bitmap_unit;	/* padding and data requirements */
	int bitmap_pad;		/* padding requirements on bitmaps */
	int bitmap_bit_order;	/* LeastSignificant or MostSignificant */
	int nformats;		/* number of pixmap formats in list */
	ScreenFormat *pixmap_format;	/* pixmap format list */
	int private8;
	int release;		/* release of the server */
	struct _XPrivate *private9, *private10;
	int qlen;		/* Length of input event queue */
	unsigned long last_request_read; /* seq number of last event read */
	unsigned long request;	/* sequence number of last request. */
	XPointer private11;
	XPointer private12;
	XPointer private13;
	XPointer private14;
	unsigned max_request_size; /* maximum number 32 bit words in request*/
	struct _XrmHashBucketRec *db;
	int (*private15)(
		struct _XDisplay*
		);
	char *display_name;	/* "host:display" string used on this connect*/
	int default_screen;	/* default screen for operations */
	int nscreens;		/* number of screens on this server*/
	Screen *screens;	/* pointer to list of screens */
	unsigned long motion_buffer;	/* size of motion buffer */
	unsigned long private16;
	int min_keycode;	/* minimum defined keycode */
	int max_keycode;	/* maximum defined keycode */
	XPointer private17;
	XPointer private18;
	int private19;
	char *xdefaults;	/* contents of defaults from server */
	/* there is more to this structure, but it is private to Xlib */
}
#ifdef XLIB_ILLEGAL_ACCESS
Display, 
#endif
*_XPrivDisplay;
webhamster
() автор топика
Ответ на: комментарий от x3al

Что-то я протупил. Вроде как есть готовая функция RootWindow().

Я заменил:

Вариант 1:

win=XCreateSimpleWindow(dis, RootWindow(dis, 0), 1, 1, 500, 500, 0, BlackPixel (dis, 0), BlackPixel(dis, 0));

на

Вариант 2:

win=RootWindow(dis, 0);

И никаких событий отловить не могу.

В варианте 1 ловятся события, но только те которые относятся к окну.

В варианте 2 вообще никаких событий не приходит.

webhamster
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.