mirror of
https://github.com/arduino/Arduino.git
synced 2025-01-19 08:52:15 +01:00
Make ctrl-tab and ctrl-shift-tab work again
In the previous commit, these bindings were moved to EditorTab and registered in a cleaner way, but this move also allows more components to hijack these keystrokes and prevent them from reaching EditorTab. This commit makes the keybindings work again, by preventing other components from handling the keys. In particular: - JSplitPane had a binding to switch between its two panes, which is now removed after creating the JSplitPane. - The default focus traversal manager in Swing uses these keys to traverse focus (in addition to the the normal tab and shift-tab keys). By removing these keys from the set of "focus traversal keys" defined for the window, this should be prevented when the focus is on any component inside the window. - JTextPane didn't respond to the previous modification of the window-default focus traversal keys, since it defines its own set (to only contain ctrl-tab and ctrl-shift-tab, but not tab and shift-tab, for undocumented reasons). To fix this, focus traversal is simply disabled on the JTextPane, since this wasn't really being used anyway. There was some code in SketchTextArea that tried to modify the focus traversal keys for just the text area, which is now removed. This code wasn't really useful, since focus traversal is disabled for the text area already. Also, the code contained a bug where it would not actually set the new set of keys for the backward focus traversal. Closes #195
This commit is contained in:
parent
fc4b2028fa
commit
f06820713e
@ -38,6 +38,7 @@ import org.fife.ui.rtextarea.Gutter;
|
|||||||
import org.fife.ui.rtextarea.RTextScrollPane;
|
import org.fife.ui.rtextarea.RTextScrollPane;
|
||||||
import processing.app.debug.RunnerException;
|
import processing.app.debug.RunnerException;
|
||||||
import processing.app.forms.PasswordAuthorizationDialog;
|
import processing.app.forms.PasswordAuthorizationDialog;
|
||||||
|
import processing.app.helpers.Keys;
|
||||||
import processing.app.helpers.OSUtils;
|
import processing.app.helpers.OSUtils;
|
||||||
import processing.app.helpers.PreferencesMapException;
|
import processing.app.helpers.PreferencesMapException;
|
||||||
import processing.app.legacy.PApplet;
|
import processing.app.legacy.PApplet;
|
||||||
@ -312,6 +313,12 @@ public class Editor extends JFrame implements RunnerListener {
|
|||||||
// to fix ugliness.. normally macosx java 1.3 puts an
|
// to fix ugliness.. normally macosx java 1.3 puts an
|
||||||
// ugly white border around this object, so turn it off.
|
// ugly white border around this object, so turn it off.
|
||||||
splitPane.setBorder(null);
|
splitPane.setBorder(null);
|
||||||
|
// By default, the split pane binds Ctrl-Tab and Ctrl-Shift-Tab for changing
|
||||||
|
// focus. Since we do not use that, but want to use these shortcuts for
|
||||||
|
// switching tabs, remove the bindings from the split pane. This allows the
|
||||||
|
// events to bubble up and be handled by the EditorHeader.
|
||||||
|
Keys.killBinding(splitPane, Keys.ctrl(KeyEvent.VK_TAB));
|
||||||
|
Keys.killBinding(splitPane, Keys.ctrlShift(KeyEvent.VK_TAB));
|
||||||
|
|
||||||
// the default size on windows is too small and kinda ugly
|
// the default size on windows is too small and kinda ugly
|
||||||
int dividerSize = PreferencesData.getInteger("editor.divider.size");
|
int dividerSize = PreferencesData.getInteger("editor.divider.size");
|
||||||
|
@ -63,6 +63,7 @@ public class EditorConsole extends JScrollPane {
|
|||||||
consoleTextPane.setEditable(false);
|
consoleTextPane.setEditable(false);
|
||||||
DefaultCaret caret = (DefaultCaret) consoleTextPane.getCaret();
|
DefaultCaret caret = (DefaultCaret) consoleTextPane.getCaret();
|
||||||
caret.setUpdatePolicy(DefaultCaret.NEVER_UPDATE);
|
caret.setUpdatePolicy(DefaultCaret.NEVER_UPDATE);
|
||||||
|
consoleTextPane.setFocusTraversalKeysEnabled(false);
|
||||||
|
|
||||||
Color backgroundColour = Theme.getColor("console.color");
|
Color backgroundColour = Theme.getColor("console.color");
|
||||||
consoleTextPane.setBackground(backgroundColour);
|
consoleTextPane.setBackground(backgroundColour);
|
||||||
|
@ -118,6 +118,27 @@ public class EditorHeader extends JComponent {
|
|||||||
}
|
}
|
||||||
public Actions actions = new Actions();
|
public Actions actions = new Actions();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called whenever we, or any of our ancestors, is added to a container.
|
||||||
|
*/
|
||||||
|
public void addNotify() {
|
||||||
|
super.addNotify();
|
||||||
|
/*
|
||||||
|
* Once we get added to a window, remove Ctrl-Tab and Ctrl-Shift-Tab from
|
||||||
|
* the keys used for focus traversal (so our bindings for these keys will
|
||||||
|
* work). All components inherit from the window eventually, so this should
|
||||||
|
* work whenever the focus is inside our window. Some components (notably
|
||||||
|
* JTextPane / JEditorPane) keep their own focus traversal keys, though, and
|
||||||
|
* have to be treated individually (either the same as below, or by
|
||||||
|
* disabling focus traversal entirely).
|
||||||
|
*/
|
||||||
|
Window window = SwingUtilities.getWindowAncestor(this);
|
||||||
|
if (window != null) {
|
||||||
|
Keys.killFocusTraversalBinding(window, Keys.ctrl(KeyEvent.VK_TAB));
|
||||||
|
Keys.killFocusTraversalBinding(window, Keys.ctrlShift(KeyEvent.VK_TAB));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public EditorHeader(Editor eddie) {
|
public EditorHeader(Editor eddie) {
|
||||||
this.editor = eddie; // weird name for listener
|
this.editor = eddie; // weird name for listener
|
||||||
|
|
||||||
|
@ -29,11 +29,17 @@
|
|||||||
|
|
||||||
package processing.app.helpers;
|
package processing.app.helpers;
|
||||||
|
|
||||||
|
import java.awt.AWTKeyStroke;
|
||||||
|
import java.awt.Component;
|
||||||
|
import java.awt.KeyboardFocusManager;
|
||||||
import java.awt.Toolkit;
|
import java.awt.Toolkit;
|
||||||
import java.awt.event.InputEvent;
|
import java.awt.event.InputEvent;
|
||||||
import java.beans.PropertyChangeEvent;
|
import java.beans.PropertyChangeEvent;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
import javax.swing.Action;
|
import javax.swing.Action;
|
||||||
|
import javax.swing.InputMap;
|
||||||
import javax.swing.JComponent;
|
import javax.swing.JComponent;
|
||||||
import javax.swing.KeyStroke;
|
import javax.swing.KeyStroke;
|
||||||
|
|
||||||
@ -115,6 +121,65 @@ public class Keys {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Kill an existing binding from the given condition. If the binding is
|
||||||
|
* defined on the given component, it is removed, but if it is defined through
|
||||||
|
* a parent inputmap (typically shared by multiple components, so best not
|
||||||
|
* touched), this adds a dummy binding for this component, that will never
|
||||||
|
* match an action in the component's action map, effectively disabling the
|
||||||
|
* binding.
|
||||||
|
*
|
||||||
|
* This method is not intended to unbind a binding created by bind(), since
|
||||||
|
* such a binding would get re-enabled when the action is re-enabled.
|
||||||
|
*/
|
||||||
|
public static void killBinding(final JComponent component,
|
||||||
|
final KeyStroke keystroke, int condition) {
|
||||||
|
InputMap map = component.getInputMap(condition);
|
||||||
|
// First, try removing it
|
||||||
|
map.remove(keystroke);
|
||||||
|
// If the binding is defined in a parent map, defining it will not work, so
|
||||||
|
// instead add an override that will never appear in the action map.
|
||||||
|
if (map.get(keystroke) != null)
|
||||||
|
map.put(keystroke, new Object());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Kill an existing binding like above, but from all three conditions
|
||||||
|
* (WHEN_FOCUSED, WHEN_ANCESTOR_OF_FOCUSED_COMPONENT, WHEN_IN_FOCUSED_WINDOW).
|
||||||
|
*/
|
||||||
|
public static void killBinding(final JComponent component,
|
||||||
|
final KeyStroke key) {
|
||||||
|
killBinding(component, key, JComponent.WHEN_FOCUSED);
|
||||||
|
killBinding(component, key, JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
|
||||||
|
killBinding(component, key, JComponent.WHEN_IN_FOCUSED_WINDOW);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove a keystroke from the keys used to shift focus in or below the given
|
||||||
|
* component. This modifies all sets of focus traversal keys on the given
|
||||||
|
* component to remove the given keystroke. These sets are inherited down the
|
||||||
|
* component hierarchy (until a component that has a custom set itself).
|
||||||
|
*/
|
||||||
|
public static void killFocusTraversalBinding(final Component component,
|
||||||
|
final KeyStroke keystroke) {
|
||||||
|
int[] sets = { KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS,
|
||||||
|
KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS,
|
||||||
|
KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS,
|
||||||
|
KeyboardFocusManager.DOWN_CYCLE_TRAVERSAL_KEYS };
|
||||||
|
for (int set : sets) {
|
||||||
|
Set<AWTKeyStroke> keys = component.getFocusTraversalKeys(set);
|
||||||
|
// keys is immutable, so create a new set to allow changes
|
||||||
|
keys = new HashSet<>(keys);
|
||||||
|
if (set == 0)
|
||||||
|
keys.add(ctrlAlt('Z'));
|
||||||
|
|
||||||
|
// If the given keystroke was present in the set, replace it with the
|
||||||
|
// updated set with the keystroke removed.
|
||||||
|
if (keys.remove(keystroke))
|
||||||
|
component.setFocusTraversalKeys(set, keys);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private static void enableBind(final JComponent component,
|
private static void enableBind(final JComponent component,
|
||||||
final Action action, final KeyStroke keystroke,
|
final Action action, final KeyStroke keystroke,
|
||||||
int condition) {
|
int condition) {
|
||||||
|
@ -41,7 +41,6 @@ import processing.app.BaseNoGui;
|
|||||||
import processing.app.EditorListener;
|
import processing.app.EditorListener;
|
||||||
import processing.app.PreferencesData;
|
import processing.app.PreferencesData;
|
||||||
|
|
||||||
import javax.swing.*;
|
|
||||||
import javax.swing.event.EventListenerList;
|
import javax.swing.event.EventListenerList;
|
||||||
import javax.swing.event.HyperlinkEvent;
|
import javax.swing.event.HyperlinkEvent;
|
||||||
import javax.swing.event.HyperlinkListener;
|
import javax.swing.event.HyperlinkListener;
|
||||||
@ -57,9 +56,7 @@ import java.io.FileInputStream;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.net.MalformedURLException;
|
import java.net.MalformedURLException;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -91,8 +88,6 @@ public class SketchTextArea extends RSyntaxTextArea {
|
|||||||
|
|
||||||
setLinkGenerator(new DocLinkGenerator(pdeKeywords));
|
setLinkGenerator(new DocLinkGenerator(pdeKeywords));
|
||||||
|
|
||||||
fixControlTab();
|
|
||||||
|
|
||||||
setSyntaxEditingStyle(SYNTAX_STYLE_CPLUSPLUS);
|
setSyntaxEditingStyle(SYNTAX_STYLE_CPLUSPLUS);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -153,28 +148,6 @@ public class SketchTextArea extends RSyntaxTextArea {
|
|||||||
getSyntaxScheme().setStyle(tokenType, style);
|
getSyntaxScheme().setStyle(tokenType, style);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Removing the default focus traversal keys
|
|
||||||
// This is because the DefaultKeyboardFocusManager handles the keypress and consumes the event
|
|
||||||
private void fixControlTab() {
|
|
||||||
removeCTRLTabFromFocusTraversal();
|
|
||||||
|
|
||||||
removeCTRLSHIFTTabFromFocusTraversal();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void removeCTRLSHIFTTabFromFocusTraversal() {
|
|
||||||
KeyStroke ctrlShiftTab = KeyStroke.getKeyStroke("ctrl shift TAB");
|
|
||||||
Set<AWTKeyStroke> backwardKeys = new HashSet<>(this.getFocusTraversalKeys(KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS));
|
|
||||||
backwardKeys.remove(ctrlShiftTab);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void removeCTRLTabFromFocusTraversal() {
|
|
||||||
KeyStroke ctrlTab = KeyStroke.getKeyStroke("ctrl TAB");
|
|
||||||
Set<AWTKeyStroke> forwardKeys = new HashSet<>(this.getFocusTraversalKeys(KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS));
|
|
||||||
forwardKeys.remove(ctrlTab);
|
|
||||||
this.setFocusTraversalKeys(KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS, forwardKeys);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public boolean isSelectionActive() {
|
public boolean isSelectionActive() {
|
||||||
return this.getSelectedText() != null;
|
return this.getSelectedText() != null;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user