1 /*
   2  * Copyright (c) 2002-2016, the original author or authors.
   3  *
   4  * This software is distributable under the BSD license. See the terms of the
   5  * BSD license in the documentation provided with this software.
   6  *
   7  * http://www.opensource.org/licenses/bsd-license.php
   8  */
   9 package jdk.internal.jline.console;
  10 
  11 import java.util.HashMap;
  12 import java.util.Map;
  13 
  14 /**
  15  * The KeyMap class contains all bindings from keys to operations.
  16  *
  17  * @author <a href="mailto:gnodet@gmail.com">Guillaume Nodet</a>
  18  * @since 2.6
  19  */
  20 public class KeyMap {
  21 
  22     public static final String VI_MOVE        = "vi-move";
  23     public static final String VI_INSERT      = "vi-insert";
  24     public static final String EMACS          = "emacs";
  25     public static final String EMACS_STANDARD = "emacs-standard";
  26     public static final String EMACS_CTLX     = "emacs-ctlx";
  27     public static final String EMACS_META     = "emacs-meta";
  28 
  29     private static final int KEYMAP_LENGTH = 256;
  30 
  31     private static final Object NULL_FUNCTION = new Object();
  32 
  33     private Object[] mapping = new Object[KEYMAP_LENGTH];
  34     private Object anotherKey = null;
  35     private String name;
  36 
  37     public KeyMap(String name) {
  38         this(name, new Object[KEYMAP_LENGTH]);
  39     }
  40 
  41     @Deprecated
  42     public KeyMap(String name, boolean unused) {
  43         this(name);
  44     }
  45 
  46     protected KeyMap(String name, Object[] mapping) {
  47         this.mapping = mapping;
  48         this.name = name;
  49     }
  50 
  51     public String getName() {
  52         return name;
  53     }
  54 
  55     public Object getAnotherKey() {
  56         return anotherKey;
  57     }
  58 
  59     public void from(KeyMap other) {
  60         this.mapping = other.mapping;
  61         this.anotherKey = other.anotherKey;
  62     }
  63 
  64     public Object getBound( CharSequence keySeq ) {
  65         if (keySeq != null && keySeq.length() > 0) {
  66             KeyMap map = this;
  67             for (int i = 0; i < keySeq.length(); i++) {
  68                 char c = keySeq.charAt(i);
  69                 if (c > 255) {
  70                     return Operation.SELF_INSERT;
  71                 }
  72                 if (map.mapping[c] instanceof KeyMap) {
  73                     if (i == keySeq.length() - 1) {
  74                         return map.mapping[c];
  75                     } else {
  76                         map = (KeyMap) map.mapping[c];
  77                     }
  78                 } else {
  79                     return map.mapping[c];
  80                 }
  81             }
  82         }
  83         return null;
  84     }
  85 
  86     public void bindIfNotBound( CharSequence keySeq, Object function ) {
  87 
  88         bind (this, keySeq, function, true);
  89     }
  90 
  91     public void bind( CharSequence keySeq, Object function ) {
  92 
  93         bind (this, keySeq, function, false);
  94     }
  95 
  96     private static void bind( KeyMap map, CharSequence keySeq, Object function ) {
  97 
  98         bind (map, keySeq, function, false);
  99     }
 100 
 101     private static void bind( KeyMap map, CharSequence keySeq, Object function,
 102             boolean onlyIfNotBound ) {
 103 
 104         if (keySeq != null && keySeq.length() > 0) {
 105             for (int i = 0; i < keySeq.length(); i++) {
 106                 char c = keySeq.charAt(i);
 107                 if (c >= map.mapping.length) {
 108                     return;
 109                 }
 110                 if (i < keySeq.length() - 1) {
 111                     if (!(map.mapping[c] instanceof KeyMap)) {
 112                         KeyMap m = new KeyMap("anonymous");
 113                         if (map.mapping[c] != Operation.DO_LOWERCASE_VERSION) {
 114                             m.anotherKey = map.mapping[c];
 115                         }
 116                         map.mapping[c] = m;
 117                     }
 118                     map = (KeyMap) map.mapping[c];
 119                 } else {
 120                     if (function == null) {
 121                         function = NULL_FUNCTION;
 122                     }
 123                     if (map.mapping[c] instanceof KeyMap) {
 124                         map.anotherKey = function;
 125                     } else {
 126                         Object op = map.mapping[c];
 127                         if (onlyIfNotBound == false
 128                             || op == null
 129                             || op == Operation.DO_LOWERCASE_VERSION
 130                             || op == Operation.VI_MOVEMENT_MODE ) {
 131 
 132                         }
 133 
 134                         map.mapping[c] = function;
 135                     }
 136                 }
 137             }
 138         }
 139     }
 140 
 141     public void setBlinkMatchingParen(boolean on) {
 142         if (on) {
 143             bind( "}", Operation.INSERT_CLOSE_CURLY );
 144             bind( ")", Operation.INSERT_CLOSE_PAREN );
 145             bind( "]", Operation.INSERT_CLOSE_SQUARE );
 146         }
 147     }
 148 
 149     private static void bindArrowKeys(KeyMap map) {
 150 
 151         // MS-DOS
 152         bind( map, "\033[0A", Operation.PREVIOUS_HISTORY );
 153         bind( map, "\033[0B", Operation.BACKWARD_CHAR );
 154         bind( map, "\033[0C", Operation.FORWARD_CHAR );
 155         bind( map, "\033[0D", Operation.NEXT_HISTORY );
 156 
 157         // Windows
 158         bind( map, "\340\000", Operation.KILL_WHOLE_LINE );
 159         bind( map, "\340\107", Operation.BEGINNING_OF_LINE );
 160         bind( map, "\340\110", Operation.PREVIOUS_HISTORY );
 161         bind( map, "\340\111", Operation.BEGINNING_OF_HISTORY );
 162         bind( map, "\340\113", Operation.BACKWARD_CHAR );
 163         bind( map, "\340\115", Operation.FORWARD_CHAR );
 164         bind( map, "\340\117", Operation.END_OF_LINE );
 165         bind( map, "\340\120", Operation.NEXT_HISTORY );
 166         bind( map, "\340\121", Operation.END_OF_HISTORY );
 167         bind( map, "\340\122", Operation.OVERWRITE_MODE );
 168         bind( map, "\340\123", Operation.DELETE_CHAR );
 169 
 170         bind( map, "\000\107", Operation.BEGINNING_OF_LINE );
 171         bind( map, "\000\110", Operation.PREVIOUS_HISTORY );
 172         bind( map, "\000\111", Operation.BEGINNING_OF_HISTORY );
 173         bind( map, "\000\110", Operation.PREVIOUS_HISTORY );
 174         bind( map, "\000\113", Operation.BACKWARD_CHAR );
 175         bind( map, "\000\115", Operation.FORWARD_CHAR );
 176         bind( map, "\000\117", Operation.END_OF_LINE );
 177         bind( map, "\000\120", Operation.NEXT_HISTORY );
 178         bind( map, "\000\121", Operation.END_OF_HISTORY );
 179         bind( map, "\000\122", Operation.OVERWRITE_MODE );
 180         bind( map, "\000\123", Operation.DELETE_CHAR );
 181 
 182         bind( map, "\033[A", Operation.PREVIOUS_HISTORY );
 183         bind( map, "\033[B", Operation.NEXT_HISTORY );
 184         bind( map, "\033[C", Operation.FORWARD_CHAR );
 185         bind( map, "\033[D", Operation.BACKWARD_CHAR );
 186         bind( map, "\033[H", Operation.BEGINNING_OF_LINE );
 187         bind( map, "\033[F", Operation.END_OF_LINE );
 188 
 189         bind( map, "\033OA", Operation.PREVIOUS_HISTORY );
 190         bind( map, "\033OB", Operation.NEXT_HISTORY );
 191         bind( map, "\033OC", Operation.FORWARD_CHAR );
 192         bind( map, "\033OD", Operation.BACKWARD_CHAR );
 193         bind( map, "\033OH", Operation.BEGINNING_OF_LINE );
 194         bind( map, "\033OF", Operation.END_OF_LINE );
 195 
 196         bind( map, "\033[1~", Operation.BEGINNING_OF_LINE);
 197         bind( map, "\033[4~", Operation.END_OF_LINE);
 198         bind( map, "\033[3~", Operation.DELETE_CHAR);
 199 
 200         // MINGW32
 201         bind( map, "\0340H", Operation.PREVIOUS_HISTORY );
 202         bind( map, "\0340P", Operation.NEXT_HISTORY );
 203         bind( map, "\0340M", Operation.FORWARD_CHAR );
 204         bind( map, "\0340K", Operation.BACKWARD_CHAR );
 205     }
 206 
 207 //    public boolean isConvertMetaCharsToAscii() {
 208 //        return convertMetaCharsToAscii;
 209 //    }
 210 
 211 //    public void setConvertMetaCharsToAscii(boolean convertMetaCharsToAscii) {
 212 //        this.convertMetaCharsToAscii = convertMetaCharsToAscii;
 213 //    }
 214 
 215     public static boolean isMeta( char c ) {
 216         return c > 0x7f && c <= 0xff;
 217     }
 218 
 219     public static char unMeta( char c ) {
 220         return (char) (c & 0x7F);
 221     }
 222 
 223     public static char meta( char c ) {
 224         return (char) (c | 0x80);
 225     }
 226 
 227     public static Map<String, KeyMap> keyMaps() {
 228         Map<String, KeyMap> keyMaps = new HashMap<String, KeyMap>();
 229 
 230         KeyMap emacs = emacs();
 231         bindArrowKeys(emacs);
 232         keyMaps.put(EMACS, emacs);
 233         keyMaps.put(EMACS_STANDARD, emacs);
 234         keyMaps.put(EMACS_CTLX, (KeyMap) emacs.getBound("\u0018"));
 235         keyMaps.put(EMACS_META, (KeyMap) emacs.getBound("\u001b"));
 236 
 237         KeyMap viMov = viMovement();
 238         bindArrowKeys(viMov);
 239         keyMaps.put(VI_MOVE, viMov);
 240         keyMaps.put("vi-command", viMov);
 241         keyMaps.put("vi", viMov);
 242 
 243         KeyMap viIns = viInsertion();
 244         bindArrowKeys(viIns);
 245         keyMaps.put(VI_INSERT, viIns);
 246 
 247         return keyMaps;
 248     }
 249 
 250     public static KeyMap emacs() {
 251         Object[] map = new Object[KEYMAP_LENGTH];
 252         Object[] ctrl = new Object[] {
 253                         // Control keys.
 254                         Operation.SET_MARK,                 /* Control-@ */
 255                         Operation.BEGINNING_OF_LINE,        /* Control-A */
 256                         Operation.BACKWARD_CHAR,            /* Control-B */
 257                         Operation.INTERRUPT,                /* Control-C */
 258                         Operation.EXIT_OR_DELETE_CHAR,      /* Control-D */
 259                         Operation.END_OF_LINE,              /* Control-E */
 260                         Operation.FORWARD_CHAR,             /* Control-F */
 261                         Operation.ABORT,                    /* Control-G */
 262                         Operation.BACKWARD_DELETE_CHAR,     /* Control-H */
 263                         Operation.COMPLETE,                 /* Control-I */
 264                         Operation.ACCEPT_LINE,              /* Control-J */
 265                         Operation.KILL_LINE,                /* Control-K */
 266                         Operation.CLEAR_SCREEN,             /* Control-L */
 267                         Operation.ACCEPT_LINE,              /* Control-M */
 268                         Operation.NEXT_HISTORY,             /* Control-N */
 269                         null,                               /* Control-O */
 270                         Operation.PREVIOUS_HISTORY,         /* Control-P */
 271                         Operation.QUOTED_INSERT,            /* Control-Q */
 272                         Operation.REVERSE_SEARCH_HISTORY,   /* Control-R */
 273                         Operation.FORWARD_SEARCH_HISTORY,   /* Control-S */
 274                         Operation.TRANSPOSE_CHARS,          /* Control-T */
 275                         Operation.UNIX_LINE_DISCARD,        /* Control-U */
 276                         Operation.QUOTED_INSERT,            /* Control-V */
 277                         Operation.UNIX_WORD_RUBOUT,         /* Control-W */
 278                         emacsCtrlX(),                       /* Control-X */
 279                         Operation.YANK,                     /* Control-Y */
 280                         null,                               /* Control-Z */
 281                         emacsMeta(),                        /* Control-[ */
 282                         null,                               /* Control-\ */
 283                         Operation.CHARACTER_SEARCH,         /* Control-] */
 284                         null,                               /* Control-^ */
 285                         Operation.UNDO,                     /* Control-_ */
 286                 };
 287         System.arraycopy( ctrl, 0, map, 0, ctrl.length );
 288         for (int i = 32; i < 256; i++) {
 289             map[i] = Operation.SELF_INSERT;
 290         }
 291         map[DELETE] = Operation.BACKWARD_DELETE_CHAR;
 292         return new KeyMap(EMACS, map);
 293     }
 294 
 295     public static final char CTRL_D = (char) 4;
 296     public static final char CTRL_G = (char) 7;
 297     public static final char CTRL_H = (char) 8;
 298     public static final char CTRL_I = (char) 9;
 299     public static final char CTRL_J = (char) 10;
 300     public static final char CTRL_M = (char) 13;
 301     public static final char CTRL_R = (char) 18;
 302     public static final char CTRL_S = (char) 19;
 303     public static final char CTRL_U = (char) 21;
 304     public static final char CTRL_X = (char) 24;
 305     public static final char CTRL_Y = (char) 25;
 306     public static final char ESCAPE = (char) 27; /* Ctrl-[ */
 307     public static final char CTRL_OB = (char) 27; /* Ctrl-[ */
 308     public static final char CTRL_CB = (char) 29; /* Ctrl-] */
 309 
 310     public static final int DELETE = (char) 127;
 311 
 312     public static KeyMap emacsCtrlX() {
 313         Object[] map = new Object[KEYMAP_LENGTH];
 314         map[CTRL_G] = Operation.ABORT;
 315         map[CTRL_R] = Operation.RE_READ_INIT_FILE;
 316         map[CTRL_U] = Operation.UNDO;
 317         map[CTRL_X] = Operation.EXCHANGE_POINT_AND_MARK;
 318         map['('] = Operation.START_KBD_MACRO;
 319         map[')'] = Operation.END_KBD_MACRO;
 320         for (int i = 'A'; i <= 'Z'; i++) {
 321             map[i] = Operation.DO_LOWERCASE_VERSION;
 322         }
 323         map['e'] = Operation.CALL_LAST_KBD_MACRO;
 324         map[DELETE] = Operation.KILL_LINE;
 325         return new KeyMap(EMACS_CTLX, map);
 326     }
 327 
 328     public static KeyMap emacsMeta() {
 329         Object[] map = new Object[KEYMAP_LENGTH];
 330         map[CTRL_G] = Operation.ABORT;
 331         map[CTRL_H] = Operation.BACKWARD_KILL_WORD;
 332         map[CTRL_I] = Operation.TAB_INSERT;
 333         map[CTRL_J] = Operation.VI_EDITING_MODE;
 334         map[CTRL_M] = Operation.VI_EDITING_MODE;
 335         map[CTRL_R] = Operation.REVERT_LINE;
 336         map[CTRL_Y] = Operation.YANK_NTH_ARG;
 337         map[CTRL_OB] = Operation.COMPLETE;
 338         map[CTRL_CB] = Operation.CHARACTER_SEARCH_BACKWARD;
 339         map[' '] = Operation.SET_MARK;
 340         map['#'] = Operation.INSERT_COMMENT;
 341         map['&'] = Operation.TILDE_EXPAND;
 342         map['*'] = Operation.INSERT_COMPLETIONS;
 343         map['-'] = Operation.DIGIT_ARGUMENT;
 344         map['.'] = Operation.YANK_LAST_ARG;
 345         map['<'] = Operation.BEGINNING_OF_HISTORY;
 346         map['='] = Operation.POSSIBLE_COMPLETIONS;
 347         map['>'] = Operation.END_OF_HISTORY;
 348         map['?'] = Operation.POSSIBLE_COMPLETIONS;
 349         for (int i = 'A'; i <= 'Z'; i++) {
 350             map[i] = Operation.DO_LOWERCASE_VERSION;
 351         }
 352         map['\\'] = Operation.DELETE_HORIZONTAL_SPACE;
 353         map['_'] = Operation.YANK_LAST_ARG;
 354         map['b'] = Operation.BACKWARD_WORD;
 355         map['c'] = Operation.CAPITALIZE_WORD;
 356         map['d'] = Operation.KILL_WORD;
 357         map['f'] = Operation.FORWARD_WORD;
 358         map['l'] = Operation.DOWNCASE_WORD;
 359         map['p'] = Operation.NON_INCREMENTAL_REVERSE_SEARCH_HISTORY;
 360         map['r'] = Operation.REVERT_LINE;
 361         map['t'] = Operation.TRANSPOSE_WORDS;
 362         map['u'] = Operation.UPCASE_WORD;
 363         map['y'] = Operation.YANK_POP;
 364         map['~'] = Operation.TILDE_EXPAND;
 365         map[DELETE] = Operation.BACKWARD_KILL_WORD;
 366         return new KeyMap(EMACS_META, map);
 367     }
 368 
 369     public static KeyMap viInsertion() {
 370         Object[] map = new Object[KEYMAP_LENGTH];
 371         Object[] ctrl = new Object[] {
 372                         // Control keys.
 373                         null,                               /* Control-@ */
 374                         Operation.SELF_INSERT,              /* Control-A */
 375                         Operation.SELF_INSERT,              /* Control-B */
 376                         Operation.SELF_INSERT,              /* Control-C */
 377                         Operation.VI_EOF_MAYBE,             /* Control-D */
 378                         Operation.SELF_INSERT,              /* Control-E */
 379                         Operation.SELF_INSERT,              /* Control-F */
 380                         Operation.SELF_INSERT,              /* Control-G */
 381                         Operation.BACKWARD_DELETE_CHAR,     /* Control-H */
 382                         Operation.COMPLETE,                 /* Control-I */
 383                         Operation.ACCEPT_LINE,              /* Control-J */
 384                         Operation.SELF_INSERT,              /* Control-K */
 385                         Operation.SELF_INSERT,              /* Control-L */
 386                         Operation.ACCEPT_LINE,              /* Control-M */
 387                         Operation.MENU_COMPLETE,            /* Control-N */
 388                         Operation.SELF_INSERT,              /* Control-O */
 389                         Operation.MENU_COMPLETE_BACKWARD,   /* Control-P */
 390                         Operation.SELF_INSERT,              /* Control-Q */
 391                         Operation.REVERSE_SEARCH_HISTORY,   /* Control-R */
 392                         Operation.FORWARD_SEARCH_HISTORY,   /* Control-S */
 393                         Operation.TRANSPOSE_CHARS,          /* Control-T */
 394                         Operation.UNIX_LINE_DISCARD,        /* Control-U */
 395                         Operation.QUOTED_INSERT,            /* Control-V */
 396                         Operation.UNIX_WORD_RUBOUT,         /* Control-W */
 397                         Operation.SELF_INSERT,              /* Control-X */
 398                         Operation.YANK,                     /* Control-Y */
 399                         Operation.SELF_INSERT,              /* Control-Z */
 400                         Operation.VI_MOVEMENT_MODE,         /* Control-[ */
 401                         Operation.SELF_INSERT,              /* Control-\ */
 402                         Operation.SELF_INSERT,              /* Control-] */
 403                         Operation.SELF_INSERT,              /* Control-^ */
 404                         Operation.UNDO,                     /* Control-_ */
 405                 };
 406         System.arraycopy( ctrl, 0, map, 0, ctrl.length );
 407         for (int i = 32; i < 256; i++) {
 408             map[i] = Operation.SELF_INSERT;
 409         }
 410         map[DELETE] = Operation.BACKWARD_DELETE_CHAR;
 411         return new KeyMap(VI_INSERT, map);
 412     }
 413 
 414     public static KeyMap viMovement() {
 415         Object[] map = new Object[KEYMAP_LENGTH];
 416         Object[] low = new Object[] {
 417                         // Control keys.
 418                         null,                               /* Control-@ */
 419                         null,                               /* Control-A */
 420                         null,                               /* Control-B */
 421                         Operation.INTERRUPT,                /* Control-C */
 422                         /*
 423                          * ^D is supposed to move down half a screen. In bash
 424                          * appears to be ignored.
 425                          */
 426                         Operation.VI_EOF_MAYBE,             /* Control-D */
 427                         Operation.EMACS_EDITING_MODE,       /* Control-E */
 428                         null,                               /* Control-F */
 429                         Operation.ABORT,                    /* Control-G */
 430                         Operation.BACKWARD_CHAR,            /* Control-H */
 431                         null,                               /* Control-I */
 432                         Operation.VI_MOVE_ACCEPT_LINE,      /* Control-J */
 433                         Operation.KILL_LINE,                /* Control-K */
 434                         Operation.CLEAR_SCREEN,             /* Control-L */
 435                         Operation.VI_MOVE_ACCEPT_LINE,      /* Control-M */
 436                         Operation.VI_NEXT_HISTORY,          /* Control-N */
 437                         null,                               /* Control-O */
 438                         Operation.VI_PREVIOUS_HISTORY,      /* Control-P */
 439                         /*
 440                          * My testing with readline is the ^Q is ignored.
 441                          * Maybe this should be null?
 442                          */
 443                         Operation.QUOTED_INSERT,            /* Control-Q */
 444 
 445                         /*
 446                          * TODO - Very broken.  While in forward/reverse
 447                          * history search the VI keyset should go out the
 448                          * window and we need to enter a very simple keymap.
 449                          */
 450                         Operation.REVERSE_SEARCH_HISTORY,   /* Control-R */
 451                         /* TODO */
 452                         Operation.FORWARD_SEARCH_HISTORY,   /* Control-S */
 453                         Operation.TRANSPOSE_CHARS,          /* Control-T */
 454                         Operation.UNIX_LINE_DISCARD,        /* Control-U */
 455                         /* TODO */
 456                         Operation.QUOTED_INSERT,            /* Control-V */
 457                         Operation.UNIX_WORD_RUBOUT,         /* Control-W */
 458                         null,                               /* Control-X */
 459                         /* TODO */
 460                         Operation.YANK,                     /* Control-Y */
 461                         null,                               /* Control-Z */
 462                         emacsMeta(),                        /* Control-[ */
 463                         null,                               /* Control-\ */
 464                         /* TODO */
 465                         Operation.CHARACTER_SEARCH,         /* Control-] */
 466                         null,                               /* Control-^ */
 467                         /* TODO */
 468                         Operation.UNDO,                     /* Control-_ */
 469                         Operation.FORWARD_CHAR,             /* SPACE */
 470                         null,                               /* ! */
 471                         null,                               /* " */
 472                         Operation.VI_INSERT_COMMENT,        /* # */
 473                         Operation.END_OF_LINE,              /* $ */
 474                         Operation.VI_MATCH,                 /* % */
 475                         Operation.VI_TILDE_EXPAND,          /* & */
 476                         null,                               /* ' */
 477                         null,                               /* ( */
 478                         null,                               /* ) */
 479                         /* TODO */
 480                         Operation.VI_COMPLETE,              /* * */
 481                         Operation.VI_NEXT_HISTORY,          /* + */
 482                         Operation.VI_CHAR_SEARCH,           /* , */
 483                         Operation.VI_PREVIOUS_HISTORY,      /* - */
 484                         /* TODO */
 485                         Operation.VI_REDO,                  /* . */
 486                         Operation.VI_SEARCH,                /* / */
 487                         Operation.VI_BEGINNING_OF_LINE_OR_ARG_DIGIT, /* 0 */
 488                         Operation.VI_ARG_DIGIT,             /* 1 */
 489                         Operation.VI_ARG_DIGIT,             /* 2 */
 490                         Operation.VI_ARG_DIGIT,             /* 3 */
 491                         Operation.VI_ARG_DIGIT,             /* 4 */
 492                         Operation.VI_ARG_DIGIT,             /* 5 */
 493                         Operation.VI_ARG_DIGIT,             /* 6 */
 494                         Operation.VI_ARG_DIGIT,             /* 7 */
 495                         Operation.VI_ARG_DIGIT,             /* 8 */
 496                         Operation.VI_ARG_DIGIT,             /* 9 */
 497                         null,                               /* : */
 498                         Operation.VI_CHAR_SEARCH,           /* ; */
 499                         null,                               /* < */
 500                         Operation.VI_COMPLETE,              /* = */
 501                         null,                               /* > */
 502                         Operation.VI_SEARCH,                /* ? */
 503                         null,                               /* @ */
 504                         Operation.VI_APPEND_EOL,            /* A */
 505                         Operation.VI_PREV_WORD,             /* B */
 506                         Operation.VI_CHANGE_TO_EOL,         /* C */
 507                         Operation.VI_DELETE_TO_EOL,         /* D */
 508                         Operation.VI_END_WORD,              /* E */
 509                         Operation.VI_CHAR_SEARCH,           /* F */
 510                         /* I need to read up on what this does */
 511                         Operation.VI_FETCH_HISTORY,         /* G */
 512                         null,                               /* H */
 513                         Operation.VI_INSERT_BEG,            /* I */
 514                         null,                               /* J */
 515                         null,                               /* K */
 516                         null,                               /* L */
 517                         null,                               /* M */
 518                         Operation.VI_SEARCH_AGAIN,          /* N */
 519                         null,                               /* O */
 520                         Operation.VI_PUT,                   /* P */
 521                         null,                               /* Q */
 522                         /* TODO */
 523                         Operation.VI_REPLACE,               /* R */
 524                         Operation.VI_KILL_WHOLE_LINE,       /* S */
 525                         Operation.VI_CHAR_SEARCH,           /* T */
 526                         /* TODO */
 527                         Operation.REVERT_LINE,              /* U */
 528                         null,                               /* V */
 529                         Operation.VI_NEXT_WORD,             /* W */
 530                         Operation.VI_RUBOUT,                /* X */
 531                         Operation.VI_YANK_TO,               /* Y */
 532                         null,                               /* Z */
 533                         null,                               /* [ */
 534                         Operation.VI_COMPLETE,              /* \ */
 535                         null,                               /* ] */
 536                         Operation.VI_FIRST_PRINT,           /* ^ */
 537                         Operation.VI_YANK_ARG,              /* _ */
 538                         Operation.VI_GOTO_MARK,             /* ` */
 539                         Operation.VI_APPEND_MODE,           /* a */
 540                         Operation.VI_PREV_WORD,             /* b */
 541                         Operation.VI_CHANGE_TO,             /* c */
 542                         Operation.VI_DELETE_TO,             /* d */
 543                         Operation.VI_END_WORD,              /* e */
 544                         Operation.VI_CHAR_SEARCH,           /* f */
 545                         null,                               /* g */
 546                         Operation.BACKWARD_CHAR,            /* h */
 547                         Operation.VI_INSERTION_MODE,        /* i */
 548                         Operation.NEXT_HISTORY,             /* j */
 549                         Operation.PREVIOUS_HISTORY,         /* k */
 550                         Operation.FORWARD_CHAR,             /* l */
 551                         Operation.VI_SET_MARK,              /* m */
 552                         Operation.VI_SEARCH_AGAIN,          /* n */
 553                         null,                               /* o */
 554                         Operation.VI_PUT,                   /* p */
 555                         null,                               /* q */
 556                         Operation.VI_CHANGE_CHAR,           /* r */
 557                         Operation.VI_SUBST,                 /* s */
 558                         Operation.VI_CHAR_SEARCH,           /* t */
 559                         Operation.UNDO,                     /* u */
 560                         null,                               /* v */
 561                         Operation.VI_NEXT_WORD,             /* w */
 562                         Operation.VI_DELETE,                /* x */
 563                         Operation.VI_YANK_TO,               /* y */
 564                         null,                               /* z */
 565                         null,                               /* { */
 566                         Operation.VI_COLUMN,                /* | */
 567                         null,                               /* } */
 568                         Operation.VI_CHANGE_CASE,           /* ~ */
 569                         Operation.VI_DELETE                 /* DEL */
 570                 };
 571         System.arraycopy( low, 0, map, 0, low.length );
 572         for (int i = 128; i < 256; i++) {
 573             map[i] = null;
 574         }
 575         return new KeyMap(VI_MOVE, map);
 576     }
 577 }