mirror of
https://github.com/xiaoyifang/goldendict-ng.git
synced 2024-11-27 19:24:08 +00:00
+ Shield the hotkeys from being intercepted by other apps using XGrabKey(),
unless the hotkey is a clipboard copy key on its first occurence in a combo.
This commit is contained in:
parent
5bc60a13b6
commit
23abdb9b44
|
@ -52,15 +52,29 @@ HotkeyWrapper::~HotkeyWrapper()
|
||||||
void HotkeyWrapper::waitKey2()
|
void HotkeyWrapper::waitKey2()
|
||||||
{
|
{
|
||||||
state2 = false;
|
state2 = false;
|
||||||
|
|
||||||
|
#ifdef Q_WS_X11
|
||||||
|
|
||||||
|
if ( keyToUngrab != grabbedKeys.end() )
|
||||||
|
{
|
||||||
|
ungrabKey( keyToUngrab );
|
||||||
|
keyToUngrab = grabbedKeys.end();
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
bool HotkeyWrapper::checkState(quint32 vk, quint32 mod)
|
bool HotkeyWrapper::checkState(quint32 vk, quint32 mod)
|
||||||
{
|
{
|
||||||
if (state2) { // wait for 2nd key
|
if ( state2 )
|
||||||
state2 = false;
|
{ // wait for 2nd key
|
||||||
if (state2waiter.key2 == vk && state2waiter.modifier == mod) {
|
|
||||||
emit hotkeyActivated( state2waiter.handle );
|
waitKey2(); // Cancel the 2nd-key wait stage
|
||||||
return true;
|
|
||||||
|
if (state2waiter.key2 == vk && state2waiter.modifier == mod)
|
||||||
|
{
|
||||||
|
emit hotkeyActivated( state2waiter.handle );
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -77,6 +91,20 @@ bool HotkeyWrapper::checkState(quint32 vk, quint32 mod)
|
||||||
state2 = true;
|
state2 = true;
|
||||||
state2waiter = hs;
|
state2waiter = hs;
|
||||||
QTimer::singleShot(500, this, SLOT(waitKey2()));
|
QTimer::singleShot(500, this, SLOT(waitKey2()));
|
||||||
|
|
||||||
|
#ifdef Q_WS_X11
|
||||||
|
|
||||||
|
// Grab the second key, unless it's grabbed already
|
||||||
|
// Note that we only grab the clipboard key only if
|
||||||
|
// the sequence didn't begin with it
|
||||||
|
|
||||||
|
if ( ( isCopyToClipboardKey( hs.key, hs.modifier ) ||
|
||||||
|
!isCopyToClipboardKey( hs.key2, hs.modifier ) ) &&
|
||||||
|
!isKeyGrabbed( hs.key2, hs.modifier ) )
|
||||||
|
keyToUngrab = grabKey( hs.key2, hs.modifier );
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -240,6 +268,8 @@ bool QHotkeyApplication::winEventFilter ( MSG * message, long * result )
|
||||||
|
|
||||||
void HotkeyWrapper::init()
|
void HotkeyWrapper::init()
|
||||||
{
|
{
|
||||||
|
keyToUngrab = grabbedKeys.end();
|
||||||
|
|
||||||
// We use RECORD extension instead of XGrabKey. That's because XGrabKey
|
// We use RECORD extension instead of XGrabKey. That's because XGrabKey
|
||||||
// prevents other clients from getting their input if it's grabbed.
|
// prevents other clients from getting their input if it's grabbed.
|
||||||
|
|
||||||
|
@ -254,6 +284,9 @@ void HotkeyWrapper::init()
|
||||||
lAltCode = XKeysymToKeycode( display, XK_Alt_L );
|
lAltCode = XKeysymToKeycode( display, XK_Alt_L );
|
||||||
rAltCode = XKeysymToKeycode( display, XK_Alt_R );
|
rAltCode = XKeysymToKeycode( display, XK_Alt_R );
|
||||||
|
|
||||||
|
cCode = XKeysymToKeycode( display, XK_c );
|
||||||
|
insertCode = XKeysymToKeycode( display, XK_Insert );
|
||||||
|
|
||||||
currentModifiers = 0;
|
currentModifiers = 0;
|
||||||
|
|
||||||
// This one will be used to read the recorded content
|
// This one will be used to read the recorded content
|
||||||
|
@ -372,11 +405,49 @@ bool HotkeyWrapper::setGlobalKey( int key, int key2,
|
||||||
if (modifier & Qt::AltModifier)
|
if (modifier & Qt::AltModifier)
|
||||||
mod |= Mod1Mask;
|
mod |= Mod1Mask;
|
||||||
|
|
||||||
hotkeys.append( HotkeyStruct( vk, vk2, mod, handle ) );
|
hotkeys.append( HotkeyStruct( vk, vk2, mod, handle, 0 ) );
|
||||||
|
|
||||||
|
if ( !isCopyToClipboardKey( vk, mod ) )
|
||||||
|
grabKey( vk, mod ); // Make sure it doesn't get caught by other apps
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool HotkeyWrapper::isCopyToClipboardKey( quint32 keyCode, quint32 modifiers ) const
|
||||||
|
{
|
||||||
|
return modifiers == ControlMask &&
|
||||||
|
( keyCode == cCode || keyCode == insertCode );
|
||||||
|
}
|
||||||
|
|
||||||
|
bool HotkeyWrapper::isKeyGrabbed( quint32 keyCode, quint32 modifiers ) const
|
||||||
|
{
|
||||||
|
GrabbedKeys::const_iterator i = grabbedKeys.find( std::make_pair( keyCode, modifiers ) );
|
||||||
|
|
||||||
|
return i != grabbedKeys.end();
|
||||||
|
}
|
||||||
|
|
||||||
|
HotkeyWrapper::GrabbedKeys::iterator HotkeyWrapper::grabKey( quint32 keyCode,
|
||||||
|
quint32 modifiers )
|
||||||
|
{
|
||||||
|
std::pair< GrabbedKeys::iterator, bool > result =
|
||||||
|
grabbedKeys.insert( std::make_pair( keyCode, modifiers ) );
|
||||||
|
|
||||||
|
if ( result.second )
|
||||||
|
{
|
||||||
|
XGrabKey( QX11Info::display(), keyCode, modifiers, QX11Info::appRootWindow(),
|
||||||
|
True, GrabModeAsync, GrabModeAsync );
|
||||||
|
}
|
||||||
|
|
||||||
|
return result.first;
|
||||||
|
}
|
||||||
|
|
||||||
|
void HotkeyWrapper::ungrabKey( GrabbedKeys::iterator i )
|
||||||
|
{
|
||||||
|
XUngrabKey( QX11Info::display(), i->first, i->second, QX11Info::appRootWindow() );
|
||||||
|
|
||||||
|
grabbedKeys.erase( i );
|
||||||
|
}
|
||||||
|
|
||||||
quint32 HotkeyWrapper::nativeKey(int key)
|
quint32 HotkeyWrapper::nativeKey(int key)
|
||||||
{
|
{
|
||||||
QString keySymName;
|
QString keySymName;
|
||||||
|
@ -408,6 +479,9 @@ void HotkeyWrapper::unregister()
|
||||||
XFree( recordRange );
|
XFree( recordRange );
|
||||||
XCloseDisplay( dataDisplay );
|
XCloseDisplay( dataDisplay );
|
||||||
|
|
||||||
|
while( grabbedKeys.size() )
|
||||||
|
ungrabKey( grabbedKeys.begin() );
|
||||||
|
|
||||||
(static_cast<QHotkeyApplication*>(qApp))->unregisterWrapper(this);
|
(static_cast<QHotkeyApplication*>(qApp))->unregisterWrapper(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,6 +5,8 @@
|
||||||
|
|
||||||
#ifdef Q_WS_X11
|
#ifdef Q_WS_X11
|
||||||
|
|
||||||
|
#include <set>
|
||||||
|
|
||||||
#include <X11/Xlib.h>
|
#include <X11/Xlib.h>
|
||||||
#include <X11/extensions/record.h>
|
#include <X11/extensions/record.h>
|
||||||
#include <QX11Info>
|
#include <QX11Info>
|
||||||
|
@ -84,7 +86,8 @@ private:
|
||||||
void run(); // QThread
|
void run(); // QThread
|
||||||
|
|
||||||
// We do one-time init of those, translating keysyms to keycodes
|
// We do one-time init of those, translating keysyms to keycodes
|
||||||
KeyCode lShiftCode, rShiftCode, lCtrlCode, rCtrlCode, lAltCode, rAltCode;
|
KeyCode lShiftCode, rShiftCode, lCtrlCode, rCtrlCode, lAltCode, rAltCode,
|
||||||
|
cCode, insertCode;
|
||||||
|
|
||||||
quint32 currentModifiers;
|
quint32 currentModifiers;
|
||||||
|
|
||||||
|
@ -93,6 +96,26 @@ private:
|
||||||
XRecordContext recordContext;
|
XRecordContext recordContext;
|
||||||
XRecordClientSpec recordClientSpec;
|
XRecordClientSpec recordClientSpec;
|
||||||
|
|
||||||
|
/// Holds all the keys currently grabbed.
|
||||||
|
/// The first value is keycode, the second is modifiers
|
||||||
|
typedef std::set< std::pair< quint32, quint32 > > GrabbedKeys;
|
||||||
|
GrabbedKeys grabbedKeys;
|
||||||
|
|
||||||
|
GrabbedKeys::iterator keyToUngrab; // Used for second stage grabs
|
||||||
|
|
||||||
|
/// Returns true if the given key is usually used to copy from clipboard,
|
||||||
|
/// false otherwise.
|
||||||
|
bool isCopyToClipboardKey( quint32 keyCode, quint32 modifiers ) const;
|
||||||
|
/// Returns true if the given key is grabbed, false otherwise
|
||||||
|
bool isKeyGrabbed( quint32 keyCode, quint32 modifiers ) const;
|
||||||
|
/// Grabs the given key, recording the fact in grabbedKeys. If the key's
|
||||||
|
/// already grabbed, does nothing.
|
||||||
|
/// Returns the key's iterator in grabbedKeys.
|
||||||
|
GrabbedKeys::iterator grabKey( quint32 keyCode, quint32 modifiers );
|
||||||
|
/// Ungrabs the given key. erasing it from grabbedKeys. The key's provided
|
||||||
|
/// as an interator inside the grabbedKeys set.
|
||||||
|
void ungrabKey( GrabbedKeys::iterator );
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
|
|
||||||
/// Emitted from the thread
|
/// Emitted from the thread
|
||||||
|
|
Loading…
Reference in a new issue