+ 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:
Konstantin Isakov 2009-04-22 15:29:28 +00:00
parent 5bc60a13b6
commit 23abdb9b44
2 changed files with 104 additions and 7 deletions

View file

@ -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);
}

View file

@ -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