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 }