Модераторы: xvr
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Захват клавиш под Xми 
V
    Опции темы
ecspertiza
Дата 31.1.2012, 17:35 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 763
Регистрация: 3.11.2008
Где: г.Смоленск

Репутация: нет
Всего: 5



Есть софтина которая работает в фоне, по нажатию некоторой комбинации на клавиатуре должна запустить действие. Для перехвата клавиш использую 

Код

XGrabKey


но если клавиша уже захвачена другим приложением то, получаю след. вывод в консоль 

Код

X Error: BadAccess (attempt to access private resource denied) 10
  Major opcode: 33 (X_GrabKey)
  Resource id:  0xb0


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


--------------------
С уважением,
мастер конфетного цеха!

онлайн компилер
залип
PM MAIL   Вверх
tzirechnoy
Дата 31.1.2012, 20:32 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1173
Регистрация: 30.1.2009

Репутация: 3
Всего: 16



По-моему в CORE нет. Но дажэ если бы и был (по-моему, в X-Resource добавили) -- был бы race condition после проверки. Так что лучшэ через XSetErrorHandler.
PM MAIL   Вверх
ecspertiza
Дата 1.2.2012, 10:14 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 763
Регистрация: 3.11.2008
Где: г.Смоленск

Репутация: нет
Всего: 5



Спасибо за наводку, немного погуглил про XSetErrorHandler вроде то что нужно, накидал вот такой пример

Код

#include <QDebug>

#include <stdio.h>
#include <X11/Xlib.h>

#include <X11/keysym.h>

void swallow_keystroke(Display * dpy, XEvent * ev)
{
    XAllowEvents(dpy, AsyncKeyboard, ev->xkey.time);
    /* burp */
}

void passthru_keystroke(Display * dpy, XEvent * ev)
{
    /* pass it through to the app, as if we never intercepted it */
    XAllowEvents(dpy, ReplayKeyboard, ev->xkey.time);
    XFlush(dpy); /* don't forget! */
}

static int qxt_x_errhandler(Display* display, XErrorEvent *event)
{
    qDebug() << Q_FUNC_INFO << "x11 error";
    Q_UNUSED(display);
    switch (event->error_code)
    {
        case BadAccess:
            qDebug() << Q_FUNC_INFO << "Bad access";
        case BadValue:
            qDebug() << Q_FUNC_INFO << "Bad vale";
        case BadWindow:
            qDebug() << Q_FUNC_INFO << "Bad window";
            if (event->request_code == 33 /* X_GrabKey */ ||
                event->request_code == 34 /* X_UngrabKey */)
            {
                qDebug() << Q_FUNC_INFO << "error grub";
                //TODO:
                //char errstr[256];
                //XGetErrorText(dpy, err->error_code, errstr, 256);
            }
        default:
            return 0;
    }
}

int main(void)
{
    Display * dpy = XOpenDisplay(0x0);
    KeyCode PrintKey;
    XEvent ev;

    if(!dpy) return 1;

    PrintKey = XKeysymToKeycode(dpy, XK_Print);

    XErrorHandler savedErrorHandler = XSetErrorHandler(qxt_x_errhandler);


    XGrabKey(dpy, PrintKey, AnyModifier, DefaultRootWindow(dpy), true, GrabModeAsync,
            GrabModeAsync);

    XSetErrorHandler(savedErrorHandler);

    for(;;)
    {
        XNextEvent(dpy, &ev);

        if(ev.type == KeyPress)
        {

            if(ev.xkey.keycode == PrintKey && ev.xkey.state & Mod1Mask)
            {
                if(ev.type == KeyPress)
                    fprintf(stderr, "got Alt+Print\n");

                swallow_keystroke(dpy, &ev);
            }
            else if (ev.xkey.keycode == PrintKey && ev.xkey.state & ControlMask)
            {
                fprintf(stderr, "got (something else)+Print, passing through\n");
                passthru_keystroke(dpy, &ev);
            }
        }
    }
}



и он стало быть не работаетsmile видимо как то не правильно использую XSetErrorHandler , в чем косяк ?


--------------------
С уважением,
мастер конфетного цеха!

онлайн компилер
залип
PM MAIL   Вверх
ecspertiza
Дата 1.2.2012, 10:14 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 763
Регистрация: 3.11.2008
Где: г.Смоленск

Репутация: нет
Всего: 5



Спасибо за наводку, немного погуглил про XSetErrorHandler вроде то что нужно, накидал вот такой пример

Код

#include <QDebug>

#include <stdio.h>
#include <X11/Xlib.h>

#include <X11/keysym.h>

void swallow_keystroke(Display * dpy, XEvent * ev)
{
    XAllowEvents(dpy, AsyncKeyboard, ev->xkey.time);
    /* burp */
}

void passthru_keystroke(Display * dpy, XEvent * ev)
{
    /* pass it through to the app, as if we never intercepted it */
    XAllowEvents(dpy, ReplayKeyboard, ev->xkey.time);
    XFlush(dpy); /* don't forget! */
}

static int qxt_x_errhandler(Display* display, XErrorEvent *event)
{
    qDebug() << Q_FUNC_INFO << "x11 error";
    Q_UNUSED(display);
    switch (event->error_code)
    {
        case BadAccess:
            qDebug() << Q_FUNC_INFO << "Bad access";
        case BadValue:
            qDebug() << Q_FUNC_INFO << "Bad vale";
        case BadWindow:
            qDebug() << Q_FUNC_INFO << "Bad window";
            if (event->request_code == 33 /* X_GrabKey */ ||
                event->request_code == 34 /* X_UngrabKey */)
            {
                qDebug() << Q_FUNC_INFO << "error grub";
                //TODO:
                //char errstr[256];
                //XGetErrorText(dpy, err->error_code, errstr, 256);
            }
        default:
            return 0;
    }
}

int main(void)
{
    Display * dpy = XOpenDisplay(0x0);
    KeyCode PrintKey;
    XEvent ev;

    if(!dpy) return 1;

    PrintKey = XKeysymToKeycode(dpy, XK_Print);

    XErrorHandler savedErrorHandler = XSetErrorHandler(qxt_x_errhandler);


    XGrabKey(dpy, PrintKey, AnyModifier, DefaultRootWindow(dpy), true, GrabModeAsync,
            GrabModeAsync);

    XSetErrorHandler(savedErrorHandler);

    for(;;)
    {
        XNextEvent(dpy, &ev);

        if(ev.type == KeyPress)
        {

            if(ev.xkey.keycode == PrintKey && ev.xkey.state & Mod1Mask)
            {
                if(ev.type == KeyPress)
                    fprintf(stderr, "got Alt+Print\n");

                swallow_keystroke(dpy, &ev);
            }
            else if (ev.xkey.keycode == PrintKey && ev.xkey.state & ControlMask)
            {
                fprintf(stderr, "got (something else)+Print, passing through\n");
                passthru_keystroke(dpy, &ev);
            }
        }
    }
}



и он стало быть не работаетsmile видимо как то не правильно использую XSetErrorHandler , в чем косяк ?


--------------------
С уважением,
мастер конфетного цеха!

онлайн компилер
залип
PM MAIL   Вверх
tzirechnoy
Дата 1.2.2012, 10:49 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1173
Регистрация: 30.1.2009

Репутация: 3
Всего: 16



Можно, конечно, XSync вставить -- но я вообще не предполагал, что этот хэндлер Вы будете возвращать в прежнее положэние.

PS Кстати, раз это Qt -- а разве там нет своих аналогов XGrab*?
PM MAIL   Вверх
ecspertiza
Дата 1.2.2012, 11:57 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 763
Регистрация: 3.11.2008
Где: г.Смоленск

Репутация: нет
Всего: 5



Цитата(tzirechnoy @  1.2.2012,  10:49 Найти цитируемый пост)
Можно, конечно, XSync вставить -- но я вообще не предполагал, что этот хэндлер Вы будете возвращать в прежнее положэние.


Намек понял smile

Код

#include <QDebug>

#include <stdio.h>
#include <X11/Xlib.h>

#include <X11/keysym.h>

void swallow_keystroke(Display * dpy, XEvent * ev)
{
    XAllowEvents(dpy, AsyncKeyboard, ev->xkey.time);
    /* burp */
}

void passthru_keystroke(Display * dpy, XEvent * ev)
{
    /* pass it through to the app, as if we never intercepted it */
    XAllowEvents(dpy, ReplayKeyboard, ev->xkey.time);
    XFlush(dpy); /* don't forget! */
}

static int qxt_x_errhandler(Display* display, XErrorEvent *event)
{
    qDebug() << Q_FUNC_INFO << "x11 error";
    Q_UNUSED(display);
    switch (event->error_code)
    {
        case BadAccess:
            qDebug() << Q_FUNC_INFO << "Bad access";
        case BadValue:
            qDebug() << Q_FUNC_INFO << "Bad vale";
        case BadWindow:
            qDebug() << Q_FUNC_INFO << "Bad window";
            if (event->request_code == 33 /* X_GrabKey */ ||
                event->request_code == 34 /* X_UngrabKey */)
            {
                qDebug() << Q_FUNC_INFO << "error grub";
                //TODO:
                //char errstr[256];
                //XGetErrorText(dpy, err->error_code, errstr, 256);
            }
        default:
            return 0;
    }
}

int main(void)
{
    Display * dpy = XOpenDisplay(0x0);
    KeyCode PrintKey;
    XEvent ev;

    if(!dpy) return 1;

    PrintKey = XKeysymToKeycode(dpy, XK_Print);


    XErrorHandler savedErrorHandler = XSetErrorHandler(qxt_x_errhandler);

    XGrabKey(dpy, PrintKey, AnyModifier, DefaultRootWindow(dpy), true, GrabModeAsync,
            GrabModeAsync);

    for(;;)
    {
        XNextEvent(dpy, &ev);

        if(ev.type == KeyPress)
        {

            if(ev.xkey.keycode == PrintKey && ev.xkey.state & Mod1Mask)
            {
                if(ev.type == KeyPress)
                    fprintf(stderr, "got Alt+Print\n");

                swallow_keystroke(dpy, &ev);
            }
            else if (ev.xkey.keycode == PrintKey && ev.xkey.state & ControlMask)
            {
                fprintf(stderr, "got (something else)+Print, passing through\n");
                passthru_keystroke(dpy, &ev);
            }
        }
    }
}



вот так заработало.

Цитата(tzirechnoy @  1.2.2012,  10:49 Найти цитируемый пост)
PS Кстати, раз это Qt -- а разве там нет своих аналогов XGrab*? 


Те которые хукают клавиши со всей системы не нашел, есть библиотека Qxt она умеет хукать всю систему, но у нее проблемы с Print Screen.

Спасибо за помощь smile


--------------------
С уважением,
мастер конфетного цеха!

онлайн компилер
залип
PM MAIL   Вверх
tzirechnoy
Дата 1.2.2012, 18:20 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1173
Регистрация: 30.1.2009

Репутация: 3
Всего: 16



Ну и, в хэндлере, который вставляется навсегда -- по-моему имеет некоторый смысл вызывать default handler когда не знаешь, что случилось. Хотя это во многом дело вкуса, наверное.
PM MAIL   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Правила форума "С/С++: Программирование под Unix/Linux"
xvr
  • Проставьте несколько ключевых слов темы, чтобы её можно было легче найти.
  • Не забывайте пользоваться кнопкой "Код".
  • Вопросы мобильной разработки тут
  • Телепатов на форуме нет! Задавайте чёткий, конкретный и полный вопрос. Указывайте полностью ошибки компилятора и компоновщика.
  • Новое сообщение должно иметь прямое отношение к разделу форума. Флуд, флейм, оффтопик запрещены.
  • Категорически запрещается обсуждение вареза, "кряков", взлома программ и т.д.

Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, xvr.

 
 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | C/C++: Программирование под Unix/Linux | Следующая тема »


 




[ Время генерации скрипта: 0.0830 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.