some fixes and optimizations

This commit is contained in:
Radek Davidek 2026-05-19 19:42:21 +02:00
parent b3cf1825d9
commit 37c3d8ffb7
7 changed files with 276 additions and 393 deletions

View File

@ -1,13 +1,13 @@
#Pokémon GO Automatizace - Nastavení #Pokémon GO Automation - Settings
#Fri Jan 23 16:03:46 CET 2026 #Tue May 19 19:39:52 CEST 2026
autoklik.count=1000 autoklik.count=1000
window.width=807
transfer.delay=0
autoklik.x=2123
window.height=743
autoklik.downArrow=true autoklik.downArrow=true
autoklik.y=1129
autoklik.interval=150 autoklik.interval=150
transfer.count=6 autoklik.x=2123
window.x=887 autoklik.y=1129
window.y=505 transfer.count=60
transfer.delay=0
window.height=743
window.width=412
window.x=1546
window.y=343

View File

@ -33,13 +33,6 @@
<version>1.18.26</version> <version>1.18.26</version>
<scope>provided</scope> <scope>provided</scope>
</dependency> </dependency>
<!-- OpenCV pro rozpoznávání obrazu -->
<dependency>
<groupId>org.openpnp</groupId>
<artifactId>opencv</artifactId>
<version>4.7.0-0</version>
</dependency>
</dependencies> </dependencies>
<build> <build>

View File

@ -7,11 +7,10 @@ import java.util.Set;
import javax.swing.JLabel; import javax.swing.JLabel;
/** /**
* Globální hotkey listener pro detekci CTRL+ALT+Q. * Global hotkey listener for detecting CTRL+ALT+Q.
* Na Linuxu funguje i bez fokusu přes nativní polling X11. * On Linux works without focus via native X11 polling.
*/ */
public class GlobalHotkey extends JLabel { public class GlobalHotkey extends JLabel {
private static GlobalHotkey instance;
private static final long HOTKEY_COOLDOWN_MS = 700; private static final long HOTKEY_COOLDOWN_MS = 700;
private final GlobalKeyListener globalKeyListener; private final GlobalKeyListener globalKeyListener;
@ -24,11 +23,11 @@ public class GlobalHotkey extends JLabel {
this.onHotkey = onHotkey; this.onHotkey = onHotkey;
this.globalKeyListener = new GlobalKeyListener(); this.globalKeyListener = new GlobalKeyListener();
// Registrace globálního key listeneru pro případy, kdy aplikace fokus // Register global key listener for cases when application has focus
KeyboardFocusManager.getCurrentKeyboardFocusManager() KeyboardFocusManager.getCurrentKeyboardFocusManager()
.addKeyEventDispatcher(globalKeyListener); .addKeyEventDispatcher(globalKeyListener);
// Nativ polling globální hotkey na Linuxu (funguje i bez fokusu) // Native polling of global hotkey on Linux (works without focus)
if (isLinux()) { if (isLinux()) {
pollingThread = new Thread(() -> { pollingThread = new Thread(() -> {
while (running && !Thread.currentThread().isInterrupted()) { while (running && !Thread.currentThread().isInterrupted()) {
@ -40,7 +39,7 @@ public class GlobalHotkey extends JLabel {
boolean qPressed = WindowFinder.isKeyPressedGlobally(0x71) || WindowFinder.isKeyPressedGlobally(0x51); boolean qPressed = WindowFinder.isKeyPressedGlobally(0x71) || WindowFinder.isKeyPressedGlobally(0x51);
if (ctrl && alt && qPressed) { 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) { } catch (InterruptedException e) {
Thread.currentThread().interrupt(); 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) { public boolean isKeyPressed(int keyCode) {
// Na Linuxu pro šipky používáme výhradně nativní globální detekci. // On Linux for arrows we use exclusively native global detection.
// Standard KeyEventDispatcher se může "zaseknout", pokud okno ztratí fokus během stisku. // Standard KeyEventDispatcher may get "stuck" if window loses focus during press.
if (isLinux()) { if (isLinux()) {
if (keyCode == KeyEvent.VK_DOWN) { if (keyCode == KeyEvent.VK_DOWN) {
try { 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 class GlobalKeyListener implements java.awt.KeyEventDispatcher {
private Set<Integer> pressedKeys = new HashSet<>(); private Set<Integer> pressedKeys = new HashSet<>();
@ -125,14 +117,14 @@ public class GlobalHotkey extends JLabel {
// Detekce CTRL+ALT+Q // Detekce CTRL+ALT+Q
if (e.getKeyCode() == KeyEvent.VK_Q && if (e.getKeyCode() == KeyEvent.VK_Q &&
e.isControlDown() && e.isAltDown()) { e.isControlDown() && e.isAltDown()) {
triggerHotkey("Globální hotkey detekován: CTRL+ALT+Q"); triggerHotkey("Global hotkey detected: CTRL+ALT+Q");
return true; // Konzumovat event return true; // Konzumovat event
} }
} else if (e.getID() == KeyEvent.KEY_RELEASED) { } else if (e.getID() == KeyEvent.KEY_RELEASED) {
pressedKeys.remove(e.getKeyCode()); pressedKeys.remove(e.getKeyCode());
} }
return false; // Nepropagovat ostatní eventy return false; // Do not propagate other events
} }
} }
} }

View File

@ -15,8 +15,8 @@ import java.util.List;
import javax.imageio.ImageIO; import javax.imageio.ImageIO;
/** /**
* Automatizační nástroj pro Pokémon GO. * Automation tool for Pokémon GO.
* Najde běžící aplikaci, označí všechny Pokémony a stiskne tlačítko Transfer. * Finds running application, selects all Pokémon and clicks Transfer button.
*/ */
public class PokemonGoAutomation { public class PokemonGoAutomation {
@ -29,8 +29,8 @@ public class PokemonGoAutomation {
private BufferedImage includeTemplate; // Include button template private BufferedImage includeTemplate; // Include button template
private static final int DELAY_BETWEEN_CLICKS = 100; // ms private static final int DELAY_BETWEEN_CLICKS = 100; // ms
private static final int DELAY_AFTER_ACTION = 100; // ms private static final int DELAY_AFTER_ACTION = 100; // ms
private int transferredPokemonCount = 0; // Počet transfernutých pokémonů private int transferredPokemonCount = 0; // Count of transferred pokemon
private Point initialMousePosition = null; // Pozice kurzoru před začátkem automatizace private Point initialMousePosition = null; // Cursor position before start of automation
private volatile boolean stopRequested = false; private volatile boolean stopRequested = false;
public PokemonGoAutomation() throws AWTException { 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() { public int getTransferredCount() {
return transferredPokemonCount; return transferredPokemonCount;
} }
/** /**
* Resetuje počítadlo transfernutých pokémonů * Resets counter of transferred pokemon
*/ */
public void resetTransferredCount() { public void resetTransferredCount() {
transferredPokemonCount = 0; transferredPokemonCount = 0;
@ -63,62 +63,62 @@ public class PokemonGoAutomation {
} }
/** /**
* Pořídí screenshot oblasti okna * Takes screenshot of window area
*/ */
private BufferedImage captureScreen(Rectangle area) { private BufferedImage captureScreen(Rectangle area) {
return robot.createScreenCapture(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() { private void loadButtonTemplates() {
try { try {
String t1Paths = "/t1.png"; String t1Paths = "/t1.png";
t1Template = ImageIO.read(getClass().getResourceAsStream(t1Paths)); 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"; String t2Paths = "/t2.png";
t2Template = ImageIO.read(getClass().getResourceAsStream(t2Paths)); 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"; String t3Paths = "/t3.png";
t3Template = ImageIO.read(getClass().getResourceAsStream(t3Paths)); 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"; String pok1Paths = "/pok1.png";
pok1Template = ImageIO.read(getClass().getResourceAsStream(pok1Paths)); 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"; String includePaths = "/include.png";
includeTemplate = ImageIO.read(getClass().getResourceAsStream(includePaths)); 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) { if (t1Template == null) {
System.out.println("⚠️ Template t1.png nebyl nalezen"); System.out.println("⚠️ Template t1.png not found");
} }
if (t2Template == null) { if (t2Template == null) {
System.out.println("⚠️ Template t2.png nebyl nalezen"); System.out.println("⚠️ Template t2.png not found");
} }
if (pok1Template == null) { if (pok1Template == null) {
System.out.println("⚠️ Template pok1.png nebyl nalezen"); System.out.println("⚠️ Template pok1.png not found");
} }
if (includeTemplate == null) { if (includeTemplate == null) {
System.out.println("⚠️ Template include.png nebyl nalezen"); System.out.println("⚠️ Template include.png not found");
} }
} catch (IOException e) { } 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 * Compares template with area in image - simple pixel comparison with
* optimalizací * optimization
*/ */
private double templateMatch(BufferedImage screenshot, int startX, int startY, BufferedImage template, private double templateMatch(BufferedImage screenshot, int startX, int startY, BufferedImage template,
int tolerance) { int tolerance) {
@ -152,7 +152,7 @@ public class PokemonGoAutomation {
int templateRGB = template.getRGB(x, y); int templateRGB = template.getRGB(x, y);
int screenRGB = screenshot.getRGB(startX + x, startY + y); int screenRGB = screenshot.getRGB(startX + x, startY + y);
// Rozdělit RGB hodnoty // Split RGB values
int tR = (templateRGB >> 16) & 0xFF; int tR = (templateRGB >> 16) & 0xFF;
int tG = (templateRGB >> 8) & 0xFF; int tG = (templateRGB >> 8) & 0xFF;
int tB = templateRGB & 0xFF; int tB = templateRGB & 0xFF;
@ -161,7 +161,7 @@ public class PokemonGoAutomation {
int sG = (screenRGB >> 8) & 0xFF; int sG = (screenRGB >> 8) & 0xFF;
int sB = screenRGB & 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 rDiff = Math.abs(tR - sR);
int gDiff = Math.abs(tG - sG); int gDiff = Math.abs(tG - sG);
int bDiff = Math.abs(tB - sB); int bDiff = Math.abs(tB - sB);
@ -169,7 +169,7 @@ public class PokemonGoAutomation {
if (rDiff < tolerance && gDiff < tolerance && bDiff < tolerance) { if (rDiff < tolerance && gDiff < tolerance && bDiff < tolerance) {
matchingPixels++; 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)) { if (matchingPixels < requiredMatch / 2 && (y * tWidth + x) > (totalPixels / 2)) {
return 0.0; 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; 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) { 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()) { if (shouldStop()) {
return null; return null;
@ -196,7 +196,7 @@ public class PokemonGoAutomation {
int tWidth = template.getWidth(); int tWidth = template.getWidth();
int tHeight = template.getHeight(); 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 searchStartY = (int) (windowBounds.height * 0.40);
int searchEndY = (int) (windowBounds.height * 0.75); int searchEndY = (int) (windowBounds.height * 0.75);
@ -204,12 +204,12 @@ public class PokemonGoAutomation {
int bestX = 0; int bestX = 0;
int bestY = 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) { for (int y = searchStartY; y <= searchEndY - tHeight; y += 15) {
if (shouldStop()) { if (shouldStop()) {
return null; 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) { for (int x = 0; x <= windowBounds.width - tWidth; x += 30) {
double score = templateMatch(screenshot, x, y, template, tolerance); double score = templateMatch(screenshot, x, y, template, tolerance);
@ -225,17 +225,17 @@ public class PokemonGoAutomation {
Point bestMatch = new Point( Point bestMatch = new Point(
windowBounds.x + bestX + (tWidth / 2), windowBounds.x + bestX + (tWidth / 2),
windowBounds.y + bestY + (tHeight / 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) + "%)"); + String.format("%.1f", bestScore * 100) + "%)");
return bestMatch; return bestMatch;
} }
System.out.println("Template nenalezen"); System.out.println("Template not found");
return null; return null;
} }
private Point findIncludeButtonPosition(int tolerance) { 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()) { if (shouldStop()) {
return null; return null;
@ -246,7 +246,7 @@ public class PokemonGoAutomation {
int tWidth = includeTemplate.getWidth(); int tWidth = includeTemplate.getWidth();
int tHeight = includeTemplate.getHeight(); 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 searchStartY = (int) (windowBounds.height * 0.40);
int searchEndY = (int) (windowBounds.height * 0.75); int searchEndY = (int) (windowBounds.height * 0.75);
@ -254,12 +254,12 @@ public class PokemonGoAutomation {
int bestX = 0; int bestX = 0;
int bestY = 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) { for (int y = searchStartY; y <= searchEndY - tHeight; y += 15) {
if (shouldStop()) { if (shouldStop()) {
return null; 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) { for (int x = 0; x <= windowBounds.width - tWidth; x += 30) {
double score = templateMatch(screenshot, x, y, includeTemplate, tolerance); double score = templateMatch(screenshot, x, y, includeTemplate, tolerance);
@ -275,17 +275,17 @@ public class PokemonGoAutomation {
Point bestMatch = new Point( Point bestMatch = new Point(
windowBounds.x + bestX + (tWidth / 2), windowBounds.x + bestX + (tWidth / 2),
windowBounds.y + bestY + (tHeight / 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) + "%)"); + String.format("%.1f", bestScore * 100) + "%)");
return bestMatch; return bestMatch;
} }
System.out.println("Template nenalezen"); System.out.println("Template not found");
return null; 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() { public boolean findPokemonGoWindow() {
try { try {
@ -293,15 +293,15 @@ public class PokemonGoAutomation {
if (bounds != null && bounds.width > 0 && bounds.height > 0) { if (bounds != null && bounds.width > 0 && bounds.height > 0) {
windowBounds = bounds; windowBounds = bounds;
System.out.println("Nalezeno okno: " + windowBounds); System.out.println("Window found: " + windowBounds);
return true; return true;
} }
System.out.println("Okno Pokémon GO nebylo nalezeno."); System.out.println("Pokémon GO window not found.");
return false; return false;
} catch (Exception e) { } catch (Exception e) {
System.err.println("Chyba při hledání okna: " + e.getMessage()); System.err.println("Error finding window: " + e.getMessage());
e.printStackTrace(); e.printStackTrace();
return false; return false;
} }
@ -312,12 +312,12 @@ public class PokemonGoAutomation {
*/ */
public void activateWindow() { public void activateWindow() {
try { try {
// Kliknutí na horní panel okna (title bar) pro aktivaci // Click on top panel of window (title bar) for activation
// Title bar je obvykle 30-40px vysoký v horní části okna // Title bar is usually 30-40px high at top of window
int centerX = windowBounds.x + windowBounds.width / 2; 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.mouseMove(centerX, titleBarY);
robot.delay(200); robot.delay(200);
@ -325,26 +325,26 @@ public class PokemonGoAutomation {
robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK);
robot.delay(DELAY_AFTER_ACTION); robot.delay(DELAY_AFTER_ACTION);
System.out.println("Okno aktivováno"); System.out.println("Window activated");
} catch (Exception e) { } 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() { public void clickTransferButton() {
if (shouldStop()) { if (shouldStop()) {
return; return;
} }
// Použít detekci tlačítka // Use button detection
// Point buttonPos = findTransferButtonPosition(); // Point buttonPos = findTransferButtonPosition();
Point buttonPos = getAbsolutePoint(300, 1156); Point buttonPos = getAbsolutePoint(300, 1156);
if (buttonPos == null) { if (buttonPos == null) {
System.err.println("Tlačítko TRANSFER nebylo nalezeno!"); System.err.println("TRANSFER button not found!");
return; return;
} }
@ -354,26 +354,26 @@ public class PokemonGoAutomation {
robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); robot.mousePress(InputEvent.BUTTON1_DOWN_MASK);
robot.mouseRelease(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); 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) { 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()) { if (shouldStop()) {
return; 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); Point buttonPos = findConfirmTransferButtonPosition(template, tolerance);
if (buttonPos == null) { 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; return;
} }
@ -383,23 +383,23 @@ public class PokemonGoAutomation {
robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); robot.mousePress(InputEvent.BUTTON1_DOWN_MASK);
robot.mouseRelease(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); robot.delay(DELAY_AFTER_ACTION);
} }
public boolean clickIncludeButton(int tolerance) { 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()) { if (shouldStop()) {
return false; 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); Point buttonPos = findIncludeButtonPosition(tolerance);
if (buttonPos == null) { 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; return false;
} }
@ -409,79 +409,79 @@ public class PokemonGoAutomation {
robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); robot.mousePress(InputEvent.BUTTON1_DOWN_MASK);
robot.mouseRelease(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); robot.delay(DELAY_AFTER_ACTION);
return true; 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 totalPokemonCount Total number of pokemon to transfer
* @param delaySeconds Čekání mezi iteracemi (v sekundách) * @param delaySeconds Delay between iterations (in seconds)
*/ */
public void runWithCount(int totalPokemonCount, int delaySeconds) { 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"); + delaySeconds + "s");
// Uložit aktuální pozici kurzoru // Save current cursor position
PointerInfo pointerInfo = MouseInfo.getPointerInfo(); PointerInfo pointerInfo = MouseInfo.getPointerInfo();
initialMousePosition = pointerInfo != null ? pointerInfo.getLocation() : null; initialMousePosition = pointerInfo != null ? pointerInfo.getLocation() : null;
if (initialMousePosition != 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()) { 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; return;
} }
activateWindow(); activateWindow();
System.out.println("Čekám 1 sekundu před začátkem..."); System.out.println("Waiting 1 second before start...");
robot.delay(1000); robot.delay(1000);
int transferredCount = 0; int transferredCount = 0;
// Transferovat dokud nedosáhneme požadovaného počtu // Transfer until we reach desired count
try { try {
while (transferredCount < totalPokemonCount) { while (transferredCount < totalPokemonCount) {
// Kontrola přerušení // Check interruption
if (shouldStop()) { if (shouldStop()) {
System.out.println("\n⚠ Automatizace byla přerušena!"); System.out.println("\n⚠ Automation was interrupted!");
return; return;
} }
int pokemonThisRound = Math.min(12, totalPokemonCount - transferredCount); int pokemonThisRound = Math.min(12, totalPokemonCount - transferredCount);
System.out.println( System.out.println(
"\n=== Iterace " + (transferredCount / 9 + 1) + " - Transferuji maximálně " + pokemonThisRound "\n=== Iteration " + (transferredCount / 9 + 1) + " - Transferring max " + pokemonThisRound
+ " pokémonů ==="); + " pokemon ===");
// Vybrat pokémony a získat skutečný počet vybraných // Select pokemon and get actual number selected
int actualTransferredCount = selectAllPokemonCount(pokemonThisRound); int actualTransferredCount = selectAllPokemonCount(pokemonThisRound);
if (shouldStop()) { 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; return;
} }
System.out.println("Čekám na TRANSFER..."); System.out.println("Waiting for TRANSFER...");
clickTransferButton(); clickTransferButton();
if (shouldStop()) { 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; return;
} }
System.out.println("Čekám na INCLUDE dialog..."); System.out.println("Waiting for INCLUDE dialog...");
robot.delay(100); robot.delay(100);
if (clickIncludeButton(110)) { if (clickIncludeButton(110)) {
System.out.println("Čekám na potvrzovací dialog t3..."); System.out.println("Waiting for confirmation dialog t3...");
robot.delay(100); robot.delay(100);
clickConfirmTransferButton(t3Template, 70); clickConfirmTransferButton(t3Template, 70);
} else { } else {
System.out.println("Čekám na potvrzovací dialog t2..."); System.out.println("Waiting for confirmation dialog t2...");
robot.delay(100); robot.delay(100);
clickConfirmTransferButton(t2Template, 70); clickConfirmTransferButton(t2Template, 70);
} }
@ -489,17 +489,17 @@ public class PokemonGoAutomation {
transferredCount += actualTransferredCount; transferredCount += actualTransferredCount;
transferredPokemonCount += 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 + ")"); + transferredCount + ")");
// Pokud ještě zbývá co transferovat, počkat // If there is still something to transfer, wait
if (transferredCount < totalPokemonCount) { if (transferredCount < totalPokemonCount) {
System.out.println("Přestávka: " + delaySeconds + " sekund..."); System.out.println("Break: " + delaySeconds + " seconds...");
// Čekat s kontrolou přerušení // Wait with checking interruption
long endTime = System.currentTimeMillis() + (delaySeconds * 1000L); long endTime = System.currentTimeMillis() + (delaySeconds * 1000L);
while (System.currentTimeMillis() < endTime) { while (System.currentTimeMillis() < endTime) {
if (shouldStop()) { 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; break;
} }
robot.delay(100); robot.delay(100);
@ -511,48 +511,48 @@ public class PokemonGoAutomation {
if (initialMousePosition != null) { if (initialMousePosition != null) {
try { try {
robot.mouseMove(initialMousePosition.x, initialMousePosition.y); 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) { } 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) { 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(); List<Point> positions = getPossitionsAbsolute();
int maxPokemon = Math.min(count, positions.size()); 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++) { for (int i = 0; i < maxPokemon; i++) {
if (shouldStop()) { if (shouldStop()) {
System.out.println("Označování přerušeno."); System.out.println("Selection interrupted.");
return i; return i;
} }
Point pos = positions.get(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); robot.mouseMove(pos.x, pos.y);
if (i == 0) { 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.mousePress(InputEvent.BUTTON1_DOWN_MASK);
robot.delay(700); robot.delay(700);
robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK);
robot.delay(DELAY_AFTER_ACTION); robot.delay(DELAY_AFTER_ACTION);
} else { } else {
System.out.println(" -> Normální klik"); System.out.println(" -> Normal click");
robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); robot.mousePress(InputEvent.BUTTON1_DOWN_MASK);
robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK);
} }
@ -560,8 +560,8 @@ public class PokemonGoAutomation {
robot.delay(DELAY_BETWEEN_CLICKS); robot.delay(DELAY_BETWEEN_CLICKS);
} }
System.out.println("Označeno " + maxPokemon + " pokémonů!"); System.out.println("Selected " + maxPokemon + "pokemon!");
System.out.println("Čekám před kliknutím na TRANSFER..."); System.out.println("Waiting before clicking TRANSFER...");
robot.delay(800); robot.delay(800);
return maxPokemon; 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 Relativ X pozice (0.0 = levý okraj, 1.0 = pravý okraj) * @param relativeX Relative X position (0.0 = left edge, 1.0 = right edge)
* @param relativeY Relativ Y pozice (0.0 = horní okraj, 1.0 = dolní okraj) * @param relativeY Relative Y position (0.0 = top edge, 1.0 = bottom edge)
* @return Absolut pozice na obrazovce * @return Absolute position on screen
*/ */
private Point getAbsolutePoint(int relativeX, int relativeY) { private Point getAbsolutePoint(int relativeX, int relativeY) {
int xCorrection = 0; int xCorrection = 0;
@ -604,14 +604,14 @@ public class PokemonGoAutomation {
} }
/** /**
* Vyčistí všechny prostředky používané automatizací * Cleans up all resources used by automation
* Volat po skončení automatizace * Call after automation finishes
*/ */
public void cleanup() { public void cleanup() {
try { 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; t1Template = null;
t2Template = null; t2Template = null;
t3Template = null; t3Template = null;
@ -619,16 +619,16 @@ public class PokemonGoAutomation {
includeTemplate = null; includeTemplate = null;
windowBounds = null; windowBounds = null;
// Explicit vyvolat garbage collector // Explicitly invoke garbage collector
System.gc(); System.gc();
System.out.println("Prostředky automatizace vyčištěny"); System.out.println("Automation resources cleaned");
} catch (Exception e) { } 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) { public static void main(String[] args) {
System.out.println("=== Pokémon GO Automatizační Nástroj ==="); System.out.println("=== Pokémon GO Automation Tool ===");
System.out.println("Ujistěte se, že je aplikace Pokémon GO spuštěná..."); System.out.println("Make sure Pokémon GO is running...");
} }
} }

View File

@ -11,8 +11,8 @@ import java.io.*;
import java.util.Properties; import java.util.Properties;
/** /**
* Jednoduchá GUI aplikace pro Pokémon GO automatizaci * Simple GUI application for Pokémon GO automation
* S kartami pro jednotlivé automatizace * With cards for individual automations
*/ */
public class PokemonGoGUI extends JFrame { public class PokemonGoGUI extends JFrame {
@ -23,7 +23,7 @@ public class PokemonGoGUI extends JFrame {
private volatile boolean shouldStop = false; private volatile boolean shouldStop = false;
private PokemonGoAutomation automation; private PokemonGoAutomation automation;
private Thread automationThread; 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 volatile boolean autoClickRunning = false;
private GlobalHotkey globalHotkey; private GlobalHotkey globalHotkey;
@ -49,13 +49,13 @@ public class PokemonGoGUI extends JFrame {
private static final int CARD_MAX_WIDTH = 760; private static final int CARD_MAX_WIDTH = 760;
public PokemonGoGUI() { public PokemonGoGUI() {
setTitle("Pokémon GO Automatizace v" + VERSION); setTitle("Pokémon GO Automation v" + VERSION);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// Načtení uložených nastavení // Load saved settings
loadSettings(); loadSettings();
// Obnovení velikosti a pozice okna // Restore window size and position
int width = Integer.parseInt(settings.getProperty("window.width", "900")); int width = Integer.parseInt(settings.getProperty("window.width", "900"));
int height = Integer.parseInt(settings.getProperty("window.height", "680")); int height = Integer.parseInt(settings.getProperty("window.height", "680"));
int x = Integer.parseInt(settings.getProperty("window.x", "-1")); int x = Integer.parseInt(settings.getProperty("window.x", "-1"));
@ -72,7 +72,7 @@ public class PokemonGoGUI extends JFrame {
setResizable(true); setResizable(true);
setBackground(PANEL_BACKGROUND); setBackground(PANEL_BACKGROUND);
// Uložení nastavení při zavření okna // Save settings on window close
addWindowListener(new java.awt.event.WindowAdapter() { addWindowListener(new java.awt.event.WindowAdapter() {
@Override @Override
public void windowClosing(WindowEvent e) { 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)); JPanel mainPanel = new JPanel(new BorderLayout(10, 10));
mainPanel.setBorder(BorderFactory.createEmptyBorder(15, 15, 15, 15)); mainPanel.setBorder(BorderFactory.createEmptyBorder(15, 15, 15, 15));
mainPanel.setBackground(PANEL_BACKGROUND); mainPanel.setBackground(PANEL_BACKGROUND);
// Horní panel se stavem // Top panel with status
JLabel stateLabel = new JLabel("Stav:"); JLabel stateLabel = new JLabel("Status:");
stateLabel.setFont(HEADER_FONT); stateLabel.setFont(HEADER_FONT);
stateLabel.setForeground(new Color(70, 70, 70)); 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.setFont(BODY_FONT);
statusLabel.setForeground(STATUS_DEFAULT); statusLabel.setForeground(STATUS_DEFAULT);
JLabel versionLabel = new JLabel("verze " + VERSION); JLabel versionLabel = new JLabel("v" + VERSION);
versionLabel.setFont(SMALL_FONT); versionLabel.setFont(SMALL_FONT);
versionLabel.setForeground(new Color(120, 120, 120)); versionLabel.setForeground(new Color(120, 120, 120));
stopButton = new JButton("ZASTAVIT (CTRL+ALT+Q)"); stopButton = new JButton("STOP (CTRL+ALT+Q)");
stopButton.setPreferredSize(new Dimension(150, 30)); stopButton.setPreferredSize(new Dimension(220, 30));
styleButton(stopButton, PRIMARY_RED, Color.WHITE, SMALL_FONT); styleButton(stopButton, PRIMARY_RED, Color.WHITE, SMALL_FONT);
stopButton.setEnabled(false); stopButton.setEnabled(false);
stopButton.addActionListener(new ActionListener() { stopButton.addActionListener(new ActionListener() {
@ -111,7 +111,7 @@ public class PokemonGoGUI extends JFrame {
stopPanel.setOpaque(false); stopPanel.setOpaque(false);
stopPanel.add(stopButton); stopPanel.add(stopButton);
JLabel titleLabel = new JLabel("Pokémon GO Automatizace"); JLabel titleLabel = new JLabel("Pokémon GO Automation");
titleLabel.setFont(TITLE_FONT); titleLabel.setFont(TITLE_FONT);
titleLabel.setForeground(new Color(30, 30, 30)); titleLabel.setForeground(new Color(30, 30, 30));
@ -133,7 +133,7 @@ public class PokemonGoGUI extends JFrame {
headerPanel.add(Box.createVerticalStrut(6)); headerPanel.add(Box.createVerticalStrut(6));
headerPanel.add(statusRow); headerPanel.add(statusRow);
// Panel s kartami automatizací // Panel with automation cards
JPanel cardsContainer = new JPanel(new GridBagLayout()); JPanel cardsContainer = new JPanel(new GridBagLayout());
cardsContainer.setBackground(PANEL_BACKGROUND); cardsContainer.setBackground(PANEL_BACKGROUND);
cardsContainer.setBorder(BorderFactory.createEmptyBorder(8, 8, 8, 8)); cardsContainer.setBorder(BorderFactory.createEmptyBorder(8, 8, 8, 8));
@ -145,14 +145,14 @@ public class PokemonGoGUI extends JFrame {
gbc.anchor = GridBagConstraints.NORTH; gbc.anchor = GridBagConstraints.NORTH;
gbc.insets = new Insets(0, 0, 12, 0); gbc.insets = new Insets(0, 0, 12, 0);
// Karta 1: Transfer automatizace // Card 1: Transfer automation
JPanel transferCard = createAutomationCard( JPanel transferCard = createAutomationCard(
"🔄 TRANSFER AUTOMATIZACE", "🔄 TRANSFER AUTOMATION",
"Hledá Pokémony, označí je a stiskne Transfer", "Finds Pokémon, selects them, and clicks Transfer",
null null
); );
// Najít START tlačítko - je v EAST pozici BorderLayoutu // Find START button - in EAST position of BorderLayout
JButton startBtnTransfer = findStartButton(transferCard); JButton startBtnTransfer = findStartButton(transferCard);
if (startBtnTransfer != null) { if (startBtnTransfer != null) {
@ -169,14 +169,14 @@ public class PokemonGoGUI extends JFrame {
gbc.gridy++; gbc.gridy++;
gbc.insets = new Insets(0, 0, 12, 0); gbc.insets = new Insets(0, 0, 12, 0);
// Karta 2: Autoklik // Card 2: Autoclick
JPanel autoClickCard = createAutomationCard( JPanel autoClickCard = createAutomationCard(
"🖱️ AUTOKLIK", "🖱️ AUTOCLICK",
"Automaticky klikuje na zadanou pozici", "Automatically clicks at a given position",
null null
); );
// Najít START tlačítko // Find START button
JButton startBtnAutoClick = findStartButton(autoClickCard); JButton startBtnAutoClick = findStartButton(autoClickCard);
if (startBtnAutoClick != null) { if (startBtnAutoClick != null) {
@ -228,7 +228,7 @@ public class PokemonGoGUI extends JFrame {
)); ));
logScrollPane.getViewport().setBackground(new Color(247, 247, 247)); 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)); clearLogButton.setPreferredSize(new Dimension(140, 28));
styleButton(clearLogButton, ACCENT_BLUE, Color.WHITE, SMALL_FONT); styleButton(clearLogButton, ACCENT_BLUE, Color.WHITE, SMALL_FONT);
clearLogButton.addActionListener(new ActionListener() { clearLogButton.addActionListener(new ActionListener() {
@ -255,13 +255,13 @@ public class PokemonGoGUI extends JFrame {
splitPane.setBorder(null); splitPane.setBorder(null);
splitPane.setBackground(PANEL_BACKGROUND); splitPane.setBackground(PANEL_BACKGROUND);
// Přidání do hlavního panelu // Add to main panel
mainPanel.add(headerPanel, BorderLayout.NORTH); mainPanel.add(headerPanel, BorderLayout.NORTH);
mainPanel.add(splitPane, BorderLayout.CENTER); mainPanel.add(splitPane, BorderLayout.CENTER);
add(mainPanel); 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); 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().getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(hotkey, "stopAutomationAction");
getRootPane().getActionMap().put("stopAutomationAction", new AbstractAction() { 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() { globalHotkey = new GlobalHotkey(new Runnable() {
@Override @Override
public void run() { public void run() {
@ -284,17 +284,17 @@ public class PokemonGoGUI extends JFrame {
}); });
mainPanel.add(globalHotkey, BorderLayout.SOUTH); 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(); redirectSystemStreams();
logArea.append("=== Pokémon GO Automatizace ===\n\n"); logArea.append("=== Pokémon GO Automation ===\n\n");
logArea.append("Vyberte jednu z automatizací a klikněte na tlačítko START.\n"); logArea.append("Select an automation and click START.\n");
logArea.append("Ujistěte se, že je aplikace Pokémon GO spuštěná.\n"); logArea.append("Make sure Pokémon GO is running.\n");
logArea.append("Pro zastavení stiskněte Ctrl+Alt+Q nebo klikněte ZASTAVIT.\n\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) { private JPanel createAutomationCard(String title, String description, ActionListener startAction) {
JPanel card = new JPanel(new BorderLayout(12, 12)); JPanel card = new JPanel(new BorderLayout(12, 12));
@ -303,7 +303,7 @@ public class PokemonGoGUI extends JFrame {
BorderFactory.createLineBorder(CARD_BORDER_COLOR, 1), BorderFactory.createLineBorder(CARD_BORDER_COLOR, 1),
BorderFactory.createEmptyBorder(8, 8, 8, 8) 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.setPreferredSize(new Dimension(CARD_MAX_WIDTH, 160));
card.setAlignmentX(Component.CENTER_ALIGNMENT); card.setAlignmentX(Component.CENTER_ALIGNMENT);
JPanel infoPanel = new JPanel(); JPanel infoPanel = new JPanel();
@ -330,9 +330,9 @@ public class PokemonGoGUI extends JFrame {
centerPanel.setOpaque(true); centerPanel.setOpaque(true);
if (title.contains("TRANSFER")) { 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")); 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}; int[] validCounts = {1, 3, 6, 12, 24, 36, 48, 60, 72, 84, 96};
boolean isValid = false; boolean isValid = false;
for (int count : validCounts) { for (int count : validCounts) {
@ -342,10 +342,10 @@ public class PokemonGoGUI extends JFrame {
} }
} }
if (!isValid) { 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}; Integer[] counts = {1, 3, 6, 12, 24, 36, 48, 60, 72, 84, 96};
countComboBox = new JComboBox<>(counts); countComboBox = new JComboBox<>(counts);
countComboBox.setSelectedItem(savedCount); countComboBox.setSelectedItem(savedCount);
@ -360,9 +360,9 @@ public class PokemonGoGUI extends JFrame {
card.putClientProperty("countComboBox", countComboBox); card.putClientProperty("countComboBox", countComboBox);
card.putClientProperty("delaySpinner", delaySpinner); card.putClientProperty("delaySpinner", delaySpinner);
centerPanel.add(createFieldPanel("Počet:", countComboBox)); centerPanel.add(createFieldPanel("Count:", countComboBox));
centerPanel.add(createFieldPanel("Čekání (s):", delaySpinner)); centerPanel.add(createFieldPanel("Delay (s):", delaySpinner));
} else if (title.contains("AUTOKLIK")) { } else if (title.contains("AUTOCLICK")) {
JSpinner intervalSpinner = new JSpinner(new SpinnerNumberModel( JSpinner intervalSpinner = new JSpinner(new SpinnerNumberModel(
Integer.parseInt(settings.getProperty("autoklik.interval", "100")), Integer.parseInt(settings.getProperty("autoklik.interval", "100")),
10, 10000, 10 10, 10000, 10
@ -373,23 +373,23 @@ public class PokemonGoGUI extends JFrame {
centerPanel.add(createFieldPanel("Interval (ms):", intervalSpinner)); 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)); JPanel rightPanel = new JPanel(new FlowLayout(FlowLayout.LEFT, 6, 0));
rightPanel.setBackground(CARD_BACKGROUND); rightPanel.setBackground(CARD_BACKGROUND);
rightPanel.setBorder(BorderFactory.createEmptyBorder(4, 0, 0, 0)); rightPanel.setBorder(BorderFactory.createEmptyBorder(4, 0, 0, 0));
// Tlačítko START / VYPNOUT // START / TURN OFF button
JButton startBtn = new JButton("▶ START"); JButton startBtn = new JButton("▶ START");
startBtn.setPreferredSize(new Dimension(100, 32)); startBtn.setPreferredSize(new Dimension(100, 32));
styleButton(startBtn, PRIMARY_GREEN, Color.WHITE, SMALL_FONT); styleButton(startBtn, PRIMARY_GREEN, Color.WHITE, SMALL_FONT);
startBtn.addActionListener(startAction); 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); card.putClientProperty("startButton", startBtn);
rightPanel.add(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(infoPanel, BorderLayout.NORTH);
card.add(centerPanel, BorderLayout.CENTER); card.add(centerPanel, BorderLayout.CENTER);
card.add(rightPanel, BorderLayout.SOUTH); 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() { private void redirectSystemStreams() {
System.setOut(new java.io.PrintStream(System.out) { 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) { private void startTransferAutomation(JPanel transferCard) {
if (isRunning) { 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; return;
} }
// Získat počet pokémonů a čekání z GUI // Get pokemon count and delay from GUI
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
JComboBox<Integer> countComboBox = (JComboBox<Integer>) transferCard.getClientProperty("countComboBox"); JComboBox<Integer> countComboBox = (JComboBox<Integer>) transferCard.getClientProperty("countComboBox");
JSpinner delaySpinner = (JSpinner) transferCard.getClientProperty("delaySpinner"); JSpinner delaySpinner = (JSpinner) transferCard.getClientProperty("delaySpinner");
@ -490,11 +490,11 @@ public class PokemonGoGUI extends JFrame {
int delaySeconds = (Integer) delaySpinner.getValue(); int delaySeconds = (Integer) delaySpinner.getValue();
stopButton.setEnabled(true); stopButton.setEnabled(true);
statusLabel.setText("Transfer automatizace běží..."); statusLabel.setText("Transfer automation running...");
statusLabel.setForeground(new Color(255, 152, 0)); statusLabel.setForeground(new Color(255, 152, 0));
isRunning = true; isRunning = true;
// Změnit barvu START tlačítka na červenou // Change START button color to red
JButton startBtn = (JButton) transferCard.getClientProperty("startButton"); JButton startBtn = (JButton) transferCard.getClientProperty("startButton");
if (startBtn != null) { if (startBtn != null) {
startBtn.setEnabled(false); startBtn.setEnabled(false);
@ -502,8 +502,8 @@ public class PokemonGoGUI extends JFrame {
} }
logArea.append("\n========================================\n"); logArea.append("\n========================================\n");
logArea.append("SPOUŠTĚNÍ TRANSFER AUTOMATIZACE\n"); logArea.append("STARTING TRANSFER AUTOMATION\n");
logArea.append("Počet pokémonů: " + pokemonCount + ", Čekání: " + delaySeconds + "s\n"); logArea.append("Pokémon count: " + pokemonCount + ", Delay: " + delaySeconds + "s\n");
logArea.append("========================================\n\n"); logArea.append("========================================\n\n");
shouldStop = false; shouldStop = false;
@ -514,19 +514,19 @@ public class PokemonGoGUI extends JFrame {
automation = new PokemonGoAutomation(); automation = new PokemonGoAutomation();
automation.resetTransferredCount(); automation.resetTransferredCount();
// Spustit vlákno pro aktualizaci statusu // Start thread for status update
Thread statusUpdateThread = new Thread(new Runnable() { Thread statusUpdateThread = new Thread(new Runnable() {
@Override @Override
public void run() { public void run() {
while (isRunning && !shouldStop && !Thread.currentThread().isInterrupted()) { while (isRunning && !shouldStop && !Thread.currentThread().isInterrupted()) {
try { try {
Thread.sleep(500); // Aktualizovat každých 500ms Thread.sleep(500); // Update every 500ms
final int transferred = automation.getTransferredCount(); final int transferred = automation.getTransferredCount();
SwingUtilities.invokeLater(new Runnable() { SwingUtilities.invokeLater(new Runnable() {
@Override @Override
public void run() { public void run() {
if (isRunning) { 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() { SwingUtilities.invokeLater(new Runnable() {
@Override @Override
public void run() { 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)); 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() { public void run() {
statusLabel.setText("Chyba!"); statusLabel.setText("Chyba!");
statusLabel.setForeground(new Color(244, 67, 54)); statusLabel.setForeground(new Color(244, 67, 54));
logArea.append("\n❌ Chyba: " + e.getMessage() + "\n"); logArea.append("\n❌ Error: " + e.getMessage() + "\n");
e.printStackTrace(); e.printStackTrace();
} }
}); });
} finally { } finally {
// Čistit prostředky po automatizaci // Clean up resources after automation
try { try {
if (automation != null) { if (automation != null) {
automation.cleanup(); automation.cleanup();
} }
// Také vyčistit WindowFinder resources // Also clean up WindowFinder resources
WindowFinder.cleanup(); WindowFinder.cleanup();
System.gc(); System.gc();
} catch (Exception cleanupEx) { } 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() { SwingUtilities.invokeLater(new Runnable() {
@ -583,7 +583,7 @@ public class PokemonGoGUI extends JFrame {
isRunning = false; isRunning = false;
stopButton.setEnabled(false); stopButton.setEnabled(false);
// Vrátit barvu START tlačítka na zelenou // Restore START button color to green
JButton btn = (JButton) transferCard.getClientProperty("startButton"); JButton btn = (JButton) transferCard.getClientProperty("startButton");
if (btn != null) { if (btn != null) {
btn.setEnabled(true); btn.setEnabled(true);
@ -599,7 +599,7 @@ public class PokemonGoGUI extends JFrame {
} }
/** /**
* Spustí autoklik * Start autoclick
*/ */
private void startAutoClick(JPanel autoClickCard) { private void startAutoClick(JPanel autoClickCard) {
if (autoClickRunning) { if (autoClickRunning) {
@ -608,36 +608,36 @@ public class PokemonGoGUI extends JFrame {
} }
if (isRunning) { 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; return;
} }
// Načtení nastavení // Load settings
JSpinner intervalSpinner = (JSpinner) autoClickCard.getClientProperty("intervalSpinner"); JSpinner intervalSpinner = (JSpinner) autoClickCard.getClientProperty("intervalSpinner");
int interval = (Integer) intervalSpinner.getValue(); int interval = (Integer) intervalSpinner.getValue();
// Uložení nastavení // Save settings
settings.setProperty("autoklik.interval", String.valueOf(interval)); settings.setProperty("autoklik.interval", String.valueOf(interval));
saveSettings(); saveSettings();
stopButton.setEnabled(true); stopButton.setEnabled(true);
statusLabel.setText("Autokliker aktivní (Šipka dolů)..."); statusLabel.setText("Autoclicker active (Down arrow)...");
statusLabel.setForeground(new Color(255, 152, 0)); statusLabel.setForeground(new Color(255, 152, 0));
isRunning = true; isRunning = true;
autoClickRunning = true; autoClickRunning = true;
shouldStop = false; shouldStop = false;
// Změnit tlačítko na VYPNOUT // Change button to TURN OFF
JButton startBtn = (JButton) autoClickCard.getClientProperty("startButton"); JButton startBtn = (JButton) autoClickCard.getClientProperty("startButton");
if (startBtn != null) { if (startBtn != null) {
startBtn.setText("VYPNOUT"); startBtn.setText("TURN OFF");
styleButton(startBtn, PRIMARY_RED, Color.WHITE, SMALL_FONT); styleButton(startBtn, PRIMARY_RED, Color.WHITE, SMALL_FONT);
} }
logArea.append("\n========================================\n"); logArea.append("\n========================================\n");
logArea.append("AUTOKLIKER AKTIVNÍ\n"); logArea.append("AUTOCCLICKER ACTIVE\n");
logArea.append("Interval: " + interval + "ms\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"); logArea.append("========================================\n\n");
automationThread = new Thread(new Runnable() { automationThread = new Thread(new Runnable() {
@ -652,44 +652,44 @@ public class PokemonGoGUI extends JFrame {
long lastToggleTime = 0; long lastToggleTime = 0;
while (autoClickRunning && !shouldStop) { while (autoClickRunning && !shouldStop) {
// Kontrola obou šipek // Check both arrows
boolean isKeyPressed = globalHotkey.isKeyPressed(KeyEvent.VK_DOWN) || boolean isKeyPressed = globalHotkey.isKeyPressed(KeyEvent.VK_DOWN) ||
globalHotkey.isKeyPressed(KeyEvent.VK_UP); globalHotkey.isKeyPressed(KeyEvent.VK_UP);
long currentTime = System.currentTimeMillis(); 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)) { if (isKeyPressed && !wasKeyPressed && (currentTime - lastToggleTime > 200)) {
isClickingActive = !isClickingActive; isClickingActive = !isClickingActive;
lastToggleTime = currentTime; lastToggleTime = currentTime;
final boolean active = isClickingActive; final boolean active = isClickingActive;
SwingUtilities.invokeLater(() -> { SwingUtilities.invokeLater(() -> {
logArea.append(active ? "Klikání AKTIVOVÁNO šipkou\n" : "⏸ Klikání POZASTAVENO šipkou\n"); logArea.append(active ? "Clicking ACTIVATED by arrow\n" : "⏸ Clicking PAUSED by arrow\n");
statusLabel.setText(active ? "Autokliker: KLIKÁM..." : "Autokliker: POZASTAVENO"); statusLabel.setText(active ? "Autoclicker: CLICKING..." : "Autoclicker: PAUSED");
}); });
if (isClickingActive) { if (isClickingActive) {
lastClickTime = 0; // Spustit klikání hned lastClickTime = 0; // Start clicking immediately
} }
} }
wasKeyPressed = isKeyPressed; wasKeyPressed = isKeyPressed;
if (isClickingActive) { if (isClickingActive) {
if (currentTime - lastClickTime >= interval) { if (currentTime - lastClickTime >= interval) {
// Klik na aktuální pozici // Click at current position
robot.mousePress(java.awt.event.InputEvent.BUTTON1_DOWN_MASK); robot.mousePress(java.awt.event.InputEvent.BUTTON1_DOWN_MASK);
robot.mouseRelease(java.awt.event.InputEvent.BUTTON1_DOWN_MASK); robot.mouseRelease(java.awt.event.InputEvent.BUTTON1_DOWN_MASK);
clicksDone++; clicksDone++;
if (clicksDone % 20 == 0) { if (clicksDone % 20 == 0) {
final int count = clicksDone; final int count = clicksDone;
SwingUtilities.invokeLater(() -> logArea.append(" Kliknutí: " + count + "\n")); SwingUtilities.invokeLater(() -> logArea.append(" Clicks: " + count + "\n"));
} }
lastClickTime = currentTime; lastClickTime = currentTime;
} }
} }
// Rychlá smyčka pro detekci kláves (10ms) // Fast loop for key detection (10ms)
Thread.sleep(10); Thread.sleep(10);
} }
@ -697,9 +697,9 @@ public class PokemonGoGUI extends JFrame {
SwingUtilities.invokeLater(new Runnable() { SwingUtilities.invokeLater(new Runnable() {
@Override @Override
public void run() { public void run() {
statusLabel.setText("Autokliker zastaven."); statusLabel.setText("Autoclicker stopped.");
statusLabel.setForeground(new Color(76, 175, 80)); 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() { SwingUtilities.invokeLater(new Runnable() {
@Override @Override
public void run() { public void run() {
statusLabel.setText("Chyba autoklikeru!"); statusLabel.setText("Autoclicker error!");
statusLabel.setForeground(new Color(244, 67, 54)); 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; autoClickRunning = false;
stopButton.setEnabled(false); stopButton.setEnabled(false);
// Vrátit tlačítko na START // Restore button to START
JButton btn = (JButton) autoClickCard.getClientProperty("startButton"); JButton btn = (JButton) autoClickCard.getClientProperty("startButton");
if (btn != null) { if (btn != null) {
btn.setText("▶ START"); btn.setText("▶ START");
@ -740,7 +740,7 @@ public class PokemonGoGUI extends JFrame {
} }
/** /**
* Zastaví automatizaci * Stop automation
*/ */
private void stopAutomation() { private void stopAutomation() {
if (!isRunning && !autoClickRunning) { if (!isRunning && !autoClickRunning) {
@ -757,7 +757,7 @@ public class PokemonGoGUI extends JFrame {
if (automationThread != null && automationThread.isAlive()) { if (automationThread != null && automationThread.isAlive()) {
automationThread.interrupt(); automationThread.interrupt();
// Čekej max 2 sekundy na ukončení // Wait max 2 seconds for shutdown
try { try {
automationThread.join(2000); automationThread.join(2000);
} catch (InterruptedException e) { } catch (InterruptedException e) {
@ -769,15 +769,15 @@ public class PokemonGoGUI extends JFrame {
@Override @Override
public void run() { public void run() {
stopButton.setEnabled(false); stopButton.setEnabled(false);
logArea.append("\n⚠ Automatizace byla přerušena uživatelem\n"); logArea.append("\n⚠ Automation was interrupted by user\n");
statusLabel.setText("Přerušeno"); statusLabel.setText("Interrupted");
statusLabel.setForeground(new Color(244, 67, 54)); statusLabel.setForeground(new Color(244, 67, 54));
} }
}); });
} }
/** /**
* Načte uložená nastavení ze souboru * Load saved settings from file
*/ */
private void loadSettings() { private void loadSettings() {
settings = new Properties(); settings = new Properties();
@ -787,11 +787,11 @@ public class PokemonGoGUI extends JFrame {
try (java.io.FileInputStream fis = new java.io.FileInputStream(configFile)) { try (java.io.FileInputStream fis = new java.io.FileInputStream(configFile)) {
settings.load(fis); settings.load(fis);
} catch (IOException e) { } 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")) { if (!settings.containsKey("transfer.count")) {
settings.setProperty("transfer.count", "12"); 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() { private void saveSettings() {
// Uložení hodnot z combo boxu a spinneru // Save values from combo box and spinner
if (countComboBox != null) { if (countComboBox != null) {
settings.setProperty("transfer.count", countComboBox.getSelectedItem().toString()); settings.setProperty("transfer.count", countComboBox.getSelectedItem().toString());
} }
@ -824,29 +824,29 @@ public class PokemonGoGUI extends JFrame {
settings.setProperty("transfer.delay", delaySpinner.getValue().toString()); 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.width", String.valueOf(getWidth()));
settings.setProperty("window.height", String.valueOf(getHeight())); settings.setProperty("window.height", String.valueOf(getHeight()));
settings.setProperty("window.x", String.valueOf(getX())); settings.setProperty("window.x", String.valueOf(getX()));
settings.setProperty("window.y", String.valueOf(getY())); settings.setProperty("window.y", String.valueOf(getY()));
try (java.io.FileOutputStream fos = new java.io.FileOutputStream(CONFIG_FILE)) { 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) { } 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) { 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(() -> { Runtime.getRuntime().addShutdownHook(new Thread(() -> {
System.out.println("Aplikace se vypíná..."); System.out.println("Application is shutting down...");
// Vyčistit X11 resources // Vyčistit X11 resources
try { try {
WindowFinder.cleanup(); WindowFinder.cleanup();
} catch (Exception e) { } 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(); PokemonGoGUI frame = new PokemonGoGUI();
frame.setVisible(true); frame.setVisible(true);
// Nastavit window listener pro čisté ukončení // Set window listener for clean shutdown
frame.addWindowListener(new java.awt.event.WindowAdapter() { frame.addWindowListener(new java.awt.event.WindowAdapter() {
@Override @Override
public void windowClosing(WindowEvent e) { public void windowClosing(WindowEvent e) {
System.out.println("Zavírám okno..."); System.out.println("Closing window...");
if (frame.globalHotkey != null) { if (frame.globalHotkey != null) {
frame.globalHotkey.cleanup(); frame.globalHotkey.cleanup();
} }

View File

@ -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;
}
}

View File

@ -11,8 +11,8 @@ import java.util.Arrays;
import java.util.List; import java.util.List;
/** /**
* Pomocná třída pro hledání oken v Linux/X11 prostředí. * Helper class for finding windows in Linux/X11 environment.
* Používá X11 API přes JNA bindings. * Uses X11 API via JNA bindings.
*/ */
public class WindowFinder { public class WindowFinder {
@ -25,7 +25,7 @@ public class WindowFinder {
X11 INSTANCE = Native.load("X11", X11.class); 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 { class XWindowAttributes extends Structure {
public int x; public int x;
@ -79,13 +79,13 @@ public class WindowFinder {
int XFetchName(Pointer display, long window, PointerByReference window_name_return); 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, boolean XTranslateCoordinates(Pointer display, long src_w, long dest_w,
int src_x, int src_y, int src_x, int src_y,
IntByReference dest_x_return, IntByReference dest_y_return, IntByReference dest_x_return, IntByReference dest_y_return,
PointerByReference child_return); PointerByReference child_return);
// Globální klávesy // Global keys
int XQueryKeymap(Pointer display, byte[] keys_return); int XQueryKeymap(Pointer display, byte[] keys_return);
int XKeysymToKeycode(Pointer display, long keysym); 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) * Checks if a key is pressed globally (even outside application focus)
* @param keysym X11 Keysym (např. 0xFF54 pro Down Arrow) * @param keysym X11 Keysym (e.g. 0xFF54 for Down Arrow)
* @return true pokud je klávesa držena * @return true if key is held
*/ */
public static synchronized boolean isKeyPressedGlobally(long keysym) { public static synchronized boolean isKeyPressedGlobally(long keysym) {
Pointer display = null; Pointer display = null;
@ -128,51 +128,51 @@ public class WindowFinder {
} }
/** /**
* Najde okno podle jeho názvu a vrátí jeho bounds * Finds window by its name and returns its bounds
* @param searchPattern Pattern pro hledání (substring názvu okna) * @param searchPattern Pattern for searching (substring of window name)
* @return Rectangle s pozicí a velikostí okna, nebo null pokud nenalezeno * @return Rectangle with position and size of window, or null if not found
*/ */
public static synchronized Rectangle findWindowByName(String searchPattern) { public static synchronized Rectangle findWindowByName(String searchPattern) {
Pointer display = null; Pointer display = null;
try { try {
// Použít cachedDisplay pokud existuje, nebo otevřít nový // Use cachedDisplay if it exists, or open new
if (cachedDisplay != null) { if (cachedDisplay != null) {
display = cachedDisplay; display = cachedDisplay;
System.out.println("WindowFinder: Používám cachovaný X11 display"); System.out.println("WindowFinder: Using cached X11 display");
} else { } else {
display = X11.INSTANCE.XOpenDisplay(null); display = X11.INSTANCE.XOpenDisplay(null);
if (display == 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; return null;
} }
cachedDisplay = display; 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); long rootWindow = X11.INSTANCE.XDefaultRootWindow(display);
// Hledat okno a vrátit bounds // Search for window and return bounds
Rectangle bounds = searchWindowRecursiveWithBounds(display, rootWindow, searchPattern); Rectangle bounds = searchWindowRecursiveWithBounds(display, rootWindow, searchPattern);
if (bounds != null) { if (bounds != null) {
System.out.println("WindowFinder: Okno nalezeno: " + bounds); System.out.println("WindowFinder: Window found: " + bounds);
return 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; return null;
} catch (Exception e) { } catch (Exception e) {
System.err.println("WindowFinder - Chyba: " + e.getMessage()); System.err.println("WindowFinder - Error: " + e.getMessage());
e.printStackTrace(); 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) { if (display != null && display == cachedDisplay) {
try { try {
X11.INSTANCE.XCloseDisplay(display); X11.INSTANCE.XCloseDisplay(display);
cachedDisplay = null; cachedDisplay = null;
} catch (Exception ex) { } 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; 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, private static Rectangle searchWindowRecursiveWithBounds(Pointer display, long window,
String searchPattern) { String searchPattern) {
try { try {
String windowName = getWindowNameString(display, window); String windowName = getWindowNameString(display, window);
if (windowName != null && windowName.contains(searchPattern)) { 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); return getWindowBounds(display, window);
} }
} catch (Exception e) { } 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(); PointerByReference children_return = new PointerByReference();
IntByReference nchildren_return = new IntByReference(); IntByReference nchildren_return = new IntByReference();
@ -210,7 +210,7 @@ public class WindowFinder {
int numChildren = nchildren_return.getValue(); int numChildren = nchildren_return.getValue();
if (childrenPtr != null) { if (childrenPtr != null) {
// Čtení window IDs z pole // Reading window IDs from array
for (int i = 0; i < numChildren; i++) { for (int i = 0; i < numChildren; i++) {
long childWindow = childrenPtr.getLong((long) i * 8); // 64-bit window IDs long childWindow = childrenPtr.getLong((long) i * 8); // 64-bit window IDs
@ -224,14 +224,14 @@ public class WindowFinder {
} }
} }
} catch (Exception e) { } catch (Exception e) {
// Ignorovat chyby při hledání v potomcích // Ignore errors when searching in children
} }
return null; return null;
} }
/** /**
* Získá jméno okna jako String * Gets window name as String
*/ */
private static String getWindowNameString(Pointer display, long window) { private static String getWindowNameString(Pointer display, long window) {
PointerByReference namePtr = new PointerByReference(); PointerByReference namePtr = new PointerByReference();
@ -258,8 +258,8 @@ public class WindowFinder {
} }
/** /**
* Získá bounds okna (pozici a velikost) - ABSOLUTNÍ pozici na obrazovce * Gets window bounds (position and size) - ABSOLUTE position on screen
* Používá XTranslateCoordinates na správný převod souřadnic z okna do root * Uses XTranslateCoordinates for correct conversion of coordinates from window to root
*/ */
private static Rectangle getWindowBounds(Pointer display, Long window) { private static Rectangle getWindowBounds(Pointer display, Long window) {
try { try {
@ -267,11 +267,11 @@ public class WindowFinder {
int status = X11.INSTANCE.XGetWindowAttributes(display, window, attrs); int status = X11.INSTANCE.XGetWindowAttributes(display, window, attrs);
if (status == 0) { 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; 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); long rootWindow = X11.INSTANCE.XDefaultRootWindow(display);
IntByReference absX = new IntByReference(); IntByReference absX = new IntByReference();
IntByReference absY = new IntByReference(); IntByReference absY = new IntByReference();
@ -281,21 +281,21 @@ public class WindowFinder {
0, 0, absX, absY, child); 0, 0, absX, absY, child);
if (!translated) { if (!translated) {
System.err.println("WindowFinder - Chyba při XTranslateCoordinates"); System.err.println("WindowFinder - Error in XTranslateCoordinates");
// Fallback - vrátit alespoň relativní pozici // Fallback - return at least relative position
return new Rectangle(attrs.x, attrs.y, attrs.width, attrs.height); return new Rectangle(attrs.x, attrs.y, attrs.width, attrs.height);
} }
int absoluteX = absX.getValue(); int absoluteX = absX.getValue();
int absoluteY = absY.getValue(); int absoluteY = absY.getValue();
System.out.println("WindowFinder: Window bounds - ABSOLUT: x:" + absoluteX + " y:" + absoluteY + System.out.println("WindowFinder: Window bounds - ABSOLUTE: x:" + absoluteX + " y:" + absoluteY +
" w:" + attrs.width + " h:" + attrs.height); " w:" + attrs.width + " h:" + attrs.height);
return new Rectangle(absoluteX, absoluteY, attrs.width, attrs.height); return new Rectangle(absoluteX, absoluteY, attrs.width, attrs.height);
} catch (Exception e) { } 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(); e.printStackTrace();
} }
@ -303,16 +303,16 @@ public class WindowFinder {
} }
/** /**
* Ukončí X11 display connection a vyčistí cache * Closes X11 display connection and clears cache
* Volat při shutdown aplikace * Call on application shutdown
*/ */
public static synchronized void cleanup() { public static synchronized void cleanup() {
if (cachedDisplay != null) { if (cachedDisplay != null) {
try { try {
X11.INSTANCE.XCloseDisplay(cachedDisplay); 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) { } 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 { } finally {
cachedDisplay = null; cachedDisplay = null;
} }