Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package io.github.kamitejp.platform.linux.wlroots.dependencies.slurp;
package io.github.kamitejp.platform.linux.dependencies.slurp;

import java.util.ArrayList;
import java.util.regex.Pattern;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package io.github.kamitejp.platform.linux.dependencies.slurp;

public enum SlurpFade {
FADE,
NO_FADE;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package io.github.kamitejp.platform.linux.dependencies.slurp;

public enum SlurpMode {
POINT,
AREA;
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package io.github.kamitejp.platform.linux.wlroots.dependencies.slurp;
package io.github.kamitejp.platform.linux.dependencies.slurp;

import io.github.kamitejp.geometry.Rectangle;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,14 @@
import java.lang.invoke.MethodHandles;
import java.util.List;

import io.github.kamitejp.platform.PlatformOCRInitializationException;
import io.github.kamitejp.platform.linux.dependencies.slurp.Slurp;
import io.github.kamitejp.platform.linux.kde.dependencies.spectacle.Spectacle;
import io.github.kamitejp.platform.linux.kde.dependencies.spectacle.SpectacleResult;
import io.github.kamitejp.platform.linux.dependencies.slurp.SlurpFade;
import io.github.kamitejp.platform.linux.dependencies.slurp.SlurpMode;
import io.github.kamitejp.platform.linux.dependencies.slurp.SlurpResult;
import io.github.kamitejp.recognition.OCREngine;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

Expand All @@ -21,6 +29,9 @@ public class PlasmaPlatform extends WaylandPlatform {
@SuppressWarnings("unused")
private static final Logger LOG = LogManager.getLogger(MethodHandles.lookup().lookupClass());

private Spectacle spectacle;
private Slurp slurp;

public PlasmaPlatform() throws PlatformCreationException {
if (!"KDE".equalsIgnoreCase(getEnvVarAsNonNullableString("XDG_CURRENT_DESKTOP"))) {
throw new PlatformCreationException("XDG_CURRENT_DESKTOP does not match 'KDE'");
Expand All @@ -30,23 +41,90 @@ public PlasmaPlatform() throws PlatformCreationException {
@Override
public List<PlatformDependentFeature> getUnsupportedFeatures() {
return List.of(
PlatformDependentFeature.GLOBAL_OCR,
PlatformDependentFeature.GLOBAL_KEYBINDINGS
);
}

@SuppressWarnings("OverlyBroadThrowsClause")
@Override
public void initOCR(OCREngine engine) throws PlatformOCRInitializationException {
super.initOCR(engine);

slurp = new Slurp();
spectacle = new Spectacle();
var checkRes = checkIfDependenciesAvailable(List.of(slurp, spectacle));
if (checkRes.isErr()) {
spectacle = null;
throw new PlatformOCRInitializationException.MissingDependencies(checkRes.err());
}
}

@Override
public Result<Point, RecognitionOpError> getUserSelectedPoint(PointSelectionMode mode) {
throw new UnsupportedOperationException("Not implemented");
}

@Override
public Result<Rectangle, RecognitionOpError> getUserSelectedArea() {
throw new UnsupportedOperationException("Not implemented");
var slurpRunRes = runSlurp(SlurpMode.AREA, SlurpFade.FADE);
if (slurpRunRes.isErr()) {
return Result.Err(slurpRunRes.err());
}
return switch (slurpRunRes.get()) {
case SlurpResult.Area area -> Result.Ok(area.area());
default -> {
LOG.error("Received a valid but unexpected slurp result");
yield Result.Err(RecognitionOpError.SELECTION_FAILED);
}
};
}

@Override
public Result<BufferedImage, RecognitionOpError> takeAreaScreenshot(Rectangle area) {
throw new UnsupportedOperationException("Not implemented");
if (spectacle == null) {
return Result.Err(RecognitionOpError.OCR_UNAVAILABLE);
}
return switch (spectacle.takeScreenshot(area)) {
case SpectacleResult.ExecutionFailed _ -> {
LOG.error("spectacle did not execute properly");
yield Result.Err(RecognitionOpError.SCREENSHOT_FAILED);
}
case SpectacleResult.Error error -> {
LOG.error("spectacle returned an error: {}", error::error);
yield Result.Err(RecognitionOpError.SCREENSHOT_FAILED);
}
case SpectacleResult.Screenshot screenshot -> Result.Ok(screenshot.screenshot());
};
}

private Result<SlurpResult, RecognitionOpError> runSlurp(SlurpMode mode, SlurpFade fade) {
if (slurp == null) {
return Result.Err(RecognitionOpError.OCR_UNAVAILABLE);
}

var slurpRes = slurp.getSelectionFromUser(mode, fade);
return switch (slurpRes) {
case SlurpResult.ExecutionFailed _ -> {
LOG.error("slurp did not execute properly");
yield Result.Err(RecognitionOpError.SELECTION_FAILED);
}

case SlurpResult.Error error -> {
LOG.error("slurp returned an error: {}", error::error);
yield Result.Err(RecognitionOpError.SELECTION_FAILED);
}

case SlurpResult.Cancelled _ -> Result.Err(RecognitionOpError.SELECTION_CANCELLED);

case SlurpResult.FormatDifferentFromExpected expected -> {
LOG.error(
"slurp returned malformatted result instead of expected {}",
expected::expected
);
yield Result.Err(RecognitionOpError.SELECTION_FAILED);
}

default -> Result.Ok(slurpRes);
};
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package io.github.kamitejp.platform.linux.kde.dependencies.spectacle;

import io.github.kamitejp.geometry.Rectangle;
import io.github.kamitejp.image.ImageOps;
import io.github.kamitejp.platform.BaseSimpleDependency;
import io.github.kamitejp.platform.process.ProcessHelper;
import io.github.kamitejp.platform.process.ProcessRunParams;

import java.util.ArrayList;

public class Spectacle extends BaseSimpleDependency {
public Spectacle() {
super("spectacle");
}

@Override
public boolean checkIsAvailable() {
var res = ProcessHelper.run(
ProcessRunParams.ofCmd(BIN, "-h").withTimeout(DEFAULT_AVAILABILITY_CHECK_TIMEOUT_MS)
);
return res.didComplete() && res.getStdout().startsWith("Usage: spectacle");
}

public SpectacleResult takeScreenshot(Rectangle area) {
var cmd = new ArrayList<String>();
cmd.add(BIN);
cmd.add("-bno");
cmd.add("/dev/stdout");

var res = ProcessHelper.runWithBinaryOutput(ProcessRunParams.ofCmd(cmd).withTimeout(3000));
if (!res.didComplete()) {
return new SpectacleResult.ExecutionFailed();
} else if (res.didCompleteWithError()) {
return new SpectacleResult.Error(res.getStderr());
}

var image = ImageOps.fromBytes(res.getStdout());
if (image == null) {
return new SpectacleResult.ExecutionFailed();
}

if (area != null) {
image = image.getSubimage(area.getLeft(), area.getTop(), area.getWidth(), area.getHeight());
}

return new SpectacleResult.Screenshot(image);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package io.github.kamitejp.platform.linux.kde.dependencies.spectacle;

public sealed interface SpectacleResult
permits SpectacleResult.ExecutionFailed,
SpectacleResult.Error,
SpectacleResult.Screenshot {
record ExecutionFailed() implements SpectacleResult {}
record Error(String error) implements SpectacleResult {}
record Screenshot(java.awt.image.BufferedImage screenshot) implements SpectacleResult {}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,10 @@
import io.github.kamitejp.platform.linux.WaylandPlatform;
import io.github.kamitejp.platform.linux.wlroots.dependencies.grim.Grim;
import io.github.kamitejp.platform.linux.wlroots.dependencies.grim.GrimResult;
import io.github.kamitejp.platform.linux.wlroots.dependencies.slurp.Slurp;
import io.github.kamitejp.platform.linux.wlroots.dependencies.slurp.SlurpFade;
import io.github.kamitejp.platform.linux.wlroots.dependencies.slurp.SlurpMode;
import io.github.kamitejp.platform.linux.wlroots.dependencies.slurp.SlurpResult;
import io.github.kamitejp.platform.linux.dependencies.slurp.Slurp;
import io.github.kamitejp.platform.linux.dependencies.slurp.SlurpFade;
import io.github.kamitejp.platform.linux.dependencies.slurp.SlurpMode;
import io.github.kamitejp.platform.linux.dependencies.slurp.SlurpResult;
import io.github.kamitejp.platform.linux.wlroots.dependencies.wlrctl.Wlrctl;
import io.github.kamitejp.platform.linux.wlroots.dependencies.wlrctl.WlrctlResult;
import io.github.kamitejp.recognition.OCREngine;
Expand Down

This file was deleted.

This file was deleted.