[backends/hwcomposer] Use input event filter for turning screen on/off

Like in the drm backend we use an InputEventFilter to turn the backlight
on and off. In this case the filter needs to be always installed as key
event should also turn the screen off. We cannot use a global shortcut
as it would not trigger while the screen is locked.

Unlike the filter in DRM backend only the power key can toggle the
backlight, other key events are ignored. For pointer we are optimistic
and already support enabling the backlight. Double tap to wake is also
implemented, but at least on reference hardware (Nexus 5) doesn't work
as disabling the backlight also disables touch input.

Reviewed-By: Bhushan Shah
This commit is contained in:
Martin Gräßlin 2016-02-16 10:40:20 +01:00
parent a33c2730ba
commit 1c4c5caf65
2 changed files with 130 additions and 10 deletions

View file

@ -29,6 +29,8 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include <KWayland/Server/display.h>
#include <KWayland/Server/output_interface.h>
#include <KWayland/Server/seat_interface.h>
// Qt
#include <QKeyEvent>
// hybris/android
#include <hardware/hardware.h>
#include <hardware/hwcomposer.h>
@ -41,6 +43,103 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
namespace KWin
{
BacklightInputEventFilter::BacklightInputEventFilter(HwcomposerBackend *backend)
: InputEventFilter()
, m_backend(backend)
{
}
BacklightInputEventFilter::~BacklightInputEventFilter() = default;
bool BacklightInputEventFilter::pointerEvent(QMouseEvent *event, quint32 nativeButton)
{
Q_UNUSED(event)
Q_UNUSED(nativeButton)
if (!m_backend->isBacklightOff()) {
return false;
}
toggleBacklight();
return true;
}
bool BacklightInputEventFilter::wheelEvent(QWheelEvent *event)
{
Q_UNUSED(event)
if (!m_backend->isBacklightOff()) {
return false;
}
toggleBacklight();
return true;
}
bool BacklightInputEventFilter::keyEvent(QKeyEvent *event)
{
if (event->key() == Qt::Key_PowerOff && event->type() == QEvent::KeyRelease) {
toggleBacklight();
return true;
}
return m_backend->isBacklightOff();
}
bool BacklightInputEventFilter::touchDown(quint32 id, const QPointF &pos, quint32 time)
{
Q_UNUSED(pos)
Q_UNUSED(time)
if (!m_backend->isBacklightOff()) {
return false;
}
if (m_touchPoints.isEmpty()) {
if (!m_doubleTapTimer.isValid()) {
// this is the first tap
m_doubleTapTimer.start();
} else {
if (m_doubleTapTimer.elapsed() < qApp->doubleClickInterval()) {
m_secondTap = true;
} else {
// took too long. Let's consider it a new click
m_doubleTapTimer.restart();
}
}
} else {
// not a double tap
m_doubleTapTimer.invalidate();
m_secondTap = false;
}
m_touchPoints << id;
return true;
}
bool BacklightInputEventFilter::touchUp(quint32 id, quint32 time)
{
Q_UNUSED(time)
m_touchPoints.removeAll(id);
if (!m_backend->isBacklightOff()) {
return false;
}
if (m_touchPoints.isEmpty() && m_doubleTapTimer.isValid() && m_secondTap) {
if (m_doubleTapTimer.elapsed() < qApp->doubleClickInterval()) {
toggleBacklight();
}
m_doubleTapTimer.invalidate();
m_secondTap = false;
}
return true;
}
bool BacklightInputEventFilter::touchMotion(quint32 id, const QPointF &pos, quint32 time)
{
Q_UNUSED(id)
Q_UNUSED(pos)
Q_UNUSED(time)
return m_backend->isBacklightOff();
}
void BacklightInputEventFilter::toggleBacklight()
{
// queued to not modify the list of event filters while filtering
QMetaObject::invokeMethod(m_backend, "toggleBlankOutput", Qt::QueuedConnection);
}
HwcomposerBackend::HwcomposerBackend(QObject *parent)
: AbstractBackend(parent)
{
@ -137,16 +236,8 @@ void HwcomposerBackend::init()
initLights();
toggleBlankOutput();
connect(input(), &InputRedirection::keyStateChanged, this,
[this] (quint32 key, InputRedirection::KeyboardKeyState state) {
if (state != InputRedirection::KeyboardKeyState::KeyboardKeyReleased) {
return;
}
if (key == KEY_POWER) {
toggleBlankOutput();
}
}
);
m_filter.reset(new BacklightInputEventFilter(this));
input()->prepandInputEventFilter(m_filter.data());
// get display configuration
auto output = createOutput(hwcDevice);

View file

@ -20,7 +20,9 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#ifndef KWIN_HWCOMPOSER_BACKEND_H
#define KWIN_HWCOMPOSER_BACKEND_H
#include "abstract_backend.h"
#include "input.h"
#include <QElapsedTimer>
#include <QMutex>
#include <QWaitCondition>
@ -40,6 +42,7 @@ namespace KWin
{
class HwcomposerWindow;
class BacklightInputEventFilter;
class HwcomposerBackend : public AbstractBackend
{
@ -74,6 +77,10 @@ public:
void waitVSync();
void wakeVSync();
bool isBacklightOff() const {
return m_outputBlank;
}
Q_SIGNALS:
void outputBlankChanged();
@ -92,6 +99,7 @@ private:
bool m_hasVsync = false;
QMutex m_vsyncMutex;
QWaitCondition m_vsyncWaitCondition;
QScopedPointer<BacklightInputEventFilter> m_filter;
};
class HwcomposerWindow : public HWComposerNativeWindow
@ -108,6 +116,27 @@ private:
hwc_display_contents_1_t **m_list;
};
class BacklightInputEventFilter : public InputEventFilter
{
public:
BacklightInputEventFilter(HwcomposerBackend *backend);
virtual ~BacklightInputEventFilter();
bool pointerEvent(QMouseEvent *event, quint32 nativeButton) override;
bool wheelEvent(QWheelEvent *event) override;
bool keyEvent(QKeyEvent *event) override;
bool touchDown(quint32 id, const QPointF &pos, quint32 time) override;
bool touchMotion(quint32 id, const QPointF &pos, quint32 time) override;
bool touchUp(quint32 id, quint32 time) override;
private:
void toggleBacklight();
HwcomposerBackend *m_backend;
QElapsedTimer m_doubleTapTimer;
QVector<qint32> m_touchPoints;
bool m_secondTap = false;
};
}
#endif