some fixes and optimizations
This commit is contained in:
parent
b3cf1825d9
commit
37c3d8ffb7
@ -1,13 +1,13 @@
|
||||
#Pokémon GO Automatizace - Nastavení
|
||||
#Fri Jan 23 16:03:46 CET 2026
|
||||
#Pokémon GO Automation - Settings
|
||||
#Tue May 19 19:39:52 CEST 2026
|
||||
autoklik.count=1000
|
||||
window.width=807
|
||||
transfer.delay=0
|
||||
autoklik.x=2123
|
||||
window.height=743
|
||||
autoklik.downArrow=true
|
||||
autoklik.y=1129
|
||||
autoklik.interval=150
|
||||
transfer.count=6
|
||||
window.x=887
|
||||
window.y=505
|
||||
autoklik.x=2123
|
||||
autoklik.y=1129
|
||||
transfer.count=60
|
||||
transfer.delay=0
|
||||
window.height=743
|
||||
window.width=412
|
||||
window.x=1546
|
||||
window.y=343
|
||||
|
||||
7
pom.xml
7
pom.xml
@ -33,13 +33,6 @@
|
||||
<version>1.18.26</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- OpenCV pro rozpoznávání obrazu -->
|
||||
<dependency>
|
||||
<groupId>org.openpnp</groupId>
|
||||
<artifactId>opencv</artifactId>
|
||||
<version>4.7.0-0</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
|
||||
@ -7,11 +7,10 @@ import java.util.Set;
|
||||
import javax.swing.JLabel;
|
||||
|
||||
/**
|
||||
* Globální hotkey listener pro detekci CTRL+ALT+Q.
|
||||
* Na Linuxu funguje i bez fokusu přes nativní polling X11.
|
||||
* Global hotkey listener for detecting CTRL+ALT+Q.
|
||||
* On Linux works without focus via native X11 polling.
|
||||
*/
|
||||
public class GlobalHotkey extends JLabel {
|
||||
private static GlobalHotkey instance;
|
||||
private static final long HOTKEY_COOLDOWN_MS = 700;
|
||||
|
||||
private final GlobalKeyListener globalKeyListener;
|
||||
@ -24,11 +23,11 @@ public class GlobalHotkey extends JLabel {
|
||||
this.onHotkey = onHotkey;
|
||||
this.globalKeyListener = new GlobalKeyListener();
|
||||
|
||||
// Registrace globálního key listeneru pro případy, kdy má aplikace fokus
|
||||
// Register global key listener for cases when application has focus
|
||||
KeyboardFocusManager.getCurrentKeyboardFocusManager()
|
||||
.addKeyEventDispatcher(globalKeyListener);
|
||||
|
||||
// Nativní polling globální hotkey na Linuxu (funguje i bez fokusu)
|
||||
// Native polling of global hotkey on Linux (works without focus)
|
||||
if (isLinux()) {
|
||||
pollingThread = new Thread(() -> {
|
||||
while (running && !Thread.currentThread().isInterrupted()) {
|
||||
@ -40,7 +39,7 @@ public class GlobalHotkey extends JLabel {
|
||||
boolean qPressed = WindowFinder.isKeyPressedGlobally(0x71) || WindowFinder.isKeyPressedGlobally(0x51);
|
||||
|
||||
if (ctrl && alt && qPressed) {
|
||||
triggerHotkey("Globální NATIVNÍ hotkey detekován: CTRL+ALT+Q");
|
||||
triggerHotkey("Global NATIVE hotkey detected: CTRL+ALT+Q");
|
||||
}
|
||||
} catch (InterruptedException e) {
|
||||
Thread.currentThread().interrupt();
|
||||
@ -55,16 +54,9 @@ public class GlobalHotkey extends JLabel {
|
||||
}
|
||||
}
|
||||
|
||||
public static GlobalHotkey create(Runnable onHotkey) {
|
||||
if (instance == null) {
|
||||
instance = new GlobalHotkey(onHotkey);
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
|
||||
public boolean isKeyPressed(int keyCode) {
|
||||
// Na Linuxu pro šipky používáme výhradně nativní globální detekci.
|
||||
// Standardní KeyEventDispatcher se může "zaseknout", pokud okno ztratí fokus během stisku.
|
||||
// On Linux for arrows we use exclusively native global detection.
|
||||
// Standard KeyEventDispatcher may get "stuck" if window loses focus during press.
|
||||
if (isLinux()) {
|
||||
if (keyCode == KeyEvent.VK_DOWN) {
|
||||
try {
|
||||
@ -108,7 +100,7 @@ public class GlobalHotkey extends JLabel {
|
||||
}
|
||||
|
||||
/**
|
||||
* Interní třída pro globální naslouchání na klávesnici
|
||||
* Internal class for global keyboard listening
|
||||
*/
|
||||
private class GlobalKeyListener implements java.awt.KeyEventDispatcher {
|
||||
private Set<Integer> pressedKeys = new HashSet<>();
|
||||
@ -125,14 +117,14 @@ public class GlobalHotkey extends JLabel {
|
||||
// Detekce CTRL+ALT+Q
|
||||
if (e.getKeyCode() == KeyEvent.VK_Q &&
|
||||
e.isControlDown() && e.isAltDown()) {
|
||||
triggerHotkey("Globální hotkey detekován: CTRL+ALT+Q");
|
||||
triggerHotkey("Global hotkey detected: CTRL+ALT+Q");
|
||||
return true; // Konzumovat event
|
||||
}
|
||||
} else if (e.getID() == KeyEvent.KEY_RELEASED) {
|
||||
pressedKeys.remove(e.getKeyCode());
|
||||
}
|
||||
|
||||
return false; // Nepropagovat ostatní eventy
|
||||
return false; // Do not propagate other events
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -15,8 +15,8 @@ import java.util.List;
|
||||
import javax.imageio.ImageIO;
|
||||
|
||||
/**
|
||||
* Automatizační nástroj pro Pokémon GO.
|
||||
* Najde běžící aplikaci, označí všechny Pokémony a stiskne tlačítko Transfer.
|
||||
* Automation tool for Pokémon GO.
|
||||
* Finds running application, selects all Pokémon and clicks Transfer button.
|
||||
*/
|
||||
public class PokemonGoAutomation {
|
||||
|
||||
@ -29,8 +29,8 @@ public class PokemonGoAutomation {
|
||||
private BufferedImage includeTemplate; // Include button template
|
||||
private static final int DELAY_BETWEEN_CLICKS = 100; // ms
|
||||
private static final int DELAY_AFTER_ACTION = 100; // ms
|
||||
private int transferredPokemonCount = 0; // Počet transfernutých pokémonů
|
||||
private Point initialMousePosition = null; // Pozice kurzoru před začátkem automatizace
|
||||
private int transferredPokemonCount = 0; // Count of transferred pokemon
|
||||
private Point initialMousePosition = null; // Cursor position before start of automation
|
||||
private volatile boolean stopRequested = false;
|
||||
|
||||
public PokemonGoAutomation() throws AWTException {
|
||||
@ -41,14 +41,14 @@ public class PokemonGoAutomation {
|
||||
}
|
||||
|
||||
/**
|
||||
* Vrátí počet dosud transfernutých pokémonů
|
||||
* Returns count of pokemon transferred so far
|
||||
*/
|
||||
public int getTransferredCount() {
|
||||
return transferredPokemonCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resetuje počítadlo transfernutých pokémonů
|
||||
* Resets counter of transferred pokemon
|
||||
*/
|
||||
public void resetTransferredCount() {
|
||||
transferredPokemonCount = 0;
|
||||
@ -63,62 +63,62 @@ public class PokemonGoAutomation {
|
||||
}
|
||||
|
||||
/**
|
||||
* Pořídí screenshot oblasti okna
|
||||
* Takes screenshot of window area
|
||||
*/
|
||||
private BufferedImage captureScreen(Rectangle area) {
|
||||
return robot.createScreenCapture(area);
|
||||
}
|
||||
|
||||
/**
|
||||
* Načte templaty pro tlačítka TRANSFER (t1.png) a confirmation (t2.png)
|
||||
* Loads templates for TRANSFER button (t1.png) and confirmation (t2.png)
|
||||
*/
|
||||
private void loadButtonTemplates() {
|
||||
try {
|
||||
String t1Paths = "/t1.png";
|
||||
|
||||
t1Template = ImageIO.read(getClass().getResourceAsStream(t1Paths));
|
||||
System.out.println("✅ Template TRANSFER načten z: " + t1Paths);
|
||||
System.out.println("✅ Template TRANSFER loaded from: " + t1Paths);
|
||||
|
||||
String t2Paths = "/t2.png";
|
||||
|
||||
t2Template = ImageIO.read(getClass().getResourceAsStream(t2Paths));
|
||||
System.out.println("✅ Template Potvrzení načten z: " + t2Paths);
|
||||
System.out.println("✅ Template Confirmation loaded from: " + t2Paths);
|
||||
|
||||
String t3Paths = "/t3.png";
|
||||
|
||||
t3Template = ImageIO.read(getClass().getResourceAsStream(t3Paths));
|
||||
System.out.println("✅ Template Potvrzení načten z: " + t3Paths);
|
||||
System.out.println("✅ Template Confirmation loaded from: " + t3Paths);
|
||||
|
||||
String pok1Paths = "/pok1.png";
|
||||
|
||||
pok1Template = ImageIO.read(getClass().getResourceAsStream(pok1Paths));
|
||||
System.out.println("✅ Template Pokémon načten z: " + pok1Paths);
|
||||
System.out.println("✅ Template Pokémon loaded from: " + pok1Paths);
|
||||
|
||||
String includePaths = "/include.png";
|
||||
|
||||
includeTemplate = ImageIO.read(getClass().getResourceAsStream(includePaths));
|
||||
System.out.println("✅ Template INCLUDE načten z: " + includePaths);
|
||||
System.out.println("✅ Template INCLUDE loaded from: " + includePaths);
|
||||
|
||||
if (t1Template == null) {
|
||||
System.out.println("⚠️ Template t1.png nebyl nalezen");
|
||||
System.out.println("⚠️ Template t1.png not found");
|
||||
}
|
||||
if (t2Template == null) {
|
||||
System.out.println("⚠️ Template t2.png nebyl nalezen");
|
||||
System.out.println("⚠️ Template t2.png not found");
|
||||
}
|
||||
if (pok1Template == null) {
|
||||
System.out.println("⚠️ Template pok1.png nebyl nalezen");
|
||||
System.out.println("⚠️ Template pok1.png not found");
|
||||
}
|
||||
if (includeTemplate == null) {
|
||||
System.out.println("⚠️ Template include.png nebyl nalezen");
|
||||
System.out.println("⚠️ Template include.png not found");
|
||||
}
|
||||
} catch (IOException e) {
|
||||
System.err.println("⚠️ Chyba při načítání templates: " + e.getMessage());
|
||||
System.err.println("⚠️ Error loading templates: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Porovnává template s oblastí v obrázku - jednoduché pixelové porovnání s
|
||||
* optimalizací
|
||||
* Compares template with area in image - simple pixel comparison with
|
||||
* optimization
|
||||
*/
|
||||
private double templateMatch(BufferedImage screenshot, int startX, int startY, BufferedImage template,
|
||||
int tolerance) {
|
||||
@ -152,7 +152,7 @@ public class PokemonGoAutomation {
|
||||
int templateRGB = template.getRGB(x, y);
|
||||
int screenRGB = screenshot.getRGB(startX + x, startY + y);
|
||||
|
||||
// Rozdělit RGB hodnoty
|
||||
// Split RGB values
|
||||
int tR = (templateRGB >> 16) & 0xFF;
|
||||
int tG = (templateRGB >> 8) & 0xFF;
|
||||
int tB = templateRGB & 0xFF;
|
||||
@ -161,7 +161,7 @@ public class PokemonGoAutomation {
|
||||
int sG = (screenRGB >> 8) & 0xFF;
|
||||
int sB = screenRGB & 0xFF;
|
||||
|
||||
// Porovnat barvy - zvýšená tolerance pro lepší detekci
|
||||
// Compare colors - increased tolerance for better detection
|
||||
int rDiff = Math.abs(tR - sR);
|
||||
int gDiff = Math.abs(tG - sG);
|
||||
int bDiff = Math.abs(tB - sB);
|
||||
@ -169,7 +169,7 @@ public class PokemonGoAutomation {
|
||||
if (rDiff < tolerance && gDiff < tolerance && bDiff < tolerance) {
|
||||
matchingPixels++;
|
||||
|
||||
// Early exit - pokud jsme nedosáhli minima, skončit
|
||||
// Early exit - if we have not reached minimum, stop
|
||||
if (matchingPixels < requiredMatch / 2 && (y * tWidth + x) > (totalPixels / 2)) {
|
||||
return 0.0;
|
||||
}
|
||||
@ -177,15 +177,15 @@ public class PokemonGoAutomation {
|
||||
}
|
||||
}
|
||||
|
||||
// Vrátit procentuální shodu (0.0-1.0)
|
||||
// Return percentage match (0.0-1.0)
|
||||
return (double) matchingPixels / totalPixels;
|
||||
}
|
||||
|
||||
/**
|
||||
* Najde a vrátí pozici potvrzovacího tlačítka bez kliknutí
|
||||
* Finds and returns position of confirmation button without clicking
|
||||
*/
|
||||
private Point findConfirmTransferButtonPosition(BufferedImage template, int tolerance) {
|
||||
System.out.println("Hledám potvrzovací TRANSFER tlačítko pomocí template matchingu...");
|
||||
System.out.println("Looking for confirm TRANSFER button using template matching...");
|
||||
|
||||
if (shouldStop()) {
|
||||
return null;
|
||||
@ -196,7 +196,7 @@ public class PokemonGoAutomation {
|
||||
int tWidth = template.getWidth();
|
||||
int tHeight = template.getHeight();
|
||||
|
||||
// Dialog je obvykle v horní polovině po TRANSFER kliknutí
|
||||
// Dialog is usually in upper half after TRANSFER click
|
||||
int searchStartY = (int) (windowBounds.height * 0.40);
|
||||
int searchEndY = (int) (windowBounds.height * 0.75);
|
||||
|
||||
@ -204,12 +204,12 @@ public class PokemonGoAutomation {
|
||||
int bestX = 0;
|
||||
int bestY = 0;
|
||||
|
||||
// Skenovat Y-ové pozice s větším krokem - 15px místo 5px pro zrychlení
|
||||
// Scan Y positions with larger step - 15px instead of 5px for speed
|
||||
for (int y = searchStartY; y <= searchEndY - tHeight; y += 15) {
|
||||
if (shouldStop()) {
|
||||
return null;
|
||||
}
|
||||
// Skenovat také X pozice pro nalezení středu shody
|
||||
// Also scan X positions to find center of match
|
||||
for (int x = 0; x <= windowBounds.width - tWidth; x += 30) {
|
||||
double score = templateMatch(screenshot, x, y, template, tolerance);
|
||||
|
||||
@ -225,17 +225,17 @@ public class PokemonGoAutomation {
|
||||
Point bestMatch = new Point(
|
||||
windowBounds.x + bestX + (tWidth / 2),
|
||||
windowBounds.y + bestY + (tHeight / 2));
|
||||
System.out.println("✅ Nalezeno potvrzovací tlačítko (template match) na: " + bestMatch + " (shoda: "
|
||||
System.out.println("✅ Found confirmation button (template match) at: " + bestMatch + " (match: "
|
||||
+ String.format("%.1f", bestScore * 100) + "%)");
|
||||
return bestMatch;
|
||||
}
|
||||
|
||||
System.out.println("Template nenalezen");
|
||||
System.out.println("Template not found");
|
||||
return null;
|
||||
}
|
||||
|
||||
private Point findIncludeButtonPosition(int tolerance) {
|
||||
System.out.println("Hledám tlačítko INCLUDE pomocí template matchingu (include.png)...");
|
||||
System.out.println("Looking for INCLUDE button using template matching (include.png)...");
|
||||
|
||||
if (shouldStop()) {
|
||||
return null;
|
||||
@ -246,7 +246,7 @@ public class PokemonGoAutomation {
|
||||
int tWidth = includeTemplate.getWidth();
|
||||
int tHeight = includeTemplate.getHeight();
|
||||
|
||||
// Dialog je obvykle v horní polovině po TRANSFER kliknutí
|
||||
// Dialog is usually in upper half after TRANSFER click
|
||||
int searchStartY = (int) (windowBounds.height * 0.40);
|
||||
int searchEndY = (int) (windowBounds.height * 0.75);
|
||||
|
||||
@ -254,12 +254,12 @@ public class PokemonGoAutomation {
|
||||
int bestX = 0;
|
||||
int bestY = 0;
|
||||
|
||||
// Skenovat Y-ové pozice s větším krokem - 15px místo 5px pro zrychlení
|
||||
// Scan Y positions with larger step - 15px instead of 5px for speed
|
||||
for (int y = searchStartY; y <= searchEndY - tHeight; y += 15) {
|
||||
if (shouldStop()) {
|
||||
return null;
|
||||
}
|
||||
// Skenovat také X pozice pro nalezení středu shody
|
||||
// Also scan X positions to find center of match
|
||||
for (int x = 0; x <= windowBounds.width - tWidth; x += 30) {
|
||||
double score = templateMatch(screenshot, x, y, includeTemplate, tolerance);
|
||||
|
||||
@ -275,17 +275,17 @@ public class PokemonGoAutomation {
|
||||
Point bestMatch = new Point(
|
||||
windowBounds.x + bestX + (tWidth / 2),
|
||||
windowBounds.y + bestY + (tHeight / 2));
|
||||
System.out.println("✅ Nalezeno tlačítko INCLUDE (template match) na: " + bestMatch + " (shoda: "
|
||||
System.out.println("✅ Found INCLUDE button (template match) at: " + bestMatch + " (match: "
|
||||
+ String.format("%.1f", bestScore * 100) + "%)");
|
||||
return bestMatch;
|
||||
}
|
||||
|
||||
System.out.println("Template nenalezen");
|
||||
System.out.println("Template not found");
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Najde okno s názvem obsahujícím "Pokémon" nebo "Pokemon"
|
||||
* Finds window with name containing "Pokémon" or "Pokemon"
|
||||
*/
|
||||
public boolean findPokemonGoWindow() {
|
||||
try {
|
||||
@ -293,15 +293,15 @@ public class PokemonGoAutomation {
|
||||
|
||||
if (bounds != null && bounds.width > 0 && bounds.height > 0) {
|
||||
windowBounds = bounds;
|
||||
System.out.println("Nalezeno okno: " + windowBounds);
|
||||
System.out.println("Window found: " + windowBounds);
|
||||
return true;
|
||||
}
|
||||
|
||||
System.out.println("Okno Pokémon GO nebylo nalezeno.");
|
||||
System.out.println("Pokémon GO window not found.");
|
||||
return false;
|
||||
|
||||
} catch (Exception e) {
|
||||
System.err.println("Chyba při hledání okna: " + e.getMessage());
|
||||
System.err.println("Error finding window: " + e.getMessage());
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
@ -312,12 +312,12 @@ public class PokemonGoAutomation {
|
||||
*/
|
||||
public void activateWindow() {
|
||||
try {
|
||||
// Kliknutí na horní panel okna (title bar) pro aktivaci
|
||||
// Title bar je obvykle 30-40px vysoký v horní části okna
|
||||
// Click on top panel of window (title bar) for activation
|
||||
// Title bar is usually 30-40px high at top of window
|
||||
int centerX = windowBounds.x + windowBounds.width / 2;
|
||||
int titleBarY = windowBounds.y - 15; // 15px od vrcholu okna = horní panel
|
||||
int titleBarY = windowBounds.y - 15; // 15px from top of window = top panel
|
||||
|
||||
System.out.println("Aktivuji okno kliknutím na title bar: (" + centerX + ", " + titleBarY + ")");
|
||||
System.out.println("Activating window by clicking title bar: (" + centerX + ", " + titleBarY + ")");
|
||||
|
||||
robot.mouseMove(centerX, titleBarY);
|
||||
robot.delay(200);
|
||||
@ -325,26 +325,26 @@ public class PokemonGoAutomation {
|
||||
robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK);
|
||||
robot.delay(DELAY_AFTER_ACTION);
|
||||
|
||||
System.out.println("Okno aktivováno");
|
||||
System.out.println("Window activated");
|
||||
} catch (Exception e) {
|
||||
System.err.println("Chyba při aktivaci okna: " + e.getMessage());
|
||||
System.err.println("Error activating window: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Stiskne tlačítko Transfer na spodní části obrazovky
|
||||
* Clicks Transfer button at bottom of screen
|
||||
*/
|
||||
public void clickTransferButton() {
|
||||
if (shouldStop()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Použít detekci tlačítka
|
||||
// Use button detection
|
||||
// Point buttonPos = findTransferButtonPosition();
|
||||
Point buttonPos = getAbsolutePoint(300, 1156);
|
||||
|
||||
if (buttonPos == null) {
|
||||
System.err.println("Tlačítko TRANSFER nebylo nalezeno!");
|
||||
System.err.println("TRANSFER button not found!");
|
||||
return;
|
||||
}
|
||||
|
||||
@ -354,26 +354,26 @@ public class PokemonGoAutomation {
|
||||
robot.mousePress(InputEvent.BUTTON1_DOWN_MASK);
|
||||
robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK);
|
||||
|
||||
System.out.println("Tlačítko TRANSFER stisknuto!");
|
||||
System.out.println("TRANSFER button clicked!");
|
||||
robot.delay(DELAY_AFTER_ACTION);
|
||||
}
|
||||
|
||||
/**
|
||||
* Potvrdí transfer (pokud je potřeba potvrzovací dialog)
|
||||
* Confirms transfer (if confirmation dialog is needed)
|
||||
*/
|
||||
public void clickConfirmTransferButton(BufferedImage template, int tolerance) {
|
||||
System.out.println("Potvrzuji transfer - hledám confirmation button...");
|
||||
System.out.println("Confirming transfer - looking for confirmation button...");
|
||||
|
||||
if (shouldStop()) {
|
||||
return;
|
||||
}
|
||||
|
||||
robot.delay(100); // Počkat na zobrazení dialogu
|
||||
robot.delay(100); // Wait for dialog to appear
|
||||
|
||||
// Najít zelené TRANSFER tlačítko v potvrzovacím dialogu
|
||||
// Find green TRANSFER button in confirmation dialog
|
||||
Point buttonPos = findConfirmTransferButtonPosition(template, tolerance);
|
||||
if (buttonPos == null) {
|
||||
System.out.println("Potvrzovací tlačítko nebylo nalezeno, přeskočím potvrzení.");
|
||||
System.out.println("Confirmation button not found, skipping confirmation.");
|
||||
return;
|
||||
}
|
||||
|
||||
@ -383,23 +383,23 @@ public class PokemonGoAutomation {
|
||||
robot.mousePress(InputEvent.BUTTON1_DOWN_MASK);
|
||||
robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK);
|
||||
|
||||
System.out.println("Transfer finálně potvrzen!");
|
||||
System.out.println("Transfer finally confirmed!");
|
||||
robot.delay(DELAY_AFTER_ACTION);
|
||||
}
|
||||
|
||||
public boolean clickIncludeButton(int tolerance) {
|
||||
System.out.println("Potvrzuji transfer - hledám include.png (confirmation button)...");
|
||||
System.out.println("Confirming transfer - looking for include.png (confirmation button)...");
|
||||
|
||||
if (shouldStop()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
robot.delay(100); // Počkat na zobrazení dialogu
|
||||
robot.delay(100); // Wait for dialog to appear
|
||||
|
||||
// Najít zelené INCLUDE tlačítko v potvrzovacím dialogu
|
||||
// Find green INCLUDE button in confirmation dialog
|
||||
Point buttonPos = findIncludeButtonPosition(tolerance);
|
||||
if (buttonPos == null) {
|
||||
System.out.println("INCLUDE tlačítko nebylo nalezeno, přeskočím potvrzení.");
|
||||
System.out.println("INCLUDE button not found, skipping confirmation.");
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -409,79 +409,79 @@ public class PokemonGoAutomation {
|
||||
robot.mousePress(InputEvent.BUTTON1_DOWN_MASK);
|
||||
robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK);
|
||||
|
||||
System.out.println("Transfer finálně potvrzen!");
|
||||
System.out.println("Transfer finally confirmed!");
|
||||
robot.delay(DELAY_AFTER_ACTION);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Spustí Transfer automatizaci s konkrétním počtem pokémonů
|
||||
* Starts Transfer automation with specific number of pokemon
|
||||
*
|
||||
* @param totalPokemonCount Celkový počet pokémonů k transferu
|
||||
* @param delaySeconds Čekání mezi iteracemi (v sekundách)
|
||||
* @param totalPokemonCount Total number of pokemon to transfer
|
||||
* @param delaySeconds Delay between iterations (in seconds)
|
||||
*/
|
||||
public void runWithCount(int totalPokemonCount, int delaySeconds) {
|
||||
System.out.println("Spouštím Transfer automatizaci - Počet pokémonů: " + totalPokemonCount + ", Čekání: "
|
||||
System.out.println("Starting Transfer automation - Pokémon count: " + totalPokemonCount + ", Delay: "
|
||||
+ delaySeconds + "s");
|
||||
|
||||
// Uložit aktuální pozici kurzoru
|
||||
// Save current cursor position
|
||||
PointerInfo pointerInfo = MouseInfo.getPointerInfo();
|
||||
initialMousePosition = pointerInfo != null ? pointerInfo.getLocation() : null;
|
||||
if (initialMousePosition != null) {
|
||||
System.out.println("Uložena počáteční pozice kurzoru: " + initialMousePosition);
|
||||
System.out.println("Initial cursor position saved: " + initialMousePosition);
|
||||
}
|
||||
|
||||
if (!findPokemonGoWindow()) {
|
||||
System.err.println("Nepodařilo se najít okno Pokémon GO!");
|
||||
System.err.println("Failed to find Pokémon GO window!");
|
||||
return;
|
||||
}
|
||||
|
||||
activateWindow();
|
||||
|
||||
System.out.println("Čekám 1 sekundu před začátkem...");
|
||||
System.out.println("Waiting 1 second before start...");
|
||||
robot.delay(1000);
|
||||
|
||||
int transferredCount = 0;
|
||||
|
||||
// Transferovat dokud nedosáhneme požadovaného počtu
|
||||
// Transfer until we reach desired count
|
||||
try {
|
||||
while (transferredCount < totalPokemonCount) {
|
||||
// Kontrola přerušení
|
||||
// Check interruption
|
||||
if (shouldStop()) {
|
||||
System.out.println("\n⚠️ Automatizace byla přerušena!");
|
||||
System.out.println("\n⚠️ Automation was interrupted!");
|
||||
return;
|
||||
}
|
||||
|
||||
int pokemonThisRound = Math.min(12, totalPokemonCount - transferredCount);
|
||||
|
||||
System.out.println(
|
||||
"\n=== Iterace " + (transferredCount / 9 + 1) + " - Transferuji maximálně " + pokemonThisRound
|
||||
+ " pokémonů ===");
|
||||
"\n=== Iteration " + (transferredCount / 9 + 1) + " - Transferring max " + pokemonThisRound
|
||||
+ " pokemon ===");
|
||||
|
||||
// Vybrat pokémony a získat skutečný počet vybraných
|
||||
// Select pokemon and get actual number selected
|
||||
int actualTransferredCount = selectAllPokemonCount(pokemonThisRound);
|
||||
|
||||
if (shouldStop()) {
|
||||
System.out.println("\n⚠️ Automatizace byla přerušena během označování!");
|
||||
System.out.println("\n⚠️ Automation was interrupted during selection!");
|
||||
return;
|
||||
}
|
||||
|
||||
System.out.println("Čekám na TRANSFER...");
|
||||
System.out.println("Waiting for TRANSFER...");
|
||||
clickTransferButton();
|
||||
|
||||
if (shouldStop()) {
|
||||
System.out.println("\n⚠️ Automatizace byla přerušena po kliknutí na TRANSFER!");
|
||||
System.out.println("\n⚠️ Automation was interrupted after clicking TRANSFER!");
|
||||
return;
|
||||
}
|
||||
|
||||
System.out.println("Čekám na INCLUDE dialog...");
|
||||
System.out.println("Waiting for INCLUDE dialog...");
|
||||
robot.delay(100);
|
||||
if (clickIncludeButton(110)) {
|
||||
System.out.println("Čekám na potvrzovací dialog t3...");
|
||||
System.out.println("Waiting for confirmation dialog t3...");
|
||||
robot.delay(100);
|
||||
clickConfirmTransferButton(t3Template, 70);
|
||||
} else {
|
||||
System.out.println("Čekám na potvrzovací dialog t2...");
|
||||
System.out.println("Waiting for confirmation dialog t2...");
|
||||
robot.delay(100);
|
||||
clickConfirmTransferButton(t2Template, 70);
|
||||
}
|
||||
@ -489,17 +489,17 @@ public class PokemonGoAutomation {
|
||||
transferredCount += actualTransferredCount;
|
||||
transferredPokemonCount += actualTransferredCount;
|
||||
|
||||
System.out.println("Transferováno v této iteraci: " + actualTransferredCount + " pokémonů (celkem: "
|
||||
System.out.println("Transferred in this iteration: " + actualTransferredCount + "pokemon (total: "
|
||||
+ transferredCount + ")");
|
||||
|
||||
// Pokud ještě zbývá co transferovat, počkat
|
||||
// If there is still something to transfer, wait
|
||||
if (transferredCount < totalPokemonCount) {
|
||||
System.out.println("Přestávka: " + delaySeconds + " sekund...");
|
||||
// Čekat s kontrolou přerušení
|
||||
System.out.println("Break: " + delaySeconds + " seconds...");
|
||||
// Wait with checking interruption
|
||||
long endTime = System.currentTimeMillis() + (delaySeconds * 1000L);
|
||||
while (System.currentTimeMillis() < endTime) {
|
||||
if (shouldStop()) {
|
||||
System.out.println("\n⚠️ Automatizace byla přerušena během přestávky!");
|
||||
System.out.println("\n⚠️ Automation was interrupted during break!");
|
||||
break;
|
||||
}
|
||||
robot.delay(100);
|
||||
@ -511,48 +511,48 @@ public class PokemonGoAutomation {
|
||||
if (initialMousePosition != null) {
|
||||
try {
|
||||
robot.mouseMove(initialMousePosition.x, initialMousePosition.y);
|
||||
System.out.println("Kurzor vrácen na počáteční pozici: " + initialMousePosition);
|
||||
System.out.println("Cursor returned to initial position: " + initialMousePosition);
|
||||
} catch (Exception e) {
|
||||
System.err.println("Chyba při obnovení pozice kurzoru: " + e.getMessage());
|
||||
System.err.println("Error restoring cursor position: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
System.out.println("\n✅ Transfer automatizace dokončena! Transferováno: " + transferredCount + " pokémonů");
|
||||
System.out.println("\n✅ Transfer automation complete! Transferred: " + transferredCount + "pokemon");
|
||||
}
|
||||
|
||||
/**
|
||||
* Označí konkrétní počet pokémonů
|
||||
* Selects specific number of pokemon
|
||||
*
|
||||
* @return Skutečný počet vybraných pokémonů
|
||||
* @return Actual number of selected pokemon
|
||||
*/
|
||||
private int selectAllPokemonCount(int count) {
|
||||
System.out.println("Začínám označovat " + count + " pokémonů (pouze template matching)...");
|
||||
System.out.println("Starting to select " + count + "pokemon (template matching only)...");
|
||||
|
||||
List<Point> positions = getPossitionsAbsolute();
|
||||
|
||||
int maxPokemon = Math.min(count, positions.size());
|
||||
System.out.println("Budu označovat " + maxPokemon + " pokémonů...");
|
||||
System.out.println("Will select " + maxPokemon + "pokemon...");
|
||||
|
||||
for (int i = 0; i < maxPokemon; i++) {
|
||||
if (shouldStop()) {
|
||||
System.out.println("Označování přerušeno.");
|
||||
System.out.println("Selection interrupted.");
|
||||
return i;
|
||||
}
|
||||
|
||||
Point pos = positions.get(i);
|
||||
System.out.println("Klikám na Pokémona " + (i + 1) + "/" + maxPokemon + " na pozici: " + pos);
|
||||
System.out.println("Clicking on Pokémon " + (i + 1) + "/" + maxPokemon + " at position: " + pos);
|
||||
|
||||
robot.mouseMove(pos.x, pos.y);
|
||||
|
||||
if (i == 0) {
|
||||
System.out.println(" -> Dlouhé podržení (aktivace multi-select)");
|
||||
System.out.println(" -> Long press (activate multi-select)");
|
||||
robot.mousePress(InputEvent.BUTTON1_DOWN_MASK);
|
||||
robot.delay(700);
|
||||
robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK);
|
||||
robot.delay(DELAY_AFTER_ACTION);
|
||||
} else {
|
||||
System.out.println(" -> Normální klik");
|
||||
System.out.println(" -> Normal click");
|
||||
robot.mousePress(InputEvent.BUTTON1_DOWN_MASK);
|
||||
robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK);
|
||||
}
|
||||
@ -560,8 +560,8 @@ public class PokemonGoAutomation {
|
||||
robot.delay(DELAY_BETWEEN_CLICKS);
|
||||
}
|
||||
|
||||
System.out.println("Označeno " + maxPokemon + " pokémonů!");
|
||||
System.out.println("Čekám před kliknutím na TRANSFER...");
|
||||
System.out.println("Selected " + maxPokemon + "pokemon!");
|
||||
System.out.println("Waiting before clicking TRANSFER...");
|
||||
robot.delay(800);
|
||||
|
||||
return maxPokemon;
|
||||
@ -589,11 +589,11 @@ public class PokemonGoAutomation {
|
||||
}
|
||||
|
||||
/**
|
||||
* Převede relativní pozici v okně (0.0-1.0) na absolutní souřadnice obrazovky
|
||||
* Converts relative position in window (0.0-1.0) to absolute screen coordinates
|
||||
*
|
||||
* @param relativeX Relativní X pozice (0.0 = levý okraj, 1.0 = pravý okraj)
|
||||
* @param relativeY Relativní Y pozice (0.0 = horní okraj, 1.0 = dolní okraj)
|
||||
* @return Absolutní pozice na obrazovce
|
||||
* @param relativeX Relative X position (0.0 = left edge, 1.0 = right edge)
|
||||
* @param relativeY Relative Y position (0.0 = top edge, 1.0 = bottom edge)
|
||||
* @return Absolute position on screen
|
||||
*/
|
||||
private Point getAbsolutePoint(int relativeX, int relativeY) {
|
||||
int xCorrection = 0;
|
||||
@ -604,14 +604,14 @@ public class PokemonGoAutomation {
|
||||
}
|
||||
|
||||
/**
|
||||
* Vyčistí všechny prostředky používané automatizací
|
||||
* Volat po skončení automatizace
|
||||
* Cleans up all resources used by automation
|
||||
* Call after automation finishes
|
||||
*/
|
||||
public void cleanup() {
|
||||
try {
|
||||
System.out.println("Čištění prostředků automatizace...");
|
||||
System.out.println("Cleaning up automation resources...");
|
||||
|
||||
// Uvolnit reference na obrázky
|
||||
// Release references to images
|
||||
t1Template = null;
|
||||
t2Template = null;
|
||||
t3Template = null;
|
||||
@ -619,16 +619,16 @@ public class PokemonGoAutomation {
|
||||
includeTemplate = null;
|
||||
windowBounds = null;
|
||||
|
||||
// Explicitně vyvolat garbage collector
|
||||
// Explicitly invoke garbage collector
|
||||
System.gc();
|
||||
System.out.println("Prostředky automatizace vyčištěny");
|
||||
System.out.println("Automation resources cleaned");
|
||||
} catch (Exception e) {
|
||||
System.err.println("Chyba při čištění prostředků: " + e.getMessage());
|
||||
System.err.println("Error cleaning up resources: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
System.out.println("=== Pokémon GO Automatizační Nástroj ===");
|
||||
System.out.println("Ujistěte se, že je aplikace Pokémon GO spuštěná...");
|
||||
System.out.println("=== Pokémon GO Automation Tool ===");
|
||||
System.out.println("Make sure Pokémon GO is running...");
|
||||
}
|
||||
}
|
||||
|
||||
@ -11,8 +11,8 @@ import java.io.*;
|
||||
import java.util.Properties;
|
||||
|
||||
/**
|
||||
* Jednoduchá GUI aplikace pro Pokémon GO automatizaci
|
||||
* S kartami pro jednotlivé automatizace
|
||||
* Simple GUI application for Pokémon GO automation
|
||||
* With cards for individual automations
|
||||
*/
|
||||
public class PokemonGoGUI extends JFrame {
|
||||
|
||||
@ -23,7 +23,7 @@ public class PokemonGoGUI extends JFrame {
|
||||
private volatile boolean shouldStop = false;
|
||||
private PokemonGoAutomation automation;
|
||||
private Thread automationThread;
|
||||
private int totalTransferredCount = 0; // Celkový počet transfernutých pokémonů
|
||||
private int totalTransferredCount = 0; // Total count of transferred pokemon
|
||||
|
||||
private volatile boolean autoClickRunning = false;
|
||||
private GlobalHotkey globalHotkey;
|
||||
@ -49,13 +49,13 @@ public class PokemonGoGUI extends JFrame {
|
||||
private static final int CARD_MAX_WIDTH = 760;
|
||||
|
||||
public PokemonGoGUI() {
|
||||
setTitle("Pokémon GO Automatizace v" + VERSION);
|
||||
setTitle("Pokémon GO Automation v" + VERSION);
|
||||
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
|
||||
|
||||
// Načtení uložených nastavení
|
||||
// Load saved settings
|
||||
loadSettings();
|
||||
|
||||
// Obnovení velikosti a pozice okna
|
||||
// Restore window size and position
|
||||
int width = Integer.parseInt(settings.getProperty("window.width", "900"));
|
||||
int height = Integer.parseInt(settings.getProperty("window.height", "680"));
|
||||
int x = Integer.parseInt(settings.getProperty("window.x", "-1"));
|
||||
@ -72,7 +72,7 @@ public class PokemonGoGUI extends JFrame {
|
||||
setResizable(true);
|
||||
setBackground(PANEL_BACKGROUND);
|
||||
|
||||
// Uložení nastavení při zavření okna
|
||||
// Save settings on window close
|
||||
addWindowListener(new java.awt.event.WindowAdapter() {
|
||||
@Override
|
||||
public void windowClosing(WindowEvent e) {
|
||||
@ -80,24 +80,24 @@ public class PokemonGoGUI extends JFrame {
|
||||
}
|
||||
});
|
||||
|
||||
// Hlavní panel
|
||||
// Main panel
|
||||
JPanel mainPanel = new JPanel(new BorderLayout(10, 10));
|
||||
mainPanel.setBorder(BorderFactory.createEmptyBorder(15, 15, 15, 15));
|
||||
mainPanel.setBackground(PANEL_BACKGROUND);
|
||||
|
||||
// Horní panel se stavem
|
||||
JLabel stateLabel = new JLabel("Stav:");
|
||||
// Top panel with status
|
||||
JLabel stateLabel = new JLabel("Status:");
|
||||
stateLabel.setFont(HEADER_FONT);
|
||||
stateLabel.setForeground(new Color(70, 70, 70));
|
||||
statusLabel = new JLabel("Připraven k spuštění");
|
||||
statusLabel = new JLabel("Ready to start");
|
||||
statusLabel.setFont(BODY_FONT);
|
||||
statusLabel.setForeground(STATUS_DEFAULT);
|
||||
JLabel versionLabel = new JLabel("verze " + VERSION);
|
||||
JLabel versionLabel = new JLabel("v" + VERSION);
|
||||
versionLabel.setFont(SMALL_FONT);
|
||||
versionLabel.setForeground(new Color(120, 120, 120));
|
||||
|
||||
stopButton = new JButton("⏹ ZASTAVIT (CTRL+ALT+Q)");
|
||||
stopButton.setPreferredSize(new Dimension(150, 30));
|
||||
stopButton = new JButton("⏹ STOP (CTRL+ALT+Q)");
|
||||
stopButton.setPreferredSize(new Dimension(220, 30));
|
||||
styleButton(stopButton, PRIMARY_RED, Color.WHITE, SMALL_FONT);
|
||||
stopButton.setEnabled(false);
|
||||
stopButton.addActionListener(new ActionListener() {
|
||||
@ -111,7 +111,7 @@ public class PokemonGoGUI extends JFrame {
|
||||
stopPanel.setOpaque(false);
|
||||
stopPanel.add(stopButton);
|
||||
|
||||
JLabel titleLabel = new JLabel("Pokémon GO Automatizace");
|
||||
JLabel titleLabel = new JLabel("Pokémon GO Automation");
|
||||
titleLabel.setFont(TITLE_FONT);
|
||||
titleLabel.setForeground(new Color(30, 30, 30));
|
||||
|
||||
@ -133,7 +133,7 @@ public class PokemonGoGUI extends JFrame {
|
||||
headerPanel.add(Box.createVerticalStrut(6));
|
||||
headerPanel.add(statusRow);
|
||||
|
||||
// Panel s kartami automatizací
|
||||
// Panel with automation cards
|
||||
JPanel cardsContainer = new JPanel(new GridBagLayout());
|
||||
cardsContainer.setBackground(PANEL_BACKGROUND);
|
||||
cardsContainer.setBorder(BorderFactory.createEmptyBorder(8, 8, 8, 8));
|
||||
@ -145,14 +145,14 @@ public class PokemonGoGUI extends JFrame {
|
||||
gbc.anchor = GridBagConstraints.NORTH;
|
||||
gbc.insets = new Insets(0, 0, 12, 0);
|
||||
|
||||
// Karta 1: Transfer automatizace
|
||||
// Card 1: Transfer automation
|
||||
JPanel transferCard = createAutomationCard(
|
||||
"🔄 TRANSFER AUTOMATIZACE",
|
||||
"Hledá Pokémony, označí je a stiskne Transfer",
|
||||
"🔄 TRANSFER AUTOMATION",
|
||||
"Finds Pokémon, selects them, and clicks Transfer",
|
||||
null
|
||||
);
|
||||
|
||||
// Najít START tlačítko - je v EAST pozici BorderLayoutu
|
||||
// Find START button - in EAST position of BorderLayout
|
||||
JButton startBtnTransfer = findStartButton(transferCard);
|
||||
|
||||
if (startBtnTransfer != null) {
|
||||
@ -169,14 +169,14 @@ public class PokemonGoGUI extends JFrame {
|
||||
gbc.gridy++;
|
||||
gbc.insets = new Insets(0, 0, 12, 0);
|
||||
|
||||
// Karta 2: Autoklik
|
||||
// Card 2: Autoclick
|
||||
JPanel autoClickCard = createAutomationCard(
|
||||
"🖱️ AUTOKLIK",
|
||||
"Automaticky klikuje na zadanou pozici",
|
||||
"🖱️ AUTOCLICK",
|
||||
"Automatically clicks at a given position",
|
||||
null
|
||||
);
|
||||
|
||||
// Najít START tlačítko
|
||||
// Find START button
|
||||
JButton startBtnAutoClick = findStartButton(autoClickCard);
|
||||
|
||||
if (startBtnAutoClick != null) {
|
||||
@ -228,7 +228,7 @@ public class PokemonGoGUI extends JFrame {
|
||||
));
|
||||
logScrollPane.getViewport().setBackground(new Color(247, 247, 247));
|
||||
|
||||
JButton clearLogButton = new JButton("🗑 Vyčistit log");
|
||||
JButton clearLogButton = new JButton("🗑 Clear log");
|
||||
clearLogButton.setPreferredSize(new Dimension(140, 28));
|
||||
styleButton(clearLogButton, ACCENT_BLUE, Color.WHITE, SMALL_FONT);
|
||||
clearLogButton.addActionListener(new ActionListener() {
|
||||
@ -255,13 +255,13 @@ public class PokemonGoGUI extends JFrame {
|
||||
splitPane.setBorder(null);
|
||||
splitPane.setBackground(PANEL_BACKGROUND);
|
||||
|
||||
// Přidání do hlavního panelu
|
||||
// Add to main panel
|
||||
mainPanel.add(headerPanel, BorderLayout.NORTH);
|
||||
mainPanel.add(splitPane, BorderLayout.CENTER);
|
||||
|
||||
add(mainPanel);
|
||||
|
||||
// Klávesová zkratka: Ctrl+Alt+Q pro zastavení
|
||||
// Keyboard shortcut: Ctrl+Alt+Q to stop
|
||||
KeyStroke hotkey = KeyStroke.getKeyStroke(KeyEvent.VK_Q, KeyEvent.CTRL_DOWN_MASK | KeyEvent.ALT_DOWN_MASK);
|
||||
getRootPane().getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(hotkey, "stopAutomationAction");
|
||||
getRootPane().getActionMap().put("stopAutomationAction", new AbstractAction() {
|
||||
@ -273,7 +273,7 @@ public class PokemonGoGUI extends JFrame {
|
||||
}
|
||||
});
|
||||
|
||||
// Globální hotkey (funguje i když okno není fokusované)
|
||||
// Global hotkey (works even when window is not focused)
|
||||
globalHotkey = new GlobalHotkey(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
@ -284,17 +284,17 @@ public class PokemonGoGUI extends JFrame {
|
||||
});
|
||||
mainPanel.add(globalHotkey, BorderLayout.SOUTH);
|
||||
|
||||
// Přesměrování System.out a System.err do GUI
|
||||
// Redirect System.out and System.err to GUI
|
||||
redirectSystemStreams();
|
||||
|
||||
logArea.append("=== Pokémon GO Automatizace ===\n\n");
|
||||
logArea.append("Vyberte jednu z automatizací a klikněte na tlačítko START.\n");
|
||||
logArea.append("Ujistěte se, že je aplikace Pokémon GO spuštěná.\n");
|
||||
logArea.append("Pro zastavení stiskněte Ctrl+Alt+Q nebo klikněte ZASTAVIT.\n\n");
|
||||
logArea.append("=== Pokémon GO Automation ===\n\n");
|
||||
logArea.append("Select an automation and click START.\n");
|
||||
logArea.append("Make sure Pokémon GO is running.\n");
|
||||
logArea.append("To stop, press Ctrl+Alt+Q or click STOP.\n\n");
|
||||
}
|
||||
|
||||
/**
|
||||
* Vytvoří kartu automatizace s nastavením
|
||||
* Create automation card with settings
|
||||
*/
|
||||
private JPanel createAutomationCard(String title, String description, ActionListener startAction) {
|
||||
JPanel card = new JPanel(new BorderLayout(12, 12));
|
||||
@ -303,7 +303,7 @@ public class PokemonGoGUI extends JFrame {
|
||||
BorderFactory.createLineBorder(CARD_BORDER_COLOR, 1),
|
||||
BorderFactory.createEmptyBorder(8, 8, 8, 8)
|
||||
));
|
||||
card.setMaximumSize(new Dimension(CARD_MAX_WIDTH, 160));
|
||||
card.setMaximumSize(new Dimension(Integer.MAX_VALUE, 160));
|
||||
card.setPreferredSize(new Dimension(CARD_MAX_WIDTH, 160));
|
||||
card.setAlignmentX(Component.CENTER_ALIGNMENT);
|
||||
JPanel infoPanel = new JPanel();
|
||||
@ -330,9 +330,9 @@ public class PokemonGoGUI extends JFrame {
|
||||
centerPanel.setOpaque(true);
|
||||
|
||||
if (title.contains("TRANSFER")) {
|
||||
// Načíst hodnotu a zajistit, že je v platném rozsahu nebo v seznamu povolených hodnot
|
||||
// Load value and ensure it is in valid range or in list of allowed values
|
||||
int savedCount = Integer.parseInt(settings.getProperty("transfer.count", "12"));
|
||||
// Povolené hodnoty: 1, 3, 6, 12, 24, 36, 48, 60, 72, 84, 96
|
||||
// Allowed values: 1, 3, 6, 12, 24, 36, 48, 60, 72, 84, 96
|
||||
int[] validCounts = {1, 3, 6, 12, 24, 36, 48, 60, 72, 84, 96};
|
||||
boolean isValid = false;
|
||||
for (int count : validCounts) {
|
||||
@ -342,10 +342,10 @@ public class PokemonGoGUI extends JFrame {
|
||||
}
|
||||
}
|
||||
if (!isValid) {
|
||||
savedCount = 12; // Nastavit na výchozí, pokud není v seznamu povolených
|
||||
savedCount = 12; // Set to default if not in allowed list
|
||||
}
|
||||
|
||||
// Vytvořit dropdown s hodnotami 1, 3, 6, 12, 24, 36, ..., 96
|
||||
// Create dropdown with values 1, 3, 6, 12, 24, 36, ..., 96
|
||||
Integer[] counts = {1, 3, 6, 12, 24, 36, 48, 60, 72, 84, 96};
|
||||
countComboBox = new JComboBox<>(counts);
|
||||
countComboBox.setSelectedItem(savedCount);
|
||||
@ -360,9 +360,9 @@ public class PokemonGoGUI extends JFrame {
|
||||
card.putClientProperty("countComboBox", countComboBox);
|
||||
card.putClientProperty("delaySpinner", delaySpinner);
|
||||
|
||||
centerPanel.add(createFieldPanel("Počet:", countComboBox));
|
||||
centerPanel.add(createFieldPanel("Čekání (s):", delaySpinner));
|
||||
} else if (title.contains("AUTOKLIK")) {
|
||||
centerPanel.add(createFieldPanel("Count:", countComboBox));
|
||||
centerPanel.add(createFieldPanel("Delay (s):", delaySpinner));
|
||||
} else if (title.contains("AUTOCLICK")) {
|
||||
JSpinner intervalSpinner = new JSpinner(new SpinnerNumberModel(
|
||||
Integer.parseInt(settings.getProperty("autoklik.interval", "100")),
|
||||
10, 10000, 10
|
||||
@ -373,23 +373,23 @@ public class PokemonGoGUI extends JFrame {
|
||||
centerPanel.add(createFieldPanel("Interval (ms):", intervalSpinner));
|
||||
}
|
||||
|
||||
// Pravý panel - START tlačítko (a u Autokliku i STOP v rámci tlačítka)
|
||||
// Right panel - START button (and for Autoclick also STOP within the button)
|
||||
JPanel rightPanel = new JPanel(new FlowLayout(FlowLayout.LEFT, 6, 0));
|
||||
rightPanel.setBackground(CARD_BACKGROUND);
|
||||
rightPanel.setBorder(BorderFactory.createEmptyBorder(4, 0, 0, 0));
|
||||
|
||||
// Tlačítko START / VYPNOUT
|
||||
// START / TURN OFF button
|
||||
JButton startBtn = new JButton("▶ START");
|
||||
startBtn.setPreferredSize(new Dimension(100, 32));
|
||||
styleButton(startBtn, PRIMARY_GREEN, Color.WHITE, SMALL_FONT);
|
||||
startBtn.addActionListener(startAction);
|
||||
|
||||
// Uložit tlačítko do card pro změnu barvy během běhu
|
||||
// Save button to card for color change during run
|
||||
card.putClientProperty("startButton", startBtn);
|
||||
|
||||
rightPanel.add(startBtn);
|
||||
|
||||
// Komponování karty: info nahoře, nastavení uprostřed, tlačítko dole
|
||||
// Card composition: info on top, settings in middle, button at bottom
|
||||
card.add(infoPanel, BorderLayout.NORTH);
|
||||
card.add(centerPanel, BorderLayout.CENTER);
|
||||
card.add(rightPanel, BorderLayout.SOUTH);
|
||||
@ -440,7 +440,7 @@ public class PokemonGoGUI extends JFrame {
|
||||
}
|
||||
|
||||
/**
|
||||
* Přesměruje System.out a System.err do log area
|
||||
* Redirects System.out and System.err to log area
|
||||
*/
|
||||
private void redirectSystemStreams() {
|
||||
System.setOut(new java.io.PrintStream(System.out) {
|
||||
@ -473,15 +473,15 @@ public class PokemonGoGUI extends JFrame {
|
||||
}
|
||||
|
||||
/**
|
||||
* Spustí Transfer automatizaci
|
||||
* Start Transfer automation
|
||||
*/
|
||||
private void startTransferAutomation(JPanel transferCard) {
|
||||
if (isRunning) {
|
||||
JOptionPane.showMessageDialog(this, "Automatizace již běží!", "Upozornění", JOptionPane.WARNING_MESSAGE);
|
||||
JOptionPane.showMessageDialog(this, "Automation is already running!", "Warning", JOptionPane.WARNING_MESSAGE);
|
||||
return;
|
||||
}
|
||||
|
||||
// Získat počet pokémonů a čekání z GUI
|
||||
// Get pokemon count and delay from GUI
|
||||
@SuppressWarnings("unchecked")
|
||||
JComboBox<Integer> countComboBox = (JComboBox<Integer>) transferCard.getClientProperty("countComboBox");
|
||||
JSpinner delaySpinner = (JSpinner) transferCard.getClientProperty("delaySpinner");
|
||||
@ -490,11 +490,11 @@ public class PokemonGoGUI extends JFrame {
|
||||
int delaySeconds = (Integer) delaySpinner.getValue();
|
||||
|
||||
stopButton.setEnabled(true);
|
||||
statusLabel.setText("Transfer automatizace běží...");
|
||||
statusLabel.setText("Transfer automation running...");
|
||||
statusLabel.setForeground(new Color(255, 152, 0));
|
||||
isRunning = true;
|
||||
|
||||
// Změnit barvu START tlačítka na červenou
|
||||
// Change START button color to red
|
||||
JButton startBtn = (JButton) transferCard.getClientProperty("startButton");
|
||||
if (startBtn != null) {
|
||||
startBtn.setEnabled(false);
|
||||
@ -502,8 +502,8 @@ public class PokemonGoGUI extends JFrame {
|
||||
}
|
||||
|
||||
logArea.append("\n========================================\n");
|
||||
logArea.append("SPOUŠTĚNÍ TRANSFER AUTOMATIZACE\n");
|
||||
logArea.append("Počet pokémonů: " + pokemonCount + ", Čekání: " + delaySeconds + "s\n");
|
||||
logArea.append("STARTING TRANSFER AUTOMATION\n");
|
||||
logArea.append("Pokémon count: " + pokemonCount + ", Delay: " + delaySeconds + "s\n");
|
||||
logArea.append("========================================\n\n");
|
||||
|
||||
shouldStop = false;
|
||||
@ -514,19 +514,19 @@ public class PokemonGoGUI extends JFrame {
|
||||
automation = new PokemonGoAutomation();
|
||||
automation.resetTransferredCount();
|
||||
|
||||
// Spustit vlákno pro aktualizaci statusu
|
||||
// Start thread for status update
|
||||
Thread statusUpdateThread = new Thread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
while (isRunning && !shouldStop && !Thread.currentThread().isInterrupted()) {
|
||||
try {
|
||||
Thread.sleep(500); // Aktualizovat každých 500ms
|
||||
Thread.sleep(500); // Update every 500ms
|
||||
final int transferred = automation.getTransferredCount();
|
||||
SwingUtilities.invokeLater(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (isRunning) {
|
||||
statusLabel.setText("Transfer běží... Transferováno: " + transferred + "/" + pokemonCount);
|
||||
statusLabel.setText("Transfer running... Transferred: " + transferred + "/" + pokemonCount);
|
||||
}
|
||||
}
|
||||
});
|
||||
@ -548,9 +548,9 @@ public class PokemonGoGUI extends JFrame {
|
||||
SwingUtilities.invokeLater(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
statusLabel.setText("Automatizace dokončena! Celkem transferováno: " + totalTransferredCount);
|
||||
statusLabel.setText("Automation complete! Total transferred: " + totalTransferredCount);
|
||||
statusLabel.setForeground(new Color(76, 175, 80));
|
||||
logArea.append("\n✅ Transfer automatizace úspěšně dokončena! Transferováno: " + automation.getTransferredCount() + " pokémonů\n");
|
||||
logArea.append("\n✅ Transfer automation completed successfully! Transferred: " + automation.getTransferredCount() + "pokemon\n");
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -560,21 +560,21 @@ public class PokemonGoGUI extends JFrame {
|
||||
public void run() {
|
||||
statusLabel.setText("Chyba!");
|
||||
statusLabel.setForeground(new Color(244, 67, 54));
|
||||
logArea.append("\n❌ Chyba: " + e.getMessage() + "\n");
|
||||
logArea.append("\n❌ Error: " + e.getMessage() + "\n");
|
||||
e.printStackTrace();
|
||||
}
|
||||
});
|
||||
} finally {
|
||||
// Čistit prostředky po automatizaci
|
||||
// Clean up resources after automation
|
||||
try {
|
||||
if (automation != null) {
|
||||
automation.cleanup();
|
||||
}
|
||||
// Také vyčistit WindowFinder resources
|
||||
// Also clean up WindowFinder resources
|
||||
WindowFinder.cleanup();
|
||||
System.gc();
|
||||
} catch (Exception cleanupEx) {
|
||||
System.err.println("Chyba při čištění: " + cleanupEx.getMessage());
|
||||
System.err.println("Error during cleanup: " + cleanupEx.getMessage());
|
||||
}
|
||||
|
||||
SwingUtilities.invokeLater(new Runnable() {
|
||||
@ -583,7 +583,7 @@ public class PokemonGoGUI extends JFrame {
|
||||
isRunning = false;
|
||||
stopButton.setEnabled(false);
|
||||
|
||||
// Vrátit barvu START tlačítka na zelenou
|
||||
// Restore START button color to green
|
||||
JButton btn = (JButton) transferCard.getClientProperty("startButton");
|
||||
if (btn != null) {
|
||||
btn.setEnabled(true);
|
||||
@ -599,7 +599,7 @@ public class PokemonGoGUI extends JFrame {
|
||||
}
|
||||
|
||||
/**
|
||||
* Spustí autoklik
|
||||
* Start autoclick
|
||||
*/
|
||||
private void startAutoClick(JPanel autoClickCard) {
|
||||
if (autoClickRunning) {
|
||||
@ -608,36 +608,36 @@ public class PokemonGoGUI extends JFrame {
|
||||
}
|
||||
|
||||
if (isRunning) {
|
||||
JOptionPane.showMessageDialog(this, "Jiná automatizace již běží!", "Upozornění", JOptionPane.WARNING_MESSAGE);
|
||||
JOptionPane.showMessageDialog(this, "Another automation is already running!", "Warning", JOptionPane.WARNING_MESSAGE);
|
||||
return;
|
||||
}
|
||||
|
||||
// Načtení nastavení
|
||||
// Load settings
|
||||
JSpinner intervalSpinner = (JSpinner) autoClickCard.getClientProperty("intervalSpinner");
|
||||
int interval = (Integer) intervalSpinner.getValue();
|
||||
|
||||
// Uložení nastavení
|
||||
// Save settings
|
||||
settings.setProperty("autoklik.interval", String.valueOf(interval));
|
||||
saveSettings();
|
||||
|
||||
stopButton.setEnabled(true);
|
||||
statusLabel.setText("Autokliker aktivní (Šipka dolů)...");
|
||||
statusLabel.setText("Autoclicker active (Down arrow)...");
|
||||
statusLabel.setForeground(new Color(255, 152, 0));
|
||||
isRunning = true;
|
||||
autoClickRunning = true;
|
||||
shouldStop = false;
|
||||
|
||||
// Změnit tlačítko na VYPNOUT
|
||||
// Change button to TURN OFF
|
||||
JButton startBtn = (JButton) autoClickCard.getClientProperty("startButton");
|
||||
if (startBtn != null) {
|
||||
startBtn.setText("⏹ VYPNOUT");
|
||||
startBtn.setText("⏹ TURN OFF");
|
||||
styleButton(startBtn, PRIMARY_RED, Color.WHITE, SMALL_FONT);
|
||||
}
|
||||
|
||||
logArea.append("\n========================================\n");
|
||||
logArea.append("AUTOKLIKER AKTIVNÍ\n");
|
||||
logArea.append("AUTOCCLICKER ACTIVE\n");
|
||||
logArea.append("Interval: " + interval + "ms\n");
|
||||
logArea.append("Ovládání: Stiskněte ŠIPKU NAHORU nebo DOLŮ pro zapnutí/vypnutí\n");
|
||||
logArea.append("Control: Press UP or DOWN ARROW to toggle\n");
|
||||
logArea.append("========================================\n\n");
|
||||
|
||||
automationThread = new Thread(new Runnable() {
|
||||
@ -652,44 +652,44 @@ public class PokemonGoGUI extends JFrame {
|
||||
long lastToggleTime = 0;
|
||||
|
||||
while (autoClickRunning && !shouldStop) {
|
||||
// Kontrola obou šipek
|
||||
// Check both arrows
|
||||
boolean isKeyPressed = globalHotkey.isKeyPressed(KeyEvent.VK_DOWN) ||
|
||||
globalHotkey.isKeyPressed(KeyEvent.VK_UP);
|
||||
long currentTime = System.currentTimeMillis();
|
||||
|
||||
// Detekce stisku (náběžná hrana) pro přepnutí stavu
|
||||
// Detect press (rising edge) to toggle state
|
||||
if (isKeyPressed && !wasKeyPressed && (currentTime - lastToggleTime > 200)) {
|
||||
isClickingActive = !isClickingActive;
|
||||
lastToggleTime = currentTime;
|
||||
|
||||
final boolean active = isClickingActive;
|
||||
SwingUtilities.invokeLater(() -> {
|
||||
logArea.append(active ? "▶ Klikání AKTIVOVÁNO šipkou\n" : "⏸ Klikání POZASTAVENO šipkou\n");
|
||||
statusLabel.setText(active ? "Autokliker: KLIKÁM..." : "Autokliker: POZASTAVENO");
|
||||
logArea.append(active ? "▶ Clicking ACTIVATED by arrow\n" : "⏸ Clicking PAUSED by arrow\n");
|
||||
statusLabel.setText(active ? "Autoclicker: CLICKING..." : "Autoclicker: PAUSED");
|
||||
});
|
||||
|
||||
if (isClickingActive) {
|
||||
lastClickTime = 0; // Spustit klikání hned
|
||||
lastClickTime = 0; // Start clicking immediately
|
||||
}
|
||||
}
|
||||
wasKeyPressed = isKeyPressed;
|
||||
|
||||
if (isClickingActive) {
|
||||
if (currentTime - lastClickTime >= interval) {
|
||||
// Klik na aktuální pozici
|
||||
// Click at current position
|
||||
robot.mousePress(java.awt.event.InputEvent.BUTTON1_DOWN_MASK);
|
||||
robot.mouseRelease(java.awt.event.InputEvent.BUTTON1_DOWN_MASK);
|
||||
|
||||
clicksDone++;
|
||||
if (clicksDone % 20 == 0) {
|
||||
final int count = clicksDone;
|
||||
SwingUtilities.invokeLater(() -> logArea.append(" Kliknutí: " + count + "\n"));
|
||||
SwingUtilities.invokeLater(() -> logArea.append(" Clicks: " + count + "\n"));
|
||||
}
|
||||
lastClickTime = currentTime;
|
||||
}
|
||||
}
|
||||
|
||||
// Rychlá smyčka pro detekci kláves (10ms)
|
||||
// Fast loop for key detection (10ms)
|
||||
Thread.sleep(10);
|
||||
}
|
||||
|
||||
@ -697,9 +697,9 @@ public class PokemonGoGUI extends JFrame {
|
||||
SwingUtilities.invokeLater(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
statusLabel.setText("Autokliker zastaven.");
|
||||
statusLabel.setText("Autoclicker stopped.");
|
||||
statusLabel.setForeground(new Color(76, 175, 80));
|
||||
logArea.append("\n✅ Autokliker byl vypnut.\n");
|
||||
logArea.append("\n✅ Autoclicker was turned off.\n");
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -710,9 +710,9 @@ public class PokemonGoGUI extends JFrame {
|
||||
SwingUtilities.invokeLater(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
statusLabel.setText("Chyba autoklikeru!");
|
||||
statusLabel.setText("Autoclicker error!");
|
||||
statusLabel.setForeground(new Color(244, 67, 54));
|
||||
logArea.append("\n❌ Chyba: " + e.getMessage() + "\n");
|
||||
logArea.append("\n❌ Error: " + e.getMessage() + "\n");
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -724,7 +724,7 @@ public class PokemonGoGUI extends JFrame {
|
||||
autoClickRunning = false;
|
||||
stopButton.setEnabled(false);
|
||||
|
||||
// Vrátit tlačítko na START
|
||||
// Restore button to START
|
||||
JButton btn = (JButton) autoClickCard.getClientProperty("startButton");
|
||||
if (btn != null) {
|
||||
btn.setText("▶ START");
|
||||
@ -740,7 +740,7 @@ public class PokemonGoGUI extends JFrame {
|
||||
}
|
||||
|
||||
/**
|
||||
* Zastaví automatizaci
|
||||
* Stop automation
|
||||
*/
|
||||
private void stopAutomation() {
|
||||
if (!isRunning && !autoClickRunning) {
|
||||
@ -757,7 +757,7 @@ public class PokemonGoGUI extends JFrame {
|
||||
|
||||
if (automationThread != null && automationThread.isAlive()) {
|
||||
automationThread.interrupt();
|
||||
// Čekej max 2 sekundy na ukončení
|
||||
// Wait max 2 seconds for shutdown
|
||||
try {
|
||||
automationThread.join(2000);
|
||||
} catch (InterruptedException e) {
|
||||
@ -769,15 +769,15 @@ public class PokemonGoGUI extends JFrame {
|
||||
@Override
|
||||
public void run() {
|
||||
stopButton.setEnabled(false);
|
||||
logArea.append("\n⚠️ Automatizace byla přerušena uživatelem\n");
|
||||
statusLabel.setText("Přerušeno");
|
||||
logArea.append("\n⚠️ Automation was interrupted by user\n");
|
||||
statusLabel.setText("Interrupted");
|
||||
statusLabel.setForeground(new Color(244, 67, 54));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Načte uložená nastavení ze souboru
|
||||
* Load saved settings from file
|
||||
*/
|
||||
private void loadSettings() {
|
||||
settings = new Properties();
|
||||
@ -787,11 +787,11 @@ public class PokemonGoGUI extends JFrame {
|
||||
try (java.io.FileInputStream fis = new java.io.FileInputStream(configFile)) {
|
||||
settings.load(fis);
|
||||
} catch (IOException e) {
|
||||
System.err.println("Chyba při načítání nastavení: " + e.getMessage());
|
||||
System.err.println("Error loading settings: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
// Výchozí hodnoty, pokud nastavení neexistují
|
||||
// Default values if settings do not exist
|
||||
if (!settings.containsKey("transfer.count")) {
|
||||
settings.setProperty("transfer.count", "12");
|
||||
}
|
||||
@ -813,10 +813,10 @@ public class PokemonGoGUI extends JFrame {
|
||||
}
|
||||
|
||||
/**
|
||||
* Uloží aktuální nastavení do souboru
|
||||
* Save current settings to file
|
||||
*/
|
||||
private void saveSettings() {
|
||||
// Uložení hodnot z combo boxu a spinneru
|
||||
// Save values from combo box and spinner
|
||||
if (countComboBox != null) {
|
||||
settings.setProperty("transfer.count", countComboBox.getSelectedItem().toString());
|
||||
}
|
||||
@ -824,29 +824,29 @@ public class PokemonGoGUI extends JFrame {
|
||||
settings.setProperty("transfer.delay", delaySpinner.getValue().toString());
|
||||
}
|
||||
|
||||
// Uložení velikosti a pozice okna
|
||||
// Save window size and position
|
||||
settings.setProperty("window.width", String.valueOf(getWidth()));
|
||||
settings.setProperty("window.height", String.valueOf(getHeight()));
|
||||
settings.setProperty("window.x", String.valueOf(getX()));
|
||||
settings.setProperty("window.y", String.valueOf(getY()));
|
||||
|
||||
try (java.io.FileOutputStream fos = new java.io.FileOutputStream(CONFIG_FILE)) {
|
||||
settings.store(fos, "Pokémon GO Automatizace - Nastavení");
|
||||
settings.store(fos, "Pokémon GO Automation - Settings");
|
||||
} catch (IOException e) {
|
||||
System.err.println("Chyba při ukládání nastavení: " + e.getMessage());
|
||||
System.err.println("Error saving settings: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static void main(String[] args) {
|
||||
// Nastavit shutdown hook pro bezpečné ukončení
|
||||
// Set shutdown hook for safe shutdown
|
||||
Runtime.getRuntime().addShutdownHook(new Thread(() -> {
|
||||
System.out.println("Aplikace se vypíná...");
|
||||
System.out.println("Application is shutting down...");
|
||||
// Vyčistit X11 resources
|
||||
try {
|
||||
WindowFinder.cleanup();
|
||||
} catch (Exception e) {
|
||||
System.err.println("Chyba při čištění WindowFinder: " + e.getMessage());
|
||||
System.err.println("Error cleaning up WindowFinder: " + e.getMessage());
|
||||
}
|
||||
}));
|
||||
|
||||
@ -856,11 +856,11 @@ public class PokemonGoGUI extends JFrame {
|
||||
PokemonGoGUI frame = new PokemonGoGUI();
|
||||
frame.setVisible(true);
|
||||
|
||||
// Nastavit window listener pro čisté ukončení
|
||||
// Set window listener for clean shutdown
|
||||
frame.addWindowListener(new java.awt.event.WindowAdapter() {
|
||||
@Override
|
||||
public void windowClosing(WindowEvent e) {
|
||||
System.out.println("Zavírám okno...");
|
||||
System.out.println("Closing window...");
|
||||
if (frame.globalHotkey != null) {
|
||||
frame.globalHotkey.cleanup();
|
||||
}
|
||||
|
||||
@ -1,102 +0,0 @@
|
||||
package com.pokemongo;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
import java.awt.event.MouseAdapter;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.awt.event.KeyAdapter;
|
||||
import java.awt.event.KeyEvent;
|
||||
|
||||
public class PositionPicker extends JWindow {
|
||||
private Point selectedPosition = null;
|
||||
private boolean positionSelected = false;
|
||||
private PositionPickerListener listener = null;
|
||||
|
||||
public interface PositionPickerListener {
|
||||
void onPositionSelected(Point position);
|
||||
void onCancelled();
|
||||
}
|
||||
|
||||
public PositionPicker(PositionPickerListener listener) {
|
||||
this.listener = listener;
|
||||
GraphicsDevice gd = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice();
|
||||
Rectangle screenBounds = gd.getDefaultConfiguration().getBounds();
|
||||
|
||||
// Pokrýt celou obrazovku bez omezení insets
|
||||
// (protože vrátíme absolutní globální souřadnice, ne relativní)
|
||||
setBounds(screenBounds);
|
||||
|
||||
System.out.println("PositionPicker vytvořen: " + screenBounds);
|
||||
|
||||
setFocusable(true);
|
||||
setBackground(new Color(0, 0, 0, 0));
|
||||
|
||||
// Přidáme panel pro vykreslování
|
||||
JPanel panel = new JPanel() {
|
||||
@Override
|
||||
protected void paintComponent(Graphics g) {
|
||||
super.paintComponent(g);
|
||||
Graphics2D g2d = (Graphics2D) g;
|
||||
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
|
||||
|
||||
// Lehké šedé pozadí
|
||||
g2d.setColor(new Color(100, 100, 100, 10));
|
||||
g2d.fillRect(0, 0, getWidth(), getHeight());
|
||||
|
||||
// Instrukce
|
||||
g2d.setColor(new Color(0, 0, 0, 200));
|
||||
g2d.fillRect(10, 10, 400, 60);
|
||||
|
||||
g2d.setColor(new Color(255, 255, 0, 255));
|
||||
g2d.setFont(new Font("Monospaced", Font.BOLD, 12));
|
||||
g2d.drawString("VYBERTE POZICI - Klikněte na místo kde chcete klikat", 20, 30);
|
||||
g2d.drawString("ESC: Zrušit", 20, 50);
|
||||
}
|
||||
};
|
||||
panel.setOpaque(false);
|
||||
panel.setBackground(new Color(0, 0, 0, 0));
|
||||
setContentPane(panel);
|
||||
|
||||
panel.addMouseListener(new MouseAdapter() {
|
||||
@Override
|
||||
public void mouseClicked(MouseEvent e) {
|
||||
// Vrátit absolutní globální souřadnice na obrazovce
|
||||
selectedPosition = new Point(
|
||||
screenBounds.x + e.getX(),
|
||||
screenBounds.y + e.getY()
|
||||
);
|
||||
positionSelected = true;
|
||||
System.out.println("✅ Pozice vybrána: " + selectedPosition);
|
||||
if (listener != null) {
|
||||
listener.onPositionSelected(selectedPosition);
|
||||
}
|
||||
dispose();
|
||||
}
|
||||
});
|
||||
|
||||
panel.addKeyListener(new KeyAdapter() {
|
||||
@Override
|
||||
public void keyPressed(KeyEvent e) {
|
||||
if (e.getKeyCode() == KeyEvent.VK_ESCAPE) {
|
||||
System.out.println("ESC - Výběr zrušen");
|
||||
positionSelected = false;
|
||||
if (listener != null) {
|
||||
listener.onCancelled();
|
||||
}
|
||||
dispose();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
panel.setFocusable(true);
|
||||
panel.requestFocus();
|
||||
}
|
||||
|
||||
public Point getSelectedPosition() {
|
||||
return selectedPosition;
|
||||
}
|
||||
|
||||
public boolean isPositionSelected() {
|
||||
return positionSelected;
|
||||
}
|
||||
}
|
||||
@ -11,8 +11,8 @@ import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Pomocná třída pro hledání oken v Linux/X11 prostředí.
|
||||
* Používá X11 API přes JNA bindings.
|
||||
* Helper class for finding windows in Linux/X11 environment.
|
||||
* Uses X11 API via JNA bindings.
|
||||
*/
|
||||
public class WindowFinder {
|
||||
|
||||
@ -25,7 +25,7 @@ public class WindowFinder {
|
||||
X11 INSTANCE = Native.load("X11", X11.class);
|
||||
|
||||
/**
|
||||
* X11 Window Attributes struktura - přesná kopie z X11/Xlib.h
|
||||
* X11 Window Attributes structure - exact copy from X11/Xlib.h
|
||||
*/
|
||||
class XWindowAttributes extends Structure {
|
||||
public int x;
|
||||
@ -79,13 +79,13 @@ public class WindowFinder {
|
||||
|
||||
int XFetchName(Pointer display, long window, PointerByReference window_name_return);
|
||||
|
||||
// XTranslateCoordinates - převede souřadnice z jednoho okna do jiného (root)
|
||||
// XTranslateCoordinates - converts coordinates from one window to another (root)
|
||||
boolean XTranslateCoordinates(Pointer display, long src_w, long dest_w,
|
||||
int src_x, int src_y,
|
||||
IntByReference dest_x_return, IntByReference dest_y_return,
|
||||
PointerByReference child_return);
|
||||
|
||||
// Globální klávesy
|
||||
// Global keys
|
||||
int XQueryKeymap(Pointer display, byte[] keys_return);
|
||||
int XKeysymToKeycode(Pointer display, long keysym);
|
||||
|
||||
@ -93,9 +93,9 @@ public class WindowFinder {
|
||||
}
|
||||
|
||||
/**
|
||||
* Zjistí, zda je klávesa stisknuta globálně (i mimo fokus aplikace)
|
||||
* @param keysym X11 Keysym (např. 0xFF54 pro Down Arrow)
|
||||
* @return true pokud je klávesa držena
|
||||
* Checks if a key is pressed globally (even outside application focus)
|
||||
* @param keysym X11 Keysym (e.g. 0xFF54 for Down Arrow)
|
||||
* @return true if key is held
|
||||
*/
|
||||
public static synchronized boolean isKeyPressedGlobally(long keysym) {
|
||||
Pointer display = null;
|
||||
@ -128,51 +128,51 @@ public class WindowFinder {
|
||||
}
|
||||
|
||||
/**
|
||||
* Najde okno podle jeho názvu a vrátí jeho bounds
|
||||
* @param searchPattern Pattern pro hledání (substring názvu okna)
|
||||
* @return Rectangle s pozicí a velikostí okna, nebo null pokud nenalezeno
|
||||
* Finds window by its name and returns its bounds
|
||||
* @param searchPattern Pattern for searching (substring of window name)
|
||||
* @return Rectangle with position and size of window, or null if not found
|
||||
*/
|
||||
public static synchronized Rectangle findWindowByName(String searchPattern) {
|
||||
Pointer display = null;
|
||||
|
||||
try {
|
||||
// Použít cachedDisplay pokud existuje, nebo otevřít nový
|
||||
// Use cachedDisplay if it exists, or open new
|
||||
if (cachedDisplay != null) {
|
||||
display = cachedDisplay;
|
||||
System.out.println("WindowFinder: Používám cachovaný X11 display");
|
||||
System.out.println("WindowFinder: Using cached X11 display");
|
||||
} else {
|
||||
display = X11.INSTANCE.XOpenDisplay(null);
|
||||
if (display == null) {
|
||||
System.out.println("WindowFinder: Nelze se připojit k X11 displei");
|
||||
System.out.println("WindowFinder: Cannot connect to X11 display");
|
||||
return null;
|
||||
}
|
||||
cachedDisplay = display;
|
||||
System.out.println("WindowFinder: Připojen k X11 displayu a uložen v cache");
|
||||
System.out.println("WindowFinder: Connected to X11 display and cached");
|
||||
}
|
||||
|
||||
long rootWindow = X11.INSTANCE.XDefaultRootWindow(display);
|
||||
|
||||
// Hledat okno a vrátit bounds
|
||||
// Search for window and return bounds
|
||||
Rectangle bounds = searchWindowRecursiveWithBounds(display, rootWindow, searchPattern);
|
||||
|
||||
if (bounds != null) {
|
||||
System.out.println("WindowFinder: Okno nalezeno: " + bounds);
|
||||
System.out.println("WindowFinder: Window found: " + bounds);
|
||||
return bounds;
|
||||
}
|
||||
|
||||
System.out.println("WindowFinder: Okno s názvem '" + searchPattern + "' nenalezeno");
|
||||
System.out.println("WindowFinder: Window with name '" + searchPattern + "' not found");
|
||||
return null;
|
||||
|
||||
} catch (Exception e) {
|
||||
System.err.println("WindowFinder - Chyba: " + e.getMessage());
|
||||
System.err.println("WindowFinder - Error: " + e.getMessage());
|
||||
e.printStackTrace();
|
||||
// Pokud dojde k chybě, vynulovat cache a zavřít display
|
||||
// If error occurs, clear cache and close display
|
||||
if (display != null && display == cachedDisplay) {
|
||||
try {
|
||||
X11.INSTANCE.XCloseDisplay(display);
|
||||
cachedDisplay = null;
|
||||
} catch (Exception ex) {
|
||||
System.err.println("WindowFinder - Chyba při zavírání displeje: " + ex.getMessage());
|
||||
System.err.println("WindowFinder - Error closing display: " + ex.getMessage());
|
||||
}
|
||||
}
|
||||
return null;
|
||||
@ -180,21 +180,21 @@ public class WindowFinder {
|
||||
}
|
||||
|
||||
/**
|
||||
* Rekurzivně hledá okno v stromě oken a vrátí jeho bounds při nalezení
|
||||
* Recursively searches for window in window tree and returns its bounds when found
|
||||
*/
|
||||
private static Rectangle searchWindowRecursiveWithBounds(Pointer display, long window,
|
||||
String searchPattern) {
|
||||
try {
|
||||
String windowName = getWindowNameString(display, window);
|
||||
if (windowName != null && windowName.contains(searchPattern)) {
|
||||
System.out.println("WindowFinder: Nalezeno okno: '" + windowName + "' (XID: " + window + ")");
|
||||
System.out.println("WindowFinder: Window found: '" + windowName + "' (XID: " + window + ")");
|
||||
return getWindowBounds(display, window);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
// Ignorovat chyby při čtení jména okna
|
||||
// Ignore errors when reading window name
|
||||
}
|
||||
|
||||
// Hledat v potomcích
|
||||
// Search in children
|
||||
PointerByReference children_return = new PointerByReference();
|
||||
IntByReference nchildren_return = new IntByReference();
|
||||
|
||||
@ -210,7 +210,7 @@ public class WindowFinder {
|
||||
int numChildren = nchildren_return.getValue();
|
||||
|
||||
if (childrenPtr != null) {
|
||||
// Čtení window IDs z pole
|
||||
// Reading window IDs from array
|
||||
for (int i = 0; i < numChildren; i++) {
|
||||
long childWindow = childrenPtr.getLong((long) i * 8); // 64-bit window IDs
|
||||
|
||||
@ -224,14 +224,14 @@ public class WindowFinder {
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
// Ignorovat chyby při hledání v potomcích
|
||||
// Ignore errors when searching in children
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Získá jméno okna jako String
|
||||
* Gets window name as String
|
||||
*/
|
||||
private static String getWindowNameString(Pointer display, long window) {
|
||||
PointerByReference namePtr = new PointerByReference();
|
||||
@ -258,8 +258,8 @@ public class WindowFinder {
|
||||
}
|
||||
|
||||
/**
|
||||
* Získá bounds okna (pozici a velikost) - ABSOLUTNÍ pozici na obrazovce
|
||||
* Používá XTranslateCoordinates na správný převod souřadnic z okna do root
|
||||
* Gets window bounds (position and size) - ABSOLUTE position on screen
|
||||
* Uses XTranslateCoordinates for correct conversion of coordinates from window to root
|
||||
*/
|
||||
private static Rectangle getWindowBounds(Pointer display, Long window) {
|
||||
try {
|
||||
@ -267,11 +267,11 @@ public class WindowFinder {
|
||||
int status = X11.INSTANCE.XGetWindowAttributes(display, window, attrs);
|
||||
|
||||
if (status == 0) {
|
||||
System.err.println("WindowFinder - Chyba při získávání window attributes");
|
||||
System.err.println("WindowFinder - Error getting window attributes");
|
||||
return null;
|
||||
}
|
||||
|
||||
// Použít XTranslateCoordinates na převod souřadnic z okna do root
|
||||
// Use XTranslateCoordinates to convert coordinates from window to root
|
||||
long rootWindow = X11.INSTANCE.XDefaultRootWindow(display);
|
||||
IntByReference absX = new IntByReference();
|
||||
IntByReference absY = new IntByReference();
|
||||
@ -281,21 +281,21 @@ public class WindowFinder {
|
||||
0, 0, absX, absY, child);
|
||||
|
||||
if (!translated) {
|
||||
System.err.println("WindowFinder - Chyba při XTranslateCoordinates");
|
||||
// Fallback - vrátit alespoň relativní pozici
|
||||
System.err.println("WindowFinder - Error in XTranslateCoordinates");
|
||||
// Fallback - return at least relative position
|
||||
return new Rectangle(attrs.x, attrs.y, attrs.width, attrs.height);
|
||||
}
|
||||
|
||||
int absoluteX = absX.getValue();
|
||||
int absoluteY = absY.getValue();
|
||||
|
||||
System.out.println("WindowFinder: Window bounds - ABSOLUTNÍ: x:" + absoluteX + " y:" + absoluteY +
|
||||
System.out.println("WindowFinder: Window bounds - ABSOLUTE: x:" + absoluteX + " y:" + absoluteY +
|
||||
" w:" + attrs.width + " h:" + attrs.height);
|
||||
|
||||
return new Rectangle(absoluteX, absoluteY, attrs.width, attrs.height);
|
||||
|
||||
} catch (Exception e) {
|
||||
System.err.println("WindowFinder - Chyba při získávání bounds: " + e.getMessage());
|
||||
System.err.println("WindowFinder - Error getting bounds: " + e.getMessage());
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
@ -303,16 +303,16 @@ public class WindowFinder {
|
||||
}
|
||||
|
||||
/**
|
||||
* Ukončí X11 display connection a vyčistí cache
|
||||
* Volat při shutdown aplikace
|
||||
* Closes X11 display connection and clears cache
|
||||
* Call on application shutdown
|
||||
*/
|
||||
public static synchronized void cleanup() {
|
||||
if (cachedDisplay != null) {
|
||||
try {
|
||||
X11.INSTANCE.XCloseDisplay(cachedDisplay);
|
||||
System.out.println("WindowFinder: X11 display uzavřen a cache vyčištěn");
|
||||
System.out.println("WindowFinder: X11 display closed and cache cleared");
|
||||
} catch (Exception e) {
|
||||
System.err.println("WindowFinder - Chyba při zavírání displeje: " + e.getMessage());
|
||||
System.err.println("WindowFinder - Error closing display: " + e.getMessage());
|
||||
} finally {
|
||||
cachedDisplay = null;
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user