/******************************************************************************* * Breakout Cave Survey Visualizer * * Copyright (C) 2014 James Edwards * * jedwards8 at fastmail dot fm * * This program is free software; you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) any later * version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License along with * this program; if not, write to the Free Software Foundation, Inc., 51 * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. *******************************************************************************/ package org.andork.ui.test; import static java.awt.event.InputEvent.ALT_DOWN_MASK; import static java.awt.event.InputEvent.CTRL_DOWN_MASK; import static java.awt.event.InputEvent.SHIFT_DOWN_MASK; import static java.awt.event.KeyEvent.CHAR_UNDEFINED; import static java.awt.event.KeyEvent.KEY_PRESSED; import static java.awt.event.KeyEvent.KEY_RELEASED; import static java.awt.event.KeyEvent.KEY_TYPED; import java.awt.Component; import java.awt.Container; import java.awt.EventQueue; import java.awt.Rectangle; import java.awt.Robot; import java.awt.Toolkit; import java.awt.event.KeyEvent; import java.awt.event.MouseEvent; import javax.swing.CellRendererPane; import javax.swing.JComponent; import javax.swing.SwingUtilities; /** * Like {@link Robot}, except that it works by posting fake events to the AWT * event queue rather than faking user action at the OS level. * * @author andy.edwards */ public class DefaultGhost implements Ghost { private static void scrollRectToVisible(Component c, Rectangle aRect) { if (c instanceof JComponent) { ((JComponent) c).scrollRectToVisible(aRect); } else { Container parent; int dx = c.getX(), dy = c.getY(); for (parent = c.getParent(); !(parent == null) && !(parent instanceof JComponent) && !(parent instanceof CellRendererPane); parent = parent.getParent()) { Rectangle bounds = parent.getBounds(); dx += bounds.x; dy += bounds.y; } if (!(parent == null) && !(parent instanceof CellRendererPane)) { aRect.x += dx; aRect.y += dy; scrollRectToVisible(parent, aRect); aRect.x -= dx; aRect.y -= dy; } } } @Override public InputBuilder on(Component c) { return new InputBuilder(c) { @Override public InputBuilder click(int button, int clickCount) { EventQueue queue = Toolkit.getDefaultToolkit().getSystemEventQueue(); boolean ctrl = (modifiers & CTRL_DOWN_MASK) != 0; boolean alt = (modifiers & ALT_DOWN_MASK) != 0; boolean shift = (modifiers & SHIFT_DOWN_MASK) != 0; int curModifiers = 0; if (ctrl) { curModifiers |= CTRL_DOWN_MASK; queue.postEvent(new KeyEvent(comp, KEY_PRESSED, System.currentTimeMillis(), curModifiers, KeyEvent.VK_CONTROL, CHAR_UNDEFINED)); } if (alt) { curModifiers |= ALT_DOWN_MASK; queue.postEvent(new KeyEvent(comp, KEY_PRESSED, System.currentTimeMillis(), curModifiers, KeyEvent.VK_ALT, CHAR_UNDEFINED)); } if (shift) { curModifiers |= SHIFT_DOWN_MASK; queue.postEvent(new KeyEvent(comp, KEY_PRESSED, System.currentTimeMillis(), curModifiers, KeyEvent.VK_SHIFT, CHAR_UNDEFINED)); } for (int i = 0; i < clickCount; i++) { queue.postEvent(new MouseEvent(comp, MouseEvent.MOUSE_PRESSED, System.currentTimeMillis(), modifiers, mouseLocation.x, mouseLocation.y, i, false, button)); queue.postEvent(new MouseEvent(comp, MouseEvent.MOUSE_RELEASED, System.currentTimeMillis(), modifiers, mouseLocation.x, mouseLocation.y, i, false, button)); queue.postEvent(new MouseEvent(comp, MouseEvent.MOUSE_CLICKED, System.currentTimeMillis(), modifiers, mouseLocation.x, mouseLocation.y, i + 1, false, button)); try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } } if (ctrl) { curModifiers &= ~CTRL_DOWN_MASK; queue.postEvent(new KeyEvent(comp, KEY_RELEASED, System.currentTimeMillis(), curModifiers, KeyEvent.VK_CONTROL, CHAR_UNDEFINED)); } if (alt) { curModifiers &= ~ALT_DOWN_MASK; queue.postEvent(new KeyEvent(comp, KEY_RELEASED, System.currentTimeMillis(), curModifiers, KeyEvent.VK_ALT, CHAR_UNDEFINED)); } if (shift) { curModifiers &= ~SHIFT_DOWN_MASK; queue.postEvent(new KeyEvent(comp, KEY_RELEASED, System.currentTimeMillis(), curModifiers, KeyEvent.VK_SHIFT, CHAR_UNDEFINED)); } return this; } @Override public InputBuilder press(int keyCode) { EventQueue queue = Toolkit.getDefaultToolkit().getSystemEventQueue(); char keyChar = (char) keyCode; boolean ctrl = (modifiers & CTRL_DOWN_MASK) != 0; boolean alt = (modifiers & ALT_DOWN_MASK) != 0; boolean shift = (modifiers & SHIFT_DOWN_MASK) != 0; int curModifiers = 0; if (ctrl) { curModifiers |= CTRL_DOWN_MASK; queue.postEvent(new KeyEvent(comp, KEY_PRESSED, System.currentTimeMillis(), curModifiers, KeyEvent.VK_CONTROL, CHAR_UNDEFINED)); } if (alt) { curModifiers |= ALT_DOWN_MASK; queue.postEvent(new KeyEvent(comp, KEY_PRESSED, System.currentTimeMillis(), curModifiers, KeyEvent.VK_ALT, CHAR_UNDEFINED)); } if (shift) { curModifiers |= SHIFT_DOWN_MASK; queue.postEvent(new KeyEvent(comp, KEY_PRESSED, System.currentTimeMillis(), curModifiers, KeyEvent.VK_SHIFT, CHAR_UNDEFINED)); } queue.postEvent(new KeyEvent(comp, KEY_PRESSED, System.currentTimeMillis(), modifiers, Character.toUpperCase(keyChar), CHAR_UNDEFINED)); return this; } @Override public InputBuilder release(int keyCode) { EventQueue queue = Toolkit.getDefaultToolkit().getSystemEventQueue(); char keyChar = (char) keyCode; boolean ctrl = (modifiers & CTRL_DOWN_MASK) != 0; boolean alt = (modifiers & ALT_DOWN_MASK) != 0; boolean shift = (modifiers & SHIFT_DOWN_MASK) != 0; int curModifiers = 0; if (ctrl) { curModifiers |= CTRL_DOWN_MASK; } if (alt) { curModifiers |= ALT_DOWN_MASK; } if (shift) { curModifiers |= SHIFT_DOWN_MASK; } queue.postEvent(new KeyEvent(comp, KEY_RELEASED, System.currentTimeMillis(), modifiers, Character.toUpperCase(keyChar), CHAR_UNDEFINED)); if (ctrl) { curModifiers &= ~CTRL_DOWN_MASK; queue.postEvent(new KeyEvent(comp, KEY_RELEASED, System.currentTimeMillis(), curModifiers, KeyEvent.VK_CONTROL, CHAR_UNDEFINED)); } if (alt) { curModifiers &= ~ALT_DOWN_MASK; queue.postEvent(new KeyEvent(comp, KEY_RELEASED, System.currentTimeMillis(), curModifiers, KeyEvent.VK_ALT, CHAR_UNDEFINED)); } if (shift) { curModifiers &= ~SHIFT_DOWN_MASK; queue.postEvent(new KeyEvent(comp, KEY_RELEASED, System.currentTimeMillis(), curModifiers, KeyEvent.VK_SHIFT, CHAR_UNDEFINED)); } return this; } @Override public InputBuilder type(int keyCode) { EventQueue queue = Toolkit.getDefaultToolkit().getSystemEventQueue(); char keyChar = (char) keyCode; boolean ctrl = (modifiers & CTRL_DOWN_MASK) != 0; boolean alt = (modifiers & ALT_DOWN_MASK) != 0; boolean shift = (modifiers & SHIFT_DOWN_MASK) != 0; int curModifiers = 0; if (ctrl) { curModifiers |= CTRL_DOWN_MASK; queue.postEvent(new KeyEvent(comp, KEY_PRESSED, System.currentTimeMillis(), curModifiers, KeyEvent.VK_CONTROL, CHAR_UNDEFINED)); } if (alt) { curModifiers |= ALT_DOWN_MASK; queue.postEvent(new KeyEvent(comp, KEY_PRESSED, System.currentTimeMillis(), curModifiers, KeyEvent.VK_ALT, CHAR_UNDEFINED)); } if (shift) { curModifiers |= SHIFT_DOWN_MASK; queue.postEvent(new KeyEvent(comp, KEY_PRESSED, System.currentTimeMillis(), curModifiers, KeyEvent.VK_SHIFT, CHAR_UNDEFINED)); } queue.postEvent(new KeyEvent(comp, KEY_PRESSED, System.currentTimeMillis(), modifiers, Character.toUpperCase(keyChar), CHAR_UNDEFINED)); queue.postEvent(new KeyEvent(comp, KEY_TYPED, System.currentTimeMillis(), modifiers, KeyEvent.VK_UNDEFINED, keyChar)); queue.postEvent(new KeyEvent(comp, KEY_RELEASED, System.currentTimeMillis(), modifiers, Character.toUpperCase(keyChar), CHAR_UNDEFINED)); if (ctrl) { curModifiers &= ~CTRL_DOWN_MASK; queue.postEvent(new KeyEvent(comp, KEY_RELEASED, System.currentTimeMillis(), curModifiers, KeyEvent.VK_CONTROL, CHAR_UNDEFINED)); } if (alt) { curModifiers &= ~ALT_DOWN_MASK; queue.postEvent(new KeyEvent(comp, KEY_RELEASED, System.currentTimeMillis(), curModifiers, KeyEvent.VK_ALT, CHAR_UNDEFINED)); } if (shift) { curModifiers &= ~SHIFT_DOWN_MASK; queue.postEvent(new KeyEvent(comp, KEY_RELEASED, System.currentTimeMillis(), curModifiers, KeyEvent.VK_SHIFT, CHAR_UNDEFINED)); } return this; } }; } @Override public void scroll(final Component c, final Rectangle toBounds) { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { scrollRectToVisible(c, toBounds); } }); } private void type(Component c, int modifiers, int keyCode) { EventQueue queue = Toolkit.getDefaultToolkit().getSystemEventQueue(); char keyChar = (char) keyCode; boolean ctrl = (modifiers & CTRL_DOWN_MASK) != 0; boolean alt = (modifiers & ALT_DOWN_MASK) != 0; boolean shift = (modifiers & SHIFT_DOWN_MASK) != 0; int curModifiers = 0; if (ctrl) { curModifiers |= CTRL_DOWN_MASK; queue.postEvent(new KeyEvent(c, KEY_PRESSED, System.currentTimeMillis(), curModifiers, KeyEvent.VK_CONTROL, CHAR_UNDEFINED)); } if (alt) { curModifiers |= ALT_DOWN_MASK; queue.postEvent(new KeyEvent(c, KEY_PRESSED, System.currentTimeMillis(), curModifiers, KeyEvent.VK_ALT, CHAR_UNDEFINED)); } if (shift) { curModifiers |= SHIFT_DOWN_MASK; queue.postEvent(new KeyEvent(c, KEY_PRESSED, System.currentTimeMillis(), curModifiers, KeyEvent.VK_SHIFT, CHAR_UNDEFINED)); } queue.postEvent(new KeyEvent(c, KEY_PRESSED, System.currentTimeMillis(), modifiers, Character.toUpperCase(keyChar), CHAR_UNDEFINED)); queue.postEvent(new KeyEvent(c, KEY_TYPED, System.currentTimeMillis(), modifiers, KeyEvent.VK_UNDEFINED, keyChar)); queue.postEvent(new KeyEvent(c, KEY_RELEASED, System.currentTimeMillis(), modifiers, Character.toUpperCase(keyChar), CHAR_UNDEFINED)); if (ctrl) { curModifiers &= ~CTRL_DOWN_MASK; queue.postEvent(new KeyEvent(c, KEY_RELEASED, System.currentTimeMillis(), curModifiers, KeyEvent.VK_CONTROL, CHAR_UNDEFINED)); } if (alt) { curModifiers &= ~ALT_DOWN_MASK; queue.postEvent(new KeyEvent(c, KEY_RELEASED, System.currentTimeMillis(), curModifiers, KeyEvent.VK_ALT, CHAR_UNDEFINED)); } if (shift) { curModifiers &= ~SHIFT_DOWN_MASK; queue.postEvent(new KeyEvent(c, KEY_RELEASED, System.currentTimeMillis(), curModifiers, KeyEvent.VK_SHIFT, CHAR_UNDEFINED)); } } @Override public void type(Component c, String text) { for (int i = 0; i < text.length(); i++) { type(c, 0, text.charAt(i)); } } }