Skip to content

Commit

Permalink
Merge pull request barry-ran#204 from liangent/xmousetap-pr
Browse files Browse the repository at this point in the history
Support for "Customized key mapping" in Linux
  • Loading branch information
barry-ran authored Jun 11, 2020
2 parents e3a37fb + a1fb436 commit bd41607
Show file tree
Hide file tree
Showing 5 changed files with 124 additions and 3 deletions.
14 changes: 12 additions & 2 deletions QtScrcpy/device/ui/videoform.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ QRect VideoForm::getGrabCursorRect()
// high dpi support
rc.setTopLeft(rc.topLeft() * m_videoWidget->devicePixelRatio());
rc.setBottomRight(rc.bottomRight() * m_videoWidget->devicePixelRatio());

rc.setX(rc.x() + 10);
rc.setY(rc.y() + 10);
rc.setWidth(rc.width() - 20);
Expand All @@ -100,12 +101,21 @@ QRect VideoForm::getGrabCursorRect()
rc = m_videoWidget->geometry();
rc.setTopLeft(ui->keepRadioWidget->mapToGlobal(rc.topLeft()));
rc.setBottomRight(ui->keepRadioWidget->mapToGlobal(rc.bottomRight()));

rc.setX(rc.x() + 10);
rc.setY(rc.y() + 10);
rc.setWidth(rc.width() - 20);
rc.setHeight(rc.height() - 20);
#elif defined(Q_OS_LINUX)
rc = QRect(ui->keepRadioWidget->mapToGlobal(m_videoWidget->pos()), m_videoWidget->size());
// high dpi support -- taken from the WIN32 section and untested
rc.setTopLeft(rc.topLeft() * m_videoWidget->devicePixelRatio());
rc.setBottomRight(rc.bottomRight() * m_videoWidget->devicePixelRatio());

rc.setX(rc.x() + 10);
rc.setY(rc.y() + 10);
rc.setWidth(rc.width() - 20);
rc.setHeight(rc.height() - 20);
#else

#endif
return rc;
}
Expand Down
5 changes: 4 additions & 1 deletion QtScrcpy/util/mousetap/mousetap.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@
#ifdef Q_OS_OSX
#include "cocoamousetap.h"
#endif
#ifdef Q_OS_LINUX
#include "xmousetap.h"
#endif

MouseTap *MouseTap::s_instance = Q_NULLPTR;
MouseTap *MouseTap::getInstance()
Expand All @@ -19,7 +22,7 @@ MouseTap *MouseTap::getInstance()
s_instance = new CocoaMouseTap();
#endif
#ifdef Q_OS_LINUX
Q_ASSERT(false);
s_instance = new XMouseTap();
#endif
}
return s_instance;
Expand Down
7 changes: 7 additions & 0 deletions QtScrcpy/util/mousetap/mousetap.pri
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,10 @@ mac {
LIBS += -framework Appkit
QMAKE_CFLAGS += -mmacosx-version-min=10.6
}

linux {
HEADERS += $$PWD/xmousetap.h
SOURCES += $$PWD/xmousetap.cpp
LIBS += -lxcb
QT += x11extras
}
84 changes: 84 additions & 0 deletions QtScrcpy/util/mousetap/xmousetap.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
#include <QX11Info>

#include <xcb/xproto.h>
#include <stdlib.h>
#include <stdint.h>

#include "xmousetap.h"

XMouseTap::XMouseTap() {}

XMouseTap::~XMouseTap() {}

void XMouseTap::initMouseEventTap() {}

void XMouseTap::quitMouseEventTap() {}

static void find_grab_window_recursive(xcb_connection_t *dpy, xcb_window_t window,
QRect rc, int16_t offset_x, int16_t offset_y,
xcb_window_t *grab_window, uint32_t *grab_window_size) {
xcb_query_tree_cookie_t tree_cookie;
xcb_query_tree_reply_t *tree;
tree_cookie = xcb_query_tree(dpy, window);
tree = xcb_query_tree_reply(dpy, tree_cookie, NULL);

xcb_window_t *children = xcb_query_tree_children(tree);
for (int i = 0; i < xcb_query_tree_children_length(tree); i++) {
xcb_get_geometry_cookie_t gg_cookie;
xcb_get_geometry_reply_t *gg;
gg_cookie = xcb_get_geometry(dpy, children[i]);
gg = xcb_get_geometry_reply(dpy, gg_cookie, NULL);

if (gg->x + offset_x <= rc.left() && gg->x + offset_x + gg->width >= rc.right() &&
gg->y + offset_y <= rc.top() && gg->y + offset_y + gg->height >= rc.bottom()) {
if (!*grab_window || gg->width * gg->height <= *grab_window_size) {
*grab_window = children[i];
*grab_window_size = gg->width * gg->height;
}
}

find_grab_window_recursive(dpy, children[i], rc,
gg->x + offset_x, gg->y + offset_y,
grab_window, grab_window_size);

free(gg);
}

free(tree);
}

void XMouseTap::enableMouseEventTap(QRect rc, bool enabled) {
if (enabled && rc.isEmpty()) {
return;
}

xcb_connection_t *dpy = QX11Info::connection();

if (enabled) {
// We grab the top-most smallest window
xcb_window_t grab_window = 0;
uint32_t grab_window_size = 0;

find_grab_window_recursive(dpy, QX11Info::appRootWindow(QX11Info::appScreen()),
rc, 0, 0, &grab_window, &grab_window_size);

if (grab_window) {
xcb_grab_pointer_cookie_t grab_cookie;
xcb_grab_pointer_reply_t *grab;
grab_cookie = xcb_grab_pointer(dpy, /* owner_events = */ 1,
grab_window, /* event_mask = */ 0,
XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC,
grab_window, XCB_NONE, XCB_CURRENT_TIME);
grab = xcb_grab_pointer_reply(dpy, grab_cookie, NULL);

free(grab);
}
} else {
xcb_void_cookie_t ungrab_cookie;
xcb_generic_error_t *error;
ungrab_cookie = xcb_ungrab_pointer_checked(dpy, XCB_CURRENT_TIME);
error = xcb_request_check(dpy, ungrab_cookie);

free(error);
}
}
17 changes: 17 additions & 0 deletions QtScrcpy/util/mousetap/xmousetap.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#ifndef XMOUSETAP_H
#define XMOUSETAP_H

#include "mousetap.h"

class XMouseTap : public MouseTap
{
public:
XMouseTap();
virtual ~XMouseTap();

void initMouseEventTap() override;
void quitMouseEventTap() override;
void enableMouseEventTap(QRect rc, bool enabled) override;
};

#endif // XMOUSETAP_H

0 comments on commit bd41607

Please sign in to comment.