summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorStanislaw Halik <sthalik@misaki.pl>2017-05-30 20:08:49 +0200
committerStanislaw Halik <sthalik@misaki.pl>2017-05-30 20:08:49 +0200
commitf018bf4beeb15f346177dcee2b9e1a023627e7c4 (patch)
tree94aa371f97ff9e6a5b5db9c3804103aa782fe1ae
parentc52b5ad0a8340012fab7982f0c670a46c3e5d93d (diff)
qxt-mini: finish up X11 shortcuts
It didn't work without XLookupString.
-rw-r--r--qxt-mini/qxtglobalshortcut_x11.cpp459
-rw-r--r--qxt-mini/x11-keymap.cpp209
-rw-r--r--qxt-mini/x11-keymap.hpp28
3 files changed, 491 insertions, 205 deletions
diff --git a/qxt-mini/qxtglobalshortcut_x11.cpp b/qxt-mini/qxtglobalshortcut_x11.cpp
index 01dfe8df..b214a3a0 100644
--- a/qxt-mini/qxtglobalshortcut_x11.cpp
+++ b/qxt-mini/qxtglobalshortcut_x11.cpp
@@ -30,136 +30,154 @@
** <http://libqxt.org> <foundation@libqxt.org>
*****************************************************************************/
+// qt must go first or #error
#include <QHash>
#include <QMutex>
#include <QDebug>
#include <QPair>
#include <QKeyEvent>
#include <QApplication>
+#include "qplatformnativeinterface.h"
+
+#include "x11-keymap.hpp"
#include <X11/Xlib.h>
#include <X11/XKBlib.h>
#include <xcb/xcb.h>
-#include "qplatformnativeinterface.h"
#include "compat/util.hpp"
#include <iterator>
-#include "x11-keymap.hpp"
+#include <vector>
+#include <type_traits>
+#include <utility>
+#include <cinttypes>
+#include <array>
+
+template<typename t, int M, typename size_type_ = std::uintptr_t>
+struct powerset final
+{
+ static_assert(std::is_integral<size_type_>::value, "");
-static constexpr quint32 AllMods = ShiftMask|LockMask|ControlMask|Mod1Mask|Mod2Mask|Mod3Mask|Mod4Mask|Mod5Mask;
+ using size_type = size_type_;
-static constexpr quint32 evil_mods[] = {
-#if 0
- LockMask, // caps lock
- Mod3Mask, // scroll lock
-#endif
- Mod2Mask, // num lock
- Mod5Mask, // altgr
+ static_assert(M > 0, "");
+ static_assert(M < sizeof(size_type[8]), "");
+ static_assert(std::is_unsigned<size_type>::value || M < sizeof(size_type)*8 - 1, "");
- Mod2Mask | Mod5Mask,
-};
+ using N = std::integral_constant<size_type, (size_type(1) << size_type(M))-1>;
+ static_assert((N::value & (N::value + 1)) == 0, "");
-typedef int (*X11ErrorHandler)(Display *display, XErrorEvent *event);
+ using set_type = std::vector<t>;
+ using sets_type = std::array<set_type, N::value>;
+ using element_type = t;
+ using element_count = std::integral_constant<size_type, N::value>;
+ using self_type = powerset<t, M>;
-using pair = QPair<quint32, quint32>;
+ operator const sets_type&() const { return sets_; }
+ operator sets_type&() { return sets_; }
-struct keybinding final
-{
- quint32 code, mods;
- int refcnt;
+ const sets_type& sets() const { return sets_; }
+ sets_type& sets() { return sets_; }
- static QHash<pair, keybinding> list;
- static QMutex lock;
+ set_type& operator[](unsigned k) { return sets_[k]; }
+ const set_type& operator[](unsigned k) const { return sets_[k]; }
- static bool incf(quint32 code, quint32 mods);
- static bool decf(quint32 code, quint32 mods);
+ const set_type& elements() const { return elements_; }
+ set_type& elements() { return elements_; }
- ~keybinding();
+ template<typename = void>
+ operator QString() const
+ {
+ QString str;
+ unsigned k = 0;
+ for (const auto& set : sets_)
+ {
+ str.append(QStringLiteral("#%1: ").arg(++k));
+ for (const auto& x : set)
+ str.append(QStringLiteral("%1 ").arg(x));
+ str.append('\n');
+ }
+ return str.mid(0, str.size() - 1);
+ }
+
+ powerset() {}
private:
- keybinding(quint32 code, quint32 mods);
+ sets_type sets_;
+ set_type elements_;
};
-bool operator==(const keybinding& k1, const keybinding& k2)
+template<typename t, typename... xs>
+static auto
+make_powerset(const t& arg, const xs&... args)
{
- return k1.code == k2.code && k1.mods == k2.mods;
-}
+ using cnt = std::integral_constant<std::uintptr_t, sizeof...(xs)+1>;
+ using p = powerset<t, cnt::value>;
+ using len = typename p::element_count;
+ using vec = typename p::set_type;
+ using size_type = typename p::size_type;
-inline bool operator!=(const keybinding& k1, const keybinding& k2)
-{
- return !(k1 == k2);
-}
-
-uint qHash(const keybinding& k)
-{
- return uint(k.code * 41) ^ qHash(k.mods);
-}
-
-uint qHash(const keybinding& k, uint seed)
-{
- return qHash(uint(k.code * 41) ^ qHash(k.mods), seed);
-}
-
-keybinding::keybinding(quint32 code, quint32 mods) :
- code(code), mods(mods),
- refcnt(0)
-{
-}
+ p ret;
+ vec v;
+ v.reserve(len());
-keybinding::~keybinding()
-{
-}
+ const typename p::set_type ts {{arg, static_cast<t>(args)...}};
-bool keybinding::incf(quint32 code, quint32 mods)
-{
- QMutexLocker l(&lock);
-
- keybinding k = list.value(pair(code, mods), keybinding(code, mods));
+ ret.elements() = std::vector<t>(std::begin(ts), std::end(ts));
- const bool ret = k.refcnt == 0;
-
- if (ret)
+ // no nullary set
+ for (size_type i = 0; i < len(); i++)
{
- //qDebug() << "qxt-mini: registered keybinding" << code;
- }
-
- k.refcnt++;
- list.insert(pair(code, mods), k);
+ v.clear();
+ size_type k = 1;
+ for (const t& x : ts)
+ {
+ if ((i+1) & k)
+ v.push_back(std::move(x));
+ k <<= 1;
+ }
- //qDebug() << "qxt-mini: incf: refcount for" << code << "now" << k.refcnt;
+ ret[i] = vec(std::begin(v), std::end(v));
+ ret[i].shrink_to_fit();
+ }
return ret;
}
-bool keybinding::decf(quint32 code, quint32 mods)
-{
- QMutexLocker l(&lock);
+static auto evil_mods = make_powerset(LockMask, Mod3Mask, Mod5Mask);
- auto it = list.find(pair(code, mods));
+static Qt::KeyboardModifiers evil_qt_mods = Qt::KeypadModifier;
- if (it == list.end())
+static inline quint32 filter_evil_mods(quint32 mods)
+{
+ for (auto mod : evil_mods.elements())
{
- qWarning() << "qxt-mini: spurious keybinding decf on" << code;
- return false;
+ mods &= quint32(~mod);
}
+ return mods;
+}
- keybinding& k = *it;
- k.refcnt--;
+using pair = QPair<quint32, quint32>;
- if (k.refcnt == 0)
- {
- list.erase(it);
- //qDebug() << "qxt-mini: removed keybinding" << code;
- return true;
- }
+struct keybinding final
+{
+ quint32 code, mods;
+ int refcnt;
- //qDebug() << "qxt-mini: decf: refcount for" << code << "now" << k.refcnt;
+ static QHash<pair, keybinding> list;
+ static QMutex lock;
- return false;
-}
+ static bool incf(quint32 code, quint32 mods);
+ static bool decf(quint32 code, quint32 mods);
-QHash<pair, keybinding> keybinding::list;
-QMutex keybinding::lock;
+ ~keybinding();
+
+private:
+ keybinding(quint32 code, quint32 mods);
+};
+
+static std::vector<pair> native_key(Qt::Key key, Qt::KeyboardModifiers modifiers);
+typedef int (*X11ErrorHandler)(Display *display, XErrorEvent *event);
class QxtX11ErrorHandler {
public:
@@ -197,8 +215,6 @@ private:
X11ErrorHandler m_previousErrorHandler;
};
-bool QxtX11ErrorHandler::error = false;
-
class QxtX11Data {
public:
QxtX11Data()
@@ -225,95 +241,203 @@ public:
return DefaultRootWindow(display());
}
- static constexpr quint32 filter_evil_mods(quint32 mods)
+ bool grabKey(quint32 code, quint32 mods)
{
- for (quint32 mod : evil_mods)
- mods &= ~mod;
- return mods;
- }
+ const std::vector<pair> keycodes = native_key(Qt::Key(code), Qt::KeyboardModifiers(mods));
+ bool ret = true;
- bool grabKey(quint32 code, quint32 mods, Window window)
- {
- // qDebug() << "grabbing key" << code << mods;
+ for (pair x : keycodes)
+ {
+ int native_code = x.first, native_mods = x.second;
- mods = filter_evil_mods(mods);
+ if (keybinding::incf(native_code, native_mods))
+ {
+ QxtX11ErrorHandler errorHandler;
- // qDebug() << "mods now" << mods;
+ XGrabKey(display(), native_code, native_mods, rootWindow(), True, GrabModeAsync, GrabModeAsync);
- if (keybinding::incf(code, mods))
- {
- QxtX11ErrorHandler errorHandler;
-
- XGrabKey(display(), code, mods, window, True, GrabModeAsync, GrabModeAsync);
+ for (const auto& set : evil_mods.sets())
+ {
+ quint32 m = native_mods;
- for (quint32 evil : evil_mods)
- {
- quint32 m = mods | evil;
+ for (auto value : set)
+ m |= value;
- XGrabKey(display(), code, m, window, True, GrabModeAsync, GrabModeAsync);
- }
+ XGrabKey(display(), native_code, m, rootWindow(), True, GrabModeAsync, GrabModeAsync);
+ }
- if (errorHandler.error)
- {
- qDebug() << "qxt-mini: error while binding to" << code << mods;
- ungrabKey(code, mods, window);
- return false;
+ if (errorHandler.error)
+ {
+ qDebug() << "qxt-mini: error while binding to" << code << mods;
+ ungrabKey(code, mods);
+ ret = false;
+ }
}
}
- return true;
+ return ret;
}
- bool ungrabKey(quint32 code, quint32 mods, Window window)
+ bool ungrabKey(quint32 code, quint32 mods)
{
- mods = filter_evil_mods(mods);
+ const std::vector<pair> keycodes = native_key(Qt::Key(code), Qt::KeyboardModifiers(mods));
+ bool ret = true;
- if (keybinding::decf(code, mods))
+ for (pair x : keycodes)
{
- QxtX11ErrorHandler errorHandler;
- XUngrabKey(display(), code, mods, window);
+ int native_code = x.first, native_mods = x.second;
- for (quint32 evil : evil_mods)
+ if (keybinding::decf(native_code, native_mods))
{
- quint32 m = mods | evil;
- XUngrabKey(display(), code, m, window);
- }
+ QxtX11ErrorHandler errorHandler;
+ XUngrabKey(display(), native_code, native_mods, rootWindow());
- if (errorHandler.error)
- {
- qDebug() << "qxt-mini: error while unbinding" << code << mods;
- return false;
+ for (const auto& set : evil_mods.sets())
+ {
+ quint32 m = mods;
+
+ for (auto value : set)
+ m |= value;
+
+ XUngrabKey(display(), code, m, rootWindow());
+ }
+
+ if (errorHandler.error)
+ {
+ qDebug() << "qxt-mini: error while unbinding" << code << mods;
+ ret = false;
+ }
}
}
- return true;
+ return ret;
}
private:
Display *m_display;
};
+static std::vector<pair> native_key(Qt::Key key, Qt::KeyboardModifiers modifiers)
+{
+ std::vector<pair> ret;
+
+ QxtX11Data x11;
+ if (!x11.isValid())
+ return ret;
+
+ std::vector<quint32> keycodes = qt_key_to_x11(x11.display(), key, modifiers);
+ unsigned mods = qt_mods_to_x11(modifiers);
+ mods = filter_evil_mods(mods);
+
+ for (quint32 code : keycodes)
+ ret.push_back(pair(code, mods));
+
+ return ret;
+}
+
+bool operator==(const keybinding& k1, const keybinding& k2)
+{
+ return k1.code == k2.code && k1.mods == k2.mods;
+}
+
+inline bool operator!=(const keybinding& k1, const keybinding& k2)
+{
+ return !(k1 == k2);
+}
+
+uint qHash(const keybinding& k)
+{
+ return uint(k.code * 41) ^ qHash(k.mods);
+}
+
+uint qHash(const keybinding& k, uint seed)
+{
+ return qHash(uint(k.code * 41) ^ qHash(k.mods), seed);
+}
+
+keybinding::keybinding(quint32 code, quint32 mods) :
+ code(code), mods(mods),
+ refcnt(0)
+{
+}
+
+keybinding::~keybinding()
+{
+}
+
+bool keybinding::incf(quint32 code, quint32 mods)
+{
+ QMutexLocker l(&lock);
+
+ keybinding k = list.value(pair(code, mods), keybinding(code, mods));
+
+ const bool ret = k.refcnt == 0;
+
+ if (ret)
+ {
+ //qDebug() << "qxt-mini: registered keybinding" << code;
+ }
+
+ k.refcnt++;
+ list.insert(pair(code, mods), k);
+
+ //qDebug() << "qxt-mini: incf: refcount for" << code << "now" << k.refcnt;
+
+ return ret;
+}
+
+bool keybinding::decf(quint32 code, quint32 mods)
+{
+ QMutexLocker l(&lock);
+
+ auto it = list.find(pair(code, mods));
+
+ if (it == list.end())
+ {
+ qWarning() << "qxt-mini: spurious keybinding decf on" << code;
+ return false;
+ }
+
+ keybinding& k = *it;
+ k.refcnt--;
+
+ if (k.refcnt == 0)
+ {
+ list.erase(it);
+ //qDebug() << "qxt-mini: removed keybinding" << code;
+ return true;
+ }
+
+ //qDebug() << "qxt-mini: decf: refcount for" << code << "now" << k.refcnt;
+
+ return false;
+}
+
+QHash<pair, keybinding> keybinding::list;
+QMutex keybinding::lock;
+
+bool QxtX11ErrorHandler::error = false;
+
bool QxtGlobalShortcutPrivate::nativeEventFilter(const QByteArray & eventType,
- void *message, long *result)
+ void *message, long *)
{
- Q_UNUSED(result);
+ QxtX11Data x11;
+
+ if (!x11.isValid())
+ return false;
{
static bool once_ = false;
if (!once_)
{
- QxtX11Data x11;
- if (x11.isValid())
- {
- once_ = true;
- Bool val;
+ once_ = true;
+ Bool val = False;
- (void) XkbSetDetectableAutoRepeat(x11.display(), True, &val);
+ (void) XkbSetDetectableAutoRepeat(x11.display(), True, &val);
- if (val)
- qDebug() << "qxt-mini: fixed x11 autorepeat";
- else
- qDebug() << "qxt-mini: can't fix x11 autorepeat";
- }
+ if (val)
+ qDebug() << "qxt-mini: fixed x11 autorepeat";
+ else
+ qDebug() << "qxt-mini: can't fix x11 autorepeat";
}
}
@@ -357,6 +481,10 @@ bool QxtGlobalShortcutPrivate::nativeEventFilter(const QByteArray & eventType,
#endif
unsigned int keycode = kev->detail;
+
+ if (keycode == 0)
+ return false;
+
unsigned int keystate = 0;
if(kev->state & XCB_MOD_MASK_1) // alt
keystate |= Mod1Mask;
@@ -366,64 +494,43 @@ bool QxtGlobalShortcutPrivate::nativeEventFilter(const QByteArray & eventType,
keystate |= Mod4Mask;
if(kev->state & XCB_MOD_MASK_SHIFT) //shift
keystate |= ShiftMask;
-#if 0
- if(key->state & XCB_MOD_MASK_3) // alt gr aka right-alt or ctrl+left-alt -- what mask is it?
- keystate |= AltGrMask;
-#endif
+ if(kev->state & XCB_MOD_MASK_2) // numlock
+ keystate |= Mod2Mask;
- // qDebug() << "qxt-mini:" << (is_release ? "keyup" : "keydown") << keycode << keystate;
+ keystate = filter_evil_mods(keystate);
- activateShortcut(keycode, keystate, !is_release);
+ QPair<KeySym, KeySym> sym_ = keycode_to_keysym(x11.display(), keycode, keystate, kev);
+ KeySym sym = sym_.first;
+
+ Qt::Key k; Qt::KeyboardModifiers mods;
+ std::tie(k, mods) = x11_key_to_qt(x11.display(), sym, keystate);
+
+ if (k != 0)
+ activateShortcut(k, mods, !is_release);
}
return false;
}
quint32 QxtGlobalShortcutPrivate::nativeModifiers(Qt::KeyboardModifiers modifiers)
{
- quint32 native = 0;
- if (modifiers & Qt::AltModifier)
- native |= Mod1Mask;
- if (modifiers & Qt::ControlModifier)
- native |= ControlMask;
- if (modifiers & Qt::MetaModifier)
- native |= Mod4Mask;
- if (modifiers & Qt::ShiftModifier)
- native |= ShiftMask;
- if (modifiers & Qt::KeypadModifier)
- native |= Mod2Mask;
- if (modifiers & Qt::MetaModifier) // Super aka Windows key
- native |= Mod4Mask;
- if (modifiers & Qt::KeypadModifier) // numlock
- native |= Mod2Mask;
-
- native &= AllMods;
-
- return native;
+ modifiers &= ~evil_qt_mods;
+ return quint32(modifiers);
}
quint32 QxtGlobalShortcutPrivate::nativeKeycode(Qt::Key key)
{
- QxtX11Data x11;
-
- if (x11.isValid())
- return qt_key_to_x11(x11.display(), key);
-
- return unsigned(-1);
+ return quint32(key);
}
bool QxtGlobalShortcutPrivate::registerShortcut(quint32 nativeKey, quint32 nativeMods)
{
QxtX11Data x11;
- if (nativeKey == unsigned(-1))
- return false;
- return x11.isValid() && x11.grabKey(nativeKey, nativeMods, x11.rootWindow());
+ return x11.isValid() && x11.grabKey(nativeKey, nativeMods);
}
bool QxtGlobalShortcutPrivate::unregisterShortcut(quint32 nativeKey, quint32 nativeMods)
{
QxtX11Data x11;
- if (nativeKey == unsigned(-1))
- return false;
- return x11.isValid() && x11.ungrabKey(nativeKey, nativeMods, x11.rootWindow());
+ return x11.isValid() && x11.ungrabKey(nativeKey, nativeMods);
}
#endif
diff --git a/qxt-mini/x11-keymap.cpp b/qxt-mini/x11-keymap.cpp
index b4438a3c..16e55368 100644
--- a/qxt-mini/x11-keymap.cpp
+++ b/qxt-mini/x11-keymap.cpp
@@ -1,16 +1,21 @@
#include "x11-keymap.hpp"
-#ifndef __APPLE__
+#if !defined __APPLE__ && !defined _WIN32
-#include <tuple>
+#include <QMutex>
#define XK_MISCELLANY
#define XK_LATIN1
+
#include <X11/keysymdef.h>
-using tt = std::tuple<Qt::Key, unsigned>;
-static tt keymap[] =
+struct tt {
+ Qt::Key qt;
+ quint32 keysym;
+};
+
+static const tt keymap[] =
{
{ Qt::Key_Return, XK_Return },
{ Qt::Key_Enter, XK_Return },
@@ -18,6 +23,7 @@ static tt keymap[] =
{ Qt::Key_Pause, XK_Pause },
{ Qt::Key_SysReq, XK_Sys_Req },
{ Qt::Key_Home, XK_Home },
+ { Qt::Key_Insert, XK_Insert },
{ Qt::Key_End, XK_End },
{ Qt::Key_Left, XK_Left },
{ Qt::Key_Up, XK_Up },
@@ -25,6 +31,7 @@ static tt keymap[] =
{ Qt::Key_Down, XK_Down },
{ Qt::Key_PageUp, XK_Prior },
{ Qt::Key_PageDown, XK_Next },
+ { Qt::Key_Tab, XK_Tab },
{ Qt::Key_F1, XK_F1 },
{ Qt::Key_F2, XK_F2 },
@@ -40,24 +47,41 @@ static tt keymap[] =
{ Qt::Key_F12, XK_F12 },
{ Qt::Key_Space, XK_space },
- { Qt::Key_Exclam, XK_exclam },
{ Qt::Key_QuoteDbl, XK_quotedbl },
+
+#if 1
+ { Qt::Key_Exclam, XK_exclam },
+ { Qt::Key_At, XK_at },
{ Qt::Key_NumberSign, XK_numbersign },
{ Qt::Key_Dollar, XK_dollar },
{ Qt::Key_Percent, XK_percent },
+ { Qt::Key_AsciiCircum, XK_asciicircum },
{ Qt::Key_Ampersand, XK_ampersand },
- { Qt::Key_Apostrophe, XK_apostrophe },
+ { Qt::Key_Asterisk, XK_asterisk },
{ Qt::Key_ParenLeft, XK_parenleft },
{ Qt::Key_ParenRight, XK_parenright },
- { Qt::Key_Asterisk, XK_asterisk },
+#else
+ { Qt::Key_Exclam, XK_1 },
+ { Qt::Key_At, XK_2 },
+ { Qt::Key_NumberSign, XK_3 },
+ { Qt::Key_Dollar, XK_4 },
+ { Qt::Key_Percent, XK_5 },
+ { Qt::Key_AsciiCircum, XK_6 },
+ { Qt::Key_Ampersand, XK_7 },
+ { Qt::Key_Asterisk, XK_8 },
+ { Qt::Key_ParenLeft, XK_9 },
+ { Qt::Key_ParenRight, XK_0 },
+#endif
+ { Qt::Key_Minus, XK_minus },
+ { Qt::Key_Equal, XK_equal },
+ { Qt::Key_Apostrophe, XK_apostrophe },
{ Qt::Key_Plus, XK_plus },
{ Qt::Key_Comma, XK_comma },
- { Qt::Key_Minus, XK_minus },
{ Qt::Key_Period, XK_period },
{ Qt::Key_Slash, XK_slash },
{ Qt::Key_0, XK_0 },
- { Qt::Key_1, XK_1},
+ { Qt::Key_1, XK_1 },
{ Qt::Key_2, XK_2 },
{ Qt::Key_3, XK_3 },
{ Qt::Key_4, XK_4 },
@@ -70,10 +94,8 @@ static tt keymap[] =
{ Qt::Key_Colon, XK_colon },
{ Qt::Key_Semicolon, XK_semicolon },
{ Qt::Key_Less, XK_less },
- { Qt::Key_Equal, XK_equal },
{ Qt::Key_Greater, XK_greater },
{ Qt::Key_Question, XK_question },
- { Qt::Key_At, XK_at },
{ Qt::Key_A, XK_a },
{ Qt::Key_B, XK_b },
@@ -105,32 +127,171 @@ static tt keymap[] =
{ Qt::Key_BracketLeft, XK_bracketleft },
{ Qt::Key_Backslash, XK_backslash },
{ Qt::Key_BracketRight, XK_bracketright },
- { Qt::Key_AsciiCircum, XK_asciicircum },
{ Qt::Key_Underscore, XK_underscore },
{ Qt::Key_QuoteLeft, XK_grave },
+#if 0
+};
+static tt numpad_keymap[] = {
+#endif
+ { Qt::Key_0, XK_KP_0 },
+ { Qt::Key_1, XK_KP_1 },
+ { Qt::Key_2, XK_KP_2 },
+ { Qt::Key_3, XK_KP_3 },
+ { Qt::Key_4, XK_KP_4 },
+ { Qt::Key_5, XK_KP_5 },
+ { Qt::Key_6, XK_KP_6 },
+ { Qt::Key_7, XK_KP_7 },
+ { Qt::Key_8, XK_KP_8 },
+ { Qt::Key_9, XK_KP_9 },
+ { Qt::Key_5, XK_KP_Begin },
+ { Qt::Key_Space, XK_KP_Space },
+ { Qt::Key_Tab, XK_KP_Tab },
+ { Qt::Key_F1, XK_KP_F1 },
+ { Qt::Key_F2, XK_KP_F2 },
+ { Qt::Key_F3, XK_KP_F3 },
+ { Qt::Key_F4, XK_KP_F4 },
+ { Qt::Key_Home, XK_KP_Home },
+ { Qt::Key_End, XK_KP_End },
+ { Qt::Key_Left, XK_KP_Left },
+ { Qt::Key_Right, XK_KP_Right },
+ { Qt::Key_Up, XK_KP_Up },
+ { Qt::Key_Down, XK_KP_Down },
+ { Qt::Key_PageUp, XK_KP_Page_Up },
+ { Qt::Key_PageUp, XK_KP_Prior },
+ { Qt::Key_PageDown, XK_KP_Page_Down },
+ { Qt::Key_PageDown, XK_KP_Next },
+ { Qt::Key_Insert, XK_KP_Insert },
+ { Qt::Key_Delete, XK_KP_Delete },
+ { Qt::Key_Equal, XK_KP_Equal },
+ { Qt::Key_Asterisk, XK_KP_Multiply },
+ { Qt::Key_Plus, XK_KP_Add },
+ { Qt::Key_Comma, XK_KP_Separator },
+ { Qt::Key_Minus, XK_KP_Subtract },
+ { Qt::Key_Period, XK_KP_Decimal },
+ { Qt::Key_Slash, XK_KP_Divide },
};
-unsigned qt_key_to_x11(Display* disp, Qt::Key k)
+QXT_GUI_EXPORT
+quint32 qt_mods_to_x11(Qt::KeyboardModifiers modifiers)
{
- Qt::Key k_;
- unsigned keysym;
+ quint32 mods = 0;
+
+ if (modifiers & Qt::AltModifier)
+ mods |= Mod1Mask;
+ if (modifiers & Qt::ControlModifier)
+ mods |= ControlMask;
+ if (modifiers & Qt::ShiftModifier)
+ mods |= ShiftMask;
+ if (modifiers & Qt::KeypadModifier)
+ mods |= Mod2Mask;
+ if (modifiers & Qt::MetaModifier) // Super aka Windows key
+ mods |= Mod4Mask;
+
+ return mods;
+}
+
+QXT_GUI_EXPORT
+std::vector<quint32> qt_key_to_x11(Display*, Qt::Key k, Qt::KeyboardModifiers)
+{
+ std::vector<quint32> ret;
for (const tt& tuple : keymap)
{
- std::tie(k_, keysym) = tuple;
+ Qt::Key k_ = tuple.qt;
+ unsigned keycode = tuple.keysym;
if (k == k_)
- {
- const unsigned ret = XKeysymToKeycode(disp, keysym);
+ ret.push_back(keycode);
+ }
- if (ret == 0)
- return unsigned(-1);
+ if (ret.size() == 0)
+ qDebug() << "qxt-mini: no keysym for" << k;
- return ret;
- }
+ return ret;
+}
+QXT_GUI_EXPORT
+static Qt::KeyboardModifiers x11_mods_to_qt(quint32 mods)
+{
+ Qt::KeyboardModifiers ret(0);
+
+ if (mods & Mod1Mask)
+ ret |= Qt::AltModifier;
+ if (mods & ControlMask)
+ ret |= Qt::ControlModifier;
+ if (mods & Mod4Mask)
+ ret |= Qt::MetaModifier;
+ if (mods & ShiftMask)
+ ret |= Qt::ShiftModifier;
+
+ return ret;
+}
+
+QXT_GUI_EXPORT
+std::tuple<Qt::Key, Qt::KeyboardModifiers> x11_key_to_qt(Display* disp, quint32 keycode, quint32 mods)
+{
+ (void)disp;
+ using t = std::tuple<Qt::Key, Qt::KeyboardModifiers>;
+
+ for (const tt& tuple : keymap)
+ {
+ const Qt::Key k = tuple.qt;
+
+ if (keycode == tuple.keysym)
+ return t(k, x11_mods_to_qt(mods));
}
- qDebug() << "qxt-mini: no keysym for" << k;
- return unsigned(-1);
+ return t(Qt::Key(0), Qt::KeyboardModifiers(0));
+}
+
+
+QXT_GUI_EXPORT
+QPair<KeySym, KeySym> keycode_to_keysym(Display* disp,
+ quint32 keycode, quint32 keystate,
+ xcb_key_press_event_t const* kev)
+{
+ using pair = QPair<quint32, quint32>;
+
+ static QMutex lock;
+ static QHash<pair, QPair<KeySym, KeySym>> values;
+
+ QMutexLocker l(&lock);
+
+ auto it = values.find(pair(keycode, keystate));
+
+ if (it != values.end())
+ return *it;
+
+ XKeyEvent ev{};
+ ev.serial = kev->sequence;
+ ev.send_event = False;
+ ev.display = disp;
+ ev.window = kev->root;
+ ev.subwindow = kev->child;
+ ev.window = kev->event;
+ ev.time = kev->time;
+ ev.x = kev->event_x;
+ ev.y = kev->event_x;
+ ev.x_root = kev->root_x;
+ ev.y_root = kev->root_y;
+ ev.state = keystate;
+ ev.keycode = keycode;
+ ev.same_screen = kev->same_screen;
+
+ static char bytes[255+1];
+ KeySym sym = 0;
+ int len = XLookupString(&ev, bytes, 255, &sym, NULL);
+ if (len <= 0 || len > 255)
+ {
+ len = 0;
+ sym = 0;
+ }
+
+ KeySym sym2 = XLookupKeysym(&ev, 0);
+
+ QPair<KeySym, KeySym> ret(sym, sym2);
+
+ values[pair(keycode, keystate)] = ret;
+
+ return ret;
}
#endif
diff --git a/qxt-mini/x11-keymap.hpp b/qxt-mini/x11-keymap.hpp
index b35097bc..2c737c77 100644
--- a/qxt-mini/x11-keymap.hpp
+++ b/qxt-mini/x11-keymap.hpp
@@ -1,15 +1,33 @@
#pragma once
-#ifndef BUILD_QXT_MINI
-# error "internal header"
-#endif
+#if !defined __APPLE__ && !defined _WIN32
-#ifndef __APPLE__
+#undef QXT_X11_INCLUDED
+#define QXT_X11_INCLUDED
#include <Qt>
#include <QDebug>
+#include <QHash>
+#include <QPair>
+
+#include <vector>
+#include <tuple>
+
+#include <xcb/xcb.h>
#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+
+QXT_GUI_EXPORT
+std::vector<quint32> qt_key_to_x11(Display* disp, Qt::Key k, Qt::KeyboardModifiers m);
+
+QXT_GUI_EXPORT
+std::tuple<Qt::Key, Qt::KeyboardModifiers> x11_key_to_qt(Display* disp, quint32 keycode, quint32 mods);
+
+QXT_GUI_EXPORT
+QPair<KeySym, KeySym> keycode_to_keysym(Display* disp, quint32 keycode, quint32 keystate,
+ xcb_key_press_event_t const* kev);
-unsigned qt_key_to_x11(Display* disp, Qt::Key k);
+QXT_GUI_EXPORT
+quint32 qt_mods_to_x11(Qt::KeyboardModifiers modifiers);
#endif