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:
parent
fd692ecf07
commit
f8f13a7fba
3 changed files with 117 additions and 1 deletions
|
@ -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)
|
||||
|
|
21
input.cpp
21
input.cpp
|
@ -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());
|
||||
}
|
||||
|
|
10
options.h
10
options.h
|
@ -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);
|
||||
|
|
Loading…
Reference in a new issue