Прослушивание событий клавиатуры без их использования в X11-подключение клавиатуры
Я попытался написать программу, которая зацепляет сообщения клавиатуры, чтобы произносить имя каждой клавиши всякий раз, когда она нажимается в Ubuntu (KDE); без вмешательства в нормальное действие клавиатуры в программах (просто объявляя имя клавиши).
Это моя программа:
#include <X11/Xlib.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <iostream>
using namespace std;
void SendPressKeyEvent(Display *display, XKeyEvent xkey)
{
Window current_focus_window;
int current_focus_revert;
XGetInputFocus(display, ¤t_focus_window, ¤t_focus_revert);
xkey.type = KeyPress;
xkey.display = display;
xkey.window = current_focus_window;
xkey.root = DefaultRootWindow(display);
xkey.subwindow = None;
xkey.time = 1000 * time(0);
xkey.x = 0;
xkey.y = 0;
xkey.x_root = 0;
xkey.y_root = 0;
xkey.same_screen = True;
XSendEvent(display, InputFocus, True, KeyPressMask, (XEvent *)(&xkey));
}
void SendReleaseKeyEvent(Display *display, XKeyEvent xkey)
{
Window current_focus_window;
int current_focus_revert;
XGetInputFocus(display, ¤t_focus_window, ¤t_focus_revert);
xkey.type = KeyRelease;
xkey.display = display;
xkey.window = current_focus_window;
xkey.root = DefaultRootWindow(display);
xkey.subwindow = None;
xkey.time = 1000 * time(0);
xkey.x = 0;
xkey.y = 0;
xkey.x_root = 0;
xkey.y_root = 0;
xkey.same_screen = True;
XSendEvent(display, InputFocus, True, KeyReleaseMask, (XEvent *)(&xkey));
}
void *TaskCode(void* arg)
{
switch(*(int*)arg)
{
case 38:
system("espeak -v en " ""a"");
}
return 0;
}
int main()
{
Display *display = XOpenDisplay(0);
if(display == 0)
exit(1);
XGrabKeyboard(display, DefaultRootWindow(display), True, GrabModeAsync, GrabModeAsync, CurrentTime);
XEvent event;
while(true)
{
XNextEvent(display, &event);
if(event.type == Expose)
{
}
if(event.type == KeyPress)
{
SendPressKeyEvent(display,event.xkey);
if(event.xkey.keycode == 38)
{
pthread_t thread;
int thread_arg = event.xkey.keycode;
pthread_create(&thread,0, TaskCode, (void*) &thread_arg);
}
}
if(event.type == KeyRelease)
SendReleaseKeyEvent(display,event.xkey);
}
XCloseDisplay(display);
}
Эта программа предназначена только для ключа a , который может быть расширен на другие ключи.
Но когда эта программа запущена, некоторые программы (например, Chromium) не показывают мигалку (курсор) в своих полях редактирования. Также отключаются все горячие клавиши KDE.
Как это можно исправить?
3 ответов:
Вот мой быстрый и грязный Пример
Это ненадежно, но большую часть времени это работает. (Он показывает клавиши, которые я набираю в этом окне прямо сейчас). Вы можете исследовать, почему он иногда терпит неудачу;) также он не может показывать горячие клавиши в принципе. Горячие клавиши-это захваченные ключи, и только один клиент может получить захваченный ключ. Здесь абсолютно ничего нельзя сделать, кроме загрузки специального расширения X11, предназначенного для этой цели (например, XEvIE).#include <X11/X.h> #include <X11/Xlib.h> #include <X11/Xutil.h> #include <stdio.h> #include <ctype.h> int main () { Display* d = XOpenDisplay(NULL); Window root = DefaultRootWindow(d); Window curFocus; char buf[17]; KeySym ks; XComposeStatus comp; int len; int revert; XGetInputFocus (d, &curFocus, &revert); XSelectInput(d, curFocus, KeyPressMask|KeyReleaseMask|FocusChangeMask); while (1) { XEvent ev; XNextEvent(d, &ev); switch (ev.type) { case FocusOut: printf ("Focus changed!\n"); printf ("Old focus is %d\n", (int)curFocus); if (curFocus != root) XSelectInput(d, curFocus, 0); XGetInputFocus (d, &curFocus, &revert); printf ("New focus is %d\n", (int)curFocus); if (curFocus == PointerRoot) curFocus = root; XSelectInput(d, curFocus, KeyPressMask|KeyReleaseMask|FocusChangeMask); break; case KeyPress: printf ("Got key!\n"); len = XLookupString(&ev.xkey, buf, 16, &ks, &comp); if (len > 0 && isprint(buf[0])) { buf[len]=0; printf("String is: %s\n", buf); } else { printf ("Key is: %d\n", (int)ks); } } } }
Благодаря n. m. ' S ответ и parsa 'S комментарий, Это мой окончательный код:
#include <X11/Xlib.h> #include <stdlib.h> #include <iostream> using namespace std; void* TaskCode(void* parg) { int keycode = *((int*)parg); cout<< "\n\n" << keycode << "\n\n"; if(keycode == XKeysymToKeycode(XOpenDisplay(0),'a')) system("espeak -v en " "\"a\""); delete (int*)parg; return 0; } void Action(int keycode) { pthread_t thread; pthread_attr_t attrs; pthread_attr_init(&attrs); pthread_attr_setdetachstate(&attrs,PTHREAD_CREATE_DETACHED); pthread_attr_setstacksize(&attrs, 1000); int* pthread_arg = new int; *pthread_arg = keycode; pthread_create(&thread,&attrs, TaskCode, (void*) pthread_arg); } int MyX11ErrorHandler(Display *, XErrorEvent *error_event) { cout << "\n\n" "An X11-Functions error occured. Probably the focused window was closed.""\n" "This error will be ignored." "\n"; cout<< "error_code: " << (unsigned)error_event -> error_code << "\n"; cout<< "minor_code: " << (unsigned)error_event -> minor_code << "\n"; cout<< "request_code: " << (unsigned)error_event -> request_code << "\n"; cout<< "resourceid: " << error_event -> resourceid << "\n"; cout<< "serial; " << error_event -> serial << "\n"; cout<< "type: " << error_event -> type << "\n\n"; return 0; } int main() { Display* display = XOpenDisplay(0); Window root = DefaultRootWindow(display); Window current_focus_window; int revert; XSetErrorHandler(MyX11ErrorHandler); XGetInputFocus(display, ¤t_focus_window, &revert); XSelectInput(display,current_focus_window,KeyPressMask | KeyReleaseMask | FocusChangeMask); while(true) { XEvent event; XNextEvent(display, &event); switch (event.type) { case FocusOut: if(current_focus_window != root) XSelectInput(display, current_focus_window, 0); XGetInputFocus(display, ¤t_focus_window, &revert); if(current_focus_window == PointerRoot) current_focus_window = root; XSelectInput(display, current_focus_window, KeyPressMask|KeyReleaseMask|FocusChangeMask); break; case KeyPress: Action(event.xkey.keycode); break; } } }Добавьте их в файл project. pro создателя Qt:
LIBS += -lX11 LIBS += -lpthread LIBS += -lXtstЛюбые предложения по улучшению приветствуются.
В архив я также добавляю свой окончательный код с захватом:
#include <X11/Xlib.h> #include <X11/Xutil.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <iostream> using namespace std; void* TaskCode(void* parg) { int keycode = *((int*)parg); cout<< "\n\n" << keycode << "\n\n"; system("espeak -v en " "\"a\""); delete (int*)parg; return 0; } void SendKeyEvent(Display *display, XEvent event) { Window current_focus_window; XKeyEvent& xkey = event.xkey; int current_focus_revert; XGetInputFocus(display, ¤t_focus_window, ¤t_focus_revert); xkey.state = Mod2Mask; XSendEvent(display, InputFocus, True, xkey.type, (XEvent *)(&event)); } int GrabKey(Display* display, Window grab_window, int keycode) { unsigned int modifiers = Mod2Mask; // numlock on //Window grab_window = DefaultRootWindow(display); Bool owner_events = True; int pointer_mode = GrabModeAsync; int keyboard_mode = GrabModeAsync; XGrabKey(display, keycode, modifiers, grab_window, owner_events, pointer_mode, keyboard_mode); return keycode; } void UngrabKey(Display* display, Window grab_window, int keycode) { unsigned int modifiers = Mod2Mask; // numlock on // Window grab_window = DefaultRootWindow(display); XUngrabKey(display,keycode,modifiers,grab_window); } void Action(int keycode) { pthread_t thread; int* pthread_arg = new int; *pthread_arg = keycode; pthread_create(&thread,0, TaskCode, (void*) pthread_arg); } int main() { Display* display = XOpenDisplay(0); Window root = DefaultRootWindow(display); XEvent event; int keycode = XKeysymToKeycode(display,'a'); GrabKey(display,root,keycode); XSelectInput(display, root, KeyPressMask | KeyReleaseMask); while(true) { XNextEvent(display, &event); switch(event.type) { case KeyPress: Action(event.xkey.keycode); case KeyRelease: SendKeyEvent(display,event); default: break; } } XCloseDisplay(display); }Все хорошо, за исключением того, что, в отличие от рассматриваемого кода, он игнорирует языковую разметку. Клавишей в типа
aчто regradless раскладки языка!
В качестве альтернативы прослушиванию событий X можно также прослушивать входные события Linux напрямую: https://stackoverflow.com/a/27693340/21501
Это имеет то преимущество, что можно изменять поток событий в полете, а также блокировать, редактировать или генерировать входные события.
Comments