listening for key/mouse events - java

Is it possible to listen for key and mouse events without having a gui selected by the user? I want to make a program that runs in the background without a gui and responds to user interaction such as pressing ctrl-t.

The window manger will track the focus and direct input according to its configuration. If your window manager decides to send input to a different program because it is enforcing a change of focus, you are out of luck.
While the program lacks focus, if it were able to obtain the mouse and keyboard events, it would be a major security hole. Basically any small unnoticeable background program could spy on the entire system, possibly even stealing passwords in the process.
Your only hope is to find an option in your window manager which will allow you to minimize the program without changing focus. Of course, whatever you type will only go the minimized program (and not affect the rest of the system).
Another technique (by no means guaranteed) is for the program to detect minimization events, and to request focus within a minimization event handler. Note that doing so would probably (If I were writing a window manager) unminimize the window.

You probably would like to look at jnativehook.
Jnativehook allows you to listen for keyboard events using JNA without an existing focused GUI.
https://github.com/chrislgarry/Apollo-11
https://github.com/kwhat/jnativehook/blob/2.2/doc/ConsumingEvents.md
Example usage:
try {
GlobalScreen.registerNativeHook()
} catch (NativeHookException ex) {
System.out.println(ex.message)
}
GlobalScreen.addNativeKeyListener(
new NativeKeyListener() {
#Override
public void nativeKeyTyped(NativeKeyEvent nativeEvent) {
System.out.println("Pressed " + nativeEvent.keyChar)
}
}
)

Related

How to get Java's TrayIcon message to fade out?

I have a Java application that reduce into the system tray when the red cross is pressed.
Whenever this happen, I display a message to inform the user that the application is still running in the system tray.
Here's the code for that :
...
#Override
public void windowClosing(WindowEvent e) {
try {
tray.add(trayIcon);
trayIcon.displayMessage("", "The application has been reduced
in the system tray, to stop it, press the \"Quit\" button",
TrayIcon.MessageType.WARNING);
setVisible(false);
} catch (AWTException ex) {
System.out.println("unable to add to tray");
}
}
...
For the moment, the message disappears if the user clicks on it.
I would like to set up a counter so the message would fade out after a couple of seconds even if nothing has been done.
Does anyone know a nice way to do it cause I can't seem to find any existing method for that.
EDIT
I have to correct my question, in fact, after testing it a little bit longer, it automatically fades out after, let's say, 7-8 seconds but I find it a little bit too long. Also, it only disappears if the user is executing an action (moving the mouse or typing on the keyboard)
So the new question would be : Is there a way to reduce the fade out time and change the message behaviour by configuring the Java application or is it inherent to Windows?
So the new question would be : Is there a way to reduce the fade out
time by configuring the Java application or is it inherent to Windows?
MSDN says in part How long to notify - In Windows Vista and later, notifications are displayed for a fixed duration of 9 seconds.
any changes is possible to maintain only on Windows size, but seems like is valid/applied for all messagess
you can to create own Traslucent JDialog (Transparency could be way too) placed programatically to the left bottom, fading out will be invoked from Swing Timer

Requesting user input from outside the GUI code, do I need Events or Action to communicate with the GUI in this case?

I'm writing a 2D polygon and physics editor, one functionality is to set a rotation limit for joints.
To use this functionality, the user clicks and drags a line between the joint points which need to receive the limit.
The logic of determining if the pick is valid happens outside of the GUI code.
If a pick is found, I wanted to pop up a JOptionPane.showInputDialog where the user can input the limit.
Thing is, if I do it directly, the program becomes unresponsive, I figure it's because of threading.
I's there a way to define an event listener the GUI can use that doesn't require an actual GUI component?
I want to send an event that also contains a reference to the target object to that component, then telling it that a valid pick has been made and user input is required, and then send the value back via a method of the target object.
I am very inexperienced with Swing.
My hunch is that I might be able to add an ActionListener to the main window, but I don't know how I could address that listener specifically.
As in, how would I need to define an Action that only gets processed by that particular listener?
If that is actually possible, of course.
So far I have only used listeners to let the GUI talk to the logic, not the other way around...
Edit:
The program becomes unresponsive the movement I call
result = JOptionPane.showInputDialog(this,"Enter Limit.");
That just breaks it. Can't even enter anything into the textbox, nor close it, etc.
I figure it's because it spawns a modal dialog that pauses some thread, and calling it from somewhere in the bowels of non GUI code is just not the thing I should do, but I'm too inexperienced to know another way...
Edit2:
I should add that I can use JOptionPane.showInputDialog without any problems if I spawn it, for example, after clicking a button or choosing a popup menu option.
In fact that's how I rename the items I am working with.
But I assume at that point, the dialog is being spawned inside the GUI thread, or this Event Dispatcher queue thing.
The problem with this though is, that this takes visible, interactive GUI components that fire that event.
What I'd like, however, is some sort of component that would spawn JOptionPane.showInputDialog just like a clicked button or context menu would, but without having to be interacted with by the user, but instead by the code.
I guess I could use invisible buttons and emulate mouseclick events, but that's pretty hacky...
Also, I tried spawning Threads and Runnables which spawned the JOptionPane.showInputDialog, but that didn't help either.
Unless I spawn the JOptionPane from a GUI source, everything stalls, and the dialog won't work.
The publisher will have a public add/remove listener, where the subscriber will add itself or be added via another channel to the EventListenerList in the publisher.
You can create your own listener interface that extends EventListener and a function to shoot an event. Below is an example:
import java.util.EventListener;
public interface MyEventListener extends EventListener {
public void myEventOccurred(MyEvent event);
}
You can then create your custom event class, "MyEvent" in the example above like:
import java.util.EventObject;
public class MyEvent extends EventObject {
// customer fields and methods here
public MyEvent(Object source) //more possible args here {
super(source);
//other things here to do what you want
}
}
Now you can have your subscriber implement MyEventListener and override the myEventOccurred(..) method.
Another approach would be to use the SwingWorker class to execute the logic of determining the pick in a dedicated thread without blocking the GUI dispatch thread, and use its callback method to execute the GUI action (open the input dialog).
See : http://docs.oracle.com/javase/6/docs/api/javax/swing/SwingWorker.html
(This page has a better explanation of concept than I could write.)
It should be possible for your background thread to spawn a dialog with invokeAndWait():
final double[] result = new double[1];
SwingUtilities.invokeAndWait(new Runnable() {
public void run() {
try {
result[0] = Double.parseDouble(
JOptionPane.showInputDialog("Enter value:"));
} catch(NumberFormatException e) {
result[0] = -1;
}
}
}
// ... do something with result[0]
Here I made the result an array just so that it can be final (accessible to the anonymous class) and also mutable.

How to detect the JFrame is closed?

I tried a addWindowListener and implement the windowClosing, it works, when I press the close button, but when I use Cmd+Q to close, the windowClosing is not being called, how can I solve it? Do I need to detect Cmd+Q on mac, Alt + F4 on windows via key listener? Is that a general listener for closing window, whatever via the close button or keyboard, or event Ctrl+Alt+Delete or Cmd+Option+Esc to focus kill? Thanks.
I'm not sure what the situation is on Macs, but on Windows you get the windowClosing() callback from the close button; Alt-F4; and if you close the app via task manager. You don't get the callback if you use task manager to kill the process, but I wouldn't expect that anyway.
You have remembered to call setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE); on your JFrame instance, haven't you?
there is one more method windowClosed()
try overriding thing method. hope it will work for you.
You can use this osx library:
com.apple.eawt.ApplicationListener
handleQuit(ApplicationEvent event)
Will probably do the trick.
Information from the docs:
Called when the application is sent the Quit event. This event is generated when the user selects Quit from the application menu, when the user types Command-Q, or when the user control clicks on your application icon in the Dock and chooses Quit. You can either accept or reject the request to quit.
Of course this solution will not work on Windows. As far as I know there is however no universal solution, so this is probably the best way to go.
Sounds like you need to add some KeyListeners and a factory to detect the one you want for a particular operating system.
Check Out
As you said windowClosing is called when you click the (x) button. I am also on a mac and the way I get the CMD+Q to send a signal to the application is using Runtime.addShutDownHook
Runtime.getRuntime().addShutdownHook(new Thread() {
#Override
public void run() {
// code to run when CMD+Q is pressed
}
}

Using a JFrame's focus (being lost) to stop recording a screen cast?

In my Swing application, I'm using a custom module to record a screen cast.
However, I'm a bit hung up on when to force the recording to stop. Right now, I check to see if the user still wishes to record (meaning that they haven't clicked the 'stop' button) and if the application is still open (closing the application causes the recording to stop gracefully).
The problem is that the recording will continue if the application gets pushed behind other apps or minimized, causing recording of 'junk'. I need the recording to stop when the application is no longer 'on top' of the screen. Using the application's focus doesn't seem to work due to other dialogs and things popping up.
Suggestions?
You may want to try adding a WindowListener and override the windowDeactivated() event, which should get called when the frame is no longer the "active window" according to the operating system.
UPDATE:
If you are conscientious about making sure that your child dialogs and windows are owned by your application (making sure you pass in your application frame as the owner), then you could make your WindowListener do something like this:
public void windowDeactivated(WindowEvent e) {
if(e.getOppositeWindow() == null){
// will be null when another application window gets activated, stop recording
}
for(Window w : appFrame.getOwnedWindows()){
if(w.equals(e.getOppositeWindow())){
// one of the windows owned by the frame is active, don't stop recording
}
}
}
Then you will be able to determine if the window focus has left your application altogether or if the focus has just changed to a different child window/dialog.

writing global listener

I want the active window (i.e JFrame ot JDialog) to receive specific keyEvent so that whereever the focusing this keyevent is handling by the window such as ALT+F4 if you press
it wherever the focusing the active window will close,I try to override postprocesskeyEvent but it doesn't work fine
You can add a global event listener to you application using the addAWTEventListener() method in java.awt.Toolkit.
http://java.sun.com/javase/6/docs/api/java/awt/Toolkit.html#addAWTEventListener%28java.awt.event.AWTEventListener,%20long%29
You will need to choose which type of events you want to receive with the event mask when you add the listener.
For example:
// Then on startup register.
AWTEventListener myGlobalKeyListener = new MyGlobalKeyListener();
Toolkey.getDefaultToolkit().addAWTEventListener(myGlobalKeyListener, AWTEvent.KEY_EVENT_MASK);
If you are trying to stop windows from shutting down your application when the user presses ALT-F4 then an event handler will not help you. I belive the operating system handles this by sending SIGTERM to the application. Java does not receive the KeyEvent for this.
The standard approach for intercepting KeyStrokes when using Swing is to use Key Bindings. Although as mentioned earlier this still won't work for Alt+F4.
If you are trying to prevent Alt+F4 from closing the window, then you need to use the setDefaltCloseOperation(...) method to do nothing. Closing an Application gives more information on this approach.

Categories