Implement modifier+click in InputRedirection for Wayland

This change implements the mouse command for modifier (alt/meta) plus
click in InputRedirection so that it also works on Wayland.

Modifier plus mouse wheel is not implemented yet.

For easier code in Options a new method is added which provides the
configured modifier as a Qt::KeyboardModifier instead of a Qt::Key code.

Test case is added which simulates all variants of modifiers plus
supported mouse buttons to trigger move.
This commit is contained in:
Martin Gräßlin 2016-02-17 17:04:11 +01:00
parent fd692ecf07
commit f8f13a7fba
3 changed files with 117 additions and 1 deletions

View file

@ -41,6 +41,8 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include <KWayland/Server/seat_interface.h>
#include <linux/input.h>
namespace KWin
{
@ -56,6 +58,8 @@ private Q_SLOTS:
void testWarpingUpdatesFocus();
void testWarpingGeneratesPointerMotion();
void testUpdateFocusAfterScreenChange();
void testModifierClickUnrestrictedMove_data();
void testModifierClickUnrestrictedMove();
private:
void render(KWayland::Client::Surface *surface, const QSize &size = QSize(100, 50));
@ -79,6 +83,8 @@ void PointerInputTest::initTestCase()
QMetaObject::invokeMethod(waylandServer()->backend(), "setOutputCount", Qt::DirectConnection, Q_ARG(int, 2));
waylandServer()->init(s_socketName.toLocal8Bit());
kwinApp()->setConfig(KSharedConfig::openConfig(QString(), KConfig::SimpleConfig));
kwinApp()->start();
QVERIFY(workspaceCreatedSpy.wait());
QCOMPARE(screens()->count(), 2);
@ -310,6 +316,87 @@ void PointerInputTest::testUpdateFocusAfterScreenChange()
QCOMPARE(enteredSpy.count(), 1);
}
void PointerInputTest::testModifierClickUnrestrictedMove_data()
{
QTest::addColumn<int>("modifierKey");
QTest::addColumn<int>("mouseButton");
QTest::addColumn<QString>("modKey");
const QString alt = QStringLiteral("Alt");
const QString meta = QStringLiteral("Meta");
QTest::newRow("Left Alt + Left Click") << KEY_LEFTALT << BTN_LEFT << alt;
QTest::newRow("Left Alt + Right Click") << KEY_LEFTALT << BTN_RIGHT << alt;
QTest::newRow("Left Alt + Middle Click") << KEY_LEFTALT << BTN_MIDDLE << alt;
QTest::newRow("Right Alt + Left Click") << KEY_RIGHTALT << BTN_LEFT << alt;
QTest::newRow("Right Alt + Right Click") << KEY_RIGHTALT << BTN_RIGHT << alt;
QTest::newRow("Right Alt + Middle Click") << KEY_RIGHTALT << BTN_MIDDLE << alt;
// now everything with meta
QTest::newRow("Left Meta + Left Click") << KEY_LEFTMETA << BTN_LEFT << meta;
QTest::newRow("Left Meta + Right Click") << KEY_LEFTMETA << BTN_RIGHT << meta;
QTest::newRow("Left Meta + Middle Click") << KEY_LEFTMETA << BTN_MIDDLE << meta;
QTest::newRow("Right Meta + Left Click") << KEY_RIGHTMETA << BTN_LEFT << meta;
QTest::newRow("Right Meta + Right Click") << KEY_RIGHTMETA << BTN_RIGHT << meta;
QTest::newRow("Right Meta + Middle Click") << KEY_RIGHTMETA << BTN_MIDDLE << meta;
}
void PointerInputTest::testModifierClickUnrestrictedMove()
{
// this test ensures that Alt+mouse button press triggers unrestricted move
using namespace KWayland::Client;
// create pointer and signal spy for button events
auto pointer = m_seat->createPointer(m_seat);
QVERIFY(pointer);
QVERIFY(pointer->isValid());
QSignalSpy buttonSpy(pointer, &Pointer::buttonStateChanged);
QVERIFY(buttonSpy.isValid());
// first modify the config for this run
QFETCH(QString, modKey);
KConfigGroup group = kwinApp()->config()->group("MouseBindings");
group.writeEntry("CommandAllKey", modKey);
group.writeEntry("CommandAll1", "Move");
group.writeEntry("CommandAll2", "Move");
group.writeEntry("CommandAll3", "Move");
group.sync();
workspace()->slotReconfigure();
// create a window
QSignalSpy clientAddedSpy(waylandServer(), &WaylandServer::shellClientAdded);
QVERIFY(clientAddedSpy.isValid());
Surface *surface = m_compositor->createSurface(m_compositor);
QVERIFY(surface);
ShellSurface *shellSurface = m_shell->createSurface(surface, surface);
QVERIFY(shellSurface);
render(surface);
QVERIFY(clientAddedSpy.wait());
AbstractClient *window = workspace()->activeClient();
QVERIFY(window);
// move cursor on window
Cursor::setPos(window->geometry().center());
// simulate modifier+click
quint32 timestamp = 1;
QFETCH(int, modifierKey);
QFETCH(int, mouseButton);
waylandServer()->backend()->keyboardKeyPressed(modifierKey, timestamp++);
QVERIFY(!window->isMove());
waylandServer()->backend()->pointerButtonPressed(mouseButton, timestamp++);
QVERIFY(window->isMove());
// release modifier should not change it
waylandServer()->backend()->keyboardKeyReleased(modifierKey, timestamp++);
QVERIFY(window->isMove());
// but releasing the key should end move/resize
waylandServer()->backend()->pointerButtonReleased(mouseButton, timestamp++);
QVERIFY(!window->isMove());
// all of that should not have triggered button events on the surface
QCOMPARE(buttonSpy.count(), 0);
// also waiting shouldn't give us the event
QVERIFY(!buttonSpy.wait(100));
}
}
WAYLANDTEST_MAIN(KWin::PointerInputTest)

View file

@ -520,7 +520,26 @@ public:
bool passThrough = true;
if (AbstractClient *c = dynamic_cast<AbstractClient*>(input()->pointer()->window().data())) {
bool wasAction = false;
const Options::MouseCommand command = c->getMouseCommand(event->button(), &wasAction);
Options::MouseCommand command = Options::MouseNothing;
if (event->modifiers() == options->commandAllModifier()) {
wasAction = true;
switch (event->button()) {
case Qt::LeftButton:
command = options->commandAll1();
break;
case Qt::MiddleButton:
command = options->commandAll2();
break;
case Qt::RightButton:
command = options->commandAll3();
break;
default:
// nothing
break;
}
} else {
c->getMouseCommand(event->button(), &wasAction);
}
if (wasAction) {
passThrough = c->performMouseCommand(command, event->globalPos());
}

View file

@ -459,6 +459,16 @@ public:
uint keyCmdAllModKey() const {
return CmdAllModKey;
}
Qt::KeyboardModifier commandAllModifier() const {
switch (CmdAllModKey) {
case Qt::Key_Alt:
return Qt::AltModifier;
case Qt::Key_Meta:
return Qt::MetaModifier;
default:
Q_UNREACHABLE();
}
}
static WindowOperation windowOperation(const QString &name, bool restricted);
static MouseCommand mouseCommand(const QString &name, bool restricted);