mirror of
https://github.com/xiaoyifang/goldendict-ng.git
synced 2024-11-23 20:14:05 +00:00
Compare commits
8 commits
7626855556
...
2fc85c98ff
Author | SHA1 | Date | |
---|---|---|---|
2fc85c98ff | |||
453948155a | |||
8fc71c9586 | |||
8fd5b37335 | |||
4758f9e972 | |||
15b918eb6a | |||
27cbb7351b | |||
c787a08d2f |
|
@ -142,4 +142,7 @@ StatementMacros:
|
|||
- QT_REQUIRE_VERSION
|
||||
UseCRLF: false
|
||||
UseTab: Never
|
||||
---
|
||||
Language: ObjC
|
||||
BasedOnStyle: WebKit
|
||||
...
|
||||
|
|
|
@ -17,7 +17,6 @@ Checks: >
|
|||
portability-*,
|
||||
readability-*,
|
||||
-bugprone-easily-swappable-parameters,
|
||||
-bugprone-reserved-identifier,
|
||||
-cppcoreguidelines-owning-memory,
|
||||
-cppcoreguidelines-prefer-member-initializer,
|
||||
-cppcoreguidelines-pro-bounds-array-to-pointer-decay,
|
||||
|
@ -44,5 +43,11 @@ CheckOptions:
|
|||
value: 1
|
||||
- key: cppcoreguidelines-explicit-virtual-functions.IgnoreDestructors
|
||||
value: 1
|
||||
- key: modernize-avoid-c-arrays.AllowStringArrays
|
||||
value: 1
|
||||
- key: cppcoreguidelines-avoid-c-arrays.AllowStringArrays
|
||||
value: 1
|
||||
- key: hicpp-avoid-c-arrays.AllowStringArrays
|
||||
value: 1
|
||||
...
|
||||
|
||||
|
|
|
@ -4,22 +4,17 @@
|
|||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <fmt/format.h>
|
||||
|
||||
// clang-format off
|
||||
|
||||
/// A way to declare an exception class fast
|
||||
/// Do like this:
|
||||
/// DEF_EX( exErrorInFoo, "An error in foo encountered", std::exception )
|
||||
/// DEF_EX( exFooNotFound, "Foo was not found", exErrorInFoo )
|
||||
|
||||
#define DEF_EX( exName, exDescription, exParent ) \
|
||||
class exName: public exParent \
|
||||
{ \
|
||||
public: \
|
||||
virtual const char * what() const noexcept \
|
||||
{ \
|
||||
return ( exDescription ); \
|
||||
} \
|
||||
virtual ~exName() noexcept {} \
|
||||
};
|
||||
constexpr static char ExStr_## exName[] = exDescription; \
|
||||
using exName = defineEx< exParent, ExStr_## exName >;
|
||||
|
||||
/// Same as DEF_EX, but takes a runtime string argument, which gets concatenated
|
||||
/// with the description.
|
||||
|
@ -29,20 +24,36 @@
|
|||
/// throw exCantOpen( "example.txt" );
|
||||
///
|
||||
/// what() would return "can't open file example.txt"
|
||||
|
||||
///
|
||||
#define DEF_EX_STR( exName, exDescription, exParent ) \
|
||||
class exName: public exParent \
|
||||
{ \
|
||||
std::string value; \
|
||||
\
|
||||
public: \
|
||||
explicit exName( std::string const & value_ ): \
|
||||
value( std::string( exDescription ) + " " + value_ ) \
|
||||
{ \
|
||||
} \
|
||||
virtual const char * what() const noexcept \
|
||||
{ \
|
||||
return value.c_str(); \
|
||||
} \
|
||||
virtual ~exName() noexcept {} \
|
||||
constexpr static char ExStr_## exName[] = exDescription; \
|
||||
using exName = defineExStr< exParent, ExStr_## exName >;
|
||||
|
||||
// clang-format on
|
||||
|
||||
template< typename ParentEx, const char * description >
|
||||
class defineEx: public ParentEx
|
||||
{
|
||||
public:
|
||||
virtual const char * what() const noexcept
|
||||
{
|
||||
return description;
|
||||
}
|
||||
};
|
||||
|
||||
template< typename ParentEx, const char * description >
|
||||
class defineExStr: public ParentEx
|
||||
{
|
||||
public:
|
||||
explicit defineExStr( std::string const & message_ ):
|
||||
message( fmt::format( "{} {}", description, message_ ) )
|
||||
{
|
||||
}
|
||||
virtual const char * what() const noexcept
|
||||
{
|
||||
return message.c_str();
|
||||
}
|
||||
|
||||
private:
|
||||
std::string message;
|
||||
};
|
||||
|
|
|
@ -201,6 +201,7 @@ Preferences::Preferences():
|
|||
doubleClickTranslates( true ),
|
||||
selectWordBySingleClick( false ),
|
||||
autoScrollToTargetArticle( true ),
|
||||
targetArticleAtFirst( false ),
|
||||
escKeyHidesMainWindow( false ),
|
||||
alwaysOnTop( false ),
|
||||
searchInDock( false ),
|
||||
|
@ -929,6 +930,11 @@ Class load()
|
|||
( preferences.namedItem( "autoScrollToTargetArticle" ).toElement().text() == "1" );
|
||||
}
|
||||
|
||||
if ( !preferences.namedItem( "targetArticleAtFirst" ).isNull() ) {
|
||||
c.preferences.targetArticleAtFirst =
|
||||
( preferences.namedItem( "targetArticleAtFirst" ).toElement().text() == "1" );
|
||||
}
|
||||
|
||||
if ( !preferences.namedItem( "escKeyHidesMainWindow" ).isNull() ) {
|
||||
c.preferences.escKeyHidesMainWindow =
|
||||
( preferences.namedItem( "escKeyHidesMainWindow" ).toElement().text() == "1" );
|
||||
|
@ -1866,6 +1872,10 @@ void save( Class const & c )
|
|||
opt.appendChild( dd.createTextNode( c.preferences.autoScrollToTargetArticle ? "1" : "0" ) );
|
||||
preferences.appendChild( opt );
|
||||
|
||||
opt = dd.createElement( "targetArticleAtFirst" );
|
||||
opt.appendChild( dd.createTextNode( c.preferences.targetArticleAtFirst ? "1" : "0" ) );
|
||||
preferences.appendChild( opt );
|
||||
|
||||
opt = dd.createElement( "escKeyHidesMainWindow" );
|
||||
opt.appendChild( dd.createTextNode( c.preferences.escKeyHidesMainWindow ? "1" : "0" ) );
|
||||
preferences.appendChild( opt );
|
||||
|
|
|
@ -356,6 +356,7 @@ struct Preferences
|
|||
bool doubleClickTranslates;
|
||||
bool selectWordBySingleClick;
|
||||
bool autoScrollToTargetArticle;
|
||||
bool targetArticleAtFirst;
|
||||
bool escKeyHidesMainWindow;
|
||||
bool alwaysOnTop;
|
||||
|
||||
|
|
|
@ -46,10 +46,6 @@ using BtreeIndexing::IndexInfo;
|
|||
|
||||
namespace {
|
||||
|
||||
DEF_EX_STR( exNotAardFile, "Not an AARD file", Dictionary::Ex )
|
||||
DEF_EX_STR( exWordIsTooLarge, "Enountered a word that is too large:", Dictionary::Ex )
|
||||
DEF_EX_STR( exSuddenEndOfFile, "Sudden end of file", Dictionary::Ex )
|
||||
|
||||
#pragma pack( push, 1 )
|
||||
|
||||
/// AAR file header
|
||||
|
|
|
@ -169,10 +169,6 @@ void addEntryToIndex( string & word,
|
|||
indexedWords.addWord( Utf8::decode( word ), articleOffset );
|
||||
}
|
||||
|
||||
|
||||
DEF_EX( exFailedToDecompressArticle, "Failed to decompress article's body", Dictionary::Ex )
|
||||
DEF_EX( exChunkIndexOutOfRange, "Chunk index is out of range", Dictionary::Ex )
|
||||
|
||||
class BglDictionary: public BtreeIndexing::BtreeDictionary
|
||||
{
|
||||
QMutex idxMutex;
|
||||
|
|
|
@ -301,7 +301,6 @@ namespace {
|
|||
////////////////// GLS Dictionary
|
||||
|
||||
using Dictionary::exCantReadFile;
|
||||
DEF_EX( exUserAbort, "User abort", Dictionary::Ex )
|
||||
DEF_EX_STR( exDictzipError, "DICTZIP error", Dictionary::Ex )
|
||||
|
||||
enum {
|
||||
|
|
|
@ -64,14 +64,11 @@ DEF_EX( exNotAnIfoFile, "Not an .ifo file", Dictionary::Ex )
|
|||
DEF_EX_STR( exBadFieldInIfo, "Bad field in .ifo file encountered:", Dictionary::Ex )
|
||||
DEF_EX_STR( exNoIdxFile, "No corresponding .idx file was found for", Dictionary::Ex )
|
||||
DEF_EX_STR( exNoDictFile, "No corresponding .dict file was found for", Dictionary::Ex )
|
||||
DEF_EX_STR( exNoSynFile, "No corresponding .syn file was found for", Dictionary::Ex )
|
||||
|
||||
DEF_EX( ex64BitsNotSupported, "64-bit indices are not presently supported, sorry", Dictionary::Ex )
|
||||
DEF_EX( exDicttypeNotSupported, "Dictionaries with dicttypes are not supported, sorry", Dictionary::Ex )
|
||||
|
||||
using Dictionary::exCantReadFile;
|
||||
DEF_EX_STR( exWordIsTooLarge, "Enountered a word that is too large:", Dictionary::Ex )
|
||||
DEF_EX_STR( exSuddenEndOfFile, "Sudden end of file", Dictionary::Ex )
|
||||
DEF_EX_STR( exDictzipError, "DICTZIP error", Dictionary::Ex )
|
||||
|
||||
DEF_EX_STR( exIncorrectOffset, "Incorrect offset encountered in file", Dictionary::Ex )
|
||||
|
|
|
@ -81,7 +81,6 @@ namespace {
|
|||
|
||||
using Dictionary::exCantReadFile;
|
||||
DEF_EX_STR( exNotXdxfFile, "The file is not an XDXF file:", Dictionary::Ex )
|
||||
DEF_EX( exCorruptedIndex, "The index file is corrupted", Dictionary::Ex )
|
||||
DEF_EX_STR( exDictzipError, "DICTZIP error", Dictionary::Ex )
|
||||
|
||||
enum {
|
||||
|
|
|
@ -30,8 +30,7 @@
|
|||
#endif
|
||||
|
||||
#ifdef Q_OS_MAC
|
||||
#define __SECURITYHI__
|
||||
#include <Carbon/Carbon.h>
|
||||
#import <Carbon/Carbon.h>
|
||||
#endif
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
|
|
@ -2,11 +2,13 @@
|
|||
* Part of GoldenDict. Licensed under GPLv3 or later, see the LICENSE file */
|
||||
|
||||
#include "hotkeywrapper.hh"
|
||||
#include <QTimer>
|
||||
#include <QMessageBox>
|
||||
#include <QPushButton>
|
||||
#include <QObject>
|
||||
#include <QPushButton>
|
||||
#include <QTimer>
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#import <Appkit/Appkit.h>
|
||||
|
||||
|
@ -23,84 +25,71 @@
|
|||
/// 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
|
||||
{
|
||||
struct ReverseMapEntry {
|
||||
UniChar character;
|
||||
UInt16 keyCode;
|
||||
};
|
||||
|
||||
static struct ReverseMapEntry * mapping;
|
||||
static int mapEntries = 0;
|
||||
static std::vector<ReverseMapEntry> mapping;
|
||||
|
||||
/// References:
|
||||
/// * https://github.com/libsdl-org/SDL/blob/fc12cc6dfd859a4e01376162a58f12208e539ac6/src/video/cocoa/SDL_cocoakeyboard.m#L345
|
||||
/// * https://github.com/qt/qtbase/blob/922369844fcb75386237bca3eef59edd5093f58d/src/gui/platform/darwin/qapplekeymapper.mm#L449
|
||||
///
|
||||
/// Known possible flaws 1) UCKeyTranslate doesn't handle modifiers at all 2) Handling keyboard switching
|
||||
void createMapping()
|
||||
{
|
||||
if( mapping == NULL )
|
||||
{
|
||||
TISInputSourceRef inputSourceRef = TISCopyInputSourceForLanguage( CFSTR( "en" ) );
|
||||
if ( !inputSourceRef ) {
|
||||
inputSourceRef = TISCopyCurrentKeyboardInputSource();
|
||||
}
|
||||
if (mapping.empty()) {
|
||||
mapping.reserve(128);
|
||||
|
||||
TISInputSourceRef inputSourceRef = TISCopyCurrentKeyboardLayoutInputSource();
|
||||
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<CFDataRef>((TISGetInputSourceProperty(inputSourceRef, kTISPropertyUnicodeKeyLayoutData)));
|
||||
if (!dataRef) {
|
||||
return;
|
||||
}
|
||||
CFDataRef uchrDataRef = (CFDataRef)TISGetInputSourceProperty(inputSourceRef, kTISPropertyUnicodeKeyLayoutData);
|
||||
|
||||
const UCKeyboardLayout* UCKeyboardLayoutPtr;
|
||||
|
||||
if (uchrDataRef) {
|
||||
UCKeyboardLayoutPtr = (const UCKeyboardLayout*)CFDataGetBytePtr(uchrDataRef);
|
||||
}
|
||||
|
||||
const UCKeyboardLayout * keyboardLayoutPtr = ( const UCKeyboardLayout * )CFDataGetBytePtr( dataRef );
|
||||
if( !keyboardLayoutPtr ) {
|
||||
if (!UCKeyboardLayoutPtr) {
|
||||
return;
|
||||
}
|
||||
|
||||
mapping = ( struct ReverseMapEntry * )calloc( 128 , sizeof(struct ReverseMapEntry) );
|
||||
if( !mapping ) {
|
||||
return;
|
||||
}
|
||||
|
||||
mapEntries = 0;
|
||||
|
||||
for( int i = 0; i < 128; i++ )
|
||||
{
|
||||
for (UInt16 i = 0; i < 128; i++) {
|
||||
UInt32 theDeadKeyState = 0;
|
||||
UniCharCount theLength = 0;
|
||||
if( UCKeyTranslate( keyboardLayoutPtr, i, kUCKeyActionDisplay, 0, LMGetKbdType(),
|
||||
UniChar temp_char_buf;
|
||||
if (UCKeyTranslate(UCKeyboardLayoutPtr, i, kUCKeyActionDown, 0, LMGetKbdType(),
|
||||
kUCKeyTranslateNoDeadKeysBit, &theDeadKeyState, 1, &theLength,
|
||||
&mapping[ mapEntries ].character ) == noErr && theLength > 0 )
|
||||
{
|
||||
if( isprint( mapping[ mapEntries ].character ) )
|
||||
{
|
||||
mapping[ mapEntries++ ].keyCode = i;
|
||||
&temp_char_buf)
|
||||
== noErr
|
||||
&& theLength > 0) {
|
||||
if (isprint(temp_char_buf)) {
|
||||
mapping.emplace_back(ReverseMapEntry { temp_char_buf, i });
|
||||
}
|
||||
}
|
||||
}
|
||||
mapping.shrink_to_fit();
|
||||
}
|
||||
}
|
||||
|
||||
quint32 qtKeyToNativeKey( quint32 key )
|
||||
quint32 qtKeyToNativeKey(UniChar key)
|
||||
{
|
||||
createMapping();
|
||||
if( mapping == NULL ) {
|
||||
if (mapping.empty()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
for( int i = 0; i < mapEntries; i++ )
|
||||
{
|
||||
if( mapping[ i ].character == key ) {
|
||||
return mapping[ i ].keyCode;
|
||||
for (auto& m : mapping) {
|
||||
if (m.character == key) {
|
||||
return m.keyCode;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -161,26 +150,20 @@ void checkAndRequestAccessibilityPermission()
|
|||
|
||||
void HotkeyWrapper::activated(int hkId)
|
||||
{
|
||||
if ( state2 )
|
||||
{ // wait for 2nd key
|
||||
if (state2) { // wait for 2nd key
|
||||
|
||||
waitKey2(); // Cancel the 2nd-key wait stage
|
||||
|
||||
if ( hkId == state2waiter.id + 1 ||
|
||||
( hkId == state2waiter.id && state2waiter.key == state2waiter.key2 ) )
|
||||
{
|
||||
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++ )
|
||||
{
|
||||
for (int i = 0; i < hotkeys.count(); i++) {
|
||||
HotkeyStruct& hs = hotkeys[i];
|
||||
if( hkId == hs.id )
|
||||
{
|
||||
if( hs.key == keyC && hs.modifier == cmdKey )
|
||||
{
|
||||
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
|
||||
|
@ -214,8 +197,7 @@ void HotkeyWrapper::activated( int hkId )
|
|||
|
||||
void HotkeyWrapper::unregister()
|
||||
{
|
||||
for ( int i = 0; i < hotkeys.count(); i++ )
|
||||
{
|
||||
for (int i = 0; i < hotkeys.count(); i++) {
|
||||
HotkeyStruct const& hk = hotkeys.at(i);
|
||||
|
||||
UnregisterEventHotKey(hk.hkRef);
|
||||
|
@ -279,8 +261,7 @@ bool HotkeyWrapper::setGlobalKey( int key, int key2, Qt::KeyboardModifiers modif
|
|||
return false;
|
||||
}
|
||||
|
||||
if ( vk2 && vk2 != vk )
|
||||
{
|
||||
if (vk2 && vk2 != vk) {
|
||||
hotKeyID.id = nextId + 1;
|
||||
ret = RegisterEventHotKey(vk2, mod, hotKeyID, GetApplicationEventTarget(), 0, &hk.hkRef2);
|
||||
}
|
||||
|
@ -293,41 +274,73 @@ bool HotkeyWrapper::setGlobalKey( int key, int key2, Qt::KeyboardModifiers modif
|
|||
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;
|
||||
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().unicode());
|
||||
}
|
||||
|
||||
void HotkeyWrapper::sendCmdC()
|
||||
|
|
|
@ -1,14 +1,5 @@
|
|||
#include "macmouseover.hh"
|
||||
#include <AppKit/NSTouch.h>
|
||||
#include <AppKit/NSEvent.h>
|
||||
#include <AppKit/NSScreen.h>
|
||||
#include <Foundation/NSAutoreleasePool.h>
|
||||
#include <Foundation/Foundation.h>
|
||||
|
||||
#ifndef AVAILABLE_MAC_OS_X_VERSION_10_11_AND_LATER
|
||||
#define kAXValueTypeCGPoint kAXValueCGPointType
|
||||
#define kAXValueTypeCFRange kAXValueCFRangeType
|
||||
#endif
|
||||
#import <AppKit/AppKit.h>
|
||||
|
||||
const int mouseOverInterval = 300;
|
||||
|
||||
|
@ -36,8 +27,7 @@ static CGPoint carbonScreenPointFromCocoaScreenPoint( NSPoint cocoaPoint )
|
|||
if (foundScreen) {
|
||||
CGFloat screenHeight = [foundScreen frame].size.height;
|
||||
thePoint = CGPointMake(cocoaPoint.x, screenHeight - cocoaPoint.y - 1);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
thePoint = CGPointMake(0.0, 0.0);
|
||||
}
|
||||
|
||||
|
@ -51,8 +41,8 @@ MacMouseOver & MacMouseOver::instance()
|
|||
return m;
|
||||
}
|
||||
|
||||
MacMouseOver::MacMouseOver() :
|
||||
pPref(NULL)
|
||||
MacMouseOver::MacMouseOver()
|
||||
: pPref(NULL)
|
||||
, tapRef(0)
|
||||
, loop(0)
|
||||
{
|
||||
|
@ -165,8 +155,7 @@ void MacMouseOver::handlePosition()
|
|||
return;
|
||||
}
|
||||
|
||||
for( ; ; )
|
||||
{
|
||||
for (;;) {
|
||||
CFTypeRef parameter = AXValueCreate(kAXValueTypeCGPoint, &pt);
|
||||
CFTypeRef rangeValue;
|
||||
err = AXUIElementCopyParameterizedAttributeNames(elem, &names);
|
||||
|
@ -175,8 +164,7 @@ void MacMouseOver::handlePosition()
|
|||
}
|
||||
|
||||
int numOfAttributes = CFArrayGetCount(names);
|
||||
if( CFArrayContainsValue( names, CFRangeMake( 0, numOfAttributes ), CFSTR( "AXRangeForPosition" ) ) )
|
||||
{
|
||||
if (CFArrayContainsValue(names, CFRangeMake(0, numOfAttributes), CFSTR("AXRangeForPosition"))) {
|
||||
// Standard interface
|
||||
err = AXUIElementCopyParameterizedAttributeValue(elem, kAXRangeForPositionParameterizedAttribute,
|
||||
parameter, (CFTypeRef*)&rangeValue);
|
||||
|
@ -190,8 +178,7 @@ void MacMouseOver::handlePosition()
|
|||
CFRange decodedRange = CFRangeMake(0, 0);
|
||||
bool b = AXValueGetValue((AXValueRef)rangeValue, kAXValueTypeCFRange, &decodedRange);
|
||||
CFRelease(rangeValue);
|
||||
if( b )
|
||||
{
|
||||
if (b) {
|
||||
int fromPos = decodedRange.location - 127;
|
||||
if (fromPos < 0) {
|
||||
fromPos = 0;
|
||||
|
@ -211,8 +198,7 @@ void MacMouseOver::handlePosition()
|
|||
CFRelease(stringValue);
|
||||
|
||||
// Read string further
|
||||
for( int i = 1; i < 128; i++ )
|
||||
{
|
||||
for (int i = 1; i < 128; i++) {
|
||||
range = CFRangeMake(decodedRange.location + i, 1);
|
||||
parameter = AXValueCreate(kAXValueTypeCFRange, &range);
|
||||
err = AXUIElementCopyParameterizedAttributeValue(elem, kAXStringForRangeParameterizedAttribute,
|
||||
|
@ -235,9 +221,7 @@ void MacMouseOver::handlePosition()
|
|||
|
||||
handleRetrievedString(strToTranslate, wordPos);
|
||||
}
|
||||
}
|
||||
else if( CFArrayContainsValue( names, CFRangeMake( 0, numOfAttributes ), CFSTR( "AXTextMarkerForPosition" ) ) )
|
||||
{
|
||||
} else if (CFArrayContainsValue(names, CFRangeMake(0, numOfAttributes), CFSTR("AXTextMarkerForPosition"))) {
|
||||
// Safari interface
|
||||
CFTypeRef marker, range;
|
||||
CFStringRef str;
|
||||
|
@ -258,8 +242,7 @@ void MacMouseOver::handlePosition()
|
|||
err = AXUIElementCopyParameterizedAttributeValue(elem, CFSTR("AXStringForTextMarkerRange"),
|
||||
range, (CFTypeRef*)&str);
|
||||
CFRelease(range);
|
||||
if( err == kAXErrorSuccess )
|
||||
{
|
||||
if (err == kAXErrorSuccess) {
|
||||
strToTranslate = CFStringRefToQString(str);
|
||||
CFRelease(str);
|
||||
handleRetrievedString(strToTranslate, 0);
|
||||
|
@ -286,14 +269,10 @@ void MacMouseOver::handleRetrievedString( QString & wordSeq, int wordSeqPos )
|
|||
|
||||
QString word;
|
||||
|
||||
if ( wordSeq[ wordSeqPos ].isSpace() )
|
||||
{
|
||||
if (wordSeq[wordSeqPos].isSpace()) {
|
||||
// Currently we ignore such cases
|
||||
return;
|
||||
}
|
||||
else
|
||||
if ( !wordSeq[ wordSeqPos ].isLetterOrNumber() )
|
||||
{
|
||||
} 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.
|
||||
|
@ -314,16 +293,13 @@ void MacMouseOver::handleRetrievedString( QString & wordSeq, int wordSeqPos )
|
|||
}
|
||||
}
|
||||
|
||||
if ( end - begin == 1 )
|
||||
{
|
||||
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
|
||||
{
|
||||
} else {
|
||||
// Cursor points to a letter -- cut the word it points to
|
||||
|
||||
int begin = wordSeqPos;
|
||||
|
@ -336,8 +312,7 @@ void MacMouseOver::handleRetrievedString( QString & wordSeq, int wordSeqPos )
|
|||
|
||||
int end = wordSeqPos;
|
||||
|
||||
while( ++end < wordSeq.size() )
|
||||
{
|
||||
while (++end < wordSeq.size()) {
|
||||
if (!wordSeq[end].isLetterOrNumber()) {
|
||||
break;
|
||||
}
|
||||
|
@ -347,13 +322,10 @@ void MacMouseOver::handleRetrievedString( QString & wordSeq, int wordSeqPos )
|
|||
|
||||
// See if we have an RTL char. Reverse the whole string if we do.
|
||||
|
||||
for( int x = 0; x < word.size(); ++x )
|
||||
{
|
||||
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 )
|
||||
{
|
||||
if (d == QChar::DirR || d == QChar::DirAL || d == QChar::DirRLE || d == QChar::DirRLO) {
|
||||
std::reverse(word.begin(), word.end());
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -185,6 +185,7 @@ Preferences::Preferences( QWidget * parent, Config::Class & cfg_ ):
|
|||
ui.doubleClickTranslates->setChecked( p.doubleClickTranslates );
|
||||
ui.selectBySingleClick->setChecked( p.selectWordBySingleClick );
|
||||
ui.autoScrollToTargetArticle->setChecked( p.autoScrollToTargetArticle );
|
||||
ui.targetArticleAtFirst->setChecked( p.targetArticleAtFirst );
|
||||
ui.escKeyHidesMainWindow->setChecked( p.escKeyHidesMainWindow );
|
||||
|
||||
ui.darkMode->addItem( tr( "On" ), QVariant::fromValue( Config::Dark::On ) );
|
||||
|
@ -441,6 +442,7 @@ Config::Preferences Preferences::getPreferences()
|
|||
p.doubleClickTranslates = ui.doubleClickTranslates->isChecked();
|
||||
p.selectWordBySingleClick = ui.selectBySingleClick->isChecked();
|
||||
p.autoScrollToTargetArticle = ui.autoScrollToTargetArticle->isChecked();
|
||||
p.targetArticleAtFirst = ui.targetArticleAtFirst->isChecked();
|
||||
p.escKeyHidesMainWindow = ui.escKeyHidesMainWindow->isChecked();
|
||||
|
||||
p.darkMode = ui.darkMode->currentData().value< Config::Dark >();
|
||||
|
|
|
@ -169,6 +169,16 @@ however, the article from the topmost dictionary is shown.</string>
|
|||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="1">
|
||||
<widget class="QCheckBox" name="targetArticleAtFirst">
|
||||
<property name="text">
|
||||
<string>Place the target article at the first place.</string>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QGroupBox" name="enableTrayIcon">
|
||||
<property name="toolTip">
|
||||
|
|
Loading…
Reference in a new issue