Platform specific cut paste mnemonics swing. - java

I'm developing my own text-like JComponent. It isn't a subclass of JTextComponent, because it isn't using a Document as the model. I'd still like to support the standard mnemonics of cut/copy/paste, but I know that the keystrokes depend on the platform.
Ultimately, I'll let the user edit the keybindings themselves, but for now, I'd like to at least default to something that is sensible.
Is it possible to get it from the LookAndFeel somehow? Or do I need to detect the platform myself and just have a mapping per platform?
I'm using Java 8 if that makes a difference.

There is no LAF property that I'm aware of for this purpose.
However you might be able to use the information from the InputMap of the LAF.
The following works for Windows 8:
import java.awt.*;
import javax.swing.*;
public class PlatformMnemonics
{
public static void main(String[] args)
{
KeyStroke copyKeyStroke = null;
KeyStroke cutKeyStroke = null;
KeyStroke pasteKeyStroke = null;
InputMap im = (InputMap) UIManager.get("TextField.focusInputMap");
for (KeyStroke keyStroke: im.keys())
{
boolean upperCase = Character.isUpperCase( keyStroke.getKeyCode() );
if ( upperCase )
{
String actionMapKey = im.get( keyStroke ).toString();
if ("copy-to-clipboard".equals(actionMapKey))
copyKeyStroke = keyStroke;
else if ("cut-to-clipboard".equals(actionMapKey))
cutKeyStroke = keyStroke;
else if ("paste-from-clipboard".equals(actionMapKey))
pasteKeyStroke = keyStroke;
}
}
System.out.println("Copy KeyStroke: " + copyKeyStroke);
System.out.println("Cut KeyStroke: " + cutKeyStroke);
System.out.println("Paste KeyStroke: " + pasteKeyStroke);
}
}
Note there are actually 3 bindings on Windows for each Action as you can see in the Key Bindings programs that displays all the key bindings for every Swing component. I just displayed the binding I think you are interested in.

So, the closest I found to do what I want is the OS X Integration for Java page from Apple. There is a method on the Toolkit class getMenuShortcutKeyMask(), which will help support what I want.
For example, the following will get the right keystroke for "meta-v" on mac, and "ctrl-v" on windows/linux.
KeyStroke.getKeyStroke(KeyEvent.VK_V,
Toolkit.getDefaultToolkit().getMenuShortcutKeyMask())

Related

How to emulate temporary text editor on a throwaway file

I have a basic text based Java app. I want the user to be able to enter sensitive info (password) in a text editing session that only exists for that purpose.
A bit like with git you get a temporary session/file in vi (or another set editor) to edit comment and save/quit - then the git process resumes and consumes that file. The file is (probably) deleted or at least forgotten about.
Do not need any advanced editor capabilities, just basic typing, backspace etc.
I want the user to be able to see what they're typing BUT once they have typed a password, it must be erased from screen. So plain STDIN won't work as the input remains on the screen.
How can I do it in Java or for that matter in another language?
I have looked at Scanner (basically STDIN) and Console.readPassword (user cannot see what they type).
Perhaps a solution that involves STDIN and immediate erasure of the typed line could be acceptable. But emulating git/vi interplay is more attractive because it's arguably a bit more standard.
EDIT: I have implemented something close - create temp file and run notepad.exe on that, let user save and close notepad, read from temp file, delete it. Simple but it relies on an external tool, needs to be adjusted to run on linux as well.. I would like something more seamless where the behaviour is emulated within the java app itself
Swing is pretty consistently available, here is an example of a method that opens a window, waits until the window is closed, and returns the text.
import javax.swing.*;
import java.util.concurrent.LinkedBlockingQueue;
import java.awt.EventQueue;
import java.awt.event.*;
public class EditMe{
LinkedBlockingQueue<String> queue = new LinkedBlockingQueue<String>(1);
public void showEditor(){
JFrame frame = new JFrame("edit text");
JEditorPane pane = new JEditorPane("txt", "");
frame.add(pane);
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.addWindowListener( new WindowAdapter(){
#Override
public void windowClosed(WindowEvent evt){
try{
queue.put(pane.getText());
} catch(InterruptedException e){
//not really possible, but just incase.
throw new RuntimeException(e);
}
}
} );
frame.setSize( 640, 480 );
frame.setVisible(true);
}
public static String getText() throws InterruptedException{
EditMe me = new EditMe();
EventQueue.invokeLater( ()-> me.showEditor() );
return me.queue.take();
}
public static void main(String[] args) throws Exception{
System.out.println("waiting for response");
String s = getText();
System.out.println("response received: \n" + s);
}
}
This would be about equivalent to a notepad solution, but it uses swing that comes with standard jdk's. (There are headless jdk's that don't include swing.)

How to send key press input into a browser via code (e.g. java)

I plan on writing a solver to the recently popular 2048 game
github link
I'm wondering how I could go about this without actually building the game first then solving it... My question is: Is there a way I can send key presses (e.g. 'left' 'right' 'up' and 'down' ) into a web-browser via some sort of language like java/c?
Sorry if this question has been posted before, I was not sure how to actually phrase the question and could not find any results.
use keybd_event function to send key press,
example :
keybd_event(VK_UP,0xE0,0,0);//do click, it will be stay pressed until you release it
keybd_event(VK_UP,0xE0,KEYEVENTF_KEYUP,0);//release click
the second parameter is scan code,there is a list of make and break scan codes for each key
http://stanislavs.org/helppc/make_codes.html,
and here you can find the virtual key codes
http://msdn.microsoft.com/en-us/library/windows/desktop/dd375731(v=vs.85).aspx
Using Java applets you can add a text listener to your component and capture the Keystrokes. For example, in the code below you are capturing the keystrokes of a textbox.
import java.awt.event.*;
import java.awt.*;
import java.applet.*;
public class KeyReader extends Applet{
private static final long serialVersionUID = 1L;
public void init(){
TextField textBox = new TextField(" ");
add(textBox);
textBox.addKeyListener (new KeyAdapter() {
public void keyPressed(KeyEvent e) {
int keyCode = e.getKeyCode();
System.out.println("You Pressed " + keyCode);
}
}
);
}
}

Why JVM doesn't pickup input text locale on Linux

I'm trying to get locale in which user inputs text into JPasswordField.
For this I'm doing the next:
final JPasswordField passwdField = new JpasswordField();
final InputContext it = InputContext.getInstance();
final JTextArea localeLng = new JTextArea();
...
...(some code)
...
passwdField.addKeyListener(new KeyAdapter() {
#Override
public void keyReleased(KeyEvent e) {
localeLng.setText(it.getLocale().getLanguage().toUpperCase());
}
});
I have two keyboard layouts En and Ru. When I switch between them it doesn't affect on the localeLng value. This perhaps on Ubuntu with JRE 7up7.
But this perfectly works on Windows 7.
So, in what may resides my problem at all?
My temporal rough solution :)
public void keyReleased(KeyEvent e) {
int key = (int)e.getKeyChar();
if(key>122){
localeLng.setText("!");
localeLng.setBackground(Color.RED);
} else {
localeLng.setText("En");
localeLng.setBackground(Color.BLUE);
}
}
It's probably a good thing to remind that with Java you get a well defined set of methods and classes but different implementations, there are many JVM out there and many OS that offers support for Java, probably each one with its own implementation.
That said, this link will answer your question.
I also suggest to let the user decide what is the right locale, getting the right locale programmatically can be really tricky, especially under Linux.

Using Windows sounds when displaying JOptionPane windows

How would I play whichever sound the user has set for exclamation when I display JOptionPane.WARNING_MESSAGE or the error sound when I display JOptionPane.ERROR_MESSAGE, for example?
My assumption - nothing special required to do, JOptionPane just does it - was based on skimming BasicOptionPaneUI code and checking if the optionPane's audioActionMap is installed.
The place where the audio is played is in the ui's propertyChangeListener on a change to its ancestor property:
if ("ancestor" == e.getPropertyName()) {
JOptionPane op = (JOptionPane)e.getSource();
boolean isComingUp;
// if the old value is null, then the JOptionPane is being
// created since it didn't previously have an ancestor.
if (e.getOldValue() == null) {
isComingUp = true;
} else {
isComingUp = false;
}
// figure out what to do based on the message type
switch (op.getMessageType()) {
case JOptionPane.PLAIN_MESSAGE:
if (isComingUp) {
BasicLookAndFeel.playSound(optionPane,
"OptionPane.informationSound");
}
break;
// all other message types handled as well
}
the shared actionMap is installed (lazyly, so an optionPane must have been visible once)
assertTrue(UIManager.get("AuditoryCues.actionMap") instanceof ActionMap);
ActionMap map = (ActionMap) UIManager.get("AuditoryCues.actionMap");
assertNotNull(map.get("OptionPane.errorSound"));
sounds enabled on OS (win 7) level and sound on hardware turned on (just for testing) ... WTF: but nothing happens (and assumption proven to be wrong ;-)
Debug session (I hate it ... but occasionally ...) turns out that performing the audioAction doesn't happen, here are the methods involved :
static void playSound(JComponent c, Object actionKey) {
LookAndFeel laf = UIManager.getLookAndFeel();
if (laf instanceof BasicLookAndFeel) {
ActionMap map = c.getActionMap();
if (map != null) {
Action audioAction = map.get(actionKey);
if (audioAction != null) {
// pass off firing the Action to a utility method
// JW: we have an audioAction, so on to the next method
((BasicLookAndFeel)laf).playSound(audioAction);
}
}
}
}
protected void playSound(Action audioAction) {
if (audioAction != null) {
Object[] audioStrings = (Object[])
UIManager.get("AuditoryCues.playList");
if (audioStrings != null) {
// JW: here the action is performed ... except we don't reach this
....
}
}
That's rather astonishing, isn't it? After all, the action were created, so if there is no playlist, why would they have been created?
And here comes the catch: the list used for creating the actions is a different list
// in BasicLookAndFeel
protected ActionMap getAudioActionMap() {
ActionMap audioActionMap = (ActionMap)UIManager.get(
"AuditoryCues.actionMap");
if (audioActionMap == null) {
// here it's named cueList
Object[] acList = (Object[])UIManager.get("AuditoryCues.cueList");
}
and the reason that's a different list is ... to allow LAFs to customize the sounds that actually are to be played
// BasicLookAndFeel
// *** Auditory Feedback
"AuditoryCues.cueList", allAuditoryCues,
// this key defines which of the various cues to render.
// L&Fs that want auditory feedback NEED to override playList.
"AuditoryCues.playList", null,
Ooookaaayy .. so let's see what a concrete LAF is doing, f.i. Win:
// *** Auditory Feedback
// this key defines which of the various cues to render
// Overridden from BasicL&F. This L&F should play all sounds
// all the time. The infrastructure decides what to play.
// This is disabled until sound bugs can be resolved.
"AuditoryCues.playList", null, // table.get("AuditoryCues.cueList"),
EOL.
Not quite :-) This comment hints to what is doable:
Object[] cueList = (Object[]) UIManager.get("AuditoryCues.cueList");
UIManager.put("AuditoryCues.playList", cueList);
Which in fact does work for WindowsLAF (even respecting the OS sound schema and - most importantly - not playing if disabled), but not for any of the other core LAFs.
Firstly, I agree with Andrew
However, take a look here then here
Ps I've not tested this myself
Using the links MadProgrammer provided (reposted at the end) as a starting point, here's what I figured out:
import java.awt.*;
import javax.swing.JOptionPane;
//retrieve the default sound from windows system sounds
//for another sound replace "default" accordingly
final Runnable SOUND = (Runnable)Toolkit.getDefaultToolkit().getDesktopProperty
("win.sound.default");
and then just before displaying the JOptionPane:
if(SOUND != null)SOUND.run();
NB Some sound events like Program Error cannot be accessed this way. A list of accessible sound events is available under the audio-feedback heading on the Windows Desktop Property Support page from Oracle
While this will not work at all on a non-windows o/s, it will not, according to the blog, cause the program to crash on another o/s. I don't have a JDK for my Linux partition yet, ergo I am currently unable to test this.

Multi-Line Button text in SWT/WindowBuilder?

Is there any way to force the SWT button text to span two lines, either manually in the SWT code or using the WindowBuilder GUI?
I have this:
I want something like this (digitally altered image to achieve this):
Is it possible? How?
I was able to get the multi-line button text work, by adding SWT.WRAP as a style for the button and by having '\n' inserted in the text to be set as the button label.
....
Button check = new Button(composite, SWT.WRAP | SWT.PUSH );
check.setText("Multi\n Line\n Button \n Text");
....
Even though the button.setText(..) java doc says that the button label must not contain new line chars, it works when SWT.WRAP is added as a style('\n' were ignored when SWT.WRAP was not set).
Just thought this could be useful.
Instead of diving into native code, I would do this by creating a custom control. Extend composite, use a label for the multi-line text and add some decoration with 2D drawing. There are methods in graphic context for rounded rectangles and gradient painting. It may not look exactly like a native widget, but, in my opinion, better than using JNI.
The following code does the trick:
final int style = OS.GetWindowLong(button.handle, OS.GWL_STYLE);
OS.SetWindowLong(button.handle, OS.GWL_STYLE, style | OS.BS_MULTILINE);
button.setText("line 1\nline 2");
You just import org.eclipse.swt.internal.win32.OS and that's it. Of course, that class, and the handle field inside button are not part of SWT API, so your code is no longer portable. But the functions are defined in Windows API, so you don't have to worry too much they will change in future versions of SWT.
Be aware that after this change, computeSize() no longer works well.
Edit: full class where I take care of computeSize() and GWL style
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.internal.win32.OS;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
public class MultilineButton extends Button {
public MultilineButton(Composite parent, int style) {
super(parent, style);
final int gwlStyle = OS.GetWindowLong(this.handle, OS.GWL_STYLE);
OS.SetWindowLong(this.handle, OS.GWL_STYLE, gwlStyle | OS.BS_MULTILINE);
}
#Override
protected void checkSubclass() {
}
#Override
public Point computeSize(int wHint, int hHint, boolean changed) {
final Point size = super.computeSize(wHint, hHint, changed);
final GC gc = new GC(this);
final String multiLineText = this.getText();
final Point multiLineTextSize = gc.textExtent(multiLineText, SWT.DRAW_DELIMITER);
final String flatText = multiLineText.replace('\n', ' ');
final Point flatTextSize = gc.textExtent(flatText);
gc.dispose();
size.x -= flatTextSize.x - multiLineTextSize.x;
size.y += multiLineTextSize.y - flatTextSize.y;
return size;
}
}
I would try setting the button text to a string with a '\n' character where you want the line break to happen.
there's actually a super easy way in swing, not in SWT. I misread the question when I first posted this answer, but since I found my way here whilst searching for a swing solution, I'll leave it up for others.
button.setText("<html>My<br>Text<br>");
many swing components render HTML.
On checking the date of posting, not sure if this is a relevant answer to a question that old, but I found this while trying to solve this problem so I thought I'd share. Cheers.
The only way I can think of doing this, is through JNI/JNA. Take note that if you go down this road, you'll be breaking Java's platform independence by calling platform-specific native functions.
For Windows, take a look at the SetWindowText API call. Supposing you have code similar to:
Button btn = new Button(shell, SWT.PUSH);
btn.setText("Hello world!");
You can obtain the handle via btn.handle. With a bit of JNA magic something along these lines might be possible:
final User32 lib = (User32) Native.loadLibrary("user32", User32.class);
final HWND hWnd = new W32API.HWND(new W32API.UINT_PTR(btn.handle)
.toPointer());
final String text = "Hello\nworld!"; // or "Hello\r\nworld!"?
lib.SetWindowText(hWnd, text.toCharArray());
I couldn't actually get this to work (it gives a java.lang.UnsatisfiedLinkError on SetWindowText() which I couldn't sort out), but this might point you in the right direction.

Categories

Resources