diff --git a/gtk2_ardour/ardour_dialog.cc b/gtk2_ardour/ardour_dialog.cc index 5affa6e363..63c32e8c2d 100644 --- a/gtk2_ardour/ardour_dialog.cc +++ b/gtk2_ardour/ardour_dialog.cc @@ -32,6 +32,7 @@ using namespace std; using namespace sigc; using namespace Gtk; +using namespace Gtkmm2ext; sigc::signal ArdourDialog::CloseAllDialogs; diff --git a/gtk2_ardour/ardour_ui.cc b/gtk2_ardour/ardour_ui.cc index 234f05705d..28dd679f10 100644 --- a/gtk2_ardour/ardour_ui.cc +++ b/gtk2_ardour/ardour_ui.cc @@ -274,7 +274,12 @@ ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[]) /* we like keyboards */ - keyboard = new Keyboard; + keyboard = new ArdourKeyboard; + + XMLNode* node = ARDOUR_UI::instance()->keyboard_settings(); + if (node) { + keyboard->set_state (*node, Stateful::loading_state_version); + } reset_dpi(); diff --git a/gtk2_ardour/ardour_ui.h b/gtk2_ardour/ardour_ui.h index 1d279ff281..f356db6c0a 100644 --- a/gtk2_ardour/ardour_ui.h +++ b/gtk2_ardour/ardour_ui.h @@ -70,11 +70,11 @@ class About; class AddRouteDialog; class ArdourStartup; +class ArdourKeyboard; class AudioClock; class BundleManager; class ConnectionEditor; class KeyEditor; -class Keyboard; class LocationUIWindow; class Mixer_UI; class PublicEditor; @@ -596,8 +596,8 @@ class ARDOUR_UI : public Gtkmm2ext::UI /* Keyboard Handling */ - Keyboard* keyboard; - + ArdourKeyboard* keyboard; + /* Keymap handling */ void install_actions (); diff --git a/gtk2_ardour/ardour_ui_dependents.cc b/gtk2_ardour/ardour_ui_dependents.cc index 9a9a575e73..0b6b327e8b 100644 --- a/gtk2_ardour/ardour_ui_dependents.cc +++ b/gtk2_ardour/ardour_ui_dependents.cc @@ -58,9 +58,7 @@ ARDOUR_UI::we_have_dependents () { install_actions (); ProcessorBox::register_actions (); - - Keyboard::setup_keybindings (); - + keyboard->setup_keybindings (); editor->UpdateAllTransportClocks.connect (mem_fun (*this, &ARDOUR_UI::update_transport_clocks)); } diff --git a/gtk2_ardour/audio_clock.cc b/gtk2_ardour/audio_clock.cc index 8235aca5d5..1e9e24e5bc 100644 --- a/gtk2_ardour/audio_clock.cc +++ b/gtk2_ardour/audio_clock.cc @@ -43,6 +43,8 @@ using namespace sigc; using namespace Gtk; using namespace std; +using Gtkmm2ext::Keyboard; + using PBD::atoi; using PBD::atof; diff --git a/gtk2_ardour/crossfade_edit.cc b/gtk2_ardour/crossfade_edit.cc index cc8d487185..c20b7c492a 100644 --- a/gtk2_ardour/crossfade_edit.cc +++ b/gtk2_ardour/crossfade_edit.cc @@ -57,6 +57,8 @@ using namespace Gtk; using namespace sigc; using namespace Editing; +using Gtkmm2ext::Keyboard; + #include "i18n.h" const int32_t CrossfadeEditor::Point::size = 7; diff --git a/gtk2_ardour/editor.cc b/gtk2_ardour/editor.cc index 54f73e2f4c..817b02ea29 100644 --- a/gtk2_ardour/editor.cc +++ b/gtk2_ardour/editor.cc @@ -125,6 +125,7 @@ using namespace Editing; using PBD::internationalize; using PBD::atoi; +using Gtkmm2ext::Keyboard; const double Editor::timebar_height = 15.0; diff --git a/gtk2_ardour/editor_canvas_events.cc b/gtk2_ardour/editor_canvas_events.cc index 525abf8d00..cf03587e8a 100644 --- a/gtk2_ardour/editor_canvas_events.cc +++ b/gtk2_ardour/editor_canvas_events.cc @@ -59,6 +59,8 @@ using namespace PBD; using namespace Gtk; using namespace ArdourCanvas; +using Gtkmm2ext::Keyboard; + bool Editor::track_canvas_scroll (GdkEventScroll* ev) { diff --git a/gtk2_ardour/editor_drag.cc b/gtk2_ardour/editor_drag.cc index f24463ef45..4c68a3f495 100644 --- a/gtk2_ardour/editor_drag.cc +++ b/gtk2_ardour/editor_drag.cc @@ -48,6 +48,8 @@ using namespace Gtk; using namespace Editing; using namespace ArdourCanvas; +using Gtkmm2ext::Keyboard; + double const ControlPointDrag::_zero_gain_fraction = gain_to_slider_position (dB_to_coefficient (0.0)); Drag::Drag (Editor* e, ArdourCanvas::Item* i) @@ -2181,7 +2183,7 @@ MarkerDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor) _editor->show_verbose_time_cursor (location->end(), 10); } - Selection::Operation op = Keyboard::selection_type (event->button.state); + Selection::Operation op = ArdourKeyboard::selection_type (event->button.state); switch (op) { case Selection::Toggle: @@ -2394,7 +2396,7 @@ MarkerDrag::finished (GdkEvent* event, bool movement_occurred) off the selection process */ - Selection::Operation op = Keyboard::selection_type (event->button.state); + Selection::Operation op = ArdourKeyboard::selection_type (event->button.state); switch (op) { case Selection::Set: @@ -2748,7 +2750,7 @@ RubberbandSelectDrag::finished (GdkEvent* event, bool movement_occurred) } - Selection::Operation op = Keyboard::selection_type (event->button.state); + Selection::Operation op = ArdourKeyboard::selection_type (event->button.state); bool committed; _editor->begin_reversible_command (_("rubberband selection")); diff --git a/gtk2_ardour/editor_mouse.cc b/gtk2_ardour/editor_mouse.cc index 1b0f5bb229..56acaf1077 100644 --- a/gtk2_ardour/editor_mouse.cc +++ b/gtk2_ardour/editor_mouse.cc @@ -79,6 +79,7 @@ using namespace PBD; using namespace sigc; using namespace Gtk; using namespace Editing; +using Gtkmm2ext::Keyboard; bool Editor::mouse_frame (nframes64_t& where, bool& in_track_canvas) const @@ -440,7 +441,7 @@ Editor::button_selection (ArdourCanvas::Item* /*item*/, GdkEvent* event, ItemTyp } } - Selection::Operation op = Keyboard::selection_type (event->button.state); + Selection::Operation op = ArdourKeyboard::selection_type (event->button.state); bool press = (event->type == GDK_BUTTON_PRESS); // begin_reversible_command (_("select on click")); diff --git a/gtk2_ardour/editor_ops.cc b/gtk2_ardour/editor_ops.cc index 3b60f3c903..833ac580a2 100644 --- a/gtk2_ardour/editor_ops.cc +++ b/gtk2_ardour/editor_ops.cc @@ -88,6 +88,7 @@ using namespace sigc; using namespace Gtk; using namespace Gtkmm2ext; using namespace Editing; +using Gtkmm2ext::Keyboard; /*********************************************************************** Editor operations diff --git a/gtk2_ardour/editor_regions.cc b/gtk2_ardour/editor_regions.cc index 697c46bba5..92670b8659 100644 --- a/gtk2_ardour/editor_regions.cc +++ b/gtk2_ardour/editor_regions.cc @@ -52,6 +52,7 @@ using namespace PBD; using namespace Gtk; using namespace Glib; using namespace Editing; +using Gtkmm2ext::Keyboard; EditorRegions::EditorRegions (Editor* e) : EditorComponent (e), diff --git a/gtk2_ardour/editor_route_groups.cc b/gtk2_ardour/editor_route_groups.cc index 1a2fb35f9e..79049e02bc 100644 --- a/gtk2_ardour/editor_route_groups.cc +++ b/gtk2_ardour/editor_route_groups.cc @@ -46,6 +46,7 @@ using namespace sigc; using namespace ARDOUR; using namespace PBD; using namespace Gtk; +using Gtkmm2ext::Keyboard; EditorRouteGroups::EditorRouteGroups (Editor* e) : EditorComponent (e), diff --git a/gtk2_ardour/editor_routes.cc b/gtk2_ardour/editor_routes.cc index ca22b8cbf7..e92e054426 100644 --- a/gtk2_ardour/editor_routes.cc +++ b/gtk2_ardour/editor_routes.cc @@ -55,6 +55,7 @@ using namespace PBD; using namespace Gtk; using namespace Gtkmm2ext; using namespace Glib; +using Gtkmm2ext::Keyboard; EditorRoutes::EditorRoutes (Editor* e) : EditorComponent (e), diff --git a/gtk2_ardour/editor_summary.cc b/gtk2_ardour/editor_summary.cc index 7998b090d6..be609638cf 100644 --- a/gtk2_ardour/editor_summary.cc +++ b/gtk2_ardour/editor_summary.cc @@ -30,6 +30,7 @@ using namespace std; using namespace sigc; using namespace ARDOUR; +using Gtkmm2ext::Keyboard; /** Construct an EditorSummary. * @param e Editor to represent. diff --git a/gtk2_ardour/gain_meter.cc b/gtk2_ardour/gain_meter.cc index f77a1049e0..95e41b5ee6 100644 --- a/gtk2_ardour/gain_meter.cc +++ b/gtk2_ardour/gain_meter.cc @@ -58,6 +58,7 @@ using namespace Gtkmm2ext; using namespace Gtk; using namespace sigc; using namespace std; +using Gtkmm2ext::Keyboard; sigc::signal GainMeterBase::ResetAllPeakDisplays; sigc::signal GainMeterBase::ResetGroupPeakDisplays; diff --git a/gtk2_ardour/group_tabs.cc b/gtk2_ardour/group_tabs.cc index 9a10adf554..b099c0d309 100644 --- a/gtk2_ardour/group_tabs.cc +++ b/gtk2_ardour/group_tabs.cc @@ -29,6 +29,7 @@ using namespace std; using namespace Gtk; using namespace ARDOUR; +using Gtkmm2ext::Keyboard; GroupTabs::GroupTabs (Editor* e) : EditorComponent (e), diff --git a/gtk2_ardour/keyboard.cc b/gtk2_ardour/keyboard.cc index 200a666fea..bcdd551c0a 100644 --- a/gtk2_ardour/keyboard.cc +++ b/gtk2_ardour/keyboard.cc @@ -17,436 +17,21 @@ */ -#include -#include "ardour/ardour.h" - -#include "ardour_ui.h" - -#include -#include -#include - -#include - -#include - -#include #include "pbd/error.h" #include "pbd/file_utils.h" #include "ardour/filesystem_paths.h" #include "keyboard.h" -#include "gui_thread.h" #include "opts.h" -#include "actions.h" #include "i18n.h" +using namespace std; +using namespace Gtk; using namespace PBD; using namespace ARDOUR; -using namespace Gtk; -using namespace std; - -#define KBD_DEBUG 1 -bool debug_keyboard = false; - -guint Keyboard::edit_but = 3; -guint Keyboard::edit_mod = GDK_CONTROL_MASK; -guint Keyboard::delete_but = 3; -guint Keyboard::delete_mod = GDK_SHIFT_MASK; -guint Keyboard::snap_mod = GDK_MOD3_MASK; - -#ifdef GTKOSX -guint Keyboard::PrimaryModifier = GDK_META_MASK; // Command -guint Keyboard::SecondaryModifier = GDK_MOD1_MASK; // Alt/Option -guint Keyboard::TertiaryModifier = GDK_SHIFT_MASK; // Shift -guint Keyboard::Level4Modifier = GDK_CONTROL_MASK; // Control -guint Keyboard::CopyModifier = GDK_MOD1_MASK; // Alt/Option -guint Keyboard::RangeSelectModifier = GDK_SHIFT_MASK; -guint Keyboard::button2_modifiers = Keyboard::SecondaryModifier|Keyboard::Level4Modifier; -#else -guint Keyboard::PrimaryModifier = GDK_CONTROL_MASK; // Control -guint Keyboard::SecondaryModifier = GDK_MOD1_MASK; // Alt/Option -guint Keyboard::TertiaryModifier = GDK_SHIFT_MASK; // Shift -guint Keyboard::Level4Modifier = GDK_MOD4_MASK; // Mod4/Windows -guint Keyboard::CopyModifier = GDK_CONTROL_MASK; -guint Keyboard::RangeSelectModifier = GDK_SHIFT_MASK; -guint Keyboard::button2_modifiers = 0; /* not used */ -#endif - - -Keyboard* Keyboard::_the_keyboard = 0; -Gtk::Window* Keyboard::current_window = 0; -bool Keyboard::_some_magic_widget_has_focus = false; - -std::string Keyboard::user_keybindings_path; -bool Keyboard::can_save_keybindings = false; -bool Keyboard::bindings_changed_after_save_became_legal = false; -map Keyboard::binding_files; -string Keyboard::_current_binding_name = _("Unknown"); -map,Keyboard::AccelKeyLess> Keyboard::release_keys; - -/* set this to initially contain the modifiers we care about, then track changes in ::set_edit_modifier() etc. */ - -GdkModifierType Keyboard::RelevantModifierKeyMask; - -void -Keyboard::magic_widget_grab_focus () -{ - _some_magic_widget_has_focus = true; -} - -void -Keyboard::magic_widget_drop_focus () -{ - _some_magic_widget_has_focus = false; -} - -bool -Keyboard::some_magic_widget_has_focus () -{ - return _some_magic_widget_has_focus; -} - -Keyboard::Keyboard () -{ - if (_the_keyboard == 0) { - _the_keyboard = this; - } - - RelevantModifierKeyMask = (GdkModifierType) gtk_accelerator_get_default_mod_mask (); - - RelevantModifierKeyMask = GdkModifierType (RelevantModifierKeyMask | PrimaryModifier); - RelevantModifierKeyMask = GdkModifierType (RelevantModifierKeyMask | SecondaryModifier); - RelevantModifierKeyMask = GdkModifierType (RelevantModifierKeyMask | TertiaryModifier); - RelevantModifierKeyMask = GdkModifierType (RelevantModifierKeyMask | Level4Modifier); - RelevantModifierKeyMask = GdkModifierType (RelevantModifierKeyMask | CopyModifier); - RelevantModifierKeyMask = GdkModifierType (RelevantModifierKeyMask | RangeSelectModifier); - - gtk_accelerator_set_default_mod_mask (RelevantModifierKeyMask); - - snooper_id = gtk_key_snooper_install (_snooper, (gpointer) this); - - XMLNode* node = ARDOUR_UI::instance()->keyboard_settings(); - set_state (*node, Stateful::loading_state_version); -} - -Keyboard::~Keyboard () -{ - gtk_key_snooper_remove (snooper_id); -} - -XMLNode& -Keyboard::get_state (void) -{ - XMLNode* node = new XMLNode ("Keyboard"); - char buf[32]; - - snprintf (buf, sizeof (buf), "%d", edit_but); - node->add_property ("edit-button", buf); - snprintf (buf, sizeof (buf), "%d", edit_mod); - node->add_property ("edit-modifier", buf); - snprintf (buf, sizeof (buf), "%d", delete_but); - node->add_property ("delete-button", buf); - snprintf (buf, sizeof (buf), "%d", delete_mod); - node->add_property ("delete-modifier", buf); - snprintf (buf, sizeof (buf), "%d", snap_mod); - node->add_property ("snap-modifier", buf); - - return *node; -} - -int -Keyboard::set_state (const XMLNode& node, int /*version*/) -{ - const XMLProperty* prop; - - if ((prop = node.property ("edit-button")) != 0) { - sscanf (prop->value().c_str(), "%d", &edit_but); - } - - if ((prop = node.property ("edit-modifier")) != 0) { - sscanf (prop->value().c_str(), "%d", &edit_mod); - } - - if ((prop = node.property ("delete-button")) != 0) { - sscanf (prop->value().c_str(), "%d", &delete_but); - } - - if ((prop = node.property ("delete-modifier")) != 0) { - sscanf (prop->value().c_str(), "%d", &delete_mod); - } - - if ((prop = node.property ("snap-modifier")) != 0) { - sscanf (prop->value().c_str(), "%d", &snap_mod); - } - - return 0; -} - -gint -Keyboard::_snooper (GtkWidget *widget, GdkEventKey *event, gpointer data) -{ - return ((Keyboard *) data)->snooper (widget, event); -} - -gint -Keyboard::snooper (GtkWidget *widget, GdkEventKey *event) -{ - uint32_t keyval; - bool ret = false; - -#if 0 - cerr << "snoop widget " << widget << " key " << event->keyval << " type: " << event->type - << " state " << std::hex << event->state << std::dec - << endl; -#endif - -#if KBD_DEBUG - if (debug_keyboard) { - cerr << "snoop widget " << widget << " key " << event->keyval << " type: " << event->type - << endl; - } -#endif - - if (event->keyval == GDK_Shift_R) { - keyval = GDK_Shift_L; - - } else if (event->keyval == GDK_Control_R) { - keyval = GDK_Control_L; - - } else { - keyval = event->keyval; - } - - if (event->type == GDK_KEY_PRESS) { - - if (find (state.begin(), state.end(), keyval) == state.end()) { - state.push_back (keyval); - sort (state.begin(), state.end()); - - } else { - - /* key is already down. if its also used for release, - prevent auto-repeat events. - */ - - for (map::iterator k = release_keys.begin(); k != release_keys.end(); ++k) { - - const AccelKey& ak (k->first); - - if (keyval == ak.get_key() && (Gdk::ModifierType)((event->state & Keyboard::RelevantModifierKeyMask) | Gdk::RELEASE_MASK) == ak.get_mod()) { - cerr << "Suppress auto repeat\n"; - ret = true; - break; - } - } - } - - } else if (event->type == GDK_KEY_RELEASE) { - - State::iterator i; - - if ((i = find (state.begin(), state.end(), keyval)) != state.end()) { - state.erase (i); - sort (state.begin(), state.end()); - } - - for (map::iterator k = release_keys.begin(); k != release_keys.end(); ++k) { - - const AccelKey& ak (k->first); - two_strings ts (k->second); - - if (keyval == ak.get_key() && (Gdk::ModifierType)((event->state & Keyboard::RelevantModifierKeyMask) | Gdk::RELEASE_MASK) == ak.get_mod()) { - Glib::RefPtr act = ActionManager::get_action (ts.first.c_str(), ts.second.c_str()); - if (act) { - act->activate(); - cerr << "use repeat, suppress other\n"; - ret = true; - } - break; - } - } - } - - /* Special keys that we want to handle in - any dialog, no matter whether it uses - the regular set of accelerators or not - */ - - if (event->type == GDK_KEY_RELEASE && modifier_state_equals (event->state, PrimaryModifier)) { - switch (event->keyval) { - case GDK_w: - if (current_window) { - current_window->hide (); - current_window = 0; - ret = true; - } - break; - } - } - - return ret; -} - -bool -Keyboard::key_is_down (uint32_t keyval) -{ - return find (state.begin(), state.end(), keyval) != state.end(); -} - -bool -Keyboard::enter_window (GdkEventCrossing *, Gtk::Window* win) -{ - current_window = win; - return false; -} - -bool -Keyboard::leave_window (GdkEventCrossing *ev, Gtk::Window* /*win*/) -{ - if (ev) { - switch (ev->detail) { - case GDK_NOTIFY_INFERIOR: - if (debug_keyboard) { - cerr << "INFERIOR crossing ... out\n"; - } - break; - - case GDK_NOTIFY_VIRTUAL: - if (debug_keyboard) { - cerr << "VIRTUAL crossing ... out\n"; - } - /* fallthru */ - - default: - if (debug_keyboard) { - cerr << "REAL CROSSING ... out\n"; - cerr << "clearing current target\n"; - } - state.clear (); - current_window = 0; - } - } else { - current_window = 0; - } - - return false; -} - -void -Keyboard::set_edit_button (guint but) -{ - edit_but = but; -} - -void -Keyboard::set_edit_modifier (guint mod) -{ - RelevantModifierKeyMask = GdkModifierType (RelevantModifierKeyMask & ~edit_mod); - edit_mod = mod; - RelevantModifierKeyMask = GdkModifierType (RelevantModifierKeyMask | edit_mod); -} - -void -Keyboard::set_delete_button (guint but) -{ - delete_but = but; -} - -void -Keyboard::set_delete_modifier (guint mod) -{ - RelevantModifierKeyMask = GdkModifierType (RelevantModifierKeyMask & ~delete_mod); - delete_mod = mod; - RelevantModifierKeyMask = GdkModifierType (RelevantModifierKeyMask | delete_mod); -} - -void -Keyboard::set_modifier (uint32_t newval, uint32_t& var) -{ - RelevantModifierKeyMask = GdkModifierType (RelevantModifierKeyMask & ~var); - var = newval; - RelevantModifierKeyMask = GdkModifierType (RelevantModifierKeyMask | var); -} - -void -Keyboard::set_snap_modifier (guint mod) -{ - RelevantModifierKeyMask = GdkModifierType (RelevantModifierKeyMask & ~snap_mod); - snap_mod = mod; - RelevantModifierKeyMask = GdkModifierType (RelevantModifierKeyMask | snap_mod); -} - -bool -Keyboard::is_edit_event (GdkEventButton *ev) -{ - return (ev->type == GDK_BUTTON_PRESS || ev->type == GDK_BUTTON_RELEASE) && - (ev->button == Keyboard::edit_button()) && - ((ev->state & RelevantModifierKeyMask) == Keyboard::edit_modifier()); -} - -bool -Keyboard::is_button2_event (GdkEventButton* ev) -{ -#ifdef GTKOSX - return (ev->button == 2) || - ((ev->button == 1) && - ((ev->state & Keyboard::button2_modifiers) == Keyboard::button2_modifiers)); -#else - return ev->button == 2; -#endif -} - -bool -Keyboard::is_delete_event (GdkEventButton *ev) -{ - return (ev->type == GDK_BUTTON_PRESS || ev->type == GDK_BUTTON_RELEASE) && - (ev->button == Keyboard::delete_button()) && - ((ev->state & RelevantModifierKeyMask) == Keyboard::delete_modifier()); -} - -bool -Keyboard::is_context_menu_event (GdkEventButton *ev) -{ - return (ev->type == GDK_BUTTON_PRESS || ev->type == GDK_BUTTON_RELEASE) && - (ev->button == 3) && - ((ev->state & RelevantModifierKeyMask) == 0); -} - -bool -Keyboard::no_modifiers_active (guint state) -{ - return (state & RelevantModifierKeyMask) == 0; -} - -bool -Keyboard::modifier_state_contains (guint state, ModifierMask mask) -{ - return (state & mask) == (guint) mask; -} - -bool -Keyboard::modifier_state_equals (guint state, ModifierMask mask) -{ - return (state & RelevantModifierKeyMask) == (guint) mask; -} - -Selection::Operation -Keyboard::selection_type (guint state) -{ - /* note that there is no modifier for "Add" */ - - if (modifier_state_equals (state, RangeSelectModifier)) { - return Selection::Extend; - } else if (modifier_state_equals (state, PrimaryModifier)) { - return Selection::Toggle; - } else { - return Selection::Set; - } -} - +using Gtkmm2ext::Keyboard; static void accel_map_changed (GtkAccelMap* /*map*/, @@ -459,34 +44,10 @@ accel_map_changed (GtkAccelMap* /*map*/, } void -Keyboard::keybindings_changed () -{ - if (Keyboard::can_save_keybindings) { - Keyboard::bindings_changed_after_save_became_legal = true; - } - - Keyboard::save_keybindings (); -} - -void -Keyboard::set_can_save_keybindings (bool yn) -{ - can_save_keybindings = yn; -} - -void -Keyboard::save_keybindings () -{ - if (can_save_keybindings && bindings_changed_after_save_became_legal) { - Gtk::AccelMap::save (user_keybindings_path); - } -} - -void -Keyboard::setup_keybindings () +ArdourKeyboard::setup_keybindings () { using namespace ARDOUR_COMMAND_LINE; - std::string default_bindings = "mnemonic-us.bindings"; + string default_bindings = "mnemonic-us.bindings"; vector strs; binding_files.clear (); @@ -615,69 +176,18 @@ Keyboard::setup_keybindings () g_signal_connect (accelmap, "changed", (GCallback) accel_map_changed, 0); } -bool -Keyboard::load_keybindings (string path) +Selection::Operation +ArdourKeyboard::selection_type (guint state) { - try { - info << "Loading bindings from " << path << endl; + /* note that there is no modifier for "Add" */ - Gtk::AccelMap::load (path); - - _current_binding_name = _("Unknown"); - - for (map::iterator x = binding_files.begin(); x != binding_files.end(); ++x) { - if (path == x->second) { - _current_binding_name = x->first; - break; - } - } - - - } catch (...) { - error << string_compose (_("Ardour key bindings file not found at \"%1\" or contains errors."), path) - << endmsg; - return false; + if (modifier_state_equals (state, RangeSelectModifier)) { + return Selection::Extend; + } else if (modifier_state_equals (state, PrimaryModifier)) { + return Selection::Toggle; + } else { + return Selection::Set; } - - /* now find all release-driven bindings */ - - vector groups; - vector names; - vector bindings; - - ActionManager::get_all_actions (groups, names, bindings); - - vector::iterator g; - vector::iterator b; - vector::iterator n; - - release_keys.clear (); - - bool show_bindings = (getenv ("ARDOUR_SHOW_BINDINGS") != 0); - - for (n = names.begin(), b = bindings.begin(), g = groups.begin(); n != names.end(); ++n, ++b, ++g) { - - if (show_bindings) { - - cerr << "Action: " << (*n) << " Group: " << (*g) << " binding = "; - - if ((*b).get_key() != GDK_VoidSymbol) { - cerr << (*b).get_key() << " w/mod = " << hex << (*b).get_mod() << dec << " = " << (*b).get_abbrev(); - } else { - cerr << "unbound"; - } - - cerr << endl; - } - } - - for (n = names.begin(), b = bindings.begin(), g = groups.begin(); n != names.end(); ++n, ++b, ++g) { - if ((*b).get_mod() & Gdk::RELEASE_MASK) { - release_keys.insert (pair (*b, two_strings (*g, *n))); - } - } - - return true; } diff --git a/gtk2_ardour/keyboard.h b/gtk2_ardour/keyboard.h index e34c424329..d4f1158e35 100644 --- a/gtk2_ardour/keyboard.h +++ b/gtk2_ardour/keyboard.h @@ -20,150 +20,20 @@ #ifndef __ardour_keyboard_h__ #define __ardour_keyboard_h__ -#include -#include -#include - -#include -#include -#include - #include "ardour/types.h" -#include "pbd/stateful.h" +#include "gtkmm2ext/keyboard.h" #include "selection.h" -class Keyboard : public sigc::trackable, PBD::Stateful + +class ArdourKeyboard : public Gtkmm2ext::Keyboard { public: - Keyboard (); - ~Keyboard (); + ArdourKeyboard() {} - XMLNode& get_state (void); - int set_state (const XMLNode&, int version); - - typedef std::vector State; - typedef uint32_t ModifierMask; - - static uint32_t PrimaryModifier; - static uint32_t SecondaryModifier; - static uint32_t TertiaryModifier; - static uint32_t Level4Modifier; - static uint32_t CopyModifier; - static uint32_t RangeSelectModifier; - - static void set_primary_modifier (uint32_t newval) { - set_modifier (newval, PrimaryModifier); - } - static void set_secondary_modifier (uint32_t newval) { - set_modifier (newval, SecondaryModifier); - } - static void set_tertiary_modifier (uint32_t newval) { - set_modifier (newval, TertiaryModifier); - } - static void set_level4_modifier (uint32_t newval) { - set_modifier (newval, Level4Modifier); - } - static void set_copy_modifier (uint32_t newval) { - set_modifier (newval, CopyModifier); - } - static void set_range_select_modifier (uint32_t newval) { - set_modifier (newval, RangeSelectModifier); - } - - bool key_is_down (uint32_t keyval); - - static GdkModifierType RelevantModifierKeyMask; - - static bool no_modifier_keys_pressed(GdkEventButton* ev) { - return (ev->state & RelevantModifierKeyMask) == 0; - } - - bool leave_window (GdkEventCrossing *ev, Gtk::Window*); - bool enter_window (GdkEventCrossing *ev, Gtk::Window*); - - static bool modifier_state_contains (guint state, ModifierMask); - static bool modifier_state_equals (guint state, ModifierMask); + void setup_keybindings (); static Selection::Operation selection_type (guint state); - - static bool no_modifiers_active (guint state); - - static void set_snap_modifier (guint); - - /** @return Modifier mask to temporarily toggle grid setting; with this modifier - * - magnetic or normal grid should become no grid and - * - no grid should become normal grid - */ - static ModifierMask snap_modifier () { return ModifierMask (snap_mod); } - - static guint edit_button() { return edit_but; } - static void set_edit_button (guint); - static guint edit_modifier() { return edit_mod; } - static void set_edit_modifier(guint); - - static guint delete_button() { return delete_but; } - static void set_delete_button(guint); - static guint delete_modifier() { return delete_mod; } - static void set_delete_modifier(guint); - - static bool is_edit_event (GdkEventButton*); - static bool is_delete_event (GdkEventButton*); - static bool is_context_menu_event (GdkEventButton*); - static bool is_button2_event (GdkEventButton*); - - static Keyboard& the_keyboard() { return *_the_keyboard; } - - static bool some_magic_widget_has_focus (); - static void magic_widget_grab_focus (); - static void magic_widget_drop_focus (); - - static void setup_keybindings (); - static void keybindings_changed (); - static void save_keybindings (); - static bool load_keybindings (std::string path); - static void set_can_save_keybindings (bool yn); - static std::string current_binding_name () { return _current_binding_name; } - static std::map binding_files; - - struct AccelKeyLess { - bool operator() (const Gtk::AccelKey a, const Gtk::AccelKey b) const { - if (a.get_key() != b.get_key()) { - return a.get_key() < b.get_key(); - } else { - return a.get_mod() < b.get_mod(); - } - } - }; - - private: - static Keyboard* _the_keyboard; - - guint snooper_id; - State state; - - static guint edit_but; - static guint edit_mod; - static guint delete_but; - static guint delete_mod; - static guint snap_mod; - static guint button2_modifiers; - static Gtk::Window* current_window; - static std::string user_keybindings_path; - static bool can_save_keybindings; - static bool bindings_changed_after_save_became_legal; - static std::string _current_binding_name; - - typedef std::pair two_strings; - - static std::map release_keys; - - static gint _snooper (GtkWidget*, GdkEventKey*, gpointer); - gint snooper (GtkWidget*, GdkEventKey*); - - static void set_modifier (uint32_t newval, uint32_t& variable); - - static bool _some_magic_widget_has_focus; }; #endif /* __ardour_keyboard_h__ */ diff --git a/gtk2_ardour/keyeditor.cc b/gtk2_ardour/keyeditor.cc index b8bfb5677b..f54cc4f739 100644 --- a/gtk2_ardour/keyeditor.cc +++ b/gtk2_ardour/keyeditor.cc @@ -25,6 +25,8 @@ using namespace Gtk; using namespace Gdk; using namespace PBD; +using Gtkmm2ext::Keyboard; + KeyEditor::KeyEditor () : ArdourDialog (_("Key Bindings"), false) , unbind_button (_("Remove shortcut")) diff --git a/gtk2_ardour/midi_region_view.cc b/gtk2_ardour/midi_region_view.cc index 2644be763a..4760bf593b 100644 --- a/gtk2_ardour/midi_region_view.cc +++ b/gtk2_ardour/midi_region_view.cc @@ -70,6 +70,7 @@ using namespace ARDOUR; using namespace PBD; using namespace Editing; using namespace ArdourCanvas; +using Gtkmm2ext::Keyboard; MidiRegionView::MidiRegionView (ArdourCanvas::Group *parent, RouteTimeAxisView &tv, boost::shared_ptr r, double spu, Gdk::Color const & basic_color) diff --git a/gtk2_ardour/panner2d.cc b/gtk2_ardour/panner2d.cc index 7917604b62..f03946e9aa 100644 --- a/gtk2_ardour/panner2d.cc +++ b/gtk2_ardour/panner2d.cc @@ -39,6 +39,7 @@ using namespace Gtk; using namespace sigc; using namespace ARDOUR; using namespace PBD; +using Gtkmm2ext::Keyboard; Panner2d::Target::Target (float xa, float ya, const char *txt) : x (xa, 0.0, 1.0, 0.01, 0.1) diff --git a/gtk2_ardour/port_matrix_grid.cc b/gtk2_ardour/port_matrix_grid.cc index 9a2c5c189f..5136285e48 100644 --- a/gtk2_ardour/port_matrix_grid.cc +++ b/gtk2_ardour/port_matrix_grid.cc @@ -27,6 +27,7 @@ #include "keyboard.h" using namespace std; +using Gtkmm2ext::Keyboard; PortMatrixGrid::PortMatrixGrid (PortMatrix* m, PortMatrixBody* b) : PortMatrixComponent (m, b), diff --git a/gtk2_ardour/route_time_axis.cc b/gtk2_ardour/route_time_axis.cc index a90680de4d..ef948307a2 100644 --- a/gtk2_ardour/route_time_axis.cc +++ b/gtk2_ardour/route_time_axis.cc @@ -1171,7 +1171,7 @@ RouteTimeAxisView::selection_click (GdkEventButton* ev) PublicEditor::TrackViewList* tracks = _editor.get_valid_views (this, _route->route_group()); - switch (Keyboard::selection_type (ev->state)) { + switch (ArdourKeyboard::selection_type (ev->state)) { case Selection::Toggle: _editor.get_selection().toggle (*tracks); break; diff --git a/gtk2_ardour/time_axis_view.cc b/gtk2_ardour/time_axis_view.cc index 31bea78aca..577fbcdda6 100644 --- a/gtk2_ardour/time_axis_view.cc +++ b/gtk2_ardour/time_axis_view.cc @@ -62,6 +62,7 @@ using namespace ARDOUR; using namespace PBD; using namespace Editing; using namespace ArdourCanvas; +using Gtkmm2ext::Keyboard; const double trim_handle_size = 6.0; /* pixels */ @@ -338,7 +339,7 @@ TimeAxisView::controls_ebox_button_release (GdkEventButton* ev) void TimeAxisView::selection_click (GdkEventButton* ev) { - Selection::Operation op = Keyboard::selection_type (ev->state); + Selection::Operation op = ArdourKeyboard::selection_type (ev->state); _editor.set_selected_track (*this, op, false); } diff --git a/gtk2_ardour/utils.cc b/gtk2_ardour/utils.cc index 2c64594c97..a98435f0d9 100644 --- a/gtk2_ardour/utils.cc +++ b/gtk2_ardour/utils.cc @@ -53,6 +53,7 @@ using namespace Gtk; using namespace sigc; using namespace Glib; using namespace PBD; +using Gtkmm2ext::Keyboard; sigc::signal DPIReset; diff --git a/libs/gtkmm2ext/gtkmm2ext/actions.h b/libs/gtkmm2ext/gtkmm2ext/actions.h index 3c3825944f..5616bbb302 100644 --- a/libs/gtkmm2ext/gtkmm2ext/actions.h +++ b/libs/gtkmm2ext/gtkmm2ext/actions.h @@ -21,6 +21,7 @@ #define __libgtkmm2ext_actions_h__ #include + #include #include #include diff --git a/libs/gtkmm2ext/gtkmm2ext/keyboard.h b/libs/gtkmm2ext/gtkmm2ext/keyboard.h new file mode 100644 index 0000000000..864eeaeb7d --- /dev/null +++ b/libs/gtkmm2ext/gtkmm2ext/keyboard.h @@ -0,0 +1,173 @@ +/* + Copyright (C) 2001 Paul Davis + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#ifndef __libgtkmm2ext_keyboard_h__ +#define __libgtkmm2ext_keyboard_h__ + +#include +#include +#include + +#include +#include +#include + +#include "pbd/stateful.h" + +namespace Gtk { + class Window; +} + +namespace Gtkmm2ext { + +class Keyboard : public sigc::trackable, PBD::Stateful +{ + public: + Keyboard (); + ~Keyboard (); + + XMLNode& get_state (void); + int set_state (const XMLNode&, int version); + + virtual void setup_keybindings () = 0; + + typedef std::vector State; + typedef uint32_t ModifierMask; + + static uint32_t PrimaryModifier; + static uint32_t SecondaryModifier; + static uint32_t TertiaryModifier; + static uint32_t Level4Modifier; + static uint32_t CopyModifier; + static uint32_t RangeSelectModifier; + + static void set_primary_modifier (uint32_t newval) { + set_modifier (newval, PrimaryModifier); + } + static void set_secondary_modifier (uint32_t newval) { + set_modifier (newval, SecondaryModifier); + } + static void set_tertiary_modifier (uint32_t newval) { + set_modifier (newval, TertiaryModifier); + } + static void set_level4_modifier (uint32_t newval) { + set_modifier (newval, Level4Modifier); + } + static void set_copy_modifier (uint32_t newval) { + set_modifier (newval, CopyModifier); + } + static void set_range_select_modifier (uint32_t newval) { + set_modifier (newval, RangeSelectModifier); + } + + bool key_is_down (uint32_t keyval); + + static GdkModifierType RelevantModifierKeyMask; + + static bool no_modifier_keys_pressed(GdkEventButton* ev) { + return (ev->state & RelevantModifierKeyMask) == 0; + } + + bool leave_window (GdkEventCrossing *ev, Gtk::Window*); + bool enter_window (GdkEventCrossing *ev, Gtk::Window*); + + static bool modifier_state_contains (guint state, ModifierMask); + static bool modifier_state_equals (guint state, ModifierMask); + + static bool no_modifiers_active (guint state); + + static void set_snap_modifier (guint); + + /** @return Modifier mask to temporarily toggle grid setting; with this modifier + * - magnetic or normal grid should become no grid and + * - no grid should become normal grid + */ + static ModifierMask snap_modifier () { return ModifierMask (snap_mod); } + + static guint edit_button() { return edit_but; } + static void set_edit_button (guint); + static guint edit_modifier() { return edit_mod; } + static void set_edit_modifier(guint); + + static guint delete_button() { return delete_but; } + static void set_delete_button(guint); + static guint delete_modifier() { return delete_mod; } + static void set_delete_modifier(guint); + + static bool is_edit_event (GdkEventButton*); + static bool is_delete_event (GdkEventButton*); + static bool is_context_menu_event (GdkEventButton*); + static bool is_button2_event (GdkEventButton*); + + static Keyboard& the_keyboard() { return *_the_keyboard; } + + static bool some_magic_widget_has_focus (); + static void magic_widget_grab_focus (); + static void magic_widget_drop_focus (); + + static void keybindings_changed (); + static void save_keybindings (); + static bool load_keybindings (std::string path); + static void set_can_save_keybindings (bool yn); + static std::string current_binding_name () { return _current_binding_name; } + static std::map binding_files; + + struct AccelKeyLess { + bool operator() (const Gtk::AccelKey a, const Gtk::AccelKey b) const { + if (a.get_key() != b.get_key()) { + return a.get_key() < b.get_key(); + } else { + return a.get_mod() < b.get_mod(); + } + } + }; + + protected: + static Keyboard* _the_keyboard; + + guint snooper_id; + State state; + + static guint edit_but; + static guint edit_mod; + static guint delete_but; + static guint delete_mod; + static guint snap_mod; + static guint button2_modifiers; + static Gtk::Window* current_window; + static std::string user_keybindings_path; + static bool can_save_keybindings; + static bool bindings_changed_after_save_became_legal; + static std::string _current_binding_name; + + typedef std::pair two_strings; + + static std::map release_keys; + + static gint _snooper (GtkWidget*, GdkEventKey*, gpointer); + gint snooper (GtkWidget*, GdkEventKey*); + + static void set_modifier (uint32_t newval, uint32_t& variable); + + static bool _some_magic_widget_has_focus; +}; + +} /* namespace */ + +#endif /* __libgtkmm2ext_keyboard_h__ */ diff --git a/libs/gtkmm2ext/keyboard.cc b/libs/gtkmm2ext/keyboard.cc new file mode 100644 index 0000000000..da51d4e412 --- /dev/null +++ b/libs/gtkmm2ext/keyboard.cc @@ -0,0 +1,519 @@ +/* + Copyright (C) 2001 Paul Davis + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#include + +#include +#include +#include + +#include + +#include +#include +#include +#include + +#include "pbd/error.h" +#include "pbd/file_utils.h" +#include "pbd/search_path.h" +#include "pbd/xml++.h" + +#include "gtkmm2ext/keyboard.h" +#include "gtkmm2ext/actions.h" + +#include "i18n.h" + +using namespace PBD; +using namespace Gtk; +using namespace Gtkmm2ext; +using namespace std; + +#define KBD_DEBUG 1 +bool debug_keyboard = false; + +guint Keyboard::edit_but = 3; +guint Keyboard::edit_mod = GDK_CONTROL_MASK; +guint Keyboard::delete_but = 3; +guint Keyboard::delete_mod = GDK_SHIFT_MASK; +guint Keyboard::snap_mod = GDK_MOD3_MASK; + +#ifdef GTKOSX +guint Keyboard::PrimaryModifier = GDK_META_MASK; // Command +guint Keyboard::SecondaryModifier = GDK_MOD1_MASK; // Alt/Option +guint Keyboard::TertiaryModifier = GDK_SHIFT_MASK; // Shift +guint Keyboard::Level4Modifier = GDK_CONTROL_MASK; // Control +guint Keyboard::CopyModifier = GDK_MOD1_MASK; // Alt/Option +guint Keyboard::RangeSelectModifier = GDK_SHIFT_MASK; +guint Keyboard::button2_modifiers = Keyboard::SecondaryModifier|Keyboard::Level4Modifier; +#else +guint Keyboard::PrimaryModifier = GDK_CONTROL_MASK; // Control +guint Keyboard::SecondaryModifier = GDK_MOD1_MASK; // Alt/Option +guint Keyboard::TertiaryModifier = GDK_SHIFT_MASK; // Shift +guint Keyboard::Level4Modifier = GDK_MOD4_MASK; // Mod4/Windows +guint Keyboard::CopyModifier = GDK_CONTROL_MASK; +guint Keyboard::RangeSelectModifier = GDK_SHIFT_MASK; +guint Keyboard::button2_modifiers = 0; /* not used */ +#endif + + +Keyboard* Keyboard::_the_keyboard = 0; +Gtk::Window* Keyboard::current_window = 0; +bool Keyboard::_some_magic_widget_has_focus = false; + +std::string Keyboard::user_keybindings_path; +bool Keyboard::can_save_keybindings = false; +bool Keyboard::bindings_changed_after_save_became_legal = false; +map Keyboard::binding_files; +string Keyboard::_current_binding_name = _("Unknown"); +map,Keyboard::AccelKeyLess> Keyboard::release_keys; + +/* set this to initially contain the modifiers we care about, then track changes in ::set_edit_modifier() etc. */ + +GdkModifierType Keyboard::RelevantModifierKeyMask; + +void +Keyboard::magic_widget_grab_focus () +{ + _some_magic_widget_has_focus = true; +} + +void +Keyboard::magic_widget_drop_focus () +{ + _some_magic_widget_has_focus = false; +} + +bool +Keyboard::some_magic_widget_has_focus () +{ + return _some_magic_widget_has_focus; +} + +Keyboard::Keyboard () +{ + if (_the_keyboard == 0) { + _the_keyboard = this; + } + + RelevantModifierKeyMask = (GdkModifierType) gtk_accelerator_get_default_mod_mask (); + + RelevantModifierKeyMask = GdkModifierType (RelevantModifierKeyMask | PrimaryModifier); + RelevantModifierKeyMask = GdkModifierType (RelevantModifierKeyMask | SecondaryModifier); + RelevantModifierKeyMask = GdkModifierType (RelevantModifierKeyMask | TertiaryModifier); + RelevantModifierKeyMask = GdkModifierType (RelevantModifierKeyMask | Level4Modifier); + RelevantModifierKeyMask = GdkModifierType (RelevantModifierKeyMask | CopyModifier); + RelevantModifierKeyMask = GdkModifierType (RelevantModifierKeyMask | RangeSelectModifier); + + gtk_accelerator_set_default_mod_mask (RelevantModifierKeyMask); + + snooper_id = gtk_key_snooper_install (_snooper, (gpointer) this); +} + +Keyboard::~Keyboard () +{ + gtk_key_snooper_remove (snooper_id); +} + +XMLNode& +Keyboard::get_state (void) +{ + XMLNode* node = new XMLNode ("Keyboard"); + char buf[32]; + + snprintf (buf, sizeof (buf), "%d", edit_but); + node->add_property ("edit-button", buf); + snprintf (buf, sizeof (buf), "%d", edit_mod); + node->add_property ("edit-modifier", buf); + snprintf (buf, sizeof (buf), "%d", delete_but); + node->add_property ("delete-button", buf); + snprintf (buf, sizeof (buf), "%d", delete_mod); + node->add_property ("delete-modifier", buf); + snprintf (buf, sizeof (buf), "%d", snap_mod); + node->add_property ("snap-modifier", buf); + + return *node; +} + +int +Keyboard::set_state (const XMLNode& node, int /*version*/) +{ + const XMLProperty* prop; + + if ((prop = node.property ("edit-button")) != 0) { + sscanf (prop->value().c_str(), "%d", &edit_but); + } + + if ((prop = node.property ("edit-modifier")) != 0) { + sscanf (prop->value().c_str(), "%d", &edit_mod); + } + + if ((prop = node.property ("delete-button")) != 0) { + sscanf (prop->value().c_str(), "%d", &delete_but); + } + + if ((prop = node.property ("delete-modifier")) != 0) { + sscanf (prop->value().c_str(), "%d", &delete_mod); + } + + if ((prop = node.property ("snap-modifier")) != 0) { + sscanf (prop->value().c_str(), "%d", &snap_mod); + } + + return 0; +} + +gint +Keyboard::_snooper (GtkWidget *widget, GdkEventKey *event, gpointer data) +{ + return ((Keyboard *) data)->snooper (widget, event); +} + +gint +Keyboard::snooper (GtkWidget *widget, GdkEventKey *event) +{ + uint32_t keyval; + bool ret = false; + +#if 0 + cerr << "snoop widget " << widget << " key " << event->keyval << " type: " << event->type + << " state " << std::hex << event->state << std::dec + << endl; +#endif + +#if KBD_DEBUG + if (debug_keyboard) { + cerr << "snoop widget " << widget << " key " << event->keyval << " type: " << event->type + << endl; + } +#endif + + if (event->keyval == GDK_Shift_R) { + keyval = GDK_Shift_L; + + } else if (event->keyval == GDK_Control_R) { + keyval = GDK_Control_L; + + } else { + keyval = event->keyval; + } + + if (event->type == GDK_KEY_PRESS) { + + if (find (state.begin(), state.end(), keyval) == state.end()) { + state.push_back (keyval); + sort (state.begin(), state.end()); + + } else { + + /* key is already down. if its also used for release, + prevent auto-repeat events. + */ + + for (map::iterator k = release_keys.begin(); k != release_keys.end(); ++k) { + + const AccelKey& ak (k->first); + + if (keyval == ak.get_key() && (Gdk::ModifierType)((event->state & Keyboard::RelevantModifierKeyMask) | Gdk::RELEASE_MASK) == ak.get_mod()) { + cerr << "Suppress auto repeat\n"; + ret = true; + break; + } + } + } + + } else if (event->type == GDK_KEY_RELEASE) { + + State::iterator i; + + if ((i = find (state.begin(), state.end(), keyval)) != state.end()) { + state.erase (i); + sort (state.begin(), state.end()); + } + + for (map::iterator k = release_keys.begin(); k != release_keys.end(); ++k) { + + const AccelKey& ak (k->first); + two_strings ts (k->second); + + if (keyval == ak.get_key() && (Gdk::ModifierType)((event->state & Keyboard::RelevantModifierKeyMask) | Gdk::RELEASE_MASK) == ak.get_mod()) { + Glib::RefPtr act = ActionManager::get_action (ts.first.c_str(), ts.second.c_str()); + if (act) { + act->activate(); + cerr << "use repeat, suppress other\n"; + ret = true; + } + break; + } + } + } + + /* Special keys that we want to handle in + any dialog, no matter whether it uses + the regular set of accelerators or not + */ + + if (event->type == GDK_KEY_RELEASE && modifier_state_equals (event->state, PrimaryModifier)) { + switch (event->keyval) { + case GDK_w: + if (current_window) { + current_window->hide (); + current_window = 0; + ret = true; + } + break; + } + } + + return ret; +} + +bool +Keyboard::key_is_down (uint32_t keyval) +{ + return find (state.begin(), state.end(), keyval) != state.end(); +} + +bool +Keyboard::enter_window (GdkEventCrossing *, Gtk::Window* win) +{ + current_window = win; + return false; +} + +bool +Keyboard::leave_window (GdkEventCrossing *ev, Gtk::Window* /*win*/) +{ + if (ev) { + switch (ev->detail) { + case GDK_NOTIFY_INFERIOR: + if (debug_keyboard) { + cerr << "INFERIOR crossing ... out\n"; + } + break; + + case GDK_NOTIFY_VIRTUAL: + if (debug_keyboard) { + cerr << "VIRTUAL crossing ... out\n"; + } + /* fallthru */ + + default: + if (debug_keyboard) { + cerr << "REAL CROSSING ... out\n"; + cerr << "clearing current target\n"; + } + state.clear (); + current_window = 0; + } + } else { + current_window = 0; + } + + return false; +} + +void +Keyboard::set_edit_button (guint but) +{ + edit_but = but; +} + +void +Keyboard::set_edit_modifier (guint mod) +{ + RelevantModifierKeyMask = GdkModifierType (RelevantModifierKeyMask & ~edit_mod); + edit_mod = mod; + RelevantModifierKeyMask = GdkModifierType (RelevantModifierKeyMask | edit_mod); +} + +void +Keyboard::set_delete_button (guint but) +{ + delete_but = but; +} + +void +Keyboard::set_delete_modifier (guint mod) +{ + RelevantModifierKeyMask = GdkModifierType (RelevantModifierKeyMask & ~delete_mod); + delete_mod = mod; + RelevantModifierKeyMask = GdkModifierType (RelevantModifierKeyMask | delete_mod); +} + +void +Keyboard::set_modifier (uint32_t newval, uint32_t& var) +{ + RelevantModifierKeyMask = GdkModifierType (RelevantModifierKeyMask & ~var); + var = newval; + RelevantModifierKeyMask = GdkModifierType (RelevantModifierKeyMask | var); +} + +void +Keyboard::set_snap_modifier (guint mod) +{ + RelevantModifierKeyMask = GdkModifierType (RelevantModifierKeyMask & ~snap_mod); + snap_mod = mod; + RelevantModifierKeyMask = GdkModifierType (RelevantModifierKeyMask | snap_mod); +} + +bool +Keyboard::is_edit_event (GdkEventButton *ev) +{ + return (ev->type == GDK_BUTTON_PRESS || ev->type == GDK_BUTTON_RELEASE) && + (ev->button == Keyboard::edit_button()) && + ((ev->state & RelevantModifierKeyMask) == Keyboard::edit_modifier()); +} + +bool +Keyboard::is_button2_event (GdkEventButton* ev) +{ +#ifdef GTKOSX + return (ev->button == 2) || + ((ev->button == 1) && + ((ev->state & Keyboard::button2_modifiers) == Keyboard::button2_modifiers)); +#else + return ev->button == 2; +#endif +} + +bool +Keyboard::is_delete_event (GdkEventButton *ev) +{ + return (ev->type == GDK_BUTTON_PRESS || ev->type == GDK_BUTTON_RELEASE) && + (ev->button == Keyboard::delete_button()) && + ((ev->state & RelevantModifierKeyMask) == Keyboard::delete_modifier()); +} + +bool +Keyboard::is_context_menu_event (GdkEventButton *ev) +{ + return (ev->type == GDK_BUTTON_PRESS || ev->type == GDK_BUTTON_RELEASE) && + (ev->button == 3) && + ((ev->state & RelevantModifierKeyMask) == 0); +} + +bool +Keyboard::no_modifiers_active (guint state) +{ + return (state & RelevantModifierKeyMask) == 0; +} + +bool +Keyboard::modifier_state_contains (guint state, ModifierMask mask) +{ + return (state & mask) == (guint) mask; +} + +bool +Keyboard::modifier_state_equals (guint state, ModifierMask mask) +{ + return (state & RelevantModifierKeyMask) == (guint) mask; +} + +void +Keyboard::keybindings_changed () +{ + if (Keyboard::can_save_keybindings) { + Keyboard::bindings_changed_after_save_became_legal = true; + } + + Keyboard::save_keybindings (); +} + +void +Keyboard::set_can_save_keybindings (bool yn) +{ + can_save_keybindings = yn; +} + +void +Keyboard::save_keybindings () +{ + if (can_save_keybindings && bindings_changed_after_save_became_legal) { + Gtk::AccelMap::save (user_keybindings_path); + } +} + +bool +Keyboard::load_keybindings (string path) +{ + try { + info << "Loading bindings from " << path << endl; + + Gtk::AccelMap::load (path); + + _current_binding_name = _("Unknown"); + + for (map::iterator x = binding_files.begin(); x != binding_files.end(); ++x) { + if (path == x->second) { + _current_binding_name = x->first; + break; + } + } + + + } catch (...) { + error << string_compose (_("Ardour key bindings file not found at \"%1\" or contains errors."), path) + << endmsg; + return false; + } + + /* now find all release-driven bindings */ + + vector groups; + vector names; + vector bindings; + + ActionManager::get_all_actions (groups, names, bindings); + + vector::iterator g; + vector::iterator b; + vector::iterator n; + + release_keys.clear (); + + bool show_bindings = (getenv ("ARDOUR_SHOW_BINDINGS") != 0); + + for (n = names.begin(), b = bindings.begin(), g = groups.begin(); n != names.end(); ++n, ++b, ++g) { + + if (show_bindings) { + + cerr << "Action: " << (*n) << " Group: " << (*g) << " binding = "; + + if ((*b).get_key() != GDK_VoidSymbol) { + cerr << (*b).get_key() << " w/mod = " << hex << (*b).get_mod() << dec << " = " << (*b).get_abbrev(); + } else { + cerr << "unbound"; + } + + cerr << endl; + } + } + + for (n = names.begin(), b = bindings.begin(), g = groups.begin(); n != names.end(); ++n, ++b, ++g) { + if ((*b).get_mod() & Gdk::RELEASE_MASK) { + release_keys.insert (pair (*b, two_strings (*g, *n))); + } + } + + return true; +} + + diff --git a/libs/gtkmm2ext/wscript b/libs/gtkmm2ext/wscript index 8e348602cb..46babcc7cf 100644 --- a/libs/gtkmm2ext/wscript +++ b/libs/gtkmm2ext/wscript @@ -33,6 +33,7 @@ gtkmm2ext_sources = [ 'grouped_buttons.cc', 'gtk_ui.cc', 'idle_adjustment.cc', + 'keyboard.cc', 'pixfader.cc', 'pixscroller.cc', 'popup.cc',