1 4 package gnu.jemacs.buffer; 5 import gnu.lists.*; 6 import gnu.math.IntNum; 7 import gnu.text.Char; 8 import gnu.mapping.*; 9 import java.awt.event.KeyEvent ; 10 11 public class EKeymap extends gnu.kawa.util.RangeTable 12 implements gnu.mapping.Named 13 { 14 public static final EKeymap[] empty = new EKeymap[0]; 15 EKeymap[] parents = empty; 16 17 public static int PRESSED = 0x100; 18 public static int RELEASED = 0x200; 19 20 Object defaultBinding; 21 22 String name; 23 24 26 public static final int metaKey = '\033'; 27 28 29 public static EKeymap globalKeymap = new EKeymap(); 30 31 32 public static EKeymap metaKeymap = new EKeymap("ESC-map"); 33 34 static 35 { 36 globalKeymap.setAction(metaKey, metaKeymap); 37 } 38 39 public static final int CTRL_MASK = java.awt.event.InputEvent.CTRL_MASK; 40 public static final int SHIFT_MASK = java.awt.event.InputEvent.SHIFT_MASK; 41 public static final int META_MASK = java.awt.event.InputEvent.ALT_MASK; 43 public static final int ALT_MASK = java.awt.event.InputEvent.META_MASK; 44 45 public EKeymap (String name) 46 { 47 this.name = name; 48 } 49 50 public EKeymap () 51 { 52 } 53 54 public String getName() 55 { 56 return name; 57 } 58 59 public Object getSymbol () 60 { 61 return name; 62 } 63 64 public void setName (String name) 65 { 66 this.name = name; 67 } 68 69 public final Object getDefaultBinding () 70 { 71 return defaultBinding; 72 } 73 74 public void setDefaultBinding (Object value) 75 { 76 defaultBinding = value; 77 } 78 79 public static int getModifiers (int code) 80 { 81 return (code >> 16) & 0xFF; 82 } 83 84 public EKeymap[] getParents () 85 { 86 return parents; 87 } 88 89 public void setParents (EKeymap[] parents) 90 { 91 this.parents = parents; 92 } 93 94 public void setParent (EKeymap parent) 95 { 96 if (parent == null) 97 this.parents = empty; 98 else 99 this.parents = new EKeymap[] { parent }; 100 } 101 102 public EKeymap getParent () 103 { 104 int num = parents.length; 105 if (num == 0) 106 return null; 107 if (num == 1) 108 return parents[0]; 109 throw new Error ("multiple parents - set getParents, not getParent"); 110 } 111 112 public void setAction(int key, Object command) 113 { 114 set(key, command); 115 } 116 117 public Object get (int key, int modifiers, boolean acceptDefaults) 118 { 119 return get (key | (modifiers << 16), acceptDefaults); 120 } 121 122 protected Object get (int key, boolean acceptDefaults) 123 { 124 Object value = super.lookup(key, null); 125 if (value != null) 126 return value; 127 if (acceptDefaults && defaultBinding != null) 128 return defaultBinding; 129 int plen = parents.length; 130 for (int i = 0; i <plen; i++) 131 { 132 value = parents[i].get(key, acceptDefaults); 133 if (value != null) 134 return value; 135 } 136 return null; 137 } 138 139 public String toString () 140 { 141 StringBuffer sbuf = new StringBuffer (40); 142 sbuf.append("#<keymap "); 143 if (name != null) 144 { 145 sbuf.append(name); 146 sbuf.append(' '); 147 } 148 152 sbuf.append("0x"); 153 sbuf.append(Integer.toHexString(System.identityHashCode(this))); 154 sbuf.append('>'); 155 return sbuf.toString(); 156 } 157 158 159 public EKeymap definePrefix(int key) 160 { 161 Object command = get(key, false); 162 Object cc = command; 163 Object x; 164 if (command == null) 165 { 166 EKeymap next = new EKeymap(null); 167 set(key, next); 168 return next; 169 } 170 command = Command.resolveSymbol(command); 171 if (command instanceof EKeymap) 172 return (EKeymap) command; 173 else 174 { 175 throw new Error ("prefix command cannot override exiting action: " 176 + cc+ " : "+cc.getClass()+" -> "+command+" key "+key+"="+toString(key)+" in "+this); 177 } 178 } 179 180 public void defineKey(Object keySpec, Object binding) 181 { 182 EKeymap keymap = this; 183 if (keySpec instanceof Sequence && ! (keySpec instanceof LList)) 184 { 185 Sequence value = (Sequence) keySpec; 187 boolean hackMeta = keySpec instanceof FString; 188 int len = value.size(); 189 for (int i = 0; i < len; ) 190 { 191 Object keyValue = value.get(i); 192 boolean sawMeta = false; 193 i++; 194 int key = asKeyStroke(keyValue); 195 if (key == 0) 196 throw new Error ("unknown keyspec: "+keyValue); 197 if (hackMeta && key > 127 && key <= 255) 198 { 199 sawMeta = true; 200 key = key - 128; 201 } 202 if ((getModifiers(key) & META_MASK) != 0) 203 { 204 key = stripMeta(key); 205 sawMeta = true; 206 } 207 if (sawMeta) 208 keymap = keymap.definePrefix(metaKey); 209 if (i < len) 210 keymap = keymap.definePrefix(key); 211 else 212 keymap.defineKey(key, binding); 213 } 214 } 215 else 216 { 217 int key = asKeyStroke(keySpec); 219 if (key == 0) 220 throw new Error ("unknown keyspec: "+keySpec); 221 defineKey(key, binding); 222 } 223 } 224 225 public void defineKey(int key, Object binding) 226 { 227 boolean sawMeta = false; 228 if ((getModifiers(key) & META_MASK) != 0) 229 { 230 key = stripMeta(key); 231 sawMeta = true; 232 } 233 EKeymap keymap = this; 234 if (sawMeta) 235 keymap = keymap.definePrefix(metaKey); 236 keymap.setAction(key, binding); 237 } 238 239 public static int asKeyStroke(char ch, int mods) 240 { 241 if (mods == SHIFT_MASK && Character.isLetter(ch)) 242 { 243 ch = Character.toUpperCase(ch); 244 mods = 0; 245 } 246 if (ch < ' ') 247 { 248 mods |= CTRL_MASK|PRESSED; 249 ch = ch == '\0' ? ' ' : (char) ('@' + (ch & 31)); 250 } 251 return ch | (mods << 16); 252 } 253 254 257 public static int getKeyForName (String name) 258 { 259 name = name.toLowerCase(); 260 int len = name.length(); 261 if (len == 0) 262 return KeyEvent.VK_UNDEFINED; 263 char c0 = name.charAt(0); 264 if (len == 1) 265 return c0; 266 switch (c0) 267 { 268 case 'b': 269 if (name == "backspace") return KeyEvent.VK_BACK_SPACE; 270 break; 271 case 'd': 272 if (name == "delete") return KeyEvent.VK_DELETE; 273 if (name == "down") return KeyEvent.VK_DOWN; 274 break; 275 case 'e': 276 if (name == "enter") return KeyEvent.VK_ENTER; 277 break; 278 case 'f': 279 if (len == 2) 280 { 281 char c1 = name.charAt(1); 282 if (c1 > '0' && c1 <= '9') 283 return KeyEvent.VK_F1 + c1 - '1'; 284 } 285 else if (len == 3 && name.charAt(0) == 'f') 286 { 287 int c1 = name.charAt(1); 288 int c2 = name.charAt(2); 289 if (c1 > '0' && c1 <= '9' 290 && c2 > '0' && c2 <= '9' 291 && (c1 = (c1 - '0') * 10 + (c2 - '0')) <= 24) 292 { 293 if (c1 <= 12) 294 return KeyEvent.VK_F10 + c2 - '0'; 295 else 296 return KeyEvent.VK_F13 + c1 - 13; 297 } 298 } 299 break; 300 case 'h': 301 if (name == "help") return KeyEvent.VK_HELP; 302 break; 303 case 'k': 304 if (name == "kp-left") return KeyEvent.VK_KP_LEFT; 305 else if (name == "kp-right") return KeyEvent.VK_KP_RIGHT; 306 else if (name == "kp-up") return KeyEvent.VK_KP_UP; 307 else if (name == "kp-down") return KeyEvent.VK_KP_DOWN; 308 else if (name == "kp-delete") return KeyEvent.VK_DELETE; 309 break; 310 case 'l': 311 if (name == "left") return KeyEvent.VK_LEFT; 312 break; 313 case 'n': 314 if (name == "next") return KeyEvent.VK_PAGE_DOWN; 315 break; 316 case 'p': 317 if (name == "prior") return KeyEvent.VK_PAGE_UP; 318 break; 319 case 'r': 320 if (name == "enter") return KeyEvent.VK_ENTER; 321 if (name == "return") return '\r'; 322 if (name == "right") return KeyEvent.VK_RIGHT; 323 break; 324 case 't': 325 if (name == "tab") return KeyEvent.VK_TAB; 326 break; 327 case 'u': 328 if (name == "up") return KeyEvent.VK_UP; 329 break; 330 } 331 return KeyEvent.VK_UNDEFINED; 332 } 333 334 public static int asKeyStroke(Object key) 335 { 336 int m = 0; 337 while (key instanceof Pair) 338 { 339 Pair pair = (Pair) key; 340 if (pair.cdr == LList.Empty) 341 key = pair.car; 342 else 343 { 344 Object car = pair.car; 345 if (car instanceof Symbol) 346 car = ((Symbol) car).getName(); 347 if (car == "control") 348 m |= CTRL_MASK; 349 if (car == "meta") 350 m |= META_MASK; 351 if (car == "shift") 352 m |= SHIFT_MASK; 353 if (car == "alt") 354 m |= ALT_MASK; 355 key = pair.cdr; 356 } 357 } 358 if (key instanceof Char) 359 { 360 return asKeyStroke(((Char) key).charValue(), m); 361 } 362 if (key instanceof IntNum) 363 { 364 return asKeyStroke((char) ((IntNum) key).intValue(), m); 365 } 366 if (key instanceof String || key instanceof Symbol) 367 { 368 String name = key instanceof String ? (String ) key 369 : ((Symbol) key).getName(); 370 if (name.length() == 1) 371 { 372 char ch = name.charAt(0); 373 if (m == 0) 374 return asKeyStroke((char) ch, 0); 375 else 376 { 377 ch = Character.toUpperCase(ch); 378 return asKeyStroke(ch, m); 379 } 380 } 381 int code = getKeyForName(name); 382 if (code == KeyEvent.VK_UNDEFINED) 383 throw new Error ("unknown key-name: "+name); 384 return code | ((m|PRESSED) << 16); 385 } 386 return 0; } 388 389 public static int stripMeta(int key) 390 { 391 int mods = getModifiers(key); 392 if ((mods & META_MASK) == 0) 393 return key; 394 mods &= ~ META_MASK; 395 int code = key & 0xFFFF; 396 boolean onRelease = (key & (RELEASED << 16)) != 0; 397 if ((mods & ~SHIFT_MASK) != 0 || onRelease 398 || code > 127 || code < ' ') 399 return code | ((mods|RELEASED) << 16); 400 else 401 { 402 if (code >= 'A' && code <= 'Z'&& mods != SHIFT_MASK) 403 code = code + 'a' - 'A'; 404 return code; 405 } 406 } 407 408 417 public static boolean ignorable (int key) 418 { 419 if ((key & (RELEASED << 16)) != 0) 420 return true; 421 int mods = getModifiers(key); 422 int code = key & 0xFFFF; 426 if ((key & (PRESSED << 16)) == 0) 427 { char ch = (char) key; 429 return (ch < ' ' && ch != metaKey) || ch >= 127; 430 } 431 else 432 { if (code == KeyEvent.VK_CONTROL || code == KeyEvent.VK_SHIFT 438 || code == KeyEvent.VK_ALT || code == KeyEvent.VK_META 439 || code == KeyEvent.VK_ESCAPE) 440 return true; 441 return (mods & ~SHIFT_MASK) == 0 442 && code >= KeyEvent.VK_SPACE && code < KeyEvent.VK_DELETE; 443 } 444 } 445 446 476 477 public static String toString(int code) 478 { 479 StringBuffer sbuf = new StringBuffer (); 480 sbuf.append('['); 481 if (((code >> 16) & (PRESSED|RELEASED)) == 0) 482 { 483 sbuf.append("char:'"); 484 gnu.jemacs.lang.ELisp.readableChar((char) code, sbuf, true); 485 sbuf.append("'"); 486 } 487 else 488 { 489 sbuf.append("code:"); 490 sbuf.append(code & 0xFFFF); 491 } 492 int mods = (code >> 16) & 0xff; 493 if (mods != 0) 494 { 495 sbuf.append(" mods:"); 496 sbuf.append(mods); 497 } 498 if ((code & (RELEASED << 16)) != 0) 499 sbuf.append(" release"); 500 sbuf.append(']'); 501 return sbuf.toString(); 502 } 503 504 public Object 505 lookupKey(Sequence keys, boolean acceptDefaults) 506 { 507 int nKeys = keys.size(); 508 int[] prefixKeys = new int[nKeys]; 509 java.util.Enumeration enumKeys = keys.elements(); 510 for (int i = 0; enumKeys.hasMoreElements(); i++) 511 { 512 prefixKeys[i] = asKeyStroke(enumKeys.nextElement()); 513 } 514 return lookupKey(prefixKeys, nKeys, 0, acceptDefaults); 515 } 516 517 public Object lookupKey(int[] prefixKeys, int nPrefix, 518 int key, boolean acceptDefaults) 519 { 520 EKeymap keymap = this; 521 int nKeys = nPrefix + (key != 0 ? 1 : 0); 522 boolean pendingMeta = false; 523 if (nKeys == 0) 524 throw new Error ("no keys"); 525 for (int i = 0; ; ) 526 { 527 int key_i = i == nPrefix ? key : prefixKeys[i]; 528 529 if (pendingMeta) 530 key_i |= ((META_MASK|PRESSED) << 16); 531 Object command = keymap.get(key_i, false); 532 Object metaCommand; 533 if (command == null 534 && (getModifiers(key_i) & META_MASK) != 0 535 && (metaCommand = keymap.get(metaKey, false)) instanceof EKeymap) 536 { 537 command = ((EKeymap) metaCommand).get(stripMeta(key_i), false); 538 } 539 i++; 540 if (command == null) 541 { 542 if (ignorable(key)) 543 { 544 return EToolkit.getInstance().getIgnoreAction(); 545 } 546 else 547 return keymap.getDefaultBinding(); 548 } 549 if (i == nKeys) 550 return command; 551 Object comm; 552 if (command instanceof String || command instanceof Symbol) 553 command = Command.resolveSymbol(command); 554 if (command instanceof EKeymap) 555 keymap = (EKeymap) command; 556 else 557 return null; 558 } 559 } 560 561 564 public static String show(int binary) 565 { 566 StringBuffer sb = new StringBuffer (Integer.toBinaryString(binary)); 567 for (int i = 32 - sb.length() - 1; i >= 0; i--) 568 sb.insert(0, '0'); 569 return sb.toString(); 570 } 571 } 572 573 | Popular Tags |