Linux, execl (), почему я теряю ввод с клавиатуры в приложение? - PullRequest
1 голос
/ 11 мая 2011

Моя программа для Linux имеет имя, подобное MyProgram_0001, и более новые версии получают более высокие номера. При запуске приложение ищет более новую версию в том же каталоге, и, если оно находит, она вызывается с помощью execl (). Это прекрасно работает, но пока мышь продолжает работать, новая версия не получает никакого ввода с клавиатуры, даже если я предварительно нажму в ее окне. Вызывающее приложение исчезло, другие запущенные программы продолжают получать ввод с клавиатуры ... Есть идеи? На самом деле программа написана на C ++ Qt Designer 4.7, но это не должно быть важно, или, может быть, это так :-)?

ОК, еще немного информации ... Вот код, который ловит ключи и вызывает мои слоты ...

// define my own event handler
// capture all key presses ...
bool Layout10::eventFilter(QObject *obj, QEvent *event)
{
    if (event->type() == QEvent::KeyPress)
    {
        QKeyEvent *keyEvent = static_cast<QKeyEvent*>(event);

        // directly exit on Alt-keys
        if (keyEvent->modifiers()&Qt::AltModifier) return true;

        // normal keyboard
        if ((!(keyEvent->modifiers()&Qt::KeypadModifier))&&(Keyboard_On)) switch (keyEvent->key())
        {
            case Qt::Key_0:         C->Num0ButtonClicked_KP(); return true;
            case Qt::Key_1:         C->Num1ButtonClicked_KP(); return true;
            case Qt::Key_2:         C->Num2ButtonClicked_KP(); return true;
            case Qt::Key_3:         C->Num3ButtonClicked_KP(); return true;
            case Qt::Key_4:         C->Num4ButtonClicked_KP(); return true;
            case Qt::Key_5:         C->Num5ButtonClicked_KP(); return true;
            case Qt::Key_6:         C->Num6ButtonClicked_KP(); return true;
            case Qt::Key_7:         C->Num7ButtonClicked_KP(); return true;
            case Qt::Key_8:         C->Num8ButtonClicked_KP(); return true;
            case Qt::Key_9:         C->Num9ButtonClicked_KP(); return true;
            case Qt::Key_X:         C->XButtonClicked_KP();    return true;
            case Qt::Key_Backspace: C->EButtonClicked_KP();    return true;
            case Qt::Key_F1:        C->F1ButtonClicked_KP();   return true;
            case Qt::Key_F2:        C->F2ButtonClicked_KP();   return true;
            case Qt::Key_F3:        C->F3ButtonClicked_KP();   return true;
        }

        // keypad
        if ((keyEvent->modifiers()&Qt::KeypadModifier)&&(Keypad_On)) switch (keyEvent->key())
        {
            case Qt::Key_0:         C->Num0ButtonClicked_KP(); return true;
            case Qt::Key_Insert:    C->Num0ButtonClicked_KP(); return true;
            case Qt::Key_1:         C->Num1ButtonClicked_KP(); return true;
            case Qt::Key_End:       C->Num1ButtonClicked_KP(); return true;
            case Qt::Key_2:         C->Num2ButtonClicked_KP(); return true;
            case Qt::Key_Down:      C->Num2ButtonClicked_KP(); return true;
            case Qt::Key_3:         C->Num3ButtonClicked_KP(); return true;
            case Qt::Key_PageDown:  C->Num3ButtonClicked_KP(); return true;
            case Qt::Key_4:         C->Num4ButtonClicked_KP(); return true;
            case Qt::Key_Left:      C->Num4ButtonClicked_KP(); return true;
            case Qt::Key_5:         C->Num5ButtonClicked_KP(); return true;
            case Qt::Key_Clear:     C->Num5ButtonClicked_KP(); return true;
            case Qt::Key_6:         C->Num6ButtonClicked_KP(); return true;
            case Qt::Key_Right:     C->Num6ButtonClicked_KP(); return true;
            case Qt::Key_7:         C->Num7ButtonClicked_KP(); return true;
            case Qt::Key_Home:      C->Num7ButtonClicked_KP(); return true;
            case Qt::Key_8:         C->Num8ButtonClicked_KP(); return true;
            case Qt::Key_Up:        C->Num8ButtonClicked_KP(); return true;
            case Qt::Key_9:         C->Num9ButtonClicked_KP(); return true;
            case Qt::Key_PageUp:    C->Num9ButtonClicked_KP(); return true;
            case Qt::Key_Back:      C->XButtonClicked_KP();    return true; // maybe it should have been backslash ?
            case Qt::Key_Delete:    C->EButtonClicked_KP();    return true;
            case Qt::Key_division:  C->F1ButtonClicked_KP();   return true;
            case Qt::Key_multiply:  C->F2ButtonClicked_KP();   return true;
            case Qt::Key_Minus:     C->F3ButtonClicked_KP();   return true;
        }
        return true; // event is NOT given over for further processing
    }
    else
    {
        return false; // other events may be processed further
    }
}

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

this->installEventFilter(this);

... в конструкторе класса виджетов ... У меня есть один такой обработчик для всех классов виджетов, которые составляют мои диалоги ... Ну, это работает, если я не запускаю приложение из себя через execl или startDetached() ...

Одна вещь попалась на глаза в описании startDetached() ... Они пишут, что новый процесс работает в собственной среде и ведет себя как демон в Linux. Интересно, вот почему я теряю ключи ...

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

Подробнее ... Я обнаружил, что не теряю клавиатуру, если я вызываю точно такой же двоичный файл через execl. Если я скопирую этот бинарный файл на другое имя и назову его ... клавиатура исчезнет. Это сводится к единственному изменению буквы в вызове execl, только во втором параметре, при прочих равных условиях ошибка все равно возникает ... Кажется, что есть некоторый контекст, который остается тем же, если путь + двоичный файл одинаковы, но в противном случае ключи отправляются в старый контекст, а файл, вызываемый через execl, запускается в другом контексте ...

Ответы [ 2 ]

0 голосов
/ 11 мая 2011

Мне любопытно: вы проводите какую-либо уборку перед звонком на execl?Вы вызываете его в цикле событий Qt или сначала выходите из него?

Функция execve(2) (которая execl(3) является оберткой ) делает так много видов интересный материал с состоянием вызывающего процесса, которое меня впечатлило, оно даже работает потом:

execve () не возвращает в случае успеха, а текст, данные, bss истек вызывающего процесса перезаписывается стеком загруженной программы.Вызванная программа наследует PID вызывающего процесса и любые дескрипторы открытых файлов, которые не закрываются при выполнении exec.Сигналы, ожидающие обработки вызова, очищаются.Любые сигналы, установленные для перехвата вызывающим процессом, сбрасываются до их поведения по умолчанию.Сигнал SIGCHLD (при установке на SIG_IGN) может быть сброшен или не сброшен в SIG_DFL.

Некоторые из них могут нарушить внутреннее состояние Qt или состояние X-сервера или что-то еще полностью.Для Qt все кажется начинающимся с нуля.Для всех остальных это тот же процесс.

Если вы все очищаете перед «переключателем», зачем использовать тот же процесс?Вместо этого используйте QProcess::startDetached().

Редактировать. Ваше последнее утверждение блокирует нажатия клавиш безоговорочно.Если клавиатура должна быть заблокирована только тогда, когда Keyboard_On или Keypad_On имеют значение true, последний оператор:

 return true; // event is NOT given over for further processing

должен фактически быть return false.Вы замечаете это только при перезапуске приложения, потому что, вероятно, только более новая версия приложения отбрасывает ключевые события.

0 голосов
/ 11 мая 2011

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

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