summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEduard Braun <Eduard.Braun2@gmx.de>2017-06-18 17:54:03 +0000
committerEduard Braun <eduard.braun2@gmx.de>2017-06-23 21:55:03 +0000
commit46fd67ec49c3988db20db422061a2f52582c896c (patch)
treea302a68c1694ffa59872d0b50f611f97f68981ec
parentMerge branch 'ui-files-for-ui-xml' (diff)
downloadinkscape-46fd67ec49c3988db20db422061a2f52582c896c.tar.gz
inkscape-46fd67ec49c3988db20db422061a2f52582c896c.zip
Improve and simplify shortcut handling.
Should fix many issues with unusuable keys, especially on non-English keyboard layouts.
-rw-r--r--src/helper/window.cpp10
-rw-r--r--src/main.cpp2
-rw-r--r--src/shortcuts.cpp91
-rw-r--r--src/shortcuts.h4
-rw-r--r--src/ui/dialog/dialog.cpp8
-rw-r--r--src/ui/dialog/inkscape-preferences.cpp2
-rw-r--r--src/ui/dialog/objects.cpp8
-rw-r--r--src/ui/dialog/xml-tree.cpp8
-rw-r--r--src/ui/tools/pen-tool.cpp8
-rw-r--r--src/ui/tools/tool-base.cpp29
-rw-r--r--src/ui/tools/tool-base.h2
11 files changed, 97 insertions, 75 deletions
diff --git a/src/helper/window.cpp b/src/helper/window.cpp
index 98e886a38..28fc25606 100644
--- a/src/helper/window.cpp
+++ b/src/helper/window.cpp
@@ -13,20 +13,12 @@
#include "desktop.h"
#include "inkscape.h"
#include "shortcuts.h"
-#include "ui/tools/tool-base.h"
#include "window.h"
static bool on_window_key_press(GdkEventKey* event)
{
unsigned shortcut = 0;
- // FIXME why?
- shortcut = Inkscape::UI::Tools::get_group0_keyval (event) |
- ( event->state & GDK_SHIFT_MASK ?
- SP_SHORTCUT_SHIFT_MASK : 0 ) |
- ( event->state & GDK_CONTROL_MASK ?
- SP_SHORTCUT_CONTROL_MASK : 0 ) |
- ( event->state & GDK_MOD1_MASK ?
- SP_SHORTCUT_ALT_MASK : 0 );
+ shortcut = sp_shortcut_get_for_event(event);
return sp_shortcut_invoke (shortcut, SP_ACTIVE_DESKTOP);
}
diff --git a/src/main.cpp b/src/main.cpp
index 7a786234e..a40d44afe 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -932,7 +932,7 @@ namespace Inkscape {
namespace UI {
namespace Tools {
-guint get_group0_keyval(GdkEventKey const* event);
+guint get_group0_keyval(GdkEventKey const* event, guint *consumed_modifiers = NULL);
}
}
diff --git a/src/shortcuts.cpp b/src/shortcuts.cpp
index e74d60abc..6c8ccd2ee 100644
--- a/src/shortcuts.cpp
+++ b/src/shortcuts.cpp
@@ -107,29 +107,90 @@ static void try_shortcuts_file(char const *filename) {
}
/*
- * Inkscape expects to add the Shift modifier to any accel_keys create with Shift
- * For exmaple on en_US keyboard <Shift>+6 = "&" - in this case return <Shift>+&
- * See get_group0_keyval() for explanation on why
+ * Return the keyval corresponding to the key event in group 0 and the effective modifiers.
+ *
+ * Usage of group 0 (i.e. the main, typically English layout) instead of simply event->keyval
+ * ensures that shortcuts work regardless of the active keyboard layouts (e.g. Cyrillic).
+ *
+ * The effective modifiers are the modifers that were not "consumed" by the translation and
+ * can be used by the application to define a shortcut, e.g.
+ * - when pressing "Shift+9" the resulting character is "("
+ * the shift key was "consumed" to make this character and should not be part of the shortcut
+ * - when pressing "Ctrl+9" the resulting character is also "9"
+ * the ctrl key was *not* consumed to make this character and must be included in the shortcut
+ * - Exception: letter keys like [A-Z] always need the shift modifier,
+ * otherwise lower case and uper case keys are treated as equivalent
+ * The modifier values are already transformed from the default GDK_*_MASK into the equivalent high-bit masks
+ * defined by SP_SHORTCUT_*_MASK to allow for subsequent packing of the whole shortcut into a single int
+ *
+ * Note: Don't call this function directly but use the wrappers
+ * - sp_shortcut_get_from_event() - create a new shortcut from a key event
+ * - sp_shortcut_get_for_event() - get an existing shortcut for a key event
+ * (they correctly handle the packing of modifier keys into the keyval)
+ */
+guint sp_shortcut_translate_event(GdkEventKey const *event, guint *effective_modifiers) {
+ guint keyval = 0;
+
+ guint initial_modifiers = event->state;
+ guint consumed_modifiers = 0;
+ guint remaining_modifiers = 0;
+ guint resulting_modifiers = 0; // remaining modifiers encoded in high-bit mask
+
+ keyval = Inkscape::UI::Tools::get_group0_keyval(event, &consumed_modifiers);
+
+ remaining_modifiers = initial_modifiers & ~consumed_modifiers;
+ resulting_modifiers = ( remaining_modifiers & GDK_SHIFT_MASK ? SP_SHORTCUT_SHIFT_MASK : 0 ) |
+ ( remaining_modifiers & GDK_CONTROL_MASK ? SP_SHORTCUT_CONTROL_MASK : 0 ) |
+ ( remaining_modifiers & GDK_MOD1_MASK ? SP_SHORTCUT_ALT_MASK : 0 );
+
+ // enforce the Shift modifier for uppercase letters (otherwise plain A and Shift+A are equivalent)
+ // for characters that are not letters both (is_upper and is_lower) return TRUE, so the condition is false
+ if (gdk_keyval_is_upper(keyval) && !gdk_keyval_is_lower(keyval)) {
+ resulting_modifiers |= SP_SHORTCUT_SHIFT_MASK;
+ }
+
+ *effective_modifiers = resulting_modifiers;
+ return keyval;
+}
+
+/*
+ * Returns a new Inkscape shortcut parsed from a key event.
*/
-unsigned int sp_gdkmodifier_to_shortcut(guint accel_key, Gdk::ModifierType gdkmodifier, guint hardware_keycode) {
+unsigned int sp_shortcut_get_from_event(GdkEventKey const *event) {
+ guint effective_modifiers;
+
+ sp_shortcut_translate_event(event, &effective_modifiers);
+ // return the actual keyval and the corresponding modifiers for creating the shortcut
+ // we must not return the translated keyval, otherwise we end up with illegal shortcuts like "Shift+9" instead of "("
+ return (event->keyval) | effective_modifiers;
+}
- unsigned int shortcut = 0;
+/*
+ * Returns a new Inkscape shortcut parsed from a key event.
+ * (equivalent to sp_shortcut_get_from_event() but accepts the arguments of Gtk::CellRendererAccel::signal_accel_edited)
+ */
+unsigned int sp_shortcut_get_from_gdk_event(guint accel_key, Gdk::ModifierType accel_mods, guint hardware_keycode) {
GdkEventKey event;
- event.state = gdkmodifier;
event.keyval = accel_key;
+ event.state = accel_mods;
event.hardware_keycode = hardware_keycode;
- guint keyval = Inkscape::UI::Tools::get_group0_keyval (&event);
- shortcut = accel_key |
- ( (gdkmodifier & GDK_SHIFT_MASK) || ( accel_key != keyval) ?
- SP_SHORTCUT_SHIFT_MASK : 0 ) |
- ( gdkmodifier & GDK_CONTROL_MASK ?
- SP_SHORTCUT_CONTROL_MASK : 0 ) |
- ( gdkmodifier & GDK_MOD1_MASK ?
- SP_SHORTCUT_ALT_MASK : 0 );
+ return sp_shortcut_get_from_event(&event);
+}
+
+/*
+ * Returns the Inkscape-internal integral shortcut representation for a key event.
+ * Use this to compare the received key event to known shortcuts.
+ */
+unsigned int sp_shortcut_get_for_event(GdkEventKey const *event) {
+ guint keyval;
+ guint effective_modifiers;
+
+ keyval = sp_shortcut_translate_event(event, &effective_modifiers);
- return shortcut;
+ // return the keyval translated to group 0 (English keyboard layout) and corresponding modifiers
+ return keyval | effective_modifiers;
}
Glib::ustring sp_shortcut_to_label(unsigned int const shortcut) {
diff --git a/src/shortcuts.h b/src/shortcuts.h
index f24a82603..25893378c 100644
--- a/src/shortcuts.h
+++ b/src/shortcuts.h
@@ -46,7 +46,9 @@ void sp_shortcut_add_to_file(char const *action, unsigned int const shortcut);
void sp_shortcut_delete_from_file(char const *action, unsigned int const shortcut);
void sp_shortcuts_delete_all_from_file();
Glib::ustring sp_shortcut_to_label(unsigned int const shortcut);
-unsigned int sp_gdkmodifier_to_shortcut(unsigned int accel_key, Gdk::ModifierType gdkmodifier, unsigned int hardware_keycode);
+unsigned int sp_shortcut_get_from_event(GdkEventKey const *event);
+unsigned int sp_shortcut_get_from_gdk_event(unsigned int accel_key, Gdk::ModifierType accel_mods, unsigned int hardware_keycode);
+unsigned int sp_shortcut_get_for_event(GdkEventKey const *event);
void sp_shortcut_get_file_names(std::vector<Glib::ustring> *names, std::vector<Glib::ustring> *paths);
bool sp_shortcut_is_user_set(Inkscape::Verb *verb);
void sp_shortcut_file_export();
diff --git a/src/ui/dialog/dialog.cpp b/src/ui/dialog/dialog.cpp
index 27a6e55d9..f36b13d9b 100644
--- a/src/ui/dialog/dialog.cpp
+++ b/src/ui/dialog/dialog.cpp
@@ -266,13 +266,7 @@ bool Dialog::_onEvent(GdkEvent *event)
bool Dialog::_onKeyPress(GdkEventKey *event)
{
unsigned int shortcut;
- shortcut = Inkscape::UI::Tools::get_group0_keyval(event) |
- ( event->state & GDK_SHIFT_MASK ?
- SP_SHORTCUT_SHIFT_MASK : 0 ) |
- ( event->state & GDK_CONTROL_MASK ?
- SP_SHORTCUT_CONTROL_MASK : 0 ) |
- ( event->state & GDK_MOD1_MASK ?
- SP_SHORTCUT_ALT_MASK : 0 );
+ shortcut = sp_shortcut_get_for_event((GdkEventKey*)event);
return sp_shortcut_invoke(shortcut, SP_ACTIVE_DESKTOP);
}
diff --git a/src/ui/dialog/inkscape-preferences.cpp b/src/ui/dialog/inkscape-preferences.cpp
index 646439613..43fac11aa 100644
--- a/src/ui/dialog/inkscape-preferences.cpp
+++ b/src/ui/dialog/inkscape-preferences.cpp
@@ -1679,7 +1679,7 @@ void InkscapePreferences::onKBTreeEdited (const Glib::ustring& path, guint accel
return;
}
- unsigned int const new_shortcut_id = sp_gdkmodifier_to_shortcut(accel_key, accel_mods, hardware_keycode);
+ unsigned int const new_shortcut_id = sp_shortcut_get_from_gdk_event(accel_key, accel_mods, hardware_keycode);
if (new_shortcut_id) {
// Delete current shortcut if it existed
diff --git a/src/ui/dialog/objects.cpp b/src/ui/dialog/objects.cpp
index fd78fec90..92557b1a3 100644
--- a/src/ui/dialog/objects.cpp
+++ b/src/ui/dialog/objects.cpp
@@ -701,13 +701,7 @@ bool ObjectsPanel::_handleKeyEvent(GdkEventKey *event)
return false;
unsigned int shortcut;
- shortcut = Inkscape::UI::Tools::get_group0_keyval(event) |
- ( event->state & GDK_SHIFT_MASK ?
- SP_SHORTCUT_SHIFT_MASK : 0 ) |
- ( event->state & GDK_CONTROL_MASK ?
- SP_SHORTCUT_CONTROL_MASK : 0 ) |
- ( event->state & GDK_MOD1_MASK ?
- SP_SHORTCUT_ALT_MASK : 0 );
+ shortcut = sp_shortcut_get_for_event(event);
switch (shortcut) {
// how to get users key binding for the action “start-interactive-search” ??
diff --git a/src/ui/dialog/xml-tree.cpp b/src/ui/dialog/xml-tree.cpp
index fa35b092a..72aaadb9f 100644
--- a/src/ui/dialog/xml-tree.cpp
+++ b/src/ui/dialog/xml-tree.cpp
@@ -327,13 +327,7 @@ void XmlTree::attr_reset_context(gint attr)
bool XmlTree::sp_xml_tree_key_press(GdkEventKey *event)
{
- unsigned int shortcut = Inkscape::UI::Tools::get_group0_keyval (event) |
- ( event->state & GDK_SHIFT_MASK ?
- SP_SHORTCUT_SHIFT_MASK : 0 ) |
- ( event->state & GDK_CONTROL_MASK ?
- SP_SHORTCUT_CONTROL_MASK : 0 ) |
- ( event->state & GDK_MOD1_MASK ?
- SP_SHORTCUT_ALT_MASK : 0 );
+ unsigned int shortcut = sp_shortcut_get_for_event((GdkEventKey*)event);
/* fixme: if you need to add more xml-tree-specific callbacks, you should probably upgrade
* the sp_shortcut mechanism to take into account windows. */
diff --git a/src/ui/tools/pen-tool.cpp b/src/ui/tools/pen-tool.cpp
index caf6faec2..0422dc9cd 100644
--- a/src/ui/tools/pen-tool.cpp
+++ b/src/ui/tools/pen-tool.cpp
@@ -1050,13 +1050,7 @@ bool PenTool::_handleKeyPress(GdkEvent *event) {
// Check for undo if we have started drawing a path.
if (this->npoints > 0) {
- unsigned int shortcut = Inkscape::UI::Tools::get_group0_keyval (&event->key) |
- ( event->key.state & GDK_SHIFT_MASK ?
- SP_SHORTCUT_SHIFT_MASK : 0 ) |
- ( event->key.state & GDK_CONTROL_MASK ?
- SP_SHORTCUT_CONTROL_MASK : 0 ) |
- ( event->key.state & GDK_MOD1_MASK ?
- SP_SHORTCUT_ALT_MASK : 0 );
+ unsigned int shortcut = sp_shortcut_get_for_event((GdkEventKey*)event);
Inkscape::Verb* verb = sp_shortcut_get_verb(shortcut);
if (verb) {
unsigned int vcode = verb->get_code();
diff --git a/src/ui/tools/tool-base.cpp b/src/ui/tools/tool-base.cpp
index 3d755eadc..490d0fb26 100644
--- a/src/ui/tools/tool-base.cpp
+++ b/src/ui/tools/tool-base.cpp
@@ -589,20 +589,7 @@ bool ToolBase::root_handler(GdkEvent* event) {
case GDK_KEY_Tab:
case GDK_KEY_ISO_Left_Tab:
case GDK_KEY_F1:
- shortcut = get_group0_keyval(&event->key);
-
- if (event->key.state & GDK_SHIFT_MASK) {
- shortcut |= SP_SHORTCUT_SHIFT_MASK;
- }
-
- if (event->key.state & GDK_CONTROL_MASK) {
- shortcut |= SP_SHORTCUT_CONTROL_MASK;
- }
-
- if (event->key.state & GDK_MOD1_MASK) {
- shortcut |= SP_SHORTCUT_ALT_MASK;
- }
-
+ shortcut = sp_shortcut_get_for_event((GdkEventKey*)event);
ret = sp_shortcut_invoke(shortcut, desktop);
break;
@@ -1153,14 +1140,18 @@ void sp_event_show_modifier_tip(Inkscape::MessageContext *message_context,
* Use this instead of simply event->keyval, so that your keyboard shortcuts
* work regardless of layouts (e.g., in Cyrillic).
*/
-guint get_group0_keyval(GdkEventKey const *event) {
+guint get_group0_keyval(GdkEventKey const *event, guint *consumed_modifiers /*= NULL*/) {
guint keyval = 0;
+ GdkModifierType modifiers;
- gdk_keymap_translate_keyboard_state(gdk_keymap_get_for_display(
- gdk_display_get_default()), event->hardware_keycode,
- (GdkModifierType) event->state, 0 /*event->key.group*/, &keyval,
- NULL, NULL, NULL);
+ gdk_keymap_translate_keyboard_state(
+ gdk_keymap_get_for_display(gdk_display_get_default()),
+ event->hardware_keycode, (GdkModifierType) event->state, 0 /*event->group*/,
+ &keyval, NULL, NULL, &modifiers);
+ if (consumed_modifiers) {
+ *consumed_modifiers = modifiers;
+ }
return keyval;
}
diff --git a/src/ui/tools/tool-base.h b/src/ui/tools/tool-base.h
index 3d22fc66f..69533e417 100644
--- a/src/ui/tools/tool-base.h
+++ b/src/ui/tools/tool-base.h
@@ -252,7 +252,7 @@ gint gobble_motion_events(gint mask);
void sp_event_show_modifier_tip(Inkscape::MessageContext *message_context, GdkEvent *event,
gchar const *ctrl_tip, gchar const *shift_tip, gchar const *alt_tip);
-guint get_group0_keyval(GdkEventKey const *event);
+guint get_group0_keyval(GdkEventKey const *event, guint *consumed_modifiers = NULL);
SPItem *sp_event_context_find_item (SPDesktop *desktop, Geom::Point const &p, bool select_under, bool into_groups);
SPItem *sp_event_context_over_item (SPDesktop *desktop, SPItem *item, Geom::Point const &p);