mirror of
https://github.com/Mahdi-zarei/nekoray.git
synced 2025-12-19 05:30:06 +08:00
add custom shortcut settings
This commit is contained in:
parent
4942c25f18
commit
1c0eb43617
@ -31,6 +31,19 @@ namespace Configs {
|
||||
static QStringList List();
|
||||
};
|
||||
|
||||
class Shortcuts : public JsonStore
|
||||
{
|
||||
public:
|
||||
QMap<QString, QKeySequence> shortcuts;
|
||||
|
||||
QStringList keyVal;
|
||||
|
||||
explicit Shortcuts();
|
||||
bool Save() override;
|
||||
|
||||
bool Load();
|
||||
};
|
||||
|
||||
class DataStore : public JsonStore {
|
||||
public:
|
||||
// Running
|
||||
@ -110,6 +123,7 @@ namespace Configs {
|
||||
int remember_id = -1919;
|
||||
bool remember_enable = false;
|
||||
bool windows_set_admin = false;
|
||||
std::unique_ptr<Shortcuts> shortcuts;
|
||||
|
||||
// Socks & HTTP Inbound
|
||||
QString inbound_address = "127.0.0.1";
|
||||
|
||||
@ -6,6 +6,7 @@
|
||||
#define Dialog_DialogEditProfile "DialogEditProfile"
|
||||
#define Dialog_DialogManageGroups "DialogManageGroups"
|
||||
#define Dialog_DialogManageRoutes "DialogManageRoutes"
|
||||
#define Dialog_DialogManageHotkeys "DialogManageHotkeys"
|
||||
|
||||
// Utils
|
||||
|
||||
|
||||
@ -204,6 +204,9 @@ private:
|
||||
libcore::SpeedTestResult currentTestResult;
|
||||
DownloadProgressReport currentDownloadReport; // could use a list, but don't think can show more than one anyways
|
||||
|
||||
// shortcuts
|
||||
QList<QShortcut*> hiddenMenuShortcuts;
|
||||
|
||||
std::map<std::string, std::string> ruleSetMap;
|
||||
|
||||
QStringList remoteRouteProfiles;
|
||||
@ -237,7 +240,13 @@ private:
|
||||
|
||||
void HotkeyEvent(const QString &key);
|
||||
|
||||
void RegisterShortcuts();
|
||||
void RegisterHiddenMenuShortcuts(bool unregister = false);
|
||||
|
||||
void setActionsData();
|
||||
|
||||
QList<QAction*> getActionsForShortcut();
|
||||
|
||||
void loadShortcuts();
|
||||
|
||||
// grpc
|
||||
|
||||
|
||||
@ -14,10 +14,18 @@ class DialogHotkey : public QDialog {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit DialogHotkey(QWidget *parent = nullptr);
|
||||
explicit DialogHotkey(QWidget *parent = nullptr, const QList<QAction*>& actions = {});
|
||||
|
||||
~DialogHotkey() override;
|
||||
|
||||
public slots:
|
||||
|
||||
void accept();
|
||||
|
||||
void reject();
|
||||
|
||||
private:
|
||||
void generateShortcutItems(const QList<QAction*>& actions);
|
||||
QMap<QtExtKeySequenceEdit*, QString> seqEdit2ID;
|
||||
Ui::DialogHotkey *ui;
|
||||
};
|
||||
|
||||
@ -13,64 +13,105 @@
|
||||
<property name="windowTitle">
|
||||
<string>Hotkey</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_3">
|
||||
<property name="text">
|
||||
<string>Show groups</string>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QTabWidget" name="tabWidget">
|
||||
<property name="currentIndex">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<widget class="QWidget" name="tab">
|
||||
<attribute name="title">
|
||||
<string>Global</string>
|
||||
</attribute>
|
||||
<layout class="QFormLayout" name="formLayout">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>Trigger main window</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QtExtKeySequenceEdit" name="show_mainwindow"/>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_3">
|
||||
<property name="text">
|
||||
<string>Show groups</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QtExtKeySequenceEdit" name="show_groups"/>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="label_4">
|
||||
<property name="text">
|
||||
<string>Show routes</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QtExtKeySequenceEdit" name="show_routes"/>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string>Proxy mode</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<widget class="QtExtKeySequenceEdit" name="system_proxy"/>
|
||||
</item>
|
||||
<item row="4" column="0">
|
||||
<widget class="QLabel" name="toggle_proxy_l">
|
||||
<property name="text">
|
||||
<string>Toggle System Proxy</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="1">
|
||||
<widget class="QKeySequenceEdit" name="toggle_proxy"/>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="tab_2">
|
||||
<attribute name="title">
|
||||
<string>Shortcuts</string>
|
||||
</attribute>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QScrollArea" name="shortcut_area">
|
||||
<property name="horizontalScrollBarPolicy">
|
||||
<enum>Qt::ScrollBarPolicy::ScrollBarAsNeeded</enum>
|
||||
</property>
|
||||
<property name="widgetResizable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<widget class="QWidget" name="scrollAreaWidgetContents">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>380</width>
|
||||
<height>311</height>
|
||||
</rect>
|
||||
</property>
|
||||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="1">
|
||||
<item>
|
||||
<widget class="QDialogButtonBox" name="buttonBox">
|
||||
<property name="focusPolicy">
|
||||
<enum>Qt::StrongFocus</enum>
|
||||
<enum>Qt::FocusPolicy::StrongFocus</enum>
|
||||
</property>
|
||||
<property name="standardButtons">
|
||||
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>Trigger main window</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="label_4">
|
||||
<property name="text">
|
||||
<string>Show routes</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<widget class="QtExtKeySequenceEdit" name="system_proxy"/>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string>Proxy mode</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QtExtKeySequenceEdit" name="show_groups"/>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QtExtKeySequenceEdit" name="show_routes"/>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QtExtKeySequenceEdit" name="show_mainwindow"/>
|
||||
</item>
|
||||
<item row="4" column="1">
|
||||
<widget class="QKeySequenceEdit" name="toggle_proxy"/>
|
||||
</item>
|
||||
<item row="4" column="0">
|
||||
<widget class="QLabel" name="toggle_proxy_l">
|
||||
<property name="text">
|
||||
<string>Toggle System Proxy</string>
|
||||
<set>QDialogButtonBox::StandardButton::Cancel|QDialogButtonBox::StandardButton::Ok</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
@ -84,10 +125,6 @@
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<tabstops>
|
||||
<tabstop>show_mainwindow</tabstop>
|
||||
<tabstop>show_groups</tabstop>
|
||||
<tabstop>show_routes</tabstop>
|
||||
<tabstop>system_proxy</tabstop>
|
||||
<tabstop>buttonBox</tabstop>
|
||||
</tabstops>
|
||||
<resources/>
|
||||
|
||||
@ -8,7 +8,10 @@
|
||||
#include <QJsonArray>
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonObject>
|
||||
#include <QKeySequence>
|
||||
#include <QNetworkAccessManager>
|
||||
#include <QStandardPaths>
|
||||
#include <utility>
|
||||
#include <include/api/RPC.h>
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
@ -352,6 +355,34 @@ namespace Configs {
|
||||
_add(new configItem("dns_final_out", &this->dns_final_out, itemType::string));
|
||||
}
|
||||
|
||||
Shortcuts::Shortcuts() : JsonStore()
|
||||
{
|
||||
_add(new configItem("keyval", &keyVal, itemType::stringList));
|
||||
}
|
||||
|
||||
bool Shortcuts::Save()
|
||||
{
|
||||
keyVal.clear();
|
||||
for (auto [k, v] : shortcuts.asKeyValueRange())
|
||||
{
|
||||
if (v.isEmpty()) continue;
|
||||
keyVal << k << v.toString();
|
||||
}
|
||||
|
||||
return JsonStore::Save();
|
||||
}
|
||||
|
||||
bool Shortcuts::Load() {
|
||||
auto ret = JsonStore::Load();
|
||||
if (!ret) return false;
|
||||
if (keyVal.count()%2 != 0) return false;
|
||||
for (int i=0;i<keyVal.size();i+=2)
|
||||
{
|
||||
shortcuts[keyVal[i]] = QKeySequence(keyVal[i+1]);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
QStringList Routing::List() {
|
||||
return {"Default"};
|
||||
}
|
||||
|
||||
@ -186,7 +186,7 @@ int main(int argc, char* argv[]) {
|
||||
// Datastore & Flags
|
||||
if (Configs::dataStore->start_minimal) Configs::dataStore->flag_tray = true;
|
||||
|
||||
// load routing
|
||||
// load routing and shortcuts
|
||||
Configs::dataStore->routing = std::make_unique<Configs::Routing>();
|
||||
Configs::dataStore->routing->fn = ROUTES_PREFIX + "Default";
|
||||
isLoaded = Configs::dataStore->routing->Load();
|
||||
@ -194,6 +194,13 @@ int main(int argc, char* argv[]) {
|
||||
Configs::dataStore->routing->Save();
|
||||
}
|
||||
|
||||
Configs::dataStore->shortcuts = std::make_unique<Configs::Shortcuts>();
|
||||
Configs::dataStore->shortcuts->fn = "shortcuts.json";
|
||||
isLoaded = Configs::dataStore->shortcuts->Load();
|
||||
if (!isLoaded) {
|
||||
Configs::dataStore->shortcuts->Save();
|
||||
}
|
||||
|
||||
// Translate
|
||||
QString locale;
|
||||
switch (Configs::dataStore->language) {
|
||||
|
||||
@ -86,6 +86,10 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWi
|
||||
themeManager->ApplyTheme(Configs::dataStore->theme);
|
||||
ui->setupUi(this);
|
||||
|
||||
// init shortcuts
|
||||
setActionsData();
|
||||
loadShortcuts();
|
||||
|
||||
// setup log
|
||||
ui->splitter->restoreState(DecodeB64IfValid(Configs::dataStore->splitter_state));
|
||||
new SyntaxHighlighter(isDarkMode() || Configs::dataStore->theme.toLower() == "qdarkstyle", qvLogDocument);
|
||||
@ -201,7 +205,6 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWi
|
||||
ui->tabWidget->installEventFilter(this);
|
||||
//
|
||||
RegisterHotkey(false);
|
||||
RegisterShortcuts();
|
||||
//
|
||||
auto last_size = Configs::dataStore->mw_size.split("x");
|
||||
if (last_size.length() == 2) {
|
||||
@ -749,6 +752,10 @@ void MainWindow::dialog_message_impl(const QString &sender, const QString &info)
|
||||
if (info == "NeedAdmin") {
|
||||
get_elevated_permissions();
|
||||
}
|
||||
if (info == "UpdateShortcuts")
|
||||
{
|
||||
loadShortcuts();
|
||||
}
|
||||
// sender
|
||||
if (sender == Dialog_DialogEditProfile) {
|
||||
auto msg = info.split(",");
|
||||
@ -838,7 +845,15 @@ void MainWindow::on_menu_vpn_settings_triggered() {
|
||||
}
|
||||
|
||||
void MainWindow::on_menu_hotkey_settings_triggered() {
|
||||
USE_DIALOG(DialogHotkey)
|
||||
if (dialog_is_using) return;
|
||||
dialog_is_using = true;
|
||||
auto dialog = new DialogHotkey(this, getActionsForShortcut());
|
||||
connect(dialog, &QDialog::finished, this, [=,this]
|
||||
{
|
||||
dialog->deleteLater();
|
||||
dialog_is_using = false;
|
||||
});
|
||||
dialog->show();
|
||||
}
|
||||
|
||||
void MainWindow::on_commitDataRequest() {
|
||||
@ -879,6 +894,7 @@ void MainWindow::prepare_exit()
|
||||
tray->hide();
|
||||
Configs::dataStore->prepare_exit = true;
|
||||
//
|
||||
RegisterHiddenMenuShortcuts(true);
|
||||
RegisterHotkey(true);
|
||||
if (Configs::dataStore->system_dns_set) set_system_dns(false, false);
|
||||
set_spmode_system_proxy(false, false);
|
||||
@ -2282,7 +2298,7 @@ void MainWindow::RegisterHotkey(bool unregister) {
|
||||
auto hk = RegisteredHotkey.takeFirst();
|
||||
hk->deleteLater();
|
||||
}
|
||||
if (unregister) return;
|
||||
if (unregister || Configs::dataStore->prepare_exit) return;
|
||||
|
||||
QStringList regstr{
|
||||
Configs::dataStore->hotkey_mainwindow,
|
||||
@ -2309,14 +2325,72 @@ void MainWindow::RegisterHotkey(bool unregister) {
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::RegisterShortcuts() {
|
||||
void MainWindow::RegisterHiddenMenuShortcuts(bool unregister) {
|
||||
for (const auto s : hiddenMenuShortcuts) s->deleteLater();
|
||||
hiddenMenuShortcuts.clear();
|
||||
|
||||
if (unregister) return;
|
||||
|
||||
for (const auto &action: ui->menuHidden_menu->actions()) {
|
||||
new QShortcut(action->shortcut(), this, [=,this](){
|
||||
action->trigger();
|
||||
});
|
||||
if (!action->shortcut().toString().isEmpty())
|
||||
{
|
||||
hiddenMenuShortcuts.append(new QShortcut(action->shortcut(), this, [=,this](){
|
||||
action->trigger();
|
||||
}));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::setActionsData()
|
||||
{
|
||||
// assign ids to menu actions so that we can save and restore them
|
||||
ui->menu_add_from_input->setData(QString("m2"));
|
||||
ui->menu_clear_test_result->setData(QString("m3"));
|
||||
ui->menu_clone->setData(QString("m4"));
|
||||
ui->menu_copy_links->setData(QString("m5"));
|
||||
ui->menu_delete_repeat->setData(QString("m6"));
|
||||
ui->menu_export_config->setData(QString("m7"));
|
||||
ui->menu_qr->setData(QString("m8"));
|
||||
ui->menu_remove_invalid->setData(QString("m9"));
|
||||
ui->menu_remove_unavailable->setData(QString("m10"));
|
||||
ui->menu_reset_traffic->setData(QString("m11"));
|
||||
ui->menu_resolve_domain->setData(QString("m12"));
|
||||
ui->menu_resolve_selected->setData(QString("m13"));
|
||||
ui->menu_scan_qr->setData(QString("m14"));
|
||||
ui->menu_stop_testing->setData(QString("m15"));
|
||||
ui->menu_update_subscription->setData(QString("m16"));
|
||||
ui->actionSpeedtest_Current->setData(QString("m18"));
|
||||
ui->actionSpeedtest_Group->setData(QString("m19"));
|
||||
ui->actionSpeedtest_Selected->setData(QString("m20"));
|
||||
ui->actionUrl_Test_Group->setData(QString("m21"));
|
||||
ui->actionUrl_Test_Selected->setData(QString("m22"));
|
||||
}
|
||||
|
||||
QList<QAction*> MainWindow::getActionsForShortcut()
|
||||
{
|
||||
QList<QAction*> list;
|
||||
QList<QAction *> actions = findChildren<QAction *>();
|
||||
|
||||
for (QAction *action : actions) {
|
||||
if (action->data().isNull() || action->data().toString().isEmpty()) continue;
|
||||
list.append(action);
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
void MainWindow::loadShortcuts()
|
||||
{
|
||||
auto mp = Configs::dataStore->shortcuts->shortcuts;
|
||||
for (QList<QAction *> actions = findChildren<QAction *>(); QAction *action : actions)
|
||||
{
|
||||
if (mp.count(action->data().toString()) == 0) action->setShortcut(QKeySequence());
|
||||
else action->setShortcut(mp[action->data().toString()]);
|
||||
}
|
||||
|
||||
RegisterHiddenMenuShortcuts();
|
||||
}
|
||||
|
||||
|
||||
void MainWindow::HotkeyEvent(const QString &key) {
|
||||
if (key.isEmpty()) return;
|
||||
runOnUiThread([=,this] {
|
||||
|
||||
@ -1,26 +1,63 @@
|
||||
#include "include/ui/setting/dialog_hotkey.h"
|
||||
|
||||
#include <include/global/GuiUtils.hpp>
|
||||
|
||||
#include "include/ui/mainwindow_interface.h"
|
||||
|
||||
DialogHotkey::DialogHotkey(QWidget *parent) : QDialog(parent), ui(new Ui::DialogHotkey) {
|
||||
DialogHotkey::DialogHotkey(QWidget *parent, const QList<QAction*>& actions) : QDialog(parent), ui(new Ui::DialogHotkey) {
|
||||
ui->setupUi(this);
|
||||
ui->show_mainwindow->setKeySequence(Configs::dataStore->hotkey_mainwindow);
|
||||
ui->show_groups->setKeySequence(Configs::dataStore->hotkey_group);
|
||||
ui->show_routes->setKeySequence(Configs::dataStore->hotkey_route);
|
||||
ui->system_proxy->setKeySequence(Configs::dataStore->hotkey_system_proxy_menu);
|
||||
ui->toggle_proxy->setKeySequence(Configs::dataStore->hotkey_toggle_system_proxy);
|
||||
|
||||
generateShortcutItems(actions);
|
||||
|
||||
GetMainWindow()->RegisterHotkey(true);
|
||||
}
|
||||
|
||||
DialogHotkey::~DialogHotkey() {
|
||||
if (result() == QDialog::Accepted) {
|
||||
Configs::dataStore->hotkey_mainwindow = ui->show_mainwindow->keySequence().toString();
|
||||
Configs::dataStore->hotkey_group = ui->show_groups->keySequence().toString();
|
||||
Configs::dataStore->hotkey_route = ui->show_routes->keySequence().toString();
|
||||
Configs::dataStore->hotkey_system_proxy_menu = ui->system_proxy->keySequence().toString();
|
||||
Configs::dataStore->hotkey_toggle_system_proxy = ui->toggle_proxy->keySequence().toString();
|
||||
Configs::dataStore->Save();
|
||||
void DialogHotkey::generateShortcutItems(const QList<QAction*>& actions)
|
||||
{
|
||||
auto layout = new QFormLayout(this);
|
||||
auto widget = new QWidget(this);
|
||||
widget->setLayout(layout);
|
||||
ui->shortcut_area->setWidget(widget);
|
||||
for (auto action : actions)
|
||||
{
|
||||
auto kseq = new QtExtKeySequenceEdit(this);
|
||||
if (!action->shortcut().isEmpty()) kseq->setKeySequence(action->shortcut());
|
||||
seqEdit2ID[kseq] = action->data().toString();
|
||||
layout->addRow(action->text(), kseq);
|
||||
}
|
||||
}
|
||||
|
||||
void DialogHotkey::accept()
|
||||
{
|
||||
Configs::dataStore->hotkey_mainwindow = ui->show_mainwindow->keySequence().toString();
|
||||
Configs::dataStore->hotkey_group = ui->show_groups->keySequence().toString();
|
||||
Configs::dataStore->hotkey_route = ui->show_routes->keySequence().toString();
|
||||
Configs::dataStore->hotkey_system_proxy_menu = ui->system_proxy->keySequence().toString();
|
||||
Configs::dataStore->hotkey_toggle_system_proxy = ui->toggle_proxy->keySequence().toString();
|
||||
|
||||
for (auto [kseq, actionID] : seqEdit2ID.asKeyValueRange())
|
||||
{
|
||||
Configs::dataStore->shortcuts->shortcuts[actionID] = kseq->keySequence();
|
||||
}
|
||||
Configs::dataStore->shortcuts->Save();
|
||||
|
||||
Configs::dataStore->Save();
|
||||
MW_dialog_message(Dialog_DialogManageHotkeys, "UpdateShortcuts");
|
||||
GetMainWindow()->RegisterHotkey(false);
|
||||
QDialog::accept();
|
||||
}
|
||||
|
||||
void DialogHotkey::reject()
|
||||
{
|
||||
GetMainWindow()->RegisterHotkey(false);
|
||||
QDialog::reject();
|
||||
}
|
||||
|
||||
DialogHotkey::~DialogHotkey() {
|
||||
delete ui;
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user