How to ask for a keybind within an action - java

I was playing around in Java and trying to make an autoclicker just as a challenge for myself. I was making key bindings to turn it on and off when I discovered that I needed to turn off a while loop from a different class. Normally I would think this to be easy but I am using actions, so the action keeps playing until it is broken. I thought about it for a little bit and came to the conclusion that I needed to ask for a keybind within an action, but I have no idea how to do this. Here is my code right now if you want to help me make some improvements
package autoclicker;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class Autoclicker {
JFrame frame;
JLabel label;
boolean endis;
Action enableAction;
public Autoclicker() {
frame = new JFrame("Autoclicker");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(420, 420);
frame.setLayout(null);
label = new JLabel();
label.setBackground(Color.red);
label.setBounds(100, 100, 100, 100);
label.setOpaque(true);
enableAction = new EnableAction();
label.getInputMap().put(KeyStroke.getKeyStroke("UP"), "enableAction");
label.getActionMap().put("enableAction", enableAction);
frame.add(label);
frame.setVisible(true);
}
public class EnableAction extends AbstractAction {
#Override
public void actionPerformed(ActionEvent e) {
endis = true;
try {
Robot robot = new Robot();
while(endis) {
robot.mousePress(InputEvent.BUTTON1_MASK);
robot.mouseRelease(InputEvent.BUTTON1_MASK);
}
} catch (AWTException e1) {
e1.printStackTrace();
}
}
}
}

Assuming you want to use your autoclicker on other programs besides the java application, this isn't an easy thing to do. Java Swing was only designed to get events (such as keyboard presses) from the window that's currently focused on.
However, according to MasterID on this stack overflow post, it is possible with this library: https://github.com/kwhat/jnativehook. I haven't used this library myself though.
I've made my own auto clicker a long time ago, and here's how I dealt with exiting the loop. Mouse Position is something that is easy to get in Java. MouseInfo.getPointerInfo().getLocation(); So, rather than breaking on a keypress (requiring JFrame focus in Swing), you can break on if the mouse has been moved. In your loop, if the mouse is ever not in the same position, that means it has been moved, so exit the loop.
Perhaps something like this:
public void mainLoop() {
// Sleep for an amount of time to get mouse into proper position
Thread.sleep(4000);
...
Point p = MouseInfo.getPointerInfo().getLocation();
int lastX = (int)p.getX();
int lastY = (int)p.getY();
while(!isMoved(lastX, lastY)) {
// Do Click or other Stuff...
}
}
/** Returns true if the last x and y position don't match the current mouse x and y position on the screen. False if same position. */
public boolean isMoved(int lastX, int lastY){
Point p = MouseInfo.getPointerInfo().getLocation();
return (int)p.getX() != lastX || (int)p.getY() != lastY;
}
This breaks out of the loop if the mouse is ever moved. And if you want to use Robot.mouseMove(), you could make a simple wrapper class for Robot to handle updating the last position for you.

Related

Keyboard input trigger mouse click

I want to create a program / script which triggers mouse clicks or drag an drops when the keyboard is used. For example: If u press 1, the mouse location is saved. If u press 2 the mouse will go to the saved location. I know this is possible in different programming languages and i was wondering which one is the best to use for this purpose. And could someone give me a little headstart?
Edit:
import java.awt.MouseInfo;
import java.awt.Robot;
import java.awt.event.KeyEvent;
import javax.swing.JFrame;
import java.awt.AWTException;
import java.awt.event.*;
public class nudan implements KeyListener{
int x1;
int y1;
public static void main(String[] args) throws AWTException{
JFrame jf = new JFrame("Key Event");
jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
jf.addKeyListener(new nudan());
jf.setVisible(true);
jf.setAlwaysOnTop(true);
Robot rt = new Robot();
}
#Override
public void keyPressed(KeyEvent e) {
if(e.getKeyCode() == e.VK_NUMPAD1){
System.out.println("Key Pressed: " + e.getKeyChar());
this.y1 = MouseInfo.getPointerInfo().getLocation().y;
this.x1 = MouseInfo.getPointerInfo().getLocation().x;
}
}
#Override
public void keyReleased(KeyEvent e) {
if(e.getKeyCode() == e.VK_NUMPAD2){
System.out.println(x1);
System.out.println(y1);
try {
new Robot().mouseMove(x1, y1);
} catch (AWTException e1) {
e1.printStackTrace();
}
}
}
#Override
public void keyTyped(KeyEvent e) {
}
}
Thank you so far guys. So this works. It saves the location and Prints '1' if you press Numpad 1. When numpad 2 is pressed, it goes to the saved location and prints the saved location. But somehow when i start my game and try to use this, my mouse doesn't move, eventhought it prints the locations so the script is still running. Anyone has a clue?
This can be done with pretty much every language in a fairly easy way, there is no need to use a specific language for it.
I assume you just started out programming, so one golden rule in programming: just Google it!
For java you can easily find the documentation of the MouseInfo class (java.awt.MouseInfo), which will in large provide the functionalities you'll need.
Java
import java.awt.MouseInfo;
public class ExampleMouseInfo {
public static void main(String[] args){
int mouseYPos = MouseInfo.getPointerInfo().getLocation().y;
int mouseXPos = MouseInfo.getPointerInfo().getLocation().x;
System.out.println(mouseXPos);
System.out.println(mouseYPos);
}
}
Output
488
477
This snippet of code will get the position of your mouse when you run the program. So if you want to trigger this part of code at a certain point (like you said by pressing a button) you make a function out of it and wrap it into an event handler.
Edit: example of moving a mouse can be found here.

Does "Thread.sleep()" do anything else than pause the program for a certain amount of time?

I have created a program that draws a thick line.
import javax.swing.*;
import java.awt.*;
public class Movement {
int xGrid = 50;
public static void main(String[] args) {
Movement m = new Movement();
m.animate();
}
public void animate() {
JFrame frame = new JFrame("Movement");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
ScreenDisplay display = new ScreenDisplay();
frame.getContentPane().add(display);
frame.setSize(400, 400);
frame.setVisible(true);
for (int aL = 0; aL < 200; aL++) {
xGrid++;
display.repaint();
try {
Thread.sleep(50);
} catch (Exception ex) { }
}
}
class ScreenDisplay extends JPanel {
public void paintComponent(Graphics g) {
g.setColor(Color.RED);
g.fillOval(xGrid, 175, 50, 50);
}
}
}
Because of the method "Thread.sleep(50)", the speed of the program slows down a little.
So I got a little curious and removed the "sleep()" method.
What I expected to output was the exact same output, just extremely fast.
However, it just prints out one circle in the frame.
I don't really know why it outputs just one circle, none of the researches I've done back up the answer.
Can anyone please explain why?
From Component.repaint documentation:
Repaints this component.
If this component is a lightweight component, this method
causes a call to this component's paint
method as soon as possible. Otherwise, this method causes
a call to this component's update method as soon
as possible.
By the looks of it, your for loop finishes so quickly that by the time the component calls the repaint method, it has already finished and therefore only paints the final circle stored in the buffer.

JLabel's Set Location inside for not moving smoothly

i'm using a label for a little sprite for some testing that i'm doing, but i want to move the sprite 10 pixels per keypress. Now, i can do that, but now i'm trying to make it move the 10 pixels smoothly, so i tried the next code:
for(int i = 0; i < 100; i++){
x++;
container.setLocation(x, y);
System.out.println(x);
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
Now the problem is that, the sprite only moves when the for cycle ends, but the console shows the X value changing for each iteration. Any thoughts/help?
Thanks!
I suggest you to take a look at how to animate a JComponent using Swing Timer class, instead of for loop. You can find various tutorials about how to use Swing Timer. Here, to briefly explain, you are blocking EDT(Event Dispatch Thread) which operates the graphical side of the Java. Whenever you want to make a constant and smooth flow in your animations, make sure that you never block the EDT.
EDIT: Here is the demonstration of the usage of Swing Timer Class:
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.Timer;
public class AnimationTrial extends JFrame {
private final int DELAY = 10;
private Timer timer;
private int x, y;
private JLabel label;
public static void main(String[] args) {
EventQueue.invokeLater( new Runnable () {
#Override
public void run() {
new AnimationTrial();
}
});
}
public AnimationTrial()
{
setSize(500, 500);
x = 50;
y = 50;
label = new JLabel("They see me movin' they hatin'!");
timer = new Timer( DELAY, new ActionListener()
{
#Override
public void actionPerformed(ActionEvent arg0) {
x++;
label.setLocation(x, y);
}
});
timer.start();
getContentPane().add(label);
pack();
setVisible (true);
}
}
If you dont create new Thread, the user interface runs on the same thread as its method.
Therefore your for-cycle is fired after some action and thread cant do anything else until it ends.
Solution : Create your own class, pass the JLabel or the whole form as parameter in constructor, implement threading and run it as new thread.
I'd suggest you give a look to the Timing Framework, if you want to do something close to an animation in Swing. It could help you, depending on your general need.
If you want other sprites to move in sync with your sprite you can create a TimerTask and use scheduleAtFixedRate(). Your TimerTask would then be responsible for moving all sprites and redrawing everything that was part of the moving like the JPanel in the background and the sprites.
To make your code snippet work you would have to add redrawing of the Background and the sprite after setting the location but I would advise against that approach as it can easily lead to badly designed code where you create one God Class that does everything.
The TimerTask approach should also be more precise if the calculations need a bit time as it tries to have the same time between 2 calls where the approach with the sleeping thread can easily lead to different delays if the calculations are finished earlier or later.

keyListener with Swing and game level system with Swing/keyListener and Thread

I am a novice coder, have a tiny bit of experience with C++ about 10 years ago and now learning java (it's been about 4-5 months). I have a little collaborative project going, and I've got some things to figure out.
Here's the code:
import java.awt.event.*;
import java.awt.*;
import javax.swing.JFrame;
import java.util.Scanner;
import java.util.Random;
public class Game extends JFrame {
GamePanel panel;
int[][] grid;
int size;
//...and some other variables
public Game(String title) {
super(title);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
panel = new GamePanel(grid,size);
this.add(panel);
Button button = new Button("WHAT");
button.setBounds(-100, -100, 70, 70);
this.add(button);
button.addKeyListener(new KeyHandler());
}
class KeyHandler extends KeyAdapter {
public void keyPressed(KeyEvent e) {
int keycode = e.getKeyCode();
switch(keycode) {
//arrow keys input and stuff
}
if(checkForWin()) //checkForWin() returns a boolean value for win/loss
//won the game, thus end the thread here
if(checkForLoss()) // similar stuff as checkForLoss()
//lost the game, thus end the thread here
//...update the panel
panel.repaint();
}
}
public static void main(String [] args) {
Game me = new Game("GAME");
me.setVisible(true);
}
}
So that's pretty much how the whole game thing looks like.
And I have questions:
I am using a button and put it at a negative position to make it invisible and using it as a mean of KeyListener. Is there any other way to add a key listener? ex) to the panel or something?
I want to change it so that each "level" is a thread and make it like
public static void main(String [] args) {
int level = 1;
do {
GameThread gt = new GameThread("Game");
// run() will have the game constructor inside
gt.setLevel(level);
gt.start();
gt.join(); //wait until the game "level" is finished
if(won)
level++;
if(lost)
level = 1;
} while(!checkIfDonePlaying())
}
Somewhat like this. I'm having trouble making the thread continue to run until the game level is actually finished. How do I do that?
I want to add a JLabel to show the score on the frame. But when I do that, the score doesn't update when I repaint() it. How do I do that?
Thanks in advance!
A few things:
Yes, there is a way to add a KeyListener to the panel, and that's by using key bindings. For example:
javax.swing.InputMap im = panel.getInputMap(panel.WHEN_IN_FOCUSED_WINDOW);
javax.swing.ActionMap am = panel.getActionMap();
im.put(javax.swing.KeyStroke.getKeyStroke("pressed UP"), "up");
am.put("up", new javax.swing.AbstractAction() {
#Override
public void actionPerformed(ActionEvent ev) {
// handle up arrow key action here
}
});
Swing is an event-driven environment, so do-while loops should not be used. Instead, use a Swing timer that periodically checks if your level has been completed.
Since you're not doing any custom painting on your JLabel, you shouldn't be using repaint. Instead, use its setText method.
Here's a solution for your first issue:
panel.setFocusable(true);
panel.addKeyListener(this);
Then you should just be able to do the usual key listener methods. Be sure to implement KeyListener!
Solutions for your other issues on their way. (Actually take #TNT 's suggestion and use keybindings, I'm more comfortable with listeners but for games I usually use lwjgl or slick2d)
2.
I feel that running your programs levels may be a bit inefficient (that may just be me) I would suggest having one thread in a run method and have the following:
Public void reset(int level)
{
//reset all variables based on local variable level...
}
Call it like this:
Reset(++currentLevel)); //use ++ before currentLevel so it adds to it and then resets
And you could easily use switch cases to do some special stuff if you want
Switch(level){
case 1: //...
}
And so forth. (I'm typing on mobile sorry for weird caps)

Java - Freeze Mouse

Is there a way to lock the mouse in one position in Java for a certain amount of time?
I've tried this:
while(timer == true){
Robot bot = new Robot();
bot.mouseMove(x, y);
}
But when the user moves the mouse it jumps unpleasantly back and forth (from the position the user is dragging to the position where it's supposed to be locked).
Any ideas if there is a better way to do this? Or can I completely disable user input for the mouse? Thanks in advance!
This is as far as you can go (at least with the standard libraries). The mouse "jumps" are system dependent, specifically on the "sampling rate" of the listener. I'm not aware of a JVM parameter affecting it, but wouldn't be surprised if there is something in that spirit. The jumps are in opposite relation to the mouse acceleration (the mouse can move a "long" distance between the samples).
public class Stop extends JFrame {
static Robot robot = null;
static Rectangle bounds = new Rectangle(300, 300, 300, 300);
static int lastX = 450; static int lastY = 450;
Stop() {
try {
robot = new Robot();
} catch (AWTException e) {
e.printStackTrace();
}
addMouseMotionListener(new MouseStop());
getContentPane().add(new JLabel("<html>A sticky situation<br>Hold SHIFT to get out of it", JLabel.CENTER));
setDefaultCloseOperation(EXIT_ON_CLOSE);
setBounds(bounds);
setVisible(true);
}
private static class MouseStop extends MouseAdapter {
#Override
public void mouseMoved(MouseEvent e) {
if(e.isShiftDown()) {
lastX = e.getXOnScreen();
lastY = e.getYOnScreen();
}
else
robot.mouseMove(lastX, lastY);
}
}
public static void main(String args[]) {
new Stop();
}
}
Edit: I have just gotten an idea involving painting of the cursor to appear as if the mouse is not moving at all. I'll add code if I get something working.

Categories

Resources