【问题标题】:Linux, execl(), Why do I lose keyboard input to the application?Linux,execl(),为什么我会丢失应用程序的键盘输入?
【发布时间】:2011-08-23 06:38:42
【问题描述】:

我的 Linux 程序有一个类似 MyProgram_0001 的名称,并且新版本的编号更高。启动时,应用程序会在同一目录中查找更新的版本,如果找到,则通过 execl() 调用它。这很好用,但是当鼠标继续工作时,即使我事先在其窗口中单击,新版本也不会获得任何键盘输入。调用应用程序消失了,其他正在运行的程序继续获得键盘输入......有什么想法吗?实际上该程序是编写一个 C++ Qt Designer 4.7 应用程序,但这不应该是重要的,或者它可能是:-)?

好的,更多信息...这是捕获键并调用我的 SLOT 的代码...

// 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 或@987654324 从自身启动应用程序,否则它可以工作@...

startDetached() 的描述中有一件事引起了我的注意......他们写道,新进程在自己的环境中运行,并且在 Linux 下表现得像一个守护进程。我想知道这是否就是我松开钥匙的原因......

这真的让我很困惑。是否有一些按键必须通过的层链以及我可以调试它并查看我在什么级别松开它们的方法?谢谢!

更多信息...我发现如果我通过 execl 调用完全相同的二进制文件,我不会松开键盘。如果我将该二进制文件复制到另一个名称并调用它......键盘就消失了。它归结为 execl 调用中的单个字母更改,仅在第二个参数中,所有其他都相同,错误仍然发生......如果路径+二进制文件相同,似乎有一些上下文保持不变,但是否则,密钥将被发送到旧上下文,并且通过 execl 调用的文件在不同的上下文中启动...

【问题讨论】:

    标签: linux qt keyboard exec


    【解决方案1】:

    许多应用程序通过从运行二进制文件而不是二进制文件本身的 shell 脚本开始来处理此类问题。火狐做到了这一点。您可以在脚本中进行“最新版本”检查。

    【讨论】:

    • 感谢您的快速回答!我应该提到一件事......新版本(有时)由已经运行的旧版本上传 - 当新版本可用时从数据库中获取它。以前的解决方案会自动生成一个 .BAT 文件(在 Windows 下)并在旧版本终止之前调用它。然后 BAT 删除旧版本,重命名新版本等。我发现 execl() 更干净,只要我不会丢失密钥。
    【解决方案2】:

    我很好奇:在致电execl 之前,您会进行任何类型的清理吗?您是在 Qt 事件循环中调用它还是先退出它?

    execve(2) 函数(其中execl(3) is a wrapper of)在调用过程的状态下执行了多种interesting stuff,令我印象深刻的是它甚至在之后仍然有效:

    execve() 成功时不返回,调用进程的文本、数据、bss 和堆栈被加载的程序覆盖。被调用的程序继承调用进程的 PID,以及任何未设置为在 exec 上关闭的打开文件描述符。调用进程上未决的信号被清除。任何设置为被调用进程捕获的信号都将重置为其默认行为。 SIGCHLD 信号(当设置为 SIG_IGN 时)可能会或可能不会重置为 SIG_DFL。

    其中一些可能会完全破坏 Qt 或 X 服务器状态或其他东西的内部结构。对于 Qt 来说,一切似乎都是从零开始的。对于其他人来说,这是相同的过程。

    如果您在“切换”之前清理所有内容,为什么要重复使用相同的过程?请改用QProcess::startDetached()

    编辑。您的最后一条语句是无条件地阻止按键。如果只有在 Keyboard_On 或 Keypad_On 为真时才锁定键盘,最后一条语句:

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

    实际上应该是return false。您只会在应用重新启动时注意到这一点,因为可能只有较新版本的应用会丢弃关键事件。

    【讨论】:

    • 谢谢!我会尽快看看 startDetached() 。关于 execl() ...好吧,我在调用它之前确实关闭了正在运行的线程。否则,我能说什么,它从一开始就有效。甚至花了我一段时间才注意到我丢失了键盘,因为它通常是基于鼠标的......这对我来说都是边做边学......也许我不得不去 fork 和 kill ......
    • 好吧,不幸的是 startDetached() 让我明白了……新程序启动了,一切看起来都很好,但是在鼠标输入工作时按键被忽略了……和以前一样。我将 ButtonClicked 事件链接到与 KeyPressed 事件相同的插槽,如果应用程序以正常方式启动,所有这些都可以正常工作,但是在通过 execl 或 startDetached 启动相同的事情后我松开了键......这就是我所做的钥匙...
    • 似乎无法正确格式化。希望你能复制给你的编辑。愚蠢:-(。bool Keypad::eventFilter(QObject *obj, QEvent *event) { if (event-&gt;type() == QEvent::KeyPress) { QKeyEvent *keyEvent = static_cast&lt;QKeyEvent*&gt;(event); // directly exit on Alt-keys if (keyEvent-&gt;modifiers()&amp;Qt::AltModifier) return true; // normal keyboard if ((!(keyEvent-&gt;modifiers()&amp;Qt::KeypadModifier))&amp;&amp;(Keyboard_On)) switch (keyEvent-&gt;key()) { case Qt::Key_0: C-&gt;Num0ButtonClicked_KP(); return true; ...
    • 这个 execl 东西绝对是整洁的!我写了一个小应用程序,我从事件循环内部调用 execl ,它工作得很好,键和所有。我一会儿看一下代码。
    • 那个Keyboard_On标志,是什么?这似乎不是execl 的问题。如果您愿意(当然也被允许),您可以使用 paste.org 或 gists.github.com 来分享代码中有问题的部分。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-08-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-06-06
    • 1970-01-01
    • 2019-11-27
    相关资源
    最近更新 更多