mirror of https://github.com/aseprite/aseprite.git
Add support to use mouse buttons as shortcuts (fix #598)
This commit is contained in:
parent
6c7544a132
commit
1e34821897
|
@ -94,6 +94,7 @@ protected:
|
||||||
void onInitTheme(InitThemeEvent& ev) override;
|
void onInitTheme(InitThemeEvent& ev) override;
|
||||||
LayoutIO* onGetLayoutIO() override { return this; }
|
LayoutIO* onGetLayoutIO() override { return this; }
|
||||||
void onNewDisplayConfiguration(Display* display) override;
|
void onNewDisplayConfiguration(Display* display) override;
|
||||||
|
bool onEnqueueMouseDown(MouseMessage* mouseMsg) override;
|
||||||
|
|
||||||
// LayoutIO implementation
|
// LayoutIO implementation
|
||||||
std::string loadLayout(Widget* widget) override;
|
std::string loadLayout(Widget* widget) override;
|
||||||
|
@ -678,6 +679,23 @@ void CustomizedGuiManager::onNewDisplayConfiguration(Display* display)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool CustomizedGuiManager::onEnqueueMouseDown(MouseMessage* mouseMsg)
|
||||||
|
{
|
||||||
|
ASSERT(mouseMsg->type() == kMouseDownMessage);
|
||||||
|
|
||||||
|
// If there is no modal window running...
|
||||||
|
App* app = App::instance();
|
||||||
|
if (app && getForegroundWindow() == app->mainWindow()) {
|
||||||
|
// Process a mouse button as a shortcut.
|
||||||
|
if (processKey(mouseMsg)) {
|
||||||
|
// Don't enqueue this message
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
bool CustomizedGuiManager::processKey(Message* msg)
|
bool CustomizedGuiManager::processKey(Message* msg)
|
||||||
{
|
{
|
||||||
const KeyboardShortcuts* keys = KeyboardShortcuts::instance();
|
const KeyboardShortcuts* keys = KeyboardShortcuts::instance();
|
||||||
|
|
|
@ -507,8 +507,11 @@ const AppShortcut* Key::isPressed(const Message* msg, const KeyContext keyContex
|
||||||
// etc.
|
// etc.
|
||||||
m_keycontext == KeyContext::MouseWheel) {
|
m_keycontext == KeyContext::MouseWheel) {
|
||||||
for (const AppShortcut& shortcut : shortcuts()) {
|
for (const AppShortcut& shortcut : shortcuts()) {
|
||||||
if (shortcut.modifiers() == mouseMsg->modifiers())
|
if ((shortcut.modifiers() == mouseMsg->modifiers()) &&
|
||||||
return &shortcut;
|
(shortcut.mouseButton() == mouseMsg->button()) &&
|
||||||
|
(!best || shortcut.fitsBetterThan(keyContext, keycontext(), keycontext(), *best))) {
|
||||||
|
best = &shortcut;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -57,19 +57,21 @@ protected:
|
||||||
if (keymsg->scancode() == kKeySpace)
|
if (keymsg->scancode() == kKeySpace)
|
||||||
modifiers = (KeyModifiers)(modifiers & ~kKeySpaceModifier);
|
modifiers = (KeyModifiers)(modifiers & ~kKeySpaceModifier);
|
||||||
|
|
||||||
m_shortcut = Shortcut(
|
setAndParseShortcut(
|
||||||
modifiers,
|
Shortcut(modifiers,
|
||||||
keymsg->scancode(),
|
keymsg->scancode(),
|
||||||
keymsg->unicodeChar() > 32 ? std::tolower(keymsg->unicodeChar()) : 0);
|
keymsg->unicodeChar() > 32 ? std::tolower(keymsg->unicodeChar()) : 0));
|
||||||
|
|
||||||
// Convert the shortcut to a string, and parse it
|
return true;
|
||||||
// again. Just to obtain the exact shortcut we'll read
|
}
|
||||||
// when we import the gui.xml file or an .aseprite-keys file.
|
break;
|
||||||
m_shortcut = Shortcut(m_shortcut.toString());
|
|
||||||
|
|
||||||
updateText();
|
case kMouseDownMessage:
|
||||||
|
if (!isReadOnly()) {
|
||||||
|
auto* mouseMsg = static_cast<MouseMessage*>(msg);
|
||||||
|
const KeyModifiers modifiers = mouseMsg->modifiers();
|
||||||
|
|
||||||
ShortcutChange(&m_shortcut);
|
setAndParseShortcut(Shortcut(modifiers, mouseMsg->button()));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -77,9 +79,23 @@ protected:
|
||||||
return Entry::onProcessMessage(msg);
|
return Entry::onProcessMessage(msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void setAndParseShortcut(const Shortcut& shortcut)
|
||||||
|
{
|
||||||
|
// Convert the shortcut to a string, and parse it
|
||||||
|
// again. Just to obtain the exact shortcut we'll read
|
||||||
|
// when we import the gui.xml file or an .aseprite-keys file.
|
||||||
|
m_shortcut = Shortcut(shortcut.toString());
|
||||||
|
|
||||||
|
updateText();
|
||||||
|
|
||||||
|
ShortcutChange(&m_shortcut);
|
||||||
|
}
|
||||||
|
|
||||||
void updateText()
|
void updateText()
|
||||||
{
|
{
|
||||||
setText(Shortcut(kKeyNoneModifier, m_shortcut.scancode(), m_shortcut.unicodeChar()).toString());
|
Shortcut tmp = m_shortcut;
|
||||||
|
tmp.removeModifiers();
|
||||||
|
setText(tmp.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -122,12 +138,16 @@ void SelectShortcut::onModifierChange(KeyModifiers modifier, CheckBox* checkbox)
|
||||||
KeyModifiers modifiers = m_shortcut.modifiers();
|
KeyModifiers modifiers = m_shortcut.modifiers();
|
||||||
KeyScancode scancode = m_shortcut.scancode();
|
KeyScancode scancode = m_shortcut.scancode();
|
||||||
int unicodeChar = m_shortcut.unicodeChar();
|
int unicodeChar = m_shortcut.unicodeChar();
|
||||||
|
MouseButton mouseButton = m_shortcut.mouseButton();
|
||||||
|
|
||||||
modifiers = (KeyModifiers)((modifiers & ~modifier) | (state ? modifier : 0));
|
modifiers = (KeyModifiers)((modifiers & ~modifier) | (state ? modifier : 0));
|
||||||
if (modifiers == kKeySpaceModifier && scancode == kKeySpace)
|
if (modifiers == kKeySpaceModifier && scancode == kKeySpace)
|
||||||
modifiers = kKeyNoneModifier;
|
modifiers = kKeyNoneModifier;
|
||||||
|
|
||||||
m_shortcut = Shortcut(modifiers, scancode, unicodeChar);
|
if (mouseButton != kButtonNone)
|
||||||
|
m_shortcut = Shortcut(modifiers, mouseButton);
|
||||||
|
else
|
||||||
|
m_shortcut = Shortcut(modifiers, scancode, unicodeChar);
|
||||||
|
|
||||||
m_keyField->setShortcut(m_shortcut);
|
m_keyField->setShortcut(m_shortcut);
|
||||||
m_keyField->requestFocus();
|
m_keyField->requestFocus();
|
||||||
|
|
|
@ -652,16 +652,20 @@ void Manager::handleMouseDown(Display* display,
|
||||||
if (!handleWindowZOrder())
|
if (!handleWindowZOrder())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
enqueueMessage(newMouseMessage(kMouseDownMessage,
|
std::unique_ptr<MouseMessage> mouseMsg(
|
||||||
display,
|
newMouseMessage(kMouseDownMessage,
|
||||||
(capture_widget ? capture_widget : mouse_widget),
|
display,
|
||||||
mousePos,
|
(capture_widget ? capture_widget : mouse_widget),
|
||||||
pointerType,
|
mousePos,
|
||||||
mouseButton,
|
pointerType,
|
||||||
modifiers,
|
mouseButton,
|
||||||
gfx::Point(0, 0),
|
modifiers,
|
||||||
false,
|
gfx::Point(0, 0),
|
||||||
pressure));
|
false,
|
||||||
|
pressure));
|
||||||
|
|
||||||
|
if (onEnqueueMouseDown(mouseMsg.get()))
|
||||||
|
enqueueMessage(mouseMsg.release());
|
||||||
}
|
}
|
||||||
|
|
||||||
void Manager::handleMouseUp(Display* display,
|
void Manager::handleMouseUp(Display* display,
|
||||||
|
@ -1847,6 +1851,11 @@ void Manager::onNewDisplayConfiguration(Display* display)
|
||||||
container->flushRedraw();
|
container->flushRedraw();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Manager::onEnqueueMouseDown(MouseMessage* mouseMsg)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
void Manager::onSizeHint(SizeHintEvent& ev)
|
void Manager::onSizeHint(SizeHintEvent& ev)
|
||||||
{
|
{
|
||||||
int w = 0, h = 0;
|
int w = 0, h = 0;
|
||||||
|
@ -2270,16 +2279,16 @@ Widget* Manager::findMagneticWidget(Widget* widget)
|
||||||
}
|
}
|
||||||
|
|
||||||
// static
|
// static
|
||||||
Message* Manager::newMouseMessage(MessageType type,
|
MouseMessage* Manager::newMouseMessage(MessageType type,
|
||||||
Display* display,
|
Display* display,
|
||||||
Widget* widget,
|
Widget* widget,
|
||||||
const gfx::Point& mousePos,
|
const gfx::Point& mousePos,
|
||||||
PointerType pointerType,
|
PointerType pointerType,
|
||||||
MouseButton button,
|
MouseButton button,
|
||||||
KeyModifiers modifiers,
|
KeyModifiers modifiers,
|
||||||
const gfx::Point& wheelDelta,
|
const gfx::Point& wheelDelta,
|
||||||
bool preciseWheel,
|
bool preciseWheel,
|
||||||
float pressure)
|
float pressure)
|
||||||
{
|
{
|
||||||
#ifdef __APPLE__
|
#ifdef __APPLE__
|
||||||
// Convert Ctrl+left click -> right-click
|
// Convert Ctrl+left click -> right-click
|
||||||
|
@ -2290,14 +2299,14 @@ Message* Manager::newMouseMessage(MessageType type,
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
Message* msg = new MouseMessage(type,
|
auto* msg = new MouseMessage(type,
|
||||||
pointerType,
|
pointerType,
|
||||||
button,
|
button,
|
||||||
modifiers,
|
modifiers,
|
||||||
mousePos,
|
mousePos,
|
||||||
wheelDelta,
|
wheelDelta,
|
||||||
preciseWheel,
|
preciseWheel,
|
||||||
pressure);
|
pressure);
|
||||||
|
|
||||||
if (display)
|
if (display)
|
||||||
msg->setDisplay(display);
|
msg->setDisplay(display);
|
||||||
|
|
|
@ -151,6 +151,7 @@ protected:
|
||||||
void onInitTheme(InitThemeEvent& ev) override;
|
void onInitTheme(InitThemeEvent& ev) override;
|
||||||
virtual LayoutIO* onGetLayoutIO();
|
virtual LayoutIO* onGetLayoutIO();
|
||||||
virtual void onNewDisplayConfiguration(Display* display);
|
virtual void onNewDisplayConfiguration(Display* display);
|
||||||
|
virtual bool onEnqueueMouseDown(MouseMessage* mouseMsg);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void generateSetCursorMessage(Display* display,
|
void generateSetCursorMessage(Display* display,
|
||||||
|
@ -206,16 +207,16 @@ private:
|
||||||
static Widget* findLowestCommonAncestor(Widget* a, Widget* b);
|
static Widget* findLowestCommonAncestor(Widget* a, Widget* b);
|
||||||
static bool someParentIsFocusStop(Widget* widget);
|
static bool someParentIsFocusStop(Widget* widget);
|
||||||
static Widget* findMagneticWidget(Widget* widget);
|
static Widget* findMagneticWidget(Widget* widget);
|
||||||
static Message* newMouseMessage(MessageType type,
|
static MouseMessage* newMouseMessage(MessageType type,
|
||||||
Display* display,
|
Display* display,
|
||||||
Widget* widget,
|
Widget* widget,
|
||||||
const gfx::Point& mousePos,
|
const gfx::Point& mousePos,
|
||||||
PointerType pointerType,
|
PointerType pointerType,
|
||||||
MouseButton button,
|
MouseButton button,
|
||||||
KeyModifiers modifiers,
|
KeyModifiers modifiers,
|
||||||
const gfx::Point& wheelDelta = gfx::Point(0, 0),
|
const gfx::Point& wheelDelta = gfx::Point(0, 0),
|
||||||
bool preciseWheel = false,
|
bool preciseWheel = false,
|
||||||
float pressure = 0.0f);
|
float pressure = 0.0f);
|
||||||
void broadcastKeyMsg(Message* msg);
|
void broadcastKeyMsg(Message* msg);
|
||||||
|
|
||||||
static Manager* m_defaultManager;
|
static Manager* m_defaultManager;
|
||||||
|
|
|
@ -142,7 +142,7 @@ int scancode_to_string_size = sizeof(scancode_to_string) / sizeof(scancode_to_st
|
||||||
|
|
||||||
} // anonymous namespace
|
} // anonymous namespace
|
||||||
|
|
||||||
Shortcut::Shortcut() : m_modifiers(kKeyNoneModifier), m_scancode(kKeyNil), m_unicodeChar(0)
|
Shortcut::Shortcut()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -153,10 +153,13 @@ Shortcut::Shortcut(KeyModifiers modifiers, KeyScancode scancode, int unicodeChar
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Shortcut::Shortcut(KeyModifiers modifiers, MouseButton mouseButton)
|
||||||
|
: m_modifiers(modifiers)
|
||||||
|
, m_mouseButton(mouseButton)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
Shortcut::Shortcut(const std::string& str)
|
Shortcut::Shortcut(const std::string& str)
|
||||||
: m_modifiers(kKeyNoneModifier)
|
|
||||||
, m_scancode(kKeyNil)
|
|
||||||
, m_unicodeChar(0)
|
|
||||||
{
|
{
|
||||||
// Special case: plus sign
|
// Special case: plus sign
|
||||||
if (str == "+") {
|
if (str == "+") {
|
||||||
|
@ -270,6 +273,16 @@ Shortcut::Shortcut(const std::string& str)
|
||||||
m_scancode = kKeyDelPad;
|
m_scancode = kKeyDelPad;
|
||||||
else if (tok == "enter pad")
|
else if (tok == "enter pad")
|
||||||
m_scancode = kKeyEnterPad;
|
m_scancode = kKeyEnterPad;
|
||||||
|
else if (tok == "left mouse button")
|
||||||
|
m_mouseButton = kButtonLeft;
|
||||||
|
else if (tok == "right mouse button")
|
||||||
|
m_mouseButton = kButtonRight;
|
||||||
|
else if (tok == "middle mouse button")
|
||||||
|
m_mouseButton = kButtonMiddle;
|
||||||
|
else if (tok == "x1 mouse button")
|
||||||
|
m_mouseButton = kButtonX1;
|
||||||
|
else if (tok == "x2 mouse button")
|
||||||
|
m_mouseButton = kButtonX2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -311,10 +324,23 @@ std::string Shortcut::toString() const
|
||||||
wideUnicodeChar.push_back((wchar_t)std::toupper(m_unicodeChar));
|
wideUnicodeChar.push_back((wchar_t)std::toupper(m_unicodeChar));
|
||||||
buf += base::to_utf8(wideUnicodeChar);
|
buf += base::to_utf8(wideUnicodeChar);
|
||||||
}
|
}
|
||||||
else if (m_scancode > 0 && m_scancode < scancode_to_string_size && scancode_to_string[m_scancode])
|
else if (m_scancode > 0 && m_scancode < scancode_to_string_size &&
|
||||||
|
scancode_to_string[m_scancode]) {
|
||||||
buf += scancode_to_string[m_scancode];
|
buf += scancode_to_string[m_scancode];
|
||||||
else if (!buf.empty() && buf[buf.size() - 1] == '+')
|
}
|
||||||
|
// Mouse button
|
||||||
|
else if (m_mouseButton != kButtonNone) {
|
||||||
|
switch (m_mouseButton) {
|
||||||
|
case kButtonLeft: buf += "Left Mouse Button"; break;
|
||||||
|
case kButtonRight: buf += "Right Mouse Button"; break;
|
||||||
|
case kButtonMiddle: buf += "Middle Mouse Button"; break;
|
||||||
|
case kButtonX1: buf += "X1 Mouse Button"; break;
|
||||||
|
case kButtonX2: buf += "X2 Mouse Button"; break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (!buf.empty() && buf[buf.size() - 1] == '+') {
|
||||||
buf.erase(buf.size() - 1);
|
buf.erase(buf.size() - 1);
|
||||||
|
}
|
||||||
|
|
||||||
return buf;
|
return buf;
|
||||||
}
|
}
|
||||||
|
@ -334,7 +360,7 @@ bool Shortcut::isPressed() const
|
||||||
KeyModifiers pressedModifiers = sys->keyModifiers();
|
KeyModifiers pressedModifiers = sys->keyModifiers();
|
||||||
|
|
||||||
// Check if this shortcut is only
|
// Check if this shortcut is only
|
||||||
if (m_scancode == kKeyNil && m_unicodeChar == 0)
|
if (m_scancode == kKeyNil && m_unicodeChar == 0 && m_mouseButton == kButtonNone)
|
||||||
return (m_modifiers == pressedModifiers);
|
return (m_modifiers == pressedModifiers);
|
||||||
|
|
||||||
// Compare with all pressed scancodes
|
// Compare with all pressed scancodes
|
||||||
|
@ -359,7 +385,7 @@ bool Shortcut::isLooselyPressed() const
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// Check if this shortcut is only
|
// Check if this shortcut is only
|
||||||
if (m_scancode == kKeyNil && m_unicodeChar == 0)
|
if (m_scancode == kKeyNil && m_unicodeChar == 0 && m_mouseButton == kButtonNone)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
// Compare with all pressed scancodes
|
// Compare with all pressed scancodes
|
||||||
|
|
|
@ -9,12 +9,13 @@
|
||||||
#define UI_SHORTCUT_H_INCLUDED
|
#define UI_SHORTCUT_H_INCLUDED
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "ui/keys.h"
|
||||||
|
#include "ui/mouse_button.h"
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "ui/keys.h"
|
|
||||||
|
|
||||||
namespace ui {
|
namespace ui {
|
||||||
|
|
||||||
extern const char* kWinKeyName;
|
extern const char* kWinKeyName;
|
||||||
|
@ -23,6 +24,7 @@ class Shortcut {
|
||||||
public:
|
public:
|
||||||
Shortcut();
|
Shortcut();
|
||||||
Shortcut(KeyModifiers modifiers, KeyScancode scancode, int unicodeChar);
|
Shortcut(KeyModifiers modifiers, KeyScancode scancode, int unicodeChar);
|
||||||
|
Shortcut(KeyModifiers modifiers, MouseButton mouseButton);
|
||||||
// Convert string like "Ctrl+Q" or "Alt+X" into an shortcut.
|
// Convert string like "Ctrl+Q" or "Alt+X" into an shortcut.
|
||||||
explicit Shortcut(const std::string& str);
|
explicit Shortcut(const std::string& str);
|
||||||
|
|
||||||
|
@ -45,11 +47,15 @@ public:
|
||||||
KeyModifiers modifiers() const { return m_modifiers; }
|
KeyModifiers modifiers() const { return m_modifiers; }
|
||||||
KeyScancode scancode() const { return m_scancode; }
|
KeyScancode scancode() const { return m_scancode; }
|
||||||
int unicodeChar() const { return m_unicodeChar; }
|
int unicodeChar() const { return m_unicodeChar; }
|
||||||
|
MouseButton mouseButton() const { return m_mouseButton; }
|
||||||
|
|
||||||
|
void removeModifiers() { m_modifiers = kKeyNoneModifier; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
KeyModifiers m_modifiers;
|
KeyModifiers m_modifiers = kKeyNoneModifier;
|
||||||
KeyScancode m_scancode;
|
KeyScancode m_scancode = kKeyNil;
|
||||||
int m_unicodeChar;
|
int m_unicodeChar = 0;
|
||||||
|
MouseButton m_mouseButton = kButtonNone;
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
|
|
Loading…
Reference in New Issue