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 <KWayland/Server/seat_interface.h>
|
||||||
|
|
||||||
|
#include <linux/input.h>
|
||||||
|
|
||||||
namespace KWin
|
namespace KWin
|
||||||
{
|
{
|
||||||
|
|
||||||
|
@ -56,6 +58,8 @@ private Q_SLOTS:
|
||||||
void testWarpingUpdatesFocus();
|
void testWarpingUpdatesFocus();
|
||||||
void testWarpingGeneratesPointerMotion();
|
void testWarpingGeneratesPointerMotion();
|
||||||
void testUpdateFocusAfterScreenChange();
|
void testUpdateFocusAfterScreenChange();
|
||||||
|
void testModifierClickUnrestrictedMove_data();
|
||||||
|
void testModifierClickUnrestrictedMove();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void render(KWayland::Client::Surface *surface, const QSize &size = QSize(100, 50));
|
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));
|
QMetaObject::invokeMethod(waylandServer()->backend(), "setOutputCount", Qt::DirectConnection, Q_ARG(int, 2));
|
||||||
waylandServer()->init(s_socketName.toLocal8Bit());
|
waylandServer()->init(s_socketName.toLocal8Bit());
|
||||||
|
|
||||||
|
kwinApp()->setConfig(KSharedConfig::openConfig(QString(), KConfig::SimpleConfig));
|
||||||
|
|
||||||
kwinApp()->start();
|
kwinApp()->start();
|
||||||
QVERIFY(workspaceCreatedSpy.wait());
|
QVERIFY(workspaceCreatedSpy.wait());
|
||||||
QCOMPARE(screens()->count(), 2);
|
QCOMPARE(screens()->count(), 2);
|
||||||
|
@ -310,6 +316,87 @@ void PointerInputTest::testUpdateFocusAfterScreenChange()
|
||||||
QCOMPARE(enteredSpy.count(), 1);
|
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)
|
WAYLANDTEST_MAIN(KWin::PointerInputTest)
|
||||||
|
|
21
input.cpp
21
input.cpp
|
@ -520,7 +520,26 @@ public:
|
||||||
bool passThrough = true;
|
bool passThrough = true;
|
||||||
if (AbstractClient *c = dynamic_cast<AbstractClient*>(input()->pointer()->window().data())) {
|
if (AbstractClient *c = dynamic_cast<AbstractClient*>(input()->pointer()->window().data())) {
|
||||||
bool wasAction = false;
|
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) {
|
if (wasAction) {
|
||||||
passThrough = c->performMouseCommand(command, event->globalPos());
|
passThrough = c->performMouseCommand(command, event->globalPos());
|
||||||
}
|
}
|
||||||
|
|
10
options.h
10
options.h
|
@ -459,6 +459,16 @@ public:
|
||||||
uint keyCmdAllModKey() const {
|
uint keyCmdAllModKey() const {
|
||||||
return CmdAllModKey;
|
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 WindowOperation windowOperation(const QString &name, bool restricted);
|
||||||
static MouseCommand mouseCommand(const QString &name, bool restricted);
|
static MouseCommand mouseCommand(const QString &name, bool restricted);
|
||||||
|
|
Loading…
Reference in a new issue