From 322e6e08c436d98402c430fff7af5196137fe292 Mon Sep 17 00:00:00 2001 From: Robin Gareus Date: Mon, 16 Dec 2019 15:02:39 +0100 Subject: [PATCH] Vkeybd: grab all key-events and use timer instead of key-repeat This fixes an issue with arrow-keys (up/down, left/right). Those were previously only handled when the Virtual Keyboard window itself had focus. Also key-repeat for pitch-bend is now ignored and a dedicated timer is used to queue events. This fixes an issue with the first repeat taking longer than successive ones, and makes this feature independent of any desktop user settings. --- gtk2_ardour/pianokeyboard.cc | 61 +++++++++++++++ gtk2_ardour/pianokeyboard.h | 12 ++- gtk2_ardour/virtual_keyboard_window.cc | 102 ++++++++++++------------- gtk2_ardour/virtual_keyboard_window.h | 7 ++ 4 files changed, 123 insertions(+), 59 deletions(-) diff --git a/gtk2_ardour/pianokeyboard.cc b/gtk2_ardour/pianokeyboard.cc index c68b674742..c41e8dae5a 100644 --- a/gtk2_ardour/pianokeyboard.cc +++ b/gtk2_ardour/pianokeyboard.cc @@ -558,12 +558,69 @@ get_keycode (GdkEventKey* event) return gdk_keyval_name (gdk_keyval_to_lower (keyval)); } +bool +APianoKeyboard::handle_fixed_keys (GdkEventKey* ev) +{ + if (ev->type == GDK_KEY_PRESS) { + switch (ev->keyval) { + case GDK_KEY_Left: + SwitchOctave (false); + return true; + case GDK_KEY_Right: + SwitchOctave (true); + return true; + case GDK_KEY_F1: + PitchBend (0, false); + return true; + case GDK_KEY_F2: + PitchBend (4096, false); + return true; + case GDK_KEY_F3: + PitchBend (12288, false); + return true; + case GDK_KEY_F4: + PitchBend (16383, false); + return true; + case GDK_KEY_Down: + PitchBend (0, true); + return true; + case GDK_KEY_Up: + PitchBend (16383, true); + return true; + default: + break; + } + } else if (ev->type == GDK_KEY_RELEASE) { + switch (ev->keyval) { + case GDK_KEY_F1: + /* fallthrough */ + case GDK_KEY_F2: + /* fallthrough */ + case GDK_KEY_F3: + /* fallthrough */ + case GDK_KEY_F4: + /* fallthrough */ + case GDK_KEY_Up: + /* fallthrough */ + case GDK_KEY_Down: + PitchBend (8192, false); + return true; + default: + break; + } + } + return false; +} + bool APianoKeyboard::on_key_press_event (GdkEventKey* event) { if (Gtkmm2ext::Keyboard::modifier_state_contains (event->state, Gtkmm2ext::Keyboard::PrimaryModifier)) { return false; } + if (handle_fixed_keys (event)) { + return true; + } char const* key = get_keycode (event); int note = key_binding (key); @@ -603,6 +660,10 @@ APianoKeyboard::on_key_release_event (GdkEventKey* event) if (Gtkmm2ext::Keyboard::modifier_state_contains (event->state, Gtkmm2ext::Keyboard::PrimaryModifier)) { return false; } + if (handle_fixed_keys (event)) { + return true; + } + char const* key = get_keycode (event); if (!key) { diff --git a/gtk2_ardour/pianokeyboard.h b/gtk2_ardour/pianokeyboard.h index 2b12befe73..042afcd283 100644 --- a/gtk2_ardour/pianokeyboard.h +++ b/gtk2_ardour/pianokeyboard.h @@ -31,10 +31,12 @@ public: APianoKeyboard (); ~APianoKeyboard (); - sigc::signal NoteOn; - sigc::signal NoteOff; - sigc::signal Rest; - sigc::signal SustainChanged; + sigc::signal NoteOn; + sigc::signal NoteOff; + sigc::signal Rest; + sigc::signal SustainChanged; + sigc::signal PitchBend; + sigc::signal SwitchOctave; enum Layout { QWERTY, @@ -79,6 +81,8 @@ private: void queue_note_draw (int note); + bool handle_fixed_keys (GdkEventKey*); + void press_key (int key, int vel); void release_key (int key); void stop_sustained_notes (); diff --git a/gtk2_ardour/virtual_keyboard_window.cc b/gtk2_ardour/virtual_keyboard_window.cc index 5ce4b28b75..f277693386 100644 --- a/gtk2_ardour/virtual_keyboard_window.cc +++ b/gtk2_ardour/virtual_keyboard_window.cc @@ -243,6 +243,8 @@ VirtualKeyboardWindow::VirtualKeyboardWindow () _piano.NoteOn.connect (sigc::mem_fun (*this, &VirtualKeyboardWindow::note_on_event_handler)); _piano.NoteOff.connect (sigc::mem_fun (*this, &VirtualKeyboardWindow::note_off_event_handler)); + _piano.SwitchOctave.connect (sigc::mem_fun (*this, &VirtualKeyboardWindow::octave_key_event_handler)); + _piano.PitchBend.connect (sigc::mem_fun (*this, &VirtualKeyboardWindow::pitch_bend_key_event_handler)); update_velocity_settings (0); update_octave_range (); @@ -379,41 +381,6 @@ VirtualKeyboardWindow::on_key_press_event (GdkEventKey* ev) _piano.grab_focus (); - /* handle up/down */ - // XXX consider to handle these in APianoKeyboard::on_key_press_event - // and use signals. -- also subscribe SustainChanged, indicate sustain. - // TODO: pitch-bend shortcuts - if (ev->type == GDK_KEY_PRESS) { - switch (ev->keyval) { - case GDK_KEY_Left: - _piano_octave_key.set_value (_piano_octave_key.get_value_as_int () - 1); - return true; - case GDK_KEY_Right: - _piano_octave_key.set_value (_piano_octave_key.get_value_as_int () + 1); - return true; - case GDK_KEY_F1: - _pitch_adjustment.set_value (0); - return true; - case GDK_KEY_F2: - _pitch_adjustment.set_value (4096); - return true; - case GDK_KEY_F3: - _pitch_adjustment.set_value (12288); - return true; - case GDK_KEY_F4: - _pitch_adjustment.set_value (16383); - return true; - case GDK_KEY_Down: - _pitch_adjustment.set_value (std::max(0., _pitch_adjustment.get_value() - 1024)); - return true; - case GDK_KEY_Up: - _pitch_adjustment.set_value (std::min(16383., _pitch_adjustment.get_value() + 1024)); - return true; - default: - break; - } - } - return ARDOUR_UI_UTILS::relay_key_press (ev, this); } @@ -429,26 +396,6 @@ VirtualKeyboardWindow::on_key_release_event (GdkEventKey* ev) _piano.grab_focus (); - if (ev->type == GDK_KEY_RELEASE) { - switch (ev->keyval) { - case GDK_KEY_F1: - /* fallthrough */ - case GDK_KEY_F2: - /* fallthrough */ - case GDK_KEY_F3: - /* fallthrough */ - case GDK_KEY_F4: - /* fallthrough */ - case GDK_KEY_Up: - /* fallthrough */ - case GDK_KEY_Down: - _pitch_adjustment.set_value (8192); - return true; - default: - break; - } - } - return ArdourWindow::on_key_release_event (ev); } @@ -604,6 +551,51 @@ VirtualKeyboardWindow::update_sensitivity () _piano.grab_focus (); } +void +VirtualKeyboardWindow::octave_key_event_handler (bool up) +{ + if (up) { + _piano_octave_key.set_value (_piano_octave_key.get_value_as_int () - 1); + } else { + _piano_octave_key.set_value (_piano_octave_key.get_value_as_int () + 1); + } +} + +void +VirtualKeyboardWindow::pitch_bend_key_event_handler (int target, bool interpolate) +{ + if (_pitch_adjustment.get_value() == target) { + return; + } + if (interpolate) { + _pitch_bend_target = target; + if (!_bender_connection.connected ()){ + _bender_connection = Glib::signal_timeout().connect (sigc::mem_fun(*this, &VirtualKeyboardWindow::pitch_bend_timeout), 50 /*ms*/); + } else { + } + return; + } + _bender_connection.disconnect (); + _pitch_adjustment.set_value (target); + _pitch_bend_target = target; +} + +bool +VirtualKeyboardWindow::pitch_bend_timeout () +{ + int cur = _pitch_adjustment.get_value(); + int target; + if (cur < _pitch_bend_target) { + target = std::min (_pitch_bend_target, cur + 1024); + } else if (cur > _pitch_bend_target) { + target = std::max (_pitch_bend_target, cur - 1024); + } else { + target = _pitch_bend_target; + } + _pitch_adjustment.set_value (target); + return _pitch_bend_target != target; +} + void VirtualKeyboardWindow::pitch_slider_adjusted () { diff --git a/gtk2_ardour/virtual_keyboard_window.h b/gtk2_ardour/virtual_keyboard_window.h index 3ee663b102..0db53472f2 100644 --- a/gtk2_ardour/virtual_keyboard_window.h +++ b/gtk2_ardour/virtual_keyboard_window.h @@ -104,6 +104,10 @@ private: void note_off_event_handler (int); void control_change_event_handler (int, int); + void octave_key_event_handler (bool); + void pitch_bend_key_event_handler (int, bool); + bool pitch_bend_timeout (); + void pitch_bend_event_handler (int); void pitch_bend_release (); void pitch_bend_update_tooltip (int); @@ -158,6 +162,9 @@ private: ArdourWidgets::ArdourDropdown _cc_key[VKBD_NCTRLS]; PBD::ScopedConnectionList _cc_connections; + + sigc::connection _bender_connection; + int _pitch_bend_target; }; #endif