最近做项目中用到屏保,在按键或者触屏之后唤醒屏保,在之前的文章中已经写好了用屏保的QWSServer类的只用,我们找那个方法用触摸唤醒的话,如果正好手指是触摸在一个有动作的按钮上,那马屏保恢复之后看见的屏幕不是屏保之前的界面了,这次项目上要求唤醒的时候这个情况不能发生,那么就要求触摸屏事件和键盘事件不能向应用窗口发送才能实现,考虑或很多方法,比如我在唤醒屏保后进入函数的执行的第一句就是发送个信号,给应用程序中的app上安装事件过滤器,事件过滤器中把事件过滤掉,在app中安装时间过滤器的方法:
1、首先重载过滤器函数,在前面的屏保中定义一个信号,在程序刚进入屏保的时候把这个触发的鼠标或者键盘事件过滤后移除过滤器。由于QWSServer类是在Qt中直接定义的,是个虚基类,需要重载才能使用,继承这个类重载里面的save()和restore()函数之后才能用,这部分在屏保部分说明,想实现信号槽功能,这个类必须多重继承,在继承QWSServer类的同时继承QObject,并且把QObject放在前面才能实现信号槽的功能。
bool mainwindos::eventFilter(QObject *target, QEvent *event)
{
if (event->type() == QEvent::MouseButtonDblClick
|| event->type() == QEvent::MouseButtonPress
|| event->type() == QEvent::MouseButtonRelease
|| event->type() == QEvent::MouseMove
|| event->type() == QEvent::MouseTrackingChange || event->type()==QEvent::KeyPress
|| event->type() == QEvent::KeyRelease)
{
qDebug("a keyboard or mouse event ");
event->ignore();
return true;
}
else
return QWidget::eventFilter(target,event);
}
在QApplication对象上安装事件过滤器
qApp->removeEventFilter(this);
因为qApp是指向QApplication对象的。
也可以在事件过滤器中过滤特定的键值
bool process_base::eventFilter(QObject *target, QEvent *event)
{
// qDebug("event filter entered %d",i);
if ( event->type()==QEvent::KeyPress)
{
QKeyEvent *keyEvent = static_cast<QKeyEvent*>(event);
if (keyEvent->key() == Qt::Key_1 )
{
key1_state_flag = true;
qDebug("key_1 is pressed");
return true;
}
else if(keyEvent->key() == Qt::Key_2)
{
key2_state_flag = true;
qDebug("key_2 is pressd");
return true;
}
else if(keyEvent->key() == Qt::Key_3)
{
key3_state_flag = true;
qDebug("key_3 is pressed");
return true;
}
}
else if(event->type() == QEvent::KeyRelease)
{
QKeyEvent *keyEvent = static_cast<QKeyEvent*>(event);
if (keyEvent->key() == Qt::Key_1 && key1_state_flag == true)
{
key1_state_flag = false;
qDebug("key_1 is released");
return true;
}
else if(keyEvent->key() == Qt::Key_2 && key2_state_flag == true)
{
key2_state_flag = false;
qDebug("key_2 is released");
return true;
}
else if(keyEvent->key() == Qt::Key_3 && key3_state_flag == true)
{
key3_state_flag = false;
qDebug("key_3 is released");
return true;
}
}
else
return QWidget::eventFilter(target,event);
// qDebug("event filter out %d",i);
}
理论上说这个触发屏保的,这个事件在传到应用后就顾虑掉没执行,不知道为什么没达到我的目标。
2、考虑过其他的方法,重载nitify()函数,重载QApplication类,实现屏保功能,因为键盘和触屏事件进入应用时最经过notify()但是这样做的话考虑大我们的屏保间隔可修改,还有重载函数麻烦,也不太熟悉些,放在最后考虑。
3、在看Qt的帮助文档时看见里面有个InputMethod类,里面有鼠标和键盘顾虑器,花了一天时间看了下源码中的先关InputMethod类,其实说是重载两个过滤器函数
bool MyinputMethod::filter(const QPoint &, int state, int wheel)
bool MyinputMethod::filter(int unicode, int keycode, int modifiers,bool isPress, bool autoRepeat )
具体怎么过滤我也不懂,但是在Qt的源码中看出是有鼠标或者键盘事件之后先唤醒屏保,然后再判断着两个函数的返回值,然后才把事件向窗口分发。
相关源码:
void QWSServer::sendKeyEvent( int unicode, int keycode, Qt::KeyboardModifiers modifiers, |
2532 |
bool isPress, bool autoRepeat) |
2533 |
{ |
2534 |
qws_keyModifiers = modifiers; |
2535 |
|
2536 |
if (isPress) { |
2537 |
if (keycode != Qt::Key_F34 && keycode != Qt::Key_F35) |
2538 |
qwsServerPrivate->_q_screenSaverWake(); |
2539 |
} |
2540 |
|
2541 |
#ifndef QT_NO_QWS_INPUTMETHODS |
2542 |
|
2543 |
if (!current_IM || !current_IM->filter(unicode, keycode, modifiers, isPress, autoRepeat)) |
2544 |
QWSServerPrivate::sendKeyEventUnfiltered(unicode, keycode, modifiers, isPress, autoRepeat); |
2545 |
#else |
2546 |
QWSServerPrivate::sendKeyEventUnfiltered(unicode, keycode, modifiers, isPress, autoRepeat); |
2547 |
#endif |
2548 |
} |
2549 |
|
这边看出了他们的执行顺序,所以在重载那两个过滤函数的时候,只要设置标志位,在进入屏保的时候把标志位置位,每个鼠标和键盘事件都会先经过着两个过滤器,通过标志位判断是不是屏保后首次鼠标或者键盘事件,进行相应的处理,在这里做自动关机也很方便,还有只有把键盘映射成Qt的键盘就能读出键值,键盘过滤中的参数unicoude打印出来时对应键值的ascii码,这样从Qt的最底层可以很容易获得键盘事件以及相应的键值,省去写驱动的麻烦。