Add desktop keyboard shortcuts
Signed-off-by: Vitaliy Vlasov <siphiuel@gmail.com>
This commit is contained in:
parent
2e7d89e690
commit
c8e5fd6a9c
|
@ -74,6 +74,7 @@
|
||||||
"react-native-desktop-linking"
|
"react-native-desktop-linking"
|
||||||
"react-native-desktop-menu"
|
"react-native-desktop-menu"
|
||||||
"react-native-desktop-config"
|
"react-native-desktop-config"
|
||||||
|
"react-native-desktop-shortcuts"
|
||||||
"react-native-desktop-notification"
|
"react-native-desktop-notification"
|
||||||
"text-encoding"
|
"text-encoding"
|
||||||
"js-sha3"
|
"js-sha3"
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
"modules/react-native-desktop-linking/desktop",
|
"modules/react-native-desktop-linking/desktop",
|
||||||
"modules/react-native-desktop-menu/desktop",
|
"modules/react-native-desktop-menu/desktop",
|
||||||
"modules/react-native-desktop-config/desktop",
|
"modules/react-native-desktop-config/desktop",
|
||||||
|
"modules/react-native-desktop-shortcuts/desktop",
|
||||||
"modules/react-native-desktop-notification/desktop",
|
"modules/react-native-desktop-notification/desktop",
|
||||||
"node_modules/google-breakpad"
|
"node_modules/google-breakpad"
|
||||||
],
|
],
|
||||||
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
set(CMAKE_INCLUDE_CURRENT_DIR ON)
|
||||||
|
|
||||||
|
set(REACT_NATIVE_DESKTOP_EXTERNAL_MODULES_TYPE_NAMES ${REACT_NATIVE_DESKTOP_EXTERNAL_MODULES_TYPE_NAMES}
|
||||||
|
\"DesktopShortcuts\" PARENT_SCOPE)
|
||||||
|
|
||||||
|
set(REACT_NATIVE_DESKTOP_EXTERNAL_MODULES_SRC ${REACT_NATIVE_DESKTOP_EXTERNAL_MODULES_SRC}
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/desktopshortcuts.cpp PARENT_SCOPE)
|
||||||
|
|
||||||
|
include(${CMAKE_ROOT}/Modules/ExternalProject.cmake)
|
|
@ -0,0 +1,83 @@
|
||||||
|
#include "desktopshortcuts.h"
|
||||||
|
#include "bridge.h"
|
||||||
|
|
||||||
|
#include "eventdispatcher.h"
|
||||||
|
#include <QDebug>
|
||||||
|
#include <QCoreApplication>
|
||||||
|
#include <QKeySequence>
|
||||||
|
#include <QEvent>
|
||||||
|
#include <QKeyEvent>
|
||||||
|
|
||||||
|
Q_LOGGING_CATEGORY(DESKTOPSHORTCUTS, "DesktopShortcuts")
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
struct RegisterQMLMetaType {
|
||||||
|
RegisterQMLMetaType() { qRegisterMetaType<DesktopShortcuts *>(); }
|
||||||
|
} registerMetaType;
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
DesktopShortcuts::DesktopShortcuts(QObject *parent)
|
||||||
|
: QObject(parent) {
|
||||||
|
QCoreApplication::instance()->installEventFilter(this);
|
||||||
|
connect(this, &DesktopShortcuts::shortcutInvoked, this, &DesktopShortcuts::onShortcutInvoked);
|
||||||
|
}
|
||||||
|
|
||||||
|
DesktopShortcuts::~DesktopShortcuts() {
|
||||||
|
}
|
||||||
|
|
||||||
|
void DesktopShortcuts::setBridge(Bridge *bridge) {
|
||||||
|
this->bridge = bridge;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString DesktopShortcuts::moduleName() { return "DesktopShortcutsManager"; }
|
||||||
|
|
||||||
|
QList<ModuleMethod *> DesktopShortcuts::methodsToExport() {
|
||||||
|
return QList<ModuleMethod *>{};
|
||||||
|
}
|
||||||
|
|
||||||
|
QVariantMap DesktopShortcuts::constantsToExport() { return QVariantMap(); }
|
||||||
|
|
||||||
|
void DesktopShortcuts::registerShortcuts(const QStringList& shortcuts) {
|
||||||
|
//qCDebug(DESKTOPSHORTCUTS) << "registerShortcuts" << shortcuts << " " << shortcuts.size();
|
||||||
|
this->registeredShortcuts = shortcuts;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DesktopShortcuts::eventFilter(QObject* obj, QEvent* event) {
|
||||||
|
if (event->type() == QEvent::KeyPress) {
|
||||||
|
QKeyEvent* ke = static_cast<QKeyEvent*>(event);
|
||||||
|
|
||||||
|
QString modifier;
|
||||||
|
|
||||||
|
if (ke->modifiers() & Qt::ShiftModifier) {
|
||||||
|
modifier += "Shift+";
|
||||||
|
}
|
||||||
|
if (ke->modifiers() & Qt::ControlModifier) {
|
||||||
|
modifier += "Ctrl+";
|
||||||
|
}
|
||||||
|
if (ke->modifiers() & Qt::AltModifier) {
|
||||||
|
modifier += "Alt+";
|
||||||
|
}
|
||||||
|
if (ke->modifiers() & Qt::MetaModifier) {
|
||||||
|
modifier += "Meta+";
|
||||||
|
}
|
||||||
|
QString key = QKeySequence(ke->key()).toString();
|
||||||
|
|
||||||
|
//qCDebug(DESKTOPSHORTCUTS) << "### arrow " << key;
|
||||||
|
if (registeredShortcuts.contains(modifier+key)) {
|
||||||
|
emit shortcutInvoked(modifier+key);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return QObject::eventFilter(obj, event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DesktopShortcuts::onShortcutInvoked(const QString& shortcut) {
|
||||||
|
//qCDebug(DESKTOPSHORTCUTS) << "onShortcutInvoked " << shortcut << " " << registeredShortcuts.size();
|
||||||
|
bridge->eventDispatcher()->sendDeviceEvent("shortcutInvoked", QVariantList{shortcut});
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,41 @@
|
||||||
|
#ifndef DESKTOPSHORTCUTS_H
|
||||||
|
#define DESKTOPSHORTCUTS_H
|
||||||
|
|
||||||
|
#include "moduleinterface.h"
|
||||||
|
|
||||||
|
#include <QLoggingCategory>
|
||||||
|
#include <QMap>
|
||||||
|
|
||||||
|
Q_DECLARE_LOGGING_CATEGORY(SHORTCUTS)
|
||||||
|
|
||||||
|
class DesktopShortcutsPrivate;
|
||||||
|
class DesktopShortcuts : public QObject, public ModuleInterface {
|
||||||
|
Q_OBJECT
|
||||||
|
Q_INTERFACES(ModuleInterface)
|
||||||
|
|
||||||
|
public:
|
||||||
|
Q_INVOKABLE DesktopShortcuts(QObject* parent = 0);
|
||||||
|
virtual ~DesktopShortcuts();
|
||||||
|
|
||||||
|
void setBridge(Bridge* bridge) override;
|
||||||
|
|
||||||
|
QString moduleName() override;
|
||||||
|
QList<ModuleMethod*> methodsToExport() override;
|
||||||
|
QVariantMap constantsToExport() override;
|
||||||
|
|
||||||
|
Q_INVOKABLE void registerShortcuts(const QStringList& shortcuts);
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void shortcutInvoked(const QString& shortcut);
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
void onShortcutInvoked(const QString& shortcut);
|
||||||
|
|
||||||
|
private:
|
||||||
|
Bridge* bridge;
|
||||||
|
|
||||||
|
QStringList registeredShortcuts;
|
||||||
|
bool eventFilter(QObject* obj, QEvent* event) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // DESKTOPSHORTCUTS_H
|
|
@ -0,0 +1,44 @@
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
const NativeModules = require('react-native').NativeModules;
|
||||||
|
const NativeEventEmitter = require('react-native').NativeEventEmitter;
|
||||||
|
|
||||||
|
type Shortcuts = Array<{
|
||||||
|
shortcut?: string,
|
||||||
|
onPress?: ?Function,
|
||||||
|
}>;
|
||||||
|
|
||||||
|
class DesktopShortcuts {
|
||||||
|
constructor() {
|
||||||
|
this.shortcuts = new Map();
|
||||||
|
this.eventEmitter = new NativeEventEmitter(NativeModules.DesktopShortcutsManager);
|
||||||
|
this.eventEmitter.addListener('shortcutInvoked', this.handleShortcut.bind(this));
|
||||||
|
}
|
||||||
|
|
||||||
|
handleShortcut(shortcut) {
|
||||||
|
var fn;// = this.shortcuts.get(shortcut);
|
||||||
|
for (var [key, value] of this.shortcuts) {
|
||||||
|
if (shortcut == key) {
|
||||||
|
fn = value;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (fn) {
|
||||||
|
fn();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
register(shortcuts: Shortcuts): void {
|
||||||
|
//console.log('### register(shortcuts)' + JSON.stringify(shortcuts));
|
||||||
|
this.shortcuts = new Map();
|
||||||
|
|
||||||
|
var shortcutKeys = shortcuts.map(s => s.shortcut);
|
||||||
|
for (let i = 0; i < shortcuts.length; ++i) {
|
||||||
|
this.shortcuts.set(shortcuts[i].shortcut, shortcuts[i].onPress);
|
||||||
|
}
|
||||||
|
|
||||||
|
NativeModules.DesktopShortcutsManager.registerShortcuts(shortcutKeys);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = new DesktopShortcuts();
|
|
@ -0,0 +1,13 @@
|
||||||
|
{
|
||||||
|
"private": true,
|
||||||
|
"nativePackage": true,
|
||||||
|
"name": "react-native-desktop-shortcuts",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "App-global keyboard shortcuts for Desktop",
|
||||||
|
"main": "index.js",
|
||||||
|
"scripts": {
|
||||||
|
"test": "echo \"Error: no test specified\" && exit 1"
|
||||||
|
},
|
||||||
|
"author": "",
|
||||||
|
"license": ""
|
||||||
|
}
|
|
@ -15,7 +15,7 @@
|
||||||
(def desktop-linking (.-DesktopLinking (.-NativeModules react-native)))
|
(def desktop-linking (.-DesktopLinking (.-NativeModules react-native)))
|
||||||
(def desktop-menu (js/require "react-native-desktop-menu"))
|
(def desktop-menu (js/require "react-native-desktop-menu"))
|
||||||
(def desktop-config (js/require "react-native-desktop-config"))
|
(def desktop-config (js/require "react-native-desktop-config"))
|
||||||
|
(def desktop-shortcuts (js/require "react-native-desktop-shortcuts"))
|
||||||
(def react-native-firebase #js {})
|
(def react-native-firebase #js {})
|
||||||
(def camera #js {:default #js {:constants {:Aspect "Portrait"}}})
|
(def camera #js {:default #js {:constants {:Aspect "Portrait"}}})
|
||||||
(def status-keycard #js {:default #js {}})
|
(def status-keycard #js {:default #js {}})
|
||||||
|
|
|
@ -29,3 +29,4 @@
|
||||||
(def desktop-linking #js {:addEventListener (fn [])})
|
(def desktop-linking #js {:addEventListener (fn [])})
|
||||||
(def desktop-menu #js {:addEventListener (fn [])})
|
(def desktop-menu #js {:addEventListener (fn [])})
|
||||||
(def desktop-config #js {:addEventListener (fn [])})
|
(def desktop-config #js {:addEventListener (fn [])})
|
||||||
|
(def desktop-shortcuts #js {:addEventListener (fn [])})
|
||||||
|
|
|
@ -34,6 +34,7 @@ external_modules_dir=( \
|
||||||
'modules/react-native-desktop-linking/desktop' \
|
'modules/react-native-desktop-linking/desktop' \
|
||||||
'modules/react-native-desktop-menu/desktop' \
|
'modules/react-native-desktop-menu/desktop' \
|
||||||
'modules/react-native-desktop-config/desktop' \
|
'modules/react-native-desktop-config/desktop' \
|
||||||
|
'modules/react-native-desktop-shortcuts/desktop' \
|
||||||
'modules/react-native-desktop-notification/desktop' \
|
'modules/react-native-desktop-notification/desktop' \
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
status-im.ui.screens.subs
|
status-im.ui.screens.subs
|
||||||
status-im.data-store.core
|
status-im.data-store.core
|
||||||
[reagent.impl.component :as reagent.component]
|
[reagent.impl.component :as reagent.component]
|
||||||
|
[status-im.ui.components.desktop.shortcuts :as shortcuts]
|
||||||
[status-im.ui.screens.desktop.views :as views]
|
[status-im.ui.screens.desktop.views :as views]
|
||||||
[status-im.core :as core]
|
[status-im.core :as core]
|
||||||
[status-im.desktop.deep-links :as deep-links]))
|
[status-im.desktop.deep-links :as deep-links]))
|
||||||
|
@ -15,6 +16,7 @@
|
||||||
(reagent/create-class
|
(reagent/create-class
|
||||||
{:component-did-mount (fn [this]
|
{:component-did-mount (fn [this]
|
||||||
(re-frame/dispatch [:set-initial-props (reagent/props this)])
|
(re-frame/dispatch [:set-initial-props (reagent/props this)])
|
||||||
|
(shortcuts/register-default-shortcuts)
|
||||||
(deep-links/add-event-listener))
|
(deep-links/add-event-listener))
|
||||||
:reagent-render (fn [props]
|
:reagent-render (fn [props]
|
||||||
views/main)}))
|
views/main)}))
|
||||||
|
|
|
@ -0,0 +1,23 @@
|
||||||
|
(ns status-im.ui.components.desktop.shortcuts
|
||||||
|
(:require [status-im.react-native.js-dependencies :refer [desktop-shortcuts]]
|
||||||
|
[status-im.ui.screens.desktop.main.tabs.home.views :as chat-list]
|
||||||
|
[re-frame.core :as re-frame]
|
||||||
|
[taoensso.timbre :as log]
|
||||||
|
[status-im.utils.utils :as utils]))
|
||||||
|
|
||||||
|
(defn register-shortcut [shortcut on-press]
|
||||||
|
(.set desktop-shortcuts (clj->js {:shortcut shortcut
|
||||||
|
:onPress on-press})))
|
||||||
|
|
||||||
|
(defn register-default-shortcuts []
|
||||||
|
(.register desktop-shortcuts
|
||||||
|
(clj->js (vector
|
||||||
|
{:shortcut "Ctrl+N"
|
||||||
|
:onPress #(re-frame/dispatch [:navigate-to :desktop/new-one-to-one])}
|
||||||
|
{:shortcut "Ctrl+G"
|
||||||
|
:onPress #(re-frame/dispatch [:navigate-to :desktop/new-group-chat])}
|
||||||
|
{:shortcut "Ctrl+P"
|
||||||
|
:onPress #(re-frame/dispatch [:navigate-to :desktop/new-public-chat])}
|
||||||
|
{:shortcut "Ctrl+F"
|
||||||
|
:onPress #(utils/show-popup "" "Ctrl+F")}))))
|
||||||
|
|
|
@ -45,6 +45,7 @@
|
||||||
(when show-error-tooltip?
|
(when show-error-tooltip?
|
||||||
[error-tooltip chat-error])
|
[error-tooltip chat-error])
|
||||||
[react/text-input {:placeholder "name.stateofus.eth"
|
[react/text-input {:placeholder "name.stateofus.eth"
|
||||||
|
:auto-focus true
|
||||||
:flex 1
|
:flex 1
|
||||||
:selection-color colors/blue
|
:selection-color colors/blue
|
||||||
:font :default
|
:font :default
|
||||||
|
@ -108,6 +109,7 @@
|
||||||
[error-tooltip topic-error])
|
[error-tooltip topic-error])
|
||||||
|
|
||||||
[react/text-input {:flex 1
|
[react/text-input {:flex 1
|
||||||
|
:auto-focus true
|
||||||
:font :default
|
:font :default
|
||||||
:selection-color colors/blue
|
:selection-color colors/blue
|
||||||
:placeholder ""
|
:placeholder ""
|
||||||
|
|
|
@ -33,6 +33,7 @@
|
||||||
(def react-native-firebase #js {:default #js {:notifications #js {:Notification Notification}}})
|
(def react-native-firebase #js {:default #js {:notifications #js {:Notification Notification}}})
|
||||||
|
|
||||||
(def desktop-linking #js {:addEventListener (fn [])})
|
(def desktop-linking #js {:addEventListener (fn [])})
|
||||||
|
(def desktop-shortcuts #js {:addEventListener (fn [])})
|
||||||
|
|
||||||
(def snoopy #js {:default #js {}})
|
(def snoopy #js {:default #js {}})
|
||||||
(def snoopy-filter #js {:default #js {}})
|
(def snoopy-filter #js {:default #js {}})
|
||||||
|
|
Loading…
Reference in New Issue