Skip to content

Commit

Permalink
Merge pull request #1 from umjammer/0.0.2
Browse files Browse the repository at this point in the history
0.0.2
  • Loading branch information
umjammer authored Mar 26, 2024
2 parents c3fdb88 + 76215b8 commit 99dbbd0
Show file tree
Hide file tree
Showing 5 changed files with 44 additions and 129 deletions.
10 changes: 6 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,13 @@

<img src="https://github.com/umjammer/vavi-apps-hub/assets/493908/5efff428-15df-46bb-a7b0-929e31caf3c2" width="128" alt="hub logo" />

My Hub ❤
🌐 hub for plugins that controls a computer

### plugins

* remote notificator
* remote trackpad (wip)
* gamepad binder
* 🏅 gamepad binder (Minecraft, MuseScore3)
* hand gesture recognizer (tbd)

## Install
Expand Down Expand Up @@ -63,9 +63,11 @@ My Hub ❤
## TODO

* ~~hub for notification center over inet~~
* hub for remote mouse input (wip) -> this websocket server
* ~~apple remote event?~~ -> this rest server
* ~~hub for remote mouse input~~ -> this websocket server (done)
* touchpad (wip)
* ~~apple remote event?~~ -> this rest server (done)
* ~~coexistence websocket and jersey on jetty~~ see [Main.java](src/main/java/vavi/apps/hub/Main.java)
* gamepad configuration, dsl?, json?

---
<sub>image by <a href="https://www.silhouette-illust.com/illust/49214">silhouette illust</a></sub>
4 changes: 2 additions & 2 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

<groupId>vavi</groupId>
<artifactId>vavi-apps-hub</artifactId>
<version>0.0.1</version>
<version>0.0.2</version>

<properties>
<javapackager.name>Hub</javapackager.name>
Expand Down Expand Up @@ -176,7 +176,7 @@
<dependency>
<groupId>com.github.umjammer</groupId> <!-- vavi / com.github.umjammer -->
<artifactId>vavi-awt-joystick</artifactId>
<version>0.0.7</version>
<version>0.0.8</version>
</dependency>

<dependency>
Expand Down
2 changes: 2 additions & 0 deletions src/main/java/vavi/apps/hub/Tray.java
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,10 @@ public class Tray implements Plugin {
/** */
private PopupMenu popup;

/** TODO generated automatically? */
MenuItem gamepadItem;

/** TODO location should be at gamepad plugin */
void gamepad(GenericEvent event) {
if (gamepadItem == null) {
gamepadItem = new MenuItem();
Expand Down
149 changes: 30 additions & 119 deletions src/main/java/vavi/games/input/listener/MinecraftListener.java
Original file line number Diff line number Diff line change
Expand Up @@ -11,23 +11,16 @@
import java.awt.MouseInfo;
import java.awt.Point;
import java.awt.Rectangle;
import java.util.Arrays;
import java.util.NoSuchElementException;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Consumer;
import java.util.logging.Level;

import com.sun.jna.platform.mac.CoreFoundation.CFArrayRef;
import com.sun.tools.attach.VirtualMachine;
import com.sun.tools.attach.VirtualMachineDescriptor;
import net.java.games.input.Event;
import org.rococoa.Rococoa;
import org.rococoa.cocoa.appkit.NSRunningApplication;
import org.rococoa.cocoa.coregraphics.RococaRobot;
import org.rococoa.cocoa.foundation.NSDictionary;
import org.rococoa.cocoa.foundation.NSString;
import vavi.games.input.listener.GamepadInputEventListener.AppInfo;
import vavi.games.input.listener.GamepadInputEventListener.Context;
import vavi.games.input.robot.Key;
import vavi.games.input.robot.RococaRobot;
import vavi.util.Debug;
import vavi.util.event.GenericEvent;

Expand All @@ -51,9 +44,7 @@
import static org.rococoa.carbon.CarbonCoreLibrary.kVK_Space;
import static org.rococoa.cocoa.coregraphics.CoreGraphicsLibrary.kCGMouseButtonLeft;
import static org.rococoa.cocoa.coregraphics.CoreGraphicsLibrary.kCGMouseButtonRight;
import static org.rococoa.cocoa.coregraphics.CoreGraphicsLibrary.kCGNullWindowID;
import static org.rococoa.cocoa.coregraphics.CoreGraphicsLibrary.kCGWindowListOptionOnScreenOnly;
import static org.rococoa.cocoa.coregraphics.CoreGraphicsLibrary.library;
import static vavi.games.input.helper.JavaVMAppInfo.getPidByMainClassName;


/**
Expand All @@ -66,15 +57,35 @@ public class MinecraftListener extends GamepadAdapter {

private static final String bundleId = "com.mojang.Minecraft";

/** minecraft launchers descriptor#dusplayName */
private static final String[] mcLaunchers = {
"net.minecraft.client.main.Main", // mc launcher -> original
"net.fabricmc.loader.impl.launch.knot.KnotClient", // mc launcher -> fabric
"org.prismlauncher.EntryPoint" // prism launcher
};

private long prevForBounds;

@Override
public boolean match(NSRunningApplication a) {
public boolean match(AppInfo a) {
try {
if (a.processIdentifier().intValue() == getMcLauncherPid()) {
if (a.pid() == getPidByMainClassName(mcLaunchers)) {
if (System.currentTimeMillis() - prevForBounds > 20 * 1000) {
prevForBounds = System.currentTimeMillis();
Executors.newSingleThreadScheduledExecutor().submit(() -> retrieveBounds(a));
Executors.newSingleThreadScheduledExecutor().submit(() -> {
Rectangle b = a.bounds();
if (b != null) {
Rectangle r = bounds.get();
if (r == null) {
bounds.set(b);
} else {
r.setBounds(b);
}
//Debug.println("minecraft window found: " + r);
// } else {
//Debug.println("no minecraft window found.");
}
});
}
return true;
}
Expand All @@ -84,48 +95,6 @@ public boolean match(NSRunningApplication a) {
return false;
}

/** @after {@link #bounds} */
private void retrieveBounds(NSRunningApplication a) {
CFArrayRef array = library.CGWindowListCopyWindowInfo(kCGWindowListOptionOnScreenOnly, kCGNullWindowID);
//Debug.println("windows: " + array.getCount());
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()) {
NSDictionary rect = Rococoa.cast(dic.get(NSString.stringWithString("kCGWindowBounds")), NSDictionary.class);
int x = Integer.parseInt(rect.get(NSString.stringWithString("X")).toString());
int y = Integer.parseInt(rect.get(NSString.stringWithString("Y")).toString());
int width = Integer.parseInt(rect.get(NSString.stringWithString("Width")).toString());
int height = Integer.parseInt(rect.get(NSString.stringWithString("Height")).toString());
Rectangle r = bounds.get();
if (r == null) {
bounds.set(new Rectangle(x, y, width, height));
} else {
r.setBounds(x, y, width, height);
}
//Debug.println("minecraft window found: " + r);
return;
}
}
//Debug.println("no minecraft window found.");
}

/** minecraft launchers descriptor#dusplayName */
private static final String[] mcLaunchers = {
"net.minecraft.client.main.Main", // mc launcher -> original
"net.fabricmc.loader.impl.launch.knot.KnotClient", // mc launcher -> fabric
"org.prismlauncher.EntryPoint" // prism launcher
};

/** minecraft launchers pid which displayName contains one of those */
private static int getMcLauncherPid() {
for (VirtualMachineDescriptor descriptor : VirtualMachine.list()) {
if (Arrays.asList(mcLaunchers).contains(descriptor.displayName())) {
return Integer.decode(descriptor.id());
}
}
throw new NoSuchElementException("minecraft might not run");
}

// ----

private final RococaRobot robot = new RococaRobot();
Expand All @@ -146,7 +115,6 @@ private static int getMcLauncherPid() {
private final AtomicReference<Rectangle> bounds = new AtomicReference<>();

/**
* @before {@link #retrieveBounds}
* @after {@link #point}
*/
private void normalizePoint() {
Expand All @@ -164,32 +132,6 @@ private void normalizePoint() {
}
}

static class Key {
final int code;
final Consumer<Integer> pressAction;
final Consumer<Integer> releaseAction;
boolean pressed;

public Key(int code, Consumer<Integer> pressAction, Consumer<Integer> releaseAction) {
this.code = code;
this.pressAction = pressAction;
this.releaseAction = releaseAction;
}

void press() {
if (!pressed) {
pressAction.accept(code);
pressed = true;
}
}
void release() {
if (pressed) {
releaseAction.accept(code);
pressed = false;
}
}
}

class RobotKey extends Key {
RobotKey(int code) {
super(code, robot::keyPress, robot::keyRelease);
Expand All @@ -198,38 +140,7 @@ class RobotKey extends Key {

class RobotKey2 extends Key {
RobotKey2(int code) {
super(code, robot::keyPress2, robot::keyRelease2);
}
}

@FunctionalInterface
interface TriConsumer<T, U, V> {
void accept(T t, U u, V v);
}

static class KeyWithCoordinate {
final int code;
final TriConsumer<Integer, Integer, Integer> pressActionWithCoordinat;
final TriConsumer<Integer, Integer, Integer> releaseActionWithCoordinat;
boolean pressed;

public KeyWithCoordinate(int code, TriConsumer<Integer, Integer, Integer> pressActionWithCoordinate, TriConsumer<Integer, Integer, Integer> releaseActionWithCoordinate) {
this.code = code;
this.pressActionWithCoordinat = pressActionWithCoordinate;
this.releaseActionWithCoordinat = releaseActionWithCoordinate;
}

void press(int x, int y) {
if (!pressed) {
pressActionWithCoordinat.accept(code, x, y);
pressed = true;
}
}
void release(int x, int y) {
if (pressed) {
releaseActionWithCoordinat.accept(code, x, y);
pressed = false;
}
super(code, robot::keyPressRaw, robot::keyReleaseRaw);
}
}

Expand Down Expand Up @@ -580,9 +491,9 @@ public void onButton14(Event e) {
@Override
public void after() {
if (moved) {
robot.mouseMove2(dx, dy);
robot.mouseMoveOnlyAccel(dx, dy);
normalizePoint();
robot.mouseMove0(point.x, point.y);
robot.mouseMoveOnlyLocation(point.x, point.y);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@
package vavi.games.input.listener;

import net.java.games.input.Event;
import org.rococoa.cocoa.appkit.NSRunningApplication;
import org.rococoa.cocoa.coregraphics.RococaRobot;
import vavi.games.input.listener.GamepadInputEventListener.AppInfo;
import vavi.games.input.listener.GamepadInputEventListener.Context;
import vavi.games.input.robot.RococaRobot;
import vavi.util.Debug;
import vavi.util.event.GenericEvent;

Expand All @@ -33,8 +33,8 @@ public class MuseScoreListener extends GamepadAdapter {
private static final String bundleId = "org.musescore.MuseScore";

@Override
public boolean match(NSRunningApplication a) {
return a.bundleIdentifier().equals(bundleId);
public boolean match(AppInfo a) {
return a.id().equals(bundleId);
}

private Context context;
Expand Down

0 comments on commit 99dbbd0

Please sign in to comment.