|
From: <cr...@us...> - 2008-10-12 02:50:28
|
Revision: 4622
http://jnode.svn.sourceforge.net/jnode/?rev=4622&view=rev
Author: crawley
Date: 2008-10-12 02:50:20 +0000 (Sun, 12 Oct 2008)
Log Message:
-----------
Added support for adding and removing bindings. The bindkeys command can
now list and reset bindings and can add and remove both VK and character-based
bindings ... with a gotcha which I will describe on issue #2721.
Modified Paths:
--------------
trunk/core/src/driver/org/jnode/driver/console/VirtualKey.java
trunk/core/src/driver/org/jnode/driver/console/textscreen/ConsoleKeyEventBindings.java
trunk/shell/descriptors/org.jnode.shell.command.xml
trunk/shell/src/shell/org/jnode/shell/command/BindKeysCommand.java
Modified: trunk/core/src/driver/org/jnode/driver/console/VirtualKey.java
===================================================================
--- trunk/core/src/driver/org/jnode/driver/console/VirtualKey.java 2008-10-11 15:10:13 UTC (rev 4621)
+++ trunk/core/src/driver/org/jnode/driver/console/VirtualKey.java 2008-10-12 02:50:20 UTC (rev 4622)
@@ -34,6 +34,10 @@
this.value = value;
}
+ public VirtualKey(int vk, int modifiers) {
+ this.value = vk | (modifiers << 16);
+ }
+
public int getVKCode() {
return value & 0xffff;
}
Modified: trunk/core/src/driver/org/jnode/driver/console/textscreen/ConsoleKeyEventBindings.java
===================================================================
--- trunk/core/src/driver/org/jnode/driver/console/textscreen/ConsoleKeyEventBindings.java 2008-10-11 15:10:13 UTC (rev 4621)
+++ trunk/core/src/driver/org/jnode/driver/console/textscreen/ConsoleKeyEventBindings.java 2008-10-12 02:50:20 UTC (rev 4622)
@@ -55,12 +55,17 @@
public static ConsoleKeyEventBindings createDefault() {
ConsoleKeyEventBindings res = new ConsoleKeyEventBindings();
res.setVKAction(KeyEvent.VK_BACK_SPACE, 0, KeyboardReaderAction.KR_DELETE_BEFORE);
+ res.setVKAction(KeyEvent.VK_H, KeyEvent.CTRL_DOWN_MASK, KeyboardReaderAction.KR_DELETE_BEFORE);
res.setCharAction('\b', KeyboardReaderAction.KR_DELETE_BEFORE);
res.setVKAction(KeyEvent.VK_ENTER, 0, KeyboardReaderAction.KR_ENTER);
+ res.setVKAction(KeyEvent.VK_J, KeyEvent.CTRL_DOWN_MASK, KeyboardReaderAction.KR_ENTER);
res.setCharAction('\n', KeyboardReaderAction.KR_ENTER);
res.setVKAction(KeyEvent.VK_TAB, 0, KeyboardReaderAction.KR_COMPLETE);
+ res.setVKAction(KeyEvent.VK_I, KeyEvent.CTRL_DOWN_MASK, KeyboardReaderAction.KR_COMPLETE);
res.setCharAction('\t', KeyboardReaderAction.KR_COMPLETE);
+ res.setVKAction(KeyEvent.VK_D, KeyEvent.CTRL_DOWN_MASK, KeyboardReaderAction.KR_SOFT_EOF);
res.setCharAction('\004', KeyboardReaderAction.KR_SOFT_EOF);
+ res.setVKAction(KeyEvent.VK_L, KeyEvent.CTRL_DOWN_MASK, KeyboardReaderAction.KR_KILL_LINE);
res.setCharAction('\014', KeyboardReaderAction.KR_KILL_LINE);
res.setVKAction(KeyEvent.VK_UP, 0, KeyboardReaderAction.KR_HISTORY_UP);
res.setVKAction(KeyEvent.VK_DOWN, 0, KeyboardReaderAction.KR_HISTORY_DOWN);
Modified: trunk/shell/descriptors/org.jnode.shell.command.xml
===================================================================
--- trunk/shell/descriptors/org.jnode.shell.command.xml 2008-10-11 15:10:13 UTC (rev 4621)
+++ trunk/shell/descriptors/org.jnode.shell.command.xml 2008-10-12 02:50:20 UTC (rev 4622)
@@ -61,7 +61,23 @@
<sequence description="Remove key bindings">
<option argLabel="remove" shortName="r" longName="remove"/>
<argument argLabel="action"/>
+ <repeat minCount="0">
+ <alternatives>
+ <argument argLabel="vkSpec"/>
+ <argument argLabel="character"/>
+ </alternatives>
+ </repeat>
</sequence>
+ <sequence description="Add key bindings">
+ <option argLabel="add" shortName="a" longName="add"/>
+ <argument argLabel="action"/>
+ <repeat minCount="1">
+ <alternatives>
+ <argument argLabel="vkSpec"/>
+ <argument argLabel="character"/>
+ </alternatives>
+ </repeat>
+ </sequence>
</syntax>
<syntax alias="class" description="Show details of a Java class">
<argument argLabel="className"/>
Modified: trunk/shell/src/shell/org/jnode/shell/command/BindKeysCommand.java
===================================================================
--- trunk/shell/src/shell/org/jnode/shell/command/BindKeysCommand.java 2008-10-11 15:10:13 UTC (rev 4621)
+++ trunk/shell/src/shell/org/jnode/shell/command/BindKeysCommand.java 2008-10-12 02:50:20 UTC (rev 4622)
@@ -20,8 +20,11 @@
*/
package org.jnode.shell.command;
+import java.awt.Toolkit;
import java.awt.event.KeyEvent;
import java.io.PrintWriter;
+import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
@@ -35,10 +38,11 @@
import org.jnode.driver.console.textscreen.KeyboardReaderAction;
import org.jnode.shell.AbstractCommand;
import org.jnode.shell.ShellUtils;
+import org.jnode.shell.CommandLine.Token;
import org.jnode.shell.syntax.Argument;
+import org.jnode.shell.syntax.CommandSyntaxException;
import org.jnode.shell.syntax.EnumArgument;
import org.jnode.shell.syntax.FlagArgument;
-import org.jnode.shell.syntax.StringArgument;
/**
* This command allows the user to examine and change JNode's key bindings.
@@ -47,11 +51,55 @@
*/
public class BindKeysCommand extends AbstractCommand {
+ private static final Map<String, Integer> VK_NAME_MAP =
+ new HashMap<String, Integer>();
+ private static final Map<Integer, String> VK_MAP =
+ new HashMap<Integer, String>();
+ private static final Map<String, Integer> MODIFIER_NAME_MAP =
+ new HashMap<String, Integer>();
+ private static final Map<Integer, String> MODIFIER_MAP =
+ new HashMap<Integer, String>();
+
+ static {
+ // This is the best way I can think of to enumerate all of the VK_ codes
+ // defined by the KeyEvent class.
+ for (Field field : KeyEvent.class.getFields()) {
+ if (Modifier.isStatic(field.getModifiers()) &&
+ field.getName().startsWith("VK_")) {
+ try {
+ Integer vk = (Integer) field.get(null);
+ String name = constCase(KeyEvent.getKeyText(vk.intValue()));
+ VK_NAME_MAP.put(name, vk);
+ VK_MAP.put(vk, name);
+ } catch (IllegalAccessException ex) {
+ // This cannot happen. But if it does we'll just ignore
+ // the virtual key constant that caused it.
+ }
+ }
+ }
+ // Now do the same for the modifiers. Note that we map the names to the 'new'
+ // modifier mask values; see KeyEvent javadoc ...
+ initModifier("AWT.shift", "Shift", KeyEvent.SHIFT_DOWN_MASK);
+ initModifier("AWT.control", "Ctrl", KeyEvent.CTRL_DOWN_MASK);
+ initModifier("AWT.alt", "Alt", KeyEvent.ALT_DOWN_MASK);
+ initModifier("AWT.meta", "Meta", KeyEvent.META_DOWN_MASK);
+ initModifier("AWT.button1", "Button 1", KeyEvent.BUTTON1_DOWN_MASK);
+ initModifier("AWT.button2", "Button 2", KeyEvent.BUTTON2_DOWN_MASK);
+ initModifier("AWT.button3", "Button 3", KeyEvent.BUTTON3_DOWN_MASK);
+ initModifier("AWT.altGraph", "Alt Graph", KeyEvent.ALT_GRAPH_DOWN_MASK);
+ }
+
+ private static void initModifier(String propName, String dflt, int modifier) {
+ String name = constCase(Toolkit.getProperty(propName, dflt));
+ MODIFIER_NAME_MAP.put(name, modifier);
+ MODIFIER_MAP.put(modifier, name);
+ }
+
private static final String[] ASCII_NAMES = new String[] {
"NUL", "SOH", "STC", "ETX", "EOT", "ENQ", "ACK", "BEL",
"BS", "HT", "NL", "VT", "FF", "CR", "SO", "SI",
"DLE", "DC1", "DC2", "DC3", "DC4", "NAK", "SYN", "ETB",
- "CAN", "EM", "SUB", "ESC", "FS", "GS", "RS", "US"
+ "CAN", "EM", "SUB", "ESC", "FS", "GS", "RS", "US", "SP"
};
private static class ActionArgument extends EnumArgument<KeyboardReaderAction> {
@@ -64,9 +112,75 @@
return "keyboard reader action";
}
}
+
+ private static class VirtualKeyArgument extends Argument<VirtualKey> {
+ protected VirtualKeyArgument(String label, int flags, String description) {
+ super(label, flags, new VirtualKey[0], description);
+ }
+
+ @Override
+ protected String argumentKind() {
+ return "VK spec";
+ }
+
+ @Override
+ protected VirtualKey doAccept(Token value) throws CommandSyntaxException {
+ String str = value.token;
+ String[] parts = str.split("\\+");
+ int modifiers = 0;
+ for (int i = 0; i < parts.length - 1; i++) {
+ Integer m = MODIFIER_NAME_MAP.get(constCase(parts[i]));
+ if (m == null) {
+ throw new CommandSyntaxException(parts[i] + "' is an unknown modifier");
+ }
+ modifiers |= m;
+ }
+ Integer vk = VK_NAME_MAP.get(constCase(parts[parts.length - 1]));
+ if (vk == null) {
+ throw new CommandSyntaxException(parts[parts.length - 1] + "' is an unknown virtual key name");
+ }
+ return new VirtualKey(vk, modifiers);
+ }
+ }
+
+ private static class CharacterArgument extends Argument<Character> {
+
+ protected CharacterArgument(String label, int flags, String description) {
+ super(label, flags, new Character[0], description);
+ }
+
+ @Override
+ protected String argumentKind() {
+ return "character";
+ }
+
+ @Override
+ protected Character doAccept(Token value) throws CommandSyntaxException {
+ String str = value.token;
+ String upper = str.toUpperCase();
+ for (int i = 0; i < ASCII_NAMES.length; i++) {
+ if (ASCII_NAMES[i].equals(upper)) {
+ return (char) i;
+ }
+ }
+ if (upper.equals("DEL")) {
+ return '\177';
+ }
+ if (str.length() == 3 && str.charAt(0) == '\'' && str.charAt(2) == '\'') {
+ return str.charAt(1);
+ }
+ if (str.startsWith("0x") || str.startsWith("0X")) {
+ int ch = Integer.parseInt(str.substring(2), 16);
+ return (char) ch;
+ }
+ throw new CommandSyntaxException("invalid character");
+ }
+ }
+
private final FlagArgument FLAG_RESET =
- new FlagArgument("reset", Argument.OPTIONAL, "reset the bindings to the default values");
+ new FlagArgument("reset", Argument.OPTIONAL,
+ "reset the bindings to the default values");
private final FlagArgument FLAG_ADD =
new FlagArgument("add", Argument.OPTIONAL, "add bindings");
@@ -77,11 +191,13 @@
private final ActionArgument ARG_ACTION =
new ActionArgument("action", Argument.OPTIONAL, "an keyboard reader action");
- private final StringArgument ARG_VK_NAME =
- new StringArgument("vkName", Argument.OPTIONAL + Argument.MULTIPLE, "a virtual key specification");
+ private final VirtualKeyArgument ARG_VK_SPEC =
+ new VirtualKeyArgument("vkSpec", Argument.OPTIONAL + Argument.MULTIPLE,
+ "a virtual key specification");
- private final StringArgument ARG_CHAR_NAME =
- new StringArgument("charName", Argument.OPTIONAL + Argument.MULTIPLE, "a character");
+ private final CharacterArgument ARG_CHARACTER =
+ new CharacterArgument("character", Argument.OPTIONAL + Argument.MULTIPLE,
+ "a character");
private PrintWriter out;
private PrintWriter err;
@@ -90,9 +206,23 @@
public BindKeysCommand() {
super("display or change the keyboard bindings");
registerArguments(FLAG_RESET, FLAG_ADD, FLAG_REMOVE,
- ARG_ACTION, ARG_VK_NAME, ARG_CHAR_NAME);
+ ARG_ACTION, ARG_VK_SPEC, ARG_CHARACTER);
}
+ private static String constCase(String keyText) {
+ StringBuilder sb = new StringBuilder(keyText);
+ int len = keyText.length();
+ for (int i = 0; i < len; i++) {
+ char ch = sb.charAt(i);
+ if (ch == ' ') {
+ sb.setCharAt(i, '_');
+ } else {
+ sb.setCharAt(i, Character.toUpperCase(ch));
+ }
+ }
+ return sb.toString();
+ }
+
@Override
public void execute() throws Exception {
out = getOutput().getPrintWriter();
@@ -124,28 +254,16 @@
// a bug in the command syntax and should be allowed to propagate to the shell.
KeyboardReaderAction action = ARG_ACTION.getValue();
- if (ARG_CHAR_NAME.isSet() || ARG_VK_NAME.isSet()) {
- // If character or virtual key names were supplied, remove only those bindings.
- if (ARG_CHAR_NAME.isSet()) {
- for (String charName : ARG_CHAR_NAME.getValues()) {
- char ch = getCharacter(charName);
- if (ch != KeyEvent.CHAR_UNDEFINED) {
- bindings.unsetCharAction(ch);
- } else {
- err.println("Cannot translate character name '" + charName + "'");
- exit(1);
- }
+ if (ARG_VK_SPEC.isSet() || ARG_CHARACTER.isSet()) {
+ // If virtual key names were supplied, remove only those bindings.
+ if (ARG_VK_SPEC.isSet()) {
+ for (VirtualKey vk : ARG_VK_SPEC.getValues()) {
+ bindings.unsetVKAction(vk);
}
}
- if (ARG_VK_NAME.isSet()) {
- for (String vkName : ARG_VK_NAME.getValues()) {
- VirtualKey vk = getVirtualKey(vkName);
- if (vk != null) {
- bindings.unsetVKAction(vk);
- } else {
- err.println("Cannot translate virtual key name '" + vkName + "'");
- exit(1);
- }
+ if (ARG_CHARACTER.isSet()) {
+ for (char ch : ARG_CHARACTER.getValues()) {
+ bindings.unsetCharAction(ch);
}
}
} else {
@@ -174,18 +292,29 @@
out.println("Updated the current console's key bindings for action '" + action + "'.");
}
- private char getCharacter(String charName) {
- // TODO Auto-generated method stub
- return KeyEvent.CHAR_UNDEFINED;
- }
-
- private VirtualKey getVirtualKey(String vkName) {
- // TODO Auto-generated method stub
- return null;
- }
-
private void addBindings(TextConsole console) {
ConsoleKeyEventBindings bindings = console.getKeyEventBindings();
+ // This throws an unchecked exception if the action is not supplied. It signals
+ // a bug in the command syntax and should be allowed to propagate to the shell.
+ KeyboardReaderAction action = ARG_ACTION.getValue();
+
+ int count = 0;
+ if (ARG_VK_SPEC.isSet()) {
+ for (VirtualKey vk : ARG_VK_SPEC.getValues()) {
+ bindings.setVKAction(vk, action);
+ count++;
+ }
+ }
+ if (ARG_CHARACTER.isSet()) {
+ for (char ch : ARG_CHARACTER.getValues()) {
+ bindings.setCharAction(ch, action);
+ count++;
+ }
+ }
+ if (count > 0) {
+ console.setKeyEventBindings(bindings);
+ out.println("Updated the current console's key bindings for action '" + action + "'.");
+ }
}
private void resetBindings(TextConsole console) {
@@ -235,7 +364,6 @@
}
}
out.println(sb);
-
}
}
@@ -286,34 +414,54 @@
private String describe(KeyboardReaderAction action) {
return action.toString();
}
-
- private KeyboardReaderAction getAction(String name) {
- return KeyboardReaderAction.valueOf(name);
- }
private String describe(char ch) {
StringBuilder sb = new StringBuilder();
if (ch < 0x1f) {
- sb.append("CTRL-" + (char)(ch + 0x40));
- sb.append(" (").append(ASCII_NAMES[ch]).append(")");
+ sb.append(ASCII_NAMES[ch]);
} else if (ch == ' ') {
- sb.append("SPACE");
+ sb.append("SP");
} else if (ch == '\177') {
sb.append("DEL");
} else if (ch < '\177') {
- sb.append(ch);
+ sb.append('\'').append(ch).append('\'');
} else {
- sb.append(ch).append("(0x" + Integer.toHexString(ch)).append(')');
+ sb.append('\'').append(ch).append("' (0x" + Integer.toHexString(ch)).append(')');
}
return sb.toString();
}
private String describe(VirtualKey vk) {
- if (vk.getModifiers() != 0) {
- return (KeyEvent.getKeyModifiersText(vk.getModifiers()) + " " +
- KeyEvent.getKeyText(vk.getVKCode()));
- } else {
- return KeyEvent.getKeyText(vk.getVKCode());
+ int modifiers = vk.getModifiers();
+ StringBuilder sb = new StringBuilder();
+ // We don't use the KeyEvent.getKeyModifierText method because it
+ // expects the 'old' mask values and conflates some of the masks.
+ if ((modifiers & KeyEvent.SHIFT_DOWN_MASK) != 0) {
+ sb.append(MODIFIER_MAP.get(KeyEvent.SHIFT_DOWN_MASK)).append('+');
}
+ if ((modifiers & KeyEvent.CTRL_DOWN_MASK) != 0) {
+ sb.append(MODIFIER_MAP.get(KeyEvent.CTRL_DOWN_MASK)).append('+');
+ }
+ if ((modifiers & KeyEvent.ALT_DOWN_MASK) != 0) {
+ sb.append(MODIFIER_MAP.get(KeyEvent.ALT_DOWN_MASK)).append('+');
+ }
+ if ((modifiers & KeyEvent.META_DOWN_MASK) != 0) {
+ sb.append(MODIFIER_MAP.get(KeyEvent.META_DOWN_MASK)).append('+');
+ }
+ if ((modifiers & KeyEvent.BUTTON1_DOWN_MASK) != 0) {
+ sb.append(MODIFIER_MAP.get(KeyEvent.BUTTON1_DOWN_MASK)).append('+');
+ }
+ if ((modifiers & KeyEvent.BUTTON2_DOWN_MASK) != 0) {
+ sb.append(MODIFIER_MAP.get(KeyEvent.BUTTON2_DOWN_MASK)).append('+');
+ }
+ if ((modifiers & KeyEvent.BUTTON3_DOWN_MASK) != 0) {
+ sb.append(MODIFIER_MAP.get(KeyEvent.BUTTON3_DOWN_MASK)).append('+');
+ }
+ if ((modifiers & KeyEvent.ALT_GRAPH_DOWN_MASK) != 0) {
+ sb.append(MODIFIER_MAP.get(KeyEvent.ALT_GRAPH_DOWN_MASK)).append('+');
+ }
+ sb.append("VK_");
+ sb.append(VK_MAP.get(vk.getVKCode()));
+ return sb.toString();
}
}
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|