mirror of
https://github.com/xiaoyifang/goldendict-ng.git
synced 2024-11-23 20:14:05 +00:00
Compare commits
28 commits
ecb90c86ce
...
1bd4bf58e3
Author | SHA1 | Date | |
---|---|---|---|
1bd4bf58e3 | |||
c5d682c993 | |||
0f71f32ad4 | |||
5cc43a3dc8 | |||
beef6dd138 | |||
ccf70cdfb6 | |||
6865b02547 | |||
fbec70e41a | |||
20fcea33e1 | |||
9db5867ce8 | |||
c8af0450f1 | |||
453948155a | |||
8fc71c9586 | |||
8fd5b37335 | |||
4758f9e972 | |||
608016208b | |||
1e3b22ebd0 | |||
3c5233f2a1 | |||
c5ca1b7d63 | |||
5092ebe2ee | |||
5bef4cef22 | |||
59d01868da | |||
10b0496cce | |||
1cf495e7dd | |||
c2fc90801b | |||
2de2141758 | |||
db4c352d6c | |||
7c32cad65a |
|
@ -142,4 +142,7 @@ StatementMacros:
|
||||||
- QT_REQUIRE_VERSION
|
- QT_REQUIRE_VERSION
|
||||||
UseCRLF: false
|
UseCRLF: false
|
||||||
UseTab: Never
|
UseTab: Never
|
||||||
|
---
|
||||||
|
Language: ObjC
|
||||||
|
BasedOnStyle: WebKit
|
||||||
...
|
...
|
||||||
|
|
|
@ -17,7 +17,6 @@ Checks: >
|
||||||
portability-*,
|
portability-*,
|
||||||
readability-*,
|
readability-*,
|
||||||
-bugprone-easily-swappable-parameters,
|
-bugprone-easily-swappable-parameters,
|
||||||
-bugprone-reserved-identifier,
|
|
||||||
-cppcoreguidelines-owning-memory,
|
-cppcoreguidelines-owning-memory,
|
||||||
-cppcoreguidelines-prefer-member-initializer,
|
-cppcoreguidelines-prefer-member-initializer,
|
||||||
-cppcoreguidelines-pro-bounds-array-to-pointer-decay,
|
-cppcoreguidelines-pro-bounds-array-to-pointer-decay,
|
||||||
|
@ -44,5 +43,11 @@ CheckOptions:
|
||||||
value: 1
|
value: 1
|
||||||
- key: cppcoreguidelines-explicit-virtual-functions.IgnoreDestructors
|
- key: cppcoreguidelines-explicit-virtual-functions.IgnoreDestructors
|
||||||
value: 1
|
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
|
||||||
...
|
...
|
||||||
|
|
||||||
|
|
|
@ -15,3 +15,6 @@ a11c9e3aeca4329e1982d8fe26bacbb21ab50ddf
|
||||||
|
|
||||||
# mass apply clang-tidy's modernize-use-using
|
# mass apply clang-tidy's modernize-use-using
|
||||||
d15081e723756eef053550dc9e06e31d7828dec3
|
d15081e723756eef053550dc9e06e31d7828dec3
|
||||||
|
|
||||||
|
# remove gd::toWString
|
||||||
|
c8af0450f1f7f8188004db96e3f53e7e33e2ccad
|
|
@ -521,7 +521,7 @@ void ArticleRequest::altSearchFinished()
|
||||||
|
|
||||||
vector< wstring > altsVector( alts.begin(), alts.end() );
|
vector< wstring > altsVector( alts.begin(), alts.end() );
|
||||||
|
|
||||||
wstring wordStd = gd::toWString( word );
|
wstring wordStd = word.toStdU32String();
|
||||||
|
|
||||||
if ( activeDicts.size() <= 1 ) {
|
if ( activeDicts.size() <= 1 ) {
|
||||||
articleSizeLimit = -1; // Don't collapse article if only one dictionary presented
|
articleSizeLimit = -1; // Don't collapse article if only one dictionary presented
|
||||||
|
|
|
@ -6,11 +6,7 @@
|
||||||
#include <QWaitCondition>
|
#include <QWaitCondition>
|
||||||
#include <QCoreApplication>
|
#include <QCoreApplication>
|
||||||
#include <QThreadPool>
|
#include <QThreadPool>
|
||||||
#if QT_VERSION < QT_VERSION_CHECK( 6, 0, 0 )
|
#include <QAudioSink>
|
||||||
#include <QAudioOutput>
|
|
||||||
#else
|
|
||||||
#include <QAudioSink>
|
|
||||||
#endif
|
|
||||||
#include <QtGlobal>
|
#include <QtGlobal>
|
||||||
#include <QBuffer>
|
#include <QBuffer>
|
||||||
|
|
||||||
|
@ -23,18 +19,7 @@ static QAudioFormat format( int sampleRate, int channelCount )
|
||||||
|
|
||||||
out.setSampleRate( sampleRate );
|
out.setSampleRate( sampleRate );
|
||||||
out.setChannelCount( channelCount );
|
out.setChannelCount( channelCount );
|
||||||
#if QT_VERSION < QT_VERSION_CHECK( 6, 0, 0 )
|
|
||||||
out.setByteOrder( QAudioFormat::LittleEndian );
|
|
||||||
out.setCodec( QLatin1String( "audio/pcm" ) );
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if QT_VERSION < QT_VERSION_CHECK( 6, 0, 0 )
|
|
||||||
out.setSampleSize( 16 );
|
|
||||||
out.setSampleType( QAudioFormat::SignedInt );
|
|
||||||
#else
|
|
||||||
out.setSampleFormat( QAudioFormat::Int16 );
|
out.setSampleFormat( QAudioFormat::Int16 );
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
@ -50,11 +35,8 @@ public:
|
||||||
|
|
||||||
QFuture< void > audioPlayFuture;
|
QFuture< void > audioPlayFuture;
|
||||||
|
|
||||||
#if QT_VERSION < QT_VERSION_CHECK( 6, 0, 0 )
|
|
||||||
using AudioOutput = QAudioOutput;
|
|
||||||
#else
|
|
||||||
using AudioOutput = QAudioSink;
|
using AudioOutput = QAudioSink;
|
||||||
#endif
|
|
||||||
AudioOutput * audioOutput = nullptr;
|
AudioOutput * audioOutput = nullptr;
|
||||||
QByteArray buffer;
|
QByteArray buffer;
|
||||||
qint64 offset = 0;
|
qint64 offset = 0;
|
||||||
|
@ -185,11 +167,7 @@ AudioOutput::AudioOutput( QObject * parent ):
|
||||||
QObject( parent ),
|
QObject( parent ),
|
||||||
d_ptr( new AudioOutputPrivate )
|
d_ptr( new AudioOutputPrivate )
|
||||||
{
|
{
|
||||||
#if QT_VERSION < QT_VERSION_CHECK( 6, 0, 0 )
|
|
||||||
d_ptr->audioPlayFuture = QtConcurrent::run( &d_ptr->threadPool, d_ptr.data(), &AudioOutputPrivate::doPlayAudio );
|
|
||||||
#else
|
|
||||||
d_ptr->audioPlayFuture = QtConcurrent::run( &d_ptr->threadPool, &AudioOutputPrivate::doPlayAudio, d_ptr.data() );
|
d_ptr->audioPlayFuture = QtConcurrent::run( &d_ptr->threadPool, &AudioOutputPrivate::doPlayAudio, d_ptr.data() );
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudioOutput::setAudioFormat( int sampleRate, int channels )
|
void AudioOutput::setAudioFormat( int sampleRate, int channels )
|
||||||
|
|
|
@ -2,27 +2,14 @@
|
||||||
|
|
||||||
#include "audiooutput.hh"
|
#include "audiooutput.hh"
|
||||||
#include "ffmpegaudio.hh"
|
#include "ffmpegaudio.hh"
|
||||||
|
|
||||||
#include <errno.h>
|
|
||||||
|
|
||||||
extern "C" {
|
|
||||||
#include <libavcodec/avcodec.h>
|
|
||||||
#include <libavformat/avformat.h>
|
|
||||||
#include <libavutil/avutil.h>
|
|
||||||
#include "libswresample/swresample.h"
|
|
||||||
}
|
|
||||||
|
|
||||||
#include <QString>
|
|
||||||
#include <QDataStream>
|
|
||||||
|
|
||||||
#include <vector>
|
|
||||||
#if ( QT_VERSION >= QT_VERSION_CHECK( 6, 2, 0 ) )
|
|
||||||
#include <QMediaDevices>
|
|
||||||
|
|
||||||
#include <QAudioDevice>
|
|
||||||
#endif
|
|
||||||
#include "gddebug.hh"
|
#include "gddebug.hh"
|
||||||
#include "utils.hh"
|
#include "utils.hh"
|
||||||
|
#include <QAudioDevice>
|
||||||
|
#include <QDataStream>
|
||||||
|
#include <QMediaDevices>
|
||||||
|
#include <QString>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
using std::vector;
|
using std::vector;
|
||||||
|
|
||||||
|
@ -284,14 +271,11 @@ void DecoderContext::closeCodec()
|
||||||
|
|
||||||
bool DecoderContext::openOutputDevice( QString & errorString )
|
bool DecoderContext::openOutputDevice( QString & errorString )
|
||||||
{
|
{
|
||||||
// only check device when qt version is greater than 6.2
|
|
||||||
#if ( QT_VERSION >= QT_VERSION_CHECK( 6, 2, 0 ) )
|
|
||||||
QAudioDevice m_outputDevice = QMediaDevices::defaultAudioOutput();
|
QAudioDevice m_outputDevice = QMediaDevices::defaultAudioOutput();
|
||||||
if ( m_outputDevice.isNull() ) {
|
if ( m_outputDevice.isNull() ) {
|
||||||
errorString += QString( "Can not found default audio output device" );
|
errorString += QString( "Can not found default audio output device" );
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
if ( audioOutput == nullptr ) {
|
if ( audioOutput == nullptr ) {
|
||||||
errorString += QStringLiteral( "Failed to create audioOutput." );
|
errorString += QStringLiteral( "Failed to create audioOutput." );
|
||||||
|
|
|
@ -1,27 +1,24 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#ifdef MAKE_FFMPEG_PLAYER
|
#ifdef MAKE_FFMPEG_PLAYER
|
||||||
#include "audiooutput.hh"
|
|
||||||
#include <QObject>
|
|
||||||
#include <QMutex>
|
|
||||||
#include <QByteArray>
|
|
||||||
#include <QThread>
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#include <libavcodec/avcodec.h>
|
#include <libavcodec/avcodec.h>
|
||||||
#include <libavformat/avformat.h>
|
#include <libavformat/avformat.h>
|
||||||
#include <libavutil/avutil.h>
|
#include <libavutil/avutil.h>
|
||||||
#include "libswresample/swresample.h"
|
#include "libswresample/swresample.h"
|
||||||
}
|
}
|
||||||
|
#include "audiooutput.hh"
|
||||||
#include <QString>
|
#include <QObject>
|
||||||
|
#include <QMutex>
|
||||||
|
#include <QByteArray>
|
||||||
|
#include <QThread>
|
||||||
|
#include <QAudioDevice>
|
||||||
#include <QDataStream>
|
#include <QDataStream>
|
||||||
|
#include <QMediaDevices>
|
||||||
|
#include <QString>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#if ( QT_VERSION >= QT_VERSION_CHECK( 6, 2, 0 ) )
|
|
||||||
#include <QMediaDevices>
|
|
||||||
|
|
||||||
#include <QAudioDevice>
|
|
||||||
#endif
|
|
||||||
using std::vector;
|
using std::vector;
|
||||||
namespace Ffmpeg {
|
namespace Ffmpeg {
|
||||||
class DecoderThread;
|
class DecoderThread;
|
||||||
|
|
|
@ -4,29 +4,18 @@
|
||||||
#ifdef MAKE_QTMULTIMEDIA_PLAYER
|
#ifdef MAKE_QTMULTIMEDIA_PLAYER
|
||||||
|
|
||||||
#include <QByteArray>
|
#include <QByteArray>
|
||||||
#if ( QT_VERSION < QT_VERSION_CHECK( 6, 0, 0 ) )
|
#include <QAudioDevice>
|
||||||
#include <QMediaContent>
|
|
||||||
#endif
|
|
||||||
#if ( QT_VERSION > QT_VERSION_CHECK( 6, 2, 0 ) )
|
|
||||||
#include <QAudioDevice>
|
|
||||||
#endif
|
|
||||||
#include "multimediaaudioplayer.hh"
|
#include "multimediaaudioplayer.hh"
|
||||||
|
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
|
|
||||||
MultimediaAudioPlayer::MultimediaAudioPlayer()
|
MultimediaAudioPlayer::MultimediaAudioPlayer()
|
||||||
#if ( QT_VERSION < QT_VERSION_CHECK( 6, 0, 0 ) )
|
|
||||||
:
|
|
||||||
player( 0, QMediaPlayer::StreamPlayback )
|
|
||||||
#endif
|
|
||||||
{
|
{
|
||||||
player.setAudioOutput( &audioOutput );
|
player.setAudioOutput( &audioOutput );
|
||||||
|
|
||||||
connect( &player, &QMediaPlayer::errorChanged, this, &MultimediaAudioPlayer::onMediaPlayerError );
|
connect( &player, &QMediaPlayer::errorChanged, this, &MultimediaAudioPlayer::onMediaPlayerError );
|
||||||
|
|
||||||
#if ( QT_VERSION > QT_VERSION_CHECK( 6, 2, 0 ) )
|
|
||||||
connect( &mediaDevices, &QMediaDevices::audioOutputsChanged, this, &MultimediaAudioPlayer::audioOutputChange );
|
connect( &mediaDevices, &QMediaDevices::audioOutputsChanged, this, &MultimediaAudioPlayer::audioOutputChange );
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MultimediaAudioPlayer::audioOutputChange()
|
void MultimediaAudioPlayer::audioOutputChange()
|
||||||
|
@ -42,15 +31,11 @@ QString MultimediaAudioPlayer::play( const char * data, int size )
|
||||||
if ( !audioBuffer->open( QIODevice::ReadOnly ) ) {
|
if ( !audioBuffer->open( QIODevice::ReadOnly ) ) {
|
||||||
return tr( "Couldn't open audio buffer for reading." );
|
return tr( "Couldn't open audio buffer for reading." );
|
||||||
}
|
}
|
||||||
#if ( QT_VERSION >= QT_VERSION_CHECK( 6, 0, 0 ) )
|
|
||||||
player.setSourceDevice( audioBuffer );
|
player.setSourceDevice( audioBuffer );
|
||||||
#if ( QT_VERSION > QT_VERSION_CHECK( 6, 2, 0 ) )
|
|
||||||
audioOutput.setDevice( QMediaDevices::defaultAudioOutput() );
|
audioOutput.setDevice( QMediaDevices::defaultAudioOutput() );
|
||||||
player.setAudioOutput( &audioOutput );
|
player.setAudioOutput( &audioOutput );
|
||||||
#endif
|
|
||||||
#else
|
|
||||||
player.setMedia( QMediaContent(), audioBuffer );
|
|
||||||
#endif
|
|
||||||
player.play();
|
player.play();
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
@ -58,9 +43,7 @@ QString MultimediaAudioPlayer::play( const char * data, int size )
|
||||||
void MultimediaAudioPlayer::stop()
|
void MultimediaAudioPlayer::stop()
|
||||||
{
|
{
|
||||||
player.stop();
|
player.stop();
|
||||||
#if ( QT_VERSION < QT_VERSION_CHECK( 6, 0, 0 ) )
|
|
||||||
player.setMedia( QMediaContent() ); // Forget about audioBuffer.
|
|
||||||
#endif
|
|
||||||
if ( audioBuffer ) {
|
if ( audioBuffer ) {
|
||||||
audioBuffer->close();
|
audioBuffer->close();
|
||||||
audioBuffer->setData( QByteArray() ); // Free memory.
|
audioBuffer->setData( QByteArray() ); // Free memory.
|
||||||
|
|
|
@ -5,15 +5,11 @@
|
||||||
|
|
||||||
#ifdef MAKE_QTMULTIMEDIA_PLAYER
|
#ifdef MAKE_QTMULTIMEDIA_PLAYER
|
||||||
|
|
||||||
#include <QBuffer>
|
|
||||||
#include <QMediaPlayer>
|
|
||||||
#include "audioplayerinterface.hh"
|
#include "audioplayerinterface.hh"
|
||||||
#if ( QT_VERSION >= QT_VERSION_CHECK( 6, 0, 0 ) )
|
#include <QAudioOutput>
|
||||||
#include <QAudioOutput>
|
#include <QBuffer>
|
||||||
#endif
|
#include <QMediaDevices>
|
||||||
#if ( QT_VERSION >= QT_VERSION_CHECK( 6, 2, 0 ) )
|
#include <QMediaPlayer>
|
||||||
#include <QMediaDevices>
|
|
||||||
#endif
|
|
||||||
#include <QPointer>
|
#include <QPointer>
|
||||||
|
|
||||||
class MultimediaAudioPlayer: public AudioPlayerInterface
|
class MultimediaAudioPlayer: public AudioPlayerInterface
|
||||||
|
@ -34,12 +30,8 @@ private slots:
|
||||||
private:
|
private:
|
||||||
QPointer< QBuffer > audioBuffer;
|
QPointer< QBuffer > audioBuffer;
|
||||||
QMediaPlayer player; ///< Depends on audioBuffer.
|
QMediaPlayer player; ///< Depends on audioBuffer.
|
||||||
#if ( QT_VERSION >= QT_VERSION_CHECK( 6, 2, 0 ) )
|
|
||||||
QAudioOutput audioOutput;
|
QAudioOutput audioOutput;
|
||||||
#endif
|
|
||||||
#if ( QT_VERSION >= QT_VERSION_CHECK( 6, 2, 0 ) )
|
|
||||||
QMediaDevices mediaDevices;
|
QMediaDevices mediaDevices;
|
||||||
#endif
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // MAKE_QTMULTIMEDIA_PLAYER
|
#endif // MAKE_QTMULTIMEDIA_PLAYER
|
||||||
|
|
|
@ -4,22 +4,17 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <fmt/format.h>
|
||||||
|
|
||||||
|
// clang-format off
|
||||||
|
|
||||||
/// A way to declare an exception class fast
|
/// A way to declare an exception class fast
|
||||||
/// Do like this:
|
/// Do like this:
|
||||||
/// DEF_EX( exErrorInFoo, "An error in foo encountered", std::exception )
|
/// DEF_EX( exErrorInFoo, "An error in foo encountered", std::exception )
|
||||||
/// DEF_EX( exFooNotFound, "Foo was not found", exErrorInFoo )
|
/// DEF_EX( exFooNotFound, "Foo was not found", exErrorInFoo )
|
||||||
|
#define DEF_EX( exName, exDescription, exParent ) \
|
||||||
#define DEF_EX( exName, exDescription, exParent ) \
|
constexpr static char ExStr_## exName[] = exDescription; \
|
||||||
class exName: public exParent \
|
using exName = defineEx< exParent, ExStr_## exName >;
|
||||||
{ \
|
|
||||||
public: \
|
|
||||||
virtual const char * what() const noexcept \
|
|
||||||
{ \
|
|
||||||
return ( exDescription ); \
|
|
||||||
} \
|
|
||||||
virtual ~exName() noexcept {} \
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Same as DEF_EX, but takes a runtime string argument, which gets concatenated
|
/// Same as DEF_EX, but takes a runtime string argument, which gets concatenated
|
||||||
/// with the description.
|
/// with the description.
|
||||||
|
@ -29,20 +24,36 @@
|
||||||
/// throw exCantOpen( "example.txt" );
|
/// throw exCantOpen( "example.txt" );
|
||||||
///
|
///
|
||||||
/// what() would return "can't open file example.txt"
|
/// what() would return "can't open file example.txt"
|
||||||
|
///
|
||||||
|
#define DEF_EX_STR( exName, exDescription, exParent ) \
|
||||||
|
constexpr static char ExStr_## exName[] = exDescription; \
|
||||||
|
using exName = defineExStr< exParent, ExStr_## exName >;
|
||||||
|
|
||||||
#define DEF_EX_STR( exName, exDescription, exParent ) \
|
// clang-format on
|
||||||
class exName: public exParent \
|
|
||||||
{ \
|
template< typename ParentEx, const char * description >
|
||||||
std::string value; \
|
class defineEx: public ParentEx
|
||||||
\
|
{
|
||||||
public: \
|
public:
|
||||||
explicit exName( std::string const & value_ ): \
|
virtual const char * what() const noexcept
|
||||||
value( std::string( exDescription ) + " " + value_ ) \
|
{
|
||||||
{ \
|
return description;
|
||||||
} \
|
}
|
||||||
virtual const char * what() const noexcept \
|
};
|
||||||
{ \
|
|
||||||
return value.c_str(); \
|
template< typename ParentEx, const char * description >
|
||||||
} \
|
class defineExStr: public ParentEx
|
||||||
virtual ~exName() noexcept {} \
|
{
|
||||||
};
|
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;
|
||||||
|
};
|
||||||
|
|
|
@ -20,41 +20,23 @@ bool isCombiningMark( wchar ch )
|
||||||
|
|
||||||
wstring apply( wstring const & in, bool preserveWildcards )
|
wstring apply( wstring const & in, bool preserveWildcards )
|
||||||
{
|
{
|
||||||
//remove space and accent;
|
// remove diacritics (normalization), white space, punt,
|
||||||
auto withPunc = QString::fromStdU32String( in )
|
auto temp = QString::fromStdU32String( in )
|
||||||
.normalized( QString::NormalizationForm_KD )
|
.normalized( QString::NormalizationForm_KD )
|
||||||
.remove( RX::markSpace )
|
.remove( RX::markSpace )
|
||||||
.toStdU32String();
|
.removeIf( [ preserveWildcards ]( const QChar & ch ) -> bool {
|
||||||
|
return ch.isPunct()
|
||||||
//First, strip diacritics and apply ws/punctuation removal
|
&& !( preserveWildcards && ( ch == '\\' || ch == '?' || ch == '*' || ch == '[' || ch == ']' ) );
|
||||||
wstring withoutDiacritics;
|
} )
|
||||||
|
.toStdU32String();
|
||||||
withoutDiacritics.reserve( withPunc.size() );
|
// case folding
|
||||||
|
std::u32string caseFolded;
|
||||||
|
caseFolded.reserve( temp.size() );
|
||||||
for ( auto const & ch : withPunc ) {
|
|
||||||
|
|
||||||
if ( !isPunct( ch )
|
|
||||||
|| ( preserveWildcards && ( ch == '\\' || ch == '?' || ch == '*' || ch == '[' || ch == ']' ) ) ) {
|
|
||||||
withoutDiacritics.push_back( ch );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Now, fold the case
|
|
||||||
|
|
||||||
wstring caseFolded;
|
|
||||||
|
|
||||||
caseFolded.reserve( withoutDiacritics.size() * foldCaseMaxOut );
|
|
||||||
|
|
||||||
wchar const * nextChar = withoutDiacritics.data();
|
|
||||||
|
|
||||||
wchar buf[ foldCaseMaxOut ];
|
wchar buf[ foldCaseMaxOut ];
|
||||||
|
for ( const char32_t ch : temp ) {
|
||||||
for ( size_t left = withoutDiacritics.size(); left--; ) {
|
auto n = foldCase( ch, buf );
|
||||||
caseFolded.append( buf, foldCase( *nextChar++, buf ) );
|
caseFolded.append( buf, n );
|
||||||
}
|
}
|
||||||
|
|
||||||
return caseFolded;
|
return caseFolded;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,14 +1,10 @@
|
||||||
/* This file is (c) 2013 Abs62
|
/* This file is (c) 2013 Abs62
|
||||||
* Part of GoldenDict. Licensed under GPLv3 or later, see the LICENSE file */
|
* Part of GoldenDict. Licensed under GPLv3 or later, see the LICENSE file */
|
||||||
|
|
||||||
#include <QString>
|
|
||||||
#include "gddebug.hh"
|
#include "gddebug.hh"
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
#if ( QT_VERSION >= QT_VERSION_CHECK( 6, 0, 0 ) )
|
#include <QString>
|
||||||
#include <QtCore5Compat/QTextCodec>
|
#include <QtCore5Compat/QTextCodec>
|
||||||
#else
|
|
||||||
#include <QTextCodec>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
QFile * logFilePtr;
|
QFile * logFilePtr;
|
||||||
|
|
||||||
|
|
|
@ -93,7 +93,7 @@ gd::wstring Iconv::toWstring( char const * fromEncoding, void const * fromData,
|
||||||
Iconv ic( fromEncoding );
|
Iconv ic( fromEncoding );
|
||||||
|
|
||||||
QString outStr = ic.convert( fromData, dataSize );
|
QString outStr = ic.convert( fromData, dataSize );
|
||||||
return gd::toWString( outStr );
|
return outStr.toStdU32String();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string Iconv::toUtf8( char const * fromEncoding, void const * fromData, size_t dataSize )
|
std::string Iconv::toUtf8( char const * fromEncoding, void const * fromData, size_t dataSize )
|
||||||
|
|
|
@ -9,11 +9,6 @@
|
||||||
|
|
||||||
QString wildcardsToRegexp( const QString & wc_str )
|
QString wildcardsToRegexp( const QString & wc_str )
|
||||||
{
|
{
|
||||||
#if QT_VERSION < QT_VERSION_CHECK( 6, 0, 0 )
|
// The "anchored" version will enclose the output with \A...\z.
|
||||||
//qt 5.X does not offer an unanchored version. the default output is enclosed between \A \z.
|
|
||||||
auto anchorPattern = QRegularExpression::wildcardToRegularExpression( wc_str );
|
|
||||||
return anchorPattern.mid( 2, anchorPattern.length() - 4 );
|
|
||||||
#else
|
|
||||||
return QRegularExpression::wildcardToRegularExpression( wc_str, QRegularExpression::UnanchoredWildcardConversion );
|
return QRegularExpression::wildcardToRegularExpression( wc_str, QRegularExpression::UnanchoredWildcardConversion );
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,10 +2,6 @@
|
||||||
#include <QList>
|
#include <QList>
|
||||||
|
|
||||||
namespace gd {
|
namespace gd {
|
||||||
wstring toWString( QString const & in )
|
|
||||||
{
|
|
||||||
return in.toStdU32String();
|
|
||||||
}
|
|
||||||
|
|
||||||
// When convert non-BMP characters to wstring,the ending char maybe \0 .This method remove the tailing \0 from the wstring
|
// When convert non-BMP characters to wstring,the ending char maybe \0 .This method remove the tailing \0 from the wstring
|
||||||
// as \0 is sensitive in the index. This method will be only used with index related operations like store/query.
|
// as \0 is sensitive in the index. This method will be only used with index related operations like store/query.
|
||||||
|
@ -35,7 +31,7 @@ wstring removeTrailingZero( QString const & in )
|
||||||
|
|
||||||
wstring normalize( const wstring & str )
|
wstring normalize( const wstring & str )
|
||||||
{
|
{
|
||||||
return toWString( QString::fromStdU32String( str ).normalized( QString::NormalizationForm_C ) );
|
return QString::fromStdU32String( str ).normalized( QString::NormalizationForm_C ).toStdU32String();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -10,7 +10,6 @@
|
||||||
#include <QString>
|
#include <QString>
|
||||||
|
|
||||||
namespace gd {
|
namespace gd {
|
||||||
wstring toWString( QString const & );
|
|
||||||
wstring removeTrailingZero( wstring const & v );
|
wstring removeTrailingZero( wstring const & v );
|
||||||
wstring removeTrailingZero( QString const & in );
|
wstring removeTrailingZero( QString const & in );
|
||||||
wstring normalize( wstring const & );
|
wstring normalize( wstring const & );
|
||||||
|
|
|
@ -197,9 +197,6 @@ Preferences::Preferences():
|
||||||
hideSingleTab( false ),
|
hideSingleTab( false ),
|
||||||
mruTabOrder( false ),
|
mruTabOrder( false ),
|
||||||
hideMenubar( false ),
|
hideMenubar( false ),
|
||||||
enableTrayIcon( true ),
|
|
||||||
startToTray( false ),
|
|
||||||
closeToTray( true ),
|
|
||||||
autoStart( false ),
|
autoStart( false ),
|
||||||
doubleClickTranslates( true ),
|
doubleClickTranslates( true ),
|
||||||
selectWordBySingleClick( false ),
|
selectWordBySingleClick( false ),
|
||||||
|
@ -903,10 +900,11 @@ Class load()
|
||||||
c.preferences.hideSingleTab = ( preferences.namedItem( "hideSingleTab" ).toElement().text() == "1" );
|
c.preferences.hideSingleTab = ( preferences.namedItem( "hideSingleTab" ).toElement().text() == "1" );
|
||||||
c.preferences.mruTabOrder = ( preferences.namedItem( "mruTabOrder" ).toElement().text() == "1" );
|
c.preferences.mruTabOrder = ( preferences.namedItem( "mruTabOrder" ).toElement().text() == "1" );
|
||||||
c.preferences.hideMenubar = ( preferences.namedItem( "hideMenubar" ).toElement().text() == "1" );
|
c.preferences.hideMenubar = ( preferences.namedItem( "hideMenubar" ).toElement().text() == "1" );
|
||||||
|
#ifndef Q_OS_MACOS // // macOS uses the dock menu instead of the tray icon
|
||||||
c.preferences.enableTrayIcon = ( preferences.namedItem( "enableTrayIcon" ).toElement().text() == "1" );
|
c.preferences.enableTrayIcon = ( preferences.namedItem( "enableTrayIcon" ).toElement().text() == "1" );
|
||||||
c.preferences.startToTray = ( preferences.namedItem( "startToTray" ).toElement().text() == "1" );
|
c.preferences.startToTray = ( preferences.namedItem( "startToTray" ).toElement().text() == "1" );
|
||||||
c.preferences.closeToTray = ( preferences.namedItem( "closeToTray" ).toElement().text() == "1" );
|
c.preferences.closeToTray = ( preferences.namedItem( "closeToTray" ).toElement().text() == "1" );
|
||||||
|
#endif
|
||||||
c.preferences.autoStart = ( preferences.namedItem( "autoStart" ).toElement().text() == "1" );
|
c.preferences.autoStart = ( preferences.namedItem( "autoStart" ).toElement().text() == "1" );
|
||||||
c.preferences.alwaysOnTop = ( preferences.namedItem( "alwaysOnTop" ).toElement().text() == "1" );
|
c.preferences.alwaysOnTop = ( preferences.namedItem( "alwaysOnTop" ).toElement().text() == "1" );
|
||||||
c.preferences.searchInDock = ( preferences.namedItem( "searchInDock" ).toElement().text() == "1" );
|
c.preferences.searchInDock = ( preferences.namedItem( "searchInDock" ).toElement().text() == "1" );
|
||||||
|
|
|
@ -341,9 +341,17 @@ struct Preferences
|
||||||
bool hideSingleTab;
|
bool hideSingleTab;
|
||||||
bool mruTabOrder;
|
bool mruTabOrder;
|
||||||
bool hideMenubar;
|
bool hideMenubar;
|
||||||
bool enableTrayIcon;
|
|
||||||
bool startToTray;
|
#ifdef Q_OS_MACOS // macOS uses the dock menu instead of the tray icon
|
||||||
bool closeToTray;
|
bool closeToTray = false;
|
||||||
|
bool enableTrayIcon = false;
|
||||||
|
bool startToTray = false;
|
||||||
|
#else
|
||||||
|
bool enableTrayIcon = true;
|
||||||
|
bool closeToTray = true;
|
||||||
|
bool startToTray = false;
|
||||||
|
#endif
|
||||||
|
|
||||||
bool autoStart;
|
bool autoStart;
|
||||||
bool doubleClickTranslates;
|
bool doubleClickTranslates;
|
||||||
bool selectWordBySingleClick;
|
bool selectWordBySingleClick;
|
||||||
|
@ -484,7 +492,7 @@ struct WebSite
|
||||||
QString id, name, url;
|
QString id, name, url;
|
||||||
bool enabled;
|
bool enabled;
|
||||||
QString iconFilename;
|
QString iconFilename;
|
||||||
bool inside_iframe;
|
bool inside_iframe = false;
|
||||||
|
|
||||||
WebSite():
|
WebSite():
|
||||||
enabled( false )
|
enabled( false )
|
||||||
|
@ -690,7 +698,7 @@ struct Transliteration
|
||||||
|
|
||||||
struct Lingua
|
struct Lingua
|
||||||
{
|
{
|
||||||
bool enable;
|
bool enable = false;
|
||||||
QString languageCodes;
|
QString languageCodes;
|
||||||
|
|
||||||
bool operator==( Lingua const & other ) const
|
bool operator==( Lingua const & other ) const
|
||||||
|
@ -729,13 +737,16 @@ struct Forvo
|
||||||
struct Program
|
struct Program
|
||||||
{
|
{
|
||||||
bool enabled;
|
bool enabled;
|
||||||
|
// NOTE: the value of this enum is used for config
|
||||||
enum Type {
|
enum Type {
|
||||||
Audio,
|
Invalid = -1, // Init value
|
||||||
PlainText,
|
Audio = 0,
|
||||||
Html,
|
PlainText = 1,
|
||||||
PrefixMatch,
|
Html = 2,
|
||||||
MaxTypeValue
|
PrefixMatch = 3,
|
||||||
} type;
|
MaxTypeValue = 4
|
||||||
|
};
|
||||||
|
Type type = Invalid;
|
||||||
QString id, name, commandLine;
|
QString id, name, commandLine;
|
||||||
QString iconFilename;
|
QString iconFilename;
|
||||||
|
|
||||||
|
@ -884,7 +895,7 @@ struct Class
|
||||||
QString articleSavePath; // Path to save articles
|
QString articleSavePath; // Path to save articles
|
||||||
|
|
||||||
bool pinPopupWindow; // Last pin status
|
bool pinPopupWindow; // Last pin status
|
||||||
bool popupWindowAlwaysOnTop; // Last status of pinned popup window
|
bool popupWindowAlwaysOnTop = false; // Last status of pinned popup window
|
||||||
|
|
||||||
QByteArray mainWindowState; // Binary state saved by QMainWindow
|
QByteArray mainWindowState; // Binary state saved by QMainWindow
|
||||||
QByteArray mainWindowGeometry; // Geometry saved by QMainWindow
|
QByteArray mainWindowGeometry; // Geometry saved by QMainWindow
|
||||||
|
@ -921,7 +932,7 @@ struct Class
|
||||||
Group const * getGroup( unsigned id ) const;
|
Group const * getGroup( unsigned id ) const;
|
||||||
//disable tts dictionary. does not need to save to persistent file
|
//disable tts dictionary. does not need to save to persistent file
|
||||||
bool notts = false;
|
bool notts = false;
|
||||||
bool resetState;
|
bool resetState = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Configuration-specific events. Some parts of the program need to react
|
/// Configuration-specific events. Some parts of the program need to react
|
||||||
|
|
|
@ -46,10 +46,6 @@ using BtreeIndexing::IndexInfo;
|
||||||
|
|
||||||
namespace {
|
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 )
|
#pragma pack( push, 1 )
|
||||||
|
|
||||||
/// AAR file header
|
/// AAR file header
|
||||||
|
|
|
@ -169,10 +169,6 @@ void addEntryToIndex( string & word,
|
||||||
indexedWords.addWord( Utf8::decode( word ), articleOffset );
|
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
|
class BglDictionary: public BtreeIndexing::BtreeDictionary
|
||||||
{
|
{
|
||||||
QMutex idxMutex;
|
QMutex idxMutex;
|
||||||
|
|
|
@ -45,9 +45,9 @@ DEF_EX( exCorruptedChainData, "Corrupted chain data in the leaf of a btree encou
|
||||||
struct WordArticleLink
|
struct WordArticleLink
|
||||||
{
|
{
|
||||||
string word, prefix; // in utf8
|
string word, prefix; // in utf8
|
||||||
uint32_t articleOffset;
|
uint32_t articleOffset = 0;
|
||||||
|
|
||||||
WordArticleLink() {}
|
WordArticleLink() = default;
|
||||||
|
|
||||||
WordArticleLink( string const & word_, uint32_t articleOffset_, string const & prefix_ = string() ):
|
WordArticleLink( string const & word_, uint32_t articleOffset_, string const & prefix_ = string() ):
|
||||||
word( word_ ),
|
word( word_ ),
|
||||||
|
|
|
@ -424,7 +424,7 @@ public:
|
||||||
if ( countn ) {
|
if ( countn ) {
|
||||||
QMutexLocker _( &dataMutex );
|
QMutexLocker _( &dataMutex );
|
||||||
for ( int x = 0; x < countn; x++ ) {
|
for ( int x = 0; x < countn; x++ ) {
|
||||||
matches.emplace_back( gd::toWString( matchesList.at( x ) ) );
|
matches.emplace_back( matchesList.at( x ).toStdU32String() );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
finish();
|
finish();
|
||||||
|
@ -538,11 +538,13 @@ void DictServerWordSearchRequest::readMatchData( QByteArray & reply )
|
||||||
if ( word.endsWith( '\"' ) ) {
|
if ( word.endsWith( '\"' ) ) {
|
||||||
word.chop( 1 );
|
word.chop( 1 );
|
||||||
}
|
}
|
||||||
if ( word[ 0 ] == '\"' ) {
|
if ( word.startsWith( '\"' ) ) {
|
||||||
word = word.mid( 1 );
|
word = word.remove( 0, 1 );
|
||||||
}
|
}
|
||||||
|
|
||||||
this->addMatchedWord( word );
|
if ( !word.isEmpty() ) {
|
||||||
|
this->addMatchedWord( word );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
reply = this->dictImpl->socket.readLine();
|
reply = this->dictImpl->socket.readLine();
|
||||||
|
|
|
@ -540,7 +540,7 @@ void DslDictionary::loadArticle( uint32_t address,
|
||||||
|
|
||||||
if ( !articleBody ) {
|
if ( !articleBody ) {
|
||||||
// throw exCantReadFile( getDictionaryFilenames()[ 0 ] );
|
// throw exCantReadFile( getDictionaryFilenames()[ 0 ] );
|
||||||
articleData = U"\n\r\t" + gd::toWString( QString( "DICTZIP error: " ) + dict_error_str( dz ) );
|
articleData = U"\n\r\tDICTZIP error: " + QString( dict_error_str( dz ) ).toStdU32String();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
try {
|
try {
|
||||||
|
@ -966,7 +966,7 @@ string DslDictionary::nodeToHtml( ArticleDom::Node const & node )
|
||||||
if ( n >= 0 ) {
|
if ( n >= 0 ) {
|
||||||
int n2 = attr.indexOf( '\"', n + 6 );
|
int n2 = attr.indexOf( '\"', n + 6 );
|
||||||
if ( n2 > 0 ) {
|
if ( n2 > 0 ) {
|
||||||
quint32 id = dslLanguageToId( gd::toWString( attr.mid( n + 6, n2 - n - 6 ) ) );
|
quint32 id = dslLanguageToId( attr.mid( n + 6, n2 - n - 6 ).toStdU32String() );
|
||||||
langcode = LangCoder::intToCode2( id ).toStdString();
|
langcode = LangCoder::intToCode2( id ).toStdString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1089,7 +1089,7 @@ QString const & DslDictionary::getDescription()
|
||||||
for ( ;; ) {
|
for ( ;; ) {
|
||||||
data.clear();
|
data.clear();
|
||||||
langStr = str.mid( 10 ).replace( '\"', ' ' ).trimmed();
|
langStr = str.mid( 10 ).replace( '\"', ' ' ).trimmed();
|
||||||
annLang = LangCoder::findIdForLanguage( gd::toWString( langStr ) );
|
annLang = LangCoder::findIdForLanguage( langStr.toStdU32String() );
|
||||||
do {
|
do {
|
||||||
str = annStream.readLine();
|
str = annStream.readLine();
|
||||||
if ( str.left( 10 ).compare( "#LANGUAGE " ) == 0 ) {
|
if ( str.left( 10 ).compare( "#LANGUAGE " ) == 0 ) {
|
||||||
|
@ -1391,7 +1391,7 @@ void DslDictionary::getArticleText( uint32_t articleAddress, QString & headword,
|
||||||
|
|
||||||
if ( haveInsidedCards ) {
|
if ( haveInsidedCards ) {
|
||||||
// Use base DSL parser for articles with insided cards
|
// Use base DSL parser for articles with insided cards
|
||||||
ArticleDom dom( gd::toWString( text ), getName(), articleHeadword );
|
ArticleDom dom( text.toStdU32String(), getName(), articleHeadword );
|
||||||
text = QString::fromStdU32String( dom.root.renderAsText( true ) );
|
text = QString::fromStdU32String( dom.root.renderAsText( true ) );
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|
|
@ -9,11 +9,7 @@
|
||||||
#include <zlib.h>
|
#include <zlib.h>
|
||||||
#include "dictionary.hh"
|
#include "dictionary.hh"
|
||||||
#include "iconv.hh"
|
#include "iconv.hh"
|
||||||
#if ( QT_VERSION >= QT_VERSION_CHECK( 6, 0, 0 ) )
|
#include <QtCore5Compat/QTextCodec>
|
||||||
#include <QtCore5Compat/QTextCodec>
|
|
||||||
#else
|
|
||||||
#include <QTextCodec>
|
|
||||||
#endif
|
|
||||||
#include <QByteArray>
|
#include <QByteArray>
|
||||||
#include "utf8.hh"
|
#include "utf8.hh"
|
||||||
|
|
||||||
|
|
|
@ -994,7 +994,7 @@ void EpwingWordSearchRequest::findMatches()
|
||||||
QMutexLocker _( &dataMutex );
|
QMutexLocker _( &dataMutex );
|
||||||
|
|
||||||
for ( const auto & headword : headwords )
|
for ( const auto & headword : headwords )
|
||||||
addMatch( gd::toWString( headword ) );
|
addMatch( headword.toStdU32String() );
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -1047,7 +1047,7 @@ void addWordToChunks( Epwing::Book::EpwingHeadword & head,
|
||||||
chunks.addToBlock( &head.page, sizeof( head.page ) );
|
chunks.addToBlock( &head.page, sizeof( head.page ) );
|
||||||
chunks.addToBlock( &head.offset, sizeof( head.offset ) );
|
chunks.addToBlock( &head.offset, sizeof( head.offset ) );
|
||||||
|
|
||||||
wstring hw = gd::toWString( head.headword );
|
wstring hw = head.headword.toStdU32String();
|
||||||
|
|
||||||
indexedWords.addWord( hw, offset );
|
indexedWords.addWord( hw, offset );
|
||||||
wordCount++;
|
wordCount++;
|
||||||
|
|
|
@ -541,11 +541,7 @@ bool EpwingBook::setSubBook( int book_nom )
|
||||||
QFile f( fileName );
|
QFile f( fileName );
|
||||||
if ( f.open( QFile::ReadOnly | QFile::Text ) ) {
|
if ( f.open( QFile::ReadOnly | QFile::Text ) ) {
|
||||||
QTextStream ts( &f );
|
QTextStream ts( &f );
|
||||||
#if ( QT_VERSION < QT_VERSION_CHECK( 6, 0, 0 ) )
|
|
||||||
ts.setCodec( "UTF-8" );
|
|
||||||
#else
|
|
||||||
ts.setEncoding( QStringConverter::Utf8 );
|
ts.setEncoding( QStringConverter::Utf8 );
|
||||||
#endif
|
|
||||||
|
|
||||||
QString line = ts.readLine();
|
QString line = ts.readLine();
|
||||||
while ( !line.isEmpty() ) {
|
while ( !line.isEmpty() ) {
|
||||||
|
@ -1141,7 +1137,7 @@ void EpwingBook::fixHeadword( QString & headword )
|
||||||
// return;
|
// return;
|
||||||
//}
|
//}
|
||||||
|
|
||||||
gd::wstring folded = Folding::applyPunctOnly( gd::toWString( fixed ) );
|
gd::wstring folded = Folding::applyPunctOnly( fixed.toStdU32String() );
|
||||||
//fixed = QString::fromStdU32String( folded );
|
//fixed = QString::fromStdU32String( folded );
|
||||||
|
|
||||||
//if( isHeadwordCorrect( fixed ) )
|
//if( isHeadwordCorrect( fixed ) )
|
||||||
|
|
|
@ -16,12 +16,7 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <QString>
|
#include <QString>
|
||||||
#if ( QT_VERSION >= QT_VERSION_CHECK( 6, 0, 0 ) )
|
#include <QtCore5Compat/QTextCodec>
|
||||||
#include <QtCore5Compat/QTextCodec>
|
|
||||||
#else
|
|
||||||
#include <QTextCodec>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
#include <stub_msvc.h>
|
#include <stub_msvc.h>
|
||||||
|
|
|
@ -32,11 +32,8 @@
|
||||||
#include <QBuffer>
|
#include <QBuffer>
|
||||||
|
|
||||||
#include <QRegularExpression>
|
#include <QRegularExpression>
|
||||||
#if ( QT_VERSION >= QT_VERSION_CHECK( 6, 0, 0 ) )
|
#include <QtCore5Compat/QTextCodec>
|
||||||
#include <QtCore5Compat/QTextCodec>
|
|
||||||
#else
|
|
||||||
#include <QTextCodec>
|
|
||||||
#endif
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <list>
|
#include <list>
|
||||||
#include <map>
|
#include <map>
|
||||||
|
@ -301,7 +298,6 @@ namespace {
|
||||||
////////////////// GLS Dictionary
|
////////////////// GLS Dictionary
|
||||||
|
|
||||||
using Dictionary::exCantReadFile;
|
using Dictionary::exCantReadFile;
|
||||||
DEF_EX( exUserAbort, "User abort", Dictionary::Ex )
|
|
||||||
DEF_EX_STR( exDictzipError, "DICTZIP error", Dictionary::Ex )
|
DEF_EX_STR( exDictzipError, "DICTZIP error", Dictionary::Ex )
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
|
|
|
@ -413,7 +413,7 @@ QList< wstring > suggest( wstring & word, QMutex & hunspellMutex, Hunspell & hun
|
||||||
|
|
||||||
auto match = cutStem.match( suggestion.trimmed() );
|
auto match = cutStem.match( suggestion.trimmed() );
|
||||||
if ( match.hasMatch() ) {
|
if ( match.hasMatch() ) {
|
||||||
wstring alt = gd::toWString( match.captured( 1 ) );
|
wstring alt = match.captured( 1 ).toStdU32String();
|
||||||
|
|
||||||
if ( Folding::applySimpleCaseOnly( alt ) != lowercasedWord ) // No point in providing same word
|
if ( Folding::applySimpleCaseOnly( alt ) != lowercasedWord ) // No point in providing same word
|
||||||
{
|
{
|
||||||
|
@ -643,7 +643,7 @@ wstring decodeFromHunspell( Hunspell & hunspell, char const * str )
|
||||||
size_t outLeft = result.size() * sizeof( wchar );
|
size_t outLeft = result.size() * sizeof( wchar );
|
||||||
|
|
||||||
QString convStr = conv.convert( in, inLeft );
|
QString convStr = conv.convert( in, inLeft );
|
||||||
return gd::toWString( convStr );
|
return convStr.toStdU32String();
|
||||||
}
|
}
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
|
|
|
@ -224,7 +224,7 @@ void loadDictionaries( QWidget * parent,
|
||||||
|
|
||||||
loadDicts.wait();
|
loadDicts.wait();
|
||||||
|
|
||||||
if ( loadDicts.getExceptionText().size() ) {
|
if ( !loadDicts.getExceptionText().empty() ) {
|
||||||
QMessageBox::critical( parent,
|
QMessageBox::critical( parent,
|
||||||
QCoreApplication::translate( "LoadDictionaries", "Error loading dictionaries" ),
|
QCoreApplication::translate( "LoadDictionaries", "Error loading dictionaries" ),
|
||||||
QString::fromUtf8( loadDicts.getExceptionText().c_str() ) );
|
QString::fromUtf8( loadDicts.getExceptionText().c_str() ) );
|
||||||
|
|
|
@ -32,11 +32,8 @@
|
||||||
#include <QDomDocument>
|
#include <QDomDocument>
|
||||||
#include <QTextDocumentFragment>
|
#include <QTextDocumentFragment>
|
||||||
#include <QDataStream>
|
#include <QDataStream>
|
||||||
#if ( QT_VERSION >= QT_VERSION_CHECK( 6, 0, 0 ) )
|
#include <QtCore5Compat/QTextCodec>
|
||||||
#include <QtCore5Compat/QTextCodec>
|
|
||||||
#else
|
|
||||||
#include <QTextCodec>
|
|
||||||
#endif
|
|
||||||
#include "decompress.hh"
|
#include "decompress.hh"
|
||||||
#include "gddebug.hh"
|
#include "gddebug.hh"
|
||||||
#include "ripemd.hh"
|
#include "ripemd.hh"
|
||||||
|
|
|
@ -785,7 +785,7 @@ void MddResourceRequest::run()
|
||||||
data.push_back( '\0' );
|
data.push_back( '\0' );
|
||||||
QString target =
|
QString target =
|
||||||
MdictParser::toUtf16( "UTF-16LE", &data.front() + sizeof( pattern ), data.size() - sizeof( pattern ) );
|
MdictParser::toUtf16( "UTF-16LE", &data.front() + sizeof( pattern ), data.size() - sizeof( pattern ) );
|
||||||
resourceName = gd::toWString( target.trimmed() );
|
resourceName = target.trimmed().toStdU32String();
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1200,7 +1200,7 @@ QString MdxDictionary::getCachedFileName( QString filename )
|
||||||
data.push_back( '\0' );
|
data.push_back( '\0' );
|
||||||
QString target =
|
QString target =
|
||||||
MdictParser::toUtf16( "UTF-16LE", &data.front() + sizeof( pattern ), data.size() - sizeof( pattern ) );
|
MdictParser::toUtf16( "UTF-16LE", &data.front() + sizeof( pattern ), data.size() - sizeof( pattern ) );
|
||||||
resourceName = gd::toWString( target.trimmed() );
|
resourceName = target.trimmed().toStdU32String();
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -1249,14 +1249,14 @@ static void addEntryToIndex( QString const & word, uint32_t offset, IndexedWords
|
||||||
{
|
{
|
||||||
// Strip any leading or trailing whitespaces
|
// Strip any leading or trailing whitespaces
|
||||||
QString wordTrimmed = word.trimmed();
|
QString wordTrimmed = word.trimmed();
|
||||||
indexedWords.addWord( gd::toWString( wordTrimmed ), offset );
|
indexedWords.addWord( wordTrimmed.toStdU32String(), offset );
|
||||||
}
|
}
|
||||||
|
|
||||||
static void addEntryToIndexSingle( QString const & word, uint32_t offset, IndexedWords & indexedWords )
|
static void addEntryToIndexSingle( QString const & word, uint32_t offset, IndexedWords & indexedWords )
|
||||||
{
|
{
|
||||||
// Strip any leading or trailing whitespaces
|
// Strip any leading or trailing whitespaces
|
||||||
QString wordTrimmed = word.trimmed();
|
QString wordTrimmed = word.trimmed();
|
||||||
indexedWords.addSingleWord( gd::toWString( wordTrimmed ), offset );
|
indexedWords.addSingleWord( wordTrimmed.toStdU32String(), offset );
|
||||||
}
|
}
|
||||||
|
|
||||||
class ArticleHandler: public MdictParser::RecordHandler
|
class ArticleHandler: public MdictParser::RecordHandler
|
||||||
|
|
|
@ -223,7 +223,7 @@ void MediaWikiWordSearchRequest::downloadFinished()
|
||||||
|
|
||||||
qDebug() << "matches" << matches.size();
|
qDebug() << "matches" << matches.size();
|
||||||
for ( int x = 0; x < nl.length(); ++x ) {
|
for ( int x = 0; x < nl.length(); ++x ) {
|
||||||
matches.emplace_back( gd::toWString( nl.item( x ).toElement().attribute( "title" ) ) );
|
matches.emplace_back( nl.item( x ).toElement().attribute( "title" ).toStdU32String() );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -334,7 +334,7 @@ void ProgramWordSearchRequest::instanceFinished( QByteArray output, QString erro
|
||||||
QStringList result = QString::fromUtf8( output ).split( "\n", Qt::SkipEmptyParts );
|
QStringList result = QString::fromUtf8( output ).split( "\n", Qt::SkipEmptyParts );
|
||||||
|
|
||||||
for ( const auto & x : result ) {
|
for ( const auto & x : result ) {
|
||||||
matches.push_back( Dictionary::WordMatch( gd::toWString( x ) ) );
|
matches.push_back( Dictionary::WordMatch( x.toStdU32String() ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( !error.isEmpty() ) {
|
if ( !error.isEmpty() ) {
|
||||||
|
|
|
@ -1,36 +1,31 @@
|
||||||
/* This file is (c) 2008-2012 Konstantin Isakov <ikm@goldendict.org>
|
/* This file is (c) 2008-2012 Konstantin Isakov <ikm@goldendict.org>
|
||||||
* Part of GoldenDict. Licensed under GPLv3 or later, see the LICENSE file */
|
* Part of GoldenDict. Licensed under GPLv3 or later, see the LICENSE file */
|
||||||
|
|
||||||
#include "sdict.hh"
|
|
||||||
#include "btreeidx.hh"
|
#include "btreeidx.hh"
|
||||||
#include "folding.hh"
|
|
||||||
#include "utf8.hh"
|
|
||||||
#include "chunkedstorage.hh"
|
#include "chunkedstorage.hh"
|
||||||
#include "langcoder.hh"
|
|
||||||
#include "gddebug.hh"
|
|
||||||
|
|
||||||
#include "decompress.hh"
|
#include "decompress.hh"
|
||||||
#include "htmlescape.hh"
|
#include "folding.hh"
|
||||||
#include "ftshelpers.hh"
|
#include "ftshelpers.hh"
|
||||||
|
#include "gddebug.hh"
|
||||||
|
#include "htmlescape.hh"
|
||||||
|
#include "langcoder.hh"
|
||||||
|
#include "sdict.hh"
|
||||||
|
#include "utf8.hh"
|
||||||
#include <map>
|
#include <map>
|
||||||
|
#include <QAtomicInt>
|
||||||
|
#include <QRegularExpression>
|
||||||
|
#include <QSemaphore>
|
||||||
|
#include <QString>
|
||||||
#include <set>
|
#include <set>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
|
#include "utils.hh"
|
||||||
|
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
#include <stub_msvc.h>
|
#include <stub_msvc.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <QString>
|
|
||||||
#include <QSemaphore>
|
|
||||||
#include <QAtomicInt>
|
|
||||||
#if ( QT_VERSION >= QT_VERSION_CHECK( 6, 0, 0 ) )
|
|
||||||
#include <QtCore5Compat>
|
|
||||||
#endif
|
|
||||||
#include <QRegularExpression>
|
|
||||||
|
|
||||||
#include "utils.hh"
|
|
||||||
|
|
||||||
namespace Sdict {
|
namespace Sdict {
|
||||||
|
|
||||||
using std::map;
|
using std::map;
|
||||||
|
|
|
@ -1315,10 +1315,10 @@ vector< sptr< Dictionary::Class > > makeDictionaries( vector< string > const & f
|
||||||
|| contentType.startsWith( "text/plain", Qt::CaseInsensitive ) ) {
|
|| contentType.startsWith( "text/plain", Qt::CaseInsensitive ) ) {
|
||||||
//Article
|
//Article
|
||||||
if ( maxHeadwordsToExpand && entries > maxHeadwordsToExpand ) {
|
if ( maxHeadwordsToExpand && entries > maxHeadwordsToExpand ) {
|
||||||
indexedWords.addSingleWord( gd::toWString( refEntry.key ), offsets[ i ].second );
|
indexedWords.addSingleWord( refEntry.key.toStdU32String(), offsets[ i ].second );
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
indexedWords.addWord( gd::toWString( refEntry.key ), offsets[ i ].second );
|
indexedWords.addWord( refEntry.key.toStdU32String(), offsets[ i ].second );
|
||||||
}
|
}
|
||||||
|
|
||||||
wordCount += 1;
|
wordCount += 1;
|
||||||
|
@ -1330,7 +1330,7 @@ vector< sptr< Dictionary::Class > > makeDictionaries( vector< string > const & f
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
indexedResources.addSingleWord( gd::toWString( refEntry.key ), offsets[ i ].second );
|
indexedResources.addSingleWord( refEntry.key.toStdU32String(), offsets[ i ].second );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
sf.clearRefOffsets();
|
sf.clearRefOffsets();
|
||||||
|
|
|
@ -409,7 +409,7 @@ void addDir( QDir const & baseDir,
|
||||||
const uint32_t articleOffset = chunks.startNewBlock();
|
const uint32_t articleOffset = chunks.startNewBlock();
|
||||||
chunks.addToBlock( fileName.c_str(), fileName.size() + 1 );
|
chunks.addToBlock( fileName.c_str(), fileName.size() + 1 );
|
||||||
|
|
||||||
wstring name = gd::toWString( i->fileName() );
|
wstring name = i->fileName().toStdU32String();
|
||||||
|
|
||||||
const wstring::size_type pos = name.rfind( L'.' );
|
const wstring::size_type pos = name.rfind( L'.' );
|
||||||
|
|
||||||
|
|
|
@ -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( 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( 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( 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( ex64BitsNotSupported, "64-bit indices are not presently supported, sorry", Dictionary::Ex )
|
||||||
DEF_EX( exDicttypeNotSupported, "Dictionaries with dicttypes are not supported, sorry", Dictionary::Ex )
|
DEF_EX( exDicttypeNotSupported, "Dictionaries with dicttypes are not supported, sorry", Dictionary::Ex )
|
||||||
|
|
||||||
using Dictionary::exCantReadFile;
|
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( exDictzipError, "DICTZIP error", Dictionary::Ex )
|
||||||
|
|
||||||
DEF_EX_STR( exIncorrectOffset, "Incorrect offset encountered in file", Dictionary::Ex )
|
DEF_EX_STR( exIncorrectOffset, "Incorrect offset encountered in file", Dictionary::Ex )
|
||||||
|
|
|
@ -8,11 +8,8 @@
|
||||||
#include "utf8.hh"
|
#include "utf8.hh"
|
||||||
#include "iconv.hh"
|
#include "iconv.hh"
|
||||||
#include "wstring_qt.hh"
|
#include "wstring_qt.hh"
|
||||||
#if ( QT_VERSION >= QT_VERSION_CHECK( 6, 0, 0 ) )
|
#include <QtCore5Compat/QTextCodec>
|
||||||
#include <QtCore5Compat/QTextCodec>
|
|
||||||
#else
|
|
||||||
#include <QTextCodec>
|
|
||||||
#endif
|
|
||||||
#include <QMutexLocker>
|
#include <QMutexLocker>
|
||||||
|
|
||||||
using namespace BtreeIndexing;
|
using namespace BtreeIndexing;
|
||||||
|
@ -214,7 +211,7 @@ bool IndexedZip::indexFile( BtreeIndexing::IndexedWords & zipFileNames, quint32
|
||||||
// System locale
|
// System locale
|
||||||
if ( localeCodec ) {
|
if ( localeCodec ) {
|
||||||
QString name = localeCodec->toUnicode( entry.fileName.constData(), entry.fileName.size() );
|
QString name = localeCodec->toUnicode( entry.fileName.constData(), entry.fileName.size() );
|
||||||
nameInSystemLocale = gd::toWString( name );
|
nameInSystemLocale = name.toStdU32String();
|
||||||
if ( !nameInSystemLocale.empty() ) {
|
if ( !nameInSystemLocale.empty() ) {
|
||||||
zipFileNames.addSingleWord( nameInSystemLocale, entry.localHeaderOffset );
|
zipFileNames.addSingleWord( nameInSystemLocale, entry.localHeaderOffset );
|
||||||
|
|
||||||
|
|
|
@ -81,7 +81,6 @@ namespace {
|
||||||
|
|
||||||
using Dictionary::exCantReadFile;
|
using Dictionary::exCantReadFile;
|
||||||
DEF_EX_STR( exNotXdxfFile, "The file is not an XDXF file:", Dictionary::Ex )
|
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 )
|
DEF_EX_STR( exDictzipError, "DICTZIP error", Dictionary::Ex )
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
|
@ -904,7 +903,7 @@ void indexArticle( GzippedFile & gzFile,
|
||||||
// Add words to index
|
// Add words to index
|
||||||
|
|
||||||
for ( const auto & word : words ) {
|
for ( const auto & word : words ) {
|
||||||
indexedWords.addWord( gd::toWString( word ), offset );
|
indexedWords.addWord( word.toStdU32String(), offset );
|
||||||
}
|
}
|
||||||
|
|
||||||
++articleCount;
|
++articleCount;
|
||||||
|
@ -1227,7 +1226,7 @@ vector< sptr< Dictionary::Class > > makeDictionaries( vector< string > const & f
|
||||||
while ( !( stream.isEndElement() && stream.name() == u"abbr_def" ) || !stream.atEnd() ) {
|
while ( !( stream.isEndElement() && stream.name() == u"abbr_def" ) || !stream.atEnd() ) {
|
||||||
if ( stream.isStartElement() && stream.name() == u"abbr_k" ) {
|
if ( stream.isStartElement() && stream.name() == u"abbr_k" ) {
|
||||||
s = readElementText( stream );
|
s = readElementText( stream );
|
||||||
keys.push_back( gd::toWString( s ) );
|
keys.push_back( s.toStdU32String() );
|
||||||
}
|
}
|
||||||
else if ( stream.isStartElement() && stream.name() == u"abbr_v" ) {
|
else if ( stream.isStartElement() && stream.name() == u"abbr_v" ) {
|
||||||
s = readElementText( stream );
|
s = readElementText( stream );
|
||||||
|
@ -1247,7 +1246,7 @@ vector< sptr< Dictionary::Class > > makeDictionaries( vector< string > const & f
|
||||||
while ( !( stream.isEndElement() && stream.name() == u"abr_def" ) || !stream.atEnd() ) {
|
while ( !( stream.isEndElement() && stream.name() == u"abr_def" ) || !stream.atEnd() ) {
|
||||||
if ( stream.isStartElement() && stream.name() == u"k" ) {
|
if ( stream.isStartElement() && stream.name() == u"k" ) {
|
||||||
s = readElementText( stream );
|
s = readElementText( stream );
|
||||||
keys.push_back( gd::toWString( s ) );
|
keys.push_back( s.toStdU32String() );
|
||||||
}
|
}
|
||||||
else if ( stream.isStartElement() && stream.name() == u"v" ) {
|
else if ( stream.isStartElement() && stream.name() == u"v" ) {
|
||||||
s = readElementText( stream );
|
s = readElementText( stream );
|
||||||
|
|
|
@ -102,8 +102,7 @@ string convert( string const & in,
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
// Fall-through
|
[[fallthrough]];
|
||||||
|
|
||||||
default:
|
default:
|
||||||
inConverted.push_back( i );
|
inConverted.push_back( i );
|
||||||
afterEol = false;
|
afterEol = false;
|
||||||
|
@ -630,7 +629,7 @@ string convert( string const & in,
|
||||||
|
|
||||||
// if( type == XDXF && dictPtr != NULL && !el.hasAttribute( "start" ) )
|
// if( type == XDXF && dictPtr != NULL && !el.hasAttribute( "start" ) )
|
||||||
if ( dictPtr != NULL && !el.hasAttribute( "start" ) ) {
|
if ( dictPtr != NULL && !el.hasAttribute( "start" ) ) {
|
||||||
string filename = Utf8::encode( gd::toWString( el.text() ) );
|
string filename = Utf8::encode( el.text().toStdU32String() );
|
||||||
|
|
||||||
if ( Filetype::isNameOfPicture( filename ) ) {
|
if ( Filetype::isNameOfPicture( filename ) ) {
|
||||||
QUrl url;
|
QUrl url;
|
||||||
|
|
|
@ -1,17 +1,10 @@
|
||||||
#ifdef __WIN32 // Q_OS_WIN32 isn't available at this point
|
|
||||||
#define _WIN32_WINNT 0x0430
|
|
||||||
#include <windows.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "hotkeywrapper.hh"
|
#include "hotkeywrapper.hh"
|
||||||
#include "gddebug.hh"
|
#include "gddebug.hh"
|
||||||
|
|
||||||
#include <QSessionManager>
|
|
||||||
#include <QTimer>
|
#include <QTimer>
|
||||||
|
#include <QSessionManager>
|
||||||
#include <QWidget>
|
#include <QWidget>
|
||||||
|
|
||||||
#ifdef Q_OS_WIN
|
#ifdef Q_OS_WIN
|
||||||
#include "mainwindow.hh"
|
#include <windows.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -100,11 +93,6 @@ HotkeyStruct::HotkeyStruct( quint32 key_, quint32 key2_, quint32 modifier_, int
|
||||||
modifier( modifier_ ),
|
modifier( modifier_ ),
|
||||||
handle( handle_ ),
|
handle( handle_ ),
|
||||||
id( id_ )
|
id( id_ )
|
||||||
#ifdef Q_OS_MAC
|
|
||||||
,
|
|
||||||
hkRef( 0 ),
|
|
||||||
hkRef2( 0 )
|
|
||||||
#endif
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -115,14 +103,7 @@ HotkeyWrapper::HotkeyWrapper( QObject * parent ):
|
||||||
QThread( parent ),
|
QThread( parent ),
|
||||||
state2( false )
|
state2( false )
|
||||||
{
|
{
|
||||||
#ifdef Q_OS_WIN
|
|
||||||
hwnd = (HWND)( ( static_cast< QMainWindow * >( parent ) )->winId() );
|
|
||||||
|
|
||||||
gdDebug( "Handle global hotkeys via RegisterHotkey()" );
|
|
||||||
|
|
||||||
#else
|
|
||||||
init();
|
init();
|
||||||
#endif
|
|
||||||
( static_cast< QHotkeyApplication * >( qApp ) )->registerWrapper( this );
|
( static_cast< QHotkeyApplication * >( qApp ) )->registerWrapper( this );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -164,7 +145,8 @@ bool HotkeyWrapper::checkState( quint32 vk, quint32 mod )
|
||||||
if ( hs.key == vk && hs.modifier == mod ) {
|
if ( hs.key == vk && hs.modifier == mod ) {
|
||||||
|
|
||||||
#ifdef Q_OS_WIN32
|
#ifdef Q_OS_WIN32
|
||||||
|
// 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.
|
||||||
if ( hs.key2 != 0 || ( mod == MOD_CONTROL && ( vk == VK_INSERT || vk == 'c' || vk == 'C' ) ) ) {
|
if ( hs.key2 != 0 || ( mod == MOD_CONTROL && ( vk == VK_INSERT || vk == 'c' || vk == 'C' ) ) ) {
|
||||||
// Pass-through first part of compound hotkey or clipdoard copy command
|
// Pass-through first part of compound hotkey or clipdoard copy command
|
||||||
|
|
||||||
|
@ -270,262 +252,8 @@ bool HotkeyWrapper::checkState( quint32 vk, quint32 mod )
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
#ifdef Q_OS_WIN
|
#ifndef Q_OS_WIN
|
||||||
|
|
||||||
void HotkeyWrapper::init()
|
|
||||||
{
|
|
||||||
QWidget * root = qApp->topLevelWidgets().value( 0 );
|
|
||||||
hwnd = (HWND)root->winId();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool HotkeyWrapper::setGlobalKey( QKeySequence const & seq, int 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 )
|
|
||||||
{
|
|
||||||
if ( !key )
|
|
||||||
return false; // We don't monitor empty combinations
|
|
||||||
|
|
||||||
static int id = 0;
|
|
||||||
if ( id > 0xBFFF - 1 )
|
|
||||||
id = 0;
|
|
||||||
|
|
||||||
quint32 mod = 0;
|
|
||||||
if ( modifier & Qt::CTRL )
|
|
||||||
mod |= MOD_CONTROL;
|
|
||||||
if ( modifier & Qt::ALT )
|
|
||||||
mod |= MOD_ALT;
|
|
||||||
if ( modifier & Qt::SHIFT )
|
|
||||||
mod |= MOD_SHIFT;
|
|
||||||
if ( modifier & Qt::META )
|
|
||||||
mod |= MOD_WIN;
|
|
||||||
|
|
||||||
quint32 vk = nativeKey( key );
|
|
||||||
quint32 vk2 = key2 ? nativeKey( key2 ) : 0;
|
|
||||||
|
|
||||||
hotkeys.append( HotkeyStruct( vk, vk2, mod, handle, id ) );
|
|
||||||
|
|
||||||
if ( !RegisterHotKey( hwnd, id++, mod, vk ) )
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if ( key2 && key2 != key )
|
|
||||||
return RegisterHotKey( hwnd, id++, mod, vk2 );
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
#if ( QT_VERSION < QT_VERSION_CHECK( 6, 0, 0 ) )
|
|
||||||
bool HotkeyWrapper::winEvent( MSG * message, long * result )
|
|
||||||
#else
|
|
||||||
bool HotkeyWrapper::winEvent( MSG * message, qintptr * result )
|
|
||||||
#endif
|
|
||||||
{
|
|
||||||
(void)result;
|
|
||||||
if ( message->message == WM_HOTKEY )
|
|
||||||
return checkState( ( message->lParam >> 16 ), ( message->lParam & 0xffff ) );
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
quint32 HotkeyWrapper::nativeKey( int key )
|
|
||||||
{
|
|
||||||
if ( key >= Qt::Key_0 && key <= Qt::Key_9 )
|
|
||||||
return VK_NUMPAD0 + ( key - Qt::Key_0 );
|
|
||||||
|
|
||||||
if ( key >= Qt::Key_A && key <= Qt::Key_Z )
|
|
||||||
return key;
|
|
||||||
|
|
||||||
switch ( key ) {
|
|
||||||
case Qt::Key_Space:
|
|
||||||
return VK_SPACE;
|
|
||||||
case Qt::Key_Asterisk:
|
|
||||||
return VK_MULTIPLY;
|
|
||||||
case Qt::Key_Plus:
|
|
||||||
return VK_ADD;
|
|
||||||
case Qt::Key_Comma:
|
|
||||||
return VK_SEPARATOR;
|
|
||||||
case Qt::Key_Minus:
|
|
||||||
return VK_SUBTRACT;
|
|
||||||
case Qt::Key_Slash:
|
|
||||||
return VK_DIVIDE;
|
|
||||||
case Qt::Key_Tab:
|
|
||||||
case Qt::Key_Backtab:
|
|
||||||
return VK_TAB;
|
|
||||||
case Qt::Key_Backspace:
|
|
||||||
return VK_BACK;
|
|
||||||
case Qt::Key_Return:
|
|
||||||
case Qt::Key_Escape:
|
|
||||||
return VK_ESCAPE;
|
|
||||||
case Qt::Key_Enter:
|
|
||||||
return VK_RETURN;
|
|
||||||
case Qt::Key_Insert:
|
|
||||||
return VK_INSERT;
|
|
||||||
case Qt::Key_Delete:
|
|
||||||
return VK_DELETE;
|
|
||||||
case Qt::Key_Pause:
|
|
||||||
return VK_PAUSE;
|
|
||||||
case Qt::Key_Print:
|
|
||||||
return VK_PRINT;
|
|
||||||
case Qt::Key_Clear:
|
|
||||||
return VK_CLEAR;
|
|
||||||
case Qt::Key_Home:
|
|
||||||
return VK_HOME;
|
|
||||||
case Qt::Key_End:
|
|
||||||
return VK_END;
|
|
||||||
case Qt::Key_Up:
|
|
||||||
return VK_UP;
|
|
||||||
case Qt::Key_Down:
|
|
||||||
return VK_DOWN;
|
|
||||||
case Qt::Key_Left:
|
|
||||||
return VK_LEFT;
|
|
||||||
case Qt::Key_Right:
|
|
||||||
return VK_RIGHT;
|
|
||||||
case Qt::Key_PageUp:
|
|
||||||
return VK_PRIOR;
|
|
||||||
case Qt::Key_PageDown:
|
|
||||||
return VK_NEXT;
|
|
||||||
case Qt::Key_F1:
|
|
||||||
return VK_F1;
|
|
||||||
case Qt::Key_F2:
|
|
||||||
return VK_F2;
|
|
||||||
case Qt::Key_F3:
|
|
||||||
return VK_F3;
|
|
||||||
case Qt::Key_F4:
|
|
||||||
return VK_F4;
|
|
||||||
case Qt::Key_F5:
|
|
||||||
return VK_F5;
|
|
||||||
case Qt::Key_F6:
|
|
||||||
return VK_F6;
|
|
||||||
case Qt::Key_F7:
|
|
||||||
return VK_F7;
|
|
||||||
case Qt::Key_F8:
|
|
||||||
return VK_F8;
|
|
||||||
case Qt::Key_F9:
|
|
||||||
return VK_F9;
|
|
||||||
case Qt::Key_F10:
|
|
||||||
return VK_F10;
|
|
||||||
case Qt::Key_F11:
|
|
||||||
return VK_F11;
|
|
||||||
case Qt::Key_F12:
|
|
||||||
return VK_F12;
|
|
||||||
case Qt::Key_F13:
|
|
||||||
return VK_F13;
|
|
||||||
case Qt::Key_F14:
|
|
||||||
return VK_F14;
|
|
||||||
case Qt::Key_F15:
|
|
||||||
return VK_F15;
|
|
||||||
case Qt::Key_F16:
|
|
||||||
return VK_F16;
|
|
||||||
case Qt::Key_F17:
|
|
||||||
return VK_F17;
|
|
||||||
case Qt::Key_F18:
|
|
||||||
return VK_F18;
|
|
||||||
case Qt::Key_F19:
|
|
||||||
return VK_F19;
|
|
||||||
case Qt::Key_F20:
|
|
||||||
return VK_F20;
|
|
||||||
case Qt::Key_F21:
|
|
||||||
return VK_F21;
|
|
||||||
case Qt::Key_F22:
|
|
||||||
return VK_F22;
|
|
||||||
case Qt::Key_F23:
|
|
||||||
return VK_F23;
|
|
||||||
case Qt::Key_F24:
|
|
||||||
return VK_F24;
|
|
||||||
case Qt::Key_Colon:
|
|
||||||
case Qt::Key_Semicolon:
|
|
||||||
return VK_OEM_1;
|
|
||||||
case Qt::Key_Question:
|
|
||||||
return VK_OEM_2;
|
|
||||||
case Qt::Key_AsciiTilde:
|
|
||||||
case Qt::Key_QuoteLeft:
|
|
||||||
return VK_OEM_3;
|
|
||||||
case Qt::Key_BraceLeft:
|
|
||||||
case Qt::Key_BracketLeft:
|
|
||||||
return VK_OEM_4;
|
|
||||||
case Qt::Key_Bar:
|
|
||||||
case Qt::Key_Backslash:
|
|
||||||
return VK_OEM_5;
|
|
||||||
case Qt::Key_BraceRight:
|
|
||||||
case Qt::Key_BracketRight:
|
|
||||||
return VK_OEM_6;
|
|
||||||
case Qt::Key_QuoteDbl:
|
|
||||||
case Qt::Key_Apostrophe:
|
|
||||||
return VK_OEM_7;
|
|
||||||
case Qt::Key_Less:
|
|
||||||
return VK_OEM_COMMA;
|
|
||||||
case Qt::Key_Greater:
|
|
||||||
return VK_OEM_PERIOD;
|
|
||||||
case Qt::Key_Equal:
|
|
||||||
return VK_OEM_PLUS;
|
|
||||||
case Qt::Key_ParenRight:
|
|
||||||
return 0x30;
|
|
||||||
case Qt::Key_Exclam:
|
|
||||||
return 0x31;
|
|
||||||
case Qt::Key_At:
|
|
||||||
return 0x32;
|
|
||||||
case Qt::Key_NumberSign:
|
|
||||||
return 0x33;
|
|
||||||
case Qt::Key_Dollar:
|
|
||||||
return 0x34;
|
|
||||||
case Qt::Key_Percent:
|
|
||||||
return 0x35;
|
|
||||||
case Qt::Key_AsciiCircum:
|
|
||||||
return 0x36;
|
|
||||||
case Qt::Key_Ampersand:
|
|
||||||
return 0x37;
|
|
||||||
case Qt::Key_copyright:
|
|
||||||
return 0x38;
|
|
||||||
case Qt::Key_ParenLeft:
|
|
||||||
return 0x39;
|
|
||||||
case Qt::Key_Underscore:
|
|
||||||
return VK_OEM_MINUS;
|
|
||||||
default:;
|
|
||||||
}
|
|
||||||
|
|
||||||
return key;
|
|
||||||
}
|
|
||||||
|
|
||||||
void HotkeyWrapper::unregister()
|
|
||||||
{
|
|
||||||
for ( int i = 0; i < hotkeys.count(); i++ ) {
|
|
||||||
HotkeyStruct const & hk = hotkeys.at( i );
|
|
||||||
|
|
||||||
UnregisterHotKey( hwnd, hk.id );
|
|
||||||
|
|
||||||
if ( hk.key2 && hk.key2 != hk.key )
|
|
||||||
UnregisterHotKey( hwnd, hk.id + 1 );
|
|
||||||
}
|
|
||||||
|
|
||||||
( static_cast< QHotkeyApplication * >( qApp ) )->unregisterWrapper( this );
|
|
||||||
}
|
|
||||||
|
|
||||||
#if ( QT_VERSION < QT_VERSION_CHECK( 6, 0, 0 ) )
|
|
||||||
bool QHotkeyApplication::nativeEventFilter( const QByteArray & /*eventType*/, void * message, long * result )
|
|
||||||
#else
|
|
||||||
bool QHotkeyApplication::nativeEventFilter( const QByteArray & /*eventType*/, void * message, qintptr * result )
|
|
||||||
#endif
|
|
||||||
{
|
|
||||||
MSG * msg = reinterpret_cast< MSG * >( message );
|
|
||||||
|
|
||||||
if ( msg->message == WM_HOTKEY ) {
|
|
||||||
for ( int i = 0; i < hotkeyWrappers.size(); i++ ) {
|
|
||||||
if ( hotkeyWrappers.at( i )->winEvent( msg, result ) )
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
#else
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,12 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
/// @file
|
||||||
|
/// Handling global hotkeys and some tricks
|
||||||
|
/// Part of this header are implmented in
|
||||||
|
/// + `winhotkeywrapper.cc`
|
||||||
|
/// + `machotkeywrapper.hh`
|
||||||
|
///
|
||||||
|
|
||||||
#include <QGuiApplication>
|
#include <QGuiApplication>
|
||||||
#include <QThread>
|
#include <QThread>
|
||||||
|
|
||||||
|
@ -30,23 +37,24 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef Q_OS_MAC
|
#ifdef Q_OS_MAC
|
||||||
#define __SECURITYHI__
|
#import <Carbon/Carbon.h>
|
||||||
#include <Carbon/Carbon.h>
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
struct HotkeyStruct
|
struct HotkeyStruct
|
||||||
{
|
{
|
||||||
HotkeyStruct() {}
|
HotkeyStruct() = default;
|
||||||
HotkeyStruct( quint32 key, quint32 key2, quint32 modifier, int handle, int id );
|
HotkeyStruct( quint32 key, quint32 key2, quint32 modifier, int handle, int id );
|
||||||
|
|
||||||
quint32 key, key2;
|
quint32 key = 0;
|
||||||
quint32 modifier;
|
quint32 key2 = 0;
|
||||||
int handle;
|
quint32 modifier = 0;
|
||||||
int id;
|
int handle = 0;
|
||||||
|
int id = 0;
|
||||||
#ifdef Q_OS_MAC
|
#ifdef Q_OS_MAC
|
||||||
EventHotKeyRef hkRef, hkRef2;
|
EventHotKeyRef hkRef = 0;
|
||||||
|
EventHotKeyRef hkRef2 = 0;
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -99,15 +107,11 @@ private:
|
||||||
HotkeyStruct state2waiter;
|
HotkeyStruct state2waiter;
|
||||||
|
|
||||||
#ifdef Q_OS_WIN32
|
#ifdef Q_OS_WIN32
|
||||||
|
|
||||||
#if ( QT_VERSION < QT_VERSION_CHECK( 6, 0, 0 ) )
|
|
||||||
virtual bool winEvent( MSG * message, long * result );
|
|
||||||
#else
|
|
||||||
virtual bool winEvent( MSG * message, qintptr * result );
|
virtual bool winEvent( MSG * message, qintptr * result );
|
||||||
#endif
|
|
||||||
HWND hwnd;
|
HWND hwnd;
|
||||||
|
#endif
|
||||||
|
|
||||||
#elif defined( Q_OS_MAC )
|
#ifdef Q_OS_MAC
|
||||||
|
|
||||||
public:
|
public:
|
||||||
void activated( int hkId );
|
void activated( int hkId );
|
||||||
|
@ -118,9 +122,9 @@ private:
|
||||||
static EventHandlerUPP hotKeyFunction;
|
static EventHandlerUPP hotKeyFunction;
|
||||||
quint32 keyC;
|
quint32 keyC;
|
||||||
EventHandlerRef handlerRef;
|
EventHandlerRef handlerRef;
|
||||||
|
#endif
|
||||||
|
|
||||||
#else
|
#ifdef HAVE_X11
|
||||||
|
|
||||||
static void recordEventCallback( XPointer, XRecordInterceptData * );
|
static void recordEventCallback( XPointer, XRecordInterceptData * );
|
||||||
|
|
||||||
/// Called by recordEventCallback()
|
/// Called by recordEventCallback()
|
||||||
|
@ -206,16 +210,10 @@ protected:
|
||||||
void registerWrapper( HotkeyWrapper * wrapper );
|
void registerWrapper( HotkeyWrapper * wrapper );
|
||||||
void unregisterWrapper( HotkeyWrapper * wrapper );
|
void unregisterWrapper( HotkeyWrapper * wrapper );
|
||||||
|
|
||||||
#ifdef Q_OS_WIN32
|
#ifdef Q_OS_WIN
|
||||||
|
|
||||||
#if ( QT_VERSION < QT_VERSION_CHECK( 6, 0, 0 ) )
|
|
||||||
virtual bool nativeEventFilter( const QByteArray & eventType, void * message, long * result );
|
|
||||||
#else
|
|
||||||
virtual bool nativeEventFilter( const QByteArray & eventType, void * message, qintptr * result );
|
virtual bool nativeEventFilter( const QByteArray & eventType, void * message, qintptr * result );
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
protected:
|
|
||||||
#endif // Q_OS_WIN32
|
|
||||||
QList< HotkeyWrapper * > hotkeyWrappers;
|
QList< HotkeyWrapper * > hotkeyWrappers;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -105,15 +105,8 @@ void IframeSchemeHandler::requestStarted( QWebEngineUrlRequestJob * requestJob )
|
||||||
|
|
||||||
buffer->setData( articleString.toUtf8() );
|
buffer->setData( articleString.toUtf8() );
|
||||||
|
|
||||||
#if QT_VERSION >= QT_VERSION_CHECK( 6, 0, 0 )
|
|
||||||
requestJob->reply( "text/html; charset=utf-8", buffer );
|
requestJob->reply( "text/html; charset=utf-8", buffer );
|
||||||
#else
|
|
||||||
#if defined( Q_OS_WIN32 ) || defined( Q_OS_MAC )
|
|
||||||
requestJob->reply( contentType, buffer );
|
|
||||||
#else
|
|
||||||
requestJob->reply( "text/html", buffer );
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
};
|
};
|
||||||
connect( reply, &QNetworkReply::finished, requestJob, finishAction );
|
connect( reply, &QNetworkReply::finished, requestJob, finishAction );
|
||||||
|
|
||||||
|
|
|
@ -2,11 +2,13 @@
|
||||||
* Part of GoldenDict. Licensed under GPLv3 or later, see the LICENSE file */
|
* Part of GoldenDict. Licensed under GPLv3 or later, see the LICENSE file */
|
||||||
|
|
||||||
#include "hotkeywrapper.hh"
|
#include "hotkeywrapper.hh"
|
||||||
#include <QTimer>
|
|
||||||
#include <QMessageBox>
|
#include <QMessageBox>
|
||||||
#include <QPushButton>
|
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
|
#include <QPushButton>
|
||||||
|
#include <QTimer>
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
#import <Appkit/Appkit.h>
|
#import <Appkit/Appkit.h>
|
||||||
|
|
||||||
|
@ -23,120 +25,107 @@
|
||||||
/// https://github.com/sindresorhus/KeyboardShortcuts/blob/9369a045a72a5296150879781321aecd228171db/readme.md?plain=1#L207
|
/// 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
|
// Convert Qt key codes to Mac OS X native codes
|
||||||
|
|
||||||
struct ReverseMapEntry
|
struct ReverseMapEntry {
|
||||||
{
|
UniChar character;
|
||||||
UniChar character;
|
UInt16 keyCode;
|
||||||
UInt16 keyCode;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct ReverseMapEntry * mapping;
|
static std::vector<ReverseMapEntry> mapping;
|
||||||
static int mapEntries = 0;
|
|
||||||
|
|
||||||
|
/// 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()
|
void createMapping()
|
||||||
{
|
{
|
||||||
if( mapping == NULL )
|
if (mapping.empty()) {
|
||||||
{
|
mapping.reserve(128);
|
||||||
TISInputSourceRef inputSourceRef = TISCopyInputSourceForLanguage( CFSTR( "en" ) );
|
|
||||||
if ( !inputSourceRef ) {
|
|
||||||
inputSourceRef = TISCopyCurrentKeyboardInputSource();
|
|
||||||
}
|
|
||||||
if ( !inputSourceRef ) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
CFDataRef dataRef = ( CFDataRef )TISGetInputSourceProperty( inputSourceRef,
|
TISInputSourceRef inputSourceRef = TISCopyCurrentKeyboardLayoutInputSource();
|
||||||
kTISPropertyUnicodeKeyLayoutData );
|
if (!inputSourceRef) {
|
||||||
// this method returns null under macos Japanese input method(and also Chinese), which causes cmd+C+C not to be registered as a hotkey
|
return;
|
||||||
if( !dataRef )
|
|
||||||
{
|
|
||||||
// solve the null value under Japanese keyboard
|
|
||||||
inputSourceRef = TISCopyCurrentKeyboardLayoutInputSource();
|
|
||||||
dataRef = static_cast<CFDataRef>((TISGetInputSourceProperty(inputSourceRef, kTISPropertyUnicodeKeyLayoutData)));
|
|
||||||
if (!dataRef) {
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
const UCKeyboardLayout * keyboardLayoutPtr = ( const UCKeyboardLayout * )CFDataGetBytePtr( dataRef );
|
CFDataRef uchrDataRef = (CFDataRef)TISGetInputSourceProperty(inputSourceRef, kTISPropertyUnicodeKeyLayoutData);
|
||||||
if( !keyboardLayoutPtr ) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
mapping = ( struct ReverseMapEntry * )calloc( 128 , sizeof(struct ReverseMapEntry) );
|
const UCKeyboardLayout* UCKeyboardLayoutPtr;
|
||||||
if( !mapping ) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
mapEntries = 0;
|
if (uchrDataRef) {
|
||||||
|
UCKeyboardLayoutPtr = (const UCKeyboardLayout*)CFDataGetBytePtr(uchrDataRef);
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
if (!UCKeyboardLayoutPtr) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (UInt16 i = 0; i < 128; i++) {
|
||||||
|
UInt32 theDeadKeyState = 0;
|
||||||
|
UniCharCount theLength = 0;
|
||||||
|
UniChar temp_char_buf;
|
||||||
|
if (UCKeyTranslate(UCKeyboardLayoutPtr, i, kUCKeyActionDown, 0, LMGetKbdType(),
|
||||||
|
kUCKeyTranslateNoDeadKeysBit, &theDeadKeyState, 1, &theLength,
|
||||||
|
&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();
|
createMapping();
|
||||||
if( mapping == NULL ) {
|
if (mapping.empty()) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto& m : mapping) {
|
||||||
|
if (m.character == key) {
|
||||||
|
return m.keyCode;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
for( int i = 0; i < mapEntries; i++ )
|
|
||||||
{
|
|
||||||
if( mapping[ i ].character == key ) {
|
|
||||||
return mapping[ i ].keyCode;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace MacKeyMapping
|
} // namespace MacKeyMapping
|
||||||
|
|
||||||
static pascal OSStatus hotKeyHandler( EventHandlerCallRef /* nextHandler */, EventRef theEvent, void * userData )
|
static pascal OSStatus hotKeyHandler(EventHandlerCallRef /* nextHandler */, EventRef theEvent, void* userData)
|
||||||
{
|
{
|
||||||
EventHotKeyID hkID;
|
EventHotKeyID hkID;
|
||||||
GetEventParameter( theEvent, kEventParamDirectObject, typeEventHotKeyID, NULL, sizeof(EventHotKeyID), NULL, &hkID );
|
GetEventParameter(theEvent, kEventParamDirectObject, typeEventHotKeyID, NULL, sizeof(EventHotKeyID), NULL, &hkID);
|
||||||
static_cast< HotkeyWrapper * >( userData )->activated( hkID.id );
|
static_cast<HotkeyWrapper*>(userData)->activated(hkID.id);
|
||||||
return noErr;
|
return noErr;
|
||||||
}
|
}
|
||||||
|
|
||||||
HotkeyWrapper::HotkeyWrapper( QObject *parent )
|
HotkeyWrapper::HotkeyWrapper(QObject* parent)
|
||||||
{
|
{
|
||||||
(void) parent;
|
(void)parent;
|
||||||
hotKeyFunction = NewEventHandlerUPP( hotKeyHandler );
|
hotKeyFunction = NewEventHandlerUPP(hotKeyHandler);
|
||||||
EventTypeSpec type;
|
EventTypeSpec type;
|
||||||
type.eventClass = kEventClassKeyboard;
|
type.eventClass = kEventClassKeyboard;
|
||||||
type.eventKind = kEventHotKeyPressed;
|
type.eventKind = kEventHotKeyPressed;
|
||||||
InstallApplicationEventHandler( hotKeyFunction, 1, &type, this, &handlerRef );
|
InstallApplicationEventHandler(hotKeyFunction, 1, &type, this, &handlerRef);
|
||||||
keyC = nativeKey( 'c' );
|
keyC = nativeKey('c');
|
||||||
}
|
}
|
||||||
|
|
||||||
HotkeyWrapper::~HotkeyWrapper()
|
HotkeyWrapper::~HotkeyWrapper()
|
||||||
{
|
{
|
||||||
unregister();
|
unregister();
|
||||||
RemoveEventHandler( handlerRef );
|
RemoveEventHandler(handlerRef);
|
||||||
}
|
}
|
||||||
|
|
||||||
void HotkeyWrapper::waitKey2()
|
void HotkeyWrapper::waitKey2()
|
||||||
{
|
{
|
||||||
state2 = false;
|
state2 = false;
|
||||||
}
|
}
|
||||||
void checkAndRequestAccessibilityPermission()
|
void checkAndRequestAccessibilityPermission()
|
||||||
{
|
{
|
||||||
|
@ -159,196 +148,220 @@ void checkAndRequestAccessibilityPermission()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void HotkeyWrapper::activated( int hkId )
|
void HotkeyWrapper::activated(int hkId)
|
||||||
{
|
{
|
||||||
if ( state2 )
|
if (state2) { // wait for 2nd key
|
||||||
{ // wait for 2nd key
|
|
||||||
|
|
||||||
waitKey2(); // Cancel the 2nd-key wait stage
|
waitKey2(); // Cancel the 2nd-key wait stage
|
||||||
|
|
||||||
if ( hkId == state2waiter.id + 1 ||
|
if (hkId == state2waiter.id + 1 || (hkId == state2waiter.id && state2waiter.key == state2waiter.key2)) {
|
||||||
( hkId == state2waiter.id && state2waiter.key == state2waiter.key2 ) )
|
emit hotkeyActivated(state2waiter.handle);
|
||||||
{
|
return;
|
||||||
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];
|
||||||
HotkeyStruct &hs = hotkeys[ i ];
|
if (hkId == hs.id) {
|
||||||
if( hkId == hs.id )
|
if (hs.key == keyC && hs.modifier == cmdKey) {
|
||||||
{
|
checkAndRequestAccessibilityPermission();
|
||||||
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 );
|
|
||||||
|
|
||||||
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;
|
sendCmdC();
|
||||||
hotKeyID.signature = 'GDHK';
|
|
||||||
hotKeyID.id = hs.id;
|
|
||||||
|
|
||||||
RegisterEventHotKey( hs.key, hs.modifier, hotKeyID, GetApplicationEventTarget(), 0, &hs.hkRef );
|
EventHotKeyID hotKeyID;
|
||||||
}
|
hotKeyID.signature = 'GDHK';
|
||||||
|
hotKeyID.id = hs.id;
|
||||||
|
|
||||||
if ( hs.key2 == 0 ) {
|
RegisterEventHotKey(hs.key, hs.modifier, hotKeyID, GetApplicationEventTarget(), 0, &hs.hkRef);
|
||||||
emit hotkeyActivated( hs.handle );
|
}
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
state2 = true;
|
if (hs.key2 == 0) {
|
||||||
state2waiter = hs;
|
emit hotkeyActivated(hs.handle);
|
||||||
QTimer::singleShot( 500, this, SLOT( waitKey2() ) );
|
return;
|
||||||
return;
|
}
|
||||||
|
|
||||||
|
state2 = true;
|
||||||
|
state2waiter = hs;
|
||||||
|
QTimer::singleShot(500, this, SLOT(waitKey2()));
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
state2 = false;
|
state2 = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
void HotkeyWrapper::unregister()
|
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);
|
||||||
HotkeyStruct const & hk = hotkeys.at( i );
|
|
||||||
|
|
||||||
UnregisterEventHotKey( hk.hkRef );
|
UnregisterEventHotKey(hk.hkRef);
|
||||||
|
|
||||||
if ( hk.key2 && hk.key2 != hk.key ) {
|
if (hk.key2 && hk.key2 != hk.key) {
|
||||||
UnregisterEventHotKey( hk.hkRef2 );
|
UnregisterEventHotKey(hk.hkRef2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
(static_cast< QHotkeyApplication * >( qApp ))->unregisterWrapper( this );
|
(static_cast<QHotkeyApplication*>(qApp))->unregisterWrapper(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool HotkeyWrapper::setGlobalKey( QKeySequence const & seq, int handle )
|
bool HotkeyWrapper::setGlobalKey(QKeySequence const& seq, int handle)
|
||||||
{
|
{
|
||||||
Config::HotKey hk(seq);
|
Config::HotKey hk(seq);
|
||||||
return setGlobalKey(hk.key1,hk.key2,hk.modifiers,handle);
|
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 ) {
|
if (!key) {
|
||||||
return false; // We don't monitor empty combinations
|
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 );
|
quint32 HotkeyWrapper::nativeKey(int 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 )
|
|
||||||
{
|
{
|
||||||
switch( key ) {
|
switch (key) {
|
||||||
case Qt::Key_Escape: return 0x35;
|
case Qt::Key_Escape:
|
||||||
case Qt::Key_Tab: return 0x30;
|
return 0x35;
|
||||||
case Qt::Key_Backspace: return 0x33;
|
case Qt::Key_Tab:
|
||||||
case Qt::Key_Return: return 0x24;
|
return 0x30;
|
||||||
case Qt::Key_Enter: return 0x4c;
|
case Qt::Key_Backspace:
|
||||||
case Qt::Key_Delete: return 0x75;
|
return 0x33;
|
||||||
case Qt::Key_Clear: return 0x47;
|
case Qt::Key_Return:
|
||||||
case Qt::Key_Home: return 0x73;
|
return 0x24;
|
||||||
case Qt::Key_End: return 0x77;
|
case Qt::Key_Enter:
|
||||||
case Qt::Key_Left: return 0x7b;
|
return 0x4c;
|
||||||
case Qt::Key_Up: return 0x7e;
|
case Qt::Key_Delete:
|
||||||
case Qt::Key_Right: return 0x7c;
|
return 0x75;
|
||||||
case Qt::Key_Down: return 0x7d;
|
case Qt::Key_Clear:
|
||||||
case Qt::Key_PageUp: return 0x74;
|
return 0x47;
|
||||||
case Qt::Key_PageDown: return 0x79;
|
case Qt::Key_Home:
|
||||||
case Qt::Key_CapsLock: return 0x57;
|
return 0x73;
|
||||||
case Qt::Key_F1: return 0x7a;
|
case Qt::Key_End:
|
||||||
case Qt::Key_F2: return 0x78;
|
return 0x77;
|
||||||
case Qt::Key_F3: return 0x63;
|
case Qt::Key_Left:
|
||||||
case Qt::Key_F4: return 0x76;
|
return 0x7b;
|
||||||
case Qt::Key_F5: return 0x60;
|
case Qt::Key_Up:
|
||||||
case Qt::Key_F6: return 0x61;
|
return 0x7e;
|
||||||
case Qt::Key_F7: return 0x62;
|
case Qt::Key_Right:
|
||||||
case Qt::Key_F8: return 0x64;
|
return 0x7c;
|
||||||
case Qt::Key_F9: return 0x65;
|
case Qt::Key_Down:
|
||||||
case Qt::Key_F10: return 0x6d;
|
return 0x7d;
|
||||||
case Qt::Key_F11: return 0x67;
|
case Qt::Key_PageUp:
|
||||||
case Qt::Key_F12: return 0x6f;
|
return 0x74;
|
||||||
case Qt::Key_F13: return 0x69;
|
case Qt::Key_PageDown:
|
||||||
case Qt::Key_F14: return 0x6b;
|
return 0x79;
|
||||||
case Qt::Key_F15: return 0x71;
|
case Qt::Key_CapsLock:
|
||||||
case Qt::Key_Help: return 0x72;
|
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:;
|
default:;
|
||||||
}
|
}
|
||||||
return MacKeyMapping::qtKeyToNativeKey( QChar( key ).toLower().toLatin1() );
|
return MacKeyMapping::qtKeyToNativeKey(QChar(key).toLower().unicode());
|
||||||
}
|
}
|
||||||
|
|
||||||
void HotkeyWrapper::sendCmdC()
|
void HotkeyWrapper::sendCmdC()
|
||||||
{
|
{
|
||||||
CGEventFlags flags = kCGEventFlagMaskCommand;
|
CGEventFlags flags = kCGEventFlagMaskCommand;
|
||||||
CGEventRef ev;
|
CGEventRef ev;
|
||||||
CGEventSourceRef source = CGEventSourceCreate( kCGEventSourceStateCombinedSessionState );
|
CGEventSourceRef source = CGEventSourceCreate(kCGEventSourceStateCombinedSessionState);
|
||||||
|
|
||||||
//press down
|
// press down
|
||||||
ev = CGEventCreateKeyboardEvent( source, keyC, true );
|
ev = CGEventCreateKeyboardEvent(source, keyC, true);
|
||||||
CGEventSetFlags( ev, CGEventFlags( flags | CGEventGetFlags( ev ) ) ); //combine flags
|
CGEventSetFlags(ev, CGEventFlags(flags | CGEventGetFlags(ev))); // combine flags
|
||||||
CGEventPost( kCGAnnotatedSessionEventTap, ev );
|
CGEventPost(kCGAnnotatedSessionEventTap, ev);
|
||||||
CFRelease( ev );
|
CFRelease(ev);
|
||||||
|
|
||||||
//press up
|
// press up
|
||||||
ev = CGEventCreateKeyboardEvent( source, keyC, false );
|
ev = CGEventCreateKeyboardEvent(source, keyC, false);
|
||||||
CGEventSetFlags( ev, CGEventFlags( flags | CGEventGetFlags( ev ) ) ); //combine flags
|
CGEventSetFlags(ev, CGEventFlags(flags | CGEventGetFlags(ev))); // combine flags
|
||||||
CGEventPost( kCGAnnotatedSessionEventTap, ev );
|
CGEventPost(kCGAnnotatedSessionEventTap, ev);
|
||||||
CFRelease( ev );
|
CFRelease(ev);
|
||||||
|
|
||||||
CFRelease( source );
|
CFRelease(source);
|
||||||
}
|
}
|
||||||
|
|
||||||
EventHandlerUPP HotkeyWrapper::hotKeyFunction = NULL;
|
EventHandlerUPP HotkeyWrapper::hotKeyFunction = NULL;
|
||||||
|
|
|
@ -1,372 +1,344 @@
|
||||||
#include "macmouseover.hh"
|
#include "macmouseover.hh"
|
||||||
#include <AppKit/NSTouch.h>
|
#import <AppKit/AppKit.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
|
|
||||||
|
|
||||||
const int mouseOverInterval = 300;
|
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;
|
(void)proxy;
|
||||||
if( type != kCGEventMouseMoved ) {
|
if (type != kCGEventMouseMoved) {
|
||||||
|
return event;
|
||||||
|
}
|
||||||
|
static_cast<MacMouseOver*>(refcon)->mouseMoved();
|
||||||
return event;
|
return event;
|
||||||
}
|
}
|
||||||
static_cast< MacMouseOver * >( refcon )->mouseMoved();
|
|
||||||
return event;
|
|
||||||
}
|
|
||||||
|
|
||||||
static CGPoint carbonScreenPointFromCocoaScreenPoint( NSPoint cocoaPoint )
|
static CGPoint carbonScreenPointFromCocoaScreenPoint(NSPoint cocoaPoint)
|
||||||
{
|
{
|
||||||
NSScreen *foundScreen = nil;
|
NSScreen* foundScreen = nil;
|
||||||
CGPoint thePoint;
|
CGPoint thePoint;
|
||||||
|
|
||||||
for (NSScreen *screen in [NSScreen screens]) {
|
for (NSScreen* screen in [NSScreen screens]) {
|
||||||
if (NSPointInRect(cocoaPoint, [screen frame])) {
|
if (NSPointInRect(cocoaPoint, [screen frame])) {
|
||||||
foundScreen = screen;
|
foundScreen = screen;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (foundScreen) {
|
if (foundScreen) {
|
||||||
CGFloat screenHeight = [foundScreen frame].size.height;
|
CGFloat screenHeight = [foundScreen frame].size.height;
|
||||||
thePoint = CGPointMake(cocoaPoint.x, screenHeight - cocoaPoint.y - 1);
|
thePoint = CGPointMake(cocoaPoint.x, screenHeight - cocoaPoint.y - 1);
|
||||||
}
|
} else {
|
||||||
else {
|
thePoint = CGPointMake(0.0, 0.0);
|
||||||
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() :
|
MacMouseOver::MacMouseOver()
|
||||||
pPref(NULL)
|
: pPref(NULL)
|
||||||
, tapRef( 0 )
|
, tapRef(0)
|
||||||
, loop( 0 )
|
, loop(0)
|
||||||
{
|
{
|
||||||
mouseTimer.setSingleShot( true );
|
mouseTimer.setSingleShot(true);
|
||||||
connect( &mouseTimer, SIGNAL( timeout() ), this, SLOT( timerShot() ) );
|
connect(&mouseTimer, SIGNAL(timeout()), this, SLOT(timerShot()));
|
||||||
|
|
||||||
elementSystemWide = AXUIElementCreateSystemWide();
|
elementSystemWide = AXUIElementCreateSystemWide();
|
||||||
}
|
}
|
||||||
|
|
||||||
MacMouseOver::~MacMouseOver()
|
MacMouseOver::~MacMouseOver()
|
||||||
{
|
{
|
||||||
disableMouseOver();
|
disableMouseOver();
|
||||||
|
|
||||||
if( tapRef ) {
|
if (tapRef) {
|
||||||
CFRelease( tapRef );
|
CFRelease(tapRef);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (loop) {
|
||||||
|
CFRelease(loop);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (elementSystemWide) {
|
||||||
|
CFRelease(elementSystemWide);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if( loop ) {
|
QString MacMouseOver::CFStringRefToQString(CFStringRef str)
|
||||||
CFRelease( loop );
|
|
||||||
}
|
|
||||||
|
|
||||||
if( elementSystemWide ) {
|
|
||||||
CFRelease( elementSystemWide );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
QString MacMouseOver::CFStringRefToQString( CFStringRef str )
|
|
||||||
{
|
{
|
||||||
int length = CFStringGetLength( str );
|
int length = CFStringGetLength(str);
|
||||||
if( length == 0 ) {
|
if (length == 0) {
|
||||||
return QString();
|
return QString();
|
||||||
}
|
}
|
||||||
|
|
||||||
UniChar *chars = new UniChar[ length ];
|
UniChar* chars = new UniChar[length];
|
||||||
CFStringGetCharacters( str, CFRangeMake( 0, length ), chars );
|
CFStringGetCharacters(str, CFRangeMake(0, length), chars);
|
||||||
|
|
||||||
QString result = QString::fromUtf16( (char16_t*)chars, length );
|
|
||||||
|
|
||||||
delete[] chars;
|
QString result = QString::fromUtf16((char16_t*)chars, length);
|
||||||
return result;
|
|
||||||
|
delete[] chars;
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MacMouseOver::mouseMoved()
|
void MacMouseOver::mouseMoved()
|
||||||
{
|
{
|
||||||
mouseTimer.start( mouseOverInterval );
|
mouseTimer.start(mouseOverInterval);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MacMouseOver::enableMouseOver()
|
void MacMouseOver::enableMouseOver()
|
||||||
{
|
{
|
||||||
mouseTimer.stop();
|
mouseTimer.stop();
|
||||||
if( !isAXAPIEnabled() ) {
|
if (!isAXAPIEnabled()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if( !tapRef ) {
|
if (!tapRef) {
|
||||||
tapRef = CGEventTapCreate( kCGAnnotatedSessionEventTap, kCGHeadInsertEventTap,
|
tapRef = CGEventTapCreate(kCGAnnotatedSessionEventTap, kCGHeadInsertEventTap,
|
||||||
kCGEventTapOptionListenOnly,
|
kCGEventTapOptionListenOnly,
|
||||||
CGEventMaskBit( kCGEventMouseMoved ),
|
CGEventMaskBit(kCGEventMouseMoved),
|
||||||
eventCallback, this );
|
eventCallback, this);
|
||||||
}
|
}
|
||||||
if( !tapRef ) {
|
if (!tapRef) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if( !loop ) {
|
if (!loop) {
|
||||||
loop = CFMachPortCreateRunLoopSource( kCFAllocatorDefault, tapRef, 0 );
|
loop = CFMachPortCreateRunLoopSource(kCFAllocatorDefault, tapRef, 0);
|
||||||
}
|
}
|
||||||
if( loop ) {
|
if (loop) {
|
||||||
CFRunLoopAddSource( CFRunLoopGetMain(), loop, kCFRunLoopCommonModes );
|
CFRunLoopAddSource(CFRunLoopGetMain(), loop, kCFRunLoopCommonModes);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void MacMouseOver::disableMouseOver()
|
void MacMouseOver::disableMouseOver()
|
||||||
{
|
{
|
||||||
mouseTimer.stop();
|
mouseTimer.stop();
|
||||||
if( loop ) {
|
if (loop) {
|
||||||
CFRunLoopRemoveSource( CFRunLoopGetMain(), loop, kCFRunLoopCommonModes );
|
CFRunLoopRemoveSource(CFRunLoopGetMain(), loop, kCFRunLoopCommonModes);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void MacMouseOver::timerShot()
|
void MacMouseOver::timerShot()
|
||||||
{
|
{
|
||||||
if( mouseMutex.tryLock( 0 ) ) {
|
if (mouseMutex.tryLock(0)) {
|
||||||
mouseMutex.unlock();
|
mouseMutex.unlock();
|
||||||
} else {
|
} else {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if( !pPref ) {
|
if (!pPref) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if( !pPref->enableScanPopupModifiers || checkModifiersPressed( pPref->scanPopupModifiers ) ) {
|
if (!pPref->enableScanPopupModifiers || checkModifiersPressed(pPref->scanPopupModifiers)) {
|
||||||
handlePosition();
|
handlePosition();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void MacMouseOver::handlePosition()
|
void MacMouseOver::handlePosition()
|
||||||
{
|
{
|
||||||
QMutexLocker _( &mouseMutex );
|
QMutexLocker _(&mouseMutex);
|
||||||
|
|
||||||
QString strToTranslate;
|
QString strToTranslate;
|
||||||
|
|
||||||
NSAutoreleasePool * pool = [ [ NSAutoreleasePool alloc ] init ];
|
NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
|
||||||
CGPoint pt = carbonScreenPointFromCocoaScreenPoint( [NSEvent mouseLocation] );
|
CGPoint pt = carbonScreenPointFromCocoaScreenPoint([NSEvent mouseLocation]);
|
||||||
[ pool drain ];
|
[pool drain];
|
||||||
|
|
||||||
CFArrayRef names = 0;
|
CFArrayRef names = 0;
|
||||||
|
|
||||||
AXUIElementRef elem = 0;
|
AXUIElementRef elem = 0;
|
||||||
AXError err = AXUIElementCopyElementAtPosition( elementSystemWide, pt.x, pt.y, &elem );
|
AXError err = AXUIElementCopyElementAtPosition(elementSystemWide, pt.x, pt.y, &elem);
|
||||||
|
|
||||||
if( err != kAXErrorSuccess ) {
|
if (err != kAXErrorSuccess) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
for( ; ; )
|
for (;;) {
|
||||||
{
|
CFTypeRef parameter = AXValueCreate(kAXValueTypeCGPoint, &pt);
|
||||||
CFTypeRef parameter = AXValueCreate( kAXValueTypeCGPoint, &pt );
|
CFTypeRef rangeValue;
|
||||||
CFTypeRef rangeValue;
|
err = AXUIElementCopyParameterizedAttributeNames(elem, &names);
|
||||||
err = AXUIElementCopyParameterizedAttributeNames( elem, &names );
|
if (err != kAXErrorSuccess) {
|
||||||
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 ) {
|
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
|
|
||||||
QString s = CFStringRefToQString( stringValue );
|
|
||||||
CFRelease( stringValue );
|
|
||||||
|
|
||||||
if( s[ 0 ].isLetterOrNumber() || s[ 0 ] == '-' ) {
|
|
||||||
strToTranslate += s;
|
|
||||||
} else {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
handleRetrievedString( strToTranslate, wordPos );
|
int numOfAttributes = CFArrayGetCount(names);
|
||||||
}
|
if (CFArrayContainsValue(names, CFRangeMake(0, numOfAttributes), CFSTR("AXRangeForPosition"))) {
|
||||||
}
|
// Standard interface
|
||||||
else if( CFArrayContainsValue( names, CFRangeMake( 0, numOfAttributes ), CFSTR( "AXTextMarkerForPosition" ) ) )
|
err = AXUIElementCopyParameterizedAttributeValue(elem, kAXRangeForPositionParameterizedAttribute,
|
||||||
{
|
parameter, (CFTypeRef*)&rangeValue);
|
||||||
// Safari interface
|
CFRelease(parameter);
|
||||||
CFTypeRef marker, range;
|
if (err != kAXErrorSuccess) {
|
||||||
CFStringRef str;
|
break;
|
||||||
err = AXUIElementCopyParameterizedAttributeValue( elem, CFSTR( "AXTextMarkerForPosition" ),
|
}
|
||||||
parameter, ( CFTypeRef * )&marker );
|
|
||||||
CFRelease( parameter );
|
CFStringRef stringValue;
|
||||||
if( err != kAXErrorSuccess ) {
|
|
||||||
|
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;
|
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( elem ) {
|
}
|
||||||
CFRelease( elem );
|
if (names) {
|
||||||
}
|
CFRelease(names);
|
||||||
if( names ) {
|
}
|
||||||
CFRelease( names );
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MacMouseOver::handleRetrievedString( QString & wordSeq, int wordSeqPos )
|
void MacMouseOver::handleRetrievedString(QString& wordSeq, int wordSeqPos)
|
||||||
{
|
{
|
||||||
|
|
||||||
if( wordSeq.isEmpty() ) {
|
if (wordSeq.isEmpty()) {
|
||||||
return;
|
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
word = wordSeq.mid( begin, end - begin );
|
// locate the word inside the sequence
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Cursor points to a letter -- cut the word it points to
|
|
||||||
|
|
||||||
int begin = wordSeqPos;
|
QString word;
|
||||||
|
|
||||||
for( ; begin; --begin ) {
|
if (wordSeq[wordSeqPos].isSpace()) {
|
||||||
if ( !wordSeq[ begin - 1 ].isLetterOrNumber() ) {
|
// Currently we ignore such cases
|
||||||
break;
|
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() )
|
for (; begin; --begin) {
|
||||||
{
|
if (!wordSeq[begin - 1].isLetterOrNumber()) {
|
||||||
if ( !wordSeq[ end ].isLetterOrNumber() ) {
|
break;
|
||||||
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 )
|
for (int x = 0; x < word.size(); ++x) {
|
||||||
{
|
QChar::Direction d = word[x].direction();
|
||||||
QChar::Direction d = word[ x ].direction();
|
|
||||||
|
|
||||||
if ( d == QChar::DirR || d == QChar::DirAL ||
|
if (d == QChar::DirR || d == QChar::DirAL || d == QChar::DirRLE || d == QChar::DirRLO) {
|
||||||
d == QChar::DirRLE || d == QChar::DirRLO )
|
std::reverse(word.begin(), word.end());
|
||||||
{
|
break;
|
||||||
std::reverse( word.begin(), word.end() );
|
}
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
emit instance().hovered( word, false );
|
emit instance().hovered(word, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MacMouseOver::isAXAPIEnabled()
|
bool MacMouseOver::isAXAPIEnabled()
|
||||||
{
|
{
|
||||||
if( NSFoundationVersionNumber >= 1000 ) { // MacOS 10.9+
|
if (NSFoundationVersionNumber >= 1000) { // MacOS 10.9+
|
||||||
return AXIsProcessTrusted();
|
return AXIsProcessTrusted();
|
||||||
}
|
}
|
||||||
|
|
||||||
return AXAPIEnabled();
|
return AXAPIEnabled();
|
||||||
}
|
}
|
||||||
|
|
19
src/main.cc
19
src/main.cc
|
@ -307,15 +307,7 @@ void processCommandLine( QCoreApplication * app, GDOptions * result )
|
||||||
// Handle cases where we get encoded URL
|
// Handle cases where we get encoded URL
|
||||||
if ( result->word.startsWith( QStringLiteral( "xn--" ) ) ) {
|
if ( result->word.startsWith( QStringLiteral( "xn--" ) ) ) {
|
||||||
// For `kde-open` or `gio` or others, URL are encoded into ACE or Punycode
|
// For `kde-open` or `gio` or others, URL are encoded into ACE or Punycode
|
||||||
#if QT_VERSION >= QT_VERSION_CHECK( 6, 3, 0 )
|
|
||||||
result->word = QUrl::fromAce( result->word.toLatin1(), QUrl::IgnoreIDNWhitelist );
|
result->word = QUrl::fromAce( result->word.toLatin1(), QUrl::IgnoreIDNWhitelist );
|
||||||
#else
|
|
||||||
// Old Qt's fromAce only applies to whitelisted domains, so we add .com to bypass this restriction :)
|
|
||||||
// https://bugreports.qt.io/browse/QTBUG-29080
|
|
||||||
result->word.append( QStringLiteral( ".com" ) );
|
|
||||||
result->word = QUrl::fromAce( result->word.toLatin1() );
|
|
||||||
result->word.chop( 4 );
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
else if ( result->word.startsWith( QStringLiteral( "%" ) ) ) {
|
else if ( result->word.startsWith( QStringLiteral( "%" ) ) ) {
|
||||||
// For Firefox or other browsers where URL are percent encoded
|
// For Firefox or other browsers where URL are percent encoded
|
||||||
|
@ -349,8 +341,11 @@ int main( int argc, char ** argv )
|
||||||
// attach the new console to this application's process
|
// attach the new console to this application's process
|
||||||
if ( AttachConsole( ATTACH_PARENT_PROCESS ) ) {
|
if ( AttachConsole( ATTACH_PARENT_PROCESS ) ) {
|
||||||
// reopen the std I/O streams to redirect I/O to the new console
|
// reopen the std I/O streams to redirect I/O to the new console
|
||||||
freopen( "CON", "w", stdout );
|
auto ret1 = freopen( "CON", "w", stdout );
|
||||||
freopen( "CON", "w", stderr );
|
auto ret2 = freopen( "CON", "w", stderr );
|
||||||
|
if ( ret1 == nullptr || ret2 == nullptr ) {
|
||||||
|
qDebug() << "Attaching console stdout or stderr failed";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
qputenv( "QT_QPA_PLATFORM", "windows:darkmode=1" );
|
qputenv( "QT_QPA_PLATFORM", "windows:darkmode=1" );
|
||||||
|
@ -359,10 +354,6 @@ int main( int argc, char ** argv )
|
||||||
|
|
||||||
|
|
||||||
//high dpi screen support
|
//high dpi screen support
|
||||||
#if ( QT_VERSION < QT_VERSION_CHECK( 6, 0, 0 ) )
|
|
||||||
QApplication::setAttribute( Qt::AA_EnableHighDpiScaling );
|
|
||||||
QApplication::setAttribute( Qt::AA_UseHighDpiPixmaps );
|
|
||||||
#endif
|
|
||||||
qputenv( "QT_ENABLE_HIGHDPI_SCALING", "1" );
|
qputenv( "QT_ENABLE_HIGHDPI_SCALING", "1" );
|
||||||
QApplication::setHighDpiScaleFactorRoundingPolicy( Qt::HighDpiScaleFactorRoundingPolicy::PassThrough );
|
QApplication::setHighDpiScaleFactorRoundingPolicy( Qt::HighDpiScaleFactorRoundingPolicy::PassThrough );
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,6 @@
|
||||||
#include "article_inspect.hh"
|
#include "article_inspect.hh"
|
||||||
#include <QCloseEvent>
|
#include <QCloseEvent>
|
||||||
#if ( QT_VERSION > QT_VERSION_CHECK( 6, 0, 0 ) )
|
#include <QWebEngineContextMenuRequest>
|
||||||
#include <QWebEngineContextMenuRequest>
|
|
||||||
#endif
|
|
||||||
ArticleInspector::ArticleInspector( QWidget * parent ):
|
ArticleInspector::ArticleInspector( QWidget * parent ):
|
||||||
QWidget( parent, Qt::WindowType::Window )
|
QWidget( parent, Qt::WindowType::Window )
|
||||||
{
|
{
|
||||||
|
@ -39,9 +37,7 @@ void ArticleInspector::triggerAction( QWebEnginePage * page )
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if ( QT_VERSION < QT_VERSION_CHECK( 6, 0, 0 ) || QT_VERSION > QT_VERSION_CHECK( 6, 3, 0 ) )
|
|
||||||
page->triggerAction( QWebEnginePage::InspectElement );
|
page->triggerAction( QWebEnginePage::InspectElement );
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ArticleInspector::closeEvent( QCloseEvent * )
|
void ArticleInspector::closeEvent( QCloseEvent * )
|
||||||
|
|
|
@ -31,15 +31,9 @@
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <QApplication>
|
#include <QApplication>
|
||||||
#include <QRandomGenerator>
|
#include <QRandomGenerator>
|
||||||
|
#include <QWebEngineContextMenuRequest>
|
||||||
#if ( QT_VERSION >= QT_VERSION_CHECK( 5, 0, 0 ) && QT_VERSION < QT_VERSION_CHECK( 6, 0, 0 ) )
|
#include <QWebEngineFindTextResult>
|
||||||
#include <QWebEngineContextMenuData>
|
#include <utility>
|
||||||
#endif
|
|
||||||
#if ( QT_VERSION >= QT_VERSION_CHECK( 6, 0, 0 ) )
|
|
||||||
#include <QWebEngineContextMenuRequest>
|
|
||||||
#include <QWebEngineFindTextResult>
|
|
||||||
#include <utility>
|
|
||||||
#endif
|
|
||||||
#ifdef Q_OS_WIN32
|
#ifdef Q_OS_WIN32
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
#include <QPainter>
|
#include <QPainter>
|
||||||
|
@ -214,15 +208,7 @@ ArticleView::ArticleView( QWidget * parent,
|
||||||
|
|
||||||
QWebEngineSettings * settings = webview->settings();
|
QWebEngineSettings * settings = webview->settings();
|
||||||
settings->setUnknownUrlSchemePolicy( QWebEngineSettings::UnknownUrlSchemePolicy::DisallowUnknownUrlSchemes );
|
settings->setUnknownUrlSchemePolicy( QWebEngineSettings::UnknownUrlSchemePolicy::DisallowUnknownUrlSchemes );
|
||||||
#if ( QT_VERSION < QT_VERSION_CHECK( 6, 0, 0 ) )
|
|
||||||
settings->defaultSettings()->setAttribute( QWebEngineSettings::LocalContentCanAccessRemoteUrls, true );
|
|
||||||
settings->defaultSettings()->setAttribute( QWebEngineSettings::LocalContentCanAccessFileUrls, true );
|
|
||||||
settings->defaultSettings()->setAttribute( QWebEngineSettings::ErrorPageEnabled, false );
|
|
||||||
settings->defaultSettings()->setAttribute( QWebEngineSettings::LinksIncludedInFocusChain, false );
|
|
||||||
settings->defaultSettings()->setAttribute( QWebEngineSettings::PlaybackRequiresUserGesture, false );
|
|
||||||
settings->defaultSettings()->setAttribute( QWebEngineSettings::JavascriptCanAccessClipboard, true );
|
|
||||||
settings->defaultSettings()->setAttribute( QWebEngineSettings::PrintElementBackgrounds, false );
|
|
||||||
#else
|
|
||||||
settings->setAttribute( QWebEngineSettings::LocalContentCanAccessRemoteUrls, true );
|
settings->setAttribute( QWebEngineSettings::LocalContentCanAccessRemoteUrls, true );
|
||||||
settings->setAttribute( QWebEngineSettings::LocalContentCanAccessFileUrls, true );
|
settings->setAttribute( QWebEngineSettings::LocalContentCanAccessFileUrls, true );
|
||||||
settings->setAttribute( QWebEngineSettings::ErrorPageEnabled, false );
|
settings->setAttribute( QWebEngineSettings::ErrorPageEnabled, false );
|
||||||
|
@ -230,7 +216,6 @@ ArticleView::ArticleView( QWidget * parent,
|
||||||
settings->setAttribute( QWebEngineSettings::PlaybackRequiresUserGesture, false );
|
settings->setAttribute( QWebEngineSettings::PlaybackRequiresUserGesture, false );
|
||||||
settings->setAttribute( QWebEngineSettings::JavascriptCanAccessClipboard, true );
|
settings->setAttribute( QWebEngineSettings::JavascriptCanAccessClipboard, true );
|
||||||
settings->setAttribute( QWebEngineSettings::PrintElementBackgrounds, false );
|
settings->setAttribute( QWebEngineSettings::PrintElementBackgrounds, false );
|
||||||
#endif
|
|
||||||
|
|
||||||
auto html = articleNetMgr.getHtml( ResourceType::UNTITLE );
|
auto html = articleNetMgr.getHtml( ResourceType::UNTITLE );
|
||||||
|
|
||||||
|
@ -1329,12 +1314,10 @@ void ArticleView::print( QPrinter * printer ) const
|
||||||
result = success;
|
result = success;
|
||||||
loop.quit();
|
loop.quit();
|
||||||
};
|
};
|
||||||
#if ( QT_VERSION < QT_VERSION_CHECK( 6, 0, 0 ) )
|
|
||||||
webview->page()->print( printer, std::move( printPreview ) );
|
|
||||||
#else
|
|
||||||
connect( webview, &QWebEngineView::printFinished, &loop, std::move( printPreview ) );
|
connect( webview, &QWebEngineView::printFinished, &loop, std::move( printPreview ) );
|
||||||
webview->print( printer );
|
webview->print( printer );
|
||||||
#endif
|
|
||||||
loop.exec();
|
loop.exec();
|
||||||
if ( !result ) {
|
if ( !result ) {
|
||||||
qDebug() << "print failed";
|
qDebug() << "print failed";
|
||||||
|
@ -1363,11 +1346,7 @@ void ArticleView::contextMenuRequested( QPoint const & pos )
|
||||||
QAction * saveSoundAction = nullptr;
|
QAction * saveSoundAction = nullptr;
|
||||||
QAction * saveBookmark = nullptr;
|
QAction * saveBookmark = nullptr;
|
||||||
|
|
||||||
#if ( QT_VERSION < QT_VERSION_CHECK( 6, 0, 0 ) )
|
|
||||||
const QWebEngineContextMenuData * menuData = &( r->contextMenuData() );
|
|
||||||
#else
|
|
||||||
QWebEngineContextMenuRequest * menuData = webview->lastContextMenuRequest();
|
QWebEngineContextMenuRequest * menuData = webview->lastContextMenuRequest();
|
||||||
#endif
|
|
||||||
QUrl targetUrl( menuData->linkUrl() );
|
QUrl targetUrl( menuData->linkUrl() );
|
||||||
Contexts contexts;
|
Contexts contexts;
|
||||||
|
|
||||||
|
@ -1392,12 +1371,8 @@ void ArticleView::contextMenuRequested( QPoint const & pos )
|
||||||
}
|
}
|
||||||
|
|
||||||
QUrl imageUrl;
|
QUrl imageUrl;
|
||||||
#if ( QT_VERSION < QT_VERSION_CHECK( 6, 0, 0 ) )
|
|
||||||
if ( !popupView && menuData->mediaType() == QWebEngineContextMenuData::MediaTypeImage )
|
if ( !popupView && menuData->mediaType() == QWebEngineContextMenuRequest::MediaType::MediaTypeImage ) {
|
||||||
#else
|
|
||||||
if ( !popupView && menuData->mediaType() == QWebEngineContextMenuRequest::MediaType::MediaTypeImage )
|
|
||||||
#endif
|
|
||||||
{
|
|
||||||
imageUrl = menuData->mediaUrl();
|
imageUrl = menuData->mediaUrl();
|
||||||
if ( !imageUrl.isEmpty() ) {
|
if ( !imageUrl.isEmpty() ) {
|
||||||
menu.addAction( webview->pageAction( QWebEnginePage::CopyImageToClipboard ) );
|
menu.addAction( webview->pageAction( QWebEnginePage::CopyImageToClipboard ) );
|
||||||
|
@ -1905,7 +1880,7 @@ void ArticleView::doubleClicked( QPoint pos )
|
||||||
|
|
||||||
emit sendWordToInputLine( selectedText );
|
emit sendWordToInputLine( selectedText );
|
||||||
// Do some checks to make sure there's a sensible selection indeed
|
// Do some checks to make sure there's a sensible selection indeed
|
||||||
if ( Folding::applyWhitespaceOnly( gd::toWString( selectedText ) ).size() && selectedText.size() < 60 ) {
|
if ( Folding::applyWhitespaceOnly( selectedText.toStdU32String() ).size() && selectedText.size() < 60 ) {
|
||||||
// Initiate translation
|
// Initiate translation
|
||||||
Qt::KeyboardModifiers kmod = QApplication::keyboardModifiers();
|
Qt::KeyboardModifiers kmod = QApplication::keyboardModifiers();
|
||||||
if ( kmod & ( Qt::ControlModifier | Qt::ShiftModifier ) ) { // open in new tab
|
if ( kmod & ( Qt::ControlModifier | Qt::ShiftModifier ) ) { // open in new tab
|
||||||
|
@ -1955,19 +1930,12 @@ void ArticleView::findText( QString & text,
|
||||||
const QWebEnginePage::FindFlags & f,
|
const QWebEnginePage::FindFlags & f,
|
||||||
const std::function< void( bool match ) > & callback )
|
const std::function< void( bool match ) > & callback )
|
||||||
{
|
{
|
||||||
#if ( QT_VERSION >= QT_VERSION_CHECK( 6, 0, 0 ) )
|
|
||||||
webview->findText( text, f, [ callback ]( const QWebEngineFindTextResult & result ) {
|
webview->findText( text, f, [ callback ]( const QWebEngineFindTextResult & result ) {
|
||||||
auto r = result.numberOfMatches() > 0;
|
auto r = result.numberOfMatches() > 0;
|
||||||
if ( callback ) {
|
if ( callback ) {
|
||||||
callback( r );
|
callback( r );
|
||||||
}
|
}
|
||||||
} );
|
} );
|
||||||
#else
|
|
||||||
webview->findText( text, f, [ callback ]( bool result ) {
|
|
||||||
if ( callback )
|
|
||||||
callback( result );
|
|
||||||
} );
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ArticleView::closeSearch()
|
bool ArticleView::closeSearch()
|
||||||
|
@ -2099,7 +2067,6 @@ void ArticleView::performFtsFindOperation( bool backwards )
|
||||||
QWebEnginePage::FindFlags flags( 0 );
|
QWebEnginePage::FindFlags flags( 0 );
|
||||||
|
|
||||||
if ( backwards ) {
|
if ( backwards ) {
|
||||||
#if ( QT_VERSION >= QT_VERSION_CHECK( 6, 0, 0 ) )
|
|
||||||
webview->findText( firstAvailableText,
|
webview->findText( firstAvailableText,
|
||||||
flags | QWebEnginePage::FindBackward,
|
flags | QWebEnginePage::FindBackward,
|
||||||
[ this ]( const QWebEngineFindTextResult & result ) {
|
[ this ]( const QWebEngineFindTextResult & result ) {
|
||||||
|
@ -2114,16 +2081,8 @@ void ArticleView::performFtsFindOperation( bool backwards )
|
||||||
ftsSearchPanel->statusLabel->setText(
|
ftsSearchPanel->statusLabel->setText(
|
||||||
searchStatusMessage( result.activeMatch(), result.numberOfMatches() ) );
|
searchStatusMessage( result.activeMatch(), result.numberOfMatches() ) );
|
||||||
} );
|
} );
|
||||||
#else
|
|
||||||
webview->findText( firstAvailableText, flags | QWebEnginePage::FindBackward, [ this ]( bool res ) {
|
|
||||||
ftsSearchPanel->previous->setEnabled( res );
|
|
||||||
if ( !ftsSearchPanel->next->isEnabled() )
|
|
||||||
ftsSearchPanel->next->setEnabled( res );
|
|
||||||
} );
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
#if ( QT_VERSION >= QT_VERSION_CHECK( 6, 0, 0 ) )
|
|
||||||
webview->findText( firstAvailableText, flags, [ this ]( const QWebEngineFindTextResult & result ) {
|
webview->findText( firstAvailableText, flags, [ this ]( const QWebEngineFindTextResult & result ) {
|
||||||
if ( result.numberOfMatches() == 0 ) {
|
if ( result.numberOfMatches() == 0 ) {
|
||||||
return;
|
return;
|
||||||
|
@ -2135,15 +2094,6 @@ void ArticleView::performFtsFindOperation( bool backwards )
|
||||||
|
|
||||||
ftsSearchPanel->statusLabel->setText( searchStatusMessage( result.activeMatch(), result.numberOfMatches() ) );
|
ftsSearchPanel->statusLabel->setText( searchStatusMessage( result.activeMatch(), result.numberOfMatches() ) );
|
||||||
} );
|
} );
|
||||||
#else
|
|
||||||
|
|
||||||
webview->findText( firstAvailableText, flags, [ this ]( bool res ) {
|
|
||||||
ftsSearchPanel->next->setEnabled( res );
|
|
||||||
if ( !ftsSearchPanel->previous->isEnabled() )
|
|
||||||
ftsSearchPanel->previous->setEnabled( res );
|
|
||||||
} );
|
|
||||||
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -420,10 +420,6 @@ void DictHeadwords::saveHeadersToFile()
|
||||||
// Write UTF-8 BOM
|
// Write UTF-8 BOM
|
||||||
QTextStream out( &file );
|
QTextStream out( &file );
|
||||||
out.setGenerateByteOrderMark( true );
|
out.setGenerateByteOrderMark( true );
|
||||||
//qt 6 will use utf-8 default.
|
|
||||||
#if QT_VERSION < QT_VERSION_CHECK( 6, 0, 0 )
|
|
||||||
out.setCodec( "UTF-8" );
|
|
||||||
#endif
|
|
||||||
|
|
||||||
exportAllWords( progress, out );
|
exportAllWords( progress, out );
|
||||||
|
|
||||||
|
|
|
@ -204,26 +204,11 @@ void EditDictionaries::acceptChangedSources( bool rebuildGroups )
|
||||||
// Those hold pointers to dictionaries, we need to free them.
|
// Those hold pointers to dictionaries, we need to free them.
|
||||||
groupInstances.clear();
|
groupInstances.clear();
|
||||||
|
|
||||||
groups.clear();
|
|
||||||
orderAndProps.clear();
|
|
||||||
|
|
||||||
loadDictionaries( this, cfg, dictionaries, dictNetMgr );
|
loadDictionaries( this, cfg, dictionaries, dictNetMgr );
|
||||||
|
|
||||||
Instances::updateNames( savedGroups, dictionaries );
|
|
||||||
Instances::updateNames( savedOrder, dictionaries );
|
|
||||||
Instances::updateNames( savedInactive, dictionaries );
|
|
||||||
|
|
||||||
if ( rebuildGroups ) {
|
if ( rebuildGroups ) {
|
||||||
ui.tabs->removeTab( 1 );
|
orderAndProps->rebuild( savedOrder, savedInactive, dictionaries );
|
||||||
ui.tabs->removeTab( 1 );
|
groups->rebuild( dictionaries, savedGroups, orderAndProps->getCurrentDictionaryOrder() );
|
||||||
|
|
||||||
orderAndProps = new OrderAndProps( this, savedOrder, savedInactive, dictionaries );
|
|
||||||
groups = new Groups( this, dictionaries, savedGroups, orderAndProps->getCurrentDictionaryOrder() );
|
|
||||||
|
|
||||||
ui.tabs->insertTab( 1, orderAndProps, QIcon( ":/icons/book.svg" ), tr( "&Dictionaries" ) );
|
|
||||||
ui.tabs->insertTab( 2, groups, QIcon( ":/icons/bookcase.svg" ), tr( "&Groups" ) );
|
|
||||||
connect( groups, &Groups::showDictionaryInfo, this, &EditDictionaries::showDictionaryInfo );
|
|
||||||
connect( orderAndProps, &OrderAndProps::showDictionaryHeadwords, this, &EditDictionaries::showDictionaryHeadwords );
|
|
||||||
}
|
}
|
||||||
setUpdatesEnabled( true );
|
setUpdatesEnabled( true );
|
||||||
}
|
}
|
||||||
|
|
|
@ -84,13 +84,13 @@ private slots:
|
||||||
private:
|
private:
|
||||||
virtual bool eventFilter( QObject *, QEvent * );
|
virtual bool eventFilter( QObject *, QEvent * );
|
||||||
|
|
||||||
Config::Class * m_cfg;
|
Config::Class * m_cfg = nullptr;
|
||||||
QTreeView * m_favoritesTree;
|
QTreeView * m_favoritesTree = nullptr;
|
||||||
QMenu * m_favoritesMenu;
|
QMenu * m_favoritesMenu = nullptr;
|
||||||
QAction * m_deleteSelectedAction;
|
QAction * m_deleteSelectedAction = nullptr;
|
||||||
QAction * m_separator;
|
QAction * m_separator = nullptr;
|
||||||
QAction * m_copySelectedToClipboard;
|
QAction * m_copySelectedToClipboard = nullptr;
|
||||||
QAction * m_addFolder;
|
QAction * m_addFolder = nullptr;
|
||||||
|
|
||||||
QWidget favoritesPaneTitleBar;
|
QWidget favoritesPaneTitleBar;
|
||||||
QHBoxLayout favoritesPaneTitleBarLayout;
|
QHBoxLayout favoritesPaneTitleBarLayout;
|
||||||
|
|
|
@ -64,6 +64,24 @@ Groups::Groups( QWidget * parent,
|
||||||
countChanged();
|
countChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Groups::rebuild( vector< sptr< Dictionary::Class > > const & dicts_,
|
||||||
|
Config::Groups const & groups_,
|
||||||
|
Config::Group const & order )
|
||||||
|
{
|
||||||
|
this->setUpdatesEnabled( false );
|
||||||
|
dicts = dicts_;
|
||||||
|
groups = groups_;
|
||||||
|
|
||||||
|
ui.dictionaries->setAsSource();
|
||||||
|
ui.dictionaries->populate( Instances::Group( order, dicts, Config::Group() ).dictionaries, dicts );
|
||||||
|
|
||||||
|
// Populate groups' widget
|
||||||
|
ui.groups->populate( groups, dicts, ui.dictionaries->getCurrentDictionaries() );
|
||||||
|
|
||||||
|
countChanged();
|
||||||
|
this->setUpdatesEnabled( true );
|
||||||
|
}
|
||||||
|
|
||||||
void Groups::editGroup( unsigned id )
|
void Groups::editGroup( unsigned id )
|
||||||
{
|
{
|
||||||
for ( int x = 0; x < groups.size(); ++x ) {
|
for ( int x = 0; x < groups.size(); ++x ) {
|
||||||
|
|
|
@ -18,7 +18,9 @@ public:
|
||||||
std::vector< sptr< Dictionary::Class > > const &,
|
std::vector< sptr< Dictionary::Class > > const &,
|
||||||
Config::Groups const &,
|
Config::Groups const &,
|
||||||
Config::Group const & order );
|
Config::Group const & order );
|
||||||
|
void rebuild( std::vector< sptr< Dictionary::Class > > const & dicts_,
|
||||||
|
Config::Groups const & groups_,
|
||||||
|
Config::Group const & order );
|
||||||
/// Instructs the dialog to position itself on editing the given group.
|
/// Instructs the dialog to position itself on editing the given group.
|
||||||
void editGroup( unsigned id );
|
void editGroup( unsigned id );
|
||||||
|
|
||||||
|
@ -31,7 +33,7 @@ public:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Ui::Groups ui;
|
Ui::Groups ui;
|
||||||
std::vector< sptr< Dictionary::Class > > const & dicts;
|
std::vector< sptr< Dictionary::Class > > dicts;
|
||||||
Config::Groups groups;
|
Config::Groups groups;
|
||||||
|
|
||||||
QToolButton * groupsListButton;
|
QToolButton * groupsListButton;
|
||||||
|
|
|
@ -53,13 +53,13 @@ private slots:
|
||||||
private:
|
private:
|
||||||
virtual bool eventFilter( QObject *, QEvent * );
|
virtual bool eventFilter( QObject *, QEvent * );
|
||||||
|
|
||||||
Config::Class * m_cfg;
|
Config::Class * m_cfg = nullptr;
|
||||||
History * m_history;
|
History * m_history = nullptr;
|
||||||
QListView * m_historyList;
|
QListView * m_historyList = nullptr;
|
||||||
QMenu * m_historyMenu;
|
QMenu * m_historyMenu = nullptr;
|
||||||
QAction * m_deleteSelectedAction;
|
QAction * m_deleteSelectedAction = nullptr;
|
||||||
QAction * m_separator;
|
QAction * m_separator = nullptr;
|
||||||
QAction * m_copySelectedToClipboard;
|
QAction * m_copySelectedToClipboard = nullptr;
|
||||||
|
|
||||||
QWidget historyPaneTitleBar;
|
QWidget historyPaneTitleBar;
|
||||||
QHBoxLayout historyPaneTitleBarLayout;
|
QHBoxLayout historyPaneTitleBarLayout;
|
||||||
|
|
|
@ -401,14 +401,18 @@ MainWindow::MainWindow( Config::Class & cfg_ ):
|
||||||
connect( wordsZoomOut, &QAction::triggered, this, &MainWindow::doWordsZoomOut );
|
connect( wordsZoomOut, &QAction::triggered, this, &MainWindow::doWordsZoomOut );
|
||||||
connect( wordsZoomBase, &QAction::triggered, this, &MainWindow::doWordsZoomBase );
|
connect( wordsZoomBase, &QAction::triggered, this, &MainWindow::doWordsZoomBase );
|
||||||
|
|
||||||
// tray icon
|
// tray icon
|
||||||
|
#ifndef Q_OS_MACOS // macOS uses the dock menu instead of the tray icon
|
||||||
connect( trayIconMenu.addAction( tr( "Show &Main Window" ) ), &QAction::triggered, this, [ this ] {
|
connect( trayIconMenu.addAction( tr( "Show &Main Window" ) ), &QAction::triggered, this, [ this ] {
|
||||||
this->toggleMainWindow( true );
|
this->toggleMainWindow( true );
|
||||||
} );
|
} );
|
||||||
|
#endif
|
||||||
trayIconMenu.addAction( enableScanningAction );
|
trayIconMenu.addAction( enableScanningAction );
|
||||||
|
|
||||||
|
#ifndef Q_OS_MACOS // macOS uses the dock menu instead of the tray icon
|
||||||
trayIconMenu.addSeparator();
|
trayIconMenu.addSeparator();
|
||||||
connect( trayIconMenu.addAction( tr( "&Quit" ) ), &QAction::triggered, this, &MainWindow::quitApp );
|
connect( trayIconMenu.addAction( tr( "&Quit" ) ), &QAction::triggered, this, &MainWindow::quitApp );
|
||||||
|
#endif
|
||||||
|
|
||||||
addGlobalAction( &escAction, [ this ]() {
|
addGlobalAction( &escAction, [ this ]() {
|
||||||
handleEsc();
|
handleEsc();
|
||||||
|
@ -756,11 +760,7 @@ MainWindow::MainWindow( Config::Class & cfg_ ):
|
||||||
|
|
||||||
|
|
||||||
#if defined( Q_OS_LINUX )
|
#if defined( Q_OS_LINUX )
|
||||||
#if ( QT_VERSION >= QT_VERSION_CHECK( 6, 0, 0 ) )
|
|
||||||
defaultInterfaceStyle = QApplication::style()->name();
|
defaultInterfaceStyle = QApplication::style()->name();
|
||||||
#else
|
|
||||||
defaultInterfaceStyle = QApplication::style()->objectName();
|
|
||||||
#endif
|
|
||||||
#elif defined( Q_OS_MAC )
|
#elif defined( Q_OS_MAC )
|
||||||
defaultInterfaceStyle = "Fusion";
|
defaultInterfaceStyle = "Fusion";
|
||||||
#endif
|
#endif
|
||||||
|
@ -1420,6 +1420,11 @@ void MainWindow::updateAppearances( QString const & addonStyle,
|
||||||
|
|
||||||
void MainWindow::trayIconUpdateOrInit()
|
void MainWindow::trayIconUpdateOrInit()
|
||||||
{
|
{
|
||||||
|
#ifdef Q_OS_MACOS
|
||||||
|
trayIconMenu.setAsDockMenu();
|
||||||
|
ui.actionCloseToTray->setVisible( false );
|
||||||
|
#else
|
||||||
|
|
||||||
if ( !cfg.preferences.enableTrayIcon ) {
|
if ( !cfg.preferences.enableTrayIcon ) {
|
||||||
if ( trayIcon ) {
|
if ( trayIcon ) {
|
||||||
delete trayIcon;
|
delete trayIcon;
|
||||||
|
@ -1443,6 +1448,7 @@ void MainWindow::trayIconUpdateOrInit()
|
||||||
// The 'Close to tray' action is associated with the tray icon, so we hide
|
// The 'Close to tray' action is associated with the tray icon, so we hide
|
||||||
// or show it here.
|
// or show it here.
|
||||||
ui.actionCloseToTray->setVisible( cfg.preferences.enableTrayIcon );
|
ui.actionCloseToTray->setVisible( cfg.preferences.enableTrayIcon );
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::wheelEvent( QWheelEvent * ev )
|
void MainWindow::wheelEvent( QWheelEvent * ev )
|
||||||
|
|
|
@ -133,6 +133,25 @@ OrderAndProps::OrderAndProps( QWidget * parent,
|
||||||
showDictNumbers();
|
showDictNumbers();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void OrderAndProps::rebuild( Config::Group const & dictionaryOrder,
|
||||||
|
Config::Group const & inactiveDictionaries,
|
||||||
|
std::vector< sptr< Dictionary::Class > > const & allDictionaries )
|
||||||
|
{
|
||||||
|
Instances::Group order( dictionaryOrder, allDictionaries, Config::Group() );
|
||||||
|
Instances::Group inactive( inactiveDictionaries, allDictionaries, Config::Group() );
|
||||||
|
|
||||||
|
Instances::complementDictionaryOrder( order, inactive, allDictionaries );
|
||||||
|
|
||||||
|
setUpdatesEnabled( false );
|
||||||
|
ui.dictionaryOrder->populate( order.dictionaries, allDictionaries );
|
||||||
|
ui.inactiveDictionaries->populate( inactive.dictionaries, allDictionaries );
|
||||||
|
|
||||||
|
disableDictionaryDescription();
|
||||||
|
|
||||||
|
showDictNumbers();
|
||||||
|
setUpdatesEnabled( true );
|
||||||
|
}
|
||||||
|
|
||||||
Config::Group OrderAndProps::getCurrentDictionaryOrder() const
|
Config::Group OrderAndProps::getCurrentDictionaryOrder() const
|
||||||
{
|
{
|
||||||
Instances::Group g;
|
Instances::Group g;
|
||||||
|
|
|
@ -17,7 +17,9 @@ public:
|
||||||
Config::Group const & dictionaryOrder,
|
Config::Group const & dictionaryOrder,
|
||||||
Config::Group const & inactiveDictionaries,
|
Config::Group const & inactiveDictionaries,
|
||||||
std::vector< sptr< Dictionary::Class > > const & allDictionaries );
|
std::vector< sptr< Dictionary::Class > > const & allDictionaries );
|
||||||
|
void rebuild( Config::Group const & dictionaryOrder,
|
||||||
|
Config::Group const & inactiveDictionaries,
|
||||||
|
std::vector< sptr< Dictionary::Class > > const & allDictionaries );
|
||||||
Config::Group getCurrentDictionaryOrder() const;
|
Config::Group getCurrentDictionaryOrder() const;
|
||||||
Config::Group getCurrentInactiveDictionaries() const;
|
Config::Group getCurrentInactiveDictionaries() const;
|
||||||
|
|
||||||
|
|
|
@ -174,6 +174,11 @@ Preferences::Preferences( QWidget * parent, Config::Class & cfg_ ):
|
||||||
ui.hideSingleTab->setChecked( p.hideSingleTab );
|
ui.hideSingleTab->setChecked( p.hideSingleTab );
|
||||||
ui.mruTabOrder->setChecked( p.mruTabOrder );
|
ui.mruTabOrder->setChecked( p.mruTabOrder );
|
||||||
ui.enableTrayIcon->setChecked( p.enableTrayIcon );
|
ui.enableTrayIcon->setChecked( p.enableTrayIcon );
|
||||||
|
|
||||||
|
#ifdef Q_OS_MACOS // macOS uses the dock menu instead of the tray icon
|
||||||
|
ui.enableTrayIcon->hide();
|
||||||
|
#endif
|
||||||
|
|
||||||
ui.startToTray->setChecked( p.startToTray );
|
ui.startToTray->setChecked( p.startToTray );
|
||||||
ui.closeToTray->setChecked( p.closeToTray );
|
ui.closeToTray->setChecked( p.closeToTray );
|
||||||
ui.cbAutostart->setChecked( p.autoStart );
|
ui.cbAutostart->setChecked( p.autoStart );
|
||||||
|
|
|
@ -8,11 +8,6 @@
|
||||||
#include <QBitmap>
|
#include <QBitmap>
|
||||||
#include <QMenu>
|
#include <QMenu>
|
||||||
#include <QMouseEvent>
|
#include <QMouseEvent>
|
||||||
#if ( QT_VERSION < QT_VERSION_CHECK( 6, 0, 0 ) )
|
|
||||||
#include <QDesktopWidget>
|
|
||||||
#include <QScreen>
|
|
||||||
#include <QStringList>
|
|
||||||
#endif
|
|
||||||
#include "gddebug.hh"
|
#include "gddebug.hh"
|
||||||
#include "gestures.hh"
|
#include "gestures.hh"
|
||||||
|
|
||||||
|
@ -846,11 +841,7 @@ void ScanPopup::leaveEvent( QEvent * event )
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#if ( QT_VERSION >= QT_VERSION_CHECK( 6, 0, 0 ) )
|
|
||||||
void ScanPopup::enterEvent( QEnterEvent * event )
|
void ScanPopup::enterEvent( QEnterEvent * event )
|
||||||
#else
|
|
||||||
void ScanPopup::enterEvent( QEvent * event )
|
|
||||||
#endif
|
|
||||||
{
|
{
|
||||||
QMainWindow::enterEvent( event );
|
QMainWindow::enterEvent( event );
|
||||||
|
|
||||||
|
|
|
@ -174,11 +174,7 @@ private:
|
||||||
virtual void mouseMoveEvent( QMouseEvent * );
|
virtual void mouseMoveEvent( QMouseEvent * );
|
||||||
virtual void mouseReleaseEvent( QMouseEvent * );
|
virtual void mouseReleaseEvent( QMouseEvent * );
|
||||||
virtual void leaveEvent( QEvent * event );
|
virtual void leaveEvent( QEvent * event );
|
||||||
#if ( QT_VERSION >= QT_VERSION_CHECK( 6, 0, 0 ) )
|
|
||||||
virtual void enterEvent( QEnterEvent * event );
|
virtual void enterEvent( QEnterEvent * event );
|
||||||
#else
|
|
||||||
virtual void enterEvent( QEvent * event );
|
|
||||||
#endif
|
|
||||||
virtual void showEvent( QShowEvent * );
|
virtual void showEvent( QShowEvent * );
|
||||||
virtual void closeEvent( QCloseEvent * );
|
virtual void closeEvent( QCloseEvent * );
|
||||||
virtual void moveEvent( QMoveEvent * );
|
virtual void moveEvent( QMoveEvent * );
|
||||||
|
|
256
src/windows/winhotkeywrapper.cc
Normal file
256
src/windows/winhotkeywrapper.cc
Normal file
|
@ -0,0 +1,256 @@
|
||||||
|
#include <QtGlobal>
|
||||||
|
#ifdef Q_OS_WIN
|
||||||
|
#include "hotkeywrapper.hh"
|
||||||
|
#include <windows.h>
|
||||||
|
#include <QWidget>
|
||||||
|
|
||||||
|
/// Implementation is pretty much using RegisterHotKey & UnregisterHotKey
|
||||||
|
/// https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-registerhotkey
|
||||||
|
|
||||||
|
void HotkeyWrapper::init()
|
||||||
|
{
|
||||||
|
hwnd = (HWND)( ( static_cast< QWidget * >( this->parent() ) )->winId() );
|
||||||
|
}
|
||||||
|
|
||||||
|
bool HotkeyWrapper::setGlobalKey( QKeySequence const & seq, int 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 )
|
||||||
|
{
|
||||||
|
if ( !key )
|
||||||
|
return false; // We don't monitor empty combinations
|
||||||
|
|
||||||
|
static int id = 0;
|
||||||
|
if ( id > 0xBFFF - 1 )
|
||||||
|
id = 0;
|
||||||
|
|
||||||
|
quint32 mod = 0;
|
||||||
|
if ( modifier & Qt::CTRL )
|
||||||
|
mod |= MOD_CONTROL;
|
||||||
|
if ( modifier & Qt::ALT )
|
||||||
|
mod |= MOD_ALT;
|
||||||
|
if ( modifier & Qt::SHIFT )
|
||||||
|
mod |= MOD_SHIFT;
|
||||||
|
if ( modifier & Qt::META )
|
||||||
|
mod |= MOD_WIN;
|
||||||
|
|
||||||
|
quint32 vk = nativeKey( key );
|
||||||
|
quint32 vk2 = key2 ? nativeKey( key2 ) : 0;
|
||||||
|
|
||||||
|
hotkeys.append( HotkeyStruct( vk, vk2, mod, handle, id ) );
|
||||||
|
|
||||||
|
if ( !RegisterHotKey( hwnd, id++, mod, vk ) )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if ( key2 && key2 != key )
|
||||||
|
return RegisterHotKey( hwnd, id++, mod, vk2 );
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool HotkeyWrapper::winEvent( MSG * message, qintptr * result )
|
||||||
|
{
|
||||||
|
Q_UNUSED( result );
|
||||||
|
if ( message->message == WM_HOTKEY )
|
||||||
|
return checkState( ( message->lParam >> 16 ), ( message->lParam & 0xffff ) );
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void HotkeyWrapper::unregister()
|
||||||
|
{
|
||||||
|
for ( int i = 0; i < hotkeys.count(); i++ ) {
|
||||||
|
HotkeyStruct const & hk = hotkeys.at( i );
|
||||||
|
|
||||||
|
UnregisterHotKey( hwnd, hk.id );
|
||||||
|
|
||||||
|
if ( hk.key2 && hk.key2 != hk.key )
|
||||||
|
UnregisterHotKey( hwnd, hk.id + 1 );
|
||||||
|
}
|
||||||
|
|
||||||
|
( static_cast< QHotkeyApplication * >( qApp ) )->unregisterWrapper( this );
|
||||||
|
}
|
||||||
|
|
||||||
|
bool QHotkeyApplication::nativeEventFilter( const QByteArray & /*eventType*/, void * message, qintptr * result )
|
||||||
|
{
|
||||||
|
MSG * msg = reinterpret_cast< MSG * >( message );
|
||||||
|
|
||||||
|
if ( msg->message == WM_HOTKEY ) {
|
||||||
|
for ( int i = 0; i < hotkeyWrappers.size(); i++ ) {
|
||||||
|
if ( hotkeyWrappers.at( i )->winEvent( msg, result ) )
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// References:
|
||||||
|
/// https://learn.microsoft.com/en-us/windows/win32/inputdev/virtual-key-codes
|
||||||
|
/// https://doc.qt.io/qt-6/qt.html#Key-enum
|
||||||
|
quint32 HotkeyWrapper::nativeKey( int key )
|
||||||
|
{
|
||||||
|
// Qt's 0-9 & A-Z overlaps with Windows's VK
|
||||||
|
if ( key >= Qt::Key_0 && key <= Qt::Key_9 || key >= Qt::Key_A && key <= Qt::Key_Z ) {
|
||||||
|
return key;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch ( key ) {
|
||||||
|
case Qt::Key_Space:
|
||||||
|
return VK_SPACE;
|
||||||
|
case Qt::Key_Asterisk:
|
||||||
|
return VK_MULTIPLY;
|
||||||
|
case Qt::Key_Plus:
|
||||||
|
return VK_ADD;
|
||||||
|
case Qt::Key_Comma:
|
||||||
|
return VK_SEPARATOR;
|
||||||
|
case Qt::Key_Minus:
|
||||||
|
return VK_SUBTRACT;
|
||||||
|
case Qt::Key_Slash:
|
||||||
|
return VK_DIVIDE;
|
||||||
|
case Qt::Key_Tab:
|
||||||
|
case Qt::Key_Backtab:
|
||||||
|
return VK_TAB;
|
||||||
|
case Qt::Key_Backspace:
|
||||||
|
return VK_BACK;
|
||||||
|
case Qt::Key_Return:
|
||||||
|
case Qt::Key_Escape:
|
||||||
|
return VK_ESCAPE;
|
||||||
|
case Qt::Key_Enter:
|
||||||
|
return VK_RETURN;
|
||||||
|
case Qt::Key_Insert:
|
||||||
|
return VK_INSERT;
|
||||||
|
case Qt::Key_Delete:
|
||||||
|
return VK_DELETE;
|
||||||
|
case Qt::Key_Pause:
|
||||||
|
return VK_PAUSE;
|
||||||
|
case Qt::Key_Print:
|
||||||
|
return VK_PRINT;
|
||||||
|
case Qt::Key_Clear:
|
||||||
|
return VK_CLEAR;
|
||||||
|
case Qt::Key_Home:
|
||||||
|
return VK_HOME;
|
||||||
|
case Qt::Key_End:
|
||||||
|
return VK_END;
|
||||||
|
case Qt::Key_Up:
|
||||||
|
return VK_UP;
|
||||||
|
case Qt::Key_Down:
|
||||||
|
return VK_DOWN;
|
||||||
|
case Qt::Key_Left:
|
||||||
|
return VK_LEFT;
|
||||||
|
case Qt::Key_Right:
|
||||||
|
return VK_RIGHT;
|
||||||
|
case Qt::Key_PageUp:
|
||||||
|
return VK_PRIOR;
|
||||||
|
case Qt::Key_PageDown:
|
||||||
|
return VK_NEXT;
|
||||||
|
case Qt::Key_F1:
|
||||||
|
return VK_F1;
|
||||||
|
case Qt::Key_F2:
|
||||||
|
return VK_F2;
|
||||||
|
case Qt::Key_F3:
|
||||||
|
return VK_F3;
|
||||||
|
case Qt::Key_F4:
|
||||||
|
return VK_F4;
|
||||||
|
case Qt::Key_F5:
|
||||||
|
return VK_F5;
|
||||||
|
case Qt::Key_F6:
|
||||||
|
return VK_F6;
|
||||||
|
case Qt::Key_F7:
|
||||||
|
return VK_F7;
|
||||||
|
case Qt::Key_F8:
|
||||||
|
return VK_F8;
|
||||||
|
case Qt::Key_F9:
|
||||||
|
return VK_F9;
|
||||||
|
case Qt::Key_F10:
|
||||||
|
return VK_F10;
|
||||||
|
case Qt::Key_F11:
|
||||||
|
return VK_F11;
|
||||||
|
case Qt::Key_F12:
|
||||||
|
return VK_F12;
|
||||||
|
case Qt::Key_F13:
|
||||||
|
return VK_F13;
|
||||||
|
case Qt::Key_F14:
|
||||||
|
return VK_F14;
|
||||||
|
case Qt::Key_F15:
|
||||||
|
return VK_F15;
|
||||||
|
case Qt::Key_F16:
|
||||||
|
return VK_F16;
|
||||||
|
case Qt::Key_F17:
|
||||||
|
return VK_F17;
|
||||||
|
case Qt::Key_F18:
|
||||||
|
return VK_F18;
|
||||||
|
case Qt::Key_F19:
|
||||||
|
return VK_F19;
|
||||||
|
case Qt::Key_F20:
|
||||||
|
return VK_F20;
|
||||||
|
case Qt::Key_F21:
|
||||||
|
return VK_F21;
|
||||||
|
case Qt::Key_F22:
|
||||||
|
return VK_F22;
|
||||||
|
case Qt::Key_F23:
|
||||||
|
return VK_F23;
|
||||||
|
case Qt::Key_F24:
|
||||||
|
return VK_F24;
|
||||||
|
case Qt::Key_Colon:
|
||||||
|
case Qt::Key_Semicolon:
|
||||||
|
return VK_OEM_1;
|
||||||
|
case Qt::Key_Question:
|
||||||
|
return VK_OEM_2;
|
||||||
|
case Qt::Key_AsciiTilde:
|
||||||
|
case Qt::Key_QuoteLeft:
|
||||||
|
return VK_OEM_3;
|
||||||
|
case Qt::Key_BraceLeft:
|
||||||
|
case Qt::Key_BracketLeft:
|
||||||
|
return VK_OEM_4;
|
||||||
|
case Qt::Key_Bar:
|
||||||
|
case Qt::Key_Backslash:
|
||||||
|
return VK_OEM_5;
|
||||||
|
case Qt::Key_BraceRight:
|
||||||
|
case Qt::Key_BracketRight:
|
||||||
|
return VK_OEM_6;
|
||||||
|
case Qt::Key_QuoteDbl:
|
||||||
|
case Qt::Key_Apostrophe:
|
||||||
|
return VK_OEM_7;
|
||||||
|
case Qt::Key_Less:
|
||||||
|
return VK_OEM_COMMA;
|
||||||
|
case Qt::Key_Greater:
|
||||||
|
return VK_OEM_PERIOD;
|
||||||
|
case Qt::Key_Equal:
|
||||||
|
return VK_OEM_PLUS;
|
||||||
|
case Qt::Key_ParenRight:
|
||||||
|
return 0x30;
|
||||||
|
case Qt::Key_Exclam:
|
||||||
|
return 0x31;
|
||||||
|
case Qt::Key_At:
|
||||||
|
return 0x32;
|
||||||
|
case Qt::Key_NumberSign:
|
||||||
|
return 0x33;
|
||||||
|
case Qt::Key_Dollar:
|
||||||
|
return 0x34;
|
||||||
|
case Qt::Key_Percent:
|
||||||
|
return 0x35;
|
||||||
|
case Qt::Key_AsciiCircum:
|
||||||
|
return 0x36;
|
||||||
|
case Qt::Key_Ampersand:
|
||||||
|
return 0x37;
|
||||||
|
case Qt::Key_copyright:
|
||||||
|
return 0x38;
|
||||||
|
case Qt::Key_ParenLeft:
|
||||||
|
return 0x39;
|
||||||
|
case Qt::Key_Underscore:
|
||||||
|
return VK_OEM_MINUS;
|
||||||
|
case Qt::Key_Meta:
|
||||||
|
return VK_LWIN;
|
||||||
|
default:;
|
||||||
|
}
|
||||||
|
|
||||||
|
return key;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -131,7 +131,7 @@ void WordFinder::startSearch()
|
||||||
allWordWritings.resize( 1 );
|
allWordWritings.resize( 1 );
|
||||||
}
|
}
|
||||||
|
|
||||||
allWordWritings[ 0 ] = gd::toWString( inputWord );
|
allWordWritings[ 0 ] = inputWord.toStdU32String();
|
||||||
|
|
||||||
for ( const auto & inputDict : *inputDicts ) {
|
for ( const auto & inputDict : *inputDicts ) {
|
||||||
vector< wstring > writings = inputDict->getAlternateWritings( allWordWritings[ 0 ] );
|
vector< wstring > writings = inputDict->getAlternateWritings( allWordWritings[ 0 ] );
|
||||||
|
|
|
@ -3,10 +3,10 @@
|
||||||
With venv
|
With venv
|
||||||
```
|
```
|
||||||
cd ./website
|
cd ./website
|
||||||
python -m venv ./venv/
|
python3 -m venv ./venv/
|
||||||
source ./venv/bin/activate
|
source ./venv/bin/activate
|
||||||
# source ./venv/bin/activate.fish
|
# source ./venv/bin/activate.fish
|
||||||
pip install mkdocs-material
|
pip3 install mkdocs-material
|
||||||
```
|
```
|
||||||
|
|
||||||
Then
|
Then
|
||||||
|
|
|
@ -46,3 +46,5 @@ will disable the current dictionary's full-text search.
|
||||||
You can check the full-text search status on each dictionary's info dialog.
|
You can check the full-text search status on each dictionary's info dialog.
|
||||||
|
|
||||||
![](img/dictionary-info-fullindex.png)
|
![](img/dictionary-info-fullindex.png)
|
||||||
|
|
||||||
|
Note that it is possible to enable full text for a single dictionary by disabling full-text search in the Preferences dialog, and set `fts=true` for that dictionary.
|
|
@ -1,4 +1,4 @@
|
||||||
Dictionaries management dialog can be opened via menu `Edit` -> `Dictionaries`.
|
Dictionary management dialog can be opened via menu `Edit` -> `Dictionaries`.
|
||||||
|
|
||||||
To use local dictionaries, add them via `Sources` -> `Files`.
|
To use local dictionaries, add them via `Sources` -> `Files`.
|
||||||
|
|
||||||
|
@ -34,7 +34,7 @@ Morphology dictionary uses Hunspell's morphological analysis to obtain word's va
|
||||||
|
|
||||||
You can specify a path that includes Hunspell format data files (`.aff` + `.dic`). GoldenDict scan this folder and create a list of available dictionaries.
|
You can specify a path that includes Hunspell format data files (`.aff` + `.dic`). GoldenDict scan this folder and create a list of available dictionaries.
|
||||||
|
|
||||||
One possible source of Hunspell dictionaries is Libreoffice's [dictionaries](https://github.com/LibreOffice/dictionaries).
|
One possible source of Hunspell dictionaries is LibreOffice's [dictionaries](https://github.com/LibreOffice/dictionaries).
|
||||||
|
|
||||||
The detailed document about the affix file (`.aff`) and the dict file (`.dic`) can be found at [hunspell.5](https://man.archlinux.org/man/hunspell.5.en).
|
The detailed document about the affix file (`.aff`) and the dict file (`.dic`) can be found at [hunspell.5](https://man.archlinux.org/man/hunspell.5.en).
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,7 @@ By creating `article-style.css` or `article-script.js` in GoldenDict's configura
|
||||||
. <- GD's configuration folder
|
. <- GD's configuration folder
|
||||||
├── config
|
├── config
|
||||||
├── article-style.css
|
├── article-style.css
|
||||||
|
├── article-style-print.css (affecting styles when printing)
|
||||||
├── article-script.js
|
├── article-script.js
|
||||||
└── qt-style.css
|
└── qt-style.css
|
||||||
```
|
```
|
||||||
|
|
|
@ -54,17 +54,3 @@
|
||||||
| F3 | Dictionaries dialog |
|
| F3 | Dictionaries dialog |
|
||||||
| F4 | GoldenDict preferences |
|
| F4 | GoldenDict preferences |
|
||||||
| F12 | Inspector |
|
| F12 | Inspector |
|
||||||
|
|
||||||
|
|
||||||
# Solo mode in the dictionary bar
|
|
||||||
Ctrl+Click, Enter solo mode, toggle between single & all dictionaries
|
|
||||||
Shift+Click, Exit solo mode, restore the previous dictionaries.
|
|
||||||
|
|
||||||
For example, there are 4 dictionaries A,B,C,D with ABC selected.
|
|
||||||
|
|
||||||
| Cases| Note|
|
|
||||||
|--------|--------|
|
|
||||||
| Ctrl+Click A|select A only|
|
|
||||||
| Ctrl+Click A, Ctrl+Click B | select B only|
|
|
||||||
| Ctrl+Click A, Ctrl+Click A | A,B,C,D selected(all dictionaries selected)|
|
|
||||||
| Ctrl+Click A, Shift+Click any dictionary| A,B,C selected |
|
|
||||||
|
|
|
@ -1,37 +1,56 @@
|
||||||
## Toolbar
|
## Toolbar
|
||||||
![toolbar](img/toolbar.webp)
|
![toolbar](img/toolbar.webp)
|
||||||
|
|
||||||
From left to right:
|
Type your word in Search Box and press `Enter` to search word in the current selected group. You can also choose a variant from a matches list.
|
||||||
|
|
||||||
* Forward/Backward navigation buttons;
|
Holding Ctrl or Shift will display the translation result in a new tab.
|
||||||
* Group selector
|
|
||||||
* Search Line
|
|
||||||
* Toggle Scanning
|
|
||||||
* Play the first pronunciation in found articles;
|
|
||||||
* Font scale buttons;
|
|
||||||
* Save the article as HTML
|
|
||||||
* Print article
|
|
||||||
* Add to Favorites;
|
|
||||||
|
|
||||||
Type your word in Search Box and press `Enter` to search word in the current selected group. You can also choose a variant from matches list.
|
|
||||||
|
|
||||||
If Ctrl or Shift key has been pressed the new tab for translation will be created.
|
|
||||||
|
|
||||||
### Wildcard matching
|
### Wildcard matching
|
||||||
|
|
||||||
The Search Line can contain wildcard symbols `?` (matches any one character), `*` (matches any characters number) or ranges of characters `[...]`. To find characters `?`, `*`, `[` and `]` it should be escaped with backslash like `\?`, `\*`, `\[`, `\]`.
|
The search line can use wildcard or glob symbols for matching words.
|
||||||
|
|
||||||
|
| Wildcard | Description |
|
||||||
|
|----------|------------------------------------------------------------------------|
|
||||||
|
| `?` | Matches any single character. |
|
||||||
|
| `*` | Matches zero or more of any characters. |
|
||||||
|
| `[abc]` | Matches one character given in the bracket. |
|
||||||
|
| `[a-c]` | Matches one character from the range given in the bracket. |
|
||||||
|
| `[!abc]` | Matches one character that is not given in the bracket. |
|
||||||
|
| `[!a-c]` | Matches one character that is not from the range given in the bracket. |
|
||||||
|
| `\` | Escaping wildcard symbols, e.g. `\?` to search `?` |
|
||||||
|
|
||||||
!!! note
|
!!! note
|
||||||
The wildcard symbol at first position in word leads to full headwords list scanning and it may take a long time for huge dictionaries.
|
The wildcard symbol in the first character leads to scanning of every dictionary's every word and may take a long time.
|
||||||
|
|
||||||
|
More information about wildcard matching can be found in [Wikipedia's glob article](https://en.wikipedia.org/wiki/Glob_(programming)).
|
||||||
|
|
||||||
|
|
||||||
## Dictionary Bar
|
## Dictionary Bar
|
||||||
|
|
||||||
The dictionaries bar contains all dictionaries from current dictionaries group. Click the icons to disable/enable them.
|
The dictionary bar contains all dictionaries from the current dictionaries group. Click the icons to disable/enable them.
|
||||||
|
|
||||||
Hold `Shift` and click dictionary bar will temporally focus on a single dictionary. Hold `Shift` and click again to defocus and restore the previous dictionaries bar state.
|
### "Solo" mode
|
||||||
|
|
||||||
Hold `Ctrl` and click dictionary bar will toggle between "Enable a single dictionary" and "Enable all dictionary".
|
Temporally focus on a single dictionary and restore back to all dictionaries or previously selected dictionaries.
|
||||||
|
|
||||||
Note: The `Shift` and `Ctrl` interaction can also be used on "Found in dictionaries" panel
|
To enter solo mode:
|
||||||
|
|
||||||
|
++ctrl+left-button++ -> Select a single dictionary.
|
||||||
|
|
||||||
|
To exit solo mode:
|
||||||
|
|
||||||
|
++ctrl+left-button++ -> Reselect all dictionaries.
|
||||||
|
|
||||||
|
++shift+left-button++ -> Reselect dictionaries that were previously selected before entering solo mode.
|
||||||
|
|
||||||
|
For example, there are 4 dictionaries A,B,C,D with ABC selected.
|
||||||
|
|
||||||
|
| Cases | Note |
|
||||||
|
|------------------------------------------|----------------------------------------------|
|
||||||
|
| Ctrl+Click A | select A only |
|
||||||
|
| Ctrl+Click A, Ctrl+Click B | select B only |
|
||||||
|
| Ctrl+Click A, Ctrl+Click A | A,B,C,D selected (all dictionaries selected) |
|
||||||
|
| Ctrl+Click A, Shift+Click any dictionary | A,B,C selected |
|
||||||
|
|
||||||
|
Note: This can also be used on the "Found in dictionaries" panel.
|
||||||
|
|
||||||
|
|
|
@ -21,6 +21,7 @@ markdown_extensions:
|
||||||
- admonition
|
- admonition
|
||||||
- pymdownx.details
|
- pymdownx.details
|
||||||
- pymdownx.superfences
|
- pymdownx.superfences
|
||||||
|
- pymdownx.keys
|
||||||
|
|
||||||
nav:
|
nav:
|
||||||
- Getting started: index.md
|
- Getting started: index.md
|
||||||
|
@ -33,7 +34,7 @@ nav:
|
||||||
- Popup Window: ui_popup.md
|
- Popup Window: ui_popup.md
|
||||||
- Headwords Dialog: ui_headwords.md
|
- Headwords Dialog: ui_headwords.md
|
||||||
- Full Text Search: ui_fulltextsearch.md
|
- Full Text Search: ui_fulltextsearch.md
|
||||||
- ToolBar & DictBar: ui_toolbar.md
|
- Tool & Dictionary Bar: ui_toolbar.md
|
||||||
- Favorites: ui_favorites.md
|
- Favorites: ui_favorites.md
|
||||||
- Shortcuts: ui_shortcuts.md
|
- Shortcuts: ui_shortcuts.md
|
||||||
- Advanced Usages:
|
- Advanced Usages:
|
||||||
|
|
Loading…
Reference in a new issue