From 10670e9b5345da3ab91b6e3a74f7019e3aa50760 Mon Sep 17 00:00:00 2001 From: Naohide Sano Date: Tue, 26 Mar 2024 23:21:27 +0900 Subject: [PATCH 1/2] move robot to vavi-awt-joystic --- .../cocoa/coregraphics/RococaRobot.java | 263 ------------------ .../coregraphics/CoreGraphicsLibraryTest.java | 10 +- 2 files changed, 2 insertions(+), 271 deletions(-) delete mode 100644 rococoa-contrib/src/main/java/org/rococoa/cocoa/coregraphics/RococaRobot.java diff --git a/rococoa-contrib/src/main/java/org/rococoa/cocoa/coregraphics/RococaRobot.java b/rococoa-contrib/src/main/java/org/rococoa/cocoa/coregraphics/RococaRobot.java deleted file mode 100644 index 9bad78d..0000000 --- a/rococoa-contrib/src/main/java/org/rococoa/cocoa/coregraphics/RococaRobot.java +++ /dev/null @@ -1,263 +0,0 @@ -/* - * Copyright (c) 2024 by Naohide Sano, All rights reserved. - * - * Programmed by Naohide Sano - */ - -package org.rococoa.cocoa.coregraphics; - -import java.awt.MouseInfo; -import java.awt.Point; - -import com.sun.jna.Pointer; -import org.rococoa.cocoa.corefoundation.CoreFoundation; - -import static org.rococoa.carbon.CarbonCoreLibrary.kVK_Command; -import static org.rococoa.carbon.CarbonCoreLibrary.kVK_Control; -import static org.rococoa.carbon.CarbonCoreLibrary.kVK_Option; -import static org.rococoa.carbon.CarbonCoreLibrary.kVK_Shift; -import static org.rococoa.cocoa.coregraphics.CoreGraphicsLibrary.kCGEventFlagMaskAlternate; -import static org.rococoa.cocoa.coregraphics.CoreGraphicsLibrary.kCGEventFlagMaskCommand; -import static org.rococoa.cocoa.coregraphics.CoreGraphicsLibrary.kCGEventFlagMaskControl; -import static org.rococoa.cocoa.coregraphics.CoreGraphicsLibrary.kCGEventFlagMaskShift; -import static org.rococoa.cocoa.coregraphics.CoreGraphicsLibrary.kCGEventLeftMouseDown; -import static org.rococoa.cocoa.coregraphics.CoreGraphicsLibrary.kCGEventLeftMouseUp; -import static org.rococoa.cocoa.coregraphics.CoreGraphicsLibrary.kCGEventMouseMoved; -import static org.rococoa.cocoa.coregraphics.CoreGraphicsLibrary.kCGEventRightMouseDown; -import static org.rococoa.cocoa.coregraphics.CoreGraphicsLibrary.kCGEventRightMouseUp; -import static org.rococoa.cocoa.coregraphics.CoreGraphicsLibrary.kCGEventScrollWheel; -import static org.rococoa.cocoa.coregraphics.CoreGraphicsLibrary.kCGEventSourceStateHIDSystemState; -import static org.rococoa.cocoa.coregraphics.CoreGraphicsLibrary.kCGHIDEventTap; -import static org.rococoa.cocoa.coregraphics.CoreGraphicsLibrary.kCGMouseEventDeltaX; -import static org.rococoa.cocoa.coregraphics.CoreGraphicsLibrary.kCGMouseEventDeltaY; -import static org.rococoa.cocoa.coregraphics.CoreGraphicsLibrary.kCGScrollEventUnitPixel; -import static org.rococoa.cocoa.coregraphics.CoreGraphicsLibrary.library; - - -/** - * RococaRobot. like {@link java.awt.Robot}. - * - * @author Naohide Sano (nsano) - * @version 0.00 2024-03-22 nsano initial version
- */ -public class RococaRobot { - - /** HID event source */ - private final Pointer /* CGEventSourceRef */ src = library.CGEventSourceCreate(kCGEventSourceStateHIDSystemState); - - /** Constructs a Robot object. */ - public RococaRobot() { - Runtime.getRuntime().addShutdownHook(new Thread(() -> CoreFoundation.library.CFRelease(src))); - - Point p = MouseInfo.getPointerInfo().getLocation(); - prev = new CGPoint(p.x, p.y); - } - - /** */ - private boolean command; - /** */ - private boolean option; - /** */ - private boolean control; - /** */ - private boolean shift; - - /** - * Presses a given key. The key should be released using the keyRelease method. - * @param code get by karabiner-eventviewer etc. - */ - public void keyPress(int code) { - if (code == kVK_Command) { - command = true; - } else if (code == kVK_Option) { - option = true; - } else if (code == kVK_Control) { - control = true; - } else if (code == kVK_Shift) { - shift = true; - } else { - Pointer /* CGEventRef */ event = library.CGEventCreateKeyboardEvent(src, (char) code, true); - - long flags = 0; - if (command) flags |= kCGEventFlagMaskCommand; - if (option) flags |= kCGEventFlagMaskAlternate; - if (control) flags |= kCGEventFlagMaskControl; - if (shift) flags |= kCGEventFlagMaskShift; - library.CGEventSetFlags(event, flags); - - library.CGEventPost(kCGHIDEventTap, event); - - CoreFoundation.library.CFRelease(event); - } - } - - /** - * Presses a given key. The key should be released using the keyRelease method. - * @param code get by karabiner-eventviewer etc. - */ - public void keyPress2(int code) { - Pointer /* CGEventRef */ event = library.CGEventCreateKeyboardEvent(src, (char) code, true); - - library.CGEventPost(kCGHIDEventTap, event); - - CoreFoundation.library.CFRelease(event); - } - - /** - * Releases a given key. - * @param code get by karabiner-eventviewer etc. - */ - public void keyRelease(int code) { - if (code == kVK_Command) { - command = false; - } else if (code == kVK_Option) { - option = false; - } else if (code == kVK_Control) { - control = false; - } else if (code == kVK_Shift) { - command = false; - } else { - Pointer /* CGEventRef */ event = library.CGEventCreateKeyboardEvent(src, (char) code, false); - - long flags = 0; - if (command) flags |= kCGEventFlagMaskCommand; - if (option) flags |= kCGEventFlagMaskAlternate; - if (control) flags |= kCGEventFlagMaskControl; - if (shift) flags |= kCGEventFlagMaskShift; - library.CGEventSetFlags(event, flags); - - library.CGEventPost(kCGHIDEventTap, event); - - CoreFoundation.library.CFRelease(event); - } - } - - /** - * Releases a given key. - * @param code get by karabiner-eventviewer etc. - */ - public void keyRelease2(int code) { - Pointer /* CGEventRef */ event = library.CGEventCreateKeyboardEvent(src, (char) code, false); - - library.CGEventPost(kCGHIDEventTap, event); - - CoreFoundation.library.CFRelease(event); - } - - /** the previous pointer */ - private CGPoint prev; - - /** Moves mouse pointer to given screen coordinates with moving motion. */ - public void mouseMove(int x, int y) { - int dx = x - prev.x.intValue(); - int dy = y - prev.y.intValue(); - prev = new CGPoint(x, y); - Pointer /* CGEventRef */ event = library.CGEventCreateMouseEvent( - null, kCGEventMouseMoved, - prev, - 0 // ignored - ); - // Now, execute these events with an interval to make them noticeable - library.CGEventSetIntegerValueField(event, kCGMouseEventDeltaX, dx); - library.CGEventSetIntegerValueField(event, kCGMouseEventDeltaY, dy); - library.CGEventPost(kCGHIDEventTap, event); - CoreFoundation.library.CFRelease(event); - } - - /** Moves mouse pointer to given screen coordinates w/o moving motion means like teleportation. */ - public void mouseMove0(int x, int y) { - prev = new CGPoint(x, y); - Pointer /* CGEventRef */ event = library.CGEventCreateMouseEvent( - null, kCGEventMouseMoved, - prev, - 0 // ignored - ); - // Now, execute these events with an interval to make them noticeable - library.CGEventPost(kCGHIDEventTap, event); - CoreFoundation.library.CFRelease(event); - } - - /** Moves mouse pointer to given deltas. */ - public void mouseMove2(int dx, int dy) { - Pointer /* CGEventRef */ event = library.CGEventCreateMouseEvent( - null, kCGEventMouseMoved, - prev, - 0 // ignored - ); - // Now, execute these events with an interval to make them noticeable - library.CGEventSetIntegerValueField(event, kCGMouseEventDeltaX, dx); - library.CGEventSetIntegerValueField(event, kCGMouseEventDeltaY, dy); - library.CGEventPost(kCGHIDEventTap, event); - CoreFoundation.library.CFRelease(event); - } - - /** - * Presses one or more mouse buttons. The mouse buttons should be released using the mouseRelease(int) method. - * @param buttons kCGMouseButtonLeft, kCGMouseButtonRight - */ - public void mousePress(int buttons) { - int[] events = {kCGEventLeftMouseDown, kCGEventRightMouseDown}; - Pointer /* CGEventRef */ event = library.CGEventCreateMouseEvent( - null, events[buttons], - prev, - buttons - ); - library.CGEventPost(kCGHIDEventTap, event); - CoreFoundation.library.CFRelease(event); - } - - /** - * Presses one or more mouse buttons. The mouse buttons should be released using the mouseRelease(int) method. - * @param buttons kCGMouseButtonLeft, kCGMouseButtonRight - */ - public void mousePress2(int buttons, int x, int y) { - prev = new CGPoint(x, y); - int[] events = {kCGEventLeftMouseDown, kCGEventRightMouseDown}; - Pointer /* CGEventRef */ event = library.CGEventCreateMouseEvent( - null, events[buttons], - prev, - buttons - ); - library.CGEventPost(kCGHIDEventTap, event); - CoreFoundation.library.CFRelease(event); - } - - /** - * Releases one or more mouse buttons using previous point. - * @param buttons kCGMouseButtonLeft, kCGMouseButtonRight - */ - public void mouseRelease(int buttons) { - int[] events = {kCGEventLeftMouseUp, kCGEventRightMouseUp}; - Pointer /* CGEventRef */ event = library.CGEventCreateMouseEvent( - null, events[buttons], - prev, - buttons - ); - library.CGEventPost(kCGHIDEventTap, event); - CoreFoundation.library.CFRelease(event); - } - /** - * Releases one or more mouse buttons. - * @param buttons kCGMouseButtonLeft, kCGMouseButtonRight - */ - public void mouseRelease2(int buttons, int x, int y) { - prev = new CGPoint(x, y); - int[] events = {kCGEventLeftMouseUp, kCGEventRightMouseUp}; - Pointer /* CGEventRef */ event = library.CGEventCreateMouseEvent( - null, events[buttons], - prev, - buttons - ); - library.CGEventPost(kCGHIDEventTap, event); - CoreFoundation.library.CFRelease(event); - } - - /** Rotates the scroll wheel on wheel-equipped mice. */ - public void mouseWheel(int wheelAmt) { - Pointer /* CGEventRef */ event = library.CGEventCreateScrollWheelEvent2( - null, kCGScrollEventUnitPixel, 1, wheelAmt, 0, 0); - library.CGEventSetType(event, kCGEventScrollWheel); - library.CGEventPost(kCGHIDEventTap, event); - CoreFoundation.library.CFRelease(event); - } -} diff --git a/rococoa-contrib/src/test/java/org/rococoa/cocoa/coregraphics/CoreGraphicsLibraryTest.java b/rococoa-contrib/src/test/java/org/rococoa/cocoa/coregraphics/CoreGraphicsLibraryTest.java index 78898cb..2febb1e 100644 --- a/rococoa-contrib/src/test/java/org/rococoa/cocoa/coregraphics/CoreGraphicsLibraryTest.java +++ b/rococoa-contrib/src/test/java/org/rococoa/cocoa/coregraphics/CoreGraphicsLibraryTest.java @@ -19,7 +19,6 @@ import com.sun.tools.attach.VirtualMachineDescriptor; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.condition.DisabledIfSystemProperty; import org.junit.jupiter.api.condition.EnabledIfSystemProperty; import org.rococoa.Foundation; import org.rococoa.ObjCObject; @@ -29,13 +28,10 @@ import org.rococoa.cocoa.appkit.NSWorkspace; import org.rococoa.cocoa.corefoundation.CoreFoundation; import org.rococoa.cocoa.coreimage.CIImage; -import org.rococoa.cocoa.foundation.NSBundle; import org.rococoa.cocoa.foundation.NSDictionary; import org.rococoa.cocoa.foundation.NSNotification; import org.rococoa.cocoa.foundation.NSNotificationCenter; -import org.rococoa.cocoa.foundation.NSObject; import org.rococoa.cocoa.foundation.NSString; -import org.rococoa.cocoa.gamecontroller.GCController; import vavi.util.Debug; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -171,8 +167,6 @@ void test62() throws Exception { if (!a.active()) { a.activateWithOptions(0); } - RococaRobot ide = new RococaRobot(); -// ide.keyClick(kVK_ANSI_); } catch (NoSuchElementException e) { Debug.println(Level.WARNING, "run minecraft before running this test"); } @@ -207,7 +201,7 @@ void test8() throws Exception { CountDownLatch cdl = new CountDownLatch(1); - class MyObserver implements Callback { + static class MyObserver implements Callback { public void applicationWasActivated(NSNotification notification) { NSWorkspace workspace = Rococoa.cast(notification.object(), NSWorkspace.class); @@ -225,7 +219,7 @@ public void applicationWasDeactivated(NSNotification notification) { @Test @EnabledIfSystemProperty(named = "vavi.test", matches = "ide") void test9() throws Exception { - ObjCObject proxy = Rococoa.proxy(new CoreGraphicsLibraryTest.MyObserver()); + ObjCObject proxy = Rococoa.proxy(new MyObserver()); Selector sel1 = Foundation.selector("applicationWasActivated:"); Selector sel2 = Foundation.selector("applicationWasDeactivated:"); From d9add8625335ba79683f1047b8f2a528fef70a08 Mon Sep 17 00:00:00 2001 From: Naohide Sano Date: Tue, 26 Mar 2024 23:22:48 +0900 Subject: [PATCH 2/2] try to catch exception when invoking a method in ObjCClass --- README.md | 2 + .../org/rococoa/cocoa/foundation/NSArray.java | 2 +- .../internal/ObjCObjectInvocationHandler.java | 8 ++- rococoa-core/src/test/java/Test1.java | 19 +------ rococoa-core/src/test/java/TestCase.java | 51 +++++++++++++++++++ 5 files changed, 62 insertions(+), 20 deletions(-) create mode 100644 rococoa-core/src/test/java/TestCase.java diff --git a/README.md b/README.md index 86b0bd2..e9b168d 100644 --- a/README.md +++ b/README.md @@ -96,6 +96,8 @@ implementation of Objective-C interfaces in Java. * separate same parts of jna-platform (like jna-platform-extended) * deprecate rococoa-contrib * ~~selector and java method binding for notification~~ +* exception in callback method cannot be shown as reason, shown as "Exception calling method for selector foo:" + * `OCInvocationCallbacks.java:170` ---- diff --git a/rococoa-core/src/main/java/org/rococoa/cocoa/foundation/NSArray.java b/rococoa-core/src/main/java/org/rococoa/cocoa/foundation/NSArray.java index 34a22c9..31951cd 100755 --- a/rococoa-core/src/main/java/org/rococoa/cocoa/foundation/NSArray.java +++ b/rococoa-core/src/main/java/org/rococoa/cocoa/foundation/NSArray.java @@ -69,7 +69,7 @@ static NSMutableArray toArray(NSObject...objects) { @SuppressWarnings("unchecked") public List toList() { List result = new ArrayList<>(); - for (int i = 0; i ) result; diff --git a/rococoa-core/src/main/java/org/rococoa/internal/ObjCObjectInvocationHandler.java b/rococoa-core/src/main/java/org/rococoa/internal/ObjCObjectInvocationHandler.java index bdf0475..50ff0bf 100644 --- a/rococoa-core/src/main/java/org/rococoa/internal/ObjCObjectInvocationHandler.java +++ b/rococoa-core/src/main/java/org/rococoa/internal/ObjCObjectInvocationHandler.java @@ -28,6 +28,7 @@ import java.util.ConcurrentModificationException; import java.util.List; import java.util.concurrent.Callable; +import java.util.logging.Level; import java.util.logging.Logger; import com.sun.jna.Pointer; @@ -170,7 +171,12 @@ public Object intercept(@This Object proxy, @Origin Method method, @AllArguments if (!Modifier.isAbstract(method.getModifiers())) { // method is not abstract, so a Java override has been provided, which we call logging.finest(String.format("superMethod.invoke [%s %s].%s(%s)", javaClassName, ocInstance, method.getName(), new VarArgsUnpacker(args))); - return superMethod.invoke(proxy, args); + try { + return superMethod.invoke(proxy, args); + } catch (Throwable t) { +logging.log(Level.WARNING, String.format("superMethod.invoke [%s %s].%s(%s) failure", javaClassName, ocInstance, method.getName(), new VarArgsUnpacker(args)), t); + throw t; + } } // normal case return invokeCocoa(method, args); diff --git a/rococoa-core/src/test/java/Test1.java b/rococoa-core/src/test/java/Test1.java index f58c4e1..82f6353 100644 --- a/rococoa-core/src/test/java/Test1.java +++ b/rococoa-core/src/test/java/Test1.java @@ -10,7 +10,6 @@ import java.util.concurrent.Executors; import java.util.concurrent.atomic.AtomicReference; -import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.condition.DisabledIfEnvironmentVariable; import org.rococoa.cocoa.foundation.NSString; @@ -20,29 +19,13 @@ /** - * Test1. + * Integration Test. * * @author Naohide Sano (nsano) * @version 0.00 2023-06-30 nsano initial version
*/ public class Test1 { - @Test - @Disabled - void test1() throws Exception { -// MethodHandle methodHandleFieldDirect = lookup.unreflectGetter(fieldName); -// CallSite callSiteField = new ConstantCallSite(methodHandleFieldDirect); -// methodHandleFieldDirect = callSiteField.dynamicInvoker(); -// name = (String) methodHandleFieldDirect.invokeExact(new Employee()); -// -// -////Lookup invoke dynamic -// methodType = MethodType.methodType(String.class); -// methodHandle = lookup.findVirtual(Employee.class, "getName", methodType); -// CallSite callSiteMethod = new ConstantCallSite(methodHandleFieldDirect); -// methodHandle = callSiteMethod.dynamicInvoker(); - } - @Test @DisabledIfEnvironmentVariable(named = "GITHUB_WORKFLOW", matches = ".*") void test2() throws Exception { diff --git a/rococoa-core/src/test/java/TestCase.java b/rococoa-core/src/test/java/TestCase.java new file mode 100644 index 0000000..986ef78 --- /dev/null +++ b/rococoa-core/src/test/java/TestCase.java @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2024 by Naohide Sano, All rights reserved. + * + * Programmed by Naohide Sano + */ + +import java.util.List; + +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; +import org.rococoa.cocoa.foundation.NSArray; + +import static org.junit.jupiter.api.Assertions.assertThrows; + + +/** + * TestCase. + * + * @author Naohide Sano (nsano) + * @version 0.00 2024-03-26 nsano initial version
+ */ +public class TestCase { + + @Test + @Disabled + void test1() throws Exception { +// MethodHandle methodHandleFieldDirect = lookup.unreflectGetter(fieldName); +// CallSite callSiteField = new ConstantCallSite(methodHandleFieldDirect); +// methodHandleFieldDirect = callSiteField.dynamicInvoker(); +// name = (String) methodHandleFieldDirect.invokeExact(new Employee()); +// +// +////Lookup invoke dynamic +// methodType = MethodType.methodType(String.class); +// methodHandle = lookup.findVirtual(Employee.class, "getName", methodType); +// CallSite callSiteMethod = new ConstantCallSite(methodHandleFieldDirect); +// methodHandle = callSiteMethod.dynamicInvoker(); + } + + NSArray array() { + return null; + } + + @Test + void test2() throws Exception { + NSArray array = array(); + assertThrows(NullPointerException.class, () -> { + List list = array.toList(); + }); + } +}