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. |