Skip to content

Commit 8993c7d

Browse files
committed
Incomplete Changes
1 parent b80497f commit 8993c7d

File tree

13 files changed

+725
-77
lines changed

13 files changed

+725
-77
lines changed

TODO

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
Development Milestones
2+
- Fix Interaction Support for Virtual Machine / Browser
3+
- Look at PixelStacker (https://github.com/Pangamma/PixelStacker)
4+
- Add Images and GIF Support into Plugin
5+
26
- Build QEMU Statically for All Platforms
3-
- Add Interaction Support for Virtual Machine
4-
- Add Interaction Support for Browser
5-
- Add Images and GIF Support into Plugin
7+
- Rewrite all JavaDocs

mcav-bukkit/src/main/java/me/brandonli/mcav/bukkit/utils/InteractUtils.java

Lines changed: 0 additions & 25 deletions
This file was deleted.

mcav-common/src/main/java/me/brandonli/mcav/media/player/driver/BrowserPlayer.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,15 @@ default CompletableFuture<Boolean> startAsync(final VideoPipelineStep videoPipel
108108
*/
109109
void sendMouseEvent(final int x, final int y, final MouseClick type);
110110

111+
/**
112+
* Sends a key event by simulating the entry of the specified text.
113+
*
114+
* @param text the text to be sent as a key event. This parameter represents
115+
* the string of characters or input sequence that the method simulates
116+
* being typed.
117+
*/
118+
void sendKeyEvent(final String text);
119+
111120
/**
112121
* Creates a default instance of {@code ChromeDriverPlayer} with pre-defined arguments to
113122
* configure the Chrome browser in a headless environment.

mcav-common/src/main/java/me/brandonli/mcav/media/player/driver/ChromeDriverPlayer.java

Lines changed: 21 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -166,21 +166,28 @@ public void sendMouseEvent(final int x, final int y, final MouseClick type) {
166166
action.perform();
167167
}
168168

169-
private Actions getAction(final MouseClick type, final Actions move) {
170-
switch (type) {
171-
case LEFT:
172-
return move.click();
173-
case RIGHT:
174-
return move.contextClick();
175-
case DOUBLE:
176-
return move.doubleClick();
177-
case HOLD:
178-
return move.clickAndHold();
179-
case RELEASE:
180-
return move.release();
181-
default:
182-
throw new InvalidMouseClickArgument("Invalid mouse click type!");
169+
/**
170+
* {@inheritDoc}
171+
*/
172+
@Override
173+
public void sendKeyEvent(final String text) {
174+
if (!this.running.get()) {
175+
return;
183176
}
177+
final Actions actions = new Actions(this.driver);
178+
final Actions move = actions.sendKeys(text);
179+
final Action action = move.build();
180+
action.perform();
181+
}
182+
183+
private Actions getAction(final MouseClick type, final Actions move) {
184+
return switch (type) {
185+
case LEFT -> move.click();
186+
case RIGHT -> move.contextClick();
187+
case DOUBLE -> move.doubleClick();
188+
case HOLD -> move.clickAndHold();
189+
case RELEASE -> move.release();
190+
};
184191
}
185192

186193
/**

mcav-common/src/main/java/me/brandonli/mcav/media/player/vnc/VNCPlayer.java

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,22 @@ default CompletableFuture<Boolean> startAsync(
9898
*/
9999
void moveMouse(final int x, final int y);
100100

101+
/**
102+
* Simulates a mouse click at the specified coordinates within the VNC session.
103+
* This method moves the mouse to the given position and performs a press-and-release
104+
* action for the specified mouse button type.
105+
*
106+
* @param x the x-coordinate to click at, in pixels
107+
* @param y the y-coordinate to click at, in pixels
108+
* @param type the mouse button type to click, where 0 typically represents the left button,
109+
* 1 represents the middle button, and 2 represents the right button
110+
*/
111+
default void click(final int x, final int y, final int type) {
112+
this.moveMouse(x, y);
113+
this.updateMouseButton(type, true);
114+
this.updateMouseButton(type, false);
115+
}
116+
101117
/**
102118
* Simulates typing the provided text into the VNC session by sending corresponding keyboard input events.
103119
*

mcav-common/src/main/java/me/brandonli/mcav/media/player/vnc/VNCPlayerImpl.java

Lines changed: 31 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
import java.util.concurrent.Executors;
2828
import java.util.concurrent.atomic.AtomicBoolean;
2929
import me.brandonli.mcav.media.image.StaticImage;
30+
import me.brandonli.mcav.media.player.PlayerException;
3031
import me.brandonli.mcav.media.player.metadata.VideoMetadata;
3132
import me.brandonli.mcav.media.player.pipeline.step.VideoPipelineStep;
3233
import me.brandonli.mcav.media.source.VNCSource;
@@ -49,18 +50,16 @@ public class VNCPlayerImpl implements VNCPlayer {
4950
private final AtomicBoolean running;
5051
private final Object lock = new Object();
5152

52-
private boolean connected;
53-
private volatile BufferedImage current;
5453
private @Nullable CompletableFuture<?> processingFuture;
5554
private @Nullable VernacularClient vncClient;
5655

57-
private VideoPipelineStep videoPipeline;
58-
private VideoMetadata videoMetadata;
56+
private volatile BufferedImage current;
57+
private volatile VideoPipelineStep videoPipeline;
58+
private volatile VideoMetadata videoMetadata;
5959

6060
VNCPlayerImpl() {
6161
this.frameProcessorExecutor = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());
6262
this.running = new AtomicBoolean(false);
63-
this.connected = false;
6463
}
6564

6665
/**
@@ -69,7 +68,7 @@ public class VNCPlayerImpl implements VNCPlayer {
6968
@Override
7069
public boolean start(final VideoPipelineStep videoPipeline, final VNCSource source) {
7170
synchronized (this.lock) {
72-
if (this.connected) {
71+
if (this.running.get()) {
7372
return true;
7473
}
7574
this.videoPipeline = videoPipeline;
@@ -79,7 +78,6 @@ public boolean start(final VideoPipelineStep videoPipeline, final VNCSource sour
7978
this.vncClient = new VernacularClient(config);
8079
this.vncClient.start(source.getHost(), source.getPort());
8180

82-
this.connected = true;
8381
this.running.set(true);
8482

8583
this.processingFuture = CompletableFuture.runAsync(this::processFrames, this.frameProcessorExecutor);
@@ -139,7 +137,7 @@ private void processFrames() {
139137
@Override
140138
public boolean pause() {
141139
synchronized (this.lock) {
142-
if (this.connected && this.running.get()) {
140+
if (this.running.get()) {
143141
this.running.set(false);
144142
return true;
145143
}
@@ -153,7 +151,7 @@ public boolean pause() {
153151
@Override
154152
public boolean resume() {
155153
synchronized (this.lock) {
156-
if (this.connected && !this.running.get()) {
154+
if (!this.running.get()) {
157155
this.running.set(true);
158156
if (this.processingFuture == null || this.processingFuture.isDone()) {
159157
this.processingFuture = CompletableFuture.runAsync(this::processFrames, this.frameProcessorExecutor);
@@ -171,23 +169,15 @@ public boolean resume() {
171169
public boolean release() {
172170
synchronized (this.lock) {
173171
this.running.set(false);
174-
175-
if (this.connected) {
176-
if (this.processingFuture != null) {
177-
this.processingFuture.cancel(true);
178-
this.processingFuture = null;
179-
}
180-
181-
if (this.vncClient != null) {
182-
this.vncClient.stop();
183-
this.vncClient = null;
184-
}
185-
186-
this.connected = false;
172+
if (this.processingFuture != null) {
173+
this.processingFuture.cancel(true);
174+
this.processingFuture = null;
175+
}
176+
if (this.vncClient != null) {
177+
this.vncClient.stop();
178+
this.vncClient = null;
187179
}
188-
189180
ExecutorUtils.shutdownExecutorGracefully(this.frameProcessorExecutor);
190-
191181
return true;
192182
}
193183
}
@@ -197,9 +187,24 @@ public boolean release() {
197187
*/
198188
@Override
199189
public void moveMouse(final int x, final int y) {
200-
if (this.vncClient != null) {
201-
this.vncClient.moveMouse(x, y);
190+
final VernacularClient client = this.vncClient;
191+
if (client != null) {
192+
final int[] translated = this.translateCoordinates(x, y);
193+
client.moveMouse(translated[0], translated[1]);
194+
}
195+
}
196+
197+
private int[] translateCoordinates(final int x, final int y) {
198+
final int originWidth = this.videoMetadata.getVideoWidth();
199+
final int originHeight = this.videoMetadata.getVideoHeight();
200+
if (this.current == null) {
201+
throw new PlayerException("VNC source not started!");
202202
}
203+
final int targetWidth = this.current.getWidth();
204+
final int targetHeight = this.current.getHeight();
205+
final int newX = (int) (((float) x / originWidth) * targetWidth);
206+
final int newY = (int) (((float) y / originHeight) * targetHeight);
207+
return new int[] { newX, newY };
203208
}
204209

205210
/**

0 commit comments

Comments
 (0)