Java System.in.read() vs Event Handler? - java

Assuming I have something like this:
x= (char) System.in.read();
if(x == 'a') {
// Do something;
}
How much different is it from something like:
public void handle(KeyEvent event) {
switch (event.getCode()) {
case A: // Do something;
case ENTER: // Do something else;
}
}
I mean when should I use the first and when the second? What are the pros and cons?

The two approaches are getting input from the user in two different ways.
The first is reading characters from the JVM's "standard input" stream. If you ran your application without redirecting standard input, this stream is likely to be coming from the "console window" where you launched the JVM. The keystrokes on the console window are processed by the console / OS line editor until the user types ENTER. When that happens a line of characters is delivered to the input stream ready to be read by the JVM / Java application.
The second is processing keyboard events directly. However, this only works in a GUI application. It only sees the keyboard events directed at the application's window(s).
I mean when should I use the first and when the second?
Use the first in a console-based where you don't need to see characters at the instance the user presses a key.
Use the second when you have a GUI based application and you want to get input from the user interactively.
What are the pros and cons?
That is self-evident from the above. However, there are a couple additional "cons".
With the System.in approach:
The System.in stream could be coming from a file. If you need to be sure (or as sure as possible) that you are talking to a real user, use System.console() ... and check that you don't get null.
If you want to see the user's characters as they are typed, you need to use a 3rd-party library.
With the EventHandler approach:
This won't work on a "headless" system.
It is heavy-weight on the Java side as well. Something on the Java side needs to deal with key-up / key-down events, echoing, line-editing, end so on. If you are intercepting the events in your code, it may well be your code that has to do the heavy lifting.
I don't think there is a way to use it without launching a window. (Otherwise there would be no way for the end-use to know where the "input focus" is for the characters that he / she is typing.)

Related

On Spy++ and capturing and sending messages to/from SunAwtFrame [duplicate]

Background:
I was trying to program an auto clicker to click in the background to an application (Roblox, not trying to do anything malicious). I was able to get the window and perform commands like closing it. However, when trying to send clicks to the window it returns 0. (I'm using SendMessage so I don't activate the window)
Minimum reproducible example:
import win32gui
import win32con
import win32api
hwnd = win32gui.FindWindow(None, "Roblox")
while True:
lParam = win32api.MAKELONG(100, 100)
temp = win32gui.SendMessage(hwnd, win32con.WM_LBUTTONDOWN, None, lParam)
win32gui.SendMessage(hwnd, win32con.WM_LBUTTONUP, None, lParam)
print(temp)
Things I tried:
I tried changing the window to see if it was the wrong window, or if it didn't see the window
I tried sending the message normally:
lParam = win32api.MAKELONG(100, 100) # Get the coordinates and change to long
temp = win32gui.SendMessage(hwnd, win32con.WM_LBUTTONDOWN, None, lParam) # Send message to handle
win32gui.SendMessage(hwnd, win32con.WM_LBUTTONUP, None, lParam) # Release key from sent message to handle
I tried it with other windows, and it worked, but not for Roblox
I tried with other commands and it works, but clicks don't. This works: (So I know it's the right window)
temp = win32gui.SendMessage(hwnd, win32con.WM_CLOSE, 0, 0) # Close window with SendMessage
You cannot do that.
Let's start by rephrasing the problem statement to more easily follow along, why that is the case:
"How do I convince a program that has chosen to ignore mouse input messages—by decision or coincidence—to acknowledge mouse input messages?"
As it turns out, that part is actually solved. As the documentation for WM_LBUTTONDOWN notes:
If an application processes this message, it should return zero.
And zero you get, so there's no reason to question the fact that the message has been handled to the extent deemed necessary by the application. This probably falls down the "coincidence" branch, where the application just isn't interested in mouse messages any more than passing them on to DefWindowProc, the kitchen sink for all messages that aren't relevant enough to even ignore.
Key insight here is: A program that needs to process and respond to mouse input can decide to ignore mouse input messages1. (And clients that are based on mouse message handling can easily identify fake input messages, too, and respond by, y'know, not responding altogether.)
So, in essence, sending (or posting) fake mouse messages isn't going to work. Reliably. Ever.
Which leaves you with essentially 3 alternatives:
UI Automation
Accessing a custom automation interface
SendInput (a consolidated version combining keybd_event and mouse_event)
The first two options are listed for completeness only. They are commonly available for applications that actively support being automated. Games generally don't, and protecting against those avenues is easy, and cheap: An application doesn't have to do anything.
SendInput won't work, either. As far as the system is concerned, injected input is processed the same way as any other input (this blog post offers a helpful illustration). Specifically, when a mouse click is injected over a window, that window comes to the foreground. So that fails the requirement to have the application "in the background".
Even if that wasn't the case, injected input is easily and reliably identifiable. A low-level mouse hook is all that's required to get an MSLLHOOKSTRUCT, whose flags field gives this information readily away. With a low-level hook's ability to prevent input from being passed on to the system, a return 1; is all that's needed to filter out those input events.
And that covers all supported ways to automate a foreign application. It's a dead end so dead that it's not worth beating.
Now, if automating an application that runs in the background using fake input summarizes the requirements, then your only option is to run the application in a virtualized environment (which ensures that a click stays confined within the virtual environment and won't bring the application to the front). Keep in mind that all restrictions covered above still apply, and you cannot use any of the methods above. You would have to implement and install a custom mouse driver that generates input that's indiscernible from genuine hardware-sourced input events.
But even then, applications have ways of discovering that they are running in a virtualized environment, and refuse to operate when they do.
The bottom line is: Cheating is hard. Really hard. And your problem doesn't have an easy solution.
1 Mouse input messages are generated by the system as a convenience. They represent a useful (and lossy) abstraction over hardware input events. The full fidelity of those hardware input events is generally not required by "standard" applications.
Games, on the other hand, will usually use lower-level input processing infrastructure, such as Raw Input, and not even look at any of the higher-level processing artifacts.

How to clear the console screen when introducing input in Java?

Is there a way to clear the console when the Java program detects the user it's introducing some data?
I'm executing a program that does the following:
User: //enter username
//show data of the username
I want to make it so the user can search for as many users he want until he ends the execution.
To make it clear and nice, after each username search, I want to clear the screen when the program detects the user is typing something (filling the buffer).
Is there any way to do this?
This is the code I'm using to clear the console (this does not detect when the user is typing):
public static void clearScreen() {
System.out.print("\033[H\033[2J");
System.out.flush();
}
Thanks in advance.
You cannot use System.in without pressing the ENTER key at the end. Its the only way. System.in is not aware of the user input until enter is pressed. So if you are using a normal command line to do this, this won't work and you have to stick different raw command lines like jline
For example :
Terminal terminal = TerminalBuilder.builder().system(true).jna(true).build();
terminal.enterRawMode(); //this enters into a raw mode and get's input on reader
reader = terminal.reader();
//finally
reader.close();
You can check it out. Although it highly doesn't make sense to bring in more dependencies unless you really want to and could just stick to a simple while loop
If you are using maven here's the dependency you can use.
<dependency>
<groupId>org.jline</groupId>
<artifactId>jline</artifactId>
</dependency>
By default, a terminal can only output text line by line.
Moving the cursor around, changing colors or clearing the screen requires special escape sequences that are interpreted by the terminal emulator in which you run your application.
C programs in Linux would usually do this via the ncurses library.
Java programs can do something similar with Lanterna (https://github.com/mabe02/lanterna) but within a GUI window. See also this article, which names other alternatives and shows how to use Lanterna: http://rememberjava.com/cli/2017/01/22/ncurses_terminal_libs.html

Java concurrent console IO

I wrote multithreaded java server-client sockets app with messaging functionality but I encountered a problem with simultaneous console IO.Main server console is listening for keyboard input and simultaneously printing out messages from the clients. On client side there is a separate thread for printout.
Here is simplified code representation:
public class ServerThread{
....
BufferedReader in = ... (sock.getInputStream);
while(true){
System.out.println(in.readline());
....
public class ServerMain{
.....
BufferedReader keyb = ... (System.in);
while(true){
in = keyb.readLine();
....
The problem occurs while I'm typing something in the main server console and at the same time a message arrives from one of the clients.
That message is then concated to what I was typing on screen and cursor moves to the beginning of the next line waiting for input.
What was typed in previously is stuck in the keyboard buffer, and I cant edit it anymore. Same problem happens on client side.
The question is how can I print messages on screen without disrupting ongoing input?
(inputted text also needs to stay printed on screen as in readLine() default behavior)
I already tried some of the solutions suggested for other similar problems:
In Lanterna and JCurses libraries there's no support for native System.IO streams. I would have to reinvent the wheel and implement it all by myself manually from memory to screen, one char at a time plus build whole console GUI layer.
The other thing was using ANSI codes but I couldn't figure out how to do what I need with them. I could read one input char at a time instead of a whole line, then if message arrives clear the line, move cursor to the beginning and printout, but afterwards in nextline I don't know how to print previously buffered text and still be able to delete chars with backspace.
edit:
GUI is not an option as I want my code to be able to run on a headless server.(also assume that there will be only one terminal, console, shell, and app running per side)
A distinct non-answer, based on: there is only one console.
And that console is an artefact from times when multiple threads weren't a real problem. "Works nicely with multiple threads" was never a requirement for that low level console.
Thus: if you really want a sophisticated solution (that isn't a hack of some sort) simply consider: not using the stdin/stdout console(s).
Instead: write a simple Swing GUI application. Have one text entry field where input is collected, and one or maybe multiple text fields where your output goes. If you want to be fancy, make it a webapp. I am sure that using some framework, you could put together a working thing within a few hours. You will learn more valuable skills by doing that, instead of spending these hours "working around" the fact that you picked the wrong technology for your problem.
Update, given the comment by the OP: then the best I can think of: don't write to the console. Write to different files. Open multiple terminals, and use tools like "tail" to show you what is happening with your output file(s).
Ok, I found the ideal solution myself:
JLine library works in conjunction with default System.IO, also there is no need to create new Terminal objects (you can) or anything else. Simply instead of BufferedReader you use LineReader
String readLine(String prompt, Character mask, String buffer)
prompt (can be null) is the unexpanded prompt pattern that will be displayed to the user on the left of the input line
mask (can also be null) is the character used to hide user input (when reading a password for example)
buffer is the initial content of the input line
Edit: In JLine's docs i found an even better solution:
printAbove
void printAbove(AttributedString str)
Prints a string before the prompt and redraw everything. If the LineReader is not actually reading a line, the string will simply be
printed to the terminal.
Parameters:
str - the string to print*

Filter character of console input in Java

I'm writing a terminal version of my Java application, and this is the first time I do this. I tried Scanner and Console, but as far as I investigated, these classes only allow me to receive user input after he/she finish inputting (no manipulating/filtering).
For example, I want the user inputs his age, but if he inputs a meaningless string, all I can do is validating the string and requesting him to input again. What I really want is only allow him to input integer, i.e when he press any key which is not a number, the character will not be displayed on console. Using Swing and JTextField I can do this easily with DocumentFilter, but with console only, I still haven't found a way.
Any help is appreciated. Thanks all.
Java has something called robot API which u can use to control keyboard mouse etc...
Not the recommended way :)
Since the console is not Java program (its a c program) you have limited way to interface with it, perhaps you can write native API to get more control over it. I have not tried it but if needed use this option.

How to make Java console input dissapear after pressing enter

I'm using the Scanner class to take some input from the user through the console. Whenever the user inputs something in the screen and presses enter the input stays on screen for example:
This is the prompt
// User writes command and presses enter
command
output of command goes here
//Use writes command3
command
output of command goes here
command3
output of command3 goes here
Is there anyway I can make the command entered not stay in the console after pressing enter?
For example:
//User writes command
output of command goes here
Short answer: no, not from directly within Java. Java has very limited control over the console: you can only read and write to it. Whatever is displayed on the console cannot be erased programmatically.
Long answer: in Java, all console operations are handled through input and output streams—System.in is an input stream, and System.out and System.err are output streams. As you can see for yourself, there is no way to modify an output stream in Java—essentially, all an output stream really does is output bytes to some destination (which is one reason why it's called a "stream"—it's one-way).*
The only workaround I can see is to use a Console object (from System.console()) instead. Specifically, the readPassword() method doesn't echo whatever the user types back to the console. However, there are three problems with this approach. First of all, the Console class is only available in Java 1.6. Second, I wouldn't recommend using this for input other than passwords, as it would make entering commands more troublesome than it's supposed to be. And third, it still wouldn't erase the prompt from the screen, which would defeat the purpose of what you're trying to achieve, I'd think.
* - Technically speaking, System.out and System.err are both instances of PrintStream, but PrintStream is pretty much just a flexible version of OutputStream—a PrintStream is still like a normal output stream in that outputting is a one-way operation.
You will struggle to do this with the standard library.
If you don't want to do it yourself, you may be able to do this with a 3rd party library like JLine.
huh - I always assumed that if you sent backspace characters ('\b') to sysout that it would clear - but I never actually tried it (don't do much console programming these days).
Haven't tried that, but the bottom of this thread seems to indicate that it should work.
Note that this might not work in an IDE console, but may work in a regular OS console...
I'll leave actually proving for certain that it works as an exercise to the OP :-)

Categories

Resources