View Javadoc

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