From 4e1441cbf815745e89e091527ea175bc657460c8 Mon Sep 17 00:00:00 2001 From: Naohide Sano Date: Mon, 25 Mar 2024 00:01:11 +0900 Subject: [PATCH 1/5] [core] add bridge casting method for NSDictionary and NSArray --- .../src/main/java/org/rococoa/Rococoa.java | 15 +++++++++++++++ .../java/org/rococoa/internal/RococoaLibrary.java | 10 ++++++++++ rococoa-core/src/main/native/Rococoa.h | 4 ++++ rococoa-core/src/main/native/Rococoa.m | 10 ++++++++++ 4 files changed, 39 insertions(+) diff --git a/rococoa-core/src/main/java/org/rococoa/Rococoa.java b/rococoa-core/src/main/java/org/rococoa/Rococoa.java index 28ad2d0..a0c1915 100644 --- a/rococoa-core/src/main/java/org/rococoa/Rococoa.java +++ b/rococoa-core/src/main/java/org/rococoa/Rococoa.java @@ -24,10 +24,13 @@ import java.util.logging.Level; import java.util.logging.Logger; +import com.sun.jna.Pointer; import net.bytebuddy.ByteBuddy; import net.bytebuddy.implementation.MethodDelegation; import net.bytebuddy.matcher.ElementMatchers; import org.rococoa.cocoa.CFIndex; +import org.rococoa.cocoa.foundation.NSArray; +import org.rococoa.cocoa.foundation.NSDictionary; import org.rococoa.internal.OCInvocationCallbacks; import org.rococoa.internal.ObjCObjectInvocationHandler; import org.rococoa.internal.VarArgsUnpacker; @@ -208,6 +211,18 @@ private static void checkRetainCount(ID ocInstance, int expected) { } } + /** __bridge */ + public static NSArray toNSArray(Pointer p) { + ID id = Foundation.getRococoaLibrary().bridgeArray(p); + return wrap(id, NSArray.class); + } + + /** __bridge */ + public static NSDictionary toNSDictionary(Pointer p) { + ID id = Foundation.getRococoaLibrary().bridgeDictionary(p); + return wrap(id, NSDictionary.class); + } + /** * Enforce static factory-ness. */ diff --git a/rococoa-core/src/main/java/org/rococoa/internal/RococoaLibrary.java b/rococoa-core/src/main/java/org/rococoa/internal/RococoaLibrary.java index ae5a6a1..109ea93 100644 --- a/rococoa-core/src/main/java/org/rococoa/internal/RococoaLibrary.java +++ b/rococoa-core/src/main/java/org/rococoa/internal/RococoaLibrary.java @@ -72,4 +72,14 @@ interface VoidCallback extends Callback { void releaseObjCBlock(Pointer blockPtr); //#endregion Block + +//#region bridge + + /** */ + ID bridgeArray(Pointer dic); + + /** */ + ID bridgeDictionary(Pointer dic); + +//#endregion bridge } \ No newline at end of file diff --git a/rococoa-core/src/main/native/Rococoa.h b/rococoa-core/src/main/native/Rococoa.h index d0715db..c191ed9 100644 --- a/rococoa-core/src/main/native/Rococoa.h +++ b/rococoa-core/src/main/native/Rococoa.h @@ -1,8 +1,12 @@ #import +#import #include void callOnMainThread(void (*fn)(void), BOOL waitUntilDone); +id bridgeArray(CFArrayRef* array); +id bridgeDictionary(CFDictionaryRef* dic); + @interface RococoaHelper : NSObject + (void) callback: (NSValue*) fn; @end diff --git a/rococoa-core/src/main/native/Rococoa.m b/rococoa-core/src/main/native/Rococoa.m index 98a7be9..b7c7279 100644 --- a/rococoa-core/src/main/native/Rococoa.m +++ b/rococoa-core/src/main/native/Rococoa.m @@ -11,6 +11,16 @@ void callOnMainThread(void (*fn)(void), BOOL waitUntilDone) { [pool release]; } +id bridgeArray(CFArrayRef* cfarray) { + NSArray* nsarray = (__bridge NSArray*) cfarray; + return (id) nsarray; +} + +id bridgeDictionary(CFDictionaryRef* cfdic) { + NSDictionary* nsdic = (__bridge NSDictionary*) cfdic; + return (id) nsdic; +} + @implementation RococoaHelper : NSObject + (void) callback: (NSValue*) fnAsValue { From d68c91d3231d2350f717104f3975eedbb082fa37 Mon Sep 17 00:00:00 2001 From: Naohide Sano Date: Mon, 25 Mar 2024 00:05:25 +0900 Subject: [PATCH 2/5] [coregraphics] make about CGKeyCode work --- .../org/rococoa/carbon/CarbonCoreLibrary.java | 382 ++++++++++++------ .../rococoa/carbon/CarbonCoreLibraryTest.java | 12 +- .../coregraphics/CoreGraphicsLibrary.java | 37 +- 3 files changed, 281 insertions(+), 150 deletions(-) diff --git a/rococoa-cocoa/src/main/java/org/rococoa/carbon/CarbonCoreLibrary.java b/rococoa-cocoa/src/main/java/org/rococoa/carbon/CarbonCoreLibrary.java index 9a321cb..1280183 100644 --- a/rococoa-cocoa/src/main/java/org/rococoa/carbon/CarbonCoreLibrary.java +++ b/rococoa-cocoa/src/main/java/org/rococoa/carbon/CarbonCoreLibrary.java @@ -7,8 +7,8 @@ package org.rococoa.carbon; import java.awt.event.KeyEvent; -import java.util.HashMap; -import java.util.Map; +import java.util.ArrayList; +import java.util.List; import com.sun.jna.Library; import com.sun.jna.Native; @@ -52,6 +52,8 @@ public interface CarbonCoreLibrary extends Library { CFStringRef kTISPropertyUnicodeKeyLayoutData = new CFStringRef(new PointerByReference(NATIVE_LIBRARY.getGlobalVariableAddress("kTISPropertyUnicodeKeyLayoutData")).getValue().getPointer(0)); + Pointer /* TISInputSourceRef */ TISCopyCurrentKeyboardLayoutInputSource(); + Pointer /* TISInputSourceRef */ TISCopyCurrentKeyboardInputSource(); Pointer TISGetInputSourceProperty(Pointer /* TISInputSourceRef */ source, CFStringRef key); @@ -60,8 +62,140 @@ public interface CarbonCoreLibrary extends Library { //#region HIToolbox + /* +key: 0, 0x0, string: a, 0x61 +key: 1, 0x1, string: s, 0x73 +key: 2, 0x2, string: d, 0x64 +key: 3, 0x3, string: f, 0x66 +key: 4, 0x4, string: h, 0x68 +key: 5, 0x5, string: g, 0x67 +key: 6, 0x6, string: z, 0x7a +key: 7, 0x7, string: x, 0x78 +key: 8, 0x8, string: c, 0x63 +key: 9, 0x9, string: v, 0x76 +key: 10, 0xa, string: §, 0xa7 +key: 11, 0xb, string: b, 0x62 +key: 12, 0xc, string: q, 0x71 +key: 13, 0xd, string: w, 0x77 +key: 14, 0xe, string: e, 0x65 +key: 15, 0xf, string: r, 0x72 +key: 16, 0x10, string: y, 0x79 +key: 17, 0x11, string: t, 0x74 +key: 18, 0x12, string: 1, 0x31 +key: 19, 0x13, string: 2, 0x32 +key: 20, 0x14, string: 3, 0x33 +key: 21, 0x15, string: 4, 0x34 +key: 22, 0x16, string: 6, 0x36 +key: 23, 0x17, string: 5, 0x35 +key: 24, 0x18, string: ^, 0x5e +key: 25, 0x19, string: 9, 0x39 +key: 26, 0x1a, string: 7, 0x37 +key: 27, 0x1b, string: -, 0x2d +key: 28, 0x1c, string: 8, 0x38 +key: 29, 0x1d, string: 0, 0x30 +key: 30, 0x1e, string: [, 0x5b +key: 31, 0x1f, string: o, 0x6f +key: 32, 0x20, string: u, 0x75 +key: 33, 0x21, string: @, 0x40 +key: 34, 0x22, string: i, 0x69 +key: 35, 0x23, string: p, 0x70 +key: 36, 0x23, string: ???, 0xd +key: 37, 0x25, string: l, 0x6c +key: 38, 0x26, string: j, 0x6a +key: 39, 0x27, string: :, 0x3a +key: 40, 0x28, string: k, 0x6b +key: 41, 0x29, string: ;, 0x3b +key: 42, 0x2a, string: ], 0x5d +key: 43, 0x2b, string: ,, 0x2c +key: 44, 0x2c, string: /, 0x2f +key: 45, 0x2d, string: n, 0x6e +key: 46, 0x2e, string: m, 0x6d +key: 47, 0x2f, string: ., 0x2e +key: 48, 0x30, string: , 0x9 +key: 49, 0x31, string: , 0x20 +key: 50, 0x32, string: `, 0x60 +key: 51, 0x33, string:, 0x8 +key: 52, 0x34, string: , 0x3 +key: 53, 0x35, string: , 0x1b +key: 54, 0x36, string: null +key: 55, 0x37, string: null +key: 56, 0x38, string: null +key: 57, 0x39, string: null +key: 58, 0x3a, string: null +key: 59, 0x3b, string: null +key: 60, 0x3c, string: null +key: 61, 0x3d, string: null +key: 62, 0x3e, string: null +key: 63, 0x3f, string: null +key: 64, 0x40, string: null +key: 65, 0x41, string: ., 0x2e +key: 66, 0x42, string: , 0x1d +key: 67, 0x43, string: *, 0x2a +key: 68, 0x44, string: null +key: 69, 0x45, string: +, 0x2b +key: 70, 0x46, string: , 0x1c +key: 71, 0x47, string: , 0x1b +key: 72, 0x48, string: , 0x1f +key: 73, 0x49, string: null +key: 74, 0x4a, string: null +key: 75, 0x4b, string: /, 0x2f +key: 76, 0x4c, string: , 0x3 +key: 77, 0x4d, string: , 0x1e +key: 78, 0x4e, string: -, 0x2d +key: 79, 0x4f, string: null +key: 80, 0x50, string: null +key: 81, 0x51, string: =, 0x3d +key: 82, 0x52, string: 0, 0x30 +key: 83, 0x53, string: 1, 0x31 +key: 84, 0x54, string: 2, 0x32 +key: 85, 0x55, string: 3, 0x33 +key: 86, 0x56, string: 4, 0x34 +key: 87, 0x57, string: 5, 0x35 +key: 88, 0x58, string: 6, 0x36 +key: 89, 0x59, string: 7, 0x37 +key: 90, 0x5a, string: null +key: 91, 0x5b, string: 8, 0x38 +key: 92, 0x5c, string: 9, 0x39 +key: 93, 0x5d, string: ¥, 0xa5 +key: 94, 0x5e, string: _, 0x5f +key: 95, 0x5f, string: ,, 0x2c +key: 96, 0x60, string: , 0x10 +key: 97, 0x61, string: , 0x10 +key: 98, 0x62, string: , 0x10 +key: 99, 0x63, string: , 0x10 +key: 100, 0x64, string: , 0x10 +key: 101, 0x65, string: , 0x10 +key: 102, 0x66, string: , 0x20 +key: 103, 0x67, string: , 0x10 +key: 104, 0x68, string: , 0x20 +key: 105, 0x69, string: , 0x10 +key: 106, 0x6a, string: , 0x10 +key: 107, 0x6b, string: , 0x10 +key: 108, 0x6c, string: , 0x10 +key: 109, 0x6d, string: , 0x10 +key: 110, 0x6e, string: , 0x10 +key: 111, 0x6f, string: , 0x10 +key: 112, 0x70, string: , 0x10 +key: 113, 0x71, string: , 0x10 +key: 114, 0x72, string: , 0x5 +key: 115, 0x73, string: , 0x1 +key: 116, 0x74, string: , 0xb +key: 117, 0x75, string: , 0x7f +key: 118, 0x76, string: , 0x10 +key: 119, 0x77, string: , 0x4 +key: 120, 0x78, string: , 0x10 +key: 121, 0x79, string: , 0xc +key: 122, 0x7a, string: , 0x10 +key: 123, 0x7b, string: , 0x1c +key: 124, 0x7c, string: , 0x1d +key: 125, 0x7d, string: , 0x1f +key: 126, 0x7e, string: , 0x1e +key: 127, 0x7f, string: null + */ + // TODO on mac studio m2, some key name is not matched // karabiner-elements event viewer also + // https://qiita.com/nak435/items/37cf3352b4d77585c38e int kVK_ANSI_A = 0x00; int kVK_ANSI_S = 0x01; @@ -192,127 +326,129 @@ public interface CarbonCoreLibrary extends Library { int kVK_JIS_Eisu = 0x66; int kVK_JIS_Kana = 0x68; - /** java to native conversion */ - Map javaNativeMap = new HashMap<>() {{ - put(KeyEvent.VK_A, kVK_ANSI_A); - put(KeyEvent.VK_S, kVK_ANSI_S); - put(KeyEvent.VK_D, kVK_ANSI_D); - put(KeyEvent.VK_F, kVK_ANSI_F); - put(KeyEvent.VK_H, kVK_ANSI_H); - put(KeyEvent.VK_G, kVK_ANSI_G); - put(KeyEvent.VK_Z, kVK_ANSI_Z); - put(KeyEvent.VK_X, kVK_ANSI_X); - put(KeyEvent.VK_C, kVK_ANSI_C); - put(KeyEvent.VK_V, kVK_ANSI_V); - put(KeyEvent.VK_B, kVK_ANSI_B); - put(KeyEvent.VK_Q, kVK_ANSI_Q); - put(KeyEvent.VK_W, kVK_ANSI_W); - put(KeyEvent.VK_E, kVK_ANSI_E); - put(KeyEvent.VK_R, kVK_ANSI_R); - put(KeyEvent.VK_Y, kVK_ANSI_Y); - put(KeyEvent.VK_T, kVK_ANSI_T); - put(KeyEvent.VK_1, kVK_ANSI_1); - put(KeyEvent.VK_2, kVK_ANSI_2); - put(KeyEvent.VK_3, kVK_ANSI_3); - put(KeyEvent.VK_4, kVK_ANSI_4); - put(KeyEvent.VK_6, kVK_ANSI_6); - put(KeyEvent.VK_5, kVK_ANSI_5); - put(KeyEvent.VK_EQUALS, kVK_ANSI_Equal); - put(KeyEvent.VK_9, kVK_ANSI_9); - put(KeyEvent.VK_7, kVK_ANSI_7); - put(KeyEvent.VK_MINUS, kVK_ANSI_Minus); - put(KeyEvent.VK_8, kVK_ANSI_8); - put(KeyEvent.VK_0, kVK_ANSI_0); - put(KeyEvent.VK_RIGHT_PARENTHESIS, kVK_ANSI_RightBracket); - put(KeyEvent.VK_O, kVK_ANSI_O); - put(KeyEvent.VK_U, kVK_ANSI_U); - put(KeyEvent.VK_LEFT_PARENTHESIS, kVK_ANSI_LeftBracket); - put(KeyEvent.VK_I, kVK_ANSI_I); - put(KeyEvent.VK_P, kVK_ANSI_P); - put(KeyEvent.VK_L, kVK_ANSI_L); - put(KeyEvent.VK_J, kVK_ANSI_J); - put(KeyEvent.VK_QUOTE, kVK_ANSI_Quote); - put(KeyEvent.VK_K, kVK_ANSI_K); - put(KeyEvent.VK_SEMICOLON, kVK_ANSI_Semicolon); - put(KeyEvent.VK_BACK_SLASH, kVK_ANSI_Backslash); - put(KeyEvent.VK_COMMA, kVK_ANSI_Comma); - put(KeyEvent.VK_SLASH, kVK_ANSI_Slash); - put(KeyEvent.VK_N, kVK_ANSI_N); - put(KeyEvent.VK_M, kVK_ANSI_M); - put(KeyEvent.VK_PERIOD, kVK_ANSI_Period); - put(KeyEvent.VK_DEAD_GRAVE, kVK_ANSI_Grave); - put(KeyEvent.VK_DECIMAL, kVK_ANSI_KeypadDecimal); - put(KeyEvent.VK_MULTIPLY, kVK_ANSI_KeypadMultiply); - put(KeyEvent.VK_PLUS, kVK_ANSI_KeypadPlus); - put(KeyEvent.VK_CLEAR, kVK_ANSI_KeypadClear); - put(KeyEvent.VK_DIVIDE, kVK_ANSI_KeypadDivide); -// put(KeyEvent.VK_ENTER, kVK_ANSI_KeypadEnter); -// put(KeyEvent.VK_MINUS, kVK_ANSI_KeypadMinus); -// put(KeyEvent.VK_EQUALS, kVK_ANSI_KeypadEquals); - put(KeyEvent.VK_NUMPAD0, kVK_ANSI_Keypad0); - put(KeyEvent.VK_NUMPAD1, kVK_ANSI_Keypad1); - put(KeyEvent.VK_NUMPAD2, kVK_ANSI_Keypad2); - put(KeyEvent.VK_NUMPAD3, kVK_ANSI_Keypad3); - put(KeyEvent.VK_NUMPAD4, kVK_ANSI_Keypad4); - put(KeyEvent.VK_NUMPAD5, kVK_ANSI_Keypad5); - put(KeyEvent.VK_NUMPAD6, kVK_ANSI_Keypad6); - put(KeyEvent.VK_NUMPAD7, kVK_ANSI_Keypad7); - put(KeyEvent.VK_NUMPAD8, kVK_ANSI_Keypad8); - put(KeyEvent.VK_NUMPAD9, kVK_ANSI_Keypad9); - put(KeyEvent.VK_ENTER, kVK_Return); - put(KeyEvent.VK_TAB, kVK_Tab); - put(KeyEvent.VK_SPACE, kVK_Space); - put(KeyEvent.VK_DELETE, kVK_Delete); - put(KeyEvent.VK_ESCAPE, kVK_Escape); - put(KeyEvent.VK_META, kVK_Command); - put(KeyEvent.VK_SHIFT, kVK_Shift); - put(KeyEvent.VK_CAPS_LOCK, kVK_CapsLock); - put(KeyEvent.VK_ALT, kVK_Option); - put(KeyEvent.VK_CONTROL, kVK_Control); -// put(KeyEvent.VK_META, kVK_RightCommand); -// put(KeyEvent.VK_SHIFT, kVK_RightShift); -// put(KeyEvent.VK_ALT, kVK_RightOption); -// put(KeyEvent.VK_CONTROL, kVK_RightControl); -// put(KeyEvent.VK_???, kVK_Function); - put(KeyEvent.VK_F17, kVK_F17); -// put(KeyEvent.VK_???, kVK_VolumeUp); -// put(KeyEvent.VK_???, kVK_VolumeDown); -// put(KeyEvent.VK_???, kVK_Mute); - put(KeyEvent.VK_F18, kVK_F18); - put(KeyEvent.VK_F19, kVK_F19); - put(KeyEvent.VK_F20, kVK_F20); - put(KeyEvent.VK_F5, kVK_F5); - put(KeyEvent.VK_F6, kVK_F6); - put(KeyEvent.VK_F7, kVK_F7); - put(KeyEvent.VK_F3, kVK_F3); - put(KeyEvent.VK_F8, kVK_F8); - put(KeyEvent.VK_F9, kVK_F9); - put(KeyEvent.VK_F11, kVK_F11); - put(KeyEvent.VK_F13, kVK_F13); - put(KeyEvent.VK_F16, kVK_F16); - put(KeyEvent.VK_F14, kVK_F14); - put(KeyEvent.VK_F10, kVK_F10); - put(KeyEvent.VK_F12, kVK_F12); - put(KeyEvent.VK_F15, kVK_F15); - put(KeyEvent.VK_HELP, kVK_Help); - put(KeyEvent.VK_HOME, kVK_Home); - put(KeyEvent.VK_PAGE_UP, kVK_PageUp); -// put(KeyEvent.VK_DELETE, kVK_ForwardDelete); - put(KeyEvent.VK_F4, kVK_F4); - put(KeyEvent.VK_END, kVK_End); - put(KeyEvent.VK_F2, kVK_F2); - put(KeyEvent.VK_PAGE_DOWN, kVK_PageDown); - put(KeyEvent.VK_F1, kVK_F1); - put(KeyEvent.VK_LEFT, kVK_LeftArrow); - put(KeyEvent.VK_RIGHT, kVK_RightArrow); - put(KeyEvent.VK_DOWN, kVK_DownArrow); - put(KeyEvent.VK_UP, kVK_UpArrow); -// put(KeyEvent.VK_???, kVK_ISO_Section); -// put(KeyEvent.VK_BACK_SLASH, kVK_JIS_Yen); - put(KeyEvent.VK_UNDERSCORE, kVK_JIS_Underscore); -// put(KeyEvent.VK_COMMA, kVK_JIS_KeypadComma); - put(KeyEvent.VK_ALPHANUMERIC, kVK_JIS_Eisu); - put(KeyEvent.VK_HIRAGANA, kVK_JIS_Kana); + record JavaNativePair(int java, int carbon) {} + + /** TODO java to native conversion */ + List javaNativeMap = new ArrayList<>() {{ + add(new JavaNativePair(KeyEvent.VK_A, kVK_ANSI_A)); + add(new JavaNativePair(KeyEvent.VK_S, kVK_ANSI_S)); + add(new JavaNativePair(KeyEvent.VK_D, kVK_ANSI_D)); + add(new JavaNativePair(KeyEvent.VK_F, kVK_ANSI_F)); + add(new JavaNativePair(KeyEvent.VK_H, kVK_ANSI_H)); + add(new JavaNativePair(KeyEvent.VK_G, kVK_ANSI_G)); + add(new JavaNativePair(KeyEvent.VK_Z, kVK_ANSI_Z)); + add(new JavaNativePair(KeyEvent.VK_X, kVK_ANSI_X)); + add(new JavaNativePair(KeyEvent.VK_C, kVK_ANSI_C)); + add(new JavaNativePair(KeyEvent.VK_V, kVK_ANSI_V)); + add(new JavaNativePair(KeyEvent.VK_B, kVK_ANSI_B)); + add(new JavaNativePair(KeyEvent.VK_Q, kVK_ANSI_Q)); + add(new JavaNativePair(KeyEvent.VK_W, kVK_ANSI_W)); + add(new JavaNativePair(KeyEvent.VK_E, kVK_ANSI_E)); + add(new JavaNativePair(KeyEvent.VK_R, kVK_ANSI_R)); + add(new JavaNativePair(KeyEvent.VK_Y, kVK_ANSI_Y)); + add(new JavaNativePair(KeyEvent.VK_T, kVK_ANSI_T)); + add(new JavaNativePair(KeyEvent.VK_1, kVK_ANSI_1)); + add(new JavaNativePair(KeyEvent.VK_2, kVK_ANSI_2)); + add(new JavaNativePair(KeyEvent.VK_3, kVK_ANSI_3)); + add(new JavaNativePair(KeyEvent.VK_4, kVK_ANSI_4)); + add(new JavaNativePair(KeyEvent.VK_6, kVK_ANSI_6)); + add(new JavaNativePair(KeyEvent.VK_5, kVK_ANSI_5)); + add(new JavaNativePair(KeyEvent.VK_EQUALS, kVK_ANSI_Equal)); + add(new JavaNativePair(KeyEvent.VK_9, kVK_ANSI_9)); + add(new JavaNativePair(KeyEvent.VK_7, kVK_ANSI_7)); + add(new JavaNativePair(KeyEvent.VK_MINUS, kVK_ANSI_Minus)); + add(new JavaNativePair(KeyEvent.VK_8, kVK_ANSI_8)); + add(new JavaNativePair(KeyEvent.VK_0, kVK_ANSI_0)); + add(new JavaNativePair(KeyEvent.VK_RIGHT_PARENTHESIS, kVK_ANSI_RightBracket)); + add(new JavaNativePair(KeyEvent.VK_O, kVK_ANSI_O)); + add(new JavaNativePair(KeyEvent.VK_U, kVK_ANSI_U)); + add(new JavaNativePair(KeyEvent.VK_LEFT_PARENTHESIS, kVK_ANSI_LeftBracket)); + add(new JavaNativePair(KeyEvent.VK_I, kVK_ANSI_I)); + add(new JavaNativePair(KeyEvent.VK_P, kVK_ANSI_P)); + add(new JavaNativePair(KeyEvent.VK_L, kVK_ANSI_L)); + add(new JavaNativePair(KeyEvent.VK_J, kVK_ANSI_J)); + add(new JavaNativePair(KeyEvent.VK_QUOTE, kVK_ANSI_Quote)); + add(new JavaNativePair(KeyEvent.VK_K, kVK_ANSI_K)); + add(new JavaNativePair(KeyEvent.VK_SEMICOLON, kVK_ANSI_Semicolon)); + add(new JavaNativePair(KeyEvent.VK_BACK_SLASH, kVK_ANSI_Backslash)); + add(new JavaNativePair(KeyEvent.VK_COMMA, kVK_ANSI_Comma)); + add(new JavaNativePair(KeyEvent.VK_SLASH, kVK_ANSI_Slash)); + add(new JavaNativePair(KeyEvent.VK_N, kVK_ANSI_N)); + add(new JavaNativePair(KeyEvent.VK_M, kVK_ANSI_M)); + add(new JavaNativePair(KeyEvent.VK_PERIOD, kVK_ANSI_Period)); + add(new JavaNativePair(KeyEvent.VK_DEAD_GRAVE, kVK_ANSI_Grave)); + add(new JavaNativePair(KeyEvent.VK_DECIMAL, kVK_ANSI_KeypadDecimal)); + add(new JavaNativePair(KeyEvent.VK_MULTIPLY, kVK_ANSI_KeypadMultiply)); + add(new JavaNativePair(KeyEvent.VK_PLUS, kVK_ANSI_KeypadPlus)); + add(new JavaNativePair(KeyEvent.VK_CLEAR, kVK_ANSI_KeypadClear)); + add(new JavaNativePair(KeyEvent.VK_DIVIDE, kVK_ANSI_KeypadDivide)); +// add(new JavaNativePair(KeyEvent.VK_ENTER, kVK_ANSI_KeypadEnter)); +// add(new JavaNativePair(KeyEvent.VK_MINUS, kVK_ANSI_KeypadMinus)); +// add(new JavaNativePair(KeyEvent.VK_EQUALS, kVK_ANSI_KeypadEquals)); + add(new JavaNativePair(KeyEvent.VK_NUMPAD0, kVK_ANSI_Keypad0)); + add(new JavaNativePair(KeyEvent.VK_NUMPAD1, kVK_ANSI_Keypad1)); + add(new JavaNativePair(KeyEvent.VK_NUMPAD2, kVK_ANSI_Keypad2)); + add(new JavaNativePair(KeyEvent.VK_NUMPAD3, kVK_ANSI_Keypad3)); + add(new JavaNativePair(KeyEvent.VK_NUMPAD4, kVK_ANSI_Keypad4)); + add(new JavaNativePair(KeyEvent.VK_NUMPAD5, kVK_ANSI_Keypad5)); + add(new JavaNativePair(KeyEvent.VK_NUMPAD6, kVK_ANSI_Keypad6)); + add(new JavaNativePair(KeyEvent.VK_NUMPAD7, kVK_ANSI_Keypad7)); + add(new JavaNativePair(KeyEvent.VK_NUMPAD8, kVK_ANSI_Keypad8)); + add(new JavaNativePair(KeyEvent.VK_NUMPAD9, kVK_ANSI_Keypad9)); + add(new JavaNativePair(KeyEvent.VK_ENTER, kVK_Return)); + add(new JavaNativePair(KeyEvent.VK_TAB, kVK_Tab)); + add(new JavaNativePair(KeyEvent.VK_SPACE, kVK_Space)); + add(new JavaNativePair(KeyEvent.VK_DELETE, kVK_Delete)); + add(new JavaNativePair(KeyEvent.VK_ESCAPE, kVK_Escape)); + add(new JavaNativePair(KeyEvent.VK_META, kVK_Command)); + add(new JavaNativePair(KeyEvent.VK_SHIFT, kVK_Shift)); + add(new JavaNativePair(KeyEvent.VK_CAPS_LOCK, kVK_CapsLock)); + add(new JavaNativePair(KeyEvent.VK_ALT, kVK_Option)); + add(new JavaNativePair(KeyEvent.VK_CONTROL, kVK_Control)); +// add(new JavaNativePair(KeyEvent.VK_META, kVK_RightCommand)); +// add(new JavaNativePair(KeyEvent.VK_SHIFT, kVK_RightShift)); +// add(new JavaNativePair(KeyEvent.VK_ALT, kVK_RightOption)); +// add(new JavaNativePair(KeyEvent.VK_CONTROL, kVK_RightControl)); +// add(new JavaNativePair(KeyEvent.VK_???, kVK_Function)); + add(new JavaNativePair(KeyEvent.VK_F17, kVK_F17)); +// add(new JavaNativePair(KeyEvent.VK_???, kVK_VolumeUp)); +// add(new JavaNativePair(KeyEvent.VK_???, kVK_VolumeDown)); +// add(new JavaNativePair(KeyEvent.VK_???, kVK_Mute)); + add(new JavaNativePair(KeyEvent.VK_F18, kVK_F18)); + add(new JavaNativePair(KeyEvent.VK_F19, kVK_F19)); + add(new JavaNativePair(KeyEvent.VK_F20, kVK_F20)); + add(new JavaNativePair(KeyEvent.VK_F5, kVK_F5)); + add(new JavaNativePair(KeyEvent.VK_F6, kVK_F6)); + add(new JavaNativePair(KeyEvent.VK_F7, kVK_F7)); + add(new JavaNativePair(KeyEvent.VK_F3, kVK_F3)); + add(new JavaNativePair(KeyEvent.VK_F8, kVK_F8)); + add(new JavaNativePair(KeyEvent.VK_F9, kVK_F9)); + add(new JavaNativePair(KeyEvent.VK_F11, kVK_F11)); + add(new JavaNativePair(KeyEvent.VK_F13, kVK_F13)); + add(new JavaNativePair(KeyEvent.VK_F16, kVK_F16)); + add(new JavaNativePair(KeyEvent.VK_F14, kVK_F14)); + add(new JavaNativePair(KeyEvent.VK_F10, kVK_F10)); + add(new JavaNativePair(KeyEvent.VK_F12, kVK_F12)); + add(new JavaNativePair(KeyEvent.VK_F15, kVK_F15)); + add(new JavaNativePair(KeyEvent.VK_HELP, kVK_Help)); + add(new JavaNativePair(KeyEvent.VK_HOME, kVK_Home)); + add(new JavaNativePair(KeyEvent.VK_PAGE_UP, kVK_PageUp)); +// add(new JavaNativePair(KeyEvent.VK_DELETE, kVK_ForwardDelete)); + add(new JavaNativePair(KeyEvent.VK_F4, kVK_F4)); + add(new JavaNativePair(KeyEvent.VK_END, kVK_End)); + add(new JavaNativePair(KeyEvent.VK_F2, kVK_F2)); + add(new JavaNativePair(KeyEvent.VK_PAGE_DOWN, kVK_PageDown)); + add(new JavaNativePair(KeyEvent.VK_F1, kVK_F1)); + add(new JavaNativePair(KeyEvent.VK_LEFT, kVK_LeftArrow)); + add(new JavaNativePair(KeyEvent.VK_RIGHT, kVK_RightArrow)); + add(new JavaNativePair(KeyEvent.VK_DOWN, kVK_DownArrow)); + add(new JavaNativePair(KeyEvent.VK_UP, kVK_UpArrow)); +// add(new JavaNativePair(KeyEvent.VK_???, kVK_ISO_Section)); +// add(new JavaNativePair(KeyEvent.VK_BACK_SLASH, kVK_JIS_Yen)); + add(new JavaNativePair(KeyEvent.VK_UNDERSCORE, kVK_JIS_Underscore)); +// add(new JavaNativePair(KeyEvent.VK_COMMA, kVK_JIS_KeypadComma)); + add(new JavaNativePair(KeyEvent.VK_ALPHANUMERIC, kVK_JIS_Eisu)); + add(new JavaNativePair(KeyEvent.VK_HIRAGANA, kVK_JIS_Kana)); }}; //#endregion diff --git a/rococoa-cocoa/src/test/java/org/rococoa/carbon/CarbonCoreLibraryTest.java b/rococoa-cocoa/src/test/java/org/rococoa/carbon/CarbonCoreLibraryTest.java index 49c7d20..4b035a7 100644 --- a/rococoa-cocoa/src/test/java/org/rococoa/carbon/CarbonCoreLibraryTest.java +++ b/rococoa-cocoa/src/test/java/org/rococoa/carbon/CarbonCoreLibraryTest.java @@ -13,6 +13,7 @@ import vavi.util.Debug; import vavi.util.StringUtil; +import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.rococoa.carbon.CarbonCoreLibrary.kTISPropertyUnicodeKeyLayoutData; import static org.rococoa.carbon.CarbonCoreLibrary.library; @@ -27,16 +28,18 @@ void test1() throws Exception { @Test void test2() throws Exception { - Pointer s = library.TISCopyCurrentKeyboardInputSource(); + Pointer s = library.TISCopyCurrentKeyboardLayoutInputSource(); Debug.println("TISCopyCurrentKeyboardInputSource: " + s); Pointer p = library.TISGetInputSourceProperty(s, kTISPropertyUnicodeKeyLayoutData); -Debug.println("TISGetInputSourceProperty: " + p); // TODO null +Debug.println("TISGetInputSourceProperty: " + p); + assertNotNull(p); } @Test void test3() throws Exception { PointerByReference pp = new PointerByReference(CarbonCoreLibrary.NATIVE_LIBRARY.getGlobalVariableAddress("kTISPropertyUnicodeKeyLayoutData")); Pointer p = pp.getValue().getPointer(0); + assertNotNull(p); Debug.printf("pointer: %s", p); Debug.printf("pointer: %s", new CFStringRef(p)); byte[] bytes = new byte[32]; @@ -49,9 +52,10 @@ void test4() throws Exception { PointerByReference pp = new PointerByReference(CarbonCoreLibrary.NATIVE_LIBRARY.getGlobalVariableAddress("kTISPropertyUnicodeKeyLayoutData")); Pointer kTISPropertyUnicodeKeyLayoutData = pp.getValue().getPointer(0); Debug.println("kTISPropertyUnicodeKeyLayoutData: " + kTISPropertyUnicodeKeyLayoutData); - Pointer s = library.TISCopyCurrentKeyboardInputSource(); + Pointer s = library.TISCopyCurrentKeyboardLayoutInputSource(); Debug.println("TISCopyCurrentKeyboardInputSource: " + s); Pointer p = library.TISGetInputSourceProperty(s, new CFStringRef(kTISPropertyUnicodeKeyLayoutData)); -Debug.println("TISGetInputSourceProperty: " + p); // TODO null +Debug.println("TISGetInputSourceProperty: " + p); + assertNotNull(p); } } \ No newline at end of file diff --git a/rococoa-contrib/src/main/java/org/rococoa/cocoa/coregraphics/CoreGraphicsLibrary.java b/rococoa-contrib/src/main/java/org/rococoa/cocoa/coregraphics/CoreGraphicsLibrary.java index 7046f00..e63f0be 100644 --- a/rococoa-contrib/src/main/java/org/rococoa/cocoa/coregraphics/CoreGraphicsLibrary.java +++ b/rococoa-contrib/src/main/java/org/rococoa/cocoa/coregraphics/CoreGraphicsLibrary.java @@ -6,6 +6,8 @@ package org.rococoa.cocoa.coregraphics; +import java.util.HashMap; +import java.util.Map; import java.util.logging.Logger; import com.sun.jna.Callback; @@ -296,48 +298,37 @@ private static CFStringRef createStringForKey(char /* CGKeyCode */ keyCode) { return CoreFoundation.library.CFStringCreateWithCharacters(kCFAllocatorDefault, chars, CFIndex.of(1)); } + /** key code, char map */ + Map charToCodeDict = new HashMap<>(128); + /** - * Returns key code for given character via the above function, or Character.MAX_VALUE (UINT16_MAX) - * on error. + * Returns key code for given character via the above function. */ static char /* CGKeyCode */ keyCodeForChar(char c) { - Pointer /* CFMutableDictionaryRef */ charToCodeDict = null; - char[] /* UniChar */ character = new char[] { c }; - // Generate table of keycodes and characters. - if (charToCodeDict == null) { - charToCodeDict = CoreFoundation.library.CFDictionaryCreateMutable(kCFAllocatorDefault, - new NativeLong(0), // must be 0 ??? - CoreFoundation.library.kCFCopyStringDictionaryKeyCallBacks, - CoreFoundation.library.kCFTypeDictionaryValueCallBacks); - if (charToCodeDict == null) throw new IllegalStateException("cannot careate CFDictionaryCreateMutable"); - + if (charToCodeDict.isEmpty()) { /* Loop through every keycode (0 - 127) to find its current mapping. */ for (char i = 0; i < 128; i++) { CFStringRef string = createStringForKey(/* CGKeyCode */ i); +logger.finest("key: " + (int) i + ", 0x" + Integer.toHexString(i) + ", string: " + string + (string != null && !string.toString().isEmpty() ? ", 0x" + Integer.toHexString(string.toString().charAt(0)) : "null")); if (string != null) { - IntByReference iRef = new IntByReference(i); - CoreFoundation.library.CFDictionaryAddValue(charToCodeDict, string, iRef.getPointer()); + charToCodeDict.put(string.toString(), i); CoreFoundation.library.CFRelease(string); } } } + char[] /* UniChar */ character = new char[] { c }; CFStringRef charStr = CoreFoundation.library.CFStringCreateWithCharacters(kCFAllocatorDefault, character, CFIndex.of(1)); - /* Our values may be NULL (0), so we need to use this function. */ - char code; - ShortByReference /* CGKeyCode */ codeRef = new ShortByReference(); - if (!CoreFoundation.library.CFDictionaryGetValueIfPresent(charToCodeDict, charStr.getPointer(), codeRef)) { - code = Character.MAX_VALUE; - } else { - code = (char) codeRef.getValue(); - } - + char code = charToCodeDict.getOrDefault(charStr.toString(), Character.MAX_VALUE); CoreFoundation.library.CFRelease(charStr); + return code; } +//#endregion + /** Returns a new Quartz keyboard event. */ Pointer /* CGEventRef */ CGEventCreateKeyboardEvent(Pointer /* CGEventSourceRef */ source, char /* CGKeyCode */ virtualKey, boolean keyDown); From a63e97c63c2cfda51e66db19032c7f525e982eda Mon Sep 17 00:00:00 2001 From: Naohide Sano Date: Mon, 25 Mar 2024 00:06:11 +0900 Subject: [PATCH 3/5] [coregraphics] make about event emulation work --- .../coregraphics/CoreGraphicsLibrary.java | 34 ++- .../cocoa/coregraphics/RococaRobot.java | 234 +++++++++++++++--- .../coregraphics/CoreGraphicsLibraryTest.java | 39 ++- .../src/test/resources/logging.properties | 1 + 4 files changed, 266 insertions(+), 42 deletions(-) diff --git a/rococoa-contrib/src/main/java/org/rococoa/cocoa/coregraphics/CoreGraphicsLibrary.java b/rococoa-contrib/src/main/java/org/rococoa/cocoa/coregraphics/CoreGraphicsLibrary.java index e63f0be..4d6a2b2 100644 --- a/rococoa-contrib/src/main/java/org/rococoa/cocoa/coregraphics/CoreGraphicsLibrary.java +++ b/rococoa-contrib/src/main/java/org/rococoa/cocoa/coregraphics/CoreGraphicsLibrary.java @@ -15,9 +15,9 @@ import com.sun.jna.Native; import com.sun.jna.NativeLong; import com.sun.jna.Pointer; +import com.sun.jna.platform.mac.CoreFoundation.CFArrayRef; import com.sun.jna.ptr.IntByReference; import com.sun.jna.ptr.NativeLongByReference; -import com.sun.jna.ptr.ShortByReference; import org.rococoa.carbon.CarbonCoreLibrary; import org.rococoa.cocoa.CFIndex; import org.rococoa.cocoa.CGFloat; @@ -190,6 +190,9 @@ interface CGRectEdge { // enum CGEventFlags long kCGEventFlagMaskCommand = NX_COMMANDMASK; + long kCGEventFlagMaskAlternate = NX_ALTERNATEMASK; + long kCGEventFlagMaskControl = NX_CONTROLMASK; + long kCGEventFlagMaskShift = NX_SHIFTMASK; long kCGEventMaskForAllEvents = 0xFFFF_FFFF_FFFF_FFFFL; @@ -264,7 +267,19 @@ interface CGEventTapCallBack extends Callback { /** Returns a Quartz event source created with a specified source state. */ Pointer /* CGEventSourceRef */ CGEventSourceCreate(int /* CGEventSourceStateID */ stateID); - // CGKeyCode + int kCGMouseEventDeltaX = 4; + int kCGMouseEventDeltaY = 5; + + /* Sets the integer value of a field in a Quartz event. */ + void CGEventSetIntegerValueField(Pointer /* CGEventRef */ event, int /* CGEventField */ field, long value); + + int kCGWindowListOptionOnScreenOnly = 1 << 0; + int kCGNullWindowID = 0; + + /** Generates and returns information about the selected windows in the current user session. */ + CFArrayRef CGWindowListCopyWindowInfo(int /* CGWindowListOption */ option, int /* CGWindowID */ relativeToWindow); + +//#region CGKeyCode /** * Returns string representation of key, if it is printable. @@ -273,10 +288,10 @@ interface CGEventTapCallBack extends Callback { * @see "https://stackoverflow.com/a/1971027" */ private static CFStringRef createStringForKey(char /* CGKeyCode */ keyCode) { - Pointer /* TISInputSourceRef */ currentKeyboard = CarbonCoreLibrary.library.TISCopyCurrentKeyboardInputSource(); -logger.fine("currentKeyboard: " + currentKeyboard);// + ", " + kTISPropertyUnicodeKeyLayoutData); + Pointer /* TISInputSourceRef */ currentKeyboard = CarbonCoreLibrary.library.TISCopyCurrentKeyboardLayoutInputSource(); // must be *Layout* +logger.finest("currentKeyboard: " + currentKeyboard);// + ", " + kTISPropertyUnicodeKeyLayoutData); Pointer /* CFDataRef */ layoutData = CarbonCoreLibrary.library.TISGetInputSourceProperty(currentKeyboard, CFStringRef.toCFString("TISPropertyUnicodeKeyLayoutData")); -logger.finer("layoutData: " + layoutData); +logger.finest("layoutData: " + layoutData); Pointer /* UCKeyboardLayout */ keyboardLayout = CoreFoundation.library.CFDataGetBytePtr(layoutData); IntByReference keysDown = new IntByReference(0); @@ -344,6 +359,9 @@ private static CFStringRef createStringForKey(char /* CGKeyCode */ keyCode) { // /** Returns a point with the specified coordinates. */ // /* inline */ CGPoint CGPointMake(CGFloat x, CGFloat y); + /** Sets the event type of a Quartz event (left mouse down, for example). */ + void CGEventSetType(Pointer /* CGEventRef */ event, int /* CGEventType */ type); + // CGMouseButton int kCGMouseButtonLeft = 0; int kCGMouseButtonRight = 1; @@ -364,4 +382,10 @@ private static CFStringRef createStringForKey(char /* CGKeyCode */ keyCode) { /** Returns a new Quartz mouse event. */ Pointer /* CGEventRef */ CGEventCreateMouseEvent(Pointer /* CGEventSourceRef */ source, int /* CGEventType */ mouseType, CGPoint mouseCursorPosition, int /* CGMouseButton */ mouseButton); + + int kCGScrollEventUnitPixel = 0; + int kCGScrollEventUnitLine = 1; + + /** Returns a new Quartz scrolling event. */ + Pointer /* CGEventRef */ CGEventCreateScrollWheelEvent2(Pointer /* CGEventSourceRef */ source, int /* CGScrollEventUnit */ units, int wheelCount, int wheel1, int wheel2, int wheel3); } 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 index 7c39199..9bad78d 100644 --- a/rococoa-contrib/src/main/java/org/rococoa/cocoa/coregraphics/RococaRobot.java +++ b/rococoa-contrib/src/main/java/org/rococoa/cocoa/coregraphics/RococaRobot.java @@ -6,86 +6,258 @@ 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.kCGMouseButtonLeft; +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) { - Pointer /* CGEventRef */ d = library.CGEventCreateKeyboardEvent(src, (char) code, true); + 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); - library.CGEventSetFlags(d, kCGEventFlagMaskCommand); + long flags = 0; + if (command) flags |= kCGEventFlagMaskCommand; + if (option) flags |= kCGEventFlagMaskAlternate; + if (control) flags |= kCGEventFlagMaskControl; + if (shift) flags |= kCGEventFlagMaskShift; + library.CGEventSetFlags(event, flags); - int /* CGEventTapLocation */ loc = kCGHIDEventTap; // kCGSessionEventTap also works - library.CGEventPost(loc, d); + library.CGEventPost(kCGHIDEventTap, event); - CoreFoundation.library.CFRelease(d); + 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) { - Pointer /* CGEventRef */ u = library.CGEventCreateKeyboardEvent(src, (char) code, false); + 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); - library.CGEventSetFlags(u, kCGEventFlagMaskCommand); + long flags = 0; + if (command) flags |= kCGEventFlagMaskCommand; + if (option) flags |= kCGEventFlagMaskAlternate; + if (control) flags |= kCGEventFlagMaskControl; + if (shift) flags |= kCGEventFlagMaskShift; + library.CGEventSetFlags(event, flags); - int /* CGEventTapLocation */ loc = kCGHIDEventTap; // kCGSessionEventTap also works - library.CGEventPost(loc, u); + library.CGEventPost(kCGHIDEventTap, event); - CoreFoundation.library.CFRelease(u); + 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 */ move = library.CGEventCreateMouseEvent( + Pointer /* CGEventRef */ event = library.CGEventCreateMouseEvent( null, kCGEventMouseMoved, prev, - kCGMouseButtonLeft // ignored + 0 // ignored ); // Now, execute these events with an interval to make them noticeable - library.CGEventPost(kCGHIDEventTap, move); - CoreFoundation.library.CFRelease(move); + 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) { - Pointer /* CGEventRef */ click_down = library.CGEventCreateMouseEvent( - null, kCGEventLeftMouseDown, + 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, - kCGMouseButtonLeft + buttons ); - library.CGEventPost(kCGHIDEventTap, click_down); - CoreFoundation.library.CFRelease(click_down); + 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) { - Pointer /* CGEventRef */ click_up = library.CGEventCreateMouseEvent( - null, kCGEventLeftMouseUp, + int[] events = {kCGEventLeftMouseUp, kCGEventRightMouseUp}; + Pointer /* CGEventRef */ event = library.CGEventCreateMouseEvent( + null, events[buttons], prev, - kCGMouseButtonLeft + buttons ); - library.CGEventPost(kCGHIDEventTap, click_up); - CoreFoundation.library.CFRelease(click_up); + 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 bc9d889..70d9b13 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 @@ -9,24 +9,33 @@ import java.util.Arrays; import java.util.NoSuchElementException; import java.util.logging.Level; +import java.util.stream.IntStream; import com.sun.jna.Pointer; +import com.sun.jna.platform.mac.CoreFoundation.CFArrayRef; +import com.sun.jna.platform.mac.CoreFoundation.CFDictionaryRef; import com.sun.tools.attach.VirtualMachine; import com.sun.tools.attach.VirtualMachineDescriptor; import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; +import org.rococoa.Foundation; import org.rococoa.Rococoa; import org.rococoa.cocoa.appkit.NSRunningApplication; import org.rococoa.cocoa.appkit.NSWorkspace; import org.rococoa.cocoa.corefoundation.CoreFoundation; import org.rococoa.cocoa.coreimage.CIImage; +import org.rococoa.cocoa.foundation.NSDictionary; +import org.rococoa.cocoa.foundation.NSRect; +import org.rococoa.cocoa.foundation.NSString; import vavi.util.Debug; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.rococoa.cocoa.coregraphics.CoreGraphicsLibrary.kCGEventFlagMaskCommand; import static org.rococoa.cocoa.coregraphics.CoreGraphicsLibrary.kCGEventSourceStateHIDSystemState; import static org.rococoa.cocoa.coregraphics.CoreGraphicsLibrary.kCGHIDEventTap; +import static org.rococoa.cocoa.coregraphics.CoreGraphicsLibrary.kCGNullWindowID; +import static org.rococoa.cocoa.coregraphics.CoreGraphicsLibrary.kCGWindowListOptionOnScreenOnly; import static org.rococoa.cocoa.coregraphics.CoreGraphicsLibrary.keyCodeForChar; import static org.rococoa.cocoa.coregraphics.CoreGraphicsLibrary.library; @@ -110,9 +119,8 @@ void test3() throws Exception { CoreFoundation.library.CFRelease(src); } - // NOT rococoa @Test - @DisplayName("list jvms") + @DisplayName("list jvms: NOT rococoa") void test5() throws Exception { for (VirtualMachineDescriptor descriptor : VirtualMachine.list()) { System.out.println(descriptor.id() + ", " + descriptor.displayName()); @@ -146,6 +154,7 @@ static NSRunningApplication getMinecraft() { } @Test + @DisplayName("NSRunningApplication") void test62() throws Exception { try { NSRunningApplication a = getMinecraft(); @@ -161,10 +170,28 @@ void test62() throws Exception { } @Test - @Disabled("TODO cause crash") + @DisplayName("CGKeyCode") void test7() throws Exception { - char c = 'a'; - char code = keyCodeForChar(c); -Debug.printf("code for '%x': %02x", c, code); + char[] cc = { 'a', '[', ']' }; + IntStream.range(0, cc.length).mapToObj(i -> cc[i]).forEach(c -> { + char code = keyCodeForChar(c); +Debug.printf("code for '%c': %02x", c, (int) code); + }); + } + + @Test + @DisplayName("CGWindowListCopyWindowInfo") + void test8() throws Exception { + CFArrayRef array = library.CGWindowListCopyWindowInfo(kCGWindowListOptionOnScreenOnly, kCGNullWindowID); +Debug.println("windows: " + array.getCount()); + NSRunningApplication a = getMinecraft(); + for (int i = 0; i < array.getCount(); i++) { + NSDictionary dic = Rococoa.toNSDictionary(array.getValueAtIndex(i)); + if (Integer.parseInt(dic.get(NSString.stringWithString("kCGWindowOwnerPID")).toString()) == a.processIdentifier().intValue()) { +Debug.println(dic); + NSDictionary rect = Rococoa.cast(dic.get(NSString.stringWithString("kCGWindowBounds")), NSDictionary.class); +Debug.println(rect); + } + } } } diff --git a/rococoa-contrib/src/test/resources/logging.properties b/rococoa-contrib/src/test/resources/logging.properties index f1ced36..f7ecac5 100644 --- a/rococoa-contrib/src/test/resources/logging.properties +++ b/rococoa-contrib/src/test/resources/logging.properties @@ -9,3 +9,4 @@ vavi.util.level=FINE #org.rococoa.internal.level=ALL org.rococoa.cocoa.appkit.level=ALL org.rococoa.cocoa.vision.level=ALL +org.rococoa.cocoa.coregraphics.level=FINER From 72470e424b858b8474f19b0cbea737176c2cb049 Mon Sep 17 00:00:00 2001 From: Naohide Sano Date: Mon, 25 Mar 2024 01:43:12 +0900 Subject: [PATCH 4/5] bump version --- pom.xml | 2 +- rococoa-cocoa/pom.xml | 2 +- rococoa-contrib/pom.xml | 2 +- rococoa-core/pom.xml | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/pom.xml b/pom.xml index 85d7b81..5f70e0b 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ org.rococoa rococoa-parent - 0.8.8 + 0.8.9 pom diff --git a/rococoa-cocoa/pom.xml b/rococoa-cocoa/pom.xml index df773c0..4d54210 100644 --- a/rococoa-cocoa/pom.xml +++ b/rococoa-cocoa/pom.xml @@ -10,7 +10,7 @@ org.rococoa rococoa-parent - 0.8.8 + 0.8.9 Rococoa Cocoa Mappings diff --git a/rococoa-contrib/pom.xml b/rococoa-contrib/pom.xml index c765ed9..b5e704e 100644 --- a/rococoa-contrib/pom.xml +++ b/rococoa-contrib/pom.xml @@ -10,7 +10,7 @@ org.rococoa rococoa-parent - 0.8.8 + 0.8.9 Rococoa Contrib diff --git a/rococoa-core/pom.xml b/rococoa-core/pom.xml index 3cdbabd..c199dba 100644 --- a/rococoa-core/pom.xml +++ b/rococoa-core/pom.xml @@ -9,7 +9,7 @@ org.rococoa rococoa-parent - 0.8.8 + 0.8.9 Rococoa Core From 2749f81f722c400551088d0384d51027499dadd7 Mon Sep 17 00:00:00 2001 From: Naohide Sano Date: Mon, 25 Mar 2024 01:57:48 +0900 Subject: [PATCH 5/5] =?UTF-8?q?=F0=9F=A5=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../org/rococoa/cocoa/coregraphics/CoreGraphicsLibraryTest.java | 2 ++ 1 file changed, 2 insertions(+) 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 70d9b13..9eaa5f5 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,6 +19,7 @@ import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.condition.EnabledIfSystemProperty; import org.rococoa.Foundation; import org.rococoa.Rococoa; import org.rococoa.cocoa.appkit.NSRunningApplication; @@ -181,6 +182,7 @@ void test7() throws Exception { @Test @DisplayName("CGWindowListCopyWindowInfo") + @EnabledIfSystemProperty(named = "vavi.test", matches = "ide") void test8() throws Exception { CFArrayRef array = library.CGWindowListCopyWindowInfo(kCGWindowListOptionOnScreenOnly, kCGNullWindowID); Debug.println("windows: " + array.getCount());