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í
#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

View File

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

View File

@ -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 aplikace fokus
// Register global key listener for cases when application has focus
KeyboardFocusManager.getCurrentKeyboardFocusManager()
.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()) {
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.
// Standard 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
}
}
}

View File

@ -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 Relativ X pozice (0.0 = levý okraj, 1.0 = pravý okraj)
* @param relativeY Relativ Y pozice (0.0 = horní okraj, 1.0 = dolní okraj)
* @return Absolut 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;
// Explicit 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...");
}
}

View File

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

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;
/**
* 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 - ABSOLUT: 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;
}