summaryrefslogtreecommitdiff
path: root/gtk2_ardour/keyboard.cc
diff options
context:
space:
mode:
authorTaybin Rutkin <taybin@taybin.com>2005-09-25 18:42:24 +0000
committerTaybin Rutkin <taybin@taybin.com>2005-09-25 18:42:24 +0000
commit209d967b1bb80a9735d690d8f4f0455ecb9970ca (patch)
tree9d76ddcd7c1ac9d91bb2b1a33d31b66ce4ded5de /gtk2_ardour/keyboard.cc
parente4b9aed743fc765219ac775905a221c017c88fba (diff)
Initial import of gtk2_ardour.
git-svn-id: svn://localhost/trunk/ardour2@24 d708f5d6-7413-0410-9779-e7cbd77b26cf
Diffstat (limited to 'gtk2_ardour/keyboard.cc')
-rw-r--r--gtk2_ardour/keyboard.cc1006
1 files changed, 1006 insertions, 0 deletions
diff --git a/gtk2_ardour/keyboard.cc b/gtk2_ardour/keyboard.cc
new file mode 100644
index 0000000000..e0d2314b2f
--- /dev/null
+++ b/gtk2_ardour/keyboard.cc
@@ -0,0 +1,1006 @@
+/*
+ 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.
+
+ $Id$
+*/
+
+#include "ardour_ui.h"
+
+#include <algorithm>
+#include <fstream>
+
+#include <ctype.h>
+
+#include <X11/keysymdef.h>
+#include <gdk/gdkx.h>
+#include <gdk/gdkkeysyms.h>
+#include <pbd/error.h>
+
+#include "keyboard.h"
+#include "keyboard_target.h"
+#include "ardour_dialog.h"
+#include "gui_thread.h"
+
+#include "i18n.h"
+
+#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;
+
+uint32_t Keyboard::Control = GDK_CONTROL_MASK;
+uint32_t Keyboard::Shift = GDK_SHIFT_MASK;
+uint32_t Keyboard::Alt = GDK_MOD1_MASK;
+uint32_t Keyboard::Meta = GDK_MOD2_MASK;
+
+Keyboard* Keyboard::_the_keyboard = 0;
+
+/* set this to initially contain the modifiers we care about, then track changes in ::set_edit_modifier() etc. */
+
+GdkModifierType Keyboard::RelevantModifierKeyMask =
+ GdkModifierType (GDK_SHIFT_MASK|GDK_CONTROL_MASK|GDK_MOD3_MASK);
+
+
+Keyboard::Keyboard ()
+{
+ if (_the_keyboard == 0) {
+ _the_keyboard = this;
+ }
+
+ target = 0;
+ default_target = 0;
+ _queue_events = false;
+ _flush_queue = false;
+ playback_ignore_count = 0;
+ focus_allowed = false;
+ collecting_prefix = false;
+ current_dialog = 0;
+
+ get_modifier_masks ();
+
+ snooper_id = gtk_key_snooper_install (_snooper, (gpointer) this);
+
+ /* some global key actions */
+
+ KeyboardTarget::add_action ("close-dialog", slot (*this, &Keyboard::close_current_dialog));
+
+ XMLNode* node = ARDOUR_UI::instance()->keyboard_settings();
+ set_state (*node);
+}
+
+Keyboard::~Keyboard ()
+{
+ gtk_key_snooper_remove (snooper_id);
+ delete [] modifier_masks;
+}
+
+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)
+{
+ 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)
+{
+ bool handled = false;
+ uint32_t keyval;
+
+#if KBD_DEBUG
+ if (debug_keyboard) {
+ cerr << "snoop widget " << widget << " key " << event->keyval << " type: " << event->type
+ << " focus allowed? " << focus_allowed << " current dialog = " << current_dialog
+ << endl;
+ }
+#endif
+
+ /* Only allow key events to propagate to the
+ usual GTK model when specifically allowed.
+ Returning FALSE here does that.
+ */
+
+ if (focus_allowed) {
+ return FALSE;
+ }
+
+ 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) {
+ bool was_prefix = false;
+
+ if (collecting_prefix) {
+ switch (keyval) {
+ case GDK_0:
+ current_prefix += '0';
+ was_prefix = true;
+ break;
+ case GDK_1:
+ current_prefix += '1';
+ was_prefix = true;
+ break;
+ case GDK_2:
+ current_prefix += '2';
+ was_prefix = true;
+ break;
+ case GDK_3:
+ current_prefix += '3';
+ was_prefix = true;
+ break;
+ case GDK_4:
+ current_prefix += '4';
+ was_prefix = true;
+ break;
+ case GDK_5:
+ current_prefix += '5';
+ was_prefix = true;
+ break;
+ case GDK_6:
+ current_prefix += '6';
+ was_prefix = true;
+ break;
+ case GDK_7:
+ current_prefix += '7';
+ was_prefix = true;
+ break;
+ case GDK_8:
+ current_prefix += '8';
+ was_prefix = true;
+ break;
+ case GDK_9:
+ current_prefix += '9';
+ was_prefix = true;
+ break;
+ case GDK_period:
+ current_prefix += '.';
+ was_prefix = true;
+ break;
+ default:
+ was_prefix = false;
+ collecting_prefix = false;
+ break;
+ }
+ }
+
+ if (find (state.begin(), state.end(), keyval) == state.end()) {
+ state.push_back (keyval);
+ sort (state.begin(), state.end());
+ }
+
+#if KBD_DEBUG
+ if (debug_keyboard) {
+ cerr << "STATE: ";
+ for (State::iterator i = state.begin(); i != state.end(); ++i) {
+ cerr << (*i) << ' ';
+ }
+ cerr << endl;
+ }
+#endif
+
+ if (!was_prefix) {
+
+ bool old_collecting_prefix = collecting_prefix;
+
+ if (target) {
+#if KBD_DEBUG
+ if (debug_keyboard) {
+ cerr << "PRESS: delivering to target " << target << endl;
+ }
+#endif
+ target->key_press_event (event, state, handled);
+ }
+
+ if (!handled && default_target) {
+#if KBD_DEBUG
+ if (debug_keyboard) {
+ cerr << "PRESS: not handled, delivering to default target " << default_target << endl;
+ }
+#endif
+ default_target->key_press_event (event, state, handled);
+ }
+
+#if KBD_DEBUG
+ if (debug_keyboard) {
+ cerr << "PRESS: handled ? " << handled << endl;
+ }
+#endif
+
+ if (handled) {
+
+ /* don't reset collecting prefix is start_prefix()
+ was called by the handler.
+ */
+
+ if (collecting_prefix == old_collecting_prefix) {
+ collecting_prefix = false;
+ current_prefix = "";
+ }
+ }
+ }
+
+ } 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());
+ }
+
+ if (target) {
+#if KBD_DEBUG
+ if (debug_keyboard) {
+ cerr << "RELEASE: delivering to target " << target << endl;
+ }
+#endif
+ target->key_release_event (event, state);
+ }
+
+ if (default_target) {
+#if KBD_DEBUG
+ if (debug_keyboard) {
+ cerr << "RELEASE: delivering to default target " << default_target << endl;
+ }
+#endif
+ default_target->key_release_event (event, state);
+ }
+ }
+
+ return TRUE;
+}
+
+bool
+Keyboard::key_is_down (uint32_t keyval)
+{
+ return find (state.begin(), state.end(), keyval) != state.end();
+}
+
+void
+Keyboard::set_target (KeyboardTarget *kt)
+{
+ /* XXX possible thread issues here */
+ target = kt;
+}
+
+void
+Keyboard::maybe_unset_target (KeyboardTarget* kt)
+{
+ if (target == kt) {
+ target = 0;
+ }
+}
+
+void
+Keyboard::set_default_target (KeyboardTarget *kt)
+{
+ /* XXX possible thread issues here */
+
+ default_target = kt;
+}
+
+void
+Keyboard::allow_focus (bool yn)
+{
+ focus_allowed = yn;
+}
+
+Keyboard::State
+Keyboard::translate_key_name (const string& name)
+
+{
+ string::size_type i;
+ string::size_type len;
+ bool at_end;
+ string::size_type hyphen;
+ string keyname;
+ string whatevers_left;
+ State result;
+ guint keycode;
+
+ i = 0;
+ len = name.length();
+ at_end = (len == 0);
+
+ while (!at_end) {
+
+ whatevers_left = name.substr (i);
+
+ if ((hyphen = whatevers_left.find_first_of ('-')) == string::npos) {
+
+ /* no hyphen, so use the whole thing */
+
+ keyname = whatevers_left;
+ at_end = true;
+
+ } else {
+
+ /* There is a hyphen. */
+
+ if (hyphen == 0 && whatevers_left.length() == 1) {
+ /* its the first and only character */
+
+ keyname = "-";
+ at_end = true;
+
+ } else {
+
+ /* use the text before the hypen */
+
+ keyname = whatevers_left.substr (0, hyphen);
+
+ if (hyphen == len - 1) {
+ at_end = true;
+ } else {
+ i += hyphen + 1;
+ at_end = (i >= len);
+ }
+ }
+ }
+
+ if (keyname.length() == 1 && isupper (keyname[0])) {
+ result.push_back (GDK_Shift_L);
+ }
+
+ if ((keycode = gdk_keyval_from_name(get_real_keyname (keyname).c_str())) == GDK_VoidSymbol) {
+ error << compose(_("KeyboardTarget: keyname \"%1\" is unknown."), keyname) << endmsg;
+ result.clear();
+ return result;
+ }
+
+ result.push_back (keycode);
+ }
+
+ sort (result.begin(), result.end());
+
+ return result;
+}
+
+string
+Keyboard::get_real_keyname (const string& name)
+{
+
+ if (name == "Control" || name == "Ctrl") {
+ return "Control_L";
+ }
+ if (name == "Meta" || name == "MetaL") {
+ return "Meta_L";
+ }
+ if (name == "MetaR") {
+ return "Meta_R";
+ }
+ if (name == "Alt" || name == "AltL") {
+ return "Alt_L";
+ }
+ if (name == "AltR") {
+ return "Alt_R";
+ }
+ if (name == "Shift") {
+ return "Shift_L";
+ }
+ if (name == "Shift_R") {
+ return "Shift_L";
+ }
+ if (name == " ") {
+ return "space";
+ }
+ if (name == "!") {
+ return "exclam";
+ }
+ if (name == "\"") {
+ return "quotedbl";
+ }
+ if (name == "#") {
+ return "numbersign";
+ }
+ if (name == "$") {
+ return "dollar";
+ }
+ if (name == "%") {
+ return "percent";
+ }
+ if (name == "&") {
+ return "ampersand";
+ }
+ if (name == "'") {
+ return "apostrophe";
+ }
+ if (name == "'") {
+ return "quoteright";
+ }
+ if (name == "(") {
+ return "parenleft";
+ }
+ if (name == ")") {
+ return "parenright";
+ }
+ if (name == "*") {
+ return "asterisk";
+ }
+ if (name == "+") {
+ return "plus";
+ }
+ if (name == ",") {
+ return "comma";
+ }
+ if (name == "-") {
+ return "minus";
+ }
+ if (name == ".") {
+ return "period";
+ }
+ if (name == "/") {
+ return "slash";
+ }
+ if (name == ":") {
+ return "colon";
+ }
+ if (name == ";") {
+ return "semicolon";
+ }
+ if (name == "<") {
+ return "less";
+ }
+ if (name == "=") {
+ return "equal";
+ }
+ if (name == ">") {
+ return "greater";
+ }
+ if (name == "?") {
+ return "question";
+ }
+ if (name == "@") {
+ return "at";
+ }
+ if (name == "[") {
+ return "bracketleft";
+ }
+ if (name == "\\") {
+ return "backslash";
+ }
+ if (name == "]") {
+ return "bracketright";
+ }
+ if (name == "^") {
+ return "asciicircum";
+ }
+ if (name == "_") {
+ return "underscore";
+ }
+ if (name == "`") {
+ return "grave";
+ }
+ if (name == "`") {
+ return "quoteleft";
+ }
+ if (name == "{") {
+ return "braceleft";
+ }
+ if (name == "|") {
+ return "bar";
+ }
+ if (name == "}") {
+ return "braceright";
+ }
+ if (name == "~") {
+ return "asciitilde";
+ }
+
+ return name;
+}
+
+int
+Keyboard::get_prefix (float& val, bool& was_floating)
+{
+ if (current_prefix.length()) {
+ if (current_prefix.find ('.') != string::npos) {
+ was_floating = true;
+ } else {
+ was_floating = false;
+ }
+ if (sscanf (current_prefix.c_str(), "%f", &val) == 1) {
+ return 0;
+ }
+ current_prefix = "";
+ }
+ return -1;
+}
+
+void
+Keyboard::start_prefix ()
+{
+ collecting_prefix = true;
+ current_prefix = "";
+}
+
+void
+Keyboard::clear_modifier_state ()
+{
+ modifier_mask = 0;
+}
+
+void
+Keyboard::check_modifier_state ()
+{
+ char keys[32];
+ int i, j;
+
+ clear_modifier_state ();
+ XQueryKeymap (GDK_DISPLAY(), keys);
+
+ for (i = 0; i < 32; ++i) {
+ for (j = 0; j < 8; ++j) {
+
+ if (keys[i] & (1<<j)) {
+ modifier_mask |= modifier_masks[(i*8)+j];
+ }
+ }
+ }
+}
+
+void
+Keyboard::check_meta_numlock (char keycode, guint mod, string modname)
+{
+ guint alternate_meta_mod;
+ string alternate_meta_modname;
+
+ if (mod == Meta) {
+
+ guint keysym = XKeycodeToKeysym (GDK_DISPLAY(), keycode, 0);
+
+ if (keysym == GDK_Num_Lock) {
+
+ switch (mod) {
+ case GDK_MOD2_MASK:
+ alternate_meta_mod = GDK_MOD3_MASK;
+ alternate_meta_modname = "Mod3";
+ break;
+ case GDK_MOD3_MASK:
+ alternate_meta_mod = GDK_MOD2_MASK;
+ alternate_meta_modname = "Mod2";
+ break;
+ case GDK_MOD4_MASK:
+ alternate_meta_mod = GDK_MOD2_MASK;
+ alternate_meta_modname = "Mod2";
+ break;
+ case GDK_MOD5_MASK:
+ alternate_meta_mod = GDK_MOD2_MASK;
+ alternate_meta_modname = "Mod2";
+ break;
+ default:
+ error << compose (_("Your system is completely broken - NumLock uses \"%1\""
+ "as its modifier. This is madness - see the man page "
+ "for xmodmap to find out how to fix this."),
+ modname)
+ << endmsg;
+ return;
+ }
+
+ warning << compose (_("Your system generates \"%1\" when the NumLock key "
+ "is pressed. This can cause problems when editing "
+ "so Ardour will use %2 to mean Meta rather than %1"),
+ modname, alternate_meta_modname)
+ << endmsg;
+
+ set_meta_modifier (alternate_meta_mod);
+ }
+ }
+}
+
+void
+Keyboard::get_modifier_masks ()
+{
+ XModifierKeymap *modifiers;
+ KeyCode *keycode;
+ int i;
+ int bound;
+
+ XDisplayKeycodes (GDK_DISPLAY(), &min_keycode, &max_keycode);
+
+ /* This function builds a lookup table to provide rapid answers to
+ the question: what, if any, modmask, is associated with a given
+ keycode ?
+ */
+
+ modifiers = XGetModifierMapping (GDK_DISPLAY());
+
+ modifier_masks = new int32_t [max_keycode+1];
+
+ keycode = modifiers->modifiermap;
+
+ for (i = 0; i < modifiers->max_keypermod; ++i) { /* shift */
+ if (*keycode) {
+ modifier_masks[*keycode] = GDK_SHIFT_MASK;
+ // cerr << "Shift = " << XKeysymToString (XKeycodeToKeysym (GDK_DISPLAY(), *keycode, 0)) << endl;
+ }
+ keycode++;
+ }
+
+ for (i = 0; i < modifiers->max_keypermod; ++i) keycode++; /* skip lock */
+
+ for (i = 0; i < modifiers->max_keypermod; ++i) { /* control */
+ if (*keycode) {
+ modifier_masks[*keycode] = GDK_CONTROL_MASK;
+ // cerr << "Control = " << XKeysymToString (XKeycodeToKeysym (GDK_DISPLAY(), *keycode, 0)) << endl;
+ }
+ keycode++;
+ }
+
+ bound = 0;
+ for (i = 0; i < modifiers->max_keypermod; ++i) { /* mod 1 */
+ if (*keycode) {
+ modifier_masks[*keycode] = GDK_MOD1_MASK;
+ // cerr << "Mod1 = " << XKeysymToString (XKeycodeToKeysym (GDK_DISPLAY(), *keycode, 0)) << endl;
+ bound++;
+ }
+ keycode++;
+ }
+#ifdef WARN_ABOUT_DUPLICATE_MODIFIERS
+ if (bound > 1) {
+ warning << compose (_("You have %1 keys bound to \"mod1\""), bound) << endmsg;
+ }
+#endif
+ bound = 0;
+ for (i = 0; i < modifiers->max_keypermod; ++i) { /* mod2 */
+ if (*keycode) {
+ modifier_masks[*keycode] = GDK_MOD2_MASK;
+ check_meta_numlock (*keycode, GDK_MOD2_MASK, "Mod2");
+ //cerr << "Mod2 = " << std::hex << (int) *keycode << std::dec << " = " << XKeysymToString (XKeycodeToKeysym (GDK_DISPLAY(), *keycode, 0)) << endl;
+ bound++;
+ }
+ keycode++;
+ }
+#ifdef WARN_ABOUT_DUPLICATE_MODIFIERS
+ if (bound > 1) {
+ warning << compose (_("You have %1 keys bound to \"mod2\""), bound) << endmsg;
+ }
+#endif
+ bound = 0;
+ for (i = 0; i < modifiers->max_keypermod; ++i) { /* mod3 */
+ if (*keycode) {
+ modifier_masks[*keycode] = GDK_MOD3_MASK;
+ check_meta_numlock (*keycode, GDK_MOD3_MASK, "Mod3");
+ // cerr << "Mod3 = " << XKeysymToString (XKeycodeToKeysym (GDK_DISPLAY(), *keycode, 0)) << endl;
+ bound++;
+ }
+ keycode++;
+ }
+#ifdef WARN_ABOUT_DUPLICATE_MODIFIERS
+ if (bound > 1) {
+ warning << compose (_("You have %1 keys bound to \"mod3\""), bound) << endmsg;
+ }
+#endif
+ bound = 0;
+ for (i = 0; i < modifiers->max_keypermod; ++i) { /* mod 4 */
+ if (*keycode) {
+ modifier_masks[*keycode] = GDK_MOD4_MASK;
+ check_meta_numlock (*keycode, GDK_MOD4_MASK, "Mod4");
+ // cerr << "Mod4 = " << XKeysymToString (XKeycodeToKeysym (GDK_DISPLAY(), *keycode, 0)) << endl;
+ bound++;
+ }
+ keycode++;
+ }
+#ifdef WARN_ABOUT_DUPLICATE_MODIFIERS
+ if (bound > 1) {
+ warning << compose (_("You have %1 keys bound to \"mod4\""), bound) << endmsg;
+ }
+#endif
+ bound = 0;
+ for (i = 0; i < modifiers->max_keypermod; ++i) { /* mod 5 */
+ if (*keycode) {
+ modifier_masks[*keycode] = GDK_MOD5_MASK;
+ check_meta_numlock (*keycode, GDK_MOD5_MASK, "Mod5");
+ // cerr << "Mod5 = " << XKeysymToString (XKeycodeToKeysym (GDK_DISPLAY(), *keycode, 0)) << endl;
+ bound++;
+ }
+ keycode++;
+ }
+#ifdef WARN_ABOUT_DUPLICATE_MODIFIERS
+ if (bound > 1) {
+ warning << compose (_("You have %1 keys bound to \"mod5\""), bound) << endmsg;
+ }
+#endif
+
+ XFreeModifiermap (modifiers);
+}
+
+gint
+Keyboard::enter_window (GdkEventCrossing *ev, KeyboardTarget *kt)
+{
+ switch (ev->detail) {
+ case GDK_NOTIFY_INFERIOR:
+ if (debug_keyboard) {
+ cerr << "INFERIOR crossing to " << kt->name() << endl;
+ }
+ break;
+
+ case GDK_NOTIFY_VIRTUAL:
+ if (debug_keyboard) {
+ cerr << "VIRTUAL crossing to " << kt->name() << endl;
+ }
+ /* fallthru */
+
+ default:
+ if (debug_keyboard) {
+ cerr << "REAL crossing to " << kt->name() << endl;
+ cerr << "set current target to " << kt->name() << endl;
+ }
+
+ set_target (kt);
+ check_modifier_state ();
+ }
+
+ return FALSE;
+}
+
+gint
+Keyboard::leave_window (GdkEventCrossing *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";
+ }
+
+ set_target (0);
+ state.clear ();
+ clear_modifier_state ();
+ }
+ return FALSE;
+
+}
+
+void
+Keyboard::register_target (KeyboardTarget *kt)
+{
+ /* do not register the default - its not meant to be
+ an actual window, just a fallback if the current
+ target for keyboard events doesn't handle an event.
+ */
+
+ if (kt->name() == X_("default")) {
+ return;
+ }
+
+ kt->window().enter_notify_event.connect (bind (slot (*this, &Keyboard::enter_window), kt));
+ kt->window().leave_notify_event.connect (slot (*this, &Keyboard::leave_window));
+
+ kt->GoingAway.connect (bind (slot (*this, &Keyboard::maybe_unset_target), kt));
+ kt->Hiding.connect (bind (slot (*this, &Keyboard::maybe_unset_target), kt));
+}
+
+void
+Keyboard::set_current_dialog (ArdourDialog* dialog)
+{
+ ENSURE_GUI_THREAD(bind (slot (*this, &Keyboard::set_current_dialog), dialog));
+
+ current_dialog = dialog;
+
+ if (current_dialog) {
+
+ if (find (known_dialogs.begin(), known_dialogs.end(), dialog) == known_dialogs.end()) {
+
+ current_dialog->GoingAway.connect
+ (bind (slot (*this, &Keyboard::set_current_dialog),
+ reinterpret_cast<ArdourDialog *>(0)));
+ current_dialog->Hiding.connect
+ (bind (slot (*this, &Keyboard::set_current_dialog),
+ reinterpret_cast<ArdourDialog *>(0)));
+
+ current_dialog->unmap_event.connect (slot (*this, &Keyboard::current_dialog_vanished));
+
+ known_dialogs.push_back (dialog);
+ }
+ }
+}
+
+gint
+Keyboard::current_dialog_vanished (GdkEventAny *ev)
+{
+ current_dialog = 0;
+ state.clear ();
+ focus_allowed = false;
+ clear_modifier_state ();
+ current_prefix = "";
+
+ return FALSE;
+}
+
+void
+Keyboard::close_current_dialog ()
+{
+ if (current_dialog) {
+ current_dialog->hide ();
+ }
+}
+
+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_meta_modifier (guint mod)
+{
+ /* we don't include Meta in the RelevantModifierKeyMask because its not used
+ in the same way as snap_mod, delete_mod etc. the only reason we allow it to be
+ set at all is that X Window has no convention for the keyboard modifier
+ that Meta should use. Some Linux distributions bind NumLock to Mod2, which
+ is our default Meta modifier, and this causes severe problems.
+ */
+ Meta = mod;
+}
+
+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_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;
+}
+
+gint
+Keyboard::focus_in_handler (GdkEventFocus* ev)
+{
+ allow_focus (true);
+ return FALSE;
+}
+
+gint
+Keyboard::focus_out_handler (GdkEventFocus* ev)
+{
+ allow_focus (false);
+ return FALSE;
+}