As per this previous link (How to send keyboard outputs) Java can simulate a key being pressed using the Robot class. However, how could a combination of key presses be simulated? If I wanted to send the combination "alt-123" would this be possible using Robot?
The simple answer is yes. Basically, you need to wrap the keyPress/Release of the Alt around the other keyPress/Releases
public class TestRobotKeys {
private Robot robot;
public static void main(String[] args) {
new TestRobotKeys();
}
public TestRobotKeys() {
try {
robot = new Robot();
robot.setAutoDelay(250);
robot.keyPress(KeyEvent.VK_ALT);
robot.keyPress(KeyEvent.VK_1);
robot.keyRelease(KeyEvent.VK_1);
robot.keyPress(KeyEvent.VK_2);
robot.keyRelease(KeyEvent.VK_2);
robot.keyPress(KeyEvent.VK_3);
robot.keyRelease(KeyEvent.VK_4);
robot.keyRelease(KeyEvent.VK_ALT);
} catch (AWTException ex) {
ex.printStackTrace();
}
}
}
For sending keys combination using java.awt.Robot the following code works fine for me
import java.awt.AWTException;
import java.awt.Robot;
import java.awt.event.KeyEvent;
public class VirtualKeyBoard extends Robot
{
public VirtualKeyBoard() throws AWTException
{
super();
}
public void pressKeys(String keysCombination) throws IllegalArgumentException
{
for (String key : keysCombination.split("\\+"))
{
try
{ System.out.println(key);
this.keyPress((int) KeyEvent.class.getField("VK_" + key.toUpperCase()).getInt(null));
} catch (IllegalAccessException e)
{
e.printStackTrace();
}catch(NoSuchFieldException e )
{
throw new IllegalArgumentException(key.toUpperCase()+" is invalid key\n"+"VK_"+key.toUpperCase() + " is not defined in java.awt.event.KeyEvent");
}
}
}
public void releaseKeys(String keysConbination) throws IllegalArgumentException
{
for (String key : keysConbination.split("\\+"))
{
try
{ // KeyRelease method inherited from java.awt.Robot
this.keyRelease((int) KeyEvent.class.getField("VK_" + key.toUpperCase()).getInt(null));
} catch (IllegalAccessException e)
{
e.printStackTrace();
}catch(NoSuchFieldException e )
{
throw new IllegalArgumentException(key.toUpperCase()+" is invalid key\n"+"VK_"+key.toUpperCase() + " is not defined in java.awt.event.KeyEvent");
}
}
}
public static void main(String[] args) throws AWTException
{
VirtualKeyBoard kb = new VirtualKeyBoard();
String keyCombination = "control+a"; // select all text on screen
//String keyCombination = "shift+a+1+c"; // types A!C on screen
// For your case
//String keyCombination = "alt+1+2+3";
kb.pressKeys(keyCombination);
kb.releaseKeys(keyCombination);
}
}
This is an example
Robot r = new Robot();
Thread.sleep(1000);
r.keyPress(KeyEvent.VK_ALT);
r.keyPress(KeyEvent.VK_NUMPAD1);
r.keyPress(KeyEvent.VK_NUMPAD2);
r.keyPress(KeyEvent.VK_NUMPAD3);
r.keyRelease(KeyEvent.VK_ALT);
Don't forget to release some special keys, it will make some crazy things on your machine
This code is too close to native windows keyboard. Even Api keyboard "presses" are coming into Eclipse ide as those would pressed normally from ide. Keys was produced from current debugged application!! (jdk 1.8, win 7, hp)
Related
I read a couple questions related to pausing main and both gave answers I didn't understand, and frankly I don't think are applicable.
I have a JFrame that makes use of a database I'm setting up in my driver class.
The JFrame will launch and the window opens; however when I try to make use of the database it fails; because back in main the program just keeps running and shuts down the connection, and closes it.
I tried just removing the connection.close() code just to see if my database methods work in the JFrame, and they do, so I just need to learn how to halt main while my JFrame is running.
public static void main(String[] args) {
File dbPropertiesFile = new File(DbConstants.DB_PROPERTIES_FILENAME);
if (!dbPropertiesFile.exists()) {
showUsage();
System.exit(-1);
}
try {
new Lab9(dbPropertiesFile).run(args);
} catch (Exception e) {
LOG.error(e.getMessage());
e.printStackTrace();
} finally {
shutdown();
}
}
private static void configureLogging() {
ConfigurationSource source;
try {
source = new ConfigurationSource(new FileInputStream(LOG4J_CONFIG_FILENAME));
Configurator.initialize(null, source);
} catch (IOException e) {
System.out.println(
String.format("Can't find the log4j logging configuration file %s.", LOG4J_CONFIG_FILENAME));
}
}
private static void shutdown() {
LOG.info("Shutting down");
if (connection != null) {
try {
connection.close();
} catch (SQLException e) {
LOG.error(e.getMessage());
e.printStackTrace();
}
}
}
private static void showUsage() {
System.err.println(
String.format("Program cannot start because %s cannot be found.", DbConstants.DB_PROPERTIES_FILENAME));
}
private Lab9(File file) throws IOException {
properties = new Properties();
properties.load(new FileInputStream(file));
database = new Database(properties);
}
/**
* Where the computer start making a lot of noise.
*
* #param args
* #throws Exception
*/
private void run(String[] args) throws Exception {
LOG.info("Running");
LOG.info("Loading database properties from: " + DbConstants.DB_PROPERTIES_FILENAME + ".");
LOG.info(properties.getProperty("db.driver"));
LOG.info("Driver loaded");
LOG.info("DB URL = " + properties.getProperty("db.url"));
LOG.info("DB USER = " + properties.getProperty("db.user"));
LOG.info("DB PASSWORD = " + properties.getProperty("db.password"));
connect();
Statement statement = connection.createStatement();
try {
// If the user enters the -drop switch
if (args[0].equalsIgnoreCase(DROP_COMMAND)) {
LOG.info("Table " + CustomerDao.TABLE_NAME + "is being DROPPED!");
customerDao.drop();
LOG.info("Table has been DROPPED!");
}
// Check to see if the table is already made; if its not then make it, and fill
// it.
if (Database.tableExists(CustomerDao.TABLE_NAME) == false) {
createTables(statement);
LOG.info("Created the table: " + CustomerDao.TABLE_NAME + ".");
LOG.info("Inserting Customer objects into table: " + CustomerDao.TABLE_NAME + ".");
insertCustomers();
LOG.info("Inserted customer info into table from file: [" + CUSTOMER_DATA + "].");
}
createUI();
// I NEED MAIN
// TO STOP
// AROUND HERE!
}catch(SQLException e){
e.printStackTrace();
LOG.error(e.getMessage());
}finally{
connection.close();
}
}
public static void createUI() {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
DatabaseControlFrame frame = new DatabaseControlFrame(customerDao);
frame.setVisible(true);
// OR MAYBE I NEED MAIN
// TO STOP
// AROUND HERE!
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
private void connect() throws SQLException {
connection = database.getConnection();
customerDao = new CustomerDao(database);
}
}
Any ideas? I tried using a while(frame.isVisilbe()){ wait(600) }; But the compiler had a spas when I tried to use wait().
You'll note I'm passing a customerDAO object to my JFrame constructor; but I'm beginning to wonder could I make a connection inside the JFrame so that when main's connection closes; my JFrame's doesn't? Is that a good idea? Is that even possible I'm not super SQL savvy I'm going to need to study up on it more.
You could use Thread.sleep() - I've found that useful with JFrame before, though I'm not 100% sure it would fit what you're looking for. If you want it to wait indefinitely, put it in a while loop:
while(//condition)
{
Thread.sleep(500); //pauses for .5 sec, then loops back to check condition
}
JFrame event handler runs on a different thread than main thread, so you need to shutdown on that thread.
Here is a example, Using JDBC with GUI API.
This example call connection.close() on received window-closing-event.
public class MyFrame extends JFrame {
public MyFrame() {
// ...
addWindowListener(new WindowAdapter() {
#Override
public void windowClosing(final WindowEvent e) {
shutdown();
System.exit(0);
}
});
}
// ...
}
I have an application class which allows the user to download a jar file, this jar file is then accessed using reflection.
public void install() {
File app = new File("C:/Temp/" + this.name + ".jar");
if(!app.exists())
download();
URLClassLoader appLoader;
Class<?> appBuilder = null;
try {
appLoader = URLClassLoader.newInstance(new URL[] { new URL("C:/Temp/" + this.name + ".jar") });
appBuilder = appLoader.loadClass("iezon.app.App");
} catch (MalformedURLException | ClassNotFoundException e) {
WebSocket.addError(e);
}
this.application = appBuilder;
}
private void download() {
try {
FileUtils.copyURLToFile(new URL(this.downloadUrl), new File("C:/Temp/" + this.name + ".jar"));
} catch (IOException e) {
WebSocket.addError(e);
}
}
Here, I am creating a new instance of the jar file:
public void start() {
try {
App.createWindow(this.application.getClass());
} catch (InstantiationException | IllegalAccessException e) {
WebSocket.addError(e);
}
}
Window is custom extension of a JFrame that is used as a base template for GUI design.
public static int createWindow(Class<?> window) throws InstantiationException, IllegalAccessException {
factory.add((Window) window.newInstance());
factory.get(factory.size() - 1).windowId = factory.size() - 1;
factory.get(factory.size() - 1).run();
return factory.size() - 1;
}
Since the jar file, once instanced, cannot access this code to load the home screen window on exit, I was wondering how I can wait for the jar file instance to be closed and then relaunch the home screen:
ie in suedo code:
when (create App.createWindow(this.application.getClass()))
dies
create App.createWindow(HomeScreen.class)
Is there a way I can use wait() and notify() methods? Or possibly add a listener when instancing the Class like factory.get(factory.size() - 1).addSomeExitListener.....() ?
You can forget about the reflection part, it's not really relevant since the same would be true if you were given a regularly constructed instance.
You'll need to design your Window class in a way that it works as desired, e.g. let it callback you when it's done. Since it is a JFrame you could also use it's window close listener like:
public static int createWindow(Class<?> window) throws InstantiationException, IllegalAccessException {
Window instance = (Window) window.newInstance();
factory.add(instance);
instance.windowId = factory.size() - 1;
if (window != HomeScreen.class) {
// instance.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); // ?
instance.addWindowListener(new WindowAdapter() {
#Override
public void windowClosed(WindowEvent e) {
App.createWindow(HomeScreen.class);
}
});
}
instance.run();
return factory.size() - 1;
}
There is such a program. It must analyze the clipboard for the presence of a five-digit number in it. But when you first copy the text that meets the condition, the program works fine, but if you copy the second text in the same window, the program that meets the condition does not work. That is, it works only if you periodically change windows.
The question is to get the program to work with each copy?
import java.awt.*;
import java.awt.datatransfer.*;
import java.io.IOException;
public class Main implements FlavorListener {
private static Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
public static void main(String[] args) throws InterruptedException {
clipboard.addFlavorListener(new Main());
// fall asleep for 100 seconds, otherwise the program will immediately end
Thread.sleep(100 * 1000);
}
#Override
public void flavorsChanged(FlavorEvent event) {
try {
String clipboardContent = (String) clipboard.getData(DataFlavor.stringFlavor);
handleClipboardContent(clipboardContent);
} catch (UnsupportedFlavorException | IOException e) {
// TODO handle error
e.printStackTrace();
}
}
private void handleClipboardContent(String clipboardContent) {
// we check that the length of the string is five
if (clipboardContent != null && clipboardContent.length() == 5)
{
System.out.println(clipboardContent);
}
else {
System.out.println("condition false");
}
}
}
// 12345
// 56789
The FlavorListener will notify you when the "type" of data in the Clipboard has changed, not when the data itself has changed. This means if you copy a String to the Clipboard, you "might" be notified, but if you copy another String to the Clipboard, you won't, because the type of data has not changed.
The "common" solution to the problem you're facing is to reset the contents of the clipboard to a different flavour. The problem with this is, what happens if some other program wants the data? You've just trampled all over it
Instead, you could "peek" at the data on a periodical bases and check to see if the contents has changed or not. A basic solution would be to use a Thread which maintained the hashCode of the current String contents, when the hashCode changes, you would then grab a copy and perform what ever operations you wanted on it.
Maybe something like...
import java.awt.Toolkit;
import java.awt.datatransfer.Clipboard;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.FlavorEvent;
import java.awt.datatransfer.FlavorListener;
import java.awt.datatransfer.Transferable;
import java.awt.datatransfer.UnsupportedFlavorException;
import java.io.IOException;
public class Test {
public static void main(String[] args) {
Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
clipboard.addFlavorListener(new FlavorListener() {
#Override
public void flavorsChanged(FlavorEvent e) {
System.out.println("Flavor has changed");
Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
if (clipboard.isDataFlavorAvailable(DataFlavor.stringFlavor)) {
try {
String text = (String) clipboard.getData(DataFlavor.stringFlavor);
textDidChangeTo(text);
} catch (UnsupportedFlavorException | IOException ex) {
ex.printStackTrace();
}
}
}
});
Thread t = new Thread(new Runnable() {
private Integer currentHashcode;
#Override
public void run() {
while (true) {
try {
Thread.sleep(1000);
} catch (InterruptedException ex) {
}
Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
Transferable contents = clipboard.getContents(this);
if (clipboard.isDataFlavorAvailable(DataFlavor.stringFlavor)) {
try {
String text = (String) clipboard.getData(DataFlavor.stringFlavor);
if (currentHashcode == null) {
currentHashcode = text.hashCode();
} else if (currentHashcode != text.hashCode()) {
currentHashcode = text.hashCode();
textDidChangeTo(text);
}
} catch (UnsupportedFlavorException | IOException ex) {
ex.printStackTrace();
}
} else {
currentHashcode = null;
}
}
}
});
t.start();
}
public static void textDidChangeTo(String text) {
System.out.println("Text did change to: " + text);
}
}
Now, this is far from perfect. It may generate two events when the contents changes from something other then String to String. In this, based on your needs, you probably don't need the FlavorListener, but I've used it for demonstration purposes
I'm trying to implement a mechanism that deletes cached files when the objects that hold them die, and decided to use PhantomReferences to get notified on garbage collection of an object. The problem is I keep experiencing weird behavior of the ReferenceQueue. When I change something in my code it suddenly doesn't fetch objects anymore. So I tried to make this example for testing, and ran into the same problem:
public class DeathNotificationObject {
private static ReferenceQueue<DeathNotificationObject>
refQueue = new ReferenceQueue<DeathNotificationObject>();
static {
Thread deathThread = new Thread("Death notification") {
#Override
public void run() {
try {
while (true) {
refQueue.remove();
System.out.println("I'm dying!");
}
} catch (Throwable t) {
t.printStackTrace();
}
}
};
deathThread.setDaemon(true);
deathThread.start();
}
public DeathNotificationObject() {
System.out.println("I'm born.");
new PhantomReference<DeathNotificationObject>(this, refQueue);
}
public static void main(String[] args) {
for (int i = 0 ; i < 10 ; i++) {
new DeathNotificationObject();
}
try {
System.gc();
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
The output is:
I'm born.
I'm born.
I'm born.
I'm born.
I'm born.
I'm born.
I'm born.
I'm born.
I'm born.
I'm born.
Needless to say, changing the sleep time, calling gc multiple times etc. didn't work.
UPDATE
As suggested, I called Reference.enqueue() of my reference, which solved the problem.
The weird thing, is that I have some code that works perfectly (just tested it), although it never calls enqueue. Is it possible that putting the Reference into a Map somehow magically enqueued the reference?
public class ElementCachedImage {
private static Map<PhantomReference<ElementCachedImage>, File>
refMap = new HashMap<PhantomReference<ElementCachedImage>, File>();
private static ReferenceQueue<ElementCachedImage>
refQue = new ReferenceQueue<ElementCachedImage>();
static {
Thread cleanUpThread = new Thread("Image Temporary Files cleanup") {
#Override
public void run() {
try {
while (true) {
Reference<? extends ElementCachedImage> phanRef =
refQue.remove();
File f = refMap.remove(phanRef);
Calendar c = Calendar.getInstance();
c.setTimeInMillis(f.lastModified());
_log.debug("Deleting unused file: " + f + " created at " + c.getTime());
f.delete();
}
} catch (Throwable t) {
_log.error(t);
}
}
};
cleanUpThread.setDaemon(true);
cleanUpThread.start();
}
ImageWrapper img = null;
private static Logger _log = Logger.getLogger(ElementCachedImage.class);
public boolean copyToFile(File dest) {
try {
FileUtils.copyFile(img.getFile(), dest);
} catch (IOException e) {
_log.error(e);
return false;
}
return true;
}
public ElementCachedImage(BufferedImage bi) {
if (bi == null) throw new NullPointerException();
img = new ImageWrapper(bi);
PhantomReference<ElementCachedImage> pref =
new PhantomReference<ElementCachedImage>(this, refQue);
refMap.put(pref, img.getFile());
new Thread("Save image to file") {
#Override
public void run() {
synchronized(ElementCachedImage.this) {
if (img != null) {
img.saveToFile();
img.getFile().deleteOnExit();
}
}
}
}.start();
}
}
Some filtered output:
2013-08-05 22:35:01,932 DEBUG Save image to file: <>\AppData\Local\Temp\tmp7..0.PNG
2013-08-05 22:35:03,379 DEBUG Deleting unused file: <>\AppData\Local\Temp\tmp7..0.PNG created at Mon Aug 05 22:35:02 IDT 2013
The answer is, that in your example the PhantomReference itself is unreachable and hence garbage collected before the referred object itself is garbage collected. So at the time the object is GCed there is no more Reference and the GC does not know that it should enqueue something somewhere.
This of course is some kind of head-to-head race :-)
This also explains (without looking to deep into your new code) why putting the reference into some reachable collection makes the example work.
Just for reference (pun intended) here is a modified version of your first example which works (on my machine :-) I just added a set holding all references.
import java.lang.ref.PhantomReference;
import java.lang.ref.Reference;
import java.lang.ref.ReferenceQueue;
import java.util.HashSet;
import java.util.Set;
public class DeathNotificationObject {
private static ReferenceQueue<DeathNotificationObject> refQueue = new ReferenceQueue<DeathNotificationObject>();
private static Set<Reference<DeathNotificationObject>> refs = new HashSet<>();
static {
Thread deathThread = new Thread("Death notification") {
#Override
public void run() {
try {
while (true) {
Reference<? extends DeathNotificationObject> ref = refQueue.remove();
refs.remove(ref);
System.out.println("I'm dying!");
}
} catch (Throwable t) {
t.printStackTrace();
}
}
};
deathThread.setDaemon(true);
deathThread.start();
}
public DeathNotificationObject() {
System.out.println("I'm born.");
PhantomReference<DeathNotificationObject> ref = new PhantomReference<DeathNotificationObject>(this, refQueue);
refs.add(ref);
}
public static void main(String[] args) {
for (int i = 0 ; i < 10 ; i++) {
new DeathNotificationObject();
}
try {
System.gc();
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
Update
Calling enqueue by hand is possible in your example but not in real code. it gives plain wrong result. Let me show by calling enqueue in the constructor and using another main:
public DeathNotificationObject() {
System.out.println("I'm born.");
PhantomReference<DeathNotificationObject> ref = new PhantomReference<DeathNotificationObject>(this, refQueue);
ref.enqueue();
}
public static void main(String[] args) throws InterruptedException {
for (int i = 0 ; i < 5 ; i++) {
DeathNotificationObject item = new DeathNotificationObject();
System.out.println("working with item "+item);
Thread.sleep(1000);
System.out.println("stopped working with item "+item);
// simulate release item
item = null;
}
try {
System.gc();
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
The output will be like this:
I'm born.
I'm dying!
working with item DeathNotificationObject#6908b095
stopped working with item DeathNotificationObject#6908b095
Which means that whatever you wanted to do with the reference queue would be done when the item is still alive.
I have this piece of code inside my application which runs continuously .
When ever a symbol is added , this below Thread gets fired up and executes two different tasks ( currently the task is represented as sys out for simplicity )
For the first time everything runs fine , but from the second time , the task is being repeated for all the symbols present inside the allSymbolsSet .
The issue i am facing here is that i want to run the task only for the new symbol added . (For example if the allSymbolsSet consists of 3 symbols initially and when a new symbol is added to it , it runs that task for all the 4 symbols , whereas i want it to execute it only for the newly added symbol )
This is my code
package com;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import java.util.concurrent.PriorityBlockingQueue;
public class TaskerThread extends Thread {
private PriorityBlockingQueue<String> priorityBlocking = new PriorityBlockingQueue<String>();
private Set<String> allSymbolsSet = new HashSet<String>();
public void addSymbols(String str) {
if (str != null) {
priorityBlocking.add(str);
}
}
public void run() {
while (true) {
try {
boolean added = false;
while (priorityBlocking.peek() != null) {
added = true;
String symbol = priorityBlocking.poll();
allSymbolsSet.add(symbol);
try {
System.out.println("Symbol From priorityBlocking"+ " " + symbol);
} catch (Exception e) {
e.printStackTrace();
}
}
Iterator<String> ite = allSymbolsSet.iterator();
if (added) {
while (ite.hasNext()) {
String symbol = ite.next();
if (symbol != null && symbol.trim().length() > 0) {
try {
System.out.println("Symbol From allSymbolsSet"+ " " + symbol);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
Thread.sleep(2000);
} catch (Exception e) {
e.printStackTrace();
}
}
}
public static void main(String args[]) {
try {
TaskerThread qT = new TaskerThread();
qT.start();
qT.addSymbols("SymbolTest");
Thread.sleep(110);
qT.addSymbols("Symbo2222222");
} catch (Exception e) {
e.printStackTrace();
}
}
}
add() method returns false if the Object being added was ignored because it was already present
A simple solution would be to have two hashsets - set1, holding all symbols, set2 containing newly added symbols. Add new symbols to set2, in your thread's run, when the execution is complete, add new symbol to set1 and remove it from set2. How about that?
Well, of course it runs for all elements in the set, you are iterating over them!
package com;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import java.util.concurrent.PriorityBlockingQueue;
public class TaskerThread extends Thread {
private final PriorityBlockingQueue<String> priorityBlocking = new PriorityBlockingQueue<String>();
private final Set<String> allSymbolsSet = new Collections.synchronizedSet(new HashSet<String>());
public void addSymbols(String str) {
if (str != null) {
priorityBlocking.add(str);
}
}
public void run() {
while (true) {
try {
while (true) {
final String symbol = priorityBlocking.take();
if (allSymbolsSet.add(symbol)) {
doSomething(symbol); // do whatever you want with the symbol
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
public static void main(String args[]) {
try {
TaskerThread qT = new TaskerThread();
qT.start();
qT.addSymbols("SymbolTest");
} catch (Exception e) {
e.printStackTrace();
}
}
}
This should do what you were looking for. Take better care of possible exceptions, namely InterruptedException.