diff --git a/build/linux/platform_specific_code/juce_linux_Windowing.cpp b/build/linux/platform_specific_code/juce_linux_Windowing.cpp index 9e65927deb..02017e3d2a 100644 --- a/build/linux/platform_specific_code/juce_linux_Windowing.cpp +++ b/build/linux/platform_specific_code/juce_linux_Windowing.cpp @@ -1067,7 +1067,8 @@ public: if (windowH != 0 && XGetWindowAttributes (display, windowH, &atts) - && atts.map_state == IsViewable) + && atts.map_state == IsViewable + && ! isFocused()) { XSetInputFocus (display, windowH, RevertToParent, CurrentTime); diff --git a/docs/JUCE changelist.txt b/docs/JUCE changelist.txt index 29a5d06b7e..4eda61451d 100644 --- a/docs/JUCE changelist.txt +++ b/docs/JUCE changelist.txt @@ -6,6 +6,7 @@ ============================================================================== Changelist for version 1.44 +- change to the keyPressed() and keyStateChanged() callbacks in Component and KeyListener. These used to be void, but they now return a bool to indicate whether the key event was needed or not. Any existing code you've got will break in the compiler, so just change it to return true if the key was used, or false to allow the event to be passed up to the next component in the chain. (This change is a better architecture than before, and was also needed so that plugins can allow unused key events to be passed on to the host application) - swapped the look and feel classes around, so that the basic LookAndFeel class is now what used to be the "shiny" one. The ShinyLookAndFeel class has been removed, and for that old fashioned look, I've added an OldSchoolLookAndFeel that you can use if you need the original L+F. This means that any custom looks that you were using may need to change their base class. - changed the MouseEvent structure so that it now contains a pointer to the event component and also the original component. - added a PopupMenu::dismissAllActiveMenus() method. diff --git a/extras/the jucer/src/model/jucer_JucerDocument.cpp b/extras/the jucer/src/model/jucer_JucerDocument.cpp index eb74297128..80ec95fec4 100644 --- a/extras/the jucer/src/model/jucer_JucerDocument.cpp +++ b/extras/the jucer/src/model/jucer_JucerDocument.cpp @@ -299,8 +299,8 @@ void JucerDocument::getOptionalMethods (StringArray& baseClasses, addMethod ("Component", "void", "mouseDoubleClick (const MouseEvent& e)", "", baseClasses, returnValues, methods, initialContents); addMethod ("Component", "void", "mouseWheelMove (const MouseEvent& e, float wheelIncrement)", "", baseClasses, returnValues, methods, initialContents); - addMethod ("Component", "void", "keyPressed (const KeyPress& key)", "", baseClasses, returnValues, methods, initialContents); - addMethod ("Component", "void", "keyStateChanged()", "", baseClasses, returnValues, methods, initialContents); + addMethod ("Component", "bool", "keyPressed (const KeyPress& key)", "return false; // Return true if your handler uses this key event, or false to allow it to be passed-on.", baseClasses, returnValues, methods, initialContents); + addMethod ("Component", "bool", "keyStateChanged()", "return false; // Return true if your handler uses this key event, or false to allow it to be passed-on.", baseClasses, returnValues, methods, initialContents); addMethod ("Component", "void", "modifierKeysChanged (const ModifierKeys& modifiers)", "", baseClasses, returnValues, methods, initialContents); addMethod ("Component", "void", "focusGained (FocusChangeType cause)", "", baseClasses, returnValues, methods, initialContents); diff --git a/extras/the jucer/src/ui/jucer_ComponentLayoutEditor.cpp b/extras/the jucer/src/ui/jucer_ComponentLayoutEditor.cpp index 48bb893b54..17ccae3b97 100644 --- a/extras/the jucer/src/ui/jucer_ComponentLayoutEditor.cpp +++ b/extras/the jucer/src/ui/jucer_ComponentLayoutEditor.cpp @@ -325,7 +325,7 @@ static void moveOrStretch (ComponentLayout& layout, int x, int y, bool snap, boo layout.moveSelectedComps (x, y, snap); } -void ComponentLayoutEditor::keyPressed (const KeyPress& key) +bool ComponentLayoutEditor::keyPressed (const KeyPress& key) { const bool snap = key.getModifiers().isAltDown(); const bool stretch = key.getModifiers().isShiftDown(); @@ -351,8 +351,10 @@ void ComponentLayoutEditor::keyPressed (const KeyPress& key) } else { - Component::keyPressed (key); + return false; } + + return true; } bool ComponentLayoutEditor::filesDropped (const StringArray& filenames, int x, int y) diff --git a/extras/the jucer/src/ui/jucer_ComponentLayoutEditor.h b/extras/the jucer/src/ui/jucer_ComponentLayoutEditor.h index 00969e5b4b..362216fac9 100644 --- a/extras/the jucer/src/ui/jucer_ComponentLayoutEditor.h +++ b/extras/the jucer/src/ui/jucer_ComponentLayoutEditor.h @@ -58,7 +58,7 @@ public: void mouseDown (const MouseEvent& e); void mouseDrag (const MouseEvent& e); void mouseUp (const MouseEvent& e); - void keyPressed (const KeyPress& key); + bool keyPressed (const KeyPress& key); bool filesDropped (const StringArray& filenames, int x, int y); ComponentLayout& getLayout() const throw() { return layout; } diff --git a/src/juce_appframework/gui/components/buttons/juce_Button.cpp b/src/juce_appframework/gui/components/buttons/juce_Button.cpp index c0b92f4938..1ee896f9f4 100644 --- a/src/juce_appframework/gui/components/buttons/juce_Button.cpp +++ b/src/juce_appframework/gui/components/buttons/juce_Button.cpp @@ -601,34 +601,40 @@ bool Button::isRegisteredForShortcut (const KeyPress& key) const throw() return false; } -void Button::keyStateChanged (Component*) +bool Button::keyStateChanged (Component*) { - if (isEnabled()) - { - const bool wasDown = isKeyDown; - isKeyDown = isShortcutPressed(); + if (! isEnabled()) + return false; - if (autoRepeatDelay >= 0 && (isKeyDown && !wasDown)) - getRepeatTimer().startTimer (autoRepeatDelay); + const bool wasDown = isKeyDown; + isKeyDown = isShortcutPressed(); - updateState (0); + if (autoRepeatDelay >= 0 && (isKeyDown && ! wasDown)) + getRepeatTimer().startTimer (autoRepeatDelay); - if (isEnabled() && wasDown && ! isKeyDown) - internalClickCallback (ModifierKeys::getCurrentModifiers()); - } + updateState (0); + + if (isEnabled() && wasDown && ! isKeyDown) + internalClickCallback (ModifierKeys::getCurrentModifiers()); + + return isKeyDown || wasDown; } -void Button::keyPressed (const KeyPress&, Component*) +bool Button::keyPressed (const KeyPress&, Component*) { - // (not actually used - the key detection happens in keyStateChanged) + // return true to avoid forwarding events for keys that we're using as shortcuts + return isShortcutPressed(); } -void Button::keyPressed (const KeyPress& key) +bool Button::keyPressed (const KeyPress& key) { if (isEnabled() && key.isKeyCode (KeyPress::returnKey)) + { triggerClick(); - else - Component::keyPressed (key); + return true; + } + + return false; } //============================================================================== diff --git a/src/juce_appframework/gui/components/buttons/juce_Button.h b/src/juce_appframework/gui/components/buttons/juce_Button.h index a9a91a9b52..876140cf39 100644 --- a/src/juce_appframework/gui/components/buttons/juce_Button.h +++ b/src/juce_appframework/gui/components/buttons/juce_Button.h @@ -439,11 +439,11 @@ protected: /** @internal */ void mouseUp (const MouseEvent& e); /** @internal */ - void keyPressed (const KeyPress& key); + bool keyPressed (const KeyPress& key); /** @internal */ - void keyPressed (const KeyPress& key, Component* originatingComponent); + bool keyPressed (const KeyPress& key, Component* originatingComponent); /** @internal */ - void keyStateChanged (Component* originatingComponent); + bool keyStateChanged (Component* originatingComponent); /** @internal */ void paint (Graphics& g); /** @internal */ diff --git a/src/juce_appframework/gui/components/controls/juce_ComboBox.cpp b/src/juce_appframework/gui/components/controls/juce_ComboBox.cpp index c4d025ac1d..36a326239e 100644 --- a/src/juce_appframework/gui/components/controls/juce_ComboBox.cpp +++ b/src/juce_appframework/gui/components/controls/juce_ComboBox.cpp @@ -282,9 +282,9 @@ int ComboBox::getSelectedItemIndex() const throw() } void ComboBox::setSelectedItemIndex (const int index, - const bool dontSendChangeMessage) + const bool dontSendChangeMessage) throw() { - if (getSelectedItemIndex() != index) + if (currentIndex != index) { if (index >= 0 && index < getNumItems()) currentIndex = index; @@ -299,7 +299,7 @@ void ComboBox::setSelectedItemIndex (const int index, } void ComboBox::setSelectedId (const int newItemId, - const bool dontSendChangeMessage) + const bool dontSendChangeMessage) throw() { for (int i = getNumItems(); --i >= 0;) { @@ -349,7 +349,7 @@ const String ComboBox::getText() const throw() } void ComboBox::setText (const String& newText, - const bool dontSendChangeMessage) + const bool dontSendChangeMessage) throw() { for (int i = items.size(); --i >= 0;) { @@ -461,38 +461,38 @@ void ComboBox::colourChanged() } //============================================================================== -void ComboBox::keyPressed (const KeyPress& key) +bool ComboBox::keyPressed (const KeyPress& key) { + bool used = false; + if (key.isKeyCode (KeyPress::upKey) || key.isKeyCode (KeyPress::leftKey)) { setSelectedItemIndex (jmax (0, currentIndex - 1)); + used = true; } else if (key.isKeyCode (KeyPress::downKey) || key.isKeyCode (KeyPress::rightKey)) { setSelectedItemIndex (jmin (currentIndex + 1, getNumItems() - 1)); + used = true; } else if (key.isKeyCode (KeyPress::returnKey)) { showPopup(); + used = true; } - else - { - Component::keyPressed (key); - } + + return used; } -void ComboBox::keyStateChanged() +bool ComboBox::keyStateChanged() { // only forward key events that aren't used by this component - if (! (KeyPress::isKeyCurrentlyDown (KeyPress::upKey) - || KeyPress::isKeyCurrentlyDown (KeyPress::leftKey) - || KeyPress::isKeyCurrentlyDown (KeyPress::downKey) - || KeyPress::isKeyCurrentlyDown (KeyPress::rightKey))) - { - Component::keyStateChanged(); - } + return KeyPress::isKeyCurrentlyDown (KeyPress::upKey) + || KeyPress::isKeyCurrentlyDown (KeyPress::leftKey) + || KeyPress::isKeyCurrentlyDown (KeyPress::downKey) + || KeyPress::isKeyCurrentlyDown (KeyPress::rightKey); } //============================================================================== diff --git a/src/juce_appframework/gui/components/controls/juce_ComboBox.h b/src/juce_appframework/gui/components/controls/juce_ComboBox.h index e9f3431e2e..46bb236ee9 100644 --- a/src/juce_appframework/gui/components/controls/juce_ComboBox.h +++ b/src/juce_appframework/gui/components/controls/juce_ComboBox.h @@ -212,7 +212,7 @@ public: @see getSelectedId, setSelectedItemIndex, setText */ void setSelectedId (const int newItemId, - const bool dontSendChangeMessage = false); + const bool dontSendChangeMessage = false) throw(); //============================================================================== /** Returns the index of the item that's currently shown in the box. @@ -236,7 +236,7 @@ public: @see getSelectedItemIndex, setSelectedId, setText */ void setSelectedItemIndex (const int newItemIndex, - const bool dontSendChangeMessage = false); + const bool dontSendChangeMessage = false) throw(); //============================================================================== /** Returns the text that is currently shown in the combo-box's text field. @@ -262,7 +262,7 @@ public: @see getText */ void setText (const String& newText, - const bool dontSendChangeMessage = false); + const bool dontSendChangeMessage = false) throw(); //============================================================================== /** Registers a listener that will be called when the box's content changes. */ @@ -366,8 +366,8 @@ private: void lookAndFeelChanged(); void paint (Graphics&); void resized(); - void keyStateChanged(); - void keyPressed (const KeyPress&); + bool keyStateChanged(); + bool keyPressed (const KeyPress&); void showPopup(); diff --git a/src/juce_appframework/gui/components/controls/juce_ListBox.cpp b/src/juce_appframework/gui/components/controls/juce_ListBox.cpp index fce0a75b9c..04f041a159 100644 --- a/src/juce_appframework/gui/components/controls/juce_ListBox.cpp +++ b/src/juce_appframework/gui/components/controls/juce_ListBox.cpp @@ -664,7 +664,7 @@ void ListBox::scrollToEnsureRowIsOnscreen (const int row) } //============================================================================== -void ListBox::keyPressed (const KeyPress& key) +bool ListBox::keyPressed (const KeyPress& key) { const int numVisibleRows = viewport->getHeight() / getRowHeight(); @@ -734,22 +734,21 @@ void ListBox::keyPressed (const KeyPress& key) } else { - Component::keyPressed (key); + return false; } + + return true; } -void ListBox::keyStateChanged() +bool ListBox::keyStateChanged() { - if (! (KeyPress::isKeyCurrentlyDown (KeyPress::upKey) - || KeyPress::isKeyCurrentlyDown (KeyPress::pageUpKey) - || KeyPress::isKeyCurrentlyDown (KeyPress::downKey) - || KeyPress::isKeyCurrentlyDown (KeyPress::pageDownKey) - || KeyPress::isKeyCurrentlyDown (KeyPress::homeKey) - || KeyPress::isKeyCurrentlyDown (KeyPress::endKey) - || KeyPress::isKeyCurrentlyDown (KeyPress::returnKey))) - { - Component::keyStateChanged(); - } + return KeyPress::isKeyCurrentlyDown (KeyPress::upKey) + || KeyPress::isKeyCurrentlyDown (KeyPress::pageUpKey) + || KeyPress::isKeyCurrentlyDown (KeyPress::downKey) + || KeyPress::isKeyCurrentlyDown (KeyPress::pageDownKey) + || KeyPress::isKeyCurrentlyDown (KeyPress::homeKey) + || KeyPress::isKeyCurrentlyDown (KeyPress::endKey) + || KeyPress::isKeyCurrentlyDown (KeyPress::returnKey); } void ListBox::mouseWheelMove (const MouseEvent& e, float wheelIncrementX, float wheelIncrementY) diff --git a/src/juce_appframework/gui/components/controls/juce_ListBox.h b/src/juce_appframework/gui/components/controls/juce_ListBox.h index 619beee15e..2c42eb32c3 100644 --- a/src/juce_appframework/gui/components/controls/juce_ListBox.h +++ b/src/juce_appframework/gui/components/controls/juce_ListBox.h @@ -502,9 +502,9 @@ public: //============================================================================== /** @internal */ - void keyPressed (const KeyPress& key); + bool keyPressed (const KeyPress& key); /** @internal */ - void keyStateChanged(); + bool keyStateChanged(); /** @internal */ void paint (Graphics& g); /** @internal */ diff --git a/src/juce_appframework/gui/components/controls/juce_TableListBox.cpp b/src/juce_appframework/gui/components/controls/juce_TableListBox.cpp index 78815adfde..f28ae0b45b 100644 --- a/src/juce_appframework/gui/components/controls/juce_TableListBox.cpp +++ b/src/juce_appframework/gui/components/controls/juce_TableListBox.cpp @@ -397,6 +397,26 @@ const Rectangle TableListBox::getCellPosition (const int columnId, const int row headerCell.getWidth(), row.getHeight()); } +void TableListBox::scrollToEnsureColumnIsOnscreen (const int columnId) +{ + ScrollBar* const scrollbar = getHorizontalScrollBar(); + + if (scrollbar != 0) + { + const Rectangle pos (header->getColumnPosition (header->getIndexOfColumnId (columnId, true))); + + double x = scrollbar->getCurrentRangeStart(); + double w = scrollbar->getCurrentRangeSize(); + + if (pos.getX() < x) + x = pos.getX(); + else if (pos.getRight() > x + w) + x += jmax (0.0, pos.getRight() - (x + w)); + + scrollbar->setCurrentRangeStart (x); + } +} + int TableListBox::getNumRows() { return model != 0 ? model->getNumRows() : 0; diff --git a/src/juce_appframework/gui/components/controls/juce_TableListBox.h b/src/juce_appframework/gui/components/controls/juce_TableListBox.h index f6157a7904..3c2e6d6017 100644 --- a/src/juce_appframework/gui/components/controls/juce_TableListBox.h +++ b/src/juce_appframework/gui/components/controls/juce_TableListBox.h @@ -270,6 +270,12 @@ public: */ const Rectangle getCellPosition (const int columnId, const int rowNumber) const; + /** Scrolls horizontally if necessary to make sure that a particular column is visible. + + @see ListBox::scrollToEnsureRowIsOnscreen + */ + void scrollToEnsureColumnIsOnscreen (const int columnId); + //============================================================================== /** @internal */ int getNumRows(); diff --git a/src/juce_appframework/gui/components/controls/juce_TextEditor.cpp b/src/juce_appframework/gui/components/controls/juce_TextEditor.cpp index cd29409f29..9fee7d5262 100644 --- a/src/juce_appframework/gui/components/controls/juce_TextEditor.cpp +++ b/src/juce_appframework/gui/components/controls/juce_TextEditor.cpp @@ -1678,13 +1678,10 @@ void TextEditor::mouseWheelMove (const MouseEvent& e, float wheelIncrementX, flo } //============================================================================== -void TextEditor::keyPressed (const KeyPress& key) +bool TextEditor::keyPressed (const KeyPress& key) { if (isReadOnly() && key != KeyPress (T('c'), ModifierKeys::commandModifier, 0)) - { - Component::keyPressed (key); - return; - } + return false; const bool moveInWholeWordSteps = key.getModifiers().isCtrlDown() || key.getModifiers().isAltDown(); @@ -1850,13 +1847,16 @@ void TextEditor::keyPressed (const KeyPress& key) } else { - Component::keyPressed (key); + return false; } + + return true; } -void TextEditor::keyStateChanged() +bool TextEditor::keyStateChanged() { // (overridden to avoid forwarding key events to the parent) + return true; } //============================================================================== diff --git a/src/juce_appframework/gui/components/controls/juce_TextEditor.h b/src/juce_appframework/gui/components/controls/juce_TextEditor.h index b969a85491..70045449ed 100644 --- a/src/juce_appframework/gui/components/controls/juce_TextEditor.h +++ b/src/juce_appframework/gui/components/controls/juce_TextEditor.h @@ -484,9 +484,9 @@ l */ /** @internal */ void mouseWheelMove (const MouseEvent& e, float wheelIncrementX, float wheelIncrementY); /** @internal */ - void keyPressed (const KeyPress& key); + bool keyPressed (const KeyPress& key); /** @internal */ - void keyStateChanged(); + bool keyStateChanged(); /** @internal */ void focusGained (FocusChangeType cause); /** @internal */ diff --git a/src/juce_appframework/gui/components/controls/juce_TreeView.cpp b/src/juce_appframework/gui/components/controls/juce_TreeView.cpp index b03d0e5c5c..13699f261c 100644 --- a/src/juce_appframework/gui/components/controls/juce_TreeView.cpp +++ b/src/juce_appframework/gui/components/controls/juce_TreeView.cpp @@ -512,7 +512,7 @@ void TreeView::scrollToKeepItemVisible (TreeViewItem* item) } } -void TreeView::keyPressed (const KeyPress& key) +bool TreeView::keyPressed (const KeyPress& key) { if (key.isKeyCode (KeyPress::upKey)) { @@ -587,8 +587,10 @@ void TreeView::keyPressed (const KeyPress& key) } else { - Component::keyPressed (key); + return false; } + + return true; } void TreeView::itemsChanged() throw() diff --git a/src/juce_appframework/gui/components/controls/juce_TreeView.h b/src/juce_appframework/gui/components/controls/juce_TreeView.h index 0e8ba9ed9e..a4b37e0920 100644 --- a/src/juce_appframework/gui/components/controls/juce_TreeView.h +++ b/src/juce_appframework/gui/components/controls/juce_TreeView.h @@ -557,7 +557,7 @@ public: /** @internal */ void resized(); /** @internal */ - void keyPressed (const KeyPress& key); + bool keyPressed (const KeyPress& key); /** @internal */ void colourChanged(); diff --git a/src/juce_appframework/gui/components/juce_Component.cpp b/src/juce_appframework/gui/components/juce_Component.cpp index ab240a77a2..31cd725582 100644 --- a/src/juce_appframework/gui/components/juce_Component.cpp +++ b/src/juce_appframework/gui/components/juce_Component.cpp @@ -1525,7 +1525,7 @@ bool Component::isCurrentlyBlockedByAnotherModalComponent() const throw() && ! mc->canModalEventBeSentToComponent (this); } -Component* Component::getCurrentlyModalComponent() throw() +Component* JUCE_CALLTYPE Component::getCurrentlyModalComponent() throw() { Component* const c = (Component*) modalComponentStack.getLast(); @@ -3466,81 +3466,14 @@ void Component::removeKeyListener (KeyListener* const listenerToRemove) throw() keyListeners_->removeValue (listenerToRemove); } -void Component::keyPressed (const KeyPress& key) +bool Component::keyPressed (const KeyPress&) { - const ComponentDeletionWatcher deletionChecker (this); - - if (key.isKeyCode (KeyPress::tabKey) - && getCurrentlyFocusedComponent()->isValidComponent()) - { - getCurrentlyFocusedComponent()->moveKeyboardFocusToSibling (! key.getModifiers().isShiftDown()); - } - else if (parentComponent_ != 0) - { - parentComponent_->keyPressed (key); - } - - if ((! deletionChecker.hasBeenDeleted()) && keyListeners_ != 0) - { - for (int i = keyListeners_->size(); --i >= 0;) - { - ((KeyListener*) keyListeners_->getUnchecked(i))->keyPressed (key, this); - - if (deletionChecker.hasBeenDeleted()) - return; - - i = jmin (i, keyListeners_->size()); - } - } -} - -void Component::keyStateChanged() -{ - const ComponentDeletionWatcher deletionChecker (this); - - if (parentComponent_ != 0) - parentComponent_->keyStateChanged(); - - if ((! deletionChecker.hasBeenDeleted()) && keyListeners_ != 0) - { - for (int i = keyListeners_->size(); --i >= 0;) - { - ((KeyListener*) keyListeners_->getUnchecked(i))->keyStateChanged (this); - - if (deletionChecker.hasBeenDeleted()) - return; - - i = jmin (i, keyListeners_->size()); - } - } -} - -bool Component::internalKeyPress (const int key, const juce_wchar textCharacter) -{ - const KeyPress keyPress (key, - ModifierKeys::getCurrentModifiers().getRawFlags() - & ModifierKeys::allKeyboardModifiers, - textCharacter); - - if (isCurrentlyBlockedByAnotherModalComponent()) - { - Component* const currentModalComp = getCurrentlyModalComponent(); - - if (currentModalComp != 0) - currentModalComp->keyPressed (keyPress); - } - else - { - keyPressed (keyPress); - } - - return true; + return false; } -bool Component::internalKeyStateChanged() +bool Component::keyStateChanged() { - keyStateChanged(); - return true; + return false; } void Component::modifierKeysChanged (const ModifierKeys& modifiers) diff --git a/src/juce_appframework/gui/components/juce_Component.h b/src/juce_appframework/gui/components/juce_Component.h index 117d8281d4..e4d8647a88 100644 --- a/src/juce_appframework/gui/components/juce_Component.h +++ b/src/juce_appframework/gui/components/juce_Component.h @@ -1452,21 +1452,17 @@ public: method called. Remember that a component will only be given the focus if its setWantsKeyboardFocus() method has been used to enable this. - The default implementation of this method does the following: + If your implementation returns true, the event will be consumed and not passed + on to any other listeners. If it returns false, the key will be passed to any + KeyListeners that have been registered with this component. As soon as one of these + returns true, the process will stop, but if they all return false, the event will + be passed upwards to this component's parent, and so on. - - calls its parent's keyPressed() method, so that its parents will get a chance - to use any keypresses that this component isn't interested in. - - calls the keyPressed() methods of any KeyListeners that have registered with the - addKeyListener() method. - - If you want to use the keypresses that reach this component and stop them being sent up to - the parents, override this method. Of course a component can consume some keypresses - selectively and then for others, just call the superclass's Component::keyPressed method - to pass on the unwanted ones. + The default implementation of this method does nothing and returns false. @see keyStateChanged, getCurrentlyFocusedComponent, addKeyListener */ - virtual void keyPressed (const KeyPress& key); + virtual bool keyPressed (const KeyPress& key); /** Called when a key is pressed or released. @@ -1475,19 +1471,20 @@ public: has the keyboard focus. Remember that a component will only be given the focus if its setWantsKeyboardFocus() method has been used to enable this. - To find out which keys are up or down at any time, see the KeyPress::isKeyCurrentlyDown() - method. + If your implementation returns true, the event will be consumed and not passed + on to any other listeners. If it returns false, then any KeyListeners that have + been registered with this component will have their keyStateChanged methods called. + As soon as one of these returns true, the process will stop, but if they all return + false, the event will be passed upwards to this component's parent, and so on. - The default implementation of this method does the following: + The default implementation of this method does nothing and returns false. - - calls its parent's keyStateChanged() method, so that its parents will get a chance - to use any events that this component isn't interested in. - - calls the keyStateChanged() methods of any KeyListeners that have registered with the - addKeyListener() method. + To find out which keys are up or down at any time, see the KeyPress::isKeyCurrentlyDown() + method. @see keyPressed, KeyPress, getCurrentlyFocusedComponent, addKeyListener */ - virtual void keyStateChanged(); + virtual bool keyStateChanged(); /** Called when a modifier key is pressed or released. @@ -1787,7 +1784,7 @@ public: @returns the modal component, or null if no components are modal @see runModalLoop, isCurrentlyModal */ - static Component* getCurrentlyModalComponent() throw(); + static Component* JUCE_CALLTYPE getCurrentlyModalComponent() throw(); /** Checks whether there's a modal component somewhere that's stopping this one from receiving messages. @@ -2078,8 +2075,6 @@ private: void internalFocusLoss (const FocusChangeType cause); void internalChildFocusChange (FocusChangeType cause); void internalModalInputAttempt(); - bool internalKeyPress (const int key, const juce_wchar textCharacter); - bool internalKeyStateChanged(); void internalModifierKeysChanged(); void internalChildrenChanged(); void internalHierarchyChanged(); diff --git a/src/juce_appframework/gui/components/keyboard/juce_KeyListener.cpp b/src/juce_appframework/gui/components/keyboard/juce_KeyListener.cpp index a77eed8aac..bbb4f05973 100644 --- a/src/juce_appframework/gui/components/keyboard/juce_KeyListener.cpp +++ b/src/juce_appframework/gui/components/keyboard/juce_KeyListener.cpp @@ -37,8 +37,9 @@ BEGIN_JUCE_NAMESPACE //============================================================================== -void KeyListener::keyStateChanged (Component*) +bool KeyListener::keyStateChanged (Component*) { + return false; } diff --git a/src/juce_appframework/gui/components/keyboard/juce_KeyListener.h b/src/juce_appframework/gui/components/keyboard/juce_KeyListener.h index a506921fb0..12aac7649e 100644 --- a/src/juce_appframework/gui/components/keyboard/juce_KeyListener.h +++ b/src/juce_appframework/gui/components/keyboard/juce_KeyListener.h @@ -54,10 +54,15 @@ public: //============================================================================== /** Called to indicate that a key has been pressed. + If your implementation returns true, then the key event is considered to have + been consumed, and will not be passed on to any other components. If it returns + false, then the key will be passed to other components that might want to use it. + @param key the keystroke, including modifier keys @param originatingComponent the component that received the key event + @see keyStateChanged, Component::keyPressed */ - virtual void keyPressed (const KeyPress& key, + virtual bool keyPressed (const KeyPress& key, Component* originatingComponent) = 0; /** Called when any key is pressed or released. @@ -66,10 +71,14 @@ public: the state of one or more keys can use KeyPress::isKeyCurrentlyDown() to check whether their key has changed. + If your implementation returns true, then the key event is considered to have + been consumed, and will not be passed on to any other components. If it returns + false, then the key will be passed to other components that might want to use it. + @param originatingComponent the component that received the key event - @see KeyPress + @see KeyPress, Component::keyStateChanged */ - virtual void keyStateChanged (Component* originatingComponent); + virtual bool keyStateChanged (Component* originatingComponent); }; diff --git a/src/juce_appframework/gui/components/keyboard/juce_KeyMappingEditorComponent.cpp b/src/juce_appframework/gui/components/keyboard/juce_KeyMappingEditorComponent.cpp index 9396610ebe..f862938888 100644 --- a/src/juce_appframework/gui/components/keyboard/juce_KeyMappingEditorComponent.cpp +++ b/src/juce_appframework/gui/components/keyboard/juce_KeyMappingEditorComponent.cpp @@ -471,7 +471,7 @@ public: { } - void keyPressed (const KeyPress& key) + bool keyPressed (const KeyPress& key) { lastPress = key; String message (TRANS("Key: ") + owner->getDescriptionForKeyPress (key)); @@ -487,6 +487,13 @@ public: } setMessage (message); + + return true; + } + + bool keyStateChanged() + { + return true; } }; diff --git a/src/juce_appframework/gui/components/keyboard/juce_KeyPressMappingSet.cpp b/src/juce_appframework/gui/components/keyboard/juce_KeyPressMappingSet.cpp index 0975a3a6fb..fb44bf6e6e 100644 --- a/src/juce_appframework/gui/components/keyboard/juce_KeyPressMappingSet.cpp +++ b/src/juce_appframework/gui/components/keyboard/juce_KeyPressMappingSet.cpp @@ -336,9 +336,11 @@ XmlElement* KeyPressMappingSet::createXml (const bool saveDifferencesFromDefault } //============================================================================== -void KeyPressMappingSet::keyPressed (const KeyPress& key, +bool KeyPressMappingSet::keyPressed (const KeyPress& key, Component* originatingComponent) { + bool used = false; + const CommandID commandID = findCommandForKeyPress (key); const ApplicationCommandInfo* const ci = commandManager->getCommandForID (commandID); @@ -352,16 +354,20 @@ void KeyPressMappingSet::keyPressed (const KeyPress& key, && (info.flags & ApplicationCommandInfo::isDisabled) == 0) { invokeCommand (commandID, key, true, 0, originatingComponent); + used = true; } else { PlatformUtilities::beep(); } } + + return used; } -void KeyPressMappingSet::keyStateChanged (Component* originatingComponent) +bool KeyPressMappingSet::keyStateChanged (Component* originatingComponent) { + bool used = false; const uint32 now = Time::getMillisecondCounter(); for (int i = mappings.size(); --i >= 0;) @@ -411,10 +417,13 @@ void KeyPressMappingSet::keyStateChanged (Component* originatingComponent) } invokeCommand (cm->commandID, key, isDown, millisecs, originatingComponent); + used = true; } } } } + + return used; } void KeyPressMappingSet::globalFocusChanged (Component* focusedComponent) diff --git a/src/juce_appframework/gui/components/keyboard/juce_KeyPressMappingSet.h b/src/juce_appframework/gui/components/keyboard/juce_KeyPressMappingSet.h index 9d51ddee91..ffa8a8e16b 100644 --- a/src/juce_appframework/gui/components/keyboard/juce_KeyPressMappingSet.h +++ b/src/juce_appframework/gui/components/keyboard/juce_KeyPressMappingSet.h @@ -228,9 +228,9 @@ public: //============================================================================== /** @internal */ - void keyPressed (const KeyPress& key, Component* originatingComponent); + bool keyPressed (const KeyPress& key, Component* originatingComponent); /** @internal */ - void keyStateChanged (Component* originatingComponent); + bool keyStateChanged (Component* originatingComponent); /** @internal */ void globalFocusChanged (Component* focusedComponent); diff --git a/src/juce_appframework/gui/components/layout/juce_ScrollBar.cpp b/src/juce_appframework/gui/components/layout/juce_ScrollBar.cpp index fadaf45b4a..4b48029936 100644 --- a/src/juce_appframework/gui/components/layout/juce_ScrollBar.cpp +++ b/src/juce_appframework/gui/components/layout/juce_ScrollBar.cpp @@ -433,23 +433,27 @@ void ScrollBar::timerCallback() } } -void ScrollBar::keyPressed (const KeyPress& key) +bool ScrollBar::keyPressed (const KeyPress& key) { - if (isVisible()) - { - if (key.isKeyCode (KeyPress::upKey) || key.isKeyCode (KeyPress::leftKey)) - moveScrollbarInSteps (-1); - else if (key.isKeyCode (KeyPress::downKey) || key.isKeyCode (KeyPress::rightKey)) - moveScrollbarInSteps (1); - else if (key.isKeyCode (KeyPress::pageUpKey)) - moveScrollbarInPages (-1); - else if (key.isKeyCode (KeyPress::pageDownKey)) - moveScrollbarInPages (1); - else if (key.isKeyCode (KeyPress::homeKey)) - scrollToTop(); - else if (key.isKeyCode (KeyPress::endKey)) - scrollToBottom(); - } + if (! isVisible()) + return false; + + if (key.isKeyCode (KeyPress::upKey) || key.isKeyCode (KeyPress::leftKey)) + moveScrollbarInSteps (-1); + else if (key.isKeyCode (KeyPress::downKey) || key.isKeyCode (KeyPress::rightKey)) + moveScrollbarInSteps (1); + else if (key.isKeyCode (KeyPress::pageUpKey)) + moveScrollbarInPages (-1); + else if (key.isKeyCode (KeyPress::pageDownKey)) + moveScrollbarInPages (1); + else if (key.isKeyCode (KeyPress::homeKey)) + scrollToTop(); + else if (key.isKeyCode (KeyPress::endKey)) + scrollToBottom(); + else + return false; + + return true; } END_JUCE_NAMESPACE diff --git a/src/juce_appframework/gui/components/layout/juce_ScrollBar.h b/src/juce_appframework/gui/components/layout/juce_ScrollBar.h index a15b070456..c184e4a6d5 100644 --- a/src/juce_appframework/gui/components/layout/juce_ScrollBar.h +++ b/src/juce_appframework/gui/components/layout/juce_ScrollBar.h @@ -259,7 +259,7 @@ public: //============================================================================== /** @internal */ - void keyPressed (const KeyPress& key); + bool keyPressed (const KeyPress& key); /** @internal */ void mouseWheelMove (const MouseEvent& e, float wheelIncrementX, float wheelIncrementY); /** @internal */ diff --git a/src/juce_appframework/gui/components/layout/juce_Viewport.cpp b/src/juce_appframework/gui/components/layout/juce_Viewport.cpp index d93cb10268..84de2ac89a 100644 --- a/src/juce_appframework/gui/components/layout/juce_Viewport.cpp +++ b/src/juce_appframework/gui/components/layout/juce_Viewport.cpp @@ -304,7 +304,7 @@ bool Viewport::useMouseWheelMoveIfNeeded (const MouseEvent& e, float wheelIncrem return false; } -void Viewport::keyPressed (const KeyPress& key) +bool Viewport::keyPressed (const KeyPress& key) { const bool isUpDownKey = key.isKeyCode (KeyPress::upKey) || key.isKeyCode (KeyPress::downKey) @@ -313,21 +313,17 @@ void Viewport::keyPressed (const KeyPress& key) || key.isKeyCode (KeyPress::homeKey) || key.isKeyCode (KeyPress::endKey); + if (verticalScrollBar->isVisible() && isUpDownKey) + return verticalScrollBar->keyPressed (key); + const bool isLeftRightKey = key.isKeyCode (KeyPress::leftKey) || key.isKeyCode (KeyPress::rightKey); - if (verticalScrollBar->isVisible() && isUpDownKey) - { - verticalScrollBar->keyPressed (key); - } - else if (horizontalScrollBar->isVisible() && (isLeftRightKey || isUpDownKey)) - { - horizontalScrollBar->keyPressed (key); - } - else - { - Component::keyPressed (key); - } + if (horizontalScrollBar->isVisible() && (isUpDownKey || isLeftRightKey)) + return horizontalScrollBar->keyPressed (key); + + return false; } + END_JUCE_NAMESPACE diff --git a/src/juce_appframework/gui/components/layout/juce_Viewport.h b/src/juce_appframework/gui/components/layout/juce_Viewport.h index bfd50505da..183dde7c71 100644 --- a/src/juce_appframework/gui/components/layout/juce_Viewport.h +++ b/src/juce_appframework/gui/components/layout/juce_Viewport.h @@ -224,7 +224,7 @@ public: /** @internal */ void mouseWheelMove (const MouseEvent& e, float wheelIncrementX, float wheelIncrementY); /** @internal */ - void keyPressed (const KeyPress& key); + bool keyPressed (const KeyPress& key); /** @internal */ void componentMovedOrResized (Component& component, bool wasMoved, bool wasResized); /** @internal */ diff --git a/src/juce_appframework/gui/components/menus/juce_MenuBarComponent.cpp b/src/juce_appframework/gui/components/menus/juce_MenuBarComponent.cpp index 4a16c73a43..1f7d3bf5dd 100644 --- a/src/juce_appframework/gui/components/menus/juce_MenuBarComponent.cpp +++ b/src/juce_appframework/gui/components/menus/juce_MenuBarComponent.cpp @@ -385,19 +385,24 @@ void MenuBarComponent::mouseMove (const MouseEvent& e) } } -void MenuBarComponent::keyPressed (const KeyPress& key) +bool MenuBarComponent::keyPressed (const KeyPress& key) { + bool used = false; const int numMenus = menuNames.size(); const int currentIndex = jlimit (0, menuNames.size() - 1, currentPopupIndex); if (key.isKeyCode (KeyPress::leftKey)) { showMenu ((currentIndex + numMenus - 1) % numMenus); + used = true; } else if (key.isKeyCode (KeyPress::rightKey)) { showMenu ((currentIndex + 1) % numMenus); + used = true; } + + return used; } void MenuBarComponent::inputAttemptWhenModal() diff --git a/src/juce_appframework/gui/components/menus/juce_MenuBarComponent.h b/src/juce_appframework/gui/components/menus/juce_MenuBarComponent.h index f354c7182f..8892c295ac 100644 --- a/src/juce_appframework/gui/components/menus/juce_MenuBarComponent.h +++ b/src/juce_appframework/gui/components/menus/juce_MenuBarComponent.h @@ -96,7 +96,7 @@ public: /** @internal */ void handleCommandMessage (int commandId); /** @internal */ - void keyPressed (const KeyPress& key); + bool keyPressed (const KeyPress& key); /** @internal */ void menuBarItemsChanged (MenuBarModel* menuBarModel); /** @internal */ diff --git a/src/juce_appframework/gui/components/menus/juce_PopupMenu.cpp b/src/juce_appframework/gui/components/menus/juce_PopupMenu.cpp index 0249f4616c..34731ec4b8 100644 --- a/src/juce_appframework/gui/components/menus/juce_PopupMenu.cpp +++ b/src/juce_appframework/gui/components/menus/juce_PopupMenu.cpp @@ -552,7 +552,7 @@ public: lastMouseX = -1; } - void keyPressed (const KeyPress& key) + bool keyPressed (const KeyPress& key) { if (key.isKeyCode (KeyPress::downKey)) { @@ -607,6 +607,12 @@ public: { dismissMenu (0); } + else + { + return false; + } + + return true; } void inputAttemptWhenModal() diff --git a/src/juce_appframework/gui/components/special/juce_MidiKeyboardComponent.cpp b/src/juce_appframework/gui/components/special/juce_MidiKeyboardComponent.cpp index 2ca4a47038..b19ce2888b 100644 --- a/src/juce_appframework/gui/components/special/juce_MidiKeyboardComponent.cpp +++ b/src/juce_appframework/gui/components/special/juce_MidiKeyboardComponent.cpp @@ -834,7 +834,7 @@ void MidiKeyboardComponent::setKeyPressBaseOctave (const int newOctaveNumber) keyMappingOctave = newOctaveNumber; } -void MidiKeyboardComponent::keyStateChanged() +bool MidiKeyboardComponent::keyStateChanged() { bool keyPressUsed = false; @@ -862,8 +862,7 @@ void MidiKeyboardComponent::keyStateChanged() } } - if (! keyPressUsed) - Component::keyStateChanged(); + return keyPressUsed; } void MidiKeyboardComponent::focusLost (FocusChangeType) diff --git a/src/juce_appframework/gui/components/special/juce_MidiKeyboardComponent.h b/src/juce_appframework/gui/components/special/juce_MidiKeyboardComponent.h index 0091bfa4a1..2c96e1be8c 100644 --- a/src/juce_appframework/gui/components/special/juce_MidiKeyboardComponent.h +++ b/src/juce_appframework/gui/components/special/juce_MidiKeyboardComponent.h @@ -292,7 +292,7 @@ public: /** @internal */ void timerCallback(); /** @internal */ - void keyStateChanged(); + bool keyStateChanged(); /** @internal */ void focusLost (FocusChangeType cause); /** @internal */ diff --git a/src/juce_appframework/gui/components/windows/juce_AlertWindow.cpp b/src/juce_appframework/gui/components/windows/juce_AlertWindow.cpp index e6ba8ac0ba..43bdf6448f 100644 --- a/src/juce_appframework/gui/components/windows/juce_AlertWindow.cpp +++ b/src/juce_appframework/gui/components/windows/juce_AlertWindow.cpp @@ -565,7 +565,7 @@ void AlertWindow::mouseDrag (const MouseEvent& e) dragger.dragComponent (this, e); } -void AlertWindow::keyPressed (const KeyPress& key) +bool AlertWindow::keyPressed (const KeyPress& key) { for (int i = buttons.size(); --i >= 0;) { @@ -574,20 +574,22 @@ void AlertWindow::keyPressed (const KeyPress& key) if (b->isRegisteredForShortcut (key)) { b->triggerClick(); - return; + return true; } } - if (buttons.size() == 0) + if (key.isKeyCode (KeyPress::escapeKey) && buttons.size() == 0) { exitModalState (0); + return true; } - else if (key.isKeyCode (KeyPress::returnKey) - && buttons.size() == 1) + else if (key.isKeyCode (KeyPress::returnKey) && buttons.size() == 1) { - AlertWindowTextButton* const mb = (AlertWindowTextButton*) buttons.getFirst(); - mb->triggerClick(); + ((AlertWindowTextButton*) buttons.getFirst())->triggerClick(); + return true; } + + return false; } void AlertWindow::lookAndFeelChanged() diff --git a/src/juce_appframework/gui/components/windows/juce_AlertWindow.h b/src/juce_appframework/gui/components/windows/juce_AlertWindow.h index da9cdc5143..f008014be9 100644 --- a/src/juce_appframework/gui/components/windows/juce_AlertWindow.h +++ b/src/juce_appframework/gui/components/windows/juce_AlertWindow.h @@ -332,7 +332,7 @@ protected: /** @internal */ void mouseDrag (const MouseEvent& e); /** @internal */ - void keyPressed (const KeyPress& key); + bool keyPressed (const KeyPress& key); /** @internal */ void buttonClicked (Button* button); /** @internal */ diff --git a/src/juce_appframework/gui/components/windows/juce_ComponentPeer.cpp b/src/juce_appframework/gui/components/windows/juce_ComponentPeer.cpp index aa2f9d4c5c..6c7d397b28 100644 --- a/src/juce_appframework/gui/components/windows/juce_ComponentPeer.cpp +++ b/src/juce_appframework/gui/components/windows/juce_ComponentPeer.cpp @@ -408,18 +408,106 @@ bool ComponentPeer::handleKeyPress (const int keyCode, { updateCurrentModifiers(); - return (Component::currentlyFocusedComponent->isValidComponent() - ? Component::currentlyFocusedComponent : component) - ->internalKeyPress (keyCode, textCharacter); + Component* target = Component::currentlyFocusedComponent->isValidComponent() + ? Component::currentlyFocusedComponent + : component; + + if (target->isCurrentlyBlockedByAnotherModalComponent()) + { + Component* const currentModalComp = Component::getCurrentlyModalComponent(); + + if (currentModalComp != 0) + target = currentModalComp; + } + + const KeyPress keyInfo (keyCode, + ModifierKeys::getCurrentModifiers().getRawFlags() + & ModifierKeys::allKeyboardModifiers, + textCharacter); + + bool keyWasUsed = false; + + while (target != 0) + { + const ComponentDeletionWatcher deletionChecker (target); + + keyWasUsed = target->keyPressed (keyInfo); + + if (keyWasUsed || deletionChecker.hasBeenDeleted()) + break; + + if (target->keyListeners_ != 0) + { + for (int i = target->keyListeners_->size(); --i >= 0;) + { + keyWasUsed = ((KeyListener*) target->keyListeners_->getUnchecked(i))->keyPressed (keyInfo, target); + + if (keyWasUsed || deletionChecker.hasBeenDeleted()) + return keyWasUsed; + + i = jmin (i, target->keyListeners_->size()); + } + } + + if (keyInfo.isKeyCode (KeyPress::tabKey) && Component::getCurrentlyFocusedComponent() != 0) + { + Component::getCurrentlyFocusedComponent() + ->moveKeyboardFocusToSibling (! keyInfo.getModifiers().isShiftDown()); + + keyWasUsed = true; + break; + } + + target = target->parentComponent_; + } + + return keyWasUsed; } bool ComponentPeer::handleKeyUpOrDown() { updateCurrentModifiers(); - return (Component::currentlyFocusedComponent->isValidComponent() - ? Component::currentlyFocusedComponent : component) - ->internalKeyStateChanged(); + Component* target = Component::currentlyFocusedComponent->isValidComponent() + ? Component::currentlyFocusedComponent + : component; + + if (target->isCurrentlyBlockedByAnotherModalComponent()) + { + Component* const currentModalComp = Component::getCurrentlyModalComponent(); + + if (currentModalComp != 0) + target = currentModalComp; + } + + bool keyWasUsed = false; + + while (target != 0) + { + const ComponentDeletionWatcher deletionChecker (target); + + keyWasUsed = target->keyStateChanged(); + + if (keyWasUsed || deletionChecker.hasBeenDeleted()) + break; + + if (target->keyListeners_ != 0) + { + for (int i = target->keyListeners_->size(); --i >= 0;) + { + keyWasUsed = ((KeyListener*) target->keyListeners_->getUnchecked(i))->keyStateChanged (target); + + if (keyWasUsed || deletionChecker.hasBeenDeleted()) + return keyWasUsed; + + i = jmin (i, target->keyListeners_->size()); + } + } + + target = target->parentComponent_; + } + + return keyWasUsed; } void ComponentPeer::handleModifierKeysChange()