Linux,execl(),为什么我会丢失应用程序的键盘输入?
我的 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 或 startDetached()
从应用程序自身...
在 startDetached()
的描述中有一件事引起了我的注意...他们写道新进程正在运行它有自己的环境,并且表现得像 Linux 下的守护进程。我想知道这是否就是我丢失钥匙的原因……
这确实让我困惑。是否有一些击键必须通过的层链以及我可以调试它并查看我在什么级别松动它们的方法?谢谢 !
更多信息...我发现如果我通过 execl 调用完全相同的二进制文件,我不会松开键盘。如果我将该二进制文件复制到另一个名称并调用它......键盘就消失了。它归结为 execl 调用中的单个字母更改,仅在第二个参数中,其他所有情况相同时错误仍然发生...似乎如果路径+二进制文件相同,则某些上下文保持不变,但是否则,密钥将被发送到旧上下文,并且通过 execl 调用的文件将在不同的上下文中启动...
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->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
}
}
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 ...
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
许多应用程序通过从运行二进制文件的 shell 脚本(而不是二进制文件本身)开始来处理此类问题。火狐就是这么做的。您可以在脚本中进行“最新版本”检查。
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.
我很好奇:在调用
execl
之前,您是否执行任何类型的清理?您是在 Qt 事件循环内调用它还是先退出它?execve(2)
函数(其中execl(3)
是一个包装器)做了很多有趣的事情调用过程的状态给我留下了深刻的印象,它甚至可以在之后工作:其中一些可能会完全破坏 Qt 的内部结构或 X 服务器状态或其他东西。对于 Qt 来说,一切似乎都是从头开始。对于其他人来说,这是相同的过程。
如果您在“切换”之前清理了所有内容,为什么要重复使用相同的流程?使用
QProcess::startDetached()
代替。编辑。您的最后一条语句无条件阻止按键。如果仅当 Keyboard_On 或 Keypad_On 为 true 时才应锁定键盘,则最后一条语句:
实际上应该是
return false
。您只有在应用程序重新启动时才会注意到这一点,因为可能只有较新版本的应用程序才会丢弃关键事件。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 (whichexecl(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: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:
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.