mirror of
https://github.com/xiaoyifang/goldendict-ng.git
synced 2024-11-27 15:24:05 +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()
|
||||
{
|
||||
state2 = false;
|
||||
|
||||
#ifdef Q_WS_X11
|
||||
|
||||
if ( keyToUngrab != grabbedKeys.end() )
|
||||
{
|
||||
ungrabKey( keyToUngrab );
|
||||
keyToUngrab = grabbedKeys.end();
|
||||
}
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
bool HotkeyWrapper::checkState(quint32 vk, quint32 mod)
|
||||
{
|
||||
if (state2) { // wait for 2nd key
|
||||
state2 = false;
|
||||
if (state2waiter.key2 == vk && state2waiter.modifier == mod) {
|
||||
emit hotkeyActivated( state2waiter.handle );
|
||||
return true;
|
||||
if ( state2 )
|
||||
{ // wait for 2nd key
|
||||
|
||||
waitKey2(); // Cancel the 2nd-key wait stage
|
||||
|
||||
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;
|
||||
state2waiter = hs;
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
@ -240,6 +268,8 @@ bool QHotkeyApplication::winEventFilter ( MSG * message, long * result )
|
|||
|
||||
void HotkeyWrapper::init()
|
||||
{
|
||||
keyToUngrab = grabbedKeys.end();
|
||||
|
||||
// We use RECORD extension instead of XGrabKey. That's because XGrabKey
|
||||
// prevents other clients from getting their input if it's grabbed.
|
||||
|
||||
|
@ -254,6 +284,9 @@ void HotkeyWrapper::init()
|
|||
lAltCode = XKeysymToKeycode( display, XK_Alt_L );
|
||||
rAltCode = XKeysymToKeycode( display, XK_Alt_R );
|
||||
|
||||
cCode = XKeysymToKeycode( display, XK_c );
|
||||
insertCode = XKeysymToKeycode( display, XK_Insert );
|
||||
|
||||
currentModifiers = 0;
|
||||
|
||||
// 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)
|
||||
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;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
QString keySymName;
|
||||
|
@ -408,6 +479,9 @@ void HotkeyWrapper::unregister()
|
|||
XFree( recordRange );
|
||||
XCloseDisplay( dataDisplay );
|
||||
|
||||
while( grabbedKeys.size() )
|
||||
ungrabKey( grabbedKeys.begin() );
|
||||
|
||||
(static_cast<QHotkeyApplication*>(qApp))->unregisterWrapper(this);
|
||||
}
|
||||
|
||||
|
|
|
@ -5,6 +5,8 @@
|
|||
|
||||
#ifdef Q_WS_X11
|
||||
|
||||
#include <set>
|
||||
|
||||
#include <X11/Xlib.h>
|
||||
#include <X11/extensions/record.h>
|
||||
#include <QX11Info>
|
||||
|
@ -84,7 +86,8 @@ private:
|
|||
void run(); // QThread
|
||||
|
||||
// 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;
|
||||
|
||||
|
@ -93,6 +96,26 @@ private:
|
|||
XRecordContext recordContext;
|
||||
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:
|
||||
|
||||
/// Emitted from the thread
|
||||
|
|
Loading…
Reference in a new issue