Skip to content

Commit e4c2995

Browse files
committed
Extensions now support defining keyboard shortcuts (aseprite#1403, aseprite#3239)
1 parent 721e401 commit e4c2995

11 files changed

+232
-71
lines changed

data/strings/en.ini

+1
Original file line numberDiff line numberDiff line change
@@ -1282,6 +1282,7 @@ download_themes = Download Themes
12821282
open_theme_folder = Open &Folder
12831283
language_extensions = Languages
12841284
theme_extensions = Themes
1285+
keys_extensions = Keyboard Shortcuts
12851286
script_extensions = Scripts
12861287
palette_extensions = Palettes
12871288
dithering_matrix_extensions = Dithering Matrices

src/app/app_menus.cpp

+15-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
// Aseprite
2-
// Copyright (C) 2019-2020 Igara Studio S.A.
2+
// Copyright (C) 2019-2022 Igara Studio S.A.
33
// Copyright (C) 2001-2018 David Capello
44
//
55
// This program is distributed under the terms of
@@ -16,6 +16,7 @@
1616
#include "app/commands/commands.h"
1717
#include "app/commands/params.h"
1818
#include "app/console.h"
19+
#include "app/extensions.h"
1920
#include "app/gui_xml.h"
2021
#include "app/i18n/strings.h"
2122
#include "app/recent_files.h"
@@ -417,10 +418,22 @@ void AppMenus::reload()
417418
.FirstChild("gui")
418419
.FirstChild("keyboard").ToElement();
419420

421+
// From a fresh start, load the default keys
420422
KeyboardShortcuts::instance()->clear();
421423
KeyboardShortcuts::instance()->importFile(xmlKey, KeySource::Original);
422424

423-
// Load user settings
425+
// Load extension-defined keys
426+
for (const Extension* ext : App::instance()->extensions()) {
427+
if (ext->isEnabled() &&
428+
ext->hasKeys()) {
429+
for (const auto& kv : ext->keys()) {
430+
KeyboardShortcuts::instance()->importFile(
431+
kv.second, KeySource::ExtensionDefined);
432+
}
433+
}
434+
}
435+
436+
// Load user-defined keys
424437
{
425438
ResourceFinder rf;
426439
rf.includeUserDir("user.aseprite-keys");

src/app/commands/cmd_keyboard_shortcuts.cpp

+3-3
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ using namespace ui;
5858

5959
namespace {
6060

61-
typedef std::map<AppMenuItem*, KeyPtr> MenuKeys;
61+
using MenuKeys = std::map<AppMenuItem*, KeyPtr>;
6262

6363
class HeaderSplitter : public Splitter {
6464
public:
@@ -195,7 +195,7 @@ class KeyItem : public ListItem {
195195
window.openWindowInForeground();
196196

197197
if (window.isModified()) {
198-
m_key->disableAccel(origAccel);
198+
m_key->disableAccel(origAccel, KeySource::UserDefined);
199199
if (!window.accel().isEmpty())
200200
m_key->add(window.accel(), KeySource::UserDefined, m_keys);
201201
}
@@ -215,7 +215,7 @@ class KeyItem : public ListItem {
215215
accel.toString())) != 1)
216216
return;
217217

218-
m_key->disableAccel(accel);
218+
m_key->disableAccel(accel, KeySource::UserDefined);
219219
window()->layout();
220220
}
221221

src/app/commands/cmd_options.cpp

+4
Original file line numberDiff line numberDiff line change
@@ -1277,6 +1277,10 @@ class OptionsWindow : public app::gen::Options {
12771277
if (extensionsList()->getItemsCount() > 0)
12781278
return;
12791279

1280+
loadExtensionsByCategory(
1281+
Extension::Category::Keys,
1282+
Strings::options_keys_extensions());
1283+
12801284
loadExtensionsByCategory(
12811285
Extension::Category::Languages,
12821286
Strings::options_language_extensions());

src/app/extensions.cpp

+28-1
Original file line numberDiff line numberDiff line change
@@ -257,6 +257,12 @@ void Extension::executeExitActions()
257257
#endif // ENABLE_SCRIPTING
258258
}
259259

260+
void Extension::addKeys(const std::string& id, const std::string& path)
261+
{
262+
m_keys[id] = path;
263+
updateCategory(Category::Keys);
264+
}
265+
260266
void Extension::addLanguage(const std::string& id, const std::string& path)
261267
{
262268
m_languages[id] = path;
@@ -456,8 +462,10 @@ bool Extension::isDefaultTheme() const
456462

457463
void Extension::updateCategory(const Category newCategory)
458464
{
459-
if (m_category == Category::None)
465+
if (m_category == Category::None ||
466+
m_category == Category::Keys) {
460467
m_category = newCategory;
468+
}
461469
else if (m_category != newCategory)
462470
m_category = Category::Multiple;
463471
}
@@ -1016,6 +1024,24 @@ Extension* Extensions::loadExtension(const std::string& path,
10161024

10171025
auto contributes = json["contributes"];
10181026
if (contributes.is_object()) {
1027+
// Keys
1028+
auto keys = contributes["keys"];
1029+
if (keys.is_array()) {
1030+
for (const auto& key : keys.array_items()) {
1031+
std::string keyId = key["id"].string_value();
1032+
std::string keyPath = key["path"].string_value();
1033+
1034+
// The path must be always relative to the extension
1035+
keyPath = base::join_path(path, keyPath);
1036+
1037+
LOG("EXT: New keyboard shortcuts '%s' in '%s'\n",
1038+
keyId.c_str(),
1039+
keyPath.c_str());
1040+
1041+
extension->addKeys(keyId, keyPath);
1042+
}
1043+
}
1044+
10191045
// Languages
10201046
auto languages = contributes["languages"];
10211047
if (languages.is_array()) {
@@ -1130,6 +1156,7 @@ Extension* Extensions::loadExtension(const std::string& path,
11301156

11311157
void Extensions::generateExtensionSignals(Extension* extension)
11321158
{
1159+
if (extension->hasKeys()) KeysChange(extension);
11331160
if (extension->hasLanguages()) LanguagesChange(extension);
11341161
if (extension->hasThemes()) ThemesChange(extension);
11351162
if (extension->hasPalettes()) PalettesChange(extension);

src/app/extensions.h

+7-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
// Aseprite
2-
// Copyright (C) 2020 Igara Studio S.A.
2+
// Copyright (C) 2020-2022 Igara Studio S.A.
33
// Copyright (C) 2017-2018 David Capello
44
//
55
// This program is distributed under the terms of
@@ -36,6 +36,7 @@ namespace app {
3636
public:
3737
enum class Category {
3838
None,
39+
Keys,
3940
Languages,
4041
Themes,
4142
Scripts,
@@ -78,10 +79,12 @@ namespace app {
7879
const std::string& displayName() const { return m_displayName; }
7980
const Category category() const { return m_category; }
8081

82+
const ExtensionItems& keys() const { return m_keys; }
8183
const ExtensionItems& languages() const { return m_languages; }
8284
const ExtensionItems& themes() const { return m_themes; }
8385
const ExtensionItems& palettes() const { return m_palettes; }
8486

87+
void addKeys(const std::string& id, const std::string& path);
8588
void addLanguage(const std::string& id, const std::string& path);
8689
void addTheme(const std::string& id, const std::string& path);
8790
void addPalette(const std::string& id, const std::string& path);
@@ -98,6 +101,7 @@ namespace app {
98101
bool canBeDisabled() const;
99102
bool canBeUninstalled() const;
100103

104+
bool hasKeys() const { return !m_keys.empty(); }
101105
bool hasLanguages() const { return !m_languages.empty(); }
102106
bool hasThemes() const { return !m_themes.empty(); }
103107
bool hasPalettes() const { return !m_palettes.empty(); }
@@ -119,6 +123,7 @@ namespace app {
119123
void exitScripts();
120124
#endif
121125

126+
ExtensionItems m_keys;
122127
ExtensionItems m_languages;
123128
ExtensionItems m_themes;
124129
ExtensionItems m_palettes;
@@ -180,6 +185,7 @@ namespace app {
180185
std::vector<Extension::DitheringMatrixInfo> ditheringMatrices();
181186

182187
obs::signal<void(Extension*)> NewExtension;
188+
obs::signal<void(Extension*)> KeysChange;
183189
obs::signal<void(Extension*)> LanguagesChange;
184190
obs::signal<void(Extension*)> ThemesChange;
185191
obs::signal<void(Extension*)> PalettesChange;

src/app/ui/key.h

+24-15
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
// Aseprite
2-
// Copyright (C) 2018 Igara Studio S.A.
2+
// Copyright (C) 2018-2022 Igara Studio S.A.
33
// Copyright (C) 2001-2018 David Capello
44
//
55
// This program is distributed under the terms of
@@ -15,6 +15,7 @@
1515
#include "ui/accelerator.h"
1616

1717
#include <memory>
18+
#include <utility>
1819
#include <vector>
1920

2021
namespace ui {
@@ -31,6 +32,7 @@ namespace app {
3132

3233
enum class KeySource {
3334
Original,
35+
ExtensionDefined,
3436
UserDefined
3537
};
3638

@@ -98,20 +100,20 @@ namespace app {
98100
return KeyAction(int(a) & int(b));
99101
}
100102

103+
using KeySourceAccelList = std::vector<std::pair<KeySource, ui::Accelerator>>;
104+
101105
class Key {
102106
public:
107+
Key(const Key& key);
103108
Key(Command* command, const Params& params, KeyContext keyContext);
104109
Key(KeyType type, tools::Tool* tool);
105110
explicit Key(KeyAction action);
106111
explicit Key(WheelAction action);
107112

108113
KeyType type() const { return m_type; }
109-
const ui::Accelerators& accels() const {
110-
return (m_useUsers ? m_users: m_accels);
111-
}
112-
const ui::Accelerators& origAccels() const { return m_accels; }
113-
const ui::Accelerators& userAccels() const { return m_users; }
114-
const ui::Accelerators& userRemovedAccels() const { return m_userRemoved; }
114+
const ui::Accelerators& accels() const;
115+
const KeySourceAccelList addsKeys() const { return m_adds; }
116+
const KeySourceAccelList delsKeys() const { return m_dels; }
115117

116118
void add(const ui::Accelerator& accel,
117119
const KeySource source,
@@ -122,9 +124,15 @@ namespace app {
122124
bool isLooselyPressed() const;
123125

124126
bool hasAccel(const ui::Accelerator& accel) const;
125-
void disableAccel(const ui::Accelerator& accel);
127+
bool hasUserDefinedAccels() const;
128+
129+
// The KeySource indicates from where the key was disabled
130+
// (e.g. if it was removed from an extension-defined file, or from
131+
// user-defined).
132+
void disableAccel(const ui::Accelerator& accel,
133+
const KeySource source);
126134

127-
// Resets user accelerators to the original ones.
135+
// Resets user accelerators to the original & extension-defined ones.
128136
void reset();
129137

130138
void copyOriginalToUser();
@@ -144,10 +152,11 @@ namespace app {
144152

145153
private:
146154
KeyType m_type;
147-
ui::Accelerators m_accels; // Default accelerators (from gui.xml)
148-
ui::Accelerators m_users; // User-defined accelerators
149-
ui::Accelerators m_userRemoved; // Default accelerators removed by user
150-
bool m_useUsers;
155+
KeySourceAccelList m_adds;
156+
KeySourceAccelList m_dels;
157+
// Final list of accelerators after processing the
158+
// addition/deletion of extension-defined & user-defined keys.
159+
mutable std::unique_ptr<ui::Accelerators> m_accels;
151160
KeyContext m_keycontext;
152161

153162
// for KeyType::Command
@@ -161,8 +170,8 @@ namespace app {
161170
WheelAction m_wheelAction;
162171
};
163172

164-
typedef std::shared_ptr<Key> KeyPtr;
165-
typedef std::vector<KeyPtr> Keys;
173+
using KeyPtr = std::shared_ptr<Key> ;
174+
using Keys = std::vector<KeyPtr>;
166175

167176
std::string convertKeyContextToString(KeyContext keyContext);
168177
std::string convertKeyContextToUserFriendlyString(KeyContext keyContext);

0 commit comments

Comments
 (0)