mirror of
https://github.com/zealdocs/zeal.git
synced 2024-11-22 21:53:03 +03:00
Configurable hotkey, remember window geometry and splitter state
This commit is contained in:
parent
3dcc45cb0e
commit
4210b1d53b
@ -33,11 +33,10 @@ Currently Zeal requires Qt 5.0. To compile it, run `qmake` and `make` in the `ze
|
||||
|
||||
## Windows binary
|
||||
|
||||
A 64-bit Windows binary with all dependencies is available to download from Dropbox - [zeal.zip](https://www.dropbox.com/s/fbi5pr1gg706gvm/zeal.zip) (24M).
|
||||
A 64-bit Windows binary with all dependencies is available to download from Dropbox - [zeal.zip](https://www.dropbox.com/s/odiu8vqvnec2jre/zeal.zip) (24M).
|
||||
|
||||
## TODO
|
||||
|
||||
* Configuration (customisable hotkey instead of hardcoded Alt+Space, remember window size, etc.)
|
||||
* Support for global hotkeys under platforms other than Linux/X11 and Windows (OSX)
|
||||
* Search enhancements - some ideas:
|
||||
1. Allow selecting subset of docsets to search in.
|
||||
|
@ -2,7 +2,6 @@
|
||||
#include "ui_mainwindow.h"
|
||||
#include "zeallistmodel.h"
|
||||
#include "zealsearchmodel.h"
|
||||
#include "zealnativeeventfilter.h"
|
||||
#include "zealdocsetsregistry.h"
|
||||
#include "zealsearchitemdelegate.h"
|
||||
#include "zealsettingsdialog.h"
|
||||
@ -14,6 +13,7 @@
|
||||
#include <QSystemTrayIcon>
|
||||
#include <QLocalSocket>
|
||||
#include <QDir>
|
||||
#include <QSettings>
|
||||
#include <QTimer>
|
||||
|
||||
#ifdef WIN32
|
||||
@ -27,13 +27,15 @@
|
||||
#include <xcb/xcb.h>
|
||||
#include <xcb/xcb_keysyms.h>
|
||||
#include <X11/keysym.h>
|
||||
#include "xcb_keysym.h"
|
||||
#endif
|
||||
|
||||
const QString serverName = "zeal_process_running";
|
||||
|
||||
MainWindow::MainWindow(QWidget *parent) :
|
||||
QMainWindow(parent),
|
||||
ui(new Ui::MainWindow)
|
||||
ui(new Ui::MainWindow),
|
||||
settings("Zeal", "Zeal")
|
||||
{
|
||||
// server for detecting already running instances
|
||||
localServer = new QLocalServer(this);
|
||||
@ -52,39 +54,23 @@ MainWindow::MainWindow(QWidget *parent) :
|
||||
setWindowIcon(icon);
|
||||
createTrayIcon();
|
||||
|
||||
QKeySequence keySequence;
|
||||
if(settings.value("hotkey").isNull()) {
|
||||
keySequence = QKeySequence("Alt+Space");
|
||||
} else {
|
||||
keySequence = settings.value("hotkey").value<QKeySequence>();
|
||||
}
|
||||
|
||||
// initialise key grabber
|
||||
auto filter = new ZealNativeEventFilter();
|
||||
connect(filter, &ZealNativeEventFilter::gotHotKey, [&]() {
|
||||
connect(&nativeFilter, &ZealNativeEventFilter::gotHotKey, [&]() {
|
||||
if(isVisible()) hide();
|
||||
else {
|
||||
bringToFront(true);
|
||||
}
|
||||
});
|
||||
qApp->eventDispatcher()->installNativeEventFilter(filter);
|
||||
qApp->eventDispatcher()->installNativeEventFilter(&nativeFilter);
|
||||
setHotKey(keySequence);
|
||||
|
||||
// platform-specific code for global key grabbing
|
||||
#ifdef WIN32
|
||||
RegisterHotKey(NULL, 10, MOD_ALT, VK_SPACE);
|
||||
#else
|
||||
auto platform = qApp->platformNativeInterface();
|
||||
|
||||
xcb_connection_t *c = static_cast<xcb_connection_t*>(platform->nativeResourceForWindow("connection", 0));
|
||||
|
||||
xcb_key_symbols_t *keysyms = xcb_key_symbols_alloc(c);
|
||||
xcb_keycode_t *keycodes = xcb_key_symbols_get_keycode(keysyms, XK_space), keycode;
|
||||
|
||||
// add bindings for all screens
|
||||
xcb_screen_iterator_t iter;
|
||||
iter = xcb_setup_roots_iterator (xcb_get_setup (c));
|
||||
for (; iter.rem; xcb_screen_next (&iter)) {
|
||||
int i = 0;
|
||||
while(keycodes[i] != XCB_NO_SYMBOL) {
|
||||
keycode = keycodes[i];
|
||||
xcb_grab_key(c, true, iter.data->root, XCB_MOD_MASK_ANY, keycode, XCB_GRAB_MODE_SYNC, XCB_GRAB_MODE_SYNC);
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
#endif // WIN32
|
||||
// initialise docsets
|
||||
auto dataLocation = QStandardPaths::writableLocation(QStandardPaths::DataLocation);
|
||||
auto dataDir = QDir(dataLocation);
|
||||
@ -102,15 +88,26 @@ MainWindow::MainWindow(QWidget *parent) :
|
||||
|
||||
// initialise ui
|
||||
ui->setupUi(this);
|
||||
restoreGeometry(settings.value("geometry").toByteArray());
|
||||
ui->splitter->restoreState(settings.value("splitter").toByteArray());
|
||||
connect(ui->splitter, &QSplitter::splitterMoved, [=](int, int) {
|
||||
settings.setValue("splitter", ui->splitter->saveState());
|
||||
});
|
||||
|
||||
// menu
|
||||
auto quitAction = ui->menuBar->addAction("&Quit");
|
||||
quitAction->setShortcut(QKeySequence::Quit);
|
||||
connect(quitAction, &QAction::triggered, [=]() { settings.setValue("geometry", saveGeometry()); });
|
||||
connect(quitAction, SIGNAL(triggered()), qApp, SLOT(quit()));
|
||||
auto settingsAction = ui->menuBar->addAction("&Options");
|
||||
connect(settingsAction, &QAction::triggered, [&]() {
|
||||
ZealSettingsDialog settings;
|
||||
settings.exec();
|
||||
connect(settingsAction, &QAction::triggered, [=]() {
|
||||
ZealSettingsDialog settingsDialog;
|
||||
settingsDialog.setHotKey(hotKey);
|
||||
nativeFilter.setEnabled(false);
|
||||
if(settingsDialog.exec()) {
|
||||
setHotKey(settingsDialog.hotKey());
|
||||
}
|
||||
nativeFilter.setEnabled(true);
|
||||
});
|
||||
auto helpMenu = new QMenu("&Help");
|
||||
auto aboutAction = helpMenu->addAction("&About");
|
||||
@ -195,3 +192,145 @@ void MainWindow::bringToFront(bool withHack)
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void MainWindow::setHotKey(const QKeySequence& hotKey_) {
|
||||
// platform-specific code for global key grabbing
|
||||
#ifdef WIN32
|
||||
UINT i_vk, i_mod = 0;
|
||||
if(!hotKey.isEmpty()) {
|
||||
// disable previous hotkey
|
||||
UnregisterHotKey(NULL, 10);
|
||||
}
|
||||
hotKey = hotKey_;
|
||||
nativeFilter.setHotKey(hotKey);
|
||||
settings.setValue("hotkey", hotKey);
|
||||
if(hotKey.isEmpty()) return;
|
||||
int key = hotKey[hotKey.count()-1];
|
||||
if(key & Qt::ALT) i_mod |= MOD_ALT;
|
||||
if(key & Qt::CTRL) i_mod |= MOD_CONTROL;
|
||||
if(key & Qt::SHIFT) i_mod |= MOD_SHIFT;
|
||||
key = key & ~(Qt::ALT | Qt::CTRL | Qt::SHIFT | Qt::META);
|
||||
#ifndef VK_VOLUME_DOWN
|
||||
#define VK_VOLUME_DOWN 0xAE
|
||||
#define VK_VOLUME_UP 0xAF
|
||||
#endif
|
||||
|
||||
#ifndef VK_MEDIA_NEXT_TRACK
|
||||
#define VK_MEDIA_NEXT_TRACK 0xB0
|
||||
#define VK_MEDIA_PREV_TRACK 0xB1
|
||||
#define VK_MEDIA_STOP 0xB2
|
||||
#define VK_MEDIA_PLAY_PAUSE 0xB3
|
||||
#endif
|
||||
|
||||
#ifndef VK_PAGEUP
|
||||
#define VK_PAGEUP 0x21
|
||||
#define VK_PAGEDOWN 0x22
|
||||
#endif
|
||||
switch(key) {
|
||||
case Qt::Key_Left: i_vk = VK_LEFT; break;
|
||||
case Qt::Key_Right: i_vk = VK_RIGHT; break;
|
||||
case Qt::Key_Up: i_vk = VK_UP; break;
|
||||
case Qt::Key_Down: i_vk = VK_DOWN; break;
|
||||
case Qt::Key_Space: i_vk = VK_SPACE; break;
|
||||
case Qt::Key_Escape: i_vk = VK_ESCAPE; break;
|
||||
case Qt::Key_Enter: i_vk = VK_RETURN; break;
|
||||
case Qt::Key_Return: i_vk = VK_RETURN; break;
|
||||
case Qt::Key_F1: i_vk = VK_F1; break;
|
||||
case Qt::Key_F2: i_vk = VK_F2; break;
|
||||
case Qt::Key_F3: i_vk = VK_F3; break;
|
||||
case Qt::Key_F4: i_vk = VK_F4; break;
|
||||
case Qt::Key_F5: i_vk = VK_F5; break;
|
||||
case Qt::Key_F6: i_vk = VK_F6; break;
|
||||
case Qt::Key_F7: i_vk = VK_F7; break;
|
||||
case Qt::Key_F8: i_vk = VK_F8; break;
|
||||
case Qt::Key_F9: i_vk = VK_F9; break;
|
||||
case Qt::Key_F10: i_vk = VK_F10; break;
|
||||
case Qt::Key_F11: i_vk = VK_F11; break;
|
||||
case Qt::Key_F12: i_vk = VK_F12; break;
|
||||
case Qt::Key_PageUp: i_vk = VK_PAGEUP; break;
|
||||
case Qt::Key_PageDown: i_vk = VK_PAGEDOWN; break;
|
||||
case Qt::Key_Home: i_vk = VK_HOME; break;
|
||||
case Qt::Key_End: i_vk = VK_END; break;
|
||||
case Qt::Key_Insert: i_vk = VK_INSERT; break;
|
||||
case Qt::Key_Delete: i_vk = VK_DELETE; break;
|
||||
case Qt::Key_VolumeDown: i_vk = VK_VOLUME_DOWN; break;
|
||||
case Qt::Key_VolumeUp: i_vk = VK_VOLUME_UP; break;
|
||||
case Qt::Key_MediaTogglePlayPause: i_vk = VK_MEDIA_PLAY_PAUSE; break;
|
||||
case Qt::Key_MediaStop: i_vk = VK_MEDIA_STOP; break;
|
||||
case Qt::Key_MediaPrevious: i_vk = VK_MEDIA_PREV_TRACK; break;
|
||||
case Qt::Key_MediaNext: i_vk = VK_MEDIA_NEXT_TRACK; break;
|
||||
default:
|
||||
i_vk = toupper( key );
|
||||
break;
|
||||
}
|
||||
|
||||
if(!RegisterHotKey(NULL, 10, i_mod, i_vk)) {
|
||||
hotKey = QKeySequence();
|
||||
nativeFilter.setHotKey(hotKey);
|
||||
settings.setValue("hotkey", hotKey);
|
||||
QMessageBox::warning(this, "Key binding failed", "Binding global hotkey failed.");
|
||||
}
|
||||
#else
|
||||
auto platform = qApp->platformNativeInterface();
|
||||
|
||||
xcb_connection_t *c = static_cast<xcb_connection_t*>(platform->nativeResourceForWindow("connection", 0));
|
||||
xcb_key_symbols_t *keysyms = xcb_key_symbols_alloc(c);
|
||||
|
||||
if(!hotKey.isEmpty()) {
|
||||
// disable previous hotkey
|
||||
xcb_keysym_t keysym = GetX11Key(hotKey[hotKey.count()-1]);
|
||||
xcb_keycode_t *keycodes = xcb_key_symbols_get_keycode(keysyms, keysym), keycode;
|
||||
|
||||
// remove bindings from all screens
|
||||
xcb_screen_iterator_t iter;
|
||||
iter = xcb_setup_roots_iterator (xcb_get_setup (c));
|
||||
for (; iter.rem; xcb_screen_next (&iter)) {
|
||||
int i = 0;
|
||||
while(keycodes[i] != XCB_NO_SYMBOL) {
|
||||
keycode = keycodes[i];
|
||||
xcb_ungrab_key(c, keycode, iter.data->root, XCB_MOD_MASK_ANY);
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
free(keycodes);
|
||||
}
|
||||
hotKey = hotKey_;
|
||||
nativeFilter.setHotKey(hotKey);
|
||||
settings.setValue("hotkey", hotKey);
|
||||
|
||||
if(hotKey.isEmpty()) return;
|
||||
|
||||
xcb_keysym_t keysym = GetX11Key(hotKey[hotKey.count()-1]);
|
||||
xcb_keycode_t *keycodes = xcb_key_symbols_get_keycode(keysyms, keysym), keycode;
|
||||
|
||||
if(!keycodes) {
|
||||
hotKey = QKeySequence();
|
||||
nativeFilter.setHotKey(hotKey);
|
||||
settings.setValue("hotkey", hotKey);
|
||||
QMessageBox::warning(this, "Key binding failed", "Binding global hotkey failed.");
|
||||
return;
|
||||
}
|
||||
|
||||
// add bindings for all screens
|
||||
xcb_screen_iterator_t iter;
|
||||
iter = xcb_setup_roots_iterator (xcb_get_setup (c));
|
||||
for (; iter.rem; xcb_screen_next (&iter)) {
|
||||
int i = 0;
|
||||
while(keycodes[i] != XCB_NO_SYMBOL) {
|
||||
keycode = keycodes[i];
|
||||
xcb_void_cookie_t cookie = xcb_grab_key_checked(c, true, iter.data->root, XCB_MOD_MASK_ANY, keycode, XCB_GRAB_MODE_SYNC, XCB_GRAB_MODE_SYNC);
|
||||
if(xcb_request_check(c, cookie)) {
|
||||
hotKey = QKeySequence();
|
||||
nativeFilter.setHotKey(hotKey);
|
||||
settings.setValue("hotkey", hotKey);
|
||||
QMessageBox::warning(this, "Key binding failed", "Binding global hotkey failed.");
|
||||
return;
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
free(keysyms);
|
||||
free(keycodes);
|
||||
#endif // WIN32
|
||||
}
|
||||
|
@ -5,8 +5,10 @@
|
||||
#include <QProcess>
|
||||
#include <QLocalServer>
|
||||
#include <QDialog>
|
||||
#include <QSettings>
|
||||
#include "zeallistmodel.h"
|
||||
#include "zealsearchmodel.h"
|
||||
#include "zealnativeeventfilter.h"
|
||||
|
||||
namespace Ui {
|
||||
class MainWindow;
|
||||
@ -31,6 +33,16 @@ private:
|
||||
QLocalServer *localServer;
|
||||
QDialog hackDialog;
|
||||
void createTrayIcon();
|
||||
void setHotKey(const QKeySequence& hotKey);
|
||||
QKeySequence hotKey;
|
||||
QSettings settings;
|
||||
ZealNativeEventFilter nativeFilter;
|
||||
|
||||
protected:
|
||||
void closeEvent(QCloseEvent *event) {
|
||||
settings.setValue("geometry", saveGeometry());
|
||||
QMainWindow::closeEvent(event);
|
||||
}
|
||||
};
|
||||
|
||||
#endif // MAINWINDOW_H
|
||||
|
226
zeal/widgets/razorshortcutbutton.cpp
Normal file
226
zeal/widgets/razorshortcutbutton.cpp
Normal file
@ -0,0 +1,226 @@
|
||||
/* BEGIN_COMMON_COPYRIGHT_HEADER
|
||||
* (c)LGPL2+
|
||||
*
|
||||
* Razor - a lightweight, Qt based, desktop toolset
|
||||
* http://razor-qt.org
|
||||
*
|
||||
* Copyright: 2010-2011 Razor team
|
||||
* Authors:
|
||||
* Alexander Sokoloff <sokoloff.a@gmail.com>
|
||||
*
|
||||
* This program or library is free software; you can redistribute it
|
||||
* and/or modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU Lesser General
|
||||
* Public License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
* Boston, MA 02110-1301 USA
|
||||
*
|
||||
* END_COMMON_COPYRIGHT_HEADER */
|
||||
|
||||
|
||||
#include "razorshortcutbutton.h"
|
||||
#include "razorshortcutbutton_p.h"
|
||||
|
||||
#include <QtGui/QKeyEvent>
|
||||
#include <QtCore/QDebug>
|
||||
|
||||
/************************************************
|
||||
|
||||
************************************************/
|
||||
RazorShortcutButton::RazorShortcutButton(QWidget *parent) :
|
||||
QToolButton(parent),
|
||||
d_ptr(new RazorShortcutButtonPrivate(this))
|
||||
{
|
||||
setFocusPolicy(Qt::StrongFocus);
|
||||
setPopupMode(QToolButton::MenuButtonPopup);
|
||||
setCheckable(true);
|
||||
|
||||
Q_D(RazorShortcutButton);
|
||||
QAction *a = d->mMenu.addAction("Clear");
|
||||
connect(a, SIGNAL(triggered()), d, SLOT(clear()));
|
||||
QAction *a_def = d->mMenu.addAction("Default");
|
||||
connect(a_def, &QAction::triggered, [=]() {
|
||||
setKeySequence(QKeySequence("Alt+Space"));
|
||||
});
|
||||
setMenu(&d->mMenu);
|
||||
|
||||
connect(this, SIGNAL(toggled(bool)), d, SLOT(activate(bool)));
|
||||
setKeySequence("");
|
||||
}
|
||||
|
||||
|
||||
/************************************************
|
||||
|
||||
************************************************/
|
||||
RazorShortcutButtonPrivate::RazorShortcutButtonPrivate(RazorShortcutButton *parent):
|
||||
q_ptr(parent),
|
||||
mKeysCount(0)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
/************************************************
|
||||
|
||||
************************************************/
|
||||
void RazorShortcutButtonPrivate::activate(bool active)
|
||||
{
|
||||
Q_Q(RazorShortcutButton);
|
||||
mKeysCount = 0;
|
||||
|
||||
if (active)
|
||||
q->grabKeyboard();
|
||||
else
|
||||
q->releaseKeyboard();
|
||||
|
||||
}
|
||||
|
||||
|
||||
/************************************************
|
||||
|
||||
************************************************/
|
||||
RazorShortcutButton::~RazorShortcutButton()
|
||||
{
|
||||
releaseKeyboard();
|
||||
Q_D(RazorShortcutButton);
|
||||
delete d;
|
||||
}
|
||||
|
||||
|
||||
/************************************************
|
||||
|
||||
************************************************/
|
||||
bool RazorShortcutButton::event(QEvent *event)
|
||||
{
|
||||
Q_D(RazorShortcutButton);
|
||||
|
||||
if (isChecked())
|
||||
{
|
||||
if (event->type() == QEvent::KeyPress)
|
||||
return d->keyPressEvent(static_cast<QKeyEvent*>(event));
|
||||
|
||||
if (event->type() == QEvent::KeyRelease)
|
||||
return d->keyReleaseEvent(static_cast<QKeyEvent*>(event));
|
||||
|
||||
if (event->type() == QEvent::FocusOut)
|
||||
setChecked(false);
|
||||
}
|
||||
|
||||
return QToolButton::event(event);
|
||||
}
|
||||
|
||||
|
||||
/************************************************
|
||||
|
||||
************************************************/
|
||||
bool RazorShortcutButtonPrivate::keyPressEvent(QKeyEvent *event)
|
||||
{
|
||||
if (event->isAutoRepeat())
|
||||
return true;
|
||||
|
||||
mKeysCount++;
|
||||
Q_Q(RazorShortcutButton);
|
||||
|
||||
int key = 0;
|
||||
switch (event->key())
|
||||
{
|
||||
case Qt::Key_Escape:
|
||||
return false;
|
||||
case Qt::Key_AltGr: //or else we get unicode salad
|
||||
return false;
|
||||
case Qt::Key_Shift:
|
||||
case Qt::Key_Control:
|
||||
case Qt::Key_Alt:
|
||||
case Qt::Key_Meta:
|
||||
case Qt::Key_Menu:
|
||||
break;
|
||||
default:
|
||||
key = event->key();
|
||||
break;
|
||||
}
|
||||
|
||||
if (key)
|
||||
{
|
||||
QKeySequence seq(key + event->modifiers());
|
||||
q->setKeySequence(seq);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/************************************************
|
||||
|
||||
************************************************/
|
||||
bool RazorShortcutButtonPrivate::keyReleaseEvent(QKeyEvent *event)
|
||||
{
|
||||
if (event->isAutoRepeat())
|
||||
return true;
|
||||
Q_Q(RazorShortcutButton);
|
||||
|
||||
mKeysCount--;
|
||||
|
||||
if (mKeysCount<1)
|
||||
{
|
||||
q->setChecked(false);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/************************************************
|
||||
|
||||
************************************************/
|
||||
QKeySequence RazorShortcutButton::keySequence() const
|
||||
{
|
||||
Q_D(const RazorShortcutButton);
|
||||
return d->mSequence;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/************************************************
|
||||
|
||||
************************************************/
|
||||
void RazorShortcutButton::setKeySequence(const QKeySequence &sequence)
|
||||
{
|
||||
Q_D(RazorShortcutButton);
|
||||
d->mSequence = QKeySequence(sequence);
|
||||
|
||||
QString s = d->mSequence.toString();
|
||||
if (s.isEmpty())
|
||||
setText("None");
|
||||
else
|
||||
setText(s);
|
||||
|
||||
emit keySequenceChanged(d->mSequence);
|
||||
emit keySequenceChanged(s);
|
||||
}
|
||||
|
||||
|
||||
/************************************************
|
||||
|
||||
************************************************/
|
||||
void RazorShortcutButton::setKeySequence(const QString &sequence)
|
||||
{
|
||||
setKeySequence(QKeySequence(sequence));
|
||||
}
|
||||
|
||||
|
||||
/************************************************
|
||||
|
||||
************************************************/
|
||||
void RazorShortcutButtonPrivate::clear()
|
||||
{
|
||||
Q_Q(RazorShortcutButton);
|
||||
q->setKeySequence("");
|
||||
}
|
87
zeal/widgets/razorshortcutbutton.h
Normal file
87
zeal/widgets/razorshortcutbutton.h
Normal file
@ -0,0 +1,87 @@
|
||||
/* BEGIN_COMMON_COPYRIGHT_HEADER
|
||||
* (c)LGPL2+
|
||||
*
|
||||
* Razor - a lightweight, Qt based, desktop toolset
|
||||
* http://razor-qt.org
|
||||
*
|
||||
* Copyright: 2010-2011 Razor team
|
||||
* Authors:
|
||||
* Alexander Sokoloff <sokoloff.a@gmail.com>
|
||||
*
|
||||
* This program or library is free software; you can redistribute it
|
||||
* and/or modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU Lesser General
|
||||
* Public License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
* Boston, MA 02110-1301 USA
|
||||
*
|
||||
* END_COMMON_COPYRIGHT_HEADER */
|
||||
|
||||
|
||||
#ifndef RAZORSHORTCUTBUTTON_H
|
||||
#define RAZORSHORTCUTBUTTON_H
|
||||
|
||||
#include <QToolButton>
|
||||
#include <QKeySequence>
|
||||
|
||||
class RazorShortcutButtonPrivate;
|
||||
|
||||
|
||||
/**
|
||||
* @short A widget to input a QKeySequence.
|
||||
*
|
||||
* This widget lets the user choose a QKeySequence, which is usually used as a
|
||||
* shortcut key. The recording is initiated by the user clicking into the widget.
|
||||
*
|
||||
*/
|
||||
class RazorShortcutButton : public QToolButton
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
/// Constructor.
|
||||
explicit RazorShortcutButton(QWidget *parent = 0);
|
||||
|
||||
/// Destructs the widget.
|
||||
virtual ~RazorShortcutButton();
|
||||
|
||||
/// Return the currently selected key sequence.
|
||||
QKeySequence keySequence() const;
|
||||
|
||||
public slots:
|
||||
/// Set the key sequence.
|
||||
void setKeySequence(const QKeySequence &sequence);
|
||||
|
||||
/// This function is provided for convenience. It's equivalent to calling setKeySequence(QKeySequence(sequence)).
|
||||
void setKeySequence(const QString &sequence);
|
||||
|
||||
signals:
|
||||
/**
|
||||
* This signal is emitted when the current key sequence has changed, be it by user
|
||||
* input or programmatically.
|
||||
*/
|
||||
void keySequenceChanged(const QKeySequence &sequence);
|
||||
|
||||
/**
|
||||
* This signal is emitted when the current key sequence has changed, be it by user
|
||||
* input or programmatically.
|
||||
*/
|
||||
void keySequenceChanged(const QString &sequence);
|
||||
|
||||
protected:
|
||||
/// @reimp
|
||||
bool event(QEvent *event);
|
||||
|
||||
private:
|
||||
RazorShortcutButtonPrivate* const d_ptr;
|
||||
Q_DECLARE_PRIVATE(RazorShortcutButton)
|
||||
};
|
||||
|
||||
#endif // RAZORSHORTCUTBUTTON_H
|
59
zeal/widgets/razorshortcutbutton_p.h
Normal file
59
zeal/widgets/razorshortcutbutton_p.h
Normal file
@ -0,0 +1,59 @@
|
||||
/* BEGIN_COMMON_COPYRIGHT_HEADER
|
||||
* (c)LGPL2+
|
||||
*
|
||||
* Razor - a lightweight, Qt based, desktop toolset
|
||||
* http://razor-qt.org
|
||||
*
|
||||
* Copyright: 2010-2011 Razor team
|
||||
* Authors:
|
||||
* Alexander Sokoloff <sokoloff.a@gmail.com>
|
||||
*
|
||||
* This program or library is free software; you can redistribute it
|
||||
* and/or modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU Lesser General
|
||||
* Public License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
* Boston, MA 02110-1301 USA
|
||||
*
|
||||
* END_COMMON_COPYRIGHT_HEADER */
|
||||
|
||||
|
||||
#ifndef RAZORSHORTCUTBUTTON_P_H
|
||||
#define RAZORSHORTCUTBUTTON_P_H
|
||||
|
||||
#include "razorshortcutbutton.h"
|
||||
#include <QMenu>
|
||||
|
||||
class QKeyEvent;
|
||||
|
||||
class RazorShortcutButtonPrivate: public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit RazorShortcutButtonPrivate(RazorShortcutButton *parent);
|
||||
|
||||
bool keyPressEvent(QKeyEvent *event);
|
||||
bool keyReleaseEvent(QKeyEvent *event);
|
||||
|
||||
public slots:
|
||||
void clear();
|
||||
void activate(bool active);
|
||||
|
||||
private:
|
||||
RazorShortcutButton* const q_ptr;
|
||||
Q_DECLARE_PUBLIC(RazorShortcutButton);
|
||||
|
||||
QKeySequence mSequence;
|
||||
QMenu mMenu;
|
||||
int mKeysCount;
|
||||
};
|
||||
|
||||
#endif // RAZORSHORTCUTBUTTON_P_H
|
@ -1,5 +1,8 @@
|
||||
HEADERS += widgets/searchablewebview.h \
|
||||
widgets/zealsearchedit.h
|
||||
widgets/zealsearchedit.h \
|
||||
widgets/razorshortcutbutton.h \
|
||||
widgets/razorshortcutbutton_p.h
|
||||
|
||||
SOURCES += widgets/searchablewebview.cpp \
|
||||
widgets/zealsearchedit.cpp
|
||||
widgets/zealsearchedit.cpp \
|
||||
widgets/razorshortcutbutton.cpp
|
||||
|
108
zeal/xcb_keysym.cpp
Normal file
108
zeal/xcb_keysym.cpp
Normal file
@ -0,0 +1,108 @@
|
||||
#include "xcb_keysym.h"
|
||||
#include <Qt>
|
||||
|
||||
const x11_to_qt x11keys_to_qtkeys[] =
|
||||
{
|
||||
{ XK_BackSpace, Qt::Key_Backspace, },
|
||||
{ XK_Tab, Qt::Key_Tab, },
|
||||
{ XK_Return, Qt::Key_Enter, },
|
||||
{ XK_Escape, Qt::Key_Escape, },
|
||||
{ XK_Home, Qt::Key_Home, },
|
||||
{ XK_Left, Qt::Key_Left, },
|
||||
{ XK_Up, Qt::Key_Up, },
|
||||
{ XK_Right, Qt::Key_Right, },
|
||||
{ XK_Down, Qt::Key_Down, },
|
||||
{ XK_Page_Up, Qt::Key_PageUp, },
|
||||
{ XK_Page_Down, Qt::Key_PageDown, },
|
||||
{ XK_End, Qt::Key_End, },
|
||||
{ XK_Begin, Qt::Key_Home, },
|
||||
{ XK_Insert, Qt::Key_Insert, },
|
||||
{ XK_Menu, Qt::Key_Menu },
|
||||
|
||||
/* Numeric pad keys - this breaks binding, so commented out for now */
|
||||
/* { XK_KP_Space, ' ', },
|
||||
{ XK_KP_Tab, Qt::Key_Tab, },
|
||||
{ XK_KP_Enter, Qt::Key_Enter, },
|
||||
{ XK_KP_F1, Qt::Key_F1, },
|
||||
{ XK_KP_F2, Qt::Key_F2, },
|
||||
{ XK_KP_F3, Qt::Key_F3, },
|
||||
{ XK_KP_F4, Qt::Key_F4, },
|
||||
{ XK_KP_Home, Qt::Key_Home, },
|
||||
{ XK_KP_Left, Qt::Key_Left, },
|
||||
{ XK_KP_Up, Qt::Key_Up, },
|
||||
{ XK_KP_Right, Qt::Key_Right, },
|
||||
{ XK_KP_Down, Qt::Key_Down, },
|
||||
{ XK_KP_Page_Up, Qt::Key_PageUp, },
|
||||
{ XK_KP_Page_Down, Qt::Key_PageDown, },
|
||||
{ XK_KP_End, Qt::Key_End, },
|
||||
{ XK_KP_Begin, Qt::Key_Home, },
|
||||
{ XK_KP_Insert, Qt::Key_Insert, },
|
||||
{ XK_KP_Delete, Qt::Key_Delete, },
|
||||
{ XK_KP_Equal, Qt::Key_Equal, },
|
||||
{ XK_KP_Multiply, Qt::Key_multiply, },
|
||||
{ XK_KP_Add, Qt::Key_Plus, },
|
||||
{ XK_KP_Separator, Qt::Key_Comma, },
|
||||
{ XK_KP_Subtract, Qt::Key_hyphen, },
|
||||
{ XK_KP_Decimal, Qt::Key_Comma, },
|
||||
{ XK_KP_Divide, Qt::Key_division, },
|
||||
{ XK_KP_0, Qt::Key_0, },
|
||||
{ XK_KP_1, Qt::Key_1, },
|
||||
{ XK_KP_2, Qt::Key_2, },
|
||||
{ XK_KP_3, Qt::Key_3, },
|
||||
{ XK_KP_4, Qt::Key_4, },
|
||||
{ XK_KP_5, Qt::Key_5, },
|
||||
{ XK_KP_6, Qt::Key_6, },
|
||||
{ XK_KP_7, Qt::Key_7, },
|
||||
{ XK_KP_8, Qt::Key_8, },
|
||||
{ XK_KP_9, Qt::Key_9, }, */
|
||||
|
||||
{ XK_F1, Qt::Key_F1, },
|
||||
{ XK_F2, Qt::Key_F2, },
|
||||
{ XK_F3, Qt::Key_F3, },
|
||||
{ XK_F4, Qt::Key_F4, },
|
||||
{ XK_F5, Qt::Key_F5, },
|
||||
{ XK_F6, Qt::Key_F6, },
|
||||
{ XK_F7, Qt::Key_F7, },
|
||||
{ XK_F8, Qt::Key_F8, },
|
||||
{ XK_F9, Qt::Key_F9, },
|
||||
{ XK_F10, Qt::Key_F10, },
|
||||
{ XK_F11, Qt::Key_F11, },
|
||||
{ XK_F12, Qt::Key_F12, },
|
||||
{ XK_Delete, Qt::Key_Delete, },
|
||||
|
||||
/* XFree86 extensions */
|
||||
{ XF86XK_AudioLowerVolume, Qt::Key_VolumeDown, },
|
||||
{ XF86XK_AudioMute, Qt::Key_VolumeMute, },
|
||||
{ XF86XK_AudioRaiseVolume, Qt::Key_VolumeUp, },
|
||||
{ XF86XK_AudioPlay, Qt::Key_MediaTogglePlayPause, },
|
||||
{ XF86XK_AudioStop, Qt::Key_MediaStop, },
|
||||
{ XF86XK_AudioPrev, Qt::Key_MediaPrevious, },
|
||||
{ XF86XK_AudioNext, Qt::Key_MediaNext, },
|
||||
{ XF86XK_HomePage, Qt::Key_HomePage, },
|
||||
{ XF86XK_Search, Qt::Key_Search, },
|
||||
{ XF86XK_Back, Qt::Key_Back, },
|
||||
{ XF86XK_Forward, Qt::Key_Forward, },
|
||||
{ XF86XK_Stop, Qt::Key_Stop, },
|
||||
{ XF86XK_Refresh, Qt::Key_Refresh, },
|
||||
{ XF86XK_Favorites, Qt::Key_Favorites, },
|
||||
{ XF86XK_AudioPause, Qt::Key_MediaTogglePlayPause, },
|
||||
{ XF86XK_Reload, Qt::Key_Reload, },
|
||||
{ 0, 0 }
|
||||
};
|
||||
|
||||
xcb_keysym_t GetX11Key( unsigned i_qt )
|
||||
{
|
||||
i_qt = i_qt & ~(Qt::ALT | Qt::CTRL | Qt::SHIFT | Qt::META);
|
||||
|
||||
/* X11 and Qt use ASCII for printable ASCII characters */
|
||||
if( i_qt >= 32 && i_qt <= 127 )
|
||||
return i_qt;
|
||||
|
||||
for( int i = 0; x11keys_to_qtkeys[i].i_qt != 0; i++ )
|
||||
{
|
||||
if( x11keys_to_qtkeys[i].i_qt == i_qt )
|
||||
return x11keys_to_qtkeys[i].i_x11;
|
||||
}
|
||||
|
||||
return XK_VoidSymbol;
|
||||
}
|
20
zeal/xcb_keysym.h
Normal file
20
zeal/xcb_keysym.h
Normal file
@ -0,0 +1,20 @@
|
||||
#ifndef XCB_KEYSYM_H
|
||||
#define XCB_KEYSYM_H
|
||||
|
||||
#include <xcb/xcb.h>
|
||||
#include <xcb/xcb_keysyms.h>
|
||||
#include <X11/keysym.h>
|
||||
#include <X11/XF86keysym.h>
|
||||
|
||||
typedef struct
|
||||
{
|
||||
xcb_keysym_t i_x11;
|
||||
unsigned i_qt;
|
||||
|
||||
} x11_to_qt;
|
||||
|
||||
extern const x11_to_qt x11keys_to_qtkeys[];
|
||||
|
||||
extern xcb_keysym_t GetX11Key( unsigned i_qt );
|
||||
|
||||
#endif
|
@ -32,7 +32,8 @@ HEADERS += mainwindow.h \
|
||||
lineedit.h \
|
||||
zealsearchitemdelegate.h \
|
||||
zealsearchitemstyle.h \
|
||||
zealsettingsdialog.h
|
||||
zealsettingsdialog.h \
|
||||
xcb_keysym.h
|
||||
|
||||
FORMS += mainwindow.ui \
|
||||
zealsettingsdialog.ui
|
||||
@ -43,5 +44,6 @@ QMAKE_CXXFLAGS += -std=c++11
|
||||
win32:DEFINES += WIN32
|
||||
|
||||
unix:!macx: LIBS += -lxcb-keysyms
|
||||
unix:!macx: SOURCES += xcb_keysym.cpp
|
||||
|
||||
include (widgets/widgets.pri)
|
||||
|
@ -7,6 +7,7 @@
|
||||
#include <xcb/xcb_keysyms.h>
|
||||
#include <X11/keysym.h>
|
||||
#include <QGuiApplication>
|
||||
#include "xcb_keysym.h"
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5, 1, 0)
|
||||
#include <QtGui/5.1.0/QtGui/qpa/qplatformnativeinterface.h>
|
||||
#else
|
||||
@ -100,21 +101,41 @@ bool ZealNativeEventFilter::nativeEventFilter(const QByteArray &eventType, void
|
||||
return true;
|
||||
}
|
||||
#else // WIN32
|
||||
|
||||
xcb_generic_event_t* ev = static_cast<xcb_generic_event_t*>(message);
|
||||
if((ev->response_type&127) == XCB_KEY_PRESS) {
|
||||
if((ev->response_type&127) == XCB_KEY_PRESS && !hotKey.isEmpty()) {
|
||||
xcb_connection_t *c = static_cast<xcb_connection_t*>(
|
||||
((QGuiApplication*)QGuiApplication::instance())->
|
||||
platformNativeInterface()->nativeResourceForWindow("connection", 0));
|
||||
xcb_key_press_event_t *event = (xcb_key_press_event_t *)ev;
|
||||
|
||||
xcb_key_symbols_t *keysyms = xcb_key_symbols_alloc(c);
|
||||
xcb_keycode_t *keycodes = xcb_key_symbols_get_keycode(keysyms, XK_space);
|
||||
xcb_keycode_t *keycodes = xcb_key_symbols_get_keycode(keysyms, GetX11Key(hotKey[hotKey.count()-1]));
|
||||
int i = 0;
|
||||
bool found = false;
|
||||
while(keycodes[i] != XCB_NO_SYMBOL) {
|
||||
if(event->detail == keycodes[i]) {
|
||||
if(event->state & GetModifier(c, keysyms, XK_Alt_L) || event->state & GetModifier(c, keysyms, XK_Alt_R)) {
|
||||
bool modifiers_present = true;
|
||||
if(hotKey[hotKey.count()-1] & Qt::ALT) {
|
||||
if(!(event->state & GetModifier(c, keysyms, XK_Alt_L) || event->state & GetModifier(c, keysyms, XK_Alt_R))) {
|
||||
modifiers_present = false;
|
||||
}
|
||||
}
|
||||
if(hotKey[hotKey.count()-1] & Qt::CTRL) {
|
||||
if(!(event->state & GetModifier(c, keysyms, XK_Control_L) || event->state & GetModifier(c, keysyms, XK_Control_R))) {
|
||||
modifiers_present = false;
|
||||
}
|
||||
}
|
||||
if(hotKey[hotKey.count()-1] & Qt::META) {
|
||||
if(!(event->state & GetModifier(c, keysyms, XK_Meta_L) || event->state & GetModifier(c, keysyms, XK_Meta_R))) {
|
||||
modifiers_present = false;
|
||||
}
|
||||
}
|
||||
if(hotKey[hotKey.count()-1] & Qt::SHIFT) {
|
||||
if(!(event->state & GetModifier(c, keysyms, XK_Shift_L) || event->state & GetModifier(c, keysyms, XK_Shift_R))) {
|
||||
modifiers_present = false;
|
||||
}
|
||||
}
|
||||
if(enabled && modifiers_present) {
|
||||
xcb_allow_events(c, XCB_ALLOW_ASYNC_KEYBOARD, event->time);
|
||||
emit gotHotKey();
|
||||
found = true;
|
||||
|
@ -3,6 +3,7 @@
|
||||
|
||||
#include <QObject>
|
||||
#include <QAbstractNativeEventFilter>
|
||||
#include <QKeySequence>
|
||||
|
||||
class ZealNativeEventFilter : public QObject, public QAbstractNativeEventFilter
|
||||
{
|
||||
@ -10,10 +11,14 @@ class ZealNativeEventFilter : public QObject, public QAbstractNativeEventFilter
|
||||
public:
|
||||
explicit ZealNativeEventFilter(QObject *parent = 0);
|
||||
bool nativeEventFilter(const QByteArray &eventType, void *message, long *result);
|
||||
void setEnabled(bool enabled_) { enabled = enabled_; }
|
||||
void setHotKey(const QKeySequence& hotKey_) { hotKey = hotKey_; }
|
||||
signals:
|
||||
void gotHotKey();
|
||||
public slots:
|
||||
|
||||
private:
|
||||
bool enabled = true;
|
||||
QKeySequence hotKey;
|
||||
};
|
||||
|
||||
#endif // ZEALNATIVEEVENTFILTER_H
|
||||
|
@ -12,3 +12,13 @@ ZealSettingsDialog::~ZealSettingsDialog()
|
||||
{
|
||||
delete ui;
|
||||
}
|
||||
|
||||
void ZealSettingsDialog::setHotKey(const QKeySequence &keySequence)
|
||||
{
|
||||
ui->toolButton->setKeySequence(keySequence);
|
||||
}
|
||||
|
||||
QKeySequence ZealSettingsDialog::hotKey()
|
||||
{
|
||||
return ui->toolButton->keySequence();
|
||||
}
|
||||
|
@ -14,6 +14,8 @@ class ZealSettingsDialog : public QDialog
|
||||
public:
|
||||
explicit ZealSettingsDialog(QWidget *parent = 0);
|
||||
~ZealSettingsDialog();
|
||||
void setHotKey(const QKeySequence &keySequence);
|
||||
QKeySequence hotKey();
|
||||
|
||||
private:
|
||||
Ui::ZealSettingsDialog *ui;
|
||||
|
@ -6,12 +6,12 @@
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>400</width>
|
||||
<height>300</height>
|
||||
<width>236</width>
|
||||
<height>101</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Dialog</string>
|
||||
<string>Zeal Options</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
@ -24,7 +24,7 @@
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QToolButton" name="toolButton">
|
||||
<widget class="RazorShortcutButton" name="toolButton">
|
||||
<property name="text">
|
||||
<string>...</string>
|
||||
</property>
|
||||
@ -44,6 +44,13 @@
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>RazorShortcutButton</class>
|
||||
<extends>QToolButton</extends>
|
||||
<header>widgets/razorshortcutbutton.h</header>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources/>
|
||||
<connections>
|
||||
<connection>
|
||||
|
Loading…
Reference in New Issue
Block a user