autoclicker reimplemented
This commit is contained in:
parent
37f49c5f33
commit
0998ba3762
@ -1,12 +1,13 @@
|
||||
#Pokémon GO Automatizace - Nastavení
|
||||
#Sat Dec 20 18:52:36 CET 2025
|
||||
autoklik.count=1
|
||||
#Fri Jan 23 16:03:46 CET 2026
|
||||
autoklik.count=1000
|
||||
window.width=807
|
||||
transfer.delay=0
|
||||
autoklik.x=2123
|
||||
window.height=743
|
||||
autoklik.x=2093
|
||||
autoklik.y=670
|
||||
autoklik.downArrow=true
|
||||
autoklik.y=1129
|
||||
autoklik.interval=150
|
||||
transfer.count=6
|
||||
window.x=1143
|
||||
autoklik.interval=100
|
||||
window.y=595
|
||||
window.x=887
|
||||
window.y=505
|
||||
|
||||
@ -17,9 +17,39 @@ public class GlobalHotkey extends JLabel {
|
||||
public GlobalHotkey(Runnable onHotkey) {
|
||||
this.globalKeyListener = new GlobalKeyListener(onHotkey);
|
||||
|
||||
// Registrace globálního key listeneru
|
||||
// Registrace globálního key listeneru pro případy, kdy má aplikace fokus
|
||||
KeyboardFocusManager.getCurrentKeyboardFocusManager()
|
||||
.addKeyEventDispatcher(globalKeyListener);
|
||||
|
||||
// Spustit nativní polling pro globální STOP hotkey na Linuxu (funguje i bez fokusu)
|
||||
if (System.getProperty("os.name").toLowerCase().contains("linux")) {
|
||||
Thread pollingThread = new Thread(() -> {
|
||||
while (true) {
|
||||
try {
|
||||
Thread.sleep(150);
|
||||
// Kontrola CTRL+ALT+X globálně
|
||||
// XK_Control_L/R: 0xFFE3/4, XK_Alt_L/R: 0xFFE9/A, XK_x: 0x78, XK_X: 0x58
|
||||
boolean ctrl = WindowFinder.isKeyPressedGlobally(0xFFE3) || WindowFinder.isKeyPressedGlobally(0xFFE4);
|
||||
boolean alt = WindowFinder.isKeyPressedGlobally(0xFFE9) || WindowFinder.isKeyPressedGlobally(0xFFEA);
|
||||
boolean xPressed = WindowFinder.isKeyPressedGlobally(0x78) || WindowFinder.isKeyPressedGlobally(0x58);
|
||||
|
||||
if (ctrl && alt && xPressed) {
|
||||
if (onHotkey != null) {
|
||||
System.out.println("🔌 Globální NATIVNÍ hotkey detekován: CTRL+ALT+X");
|
||||
onHotkey.run();
|
||||
Thread.sleep(1000); // Prevence vícenásobného spuštění
|
||||
}
|
||||
}
|
||||
} catch (InterruptedException e) {
|
||||
break;
|
||||
} catch (Exception e) {
|
||||
// Ignorovat chyby v pollingu
|
||||
}
|
||||
}
|
||||
}, "GlobalHotkeyPolling");
|
||||
pollingThread.setDaemon(true);
|
||||
pollingThread.start();
|
||||
}
|
||||
}
|
||||
|
||||
public static GlobalHotkey create(Runnable onHotkey) {
|
||||
@ -29,6 +59,23 @@ public class GlobalHotkey extends JLabel {
|
||||
return instance;
|
||||
}
|
||||
|
||||
public boolean isKeyPressed(int keyCode) {
|
||||
// Na Linuxu pro šipky používáme výhradně nativní globální detekci.
|
||||
// Standardní KeyEventDispatcher se může "zaseknout", pokud okno ztratí fokus během stisku.
|
||||
if (System.getProperty("os.name").toLowerCase().contains("linux")) {
|
||||
if (keyCode == KeyEvent.VK_DOWN) {
|
||||
try {
|
||||
return WindowFinder.isKeyPressedGlobally(0xFF54); // XK_Down
|
||||
} catch (Exception e) {}
|
||||
} else if (keyCode == KeyEvent.VK_UP) {
|
||||
try {
|
||||
return WindowFinder.isKeyPressedGlobally(0xFF52); // XK_Up
|
||||
} catch (Exception e) {}
|
||||
}
|
||||
}
|
||||
return globalKeyListener.isKeyPressed(keyCode);
|
||||
}
|
||||
|
||||
/**
|
||||
* Interní třída pro globální naslouchání na klávesnici
|
||||
*/
|
||||
@ -40,6 +87,10 @@ public class GlobalHotkey extends JLabel {
|
||||
this.callback = callback;
|
||||
}
|
||||
|
||||
public boolean isKeyPressed(int keyCode) {
|
||||
return pressedKeys.contains(keyCode);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean dispatchKeyEvent(KeyEvent e) {
|
||||
if (e.getID() == KeyEvent.KEY_PRESSED) {
|
||||
|
||||
@ -363,92 +363,24 @@ public class PokemonGoGUI extends JFrame {
|
||||
centerPanel.add(createFieldPanel("Počet:", countComboBox));
|
||||
centerPanel.add(createFieldPanel("Čekání (s):", delaySpinner));
|
||||
} else if (title.contains("AUTOKLIK")) {
|
||||
JSpinner xSpinner = new JSpinner(new SpinnerNumberModel(
|
||||
Integer.parseInt(settings.getProperty("autoklik.x", "960")),
|
||||
0, 9999, 1
|
||||
));
|
||||
xSpinner.setPreferredSize(new Dimension(70, 26));
|
||||
card.putClientProperty("xSpinner", xSpinner);
|
||||
|
||||
JSpinner ySpinner = new JSpinner(new SpinnerNumberModel(
|
||||
Integer.parseInt(settings.getProperty("autoklik.y", "540")),
|
||||
0, 9999, 1
|
||||
));
|
||||
ySpinner.setPreferredSize(new Dimension(70, 26));
|
||||
card.putClientProperty("ySpinner", ySpinner);
|
||||
|
||||
JSpinner intervalSpinner = new JSpinner(new SpinnerNumberModel(
|
||||
Integer.parseInt(settings.getProperty("autoklik.interval", "100")),
|
||||
10, 10000, 10
|
||||
));
|
||||
intervalSpinner.setPreferredSize(new Dimension(70, 26));
|
||||
intervalSpinner.setPreferredSize(new Dimension(80, 26));
|
||||
card.putClientProperty("intervalSpinner", intervalSpinner);
|
||||
|
||||
JSpinner clickCountSpinner = new JSpinner(new SpinnerNumberModel(
|
||||
Integer.parseInt(settings.getProperty("autoklik.count", "10")),
|
||||
1, 10000, 1
|
||||
));
|
||||
clickCountSpinner.setPreferredSize(new Dimension(70, 26));
|
||||
card.putClientProperty("clickCountSpinner", clickCountSpinner);
|
||||
|
||||
centerPanel.add(createFieldPanel("X:", xSpinner));
|
||||
centerPanel.add(createFieldPanel("Y:", ySpinner));
|
||||
centerPanel.add(createFieldPanel("Interval (ms):", intervalSpinner));
|
||||
centerPanel.add(createFieldPanel("Počet kliknutí:", clickCountSpinner));
|
||||
}
|
||||
|
||||
// Pravý panel - START a Nastavit (pro AUTOKLIK) tlačítka
|
||||
// Pravý panel - START tlačítko (a u Autokliku i STOP v rámci tlačítka)
|
||||
JPanel rightPanel = new JPanel(new FlowLayout(FlowLayout.LEFT, 6, 0));
|
||||
rightPanel.setBackground(CARD_BACKGROUND);
|
||||
rightPanel.setBorder(BorderFactory.createEmptyBorder(4, 0, 0, 0));
|
||||
|
||||
// Tlačítko Nastavit pro AUTOKLIK
|
||||
if (title.contains("AUTOKLIK")) {
|
||||
JSpinner xSpinner = (JSpinner) card.getClientProperty("xSpinner");
|
||||
JSpinner ySpinner = (JSpinner) card.getClientProperty("ySpinner");
|
||||
|
||||
JButton settingsBtn = new JButton("⚙ Nastavit");
|
||||
settingsBtn.setPreferredSize(new Dimension(100, 32));
|
||||
styleButton(settingsBtn, ACCENT_BLUE, Color.WHITE, SMALL_FONT);
|
||||
settingsBtn.addActionListener(new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
PositionPicker picker = new PositionPicker(null);
|
||||
|
||||
new Thread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
picker.setVisible(true);
|
||||
|
||||
while (picker.isVisible()) {
|
||||
try {
|
||||
Thread.sleep(50);
|
||||
} catch (InterruptedException ex) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (picker.isPositionSelected()) {
|
||||
Point pos = picker.getSelectedPosition();
|
||||
SwingUtilities.invokeLater(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
xSpinner.setValue(pos.x);
|
||||
ySpinner.setValue(pos.y);
|
||||
logArea.append("✅ Pozice nastavena: (" + pos.x + ", " + pos.y + ")\n");
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}).start();
|
||||
}
|
||||
});
|
||||
rightPanel.add(settingsBtn);
|
||||
}
|
||||
|
||||
// Tlačítko START
|
||||
// Tlačítko START / VYPNOUT
|
||||
JButton startBtn = new JButton("▶ START");
|
||||
startBtn.setPreferredSize(new Dimension(90, 32));
|
||||
startBtn.setPreferredSize(new Dimension(100, 32));
|
||||
styleButton(startBtn, PRIMARY_GREEN, Color.WHITE, SMALL_FONT);
|
||||
startBtn.addActionListener(startAction);
|
||||
|
||||
@ -669,51 +601,42 @@ public class PokemonGoGUI extends JFrame {
|
||||
* Spustí autoklik
|
||||
*/
|
||||
private void startAutoClick(JPanel autoClickCard) {
|
||||
if (autoClickRunning) {
|
||||
stopAutomation();
|
||||
return;
|
||||
}
|
||||
|
||||
if (isRunning) {
|
||||
JOptionPane.showMessageDialog(this, "Automatizace již běží!", "Upozornění", JOptionPane.WARNING_MESSAGE);
|
||||
JOptionPane.showMessageDialog(this, "Jiná automatizace již běží!", "Upozornění", JOptionPane.WARNING_MESSAGE);
|
||||
return;
|
||||
}
|
||||
|
||||
// Načtení nastavení
|
||||
JSpinner xSpinner = (JSpinner) autoClickCard.getClientProperty("xSpinner");
|
||||
JSpinner ySpinner = (JSpinner) autoClickCard.getClientProperty("ySpinner");
|
||||
JSpinner intervalSpinner = (JSpinner) autoClickCard.getClientProperty("intervalSpinner");
|
||||
JSpinner clickCountSpinner = (JSpinner) autoClickCard.getClientProperty("clickCountSpinner");
|
||||
|
||||
int x = (Integer) xSpinner.getValue();
|
||||
int y = (Integer) ySpinner.getValue();
|
||||
int interval = (Integer) intervalSpinner.getValue();
|
||||
int clickCount = (Integer) clickCountSpinner.getValue();
|
||||
|
||||
// Uložení nastavení
|
||||
settings.setProperty("autoklik.x", String.valueOf(x));
|
||||
settings.setProperty("autoklik.y", String.valueOf(y));
|
||||
settings.setProperty("autoklik.interval", String.valueOf(interval));
|
||||
settings.setProperty("autoklik.count", String.valueOf(clickCount));
|
||||
saveSettings();
|
||||
|
||||
// Uložit pozici myši před spuštěním
|
||||
PointerInfo pointerInfo = MouseInfo.getPointerInfo();
|
||||
Point originalMousePosition = pointerInfo != null ? pointerInfo.getLocation() : null;
|
||||
|
||||
stopButton.setEnabled(true);
|
||||
statusLabel.setText("Autoklik běží... (" + x + ", " + y + ")");
|
||||
statusLabel.setText("Autokliker aktivní (Šipka dolů)...");
|
||||
statusLabel.setForeground(new Color(255, 152, 0));
|
||||
isRunning = true;
|
||||
autoClickRunning = true;
|
||||
shouldStop = false;
|
||||
|
||||
// Změnit barvu START tlačítka na červenou
|
||||
// Změnit tlačítko na VYPNOUT
|
||||
JButton startBtn = (JButton) autoClickCard.getClientProperty("startButton");
|
||||
if (startBtn != null) {
|
||||
startBtn.setEnabled(false);
|
||||
startBtn.setText("⏹ VYPNOUT");
|
||||
styleButton(startBtn, PRIMARY_RED, Color.WHITE, SMALL_FONT);
|
||||
}
|
||||
|
||||
logArea.append("\n========================================\n");
|
||||
logArea.append("SPOUŠTĚNÍ AUTOKLIKERU\n");
|
||||
logArea.append("Pozice: (" + x + ", " + y + ")\n");
|
||||
logArea.append("Interval: " + interval + "ms, Počet kliknutí: " + clickCount + "\n");
|
||||
logArea.append("AUTOKLIKER AKTIVNÍ\n");
|
||||
logArea.append("Interval: " + interval + "ms\n");
|
||||
logArea.append("Ovládání: Stiskněte ŠIPKU NAHORU nebo DOLŮ pro zapnutí/vypnutí\n");
|
||||
logArea.append("========================================\n\n");
|
||||
|
||||
automationThread = new Thread(new Runnable() {
|
||||
@ -721,42 +644,61 @@ public class PokemonGoGUI extends JFrame {
|
||||
public void run() {
|
||||
try {
|
||||
java.awt.Robot robot = new java.awt.Robot();
|
||||
int clicksDone = 0;
|
||||
boolean isClickingActive = false;
|
||||
boolean wasKeyPressed = false;
|
||||
long lastClickTime = 0;
|
||||
long lastToggleTime = 0;
|
||||
|
||||
logArea.append("Spouštím autoklik...\n");
|
||||
while (autoClickRunning && !shouldStop) {
|
||||
// Kontrola obou šipek
|
||||
boolean isKeyPressed = globalHotkey.isKeyPressed(KeyEvent.VK_DOWN) ||
|
||||
globalHotkey.isKeyPressed(KeyEvent.VK_UP);
|
||||
long currentTime = System.currentTimeMillis();
|
||||
|
||||
for (int i = 0; i < clickCount && autoClickRunning && !shouldStop; i++) {
|
||||
// Přesunutí kurzoru na pozici
|
||||
robot.mouseMove(x, y);
|
||||
Thread.sleep(10);
|
||||
// Detekce stisku (náběžná hrana) pro přepnutí stavu
|
||||
if (isKeyPressed && !wasKeyPressed && (currentTime - lastToggleTime > 200)) {
|
||||
isClickingActive = !isClickingActive;
|
||||
lastToggleTime = currentTime;
|
||||
|
||||
// Klik
|
||||
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");
|
||||
});
|
||||
|
||||
if (isClickingActive) {
|
||||
lastClickTime = 0; // Spustit klikání hned
|
||||
}
|
||||
}
|
||||
wasKeyPressed = isKeyPressed;
|
||||
|
||||
if (isClickingActive) {
|
||||
if (currentTime - lastClickTime >= interval) {
|
||||
// Klik na aktuální pozici
|
||||
robot.mousePress(java.awt.event.InputEvent.BUTTON1_DOWN_MASK);
|
||||
robot.mouseRelease(java.awt.event.InputEvent.BUTTON1_DOWN_MASK);
|
||||
|
||||
// Čekání mezi kliknutími
|
||||
if (i < clickCount - 1 && !shouldStop) {
|
||||
Thread.sleep(interval);
|
||||
clicksDone++;
|
||||
if (clicksDone % 20 == 0) {
|
||||
final int count = clicksDone;
|
||||
SwingUtilities.invokeLater(() -> logArea.append(" Kliknutí: " + count + "\n"));
|
||||
}
|
||||
lastClickTime = currentTime;
|
||||
}
|
||||
}
|
||||
|
||||
// Update progress každých 10 kliknutí
|
||||
if ((i + 1) % 10 == 0 && !shouldStop) {
|
||||
int progress = i + 1;
|
||||
SwingUtilities.invokeLater(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
logArea.append(" Kliknutí: " + progress + "/" + clickCount + "\n");
|
||||
}
|
||||
});
|
||||
}
|
||||
// Rychlá smyčka pro detekci kláves (10ms)
|
||||
Thread.sleep(10);
|
||||
}
|
||||
|
||||
if (!shouldStop) {
|
||||
SwingUtilities.invokeLater(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
statusLabel.setText("Autoklik úspěšně dokončen!");
|
||||
statusLabel.setText("Autokliker zastaven.");
|
||||
statusLabel.setForeground(new Color(76, 175, 80));
|
||||
logArea.append("\n✅ Autoklik úspěšně dokončen! Celkem kliknutí: " + clickCount + "\n");
|
||||
logArea.append("\n✅ Autokliker byl vypnut.\n");
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -767,25 +709,13 @@ public class PokemonGoGUI extends JFrame {
|
||||
SwingUtilities.invokeLater(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
statusLabel.setText("Chyba!");
|
||||
statusLabel.setText("Chyba autoklikeru!");
|
||||
statusLabel.setForeground(new Color(244, 67, 54));
|
||||
logArea.append("\n❌ Chyba: " + e.getMessage() + "\n");
|
||||
e.printStackTrace();
|
||||
}
|
||||
});
|
||||
}
|
||||
} finally {
|
||||
// Vrátit myš na původní pozici
|
||||
if (originalMousePosition != null) {
|
||||
try {
|
||||
java.awt.Robot robot = new java.awt.Robot();
|
||||
robot.mouseMove(originalMousePosition.x, originalMousePosition.y);
|
||||
logArea.append("🖱️ Myš vrácena na původní pozici: (" + originalMousePosition.x + ", " + originalMousePosition.y + ")\n");
|
||||
} catch (Exception e) {
|
||||
System.err.println("Chyba při vracení myši: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
SwingUtilities.invokeLater(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
@ -793,10 +723,10 @@ public class PokemonGoGUI extends JFrame {
|
||||
autoClickRunning = false;
|
||||
stopButton.setEnabled(false);
|
||||
|
||||
// Vrátit barvu START tlačítka na zelenou
|
||||
// Vrátit tlačítko na START
|
||||
JButton btn = (JButton) autoClickCard.getClientProperty("startButton");
|
||||
if (btn != null) {
|
||||
btn.setEnabled(true);
|
||||
btn.setText("▶ START");
|
||||
styleButton(btn, PRIMARY_GREEN, Color.WHITE, SMALL_FONT);
|
||||
}
|
||||
}
|
||||
|
||||
@ -85,9 +85,48 @@ public class WindowFinder {
|
||||
IntByReference dest_x_return, IntByReference dest_y_return,
|
||||
PointerByReference child_return);
|
||||
|
||||
// Globální klávesy
|
||||
int XQueryKeymap(Pointer display, byte[] keys_return);
|
||||
int XKeysymToKeycode(Pointer display, long keysym);
|
||||
|
||||
Pointer XFree(Pointer ptr);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
public static synchronized boolean isKeyPressedGlobally(long keysym) {
|
||||
Pointer display = null;
|
||||
try {
|
||||
if (cachedDisplay != null) {
|
||||
display = cachedDisplay;
|
||||
} else {
|
||||
display = X11.INSTANCE.XOpenDisplay(null);
|
||||
if (display == null) return false;
|
||||
cachedDisplay = display;
|
||||
}
|
||||
|
||||
int keycode = X11.INSTANCE.XKeysymToKeycode(display, keysym);
|
||||
if (keycode == 0) return false;
|
||||
|
||||
byte[] keys = new byte[32];
|
||||
X11.INSTANCE.XQueryKeymap(display, keys);
|
||||
|
||||
// bitmask v XQueryKeymap: keycode / 8 je index bajtu, (keycode % 8) je pozice bitu
|
||||
int byteIdx = keycode / 8;
|
||||
int bitIdx = keycode % 8;
|
||||
|
||||
if (byteIdx >= 0 && byteIdx < 32) {
|
||||
return (keys[byteIdx] & (1 << bitIdx)) != 0;
|
||||
}
|
||||
return false;
|
||||
} catch (Exception e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Najde okno podle jeho názvu a vrátí jeho bounds
|
||||
* @param searchPattern Pattern pro hledání (substring názvu okna)
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user