/**************************************************************************** * Copyright 2008-2011 ThoughtWorks, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Initial Contributors: * Håkan Råberg * Manish Chakravarty * Pavan K S ***************************************************************************/ package com.thoughtworks.krypton.driver.web.user.cocoa; import org.eclipse.swt.SWT; import org.eclipse.swt.widgets.Shell; import org.rococoa.Rococoa; import org.rococoa.cocoa.foundation.NSArray; import org.rococoa.cocoa.foundation.NSPoint; import com.thoughtworks.krypton.driver.cocoa.InitializeCocoa; import com.thoughtworks.krypton.driver.cocoa.NSApplication; import com.thoughtworks.krypton.driver.cocoa.NSEvent; import com.thoughtworks.krypton.driver.cocoa.NSWindow; import com.thoughtworks.krypton.driver.web.user.User; import com.thoughtworks.krypton.driver.web.user.KeyTranslator.TransaltedKey; @SuppressWarnings({ "deprecation" }) public class CocoaUser implements User { private static final boolean CARBON = "carbon".equals(SWT.getPlatform()); private static final int LEFT = 1; private static final int RIGHT = 2; private NSWindow window; private CocoaKeyTranslator translator; private int modifiers; private final Shell shell; // Use -NSTraceEvents YES as application arguments to log Cocoa events to // System.err. private static NSWindow findCocoaWindowForShell() { NSApplication application = NSApplication.CLASS.sharedApplication(); NSArray windows = application.windows(); for (int i = 0; i < windows.count(); i++) { NSWindow window = Rococoa.cast(windows.objectAtIndex(i), NSWindow.class); if (window.toString().startsWith("<SWTWindow")) { return (NSWindow) window; } } throw new IllegalStateException("Could not find the SWTWindow"); } public CocoaUser(Shell shell) { this(findCocoaWindowForShell(), shell); } public CocoaUser(final NSWindow window, final Shell shell) { this.window = window; this.shell = shell; translator = new CocoaKeyTranslator(); window.setAutodisplay(false); } public void click(int x, int y) { click(x, y, LEFT, NSEvent.LeftMouseDown, NSEvent.LeftMouseUp); } public void doubleClick(int x, int y) { click(x, y); mouseEvent(NSEvent.LeftMouseDown, x, y, LEFT, 2, 1); mouseEvent(NSEvent.LeftMouseUp, x, y, LEFT, 2, 0); } public void rightClick(int x, int y) { click(x, y, RIGHT, NSEvent.RightMouseDown, NSEvent.RightMouseUp); } public void dragAndDrop(int startX, int startY, int endX, int endY) { int button = LEFT; mouseEvent(NSEvent.MouseMoved, startX, startY, button, 1, 0); mouseEvent(NSEvent.LeftMouseDown, startX, startY, button, 1, 1); // dragEvents(startX, startY, endX, endY, button, 10); mouseEvent(NSEvent.LeftMouseDragged, endX, endY, button, 1, 1); mouseEvent(NSEvent.LeftMouseUp, endX, endY, button, 1, 0); } // private void dragEvents(int startX, int startY, int endX, int endY, int // button, int speed) { // int x = startX; // int y = startY; // // int xDelta = startX < endX ? speed : -speed; // int yDelta = startY < endY ? speed : -speed; // // while (xDelta != 0 || yDelta != 0) { // if (Math.abs(y - endY) < speed) { // yDelta = 0; // } // if (Math.abs(x - endX) < speed) { // xDelta = 0; // } // x += xDelta; // y += yDelta; // mouseEvent(NSEvent.LeftMouseDragged, x, y, button, 1, 1); // } // } public void type(String string) { try { window.disableFlushWindow(); for (int i = 0; i < string.length(); i++) { key(string.charAt(i)); } pumpEvents(); } finally { window.enableFlushWindow(); window.flushWindowIfNeeded(); // window.display(); } } private void pumpEvents() { while (!shell.isDisposed() && shell.getDisplay().readAndDispatch()) ; } public void key(int c) { if (translator.shouldTranslateKey(c)) { TransaltedKey transaltedKey = translator.translate(c); key(transaltedKey.charCode, transaltedKey.keyCode, true); } else { key(isShiftDown() ? Character.toUpperCase(c) : c, 0, true); } } public void key(int c, int modifiers) { boolean shift = (modifiers & SWT.SHIFT) > 0; boolean control = (modifiers & SWT.CONTROL) > 0; boolean alt = (modifiers & SWT.ALT) > 0; boolean command = (modifiers & SWT.COMMAND) > 0; if (shift) { shiftDown(); } if (control) { controlDown(); } if (alt) { altDown(); } if (command) { commandDown(); } key(c); if (command) { commandUp(); } if (alt) { altUp(); } if (control) { controlUp(); } if (shift) { shiftUp(); } } public void shiftDown() { modifiers |= NSEvent.ShiftKeyMask; } public void shiftUp() { modifiers ^= NSEvent.ShiftKeyMask; } public boolean isShiftDown() { return (modifiers & NSEvent.ShiftKeyMask) > 0; } public void commandDown() { modifiers |= NSEvent.CommandKeyMask; } public void commandUp() { modifiers ^= NSEvent.CommandKeyMask; } public void controlDown() { modifiers |= NSEvent.ControlKeyMask; } public void controlUp() { modifiers ^= NSEvent.ControlKeyMask; } public void altDown() { modifiers |= NSEvent.AlternateKeyMask; } public void altUp() { modifiers ^= NSEvent.AlternateKeyMask; } private void key(int c, int keyCode, boolean wasTranslated) { keyEvent(NSEvent.KeyDown, (char) c, (short) keyCode, wasTranslated); keyEvent(NSEvent.KeyUp, (char) c, (short) keyCode, wasTranslated); } private void click(int x, int y, int button, int mouseDownEventType, int mouseUpEventType) { mouseEvent(NSEvent.MouseMoved, x, y, button, 1, 0); mouseEvent(mouseDownEventType, x, y, button, 1, 1); mouseEvent(mouseUpEventType, x, y, button, 1, 0); } private void mouseEvent(int type, final int x, final int y, int button, int clickCount, float pressure) { NSEvent mouseEvent = NSEvent.CLASS.mouseEventWithType_location_modifierFlags_timestamp_windowNumber_context_eventNumber_clickCount_pressure(type, new NSPoint(x, window.contentView().frame().size.height.intValue() - y), NSEvent.MouseEnteredMask, 0.0, window.windowNumber(), NSApplication.CLASS.sharedApplication().context(), 0, clickCount, pressure); ensureWindowCanAcceptEvents(); window.postEvent_atStart(mouseEvent, false); } private void keyEvent(int type, final char c, final short keyCode, boolean wasTranslated) { String string = new String(new char[] { c }); int mask = modifiers; // int mask = NSEvent.MouseEnteredMask | modifiers; // if (c == 0 || wasTranslated) { // mask = mask | NSEvent.OtherMouseDownMask | NSEvent. // OtherMouseDraggedMask; // } NSEvent keyEvent = NSEvent.CLASS.keyEventWithType_location_modifierFlags_timestamp_windowNumber_context_characters_charactersIgnoringModifiers_isARepeat_keyCode( type, new NSPoint(), mask, 0.0, 0, NSApplication.CLASS.sharedApplication() .context(), string, string, false, keyCode); ensureWindowCanAcceptEvents(); window.postEvent_atStart(keyEvent, false); } private void ensureWindowCanAcceptEvents() { if (CARBON) { shell.setFocus(); } if (window != null) { window.becomeKeyWindow(); } } static { InitializeCocoa.init(); } }