I found some good Q/A here on my problem but couldn't find the right one.
I have a barcode reader that reads barcode and sends scanned code as keyboard input. It is alright I can catch input easily
browser.addKeyListener(new KeyAdapter() {
#Override public void keyPressed(KeyEvent e) {
if(e.keyCode >=48 && e.keyCode <=57) {
System.out.println("number caught");
}
}
});
But I will have more inputs in my application so I need to know if it is send by barcode reader or by keyboard.
I think it can be achieved by adding some timer in code that verifies how long is some "sequence" reading.
I just can not figure it out, (I mean logic behind it), I am missing piece of logic.
User is typing some info, (alpha numerical)
user desides to use barcode reader to read barcode
I tried timer e.g
if(System.currentTimeMillis() - lastPressProcessed ??? 500) { after keyListener is triggered but I think I am missing something.
sidenote:
USB barcode reads code fast so keystrokes are emulated really fast est whole barcode is written in about 1 second + carry /r/n (also enter is pressed).
sidenote2: barcodes are going to be different in length so I can not read just some length in short time and decide wether it is user input or barcode input (max numbers read 13 + enter).
sidenote3: I have no input field for barcode I am trying to achieve running it on "background".
I am seeking logic/pseudocode suggestions on topic.
related topics that are really close to mine are here, and here
Thank you.
edit
After deep tought I found out the solution I'll keep this Q here just for another users that might find this usable.
solution
--moved to answer + edited
This code coveres everything I wanted to achieve, it reads just numbers (actualy numbers that are under F keys, not numbers that are on numpad, I had problem with it because scanner is keyboard dependant so I made function signsToNumbers() that converts signs !##$%^&*() to numbers 1234567890. I may change this function because every key on keyboard has its own unique identifier + modifier, it seems that scanner sends also SHIFT modifier to the application but that is not as problem as it seems I'll just match e.keyCode.
The code below works as:
waits for number input otherwise does nothing
if 1st number is inserted it is looping in if condition until either 200ms is reached or '\r\n` is received
sends data to server via URL
code
#Override public void keyPressed(KeyEvent e) {
if (timer == true && System.currentTimeMillis() - lastTimer < 200) {
if(e.keyCode >=48 && e.keyCode <=57) { //number pressed
lastTimer = System.currentTimeMillis();
myString = myString + Character.toString(e.character);
}
if(e.keyCode == SWT.CR) {
myString = signsToNumbers(myString);
newUrl = browser.getUrl()+ "/newcode/" + myString;
browser.setUrl(newUrl);
text.setText(newUrl);
System.out.println(myString);
System.out.println("barcode read");
myString = "";
timer = false;
lastTimer = 0;
}
}else{
if(e.keyCode >=48 && e.keyCode <=57) {
lastTimer = System.currentTimeMillis();
timer = true;
myString = Character.toString(e.character);
}
myString = "";
lastTimer = 0;
}
}
});
Here you can download my solution:
http://jhead.hu/resource/java/general/BarcodeReader.java
The following code sample shows you, how to use it. When a new barcode is identified, an ActionEvent is generated and you can get the barcode via the getActionCommand() method. If the panel is not active you can send the characters further to the focus manager.
The only problem is that my barcode scanner sends the characters too fast so the character bits are sometimes mixed. I've got no better solution yet.
public class PanelWithBarcodeReading extends javax.swing.JPanel implements ActionListener {
private BarcodeReader barcodeReader = new BarcodeReader();
public PanelWithBarcodeReading() {
initComponents();
barcodeReader.addActionListener(this);
barcodeReader.setParent(this);
KeyboardFocusManager.getCurrentKeyboardFocusManager().addKeyEventDispatcher(barcodeReader);
}
#Override
public void actionPerformed(ActionEvent e) {
if (SwingUtilities.getWindowAncestor(this).isActive()) {
System.out.println("BARCODE='" + e.getActionCommand() + "'");
} else {
barcodeReader.dispatchLastBarcodeAsKeyEvents();
}
}
...
}
Related
In Java, when you print to the console while a user is typing. It will destroy what is being typed. Let's say I have a server set up, and you can run commands from the server. Then this is what it might look like.
I'm trClient connected to server
ying to typMessage received from client
e a command
Is there a way to get around this? To have the text be printed on the line above the user is typing on. If you've ever ran a Minecraft server, you might know what I'm talking about. It would look something like this.
Since Minecraft is made using Java, I know that this is possible, but I haven't been able to figure out a way to do it.
Maybe you could do it like this.
You have one while loop with a value of true.
Everything that the user enters is entered in the ArrayList and every time the user enters something that list is printed.
If you want it to print only the entered message, you can empty it each time you print the list.
There you could use LinkedList where when you drag all the variables from the list, it remains empty.
If you want to use a library that gives terminal support, you can use com.googlecode.lanterna for your own terminal where you can set where you want to show the inputs given by the user. You can add the dependency to your program:
<!-- https://mvnrepository.com/artifact/com.googlecode.lanterna/lanterna -->
<dependency>
<groupId>com.googlecode.lanterna</groupId>
<artifactId>lanterna</artifactId>
<version>3.1.1</version>
</dependency>
You can use the Terminal of this library and do such manual positioning of input and printed test like the way you want the interface.
Have a our on this page and browse more to gather knowledge on lanterna.
I've added a very basic code for reading input and showing that on the gui:
public static void main(String[] args) {
try {
int row = 5, col = 5;
Terminal terminal = new DefaultTerminalFactory().createTerminal();
Screen screen = new TerminalScreen(terminal);
TextGraphics tg = screen.newTextGraphics();
screen.startScreen();
KeyStroke key;
List<Character> string = new ArrayList<>();
while (true) {
System.out.println("reading input");
key = terminal.readInput();
if (key != null && key.getCharacter() != null) {
System.out.println("Key not null: " + key.getCharacter());
// you can add more keypress checks, they have a lot of enums for this
if (key.getKeyType() == KeyType.Enter) {
String str = string.stream().map(String::valueOf).collect(Collectors.joining());
System.out.println(col + " " + row + " " + str);
tg.putString(col, row, str);
string.clear();
} else if (key.getKeyType() == KeyType.Escape) {
break;
} else {
string.add(key.getCharacter());
}
} else {
System.out.println("Null input");
break;
}
screen.refresh();
}
screen.stopScreen();
System.exit(0);
} catch (Exception e) {
e.printStackTrace();
}
}
I am trying to make it so that instead of hitting the enter key in my java program to make the enter action occur, I can instead hit the enter key while a custom method is running. At this point, I have looked into Hashmaps but am pretty confused if this going to do what I want. Any help would be greatly appreciated. It seems like this should be an easy thing to do, but for some reason I am just not getting a solution to it.
So, I am thinking my code will be something like this. Essentially, I am making a game of Hot Potato and I need to have the players take turn entering a character (e, d, and c for team 1 and o, k, and n for team 2). This will be involving a GUI interface as well. A have a while loop that will end once a timer reaches zero. What I would like is for the players to be able to put in a letter into a JTextField in the GUI and then simply press spacebar (as they will be sharing a keyboard). Once they enter the right letter (I made it randomized), they can hit spacebar and they will have "tossed the potato" to the other player.
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_SPACE)
{
KeyEvent.VK_ENTER;
}
}
I am working all of this out of the actionPerformed(ActionEvent ev) method. The fuller code looks like this. The if statement is commented out because I would like the game to start when the main button is pressed, but right now I get a ton of compilation errors when I uncomment the JButton and have it working with the String text that is the dialogue from the text you enter into a JTextField.
public void actionPerformed(ActionEvent ev) {
Object eventSource = ev.getSource();
String text = entryText.getText(); // text entered into JText
//JButton eventButton = (JButton) eventSource;
System.out.println(text);
//if (eventButton.equals(main))
{
int totalTime = 1000*(HotPotato.randNum());
long startTime = System.currentTimeMillis();
System.out.println(totalTime/1000);
Boolean p1Start = false;
String input = "";
while (System.currentTimeMillis() - startTime <= totalTime)
{
p1Start = !p1Start;
char a = HotPotato.randLetterBoth(p1Start);
String aString = String.valueOf(a);
while (!input.equals(aString))
{
System.out.print(aString); // temporary, shows test letter
input = theKeyboard.next();
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_SPACE)
{
KeyEvent.VK_ENTER;
}
}
}
}
if (p1Start)
{
System.out.print("Team 2 Wins!");
}
else
{
System.out.print("Team 1 Wins!");
}
setLabels();
myPicture.makeHotPotatoOn(myHotPotato.state());
myPicture.repaint();
}
}
My problem is explained in the following scenario
There are 2 JTextField objects. Let's give them variable names as jTextField1 and jTextField2. And the current focus owner is jTextField2. And the User and/or a Device is firing key inputs into the program. But according to the speed of each key being pressed and released the program should decide which text field the key char of that key input should be entered into. For an example, if the difference between KEY_PRESSED and KEY_RELEASED is less than or equal to 50 milliseconds, the Key Char should be typed into jTextField1 and never into jTextField2 but while the Focus is still owned by jTextField2 and unchanged. If the difference between the events are greater than 50 milliseconds, the text will be typed into its current Focus Owner which is jTextField2 (Or it may be any other object too according to what the User has the Focus at the moment.). So if there were 2 simultaneous activities happening, for an example a user is typing keys in a speed of greater than 50 milliseconds per key typing, and another device like a Barcode Scanner is firing Key Events in a speed less than 50 milliseconds, both of these inputs should be entered or typed into those different text fields separately according to their typing speeds while the focus owner is always at the object which the user is interacting with.
Here is the current code I have written which works well but with the problem that when keys are pressed in a speed less than 50 milliseconds per key, it sets at jTextField1 but it also gets typed at jTextField2.
#Override
public boolean dispatchKeyEvent(KeyEvent e) {
if (e.getID() == KeyEvent.KEY_PRESSED) {
millis = System.currentTimeMillis();
if (e.getKeyCode() == KeyEvent.VK_ENTER) {
enter1 = true;
}
} else if (e.getID() == KeyEvent.KEY_RELEASED) {
if ((System.currentTimeMillis() - millis) <= 10) {
if (e.getKeyCode() == KeyEvent.VK_ENTER) {
enter2 = true;
} else {
barcodeStringBuilder.append(e.getKeyChar());
}
if (enter1 && enter2) {
compo = getFocusOwner();
jTextField1.setText(barcodePool.toString());
barcodeStringBuilder.setLength(0);
compo.requestFocus();
}
enter1 = false;
enter2 = false;
} else {
}
} else if (e.getID() == KeyEvent.KEY_TYPED) {
}
return false;
}
The previous attempt I made to accomplish this task was trying to handle the input of the two devices which are a Keyboard and a Barcode Scanner separately using the Java HID API which also was unsuccessful. You can find my question thread on it here. And then I made it into this option which so far seems to be a good option.
So, does anyone know an effective way to accomplish my task as I have described above?
Thank you! And your help is highly appreciated.
I would not give either JTextFields focus, would not use a KeyEventDispatcher, but would instead try to use Key Bindings, and then based on the timing, append the text into the appropriate text field. This would prevent focus issues sending the text to two text fields.
I am building a GWT component to behave much like the comments box here on stackoverflow, and other sites. I am trying to register listeners for KeyPress, Change and ONPASTE events that will update my status line with number of characters remaining, etc.
It works except it is always one character behind the actual number of characters in the text area. I set the max number of characters to 10. When I type the first character it still says, "10 characters remaining". It doesn't update the status line until I type the second character and then it is one off, it says 9 characters remaining when the second character is typed.
When I BACKSPACE or DELETE, it is also one off, when there are no characters it still says "9 characters remaining" until I press the BACKSPACE or DELETE a second time.
I am getting this behavior in both Firefox, Chrome and Internet Explorer on Windows. So I think I am not registering something correctly.
I know this has something to do with when the events are getting fired, but I have spend hours on trying to diagnose this behavior and have run out of ideas.
Here is where I am registering the event handlers, the complete code is BoundedTextAreaWithFeedback.
private void registerHandlers()
{
final BoundedTextAreaWithFeedback outer = this;
this.textArea.addChangeHandler(new ChangeHandler()
{
public void onChange(final ChangeEvent changeEvent)
{
outer.validate();
}
});
this.textArea.addKeyPressHandler(new KeyPressHandler()
{
public void onKeyPress(final KeyPressEvent keyPressEvent)
{
outer.validate();
}
});
this.panel.addFocusHandler(new FocusHandler()
{
public void onFocus(final FocusEvent focusEvent)
{
outer.textArea.setFocus(true);
}
});
// capture paste events
this.textArea.sinkEvents(Event.ONPASTE);
}
Here is the validate() method.
private boolean validate()
{
final boolean isValid;
final int len = this.textArea.getText().length();
if (len < this.minLength)
{
this.status.setText("Enter at least " + this.minLength + " characters.");
this.status.setStyleName("input-status-underflow");
isValid = false;
}
else if (len > this.maxLength)
{
this.status.setText(this.maxLength - len + " characters remaining");
this.status.setStyleName("input-status-overflow");
isValid = false;
}
else
{
this.status.setText(this.maxLength - len + " characters remaining");
this.status.setStyleName("input-status-ok");
isValid = true;
}
return isValid;
}
I just started adding every addXXXHandler() until one worked.
this.textArea.addKeyUpHandler(new KeyUpHandler()
{
public void onKeyUp(final KeyUpEvent event)
{
outer.validate();
}
});
Seems to have done the trick.
Here is the working code, CTRL-V and paste from context menu also work now.
Try using a DeferredCommand to execute the validation code. I believe the problem is that when the event is firing, they character is not yet added to the text area. The DeferredCommand will not execute until any pending event handlers have finished, allowing the length of the text to be calculated correctly.
See this question for an example of using a DeferredCommand.
Outside of the actual SWT listener, is there any way to ignore a listener via code?
For example, I have a java program that implements SWT Text Widgets, and the widgets have:
SWT.Verify listeners to filter out unwanted text input.
ModifyListeners to wait for the correct number of valid input characters and automatically set focus (using setFocus())to the next valid field, skipping the other text widgets in the tab order.
focusLost(FocusEvent) FocusListeners that wait for the loss of focus from the text widget to perform additional input verification and execute an SQL query based on the user input.
The issue I run into is clearing the text widgets. One of the widgets has the format "####-##" (Four Numbers, a hyphen, then two numbers) and I have implemented this listener, which is a modified version of SWT Snippet Snippet179. The initial text for this text widget is " - " to provide visual feedback to the user as to the expected format. Only numbers are acceptable input, and the program automatically skips past the hyphen at the appropriate point.
/*
* This listener was adapted from the "verify input in a template (YYYY/MM/DD)" SWT Code
* Snippet (also known as Snippet179), from the Snippets page of the SWT Project.
* SWT Code Snippets can be found at:
* http://www.eclipse.org/swt/snippets/
*/
textBox.addListener(SWT.Verify, new Listener()
{
boolean ignore;
public void handleEvent(Event e)
{
if (ignore) return;
e.doit = false;
StringBuffer buffer = new StringBuffer(e.text);
char[] chars = new char[buffer.length()];
buffer.getChars(0, chars.length, chars, 0);
if (e.character == '\b')
{
for (int i = e.start; i < e.end; i++)
{
switch (i)
{
case 0: /* [x]xxx-xx */
case 1: /* x[x]xx-xx */
case 2: /* xx[x]x-xx */
case 3: /* xxx[x]-xx */
case 5: /* xxxx-[x]x */
case 6: /* xxxx-x[x] */
{
buffer.append(' ');
break;
}
case 4: /* xxxx[-]xx */
{
buffer.append('-');
break;
}
default:
return;
}
}
textBox.setSelection(e.start, e.start + buffer.length());
ignore = true;
textBox.insert(buffer.toString());
ignore = false;
textBox.setSelection(e.start, e.start);
return;
}
int start = e.start;
if (start > 6) return;
int index = 0;
for (int i = 0; i < chars.length; i++)
{
if (start + index == 4)
{
if (chars[i] == '-')
{
index++;
continue;
}
buffer.insert(index++, '-');
}
if (chars[i] < '0' || '9' < chars[i]) return;
index++;
}
String newText = buffer.toString();
int length = newText.length();
textBox.setSelection(e.start, e.start + length);
ignore = true;
textBox.insert(newText);
ignore = false;
/*
* After a valid key press, verifying if the input is completed
* and passing the cursor to the next text box.
*/
if (7 == textBox.getCaretPosition())
{
/*
* Attempting to change the text after receiving a known valid input that has no results (0000-00).
*/
if ("0000-00".equals(textBox.getText()))
{
// "0000-00" is the special "Erase Me" code for these text boxes.
ignore = true;
textBox.setText(" - ");
ignore = false;
}
// Changing focus to a different textBox by using "setFocus()" method.
differentTextBox.setFocus();
}
}
}
);
As you can see, the only method I've figured out to clear this text widget from a different point in the code is by assigning "0000-00"
textBox.setText("000000")
and checking for that input in the listener. When that input is received, the listener changes the text back to " - " (four spaces, a hyphen, then two spaces).
There is also a focusLost Listener that parses this text widget for spaces, then in order to avoid unnecessary SQL queries, it clears/resets all fields if the input is invalid (i.e contains spaces).
// Adding focus listener to textBox to wait for loss of focus to perform SQL statement.
textBox.addFocusListener(new FocusAdapter()
{
#Override
public void focusLost(FocusEvent evt)
{
// Get the contents of otherTextBox and textBox. (otherTextBox must be <= textBox)
String boxFour = otherTextBox.getText();
String boxFive = textBox.getText();
// If either text box has spaces in it, don't perform the search.
if (boxFour.contains(" ") || boxFive.contains(" "))
{
// Don't perform SQL statements. Debug statement.
System.out.println("Tray Position input contains spaces. Ignoring.");
//Make all previous results invisible, if any.
labels.setVisible(false);
differentTextBox.setText("");
labelResults.setVisible(false);
}
else
{
//... Perform SQL statement ...
}
}
}
);
OK. Often, I use SWT MessageBox widgets in this code to communicate to the user, or wish to change the text widgets back to an empty state after verifying the input. The problem is that messageboxes seem to create a focusLost event, and using the .setText(string) method is subject to SWT.Verify listeners that are present on the text widget.
Any suggestions as to selectively ignoring these listeners in code, but keeping them present for all other user input?
Thank you in advance for your assistance.
If you name the listener instead of using an anonymous one, you can add and remove it whenever you like.
Example:
// Adding focus listener to textBox to wait for loss of focus to perform SQL statement.
FocusAdapter focusTextBox = new FocusAdapter()
{
#Override
public void focusLost(FocusEvent evt)
{
// Get the contents of otherTextBox and textBox. (otherTextBox must be <= textBox)
String boxFour = otherTextBox.getText();
String boxFive = textBox.getText();
// If either text box has spaces in it, don't perform the search.
if (boxFour.contains(" ") || boxFive.contains(" "))
{
// Don't perform SQL statements. Debug statement.
System.out.println("Tray Position input contains spaces. Ignoring.");
//Make all previous results invisible, if any.
labels.setVisible(false);
differentTextBox.setText("");
labelResults.setVisible(false);
}
else
{
//... Perform SQL statement ...
}
}
};
You can then add the listener by doing this:
textBox.addFocusListener(focusTextBox);
Removal is as easy as this:
textBox.removeFocusListener(focusTextBox);
Just make sure to re-enable the listener after you've done what you've wanted to programmatically achieve, or your code will not act like you'd expect.
I didn't tested your code, but try method isFocusControl() in the listener to see if the user enters the text or you set the text with setText() when the focus is not in textBox.