diff --git a/.clang-format b/.clang-format index b0e8ca9f..c8785537 100644 --- a/.clang-format +++ b/.clang-format @@ -142,4 +142,7 @@ StatementMacros: - QT_REQUIRE_VERSION UseCRLF: false UseTab: Never +--- +Language: ObjC +BasedOnStyle: WebKit ... diff --git a/src/hotkeywrapper.hh b/src/hotkeywrapper.hh index 27e3f47c..ca233f42 100644 --- a/src/hotkeywrapper.hh +++ b/src/hotkeywrapper.hh @@ -30,8 +30,7 @@ #endif #ifdef Q_OS_MAC - #define __SECURITYHI__ - #include + #import #endif ////////////////////////////////////////////////////////////////////////// diff --git a/src/macos/machotkeywrapper.mm b/src/macos/machotkeywrapper.mm index 12c01ed8..c7f7750b 100644 --- a/src/macos/machotkeywrapper.mm +++ b/src/macos/machotkeywrapper.mm @@ -2,10 +2,10 @@ * Part of GoldenDict. Licensed under GPLv3 or later, see the LICENSE file */ #include "hotkeywrapper.hh" -#include #include -#include #include +#include +#include #include #import @@ -23,120 +23,114 @@ /// https://github.com/sindresorhus/KeyboardShortcuts/blob/9369a045a72a5296150879781321aecd228171db/readme.md?plain=1#L207 /// -namespace MacKeyMapping -{ +namespace MacKeyMapping { // Convert Qt key codes to Mac OS X native codes -struct ReverseMapEntry -{ - UniChar character; - UInt16 keyCode; +struct ReverseMapEntry { + UniChar character; + UInt16 keyCode; }; -static struct ReverseMapEntry * mapping; +static struct ReverseMapEntry* mapping; static int mapEntries = 0; void createMapping() { - if( mapping == NULL ) - { - TISInputSourceRef inputSourceRef = TISCopyInputSourceForLanguage( CFSTR( "en" ) ); - if ( !inputSourceRef ) { - inputSourceRef = TISCopyCurrentKeyboardInputSource(); -} - if ( !inputSourceRef ) { - return; -} + if (mapping == NULL) { + TISInputSourceRef inputSourceRef = TISCopyInputSourceForLanguage(CFSTR("en")); + if (!inputSourceRef) { + inputSourceRef = TISCopyCurrentKeyboardInputSource(); + } + if (!inputSourceRef) { + return; + } - CFDataRef dataRef = ( CFDataRef )TISGetInputSourceProperty( inputSourceRef, - kTISPropertyUnicodeKeyLayoutData ); - // this method returns null under macos Japanese input method(and also Chinese), which causes cmd+C+C not to be registered as a hotkey - if( !dataRef ) - { - // solve the null value under Japanese keyboard - inputSourceRef = TISCopyCurrentKeyboardLayoutInputSource(); - dataRef = static_cast((TISGetInputSourceProperty(inputSourceRef, kTISPropertyUnicodeKeyLayoutData))); + CFDataRef dataRef = (CFDataRef)TISGetInputSourceProperty(inputSourceRef, + kTISPropertyUnicodeKeyLayoutData); + // this method returns null under macos Japanese input method(and also Chinese), which causes cmd+C+C not to be registered as a hotkey if (!dataRef) { - return; + // solve the null value under Japanese keyboard + inputSourceRef = TISCopyCurrentKeyboardLayoutInputSource(); + dataRef = static_cast((TISGetInputSourceProperty(inputSourceRef, kTISPropertyUnicodeKeyLayoutData))); + if (!dataRef) { + return; + } + } + + const UCKeyboardLayout* keyboardLayoutPtr = (const UCKeyboardLayout*)CFDataGetBytePtr(dataRef); + if (!keyboardLayoutPtr) { + return; + } + + mapping = (struct ReverseMapEntry*)calloc(128, sizeof(struct ReverseMapEntry)); + if (!mapping) { + return; + } + + mapEntries = 0; + + for (int i = 0; i < 128; i++) { + UInt32 theDeadKeyState = 0; + UniCharCount theLength = 0; + if (UCKeyTranslate(keyboardLayoutPtr, i, kUCKeyActionDisplay, 0, LMGetKbdType(), + kUCKeyTranslateNoDeadKeysBit, &theDeadKeyState, 1, &theLength, + &mapping[mapEntries].character) + == noErr + && theLength > 0) { + if (isprint(mapping[mapEntries].character)) { + mapping[mapEntries++].keyCode = i; + } + } } } - - const UCKeyboardLayout * keyboardLayoutPtr = ( const UCKeyboardLayout * )CFDataGetBytePtr( dataRef ); - if( !keyboardLayoutPtr ) { - return; } - mapping = ( struct ReverseMapEntry * )calloc( 128 , sizeof(struct ReverseMapEntry) ); - if( !mapping ) { - return; -} - - mapEntries = 0; - - for( int i = 0; i < 128; i++ ) - { - UInt32 theDeadKeyState = 0; - UniCharCount theLength = 0; - if( UCKeyTranslate( keyboardLayoutPtr, i, kUCKeyActionDisplay, 0, LMGetKbdType(), - kUCKeyTranslateNoDeadKeysBit, &theDeadKeyState, 1, &theLength, - &mapping[ mapEntries ].character ) == noErr && theLength > 0 ) - { - if( isprint( mapping[ mapEntries ].character ) ) - { - mapping[ mapEntries++ ].keyCode = i; - } - } - } - } -} - -quint32 qtKeyToNativeKey( quint32 key ) +quint32 qtKeyToNativeKey(quint32 key) { - createMapping(); - if( mapping == NULL ) { + createMapping(); + if (mapping == NULL) { + return 0; + } + + for (int i = 0; i < mapEntries; i++) { + if (mapping[i].character == key) { + return mapping[i].keyCode; + } + } + return 0; } - for( int i = 0; i < mapEntries; i++ ) - { - if( mapping[ i ].character == key ) { - return mapping[ i ].keyCode; -} - } - - return 0; -} - } // namespace MacKeyMapping -static pascal OSStatus hotKeyHandler( EventHandlerCallRef /* nextHandler */, EventRef theEvent, void * userData ) +static pascal OSStatus hotKeyHandler(EventHandlerCallRef /* nextHandler */, EventRef theEvent, void* userData) { - EventHotKeyID hkID; - GetEventParameter( theEvent, kEventParamDirectObject, typeEventHotKeyID, NULL, sizeof(EventHotKeyID), NULL, &hkID ); - static_cast< HotkeyWrapper * >( userData )->activated( hkID.id ); - return noErr; + EventHotKeyID hkID; + GetEventParameter(theEvent, kEventParamDirectObject, typeEventHotKeyID, NULL, sizeof(EventHotKeyID), NULL, &hkID); + static_cast(userData)->activated(hkID.id); + return noErr; } -HotkeyWrapper::HotkeyWrapper( QObject *parent ) +HotkeyWrapper::HotkeyWrapper(QObject* parent) { -(void) parent; - hotKeyFunction = NewEventHandlerUPP( hotKeyHandler ); - EventTypeSpec type; - type.eventClass = kEventClassKeyboard; - type.eventKind = kEventHotKeyPressed; - InstallApplicationEventHandler( hotKeyFunction, 1, &type, this, &handlerRef ); - keyC = nativeKey( 'c' ); + (void)parent; + hotKeyFunction = NewEventHandlerUPP(hotKeyHandler); + EventTypeSpec type; + type.eventClass = kEventClassKeyboard; + type.eventKind = kEventHotKeyPressed; + InstallApplicationEventHandler(hotKeyFunction, 1, &type, this, &handlerRef); + keyC = nativeKey('c'); } HotkeyWrapper::~HotkeyWrapper() { - unregister(); - RemoveEventHandler( handlerRef ); + unregister(); + RemoveEventHandler(handlerRef); } void HotkeyWrapper::waitKey2() { - state2 = false; + state2 = false; } void checkAndRequestAccessibilityPermission() { @@ -159,196 +153,220 @@ void checkAndRequestAccessibilityPermission() } } -void HotkeyWrapper::activated( int hkId ) +void HotkeyWrapper::activated(int hkId) { - if ( state2 ) - { // wait for 2nd key + if (state2) { // wait for 2nd key - waitKey2(); // Cancel the 2nd-key wait stage + waitKey2(); // Cancel the 2nd-key wait stage - if ( hkId == state2waiter.id + 1 || - ( hkId == state2waiter.id && state2waiter.key == state2waiter.key2 ) ) - { - emit hotkeyActivated( state2waiter.handle ); - return; + if (hkId == state2waiter.id + 1 || (hkId == state2waiter.id && state2waiter.key == state2waiter.key2)) { + emit hotkeyActivated(state2waiter.handle); + return; + } } - } - for ( int i = 0; i < hotkeys.count(); i++ ) - { - HotkeyStruct &hs = hotkeys[ i ]; - if( hkId == hs.id ) - { - if( hs.key == keyC && hs.modifier == cmdKey ) - { - checkAndRequestAccessibilityPermission(); - - // If that was a copy-to-clipboard shortcut, re-emit it back so it could - // reach its original destination so it could be acted upon. - UnregisterEventHotKey( hs.hkRef ); + for (int i = 0; i < hotkeys.count(); i++) { + HotkeyStruct& hs = hotkeys[i]; + if (hkId == hs.id) { + if (hs.key == keyC && hs.modifier == cmdKey) { + checkAndRequestAccessibilityPermission(); - sendCmdC(); + // If that was a copy-to-clipboard shortcut, re-emit it back so it could + // reach its original destination so it could be acted upon. + UnregisterEventHotKey(hs.hkRef); - EventHotKeyID hotKeyID; - hotKeyID.signature = 'GDHK'; - hotKeyID.id = hs.id; + sendCmdC(); - RegisterEventHotKey( hs.key, hs.modifier, hotKeyID, GetApplicationEventTarget(), 0, &hs.hkRef ); - } + EventHotKeyID hotKeyID; + hotKeyID.signature = 'GDHK'; + hotKeyID.id = hs.id; - if ( hs.key2 == 0 ) { - emit hotkeyActivated( hs.handle ); - return; - } + RegisterEventHotKey(hs.key, hs.modifier, hotKeyID, GetApplicationEventTarget(), 0, &hs.hkRef); + } - state2 = true; - state2waiter = hs; - QTimer::singleShot( 500, this, SLOT( waitKey2() ) ); - return; + if (hs.key2 == 0) { + emit hotkeyActivated(hs.handle); + return; + } + + state2 = true; + state2waiter = hs; + QTimer::singleShot(500, this, SLOT(waitKey2())); + return; + } } - } - state2 = false; - return; + state2 = false; + return; } void HotkeyWrapper::unregister() { - for ( int i = 0; i < hotkeys.count(); i++ ) - { - HotkeyStruct const & hk = hotkeys.at( i ); + for (int i = 0; i < hotkeys.count(); i++) { + HotkeyStruct const& hk = hotkeys.at(i); - UnregisterEventHotKey( hk.hkRef ); + UnregisterEventHotKey(hk.hkRef); - if ( hk.key2 && hk.key2 != hk.key ) { - UnregisterEventHotKey( hk.hkRef2 ); -} - } + if (hk.key2 && hk.key2 != hk.key) { + UnregisterEventHotKey(hk.hkRef2); + } + } - (static_cast< QHotkeyApplication * >( qApp ))->unregisterWrapper( this ); + (static_cast(qApp))->unregisterWrapper(this); } -bool HotkeyWrapper::setGlobalKey( QKeySequence const & seq, int handle ) +bool HotkeyWrapper::setGlobalKey(QKeySequence const& seq, int handle) { - Config::HotKey hk(seq); - return setGlobalKey(hk.key1,hk.key2,hk.modifiers,handle); + Config::HotKey hk(seq); + return setGlobalKey(hk.key1, hk.key2, hk.modifiers, handle); } -bool HotkeyWrapper::setGlobalKey( int key, int key2, Qt::KeyboardModifiers modifier, int handle ) +bool HotkeyWrapper::setGlobalKey(int key, int key2, Qt::KeyboardModifiers modifier, int handle) { - if ( !key ) { - return false; // We don't monitor empty combinations + if (!key) { + return false; // We don't monitor empty combinations + } + + quint32 vk = nativeKey(key); + + if (vk == 0) { + return false; + } + + quint32 vk2 = key2 ? nativeKey(key2) : 0; + + static int nextId = 1; + if (nextId > 0xBFFF - 1) { + nextId = 1; + } + + quint32 mod = 0; + if (modifier & Qt::CTRL) { + mod |= cmdKey; + } + if (modifier & Qt::ALT) { + mod |= optionKey; + } + if (modifier & Qt::SHIFT) { + mod |= shiftKey; + } + if (modifier & Qt::META) { + mod |= controlKey; + } + + hotkeys.append(HotkeyStruct(vk, vk2, mod, handle, nextId)); + HotkeyStruct& hk = hotkeys.last(); + + EventHotKeyID hotKeyID; + hotKeyID.signature = 'GDHK'; + hotKeyID.id = nextId; + + OSStatus ret = RegisterEventHotKey(vk, mod, hotKeyID, GetApplicationEventTarget(), 0, &hk.hkRef); + if (ret != 0) { + return false; + } + + if (vk2 && vk2 != vk) { + hotKeyID.id = nextId + 1; + ret = RegisterEventHotKey(vk2, mod, hotKeyID, GetApplicationEventTarget(), 0, &hk.hkRef2); + } + + nextId += 2; + + return ret == 0; } - quint32 vk = nativeKey( key ); - - if( vk == 0 ) { - return false; -} - - quint32 vk2 = key2 ? nativeKey( key2 ) : 0; - - static int nextId = 1; - if( nextId > 0xBFFF - 1 ) { - nextId = 1; -} - - quint32 mod = 0; - if( modifier & Qt::CTRL ) { - mod |= cmdKey; -} - if( modifier & Qt::ALT ) { - mod |= optionKey; -} - if( modifier & Qt::SHIFT ) { - mod |= shiftKey; -} - if( modifier & Qt::META ) { - mod |= controlKey; -} - - hotkeys.append( HotkeyStruct( vk, vk2, mod, handle, nextId ) ); - HotkeyStruct &hk = hotkeys.last(); - - EventHotKeyID hotKeyID; - hotKeyID.signature = 'GDHK'; - hotKeyID.id = nextId; - - OSStatus ret = RegisterEventHotKey( vk, mod, hotKeyID, GetApplicationEventTarget(), 0, &hk.hkRef ); - if ( ret != 0 ) { - return false; -} - - if ( vk2 && vk2 != vk ) - { - hotKeyID.id = nextId + 1; - ret = RegisterEventHotKey( vk2, mod, hotKeyID, GetApplicationEventTarget(), 0, &hk.hkRef2 ); - } - - nextId += 2; - - return ret == 0; -} - -quint32 HotkeyWrapper::nativeKey( int key ) +quint32 HotkeyWrapper::nativeKey(int key) { - switch( key ) { - case Qt::Key_Escape: return 0x35; - case Qt::Key_Tab: return 0x30; - case Qt::Key_Backspace: return 0x33; - case Qt::Key_Return: return 0x24; - case Qt::Key_Enter: return 0x4c; - case Qt::Key_Delete: return 0x75; - case Qt::Key_Clear: return 0x47; - case Qt::Key_Home: return 0x73; - case Qt::Key_End: return 0x77; - case Qt::Key_Left: return 0x7b; - case Qt::Key_Up: return 0x7e; - case Qt::Key_Right: return 0x7c; - case Qt::Key_Down: return 0x7d; - case Qt::Key_PageUp: return 0x74; - case Qt::Key_PageDown: return 0x79; - case Qt::Key_CapsLock: return 0x57; - case Qt::Key_F1: return 0x7a; - case Qt::Key_F2: return 0x78; - case Qt::Key_F3: return 0x63; - case Qt::Key_F4: return 0x76; - case Qt::Key_F5: return 0x60; - case Qt::Key_F6: return 0x61; - case Qt::Key_F7: return 0x62; - case Qt::Key_F8: return 0x64; - case Qt::Key_F9: return 0x65; - case Qt::Key_F10: return 0x6d; - case Qt::Key_F11: return 0x67; - case Qt::Key_F12: return 0x6f; - case Qt::Key_F13: return 0x69; - case Qt::Key_F14: return 0x6b; - case Qt::Key_F15: return 0x71; - case Qt::Key_Help: return 0x72; + switch (key) { + case Qt::Key_Escape: + return 0x35; + case Qt::Key_Tab: + return 0x30; + case Qt::Key_Backspace: + return 0x33; + case Qt::Key_Return: + return 0x24; + case Qt::Key_Enter: + return 0x4c; + case Qt::Key_Delete: + return 0x75; + case Qt::Key_Clear: + return 0x47; + case Qt::Key_Home: + return 0x73; + case Qt::Key_End: + return 0x77; + case Qt::Key_Left: + return 0x7b; + case Qt::Key_Up: + return 0x7e; + case Qt::Key_Right: + return 0x7c; + case Qt::Key_Down: + return 0x7d; + case Qt::Key_PageUp: + return 0x74; + case Qt::Key_PageDown: + return 0x79; + case Qt::Key_CapsLock: + return 0x57; + case Qt::Key_F1: + return 0x7a; + case Qt::Key_F2: + return 0x78; + case Qt::Key_F3: + return 0x63; + case Qt::Key_F4: + return 0x76; + case Qt::Key_F5: + return 0x60; + case Qt::Key_F6: + return 0x61; + case Qt::Key_F7: + return 0x62; + case Qt::Key_F8: + return 0x64; + case Qt::Key_F9: + return 0x65; + case Qt::Key_F10: + return 0x6d; + case Qt::Key_F11: + return 0x67; + case Qt::Key_F12: + return 0x6f; + case Qt::Key_F13: + return 0x69; + case Qt::Key_F14: + return 0x6b; + case Qt::Key_F15: + return 0x71; + case Qt::Key_Help: + return 0x72; default:; - } - return MacKeyMapping::qtKeyToNativeKey( QChar( key ).toLower().toLatin1() ); + } + return MacKeyMapping::qtKeyToNativeKey(QChar(key).toLower().toLatin1()); } void HotkeyWrapper::sendCmdC() { - CGEventFlags flags = kCGEventFlagMaskCommand; - CGEventRef ev; - CGEventSourceRef source = CGEventSourceCreate( kCGEventSourceStateCombinedSessionState ); + CGEventFlags flags = kCGEventFlagMaskCommand; + CGEventRef ev; + CGEventSourceRef source = CGEventSourceCreate(kCGEventSourceStateCombinedSessionState); - //press down - ev = CGEventCreateKeyboardEvent( source, keyC, true ); - CGEventSetFlags( ev, CGEventFlags( flags | CGEventGetFlags( ev ) ) ); //combine flags - CGEventPost( kCGAnnotatedSessionEventTap, ev ); - CFRelease( ev ); + // press down + ev = CGEventCreateKeyboardEvent(source, keyC, true); + CGEventSetFlags(ev, CGEventFlags(flags | CGEventGetFlags(ev))); // combine flags + CGEventPost(kCGAnnotatedSessionEventTap, ev); + CFRelease(ev); - //press up - ev = CGEventCreateKeyboardEvent( source, keyC, false ); - CGEventSetFlags( ev, CGEventFlags( flags | CGEventGetFlags( ev ) ) ); //combine flags - CGEventPost( kCGAnnotatedSessionEventTap, ev ); - CFRelease( ev ); + // press up + ev = CGEventCreateKeyboardEvent(source, keyC, false); + CGEventSetFlags(ev, CGEventFlags(flags | CGEventGetFlags(ev))); // combine flags + CGEventPost(kCGAnnotatedSessionEventTap, ev); + CFRelease(ev); - CFRelease( source ); + CFRelease(source); } EventHandlerUPP HotkeyWrapper::hotKeyFunction = NULL; diff --git a/src/macos/macmouseover.mm b/src/macos/macmouseover.mm index a6c775cc..03377c6b 100644 --- a/src/macos/macmouseover.mm +++ b/src/macos/macmouseover.mm @@ -1,372 +1,344 @@ #include "macmouseover.hh" -#include -#include -#include -#include -#include - -#ifndef AVAILABLE_MAC_OS_X_VERSION_10_11_AND_LATER -#define kAXValueTypeCGPoint kAXValueCGPointType -#define kAXValueTypeCFRange kAXValueCFRangeType -#endif +#import const int mouseOverInterval = 300; -CGEventRef eventCallback( CGEventTapProxy proxy, CGEventType type, CGEventRef event, void *refcon ) +CGEventRef eventCallback(CGEventTapProxy proxy, CGEventType type, CGEventRef event, void* refcon) { -(void) proxy; - if( type != kCGEventMouseMoved ) { + (void)proxy; + if (type != kCGEventMouseMoved) { + return event; + } + static_cast(refcon)->mouseMoved(); return event; } - static_cast< MacMouseOver * >( refcon )->mouseMoved(); - return event; -} -static CGPoint carbonScreenPointFromCocoaScreenPoint( NSPoint cocoaPoint ) +static CGPoint carbonScreenPointFromCocoaScreenPoint(NSPoint cocoaPoint) { - NSScreen *foundScreen = nil; - CGPoint thePoint; + NSScreen* foundScreen = nil; + CGPoint thePoint; - for (NSScreen *screen in [NSScreen screens]) { - if (NSPointInRect(cocoaPoint, [screen frame])) { - foundScreen = screen; + for (NSScreen* screen in [NSScreen screens]) { + if (NSPointInRect(cocoaPoint, [screen frame])) { + foundScreen = screen; + } } - } - if (foundScreen) { - CGFloat screenHeight = [foundScreen frame].size.height; - thePoint = CGPointMake(cocoaPoint.x, screenHeight - cocoaPoint.y - 1); - } - else { - thePoint = CGPointMake(0.0, 0.0); + if (foundScreen) { + CGFloat screenHeight = [foundScreen frame].size.height; + thePoint = CGPointMake(cocoaPoint.x, screenHeight - cocoaPoint.y - 1); + } else { + thePoint = CGPointMake(0.0, 0.0); + } + + return thePoint; } - return thePoint; -} - -MacMouseOver & MacMouseOver::instance() +MacMouseOver& MacMouseOver::instance() { - static MacMouseOver m; + static MacMouseOver m; - return m; + return m; } -MacMouseOver::MacMouseOver() : - pPref(NULL) -, tapRef( 0 ) -, loop( 0 ) +MacMouseOver::MacMouseOver() + : pPref(NULL) + , tapRef(0) + , loop(0) { - mouseTimer.setSingleShot( true ); - connect( &mouseTimer, SIGNAL( timeout() ), this, SLOT( timerShot() ) ); + mouseTimer.setSingleShot(true); + connect(&mouseTimer, SIGNAL(timeout()), this, SLOT(timerShot())); - elementSystemWide = AXUIElementCreateSystemWide(); + elementSystemWide = AXUIElementCreateSystemWide(); } MacMouseOver::~MacMouseOver() { - disableMouseOver(); + disableMouseOver(); - if( tapRef ) { - CFRelease( tapRef ); + if (tapRef) { + CFRelease(tapRef); + } + + if (loop) { + CFRelease(loop); + } + + if (elementSystemWide) { + CFRelease(elementSystemWide); + } } - if( loop ) { - CFRelease( loop ); -} - - if( elementSystemWide ) { - CFRelease( elementSystemWide ); -} -} - -QString MacMouseOver::CFStringRefToQString( CFStringRef str ) +QString MacMouseOver::CFStringRefToQString(CFStringRef str) { - int length = CFStringGetLength( str ); - if( length == 0 ) { - return QString(); -} + int length = CFStringGetLength(str); + if (length == 0) { + return QString(); + } - UniChar *chars = new UniChar[ length ]; - CFStringGetCharacters( str, CFRangeMake( 0, length ), chars ); - - QString result = QString::fromUtf16( (char16_t*)chars, length ); + UniChar* chars = new UniChar[length]; + CFStringGetCharacters(str, CFRangeMake(0, length), chars); - delete[] chars; - return result; + QString result = QString::fromUtf16((char16_t*)chars, length); + + delete[] chars; + return result; } void MacMouseOver::mouseMoved() { - mouseTimer.start( mouseOverInterval ); + mouseTimer.start(mouseOverInterval); } void MacMouseOver::enableMouseOver() { - mouseTimer.stop(); - if( !isAXAPIEnabled() ) { - return; -} - if( !tapRef ) { - tapRef = CGEventTapCreate( kCGAnnotatedSessionEventTap, kCGHeadInsertEventTap, - kCGEventTapOptionListenOnly, - CGEventMaskBit( kCGEventMouseMoved ), - eventCallback, this ); -} - if( !tapRef ) { - return; -} - if( !loop ) { - loop = CFMachPortCreateRunLoopSource( kCFAllocatorDefault, tapRef, 0 ); -} - if( loop ) { - CFRunLoopAddSource( CFRunLoopGetMain(), loop, kCFRunLoopCommonModes ); -} + mouseTimer.stop(); + if (!isAXAPIEnabled()) { + return; + } + if (!tapRef) { + tapRef = CGEventTapCreate(kCGAnnotatedSessionEventTap, kCGHeadInsertEventTap, + kCGEventTapOptionListenOnly, + CGEventMaskBit(kCGEventMouseMoved), + eventCallback, this); + } + if (!tapRef) { + return; + } + if (!loop) { + loop = CFMachPortCreateRunLoopSource(kCFAllocatorDefault, tapRef, 0); + } + if (loop) { + CFRunLoopAddSource(CFRunLoopGetMain(), loop, kCFRunLoopCommonModes); + } } void MacMouseOver::disableMouseOver() { - mouseTimer.stop(); - if( loop ) { - CFRunLoopRemoveSource( CFRunLoopGetMain(), loop, kCFRunLoopCommonModes ); -} + mouseTimer.stop(); + if (loop) { + CFRunLoopRemoveSource(CFRunLoopGetMain(), loop, kCFRunLoopCommonModes); + } } void MacMouseOver::timerShot() { - if( mouseMutex.tryLock( 0 ) ) { - mouseMutex.unlock(); - } else { - return; -} - if( !pPref ) { - return; -} - if( !pPref->enableScanPopupModifiers || checkModifiersPressed( pPref->scanPopupModifiers ) ) { - handlePosition(); -} + if (mouseMutex.tryLock(0)) { + mouseMutex.unlock(); + } else { + return; + } + if (!pPref) { + return; + } + if (!pPref->enableScanPopupModifiers || checkModifiersPressed(pPref->scanPopupModifiers)) { + handlePosition(); + } } void MacMouseOver::handlePosition() { - QMutexLocker _( &mouseMutex ); + QMutexLocker _(&mouseMutex); - QString strToTranslate; + QString strToTranslate; - NSAutoreleasePool * pool = [ [ NSAutoreleasePool alloc ] init ]; - CGPoint pt = carbonScreenPointFromCocoaScreenPoint( [NSEvent mouseLocation] ); - [ pool drain ]; + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + CGPoint pt = carbonScreenPointFromCocoaScreenPoint([NSEvent mouseLocation]); + [pool drain]; - CFArrayRef names = 0; + CFArrayRef names = 0; - AXUIElementRef elem = 0; - AXError err = AXUIElementCopyElementAtPosition( elementSystemWide, pt.x, pt.y, &elem ); + AXUIElementRef elem = 0; + AXError err = AXUIElementCopyElementAtPosition(elementSystemWide, pt.x, pt.y, &elem); - if( err != kAXErrorSuccess ) { - return; -} + if (err != kAXErrorSuccess) { + return; + } - for( ; ; ) - { - CFTypeRef parameter = AXValueCreate( kAXValueTypeCGPoint, &pt ); - CFTypeRef rangeValue; - err = AXUIElementCopyParameterizedAttributeNames( elem, &names ); - if( err != kAXErrorSuccess ) { - break; -} - - int numOfAttributes = CFArrayGetCount( names ); - if( CFArrayContainsValue( names, CFRangeMake( 0, numOfAttributes ), CFSTR( "AXRangeForPosition" ) ) ) - { - // Standard interface - err = AXUIElementCopyParameterizedAttributeValue( elem, kAXRangeForPositionParameterizedAttribute, - parameter, ( CFTypeRef * )&rangeValue ); - CFRelease( parameter ); - if( err != kAXErrorSuccess ) { - break; -} - - CFStringRef stringValue; - - CFRange decodedRange = CFRangeMake( 0, 0 ); - bool b = AXValueGetValue( (AXValueRef)rangeValue, kAXValueTypeCFRange, &decodedRange ); - CFRelease( rangeValue ); - if( b ) - { - int fromPos = decodedRange.location - 127; - if( fromPos < 0 ) { - fromPos = 0; -} - int wordPos = decodedRange.location - fromPos; // Cursor position in result string - - CFRange range = CFRangeMake( fromPos, wordPos + 1 ); - parameter = AXValueCreate( kAXValueTypeCFRange, &range ); - err = AXUIElementCopyParameterizedAttributeValue( elem, kAXStringForRangeParameterizedAttribute, - parameter, (CFTypeRef *)&stringValue ); - CFRelease( parameter ); - if( err != kAXErrorSuccess ) { - break; -} - - strToTranslate = CFStringRefToQString( stringValue ); - CFRelease( stringValue ); - - // Read string further - for( int i = 1; i < 128; i++ ) - { - range = CFRangeMake( decodedRange.location + i, 1 ); - parameter = AXValueCreate( kAXValueTypeCFRange, &range ); - err = AXUIElementCopyParameterizedAttributeValue( elem, kAXStringForRangeParameterizedAttribute, - parameter, (CFTypeRef *)&stringValue ); - CFRelease( parameter ); - - if( err != kAXErrorSuccess ) { + for (;;) { + CFTypeRef parameter = AXValueCreate(kAXValueTypeCGPoint, &pt); + CFTypeRef rangeValue; + err = AXUIElementCopyParameterizedAttributeNames(elem, &names); + if (err != kAXErrorSuccess) { break; -} - - QString s = CFStringRefToQString( stringValue ); - CFRelease( stringValue ); - - if( s[ 0 ].isLetterOrNumber() || s[ 0 ] == '-' ) { - strToTranslate += s; - } else { - break; -} } - handleRetrievedString( strToTranslate, wordPos ); - } - } - else if( CFArrayContainsValue( names, CFRangeMake( 0, numOfAttributes ), CFSTR( "AXTextMarkerForPosition" ) ) ) - { - // Safari interface - CFTypeRef marker, range; - CFStringRef str; - err = AXUIElementCopyParameterizedAttributeValue( elem, CFSTR( "AXTextMarkerForPosition" ), - parameter, ( CFTypeRef * )&marker ); - CFRelease( parameter ); - if( err != kAXErrorSuccess ) { + int numOfAttributes = CFArrayGetCount(names); + if (CFArrayContainsValue(names, CFRangeMake(0, numOfAttributes), CFSTR("AXRangeForPosition"))) { + // Standard interface + err = AXUIElementCopyParameterizedAttributeValue(elem, kAXRangeForPositionParameterizedAttribute, + parameter, (CFTypeRef*)&rangeValue); + CFRelease(parameter); + if (err != kAXErrorSuccess) { + break; + } + + CFStringRef stringValue; + + CFRange decodedRange = CFRangeMake(0, 0); + bool b = AXValueGetValue((AXValueRef)rangeValue, kAXValueTypeCFRange, &decodedRange); + CFRelease(rangeValue); + if (b) { + int fromPos = decodedRange.location - 127; + if (fromPos < 0) { + fromPos = 0; + } + int wordPos = decodedRange.location - fromPos; // Cursor position in result string + + CFRange range = CFRangeMake(fromPos, wordPos + 1); + parameter = AXValueCreate(kAXValueTypeCFRange, &range); + err = AXUIElementCopyParameterizedAttributeValue(elem, kAXStringForRangeParameterizedAttribute, + parameter, (CFTypeRef*)&stringValue); + CFRelease(parameter); + if (err != kAXErrorSuccess) { + break; + } + + strToTranslate = CFStringRefToQString(stringValue); + CFRelease(stringValue); + + // Read string further + for (int i = 1; i < 128; i++) { + range = CFRangeMake(decodedRange.location + i, 1); + parameter = AXValueCreate(kAXValueTypeCFRange, &range); + err = AXUIElementCopyParameterizedAttributeValue(elem, kAXStringForRangeParameterizedAttribute, + parameter, (CFTypeRef*)&stringValue); + CFRelease(parameter); + + if (err != kAXErrorSuccess) { + break; + } + + QString s = CFStringRefToQString(stringValue); + CFRelease(stringValue); + + if (s[0].isLetterOrNumber() || s[0] == '-') { + strToTranslate += s; + } else { + break; + } + } + + handleRetrievedString(strToTranslate, wordPos); + } + } else if (CFArrayContainsValue(names, CFRangeMake(0, numOfAttributes), CFSTR("AXTextMarkerForPosition"))) { + // Safari interface + CFTypeRef marker, range; + CFStringRef str; + err = AXUIElementCopyParameterizedAttributeValue(elem, CFSTR("AXTextMarkerForPosition"), + parameter, (CFTypeRef*)&marker); + CFRelease(parameter); + if (err != kAXErrorSuccess) { + break; + } + + err = AXUIElementCopyParameterizedAttributeValue(elem, CFSTR("AXLeftWordTextMarkerRangeForTextMarker"), + marker, (CFTypeRef*)&range); + CFRelease(marker); + if (err != kAXErrorSuccess) { + break; + } + + err = AXUIElementCopyParameterizedAttributeValue(elem, CFSTR("AXStringForTextMarkerRange"), + range, (CFTypeRef*)&str); + CFRelease(range); + if (err == kAXErrorSuccess) { + strToTranslate = CFStringRefToQString(str); + CFRelease(str); + handleRetrievedString(strToTranslate, 0); + } + } break; -} - - err = AXUIElementCopyParameterizedAttributeValue( elem, CFSTR( "AXLeftWordTextMarkerRangeForTextMarker" ), - marker, ( CFTypeRef * )&range ); - CFRelease( marker ); - if( err != kAXErrorSuccess ) { - break; -} - - err = AXUIElementCopyParameterizedAttributeValue( elem, CFSTR( "AXStringForTextMarkerRange" ), - range, ( CFTypeRef * )&str ); - CFRelease( range ); - if( err == kAXErrorSuccess ) - { - strToTranslate = CFStringRefToQString( str ); - CFRelease( str ); - handleRetrievedString( strToTranslate, 0 ); - } } - break; - } - if( elem ) { - CFRelease( elem ); -} - if( names ) { - CFRelease( names ); -} + if (elem) { + CFRelease(elem); + } + if (names) { + CFRelease(names); + } } -void MacMouseOver::handleRetrievedString( QString & wordSeq, int wordSeqPos ) +void MacMouseOver::handleRetrievedString(QString& wordSeq, int wordSeqPos) { - if( wordSeq.isEmpty() ) { - return; -} - - // locate the word inside the sequence - - QString word; - - if ( wordSeq[ wordSeqPos ].isSpace() ) - { - // Currently we ignore such cases - return; - } - else - if ( !wordSeq[ wordSeqPos ].isLetterOrNumber() ) - { - // Special case: the cursor points to something which doesn't look like a - // middle of the word -- assume that it's something that joins two words - // together. - - int begin = wordSeqPos; - - for( ; begin; --begin ) { - if ( !wordSeq[ begin - 1 ].isLetterOrNumber() ) { - break; -} -} - - int end = wordSeqPos; - - while( ++end < wordSeq.size() ) { - if ( !wordSeq[ end ].isLetterOrNumber() ) { - break; -} -} - - if ( end - begin == 1 ) - { - // Well, turns out it was just a single non-letter char, discard it - return; + if (wordSeq.isEmpty()) { + return; } - word = wordSeq.mid( begin, end - begin ); - } - else - { - // Cursor points to a letter -- cut the word it points to + // locate the word inside the sequence - int begin = wordSeqPos; + QString word; - for( ; begin; --begin ) { - if ( !wordSeq[ begin - 1 ].isLetterOrNumber() ) { - break; -} -} + if (wordSeq[wordSeqPos].isSpace()) { + // Currently we ignore such cases + return; + } else if (!wordSeq[wordSeqPos].isLetterOrNumber()) { + // Special case: the cursor points to something which doesn't look like a + // middle of the word -- assume that it's something that joins two words + // together. - int end = wordSeqPos; + int begin = wordSeqPos; - while( ++end < wordSeq.size() ) - { - if ( !wordSeq[ end ].isLetterOrNumber() ) { - break; -} + for (; begin; --begin) { + if (!wordSeq[begin - 1].isLetterOrNumber()) { + break; + } + } + + int end = wordSeqPos; + + while (++end < wordSeq.size()) { + if (!wordSeq[end].isLetterOrNumber()) { + break; + } + } + + if (end - begin == 1) { + // Well, turns out it was just a single non-letter char, discard it + return; + } + + word = wordSeq.mid(begin, end - begin); + } else { + // Cursor points to a letter -- cut the word it points to + + int begin = wordSeqPos; + + for (; begin; --begin) { + if (!wordSeq[begin - 1].isLetterOrNumber()) { + break; + } + } + + int end = wordSeqPos; + + while (++end < wordSeq.size()) { + if (!wordSeq[end].isLetterOrNumber()) { + break; + } + } + word = wordSeq.mid(begin, end - begin); } - word = wordSeq.mid( begin, end - begin ); - } - // See if we have an RTL char. Reverse the whole string if we do. + // See if we have an RTL char. Reverse the whole string if we do. - for( int x = 0; x < word.size(); ++x ) - { - QChar::Direction d = word[ x ].direction(); + for (int x = 0; x < word.size(); ++x) { + QChar::Direction d = word[x].direction(); - if ( d == QChar::DirR || d == QChar::DirAL || - d == QChar::DirRLE || d == QChar::DirRLO ) - { - std::reverse( word.begin(), word.end() ); - break; + if (d == QChar::DirR || d == QChar::DirAL || d == QChar::DirRLE || d == QChar::DirRLO) { + std::reverse(word.begin(), word.end()); + break; + } } - } - emit instance().hovered( word, false ); + emit instance().hovered(word, false); } bool MacMouseOver::isAXAPIEnabled() { - if( NSFoundationVersionNumber >= 1000 ) { // MacOS 10.9+ - return AXIsProcessTrusted(); -} + if (NSFoundationVersionNumber >= 1000) { // MacOS 10.9+ + return AXIsProcessTrusted(); + } - return AXAPIEnabled(); + return AXAPIEnabled(); }