package jetbrains.mps.lang.test.runtime; /*Generated by MPS */ import java.lang.reflect.InvocationTargetException; import java.awt.event.KeyEvent; import jetbrains.mps.internal.collections.runtime.Sequence; import jetbrains.mps.internal.collections.runtime.ArrayUtils; import jetbrains.mps.internal.collections.runtime.ISelector; import java.util.List; import jetbrains.mps.internal.collections.runtime.ListSequence; import jetbrains.mps.internal.collections.runtime.ITranslator2; import java.util.Iterator; import jetbrains.mps.baseLanguage.closures.runtime.YieldingIterator; import javax.swing.KeyStroke; import java.awt.Component; import java.lang.reflect.Method; import jetbrains.mps.internal.collections.runtime.IVisitor; import junit.framework.Assert; import jetbrains.mps.nodeEditor.EditorComponent; import jetbrains.mps.openapi.editor.cells.EditorCell; import javax.swing.JComponent; public class KeyEventsDispatcher { private final BaseEditorTestBody myEditorTest; public KeyEventsDispatcher(BaseEditorTestBody editorTest) { myEditorTest = editorTest; } public void typeString(final String text) throws InterruptedException, InvocationTargetException { Iterable<KeyEvent> events = Sequence.fromIterable(ArrayUtils.fromCharacterArray(text.toCharArray())).select(new ISelector<Character, KeyEvent>() { public KeyEvent select(Character it) { return new KeyEvent(myEditorTest.getEditorComponent(), KeyEvent.KEY_TYPED, 0, 0, 0, it); } }); processKeyEvents(events); } public void pressKeys(final List<String> keyStrokes) throws InterruptedException, InvocationTargetException { Iterable<KeyEvent> events = ListSequence.fromList(keyStrokes).translate(new ITranslator2<String, KeyEvent>() { public Iterable<KeyEvent> translate(final String it) { return new Iterable<KeyEvent>() { public Iterator<KeyEvent> iterator() { return new YieldingIterator<KeyEvent>() { private int __CP__ = 0; protected boolean moveToNext() { __loop__: do { __switch__: switch (this.__CP__) { case -1: assert false : "Internal error"; return false; case 6: if (_5_keyChar == KeyEvent.CHAR_UNDEFINED && _4_keyCode != KeyEvent.VK_UNDEFINED && ((_4_keyCode >= KeyEvent.VK_0 && _4_keyCode <= KeyEvent.VK_9) || (_4_keyCode >= KeyEvent.VK_A && _4_keyCode <= KeyEvent.VK_Z))) { this.__CP__ = 7; break; } this.__CP__ = 8; break; case 8: this.__CP__ = 10; this.yield(new KeyEvent(myEditorTest.getEditorComponent(), KeyEvent.KEY_PRESSED, 0, _3_stroke.getModifiers(), _4_keyCode, _5_keyChar)); return true; case 10: this.__CP__ = 1; this.yield(new KeyEvent(myEditorTest.getEditorComponent(), KeyEvent.KEY_RELEASED, 0, _3_stroke.getModifiers(), _4_keyCode, _5_keyChar)); return true; case 0: this._3_stroke = KeyStroke.getKeyStroke(it); this._4_keyCode = _3_stroke.getKeyCode(); this._5_keyChar = _3_stroke.getKeyChar(); this.__CP__ = 6; break; case 7: // todo it may be worthwhile to also detect other unicode chars from keyCode and supply them into keyChar // There is currently no good complete cross-platform code to char conversion utility, it seems // KEY_PRESSED events may or may not contain a concrete keyChar. Its presence is definitely not a problem _5_keyChar = (char) _4_keyCode; this.__CP__ = 8; break; default: break __loop__; } } while (true); return false; } private KeyStroke _3_stroke; private int _4_keyCode; private char _5_keyChar; }; } }; } }); processKeyEvents(events); } private void processKeyEvents(final Iterable<KeyEvent> events) throws InterruptedException, InvocationTargetException { final Component eventTargetComponent = getKeyEventTargetComponent(); final Method processKeyEventMethod = KeyEventsDispatcher.getProcessKeyEventMethod(eventTargetComponent); final boolean[] eventsPassed = new boolean[]{true}; if (eventTargetComponent == null) { myEditorTest.runUndoableInEDTAndWait(new Runnable() { public void run() { Sequence.fromIterable(events).visitAll(new IVisitor<KeyEvent>() { public void visit(KeyEvent it) { if (it.getID() == KeyEvent.KEY_TYPED) { myEditorTest.getEditorComponent().processKeyTyped(it); } else if (it.getID() == KeyEvent.KEY_PRESSED) { myEditorTest.getEditorComponent().processKeyPressed(it); } else if (it.getID() == KeyEvent.KEY_RELEASED) { myEditorTest.getEditorComponent().processKeyReleased(it); } else { assert false : "Wrong Id " + it.getID(); } } }); } }); } else { myEditorTest.runUndoableInEDTAndWait(new Runnable() { public void run() { for (KeyEvent event : Sequence.fromIterable(events)) { try { processKeyEventMethod.invoke(eventTargetComponent, event); } catch (InvocationTargetException e) { eventsPassed[0] = false; } catch (IllegalAccessException e) { eventsPassed[0] = false; } } } }); } Assert.assertTrue("Keyboard events were not passed to corresponding component", eventsPassed[0]); } private Component getKeyEventTargetComponent() { EditorComponent editorComponent = myEditorTest.getEditorComponent(); EditorCell selectedCell = editorComponent.getSelectedCell(); if (selectedCell == null) { // TODO: return editorComponent here return null; } Component eventTarget = EditorUtil.getEventTargetComponent(selectedCell, editorComponent); if (eventTarget == editorComponent) { // TODO: return editorComponent here return null; } while ((eventTarget instanceof JComponent) && ((JComponent) eventTarget).getComponentCount() > 0) { eventTarget = ((JComponent) eventTarget).getComponent(((JComponent) eventTarget).getComponentCount() - 1); } return eventTarget; } private static Method getProcessKeyEventMethod(Component eventTargetComponent) { if (eventTargetComponent == null) { return null; } Class<?> clazz = eventTargetComponent.getClass(); Method theMethod = null; while (theMethod == null && clazz != null) { try { theMethod = clazz.getDeclaredMethod("processKeyEvent", KeyEvent.class); theMethod.setAccessible(true); return theMethod; } catch (NoSuchMethodException e) { } clazz = clazz.getSuperclass(); } Assert.fail("Cannot find processKeyEvent method in " + eventTargetComponent.getClass() + "class"); return null; } }