开发者

Linux, execl(), Why do I lose keyboard input to the application?

My Linux program has a name like MyProgram_0001 and newer versions get higher numbers. When started the app looks for a newer version in the same directory and if it finds one calls it via execl(). That works great, but while the mouse continues to work the new version does not get any keyboard input, even if I click in its window beforehand. The calling app is gone, other running programs continue to get keyboard input ... Any ideas ? Actually the program is written a C++ Qt Designer 4.7 application, but that shouldn't be important, or maybe it is :-) ?

OK, some more information ... Here's the code that catches the keys and calls my SLOTs ...

// 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->Num4ButtonClick开发者_运维知识库ed_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
    }
}

The Keyboard_On is just a public boolean member of the class which I use to disable the keyboard if a touchscreen is presented to the user. The message handler above is installed like this ...

this->installEventFilter(this);

... in the constructor of the widget class ... I have one such handler for all the widget classes which make up my dialogs ... Well, it works unless I start the app from itself through execl or startDetached() ...

One thing caught my eye in the description of startDetached() ... They write that the new process is running in its own environment and behaves like a deamon under Linux. I wonder if that's why I loose the keys ...

Really this puzzles me. Is there some chain of layers the keystrokes have to pass and a way I could debug that and see at what level I loose them ? Thanks !

More info ... I found that I don't loose the keyboard if I call exactly the same binary through execl. If I copy that binary to a different name and call that ... the keyboard is gone. It comes down to a a single letter change in the execl call, only in the second parameter, all else being the same the bug still occurs ... Seems like there's some context which remains the same if the path+binary are the same, but otherwise the keys get sent to the old context and the file called through execl is started within a different context ...


Many applications deal with issues like this by starting with a shell script that runs the binary, instead of the binary itself. Firefox does this. You can do the "most recent version" check in the script.


I'm curious here: do you perform any kind of clean up before the call to execl? Do you call it inside the Qt event loop or do you exit it first?

The execve(2) function (which execl(3) is a wrapper of) does so many kinds of interesting stuff with the state of the calling process that I'm impressed it even works afterwards:

execve() does not return on success, and the text, data, bss, and stack of the calling process are overwritten by that of the program loaded. The program invoked inherits the calling process's PID, and any open file descriptors that are not set to close on exec. Signals pending on the calling process are cleared. Any signals set to be caught by the calling process are reset to their default behaviour. The SIGCHLD signal (when set to SIG_IGN) may or may not be reset to SIG_DFL.

Some of that might break the internals of Qt or the X server state or something else entirely. For Qt everything seems like starting from scratch. For everyone else, it's the same process.

If you clean everything up before the "switch", why reuse the same process? Use QProcess::startDetached() instead.

Edit. Your last statement is blocking the key presses unconditionally. If the keyboard should be locked only when Keyboard_On or Keypad_On are true, the last statement:

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

should actually be a return false. You only notice this when the app restarts because probably only the newer version of the app is throwing away key events.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜