我想从Java程序中在窗口上拖动鼠标。例如,要在Google地图中平移地图。
我假设我可以通过按下鼠标,先移动鼠标然后放开鼠标来做到这一点,
wc.pressMouse();
wc.moveMouse(x, y);
wc.releaseMouse();
但是,这只是移动指针而不是屏幕。
知道我在做什么错吗?
这里有两个文件,一个用于JFrame控制器,一个用于JNA类。
使用箭头键移动,并使用数字键更改要移动的像素。为此,您将需要在谷歌浏览器中打开谷歌地图。
package uk.co.moonsit.windows;
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.event.*;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.*;
public class KeyMouseMove extends JFrame
implements KeyListener,
ActionListener {
private static final Logger LOG = Logger.getLogger(KeyMouseMove.class.getName());
JTextArea displayArea;
JTextField typingArea;
static final String NEWLINE = System.getProperty("line.separator");
WindowsComms wc;
int x = 600, y = 200;
int xshift = 10, yshift = 10;
static String appName = "KeyMouseMove";
//String winName = "Windows Task Manager";
String winName = "Google Maps - Google Chrome";
//String winName = "Viewpoint Control - Google Chrome";
int location;
public static void main(String[] args) {
/* Use an appropriate Look and Feel */
try {
//UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel");
//UIManager.setLookAndFeel("com.sun.java.swing.plaf.gtk.GTKLookAndFeel");
UIManager.setLookAndFeel("javax.swing.plaf.metal.MetalLookAndFeel");
} catch (UnsupportedLookAndFeelException | IllegalAccessException | InstantiationException | ClassNotFoundException ex) {
ex.printStackTrace();
}
/* Turn off metal's use of bold fonts */
UIManager.put("swing.boldMetal", Boolean.FALSE);
//Schedule a job for event dispatch thread:
//creating and showing this application's GUI.
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGUI();
}
});
}
/**
* Create the GUI and show it. For thread safety, this method should be
* invoked from the event-dispatching thread.
*/
private static void createAndShowGUI() {
//Create and set up the window.
KeyMouseMove frame = new KeyMouseMove(appName);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//Set up the content pane.
frame.addComponentsToPane();
//Display the window.
frame.pack();
frame.setVisible(true);
}
private void setupWindows() {
wc = new WindowsComms();
wc.findWindow(winName);
wc.setForegroundWindow();
wc.moveMouse(x, y);
}
private void addComponentsToPane() {
setupWindows();
JButton button = new JButton("Clear");
button.addActionListener(this);
typingArea = new JTextField(40);
typingArea.addKeyListener(this);
//Uncomment this if you wish to turn off focus
//traversal. The focus subsystem consumes
//focus traversal keys, such as Tab and Shift Tab.
//If you uncomment the following line of code, this
//disables focus traversal and the Tab events will
//become available to the key event listener.
//typingArea.setFocusTraversalKeysEnabled(false);
displayArea = new JTextArea();
displayArea.setEditable(false);
JScrollPane scrollPane = new JScrollPane(displayArea);
scrollPane.setPreferredSize(new Dimension(375, 250));
getContentPane().add(typingArea, BorderLayout.PAGE_START);
getContentPane().add(scrollPane, BorderLayout.CENTER);
getContentPane().add(button, BorderLayout.PAGE_END);
}
public KeyMouseMove(String name) {
super(name);
}
/**
* Handle the key typed event from the text field.
* @param e
*/
@Override
public void keyTyped(KeyEvent e) {
displayInfo(e, "KEY TYPED: ");
char c = e.getKeyChar();
LOG.log(Level.INFO, "char {0}", c);
switch (location) {
case KeyEvent.KEY_LOCATION_STANDARD:
xshift = c - 48;
break;
case KeyEvent.KEY_LOCATION_NUMPAD:
yshift = c - 48;
break;
default:
}
LOG.info("dx dy " + xshift + " " + yshift);
}
/**
* Handle the key pressed event from the text field.
* @param e
*/
@Override
public void keyPressed(KeyEvent e) {
displayInfo(e, "KEY PRESSED: ");
if (e.getKeyCode()<=40){
move(e);
}
location = e.getKeyLocation();
}
/**
* Handle the key released event from the text field.
* @param e
*/
@Override
public void keyReleased(KeyEvent e) {
displayInfo(e, "KEY RELEASED: ");
}
private void move(KeyEvent e) {
int keyCode = e.getKeyCode();
wc.findWindow(winName);
switch (keyCode) {
case 37:
x = x - xshift;
break;
case 38:
x = x + xshift;
y = y - yshift;
break;
case 39:
x = x + xshift;
break;
case 40:
y = y + yshift;
break;
}
wc.pressMouse();
wc.moveMouse(x, y);
wc.releaseMouse();
LOG.info("x y " + x + " " + y);
wc.findWindow(appName);
wc.setWindowFocus();
wc.moveMouse(10, 10);
}
/**
* Handle the button click.
*/
@Override
public void actionPerformed(ActionEvent e) {
//Clear the text components.
displayArea.setText("");
typingArea.setText("");
//Return the focus to the typing area.
typingArea.requestFocusInWindow();
}
/*
* We have to jump through some hoops to avoid
* trying to print non-printing characters
* such as Shift. (Not only do they not print,
* but if you put them in a String, the characters
* afterward won't show up in the text area.)
*/
private void displayInfo(KeyEvent e, String keyStatus) {
//You should only rely on the key char if the event
//is a key typed event.
int id = e.getID();
String keyString;
if (id == KeyEvent.KEY_TYPED) {
char c = e.getKeyChar();
keyString = "key character = '" + c + "'";
} else {
int keyCode = e.getKeyCode();
keyString = "key code = " + keyCode
+ " ("
+ KeyEvent.getKeyText(keyCode)
+ ")";
}
String locationString = "key location: ";
int location = e.getKeyLocation();
switch (location) {
case KeyEvent.KEY_LOCATION_STANDARD:
locationString += "standard";
break;
case KeyEvent.KEY_LOCATION_LEFT:
locationString += "left";
break;
case KeyEvent.KEY_LOCATION_RIGHT:
locationString += "right";
break;
case KeyEvent.KEY_LOCATION_NUMPAD:
locationString += "numpad";
break;
default:
// (location == KeyEvent.KEY_LOCATION_UNKNOWN)
locationString += "unknown";
break;
}
displayArea.append(keyStatus + " " + keyString + " " + locationString + NEWLINE);
displayArea.setCaretPosition(displayArea.getDocument().getLength());
}
}
package uk.co.moonsit.windows;
import com.sun.jna.platform.win32.BaseTSD.ULONG_PTR;
import static com.sun.jna.platform.win32.User32.INSTANCE;
import com.sun.jna.platform.win32.WinDef.DWORD;
import com.sun.jna.platform.win32.WinDef.HWND;
import com.sun.jna.platform.win32.WinDef.LONG;
import com.sun.jna.platform.win32.WinDef.WORD;
import com.sun.jna.platform.win32.WinUser.INPUT;
import static com.sun.jna.platform.win32.WinUser.SM_CXSCREEN;
import static com.sun.jna.platform.win32.WinUser.SM_CYSCREEN;
import com.sun.jna.platform.win32.WinUser.WINDOWINFO;
import com.sun.jna.win32.StdCallLibrary;
import java.util.logging.Level;
import java.util.logging.Logger;
import uk.co.moonsit.sockets.QMClient;
public class WindowsComms {
private static final Logger LOG = Logger.getLogger(WindowsComms.class.getName());
private HWND hwnd;
int[] screenDimensions;
int[] windowCorners;
int width, height;
/*
public static final long MOUSEEVENTF_MOVE = 0x0001L;
public static final long MOUSEEVENTF_VIRTUALDESK = 0x4000L;
public static final long MOUSEEVENTF_ABSOLUTE = 0x8000L;
*/
public interface MUser32 extends StdCallLibrary {
public static final long MOUSEEVENTF_MOVE = 0x0001L;
public static final long MOUSEEVENTF_VIRTUALDESK = 0x4000L;
public static final long MOUSEEVENTF_ABSOLUTE = 0x8000L;
public static final long MOUSEEVENTF_LEFTDOWN = 0x0002L;
public static final long MOUSEEVENTF_LEFTUP = 0x0004L;
//User32 INSTANCE = (User32) Native.loadLibrary("user32", User32.class);
//DWORD SendInput(DWORD dWord, INPUT[] input, int cbSize);
}
private int[] getSystemMetrics() {
int[] dims = new int[2];
int screenwidth = INSTANCE.GetSystemMetrics(SM_CXSCREEN);
int screenheight = INSTANCE.GetSystemMetrics(SM_CYSCREEN);
LOG.log(Level.INFO, "w h {0} {1}", new Object[]{screenwidth, screenheight});
dims[0] = screenwidth;
dims[1] = screenheight;
return dims;
}
private int[] getWindowInfo() {
int[] corner = new int[4];
WINDOWINFO pwi = new WINDOWINFO();
pwi.cbSize = pwi.size();
INSTANCE.GetWindowInfo(hwnd, pwi);
corner[0] = pwi.rcClient.left;
corner[1] = pwi.rcClient.top;
corner[2] = pwi.rcClient.right;
corner[3] = pwi.rcClient.bottom;
return corner;
}
@SuppressWarnings("SleepWhileInLoop")
public boolean findWindow(String name) {
boolean rtn = false;
hwnd = INSTANCE.FindWindow(null, name);
int cnt = 0;
while (hwnd == null) {
try {
Thread.sleep(1000);
} catch (InterruptedException ex) {
Logger.getLogger(QMClient.class.getName()).log(Level.SEVERE, null, ex);
}
hwnd = INSTANCE.FindWindow(null, name);
if (cnt++ == 10) {
break;
}
}
if (hwnd != null) {
rtn = true;
}
screenDimensions = getSystemMetrics();
windowCorners = getWindowInfo();
width = windowCorners[2] - windowCorners[0];
height = windowCorners[3] - windowCorners[1];
LOG.log(Level.INFO, "WindowInfo {0} {1} {2} {3} {4} {5}", new Object[]{windowCorners[0], windowCorners[1], windowCorners[2], windowCorners[3], width, height});
return rtn;
}
public void waitabit(long pause) throws InterruptedException {
for (int i = 0; i < 1; i++) {
Thread.sleep(pause);
//hwnd = WindowsComms.findWindow(name);
//LOG.log(Level.INFO, "Window {0}", hwnd.toString());
//LOG.log(Level.INFO, "Paused {0}", pause);
}
}
public void pause(long pause) throws InterruptedException {
Thread.sleep(pause);
}
public boolean openWindow(String name) {
return findWindow(name);
//int len = User32.INSTANCE.GetWindowTextLength(hwnd);
//char[] s = new char[len];
//User32.INSTANCE.GetWindowText(hwnd, s, len);
//LOG.info("Text: " + new String(s));
}
public String getWindowText() {
int len = INSTANCE.GetWindowTextLength(hwnd);
char[] s = new char[len + 1];
INSTANCE.GetWindowText(hwnd, s, len + 1);
String str = new String(s);
return str;
}
public void setForegroundWindow() {
INSTANCE.SetForegroundWindow(hwnd);
}
public void setWindowFocus() {
//User32.INSTANCE.SetForegroundWindow(hwnd);
INSTANCE.SetFocus(hwnd);//.SetForegroundWindow(hwnd);
}
public void pressReturn() {
// Bring the window to the front
//User32.INSTANCE.SetForegroundWindow(hwnd);
//User32.INSTANCE.SetFocus(hwnd);
INPUT input = new INPUT();
input.type = new DWORD(INPUT.INPUT_KEYBOARD);
input.input.setType("ki"); // Because setting INPUT_INPUT_KEYBOARD is not enough: https://groups.google.com/d/msg/jna-users/NDBGwC1VZbU/cjYCQ1CjBwAJ
input.input.ki.time = new DWORD(0); //The timestamp
//input.input.ki.dwFlags = new DWORD(KEYBDINPUT.KEYEVENTF_UNICODE); //I am handing you a unicode character
input.input.ki.wScan = new WORD(0); //The unicode code in decimal (right?)
input.input.ki.wVk = new WORD(0); //Virtual key code, i am setting this to 0 because of the unicode flag in dwFlags
input.input.ki.dwExtraInfo = new ULONG_PTR(0); //I have no idea in hell of what this does :)
// Press carriage return
byte cr = '\r';
input.input.ki.wVk = new WORD(cr);
input.input.ki.dwFlags = new DWORD(0); // keydown
INSTANCE.SendInput(new DWORD(1), (INPUT[]) input.toArray(1), input.size());
// Release carriage return
//input.input.ki.wVk = new WORD(cr);
//input.input.ki.dwFlags = new DWORD(2); // keyup
}
public void moveWindow(String name, int x, int y, int width, int height) {
hwnd = INSTANCE.FindWindow(null, name);
INSTANCE.MoveWindow(hwnd, x, y, width, height, true);
}
public void moveMouse(int xr, int yr) {
int x = windowCorners[0] + xr;
int y = windowCorners[1] + yr;
INPUT input = new INPUT();
input.type = new DWORD(INPUT.INPUT_MOUSE);
input.input.setType("mi");
input.input.mi.dx = new LONG(x * 65536 / screenDimensions[0]);
input.input.mi.dy = new LONG(y * 65536 / screenDimensions[1]);
input.input.mi.mouseData = new DWORD(0);
//input.input.mi.dwFlags = new DWORD(MUser32.MOUSEEVENTF_MOVE | MUser32.MOUSEEVENTF_ABSOLUTE | MUser32.MOUSEEVENTF_VIRTUALDESK );
input.input.mi.dwFlags = new DWORD(MUser32.MOUSEEVENTF_MOVE | MUser32.MOUSEEVENTF_ABSOLUTE );
input.input.mi.time = new DWORD(0);
INPUT[] inArray = {input};
int cbSize = input.size(); // mouse input struct size
DWORD nInputs = new DWORD(1); // number of inputs
DWORD result = INSTANCE.SendInput(nInputs, inArray, cbSize);
//LOG.log(Level.INFO, "result: {0}", result); // return 1 if the 1 event successfully inserted
//LOG.log(Level.INFO, "Moved to {0} {1}", new Object[]{x, y});
}
public void click() {
pressMouse();
releaseMouse();
}
public void pressMouse() {
INPUT input = new INPUT();
input.type = new DWORD(INPUT.INPUT_MOUSE);
input.input.setType("mi");
input.input.mi.time = new DWORD(0);
input.input.mi.mouseData = new DWORD(0);
input.input.mi.dwFlags = new DWORD(MUser32.MOUSEEVENTF_LEFTDOWN);
INPUT[] inArray = {input};
DWORD result = INSTANCE.SendInput(new DWORD(1), inArray, input.size());
//LOG.log(Level.INFO, "result: {0}", result); // return 1 if the 1 event successfully inserted
}
public void releaseMouse() {
INPUT input = new INPUT();
input.type = new DWORD(INPUT.INPUT_MOUSE);
input.input.setType("mi");
input.input.mi.time = new DWORD(0);
input.input.mi.mouseData = new DWORD(0);
input.input.mi.dwFlags = new DWORD(MUser32.MOUSEEVENTF_LEFTUP);
INPUT[] inArray = {input};
DWORD result = INSTANCE.SendInput(new DWORD(1), inArray, input.size());
//LOG.log(Level.INFO, "result: {0}", result); // return 1 if the 1 event successfully inserted
}
}