Index: Eclipse UI/org/eclipse/ui/internal/Workbench.java =================================================================== RCS file: /home/eclipse/org.eclipse.ui.workbench/Eclipse UI/org/eclipse/ui/internal/Workbench.java,v retrieving revision 1.102 diff -u -r1.102 Workbench.java --- Eclipse UI/org/eclipse/ui/internal/Workbench.java 23 Sep 2003 03:07:16 -0000 1.102 +++ Eclipse UI/org/eclipse/ui/internal/Workbench.java 23 Sep 2003 15:52:54 -0000 @@ -208,12 +208,13 @@ if (shell.getParent() != null) return; } + + final KeyStroke[] keyStrokes = new KeyStroke[3]; + keyStrokes[0] = KeySupport.convertAcceleratorToKeyStroke(KeySupport.convertEventToAccelerator(event)); + keyStrokes[1] = KeySupport.convertAcceleratorToKeyStroke(KeySupport.convertEventToShiftedAccelerator(event)); + keyStrokes[2] = KeySupport.convertAcceleratorToKeyStroke(KeySupport.convertEventToShiftedUnmodifierAccelerator(event)); - KeyStroke keyStroke = - KeySupport.convertAcceleratorToKeyStroke( - KeySupport.convertEventToAccelerator(event)); - - if (press(keyStroke, event)) { + if (press(keyStrokes, event)) { switch (event.type) { case SWT.KeyDown : event.doit = false; @@ -413,69 +414,87 @@ return true; } - // TODO move this method to CommandManager once getMode() is added to ICommandManager (and triggers and change event) - // TODO remove event parameter once key-modified actions are removed - public final boolean press(KeyStroke keyStroke, Event event) { - final KeySequence modeBeforeKeyStroke = commandManager.getMode(); - final List keyStrokes = - new ArrayList(modeBeforeKeyStroke.getKeyStrokes()); - keyStrokes.add(keyStroke); - final KeySequence modeAfterKeyStroke = - KeySequence.getInstance(keyStrokes); - final Map matchesByKeySequenceForModeBeforeKeyStroke = - commandManager.getMatchesByKeySequenceForMode(); - commandManager.setMode(modeAfterKeyStroke); - final Map matchesByKeySequenceForModeAfterKeyStroke = - commandManager.getMatchesByKeySequenceForMode(); - boolean consumeKeyStroke = false; - - if (!matchesByKeySequenceForModeAfterKeyStroke.isEmpty()) { - // this key stroke is part of one or more possible completions: consume the keystroke - updateModeLines(modeAfterKeyStroke); - consumeKeyStroke = true; - } else { - // there are no possible longer multi-stroke sequences, allow a completion now if possible - final Match match = - (Match) matchesByKeySequenceForModeBeforeKeyStroke.get( - modeAfterKeyStroke); - - if (match != null) { - // a completion was found. - final String commandId = match.getCommandId(); - final Map actionsById = commandManager.getActionsById(); - org.eclipse.ui.commands.IAction action = - (org.eclipse.ui.commands.IAction) actionsById.get( - commandId); - - if (action != null) { - // an action was found corresponding to the completion - - if (action.isEnabled()) { - updateModeLines(modeAfterKeyStroke); - try { - action.execute(event); - } catch (final Exception e) { - // TODO + /** + * Processes a key press with respect to the key binding architecture. This + * updates the mode of the command manager, and runs the current handler for + * the command that matches the key sequence, if any. + * + * @param potentialKeyStrokes The key strokes that could potentially match, + * in the order of priority; must not be null. + * @param event The event to pass to the action; may be null. + * + * @return true if a command is executed; false + * otherwise. + */ + public final boolean press(final KeyStroke[] potentialKeyStrokes, final Event event) { + // TODO move this method to CommandManager once getMode() is added to ICommandManager (and triggers and change event) + // TODO remove event parameter once key-modified actions are removed + + // Check every potential key stroke until one matches. + for (int i = 0; i < potentialKeyStrokes.length; i++) { + final KeySequence modeBeforeKeyStroke = commandManager.getMode(); + final List keyStrokes = new ArrayList(modeBeforeKeyStroke.getKeyStrokes()); + keyStrokes.add(potentialKeyStrokes[i]); + final KeySequence modeAfterKeyStroke = KeySequence.getInstance(keyStrokes); + final Map matchesByKeySequenceForModeBeforeKeyStroke = commandManager.getMatchesByKeySequenceForMode(); + commandManager.setMode(modeAfterKeyStroke); + final Map matchesByKeySequenceForModeAfterKeyStroke = commandManager.getMatchesByKeySequenceForMode(); + boolean consumeKeyStroke = false; + + if (!matchesByKeySequenceForModeAfterKeyStroke.isEmpty()) { + // this key stroke is part of one or more possible completions: consume the keystroke + updateModeLines(modeAfterKeyStroke); + consumeKeyStroke = true; + } else { + // there are no possible longer multi-stroke sequences, allow a completion now if possible + final Match match = (Match) matchesByKeySequenceForModeBeforeKeyStroke.get(modeAfterKeyStroke); + + if (match != null) { + // a completion was found. + final String commandId = match.getCommandId(); + final Map actionsById = commandManager.getActionsById(); + org.eclipse.ui.commands.IAction action = (org.eclipse.ui.commands.IAction) actionsById.get(commandId); + + if (action != null) { + // an action was found corresponding to the completion + + if (action.isEnabled()) { + updateModeLines(modeAfterKeyStroke); + try { + action.execute(event); + } catch (final Exception e) { + // TODO + } } + + // consume the keystroke + consumeKeyStroke = true; } - - // consume the keystroke - consumeKeyStroke = true; } + + // possibly no completion was found, or no action was found corresponding to the completion, but if we were already in a mode consume the keystroke anyway. + if (modeBeforeKeyStroke.getKeyStrokes().size() >= 1) + consumeKeyStroke = true; + + // clear mode + commandManager.setMode(KeySequence.getInstance()); + updateModeLines(KeySequence.getInstance()); + } + + // TODO is this necessary? + updateActiveContextIds(); + + if (consumeKeyStroke) { + // We found a match, so stop now. + return consumeKeyStroke; + } else { + // Restore the mode, so we can try again. + commandManager.setMode(modeBeforeKeyStroke); } - - // possibly no completion was found, or no action was found corresponding to the completion, but if we were already in a mode consume the keystroke anyway. - if (modeBeforeKeyStroke.getKeyStrokes().size() >= 1) - consumeKeyStroke = true; - - // clear mode - commandManager.setMode(KeySequence.getInstance()); - updateModeLines(KeySequence.getInstance()); } - - // TODO is this necessary? - updateActiveContextIds(); - return consumeKeyStroke; + + // No key strokes match. + return false; } /** Index: Eclipse UI/org/eclipse/ui/internal/keys/KeySupport.java =================================================================== RCS file: /home/eclipse/org.eclipse.ui.workbench/Eclipse UI/org/eclipse/ui/internal/keys/KeySupport.java,v retrieving revision 1.8 diff -u -r1.8 KeySupport.java --- Eclipse UI/org/eclipse/ui/internal/keys/KeySupport.java 25 Aug 2003 22:49:27 -0000 1.8 +++ Eclipse UI/org/eclipse/ui/internal/keys/KeySupport.java 23 Sep 2003 15:52:54 -0000 @@ -27,24 +27,50 @@ import org.eclipse.ui.keys.SpecialKey; public final class KeySupport { - - public static int convertEventToAccelerator(Event event) { - int key = event.character; - - if (key == 0) - key = event.keyCode; - else { - if (0 <= key && key <= 0x1F) { - if ((event.stateMask & SWT.CTRL) != 0 && event.keyCode != event.character) - key += 0x40; - } else { - if ('a' <= key && key <= 'z') - key -= 'a' - 'A'; - } - } - - int modifiers = event.stateMask & SWT.MODIFIER_MASK; - return modifiers + key; + + /** + * Converts the given event into an SWT accelerator value -- considering the + * unmodified character with all modifier keys. This is the first + * accelerator value that should be checked. However, all alphabetic + * characters are considered as their uppercase equivalents. + * + * @param event The event to be converted; must not be null. + * @return The combination of the state mask and the unmodified character. + */ + public static final int convertEventToAccelerator(final Event event) { + final int modifiers = event.stateMask & SWT.MODIFIER_MASK; + final int unmodifiedCharacter = Character.toUpperCase((char) event.keyCode); + + return modifiers + unmodifiedCharacter; + } + + /** + * Converts the given event into an SWT accelerator value -- considering the + * modified character without the shift modifier. This is the second + * accelerator value that should be checked. + * + * @param event The event to be converted; must not be null. + * @return The combination of the state mask without shift, and the modified + * character. + */ + public static final int convertEventToShiftedAccelerator(final Event event) { + final int modifiers = event.stateMask & (SWT.MODIFIER_MASK ^ SWT.SHIFT); + final int modifiedCharacter = topKey(event); + return modifiers + modifiedCharacter; + } + + /** + * Converts the given event into an SWT accelerator value -- considering the + * modified character without the shift modifier. This is the third + * accelerator value that should be checked. + * + * @param event The event to be converted; must not be null. + * @return The combination of the state mask and the unmodified character. + */ + public static final int convertEventToShiftedUnmodifierAccelerator(final Event event) { + final int modifiers = event.stateMask & SWT.MODIFIER_MASK; + final int modifiedCharacter = topKey(event); + return modifiers + modifiedCharacter; } public static KeyStroke convertAcceleratorToKeyStroke(int accelerator) { @@ -273,6 +299,30 @@ stringBuffer.append(KeyStroke.getInstance(naturalKey).format()); return stringBuffer.toString(); + } + + /** + * Makes sure that a fully-modified character is converted to the normal + * form. This means that "Ctrl+" key strokes must reverse the modification + * caused by control-escaping. Also, all lower case letters are converted + * to uppercase. + * + * @param event The event from which the fully-modified character should be + * pulled. + * + * @return The modified character, uppercase and without control-escaping. + */ + private static final int topKey(final Event event) { + final boolean ctrlDown = (event.stateMask & SWT.CTRL) != 0; + + final char modifiedCharacter; + if ((ctrlDown) && (event.character != event.keyCode)) { + modifiedCharacter = (char) (event.character + 0x40); + } else { + modifiedCharacter = event.character; + } + + return Character.toUpperCase(modifiedCharacter); } private KeySupport() {