/******************************************************************************* * Copyright (c) 2012 Google, Inc. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Google, Inc. - initial API and implementation *******************************************************************************/ package com.windowtester.runtime.swt.internal.selector; import org.eclipse.swt.SWT; import org.eclipse.swt.graphics.Point; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Event; import org.eclipse.swt.widgets.Widget; import abbot.Platform; import abbot.tester.swt.Robot; import abbot.tester.swt.WidgetLocator; import com.windowtester.runtime.internal.KeyStrokeDecoder; import com.windowtester.runtime.swt.internal.operation.SWTKeyOperation; import com.windowtester.runtime.swt.internal.operation.SWTPushEventOperation; import com.windowtester.runtime.swt.internal.state.MouseConfig; /** * Posts primitive events directly to the SWT event queue. */ public class DisplayEventDispatcher { protected Point pointT = new Point(0, 0); // keyclick on GTK helper abbot.swt.Robot _robot; //////////////////////////////////////////////////////////////////////////// // // Primitive event posting actions // //////////////////////////////////////////////////////////////////////////// /** * Dispatch a keyClick(keyUp..keyDown) event. * * @param keyCode * - the key to click. */ public void keyClick(int keyCode) { // keyDown(keyCode); // keyUp(keyCode); new SWTKeyOperation().keyCode(keyCode).execute(); } /** * Dispatch a keyClick(keyUp..keyDown) event. * * @param keyCode * - the key to click. */ public void keyClick(char keyCode) { /* * Work-around for gtk where we rely on the Robot to handle mappings for * us */ if (SWT.getPlatform().equals("gtk") || Platform.isOSX()) { // Mac // testing // (fix $ // problem) robotKeyClick(keyCode); return; } /* * In the non-gtk case, stick with our original strategy */ boolean shift = needsShift(keyCode); if (shift) keyDown(SWT.SHIFT); keyDown(keyCode); // for some reason $ becomes the +/- char on Mac, so // see above keyUp(keyCode); if (shift) keyUp(SWT.SHIFT); } /** * Key click method that delegates to SWT Robot * * @param keyCode * - the key to click. */ public void robotKeyClick(final char keyCode) { // robot takes care of figuring what modifies are used final abbot.swt.Robot robot = getAbbotRobot(); // wrap in a sync exec to try to patch repeated entries on GTK // due to OS load (conjecture from John: SWT thinks the user wants that // character to be repeated a bunch of times because their finger // hasn't left the keyboard while the even queue is processing other // stuff. Display.getDefault().syncExec(new Runnable() { public void run() { robot.keyPress((int) keyCode); robot.keyRelease((int) keyCode); } }); } /** * Determine if this key requires a shift to dispatch the keyStroke. * * @param keyCode * - the key in question * @return true if a shift event is required. */ public boolean needsShift(char keyCode) { if (keyCode >= 62 && keyCode <= 90) return true; if (keyCode >= 123 && keyCode <= 126) return true; if (keyCode >= 33 && keyCode <= 43 && keyCode != 39) return true; if (keyCode >= 94 && keyCode <= 95) return true; if (keyCode == 58 || keyCode == 60 || keyCode == 62) return true; return false; } /** * Dispatch a keyUp event. * * @param keyCode * - the key to release. */ public void keyUp(int keyCode) { int[] keys = extractKeys(keyCode); // NOTICE: this is done in reverse order! for (int i = keys.length - 1; i >= 0; --i) doKeyUp(keys[i]); } private void doKeyUp(final int keyCode) { SpecialKeyHandler.preUp(keyCode); // trace("post key up " + keyCode); Event event = new Event(); event.type = SWT.KeyUp; event.keyCode = keyCode; new SWTPushEventOperation(event).execute(); } /** * Dispatch a keyDown event. * * @param keyCode * - the key to press. */ public void keyDown(int keyCode) { int[] keys = extractKeys(keyCode); for (int i = 0; i < keys.length; ++i) doKeyDown(keys[i]); } /** * Extract discrete keys from this (possibly) compound key. */ private int[] extractKeys(int keyCode) { return KeyStrokeDecoder.extractModifiers(keyCode); } private void doKeyDown(final int keyCode) { SpecialKeyHandler.preDown(keyCode); // trace("post key down " + keyCode); Event event = new Event(); event.type = SWT.KeyDown; event.keyCode = keyCode; new SWTPushEventOperation(event).execute(); } /** * Dispatch a keyUp event. * * @param keyCode * - the key to release. */ public void keyUp(final char keyCode) { // trace("post key up " + keyCode); Event event = new Event(); event.type = SWT.KeyUp; event.character = keyCode; new SWTPushEventOperation(event).execute(); } /** * Dispatch a keyDown event. * * @param keyCode * - the key to press. */ public void keyDown(final char keyCode) { // trace("post key down " + keyCode); Event event = new Event(); event.type = SWT.KeyDown; event.character = keyCode; new SWTPushEventOperation(event).execute(); } /** * Dispatch a stream of keyClick events (one per character). * * @param str * - the String of characters to keyClick. */ public void enterText(String str) { if (str == null) return; for (int i = 0; i < str.length(); i++) { keyClick(str.charAt(i)); } } /** * Dispatch a mousePress event. * * @param accelerator * - the mouse accelerator. */ public void mouseDown(int accelerator) { Event event = createClickEvent(accelerator); event.type = SWT.MouseDown; // !pq: // event.stateMask = stateMask; new SWTPushEventOperation(event).execute(); } /** * Dispatch a mouseRelease event. * * @param accelerator * - the mouse accelerator. */ public void mouseUp(int accelerator) { Event event = createClickEvent(accelerator); event.type = SWT.MouseUp; new SWTPushEventOperation(event).execute(); } /** * Dispatch a MouseDoubleClick event. * * @param accelerator * - the mouse accelerator. */ public void mouseDoubleClick(int accelerator) { Event event = createClickEvent(accelerator); event.type = SWT.MouseDoubleClick; // !pq: // event.stateMask = stateMask; new SWTPushEventOperation(event).execute(); } /** * Dispatch a mouseMove event that moves the mouse to this x,y offset from * the top left corner of the given widget. * * @param w * - the widget to whcih to move the mouse * @param x * - the x offset * @param y * - the y offset */ public synchronized void mouseMove(final Widget w, int x, int y) { pointT = null; Robot.syncExec(w.getDisplay(), this, new Runnable() { public void run() { pointT = WidgetLocator.getLocation(w); } }); if (pointT == null) // TODO added for Mac testing return; mouseMove(pointT.x + x, pointT.y + y); } /** * Dispatch a mouseMove event that moves the mouse to this x,y coordinate. * * @param x * - the x coordinate * @param y * - the y coordinate */ public void mouseMove(int x, int y) { Event event = new Event(); event.type = SWT.MouseMove; event.x = x; event.y = y; new SWTPushEventOperation(event).execute(); } //////////////////////////////////////////////////////////////////////////// // // Internal // //////////////////////////////////////////////////////////////////////////// /** * Create a mouse event for the button associated with this accelerator. */ private static final Event createClickEvent(int accelerator) { Event event = new Event(); event.button = MouseConfig.getButton(accelerator); return event; } // get an abbot robot helper private abbot.swt.Robot getAbbotRobot() { if (_robot == null) _robot = new abbot.swt.Robot(); return _robot; } // ///////////////////////////////////////////////////////////////////////// // // Timing // // ///////////////////////////////////////////////////////////////////////// public static void pause(int ms) { try { Thread.sleep(ms); } catch (InterruptedException ie) { } } }