1 36 37 40 41 package com.sun.inputmethods.internal.codepointim; 42 import java.text.AttributedCharacterIterator ; 43 import java.util.Map ; 44 45 import java.awt.AWTEvent ; 46 import java.awt.Toolkit ; 47 import java.awt.Rectangle ; 48 import java.awt.event.InputMethodEvent ; 49 import java.awt.event.KeyEvent ; 50 import java.awt.font.TextAttribute ; 51 import java.awt.font.TextHitInfo ; 52 import java.awt.im.InputMethodHighlight ; 53 import java.awt.im.spi.InputMethod ; 54 import java.awt.im.spi.InputMethodContext ; 55 import java.io.IOException ; 56 import java.text.AttributedString ; 57 import java.util.Locale ; 58 59 66 public class CodePointInputMethod implements InputMethod { 67 68 private static final int UNSET = 0; 69 private static final int ESCAPE = 1; private static final int SPECIAL_ESCAPE = 2; private static final int SURROGATE_PAIR = 3; 73 private InputMethodContext context; 74 private Locale locale; 75 private StringBuffer buffer; 76 private int insertionPoint; 77 private int format = UNSET; 78 79 80 public CodePointInputMethod() throws IOException { 81 } 82 83 87 public void dispatchEvent(AWTEvent event) { 88 if (!(event instanceof KeyEvent )) { 90 return; 91 } 92 93 KeyEvent e = (KeyEvent ) event; 94 int eventID = event.getID(); 95 boolean notInCompositionMode = buffer.length() == 0; 96 97 if (eventID == KeyEvent.KEY_PRESSED) { 98 if (notInCompositionMode) { 100 return; 101 } 102 103 switch (e.getKeyCode()) { 104 case KeyEvent.VK_LEFT: 105 moveCaretLeft(); 106 break; 107 case KeyEvent.VK_RIGHT: 108 moveCaretRight(); 109 break; 110 } 111 } else if (eventID == KeyEvent.KEY_TYPED) { 112 char c = e.getKeyChar(); 113 114 if (notInCompositionMode) { 116 if (c != '\\') { 118 return; 119 } 120 121 startComposition(); } else { 123 switch (c) { 124 case ' ': finishComposition(); 126 break; 127 case '\u007f': deleteCharacter(); 129 break; 130 case '\b': deletePreviousCharacter(); 132 break; 133 case '\u001b': cancelComposition(); 135 break; 136 case '\n': case '\t': sendCommittedText(); 139 break; 140 default: 141 composeUnicodeEscape(c); 142 break; 143 } 144 } 145 } else { if (notInCompositionMode) { 148 return; 149 } 150 } 151 152 e.consume(); 153 } 154 155 private void composeUnicodeEscape(char c) { 156 switch (buffer.length()) { 157 case 1: waitEscapeCharacter(c); 159 break; 160 case 2: case 3: case 4: waitDigit(c); 164 break; 165 case 5: if (format == SPECIAL_ESCAPE) { 167 waitDigit(c); 168 } else { 169 waitDigit2(c); 170 } 171 break; 172 case 6: if (format == SPECIAL_ESCAPE) { 174 waitDigit(c); 175 } else if (format == SURROGATE_PAIR) { 176 waitBackSlashOrLowSurrogate(c); 177 } else { 178 beep(); 179 } 180 break; 181 case 7: waitDigit(c); 186 break; 187 case 8: case 9: case 10: case 11: if (format == SURROGATE_PAIR) { 192 waitDigit(c); 193 } else { 194 beep(); 195 } 196 break; 197 default: 198 beep(); 199 break; 200 } 201 } 202 203 private void waitEscapeCharacter(char c) { 204 if (c == 'u' || c == 'U') { 205 buffer.append(c); 206 insertionPoint++; 207 sendComposedText(); 208 format = (c == 'u') ? ESCAPE : SPECIAL_ESCAPE; 209 } else { 210 if (c != '\\') { 211 buffer.append(c); 212 insertionPoint++; 213 } 214 sendCommittedText(); 215 } 216 } 217 218 private void waitDigit(char c) { 219 if (Character.digit(c, 16) != -1) { 220 buffer.insert(insertionPoint++, c); 221 sendComposedText(); 222 } else { 223 beep(); 224 } 225 } 226 227 private void waitDigit2(char c) { 228 if (Character.digit(c, 16) != -1) { 229 buffer.insert(insertionPoint++, c); 230 char codePoint = (char)getCodePoint(buffer, 2, 5); 231 if (Character.isHighSurrogate(codePoint)) { 232 format = SURROGATE_PAIR; 233 buffer.append("\\u"); 234 insertionPoint = 8; 235 } else { 236 format = ESCAPE; 237 } 238 sendComposedText(); 239 } else { 240 beep(); 241 } 242 } 243 244 private void waitBackSlashOrLowSurrogate(char c) { 245 if (insertionPoint == 6) { 246 if (c == '\\') { 247 buffer.append(c); 248 buffer.append('u'); 249 insertionPoint = 8; 250 sendComposedText(); 251 } else if (Character.digit(c, 16) != -1) { 252 buffer.append("\\u"); 253 buffer.append(c); 254 insertionPoint = 9; 255 sendComposedText(); 256 } else { 257 beep(); 258 } 259 } else { 260 beep(); 261 } 262 } 263 264 267 private void sendComposedText() { 268 AttributedString as = new AttributedString (buffer.toString()); 269 as.addAttribute(TextAttribute.INPUT_METHOD_HIGHLIGHT, 270 InputMethodHighlight.SELECTED_RAW_TEXT_HIGHLIGHT); 271 context.dispatchInputMethodEvent( 272 InputMethodEvent.INPUT_METHOD_TEXT_CHANGED, 273 as.getIterator(), 0, 274 TextHitInfo.leading(insertionPoint), null); 275 } 276 277 280 private void sendCommittedText() { 281 AttributedString as = new AttributedString (buffer.toString()); 282 context.dispatchInputMethodEvent( 283 InputMethodEvent.INPUT_METHOD_TEXT_CHANGED, 284 as.getIterator(), buffer.length(), 285 TextHitInfo.leading(insertionPoint), null); 286 287 buffer.setLength(0); 288 insertionPoint = 0; 289 format = UNSET; 290 } 291 292 296 private void moveCaretLeft() { 297 int len = buffer.length(); 298 if (--insertionPoint < 2) { 299 insertionPoint++; 300 beep(); 301 } else if (format == SURROGATE_PAIR && insertionPoint == 7) { 302 insertionPoint = 8; 303 beep(); 304 } 305 306 context.dispatchInputMethodEvent( 307 InputMethodEvent.CARET_POSITION_CHANGED, 308 null, 0, 309 TextHitInfo.leading(insertionPoint), null); 310 } 311 312 315 private void moveCaretRight() { 316 int len = buffer.length(); 317 if (++insertionPoint > len) { 318 insertionPoint = len; 319 beep(); 320 } 321 322 context.dispatchInputMethodEvent( 323 InputMethodEvent.CARET_POSITION_CHANGED, 324 null, 0, 325 TextHitInfo.leading(insertionPoint), null); 326 } 327 328 333 private void deletePreviousCharacter() { 334 if (insertionPoint == 2) { 335 if (buffer.length() == 2) { 336 cancelComposition(); 337 } else { 338 beep(); 341 } 342 } else if (insertionPoint == 8) { 343 if (buffer.length() == 8) { 344 if (format == SURROGATE_PAIR) { 345 buffer.deleteCharAt(--insertionPoint); 346 } 347 buffer.deleteCharAt(--insertionPoint); 348 sendComposedText(); 349 } else { 350 beep(); 353 } 354 } else { 355 buffer.deleteCharAt(--insertionPoint); 356 if (buffer.length() == 0) { 357 sendCommittedText(); 358 } else { 359 sendComposedText(); 360 } 361 } 362 } 363 364 368 private void deleteCharacter() { 369 if (insertionPoint < buffer.length()) { 370 buffer.deleteCharAt(insertionPoint); 371 sendComposedText(); 372 } else { 373 beep(); 374 } 375 } 376 377 private void startComposition() { 378 buffer.append('\\'); 379 insertionPoint = 1; 380 sendComposedText(); 381 } 382 383 private void cancelComposition() { 384 buffer.setLength(0); 385 insertionPoint = 0; 386 sendCommittedText(); 387 } 388 389 private void finishComposition() { 390 int len = buffer.length(); 391 if (len == 6 && format != SPECIAL_ESCAPE) { 392 char codePoint = (char)getCodePoint(buffer, 2, 5); 393 if (Character.isValidCodePoint(codePoint) && codePoint != 0xFFFF) { 394 buffer.setLength(0); 395 buffer.append(codePoint); 396 sendCommittedText(); 397 return; 398 } 399 } else if (len == 8 && format == SPECIAL_ESCAPE) { 400 int codePoint = getCodePoint(buffer, 2, 7); 401 if (Character.isValidCodePoint(codePoint) && codePoint != 0xFFFF) { 402 buffer.setLength(0); 403 buffer.appendCodePoint(codePoint); 404 sendCommittedText(); 405 return; 406 } 407 } else if (len == 12 && format == SURROGATE_PAIR) { 408 char[] codePoint = { 409 (char)getCodePoint(buffer, 2, 5), 410 (char)getCodePoint(buffer, 8, 11) 411 }; 412 if (Character.isHighSurrogate(codePoint[0]) && 413 Character.isLowSurrogate(codePoint[1])) { 414 buffer.setLength(0); 415 buffer.append(codePoint); 416 sendCommittedText(); 417 return; 418 } 419 } 420 421 beep(); 422 } 423 424 private int getCodePoint(StringBuffer sb, int from, int to) { 425 int value = 0; 426 for (int i = from; i <= to; i++) { 427 value = (value<<4) + Character.digit(sb.charAt(i), 16); 428 } 429 return value; 430 } 431 432 private static void beep() { 433 Toolkit.getDefaultToolkit().beep(); 434 } 435 436 437 public void activate() { 438 if (buffer == null) { 439 buffer = new StringBuffer (12); 440 insertionPoint = 0; 441 } 442 } 443 444 public void deactivate(boolean isTemporary) { 445 if (!isTemporary) { 446 buffer = null; 447 } 448 } 449 450 public void dispose() { 451 } 452 453 public Object getControlObject() { 454 return null; 455 } 456 457 public void endComposition() { 458 sendCommittedText(); 459 } 460 461 public Locale getLocale() { 462 return locale; 463 } 464 465 public void hideWindows() { 466 } 467 468 public boolean isCompositionEnabled() { 469 return true; 471 } 472 473 public void notifyClientWindowChange(Rectangle location) { 474 } 475 476 public void reconvert() { 477 throw new UnsupportedOperationException (); 479 } 480 481 public void removeNotify() { 482 } 483 484 public void setCharacterSubsets(Character.Subset [] subsets) { 485 } 486 487 public void setCompositionEnabled(boolean enable) { 488 throw new UnsupportedOperationException (); 490 } 491 492 public void setInputMethodContext(InputMethodContext context) { 493 this.context = context; 494 } 495 496 499 public boolean setLocale(Locale locale) { 500 this.locale = locale; 501 return true; 502 } 503 } 504 | Popular Tags |