I was directed to the website Hackertyper.com - and it intrigued me very much. So I decided that, using Java, I would attempt to re-write it. I stumbled on some issues while I did it.
Currently, so far from my intro Java course, I only learned how to use the Scanner class, so at the moment, my "code" only takes an input after pressing the "Enter" key. At the same time, upon pressing enter, the entire String gets printed out.
My questions are:
Are there any libraries in which it would take an input (any key on the keyboard, in this case) and do something without pressing "Enter", and.
What do I need to do in order to take an input, stop the piece of code, wait for the next input, before executing the next loop?
So far below is the very poorly written code of what I have.
String paragraph = "hellothere";
Scanner newInput = new Scanner(System.in);
String input = newInput.nextLine();
for(int i = 0; i < paragraph.length(); i++){
if(input.equals("2")){
System.out.print(paragraph.charAt(i));
input = newInput.nextLine(); // call input again after executed the loop
}
}
After I solve these issues I think I will dabble with IO and let Java call a text file in which inside would have pieces of code, which onKeyPress would type out the i-th index.
Thanks!
I assume you mean Hacker Typer, not hacker type?
1) I think what you need is a key listener event
2) You could write a method that is called when the key event fires. The method would then return a piece of text. You store the text in an array, so it always returns the next piece of code.
To create the array from string you can use String.split
edit: i just saw that it always puts two characters, not the next word.
I would recommend you used the SWT toolkit.
For a functional example, run my code below. You only need to add the SWT dependencies.
Writing into the console is silly. This is much cooler:
public class Waffles
{
// Keeps track of how many times any key is pressed
private static int keyCounter = 0;
// Used to continuously append characters from the input string
private final StringBuilder builder;
// This can be read from a file, or whatever
private final String GIBBERISH;
public static void main(final String[] args)
{
new Waffles();
}
private Waffles()
{
builder = new StringBuilder();
// Put your dummy code here (extract from a file)
GIBBERISH = " I freaking love waffles!";
// Loop the SWT Display
init();
}
private void init()
{
final Display display = new Display();
final Shell shell = new Shell(display);
shell.setText("HackerTyper");
shell.setSize(500, 500);
shell.setLayout(new GridLayout());
shell.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
// Here we create the text area
createWidget(shell);
shell.open();
while (!shell.isDisposed())
{
if (!display.readAndDispatch())
display.sleep();
}
display.dispose();
}
private void createWidget(final Composite parent)
{
// Wrap it for multi line text, and set it to read only, so we can't modify
// the text 'manually'
final Text textArea = new Text(parent, SWT.MULTI | SWT.WRAP | SWT.READ_ONLY);
textArea.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
// Yay colours!
textArea.setBackground(Display.getCurrent().getSystemColor(SWT.COLOR_BLACK));
textArea.setForeground(Display.getCurrent().getSystemColor(SWT.COLOR_GREEN));
// This is what was recommended by the other two answers
textArea.addKeyListener(new KeyListener()
{
#Override
public void keyPressed(final KeyEvent arg0)
{
// *magic*
textArea.setText( getGibberish() );
}
#Override
public void keyReleased(final KeyEvent arg0)
{
}
});
}
private String getGibberish()
{
if (keyCounter > GIBBERISH.length() - 1)
keyCounter = 0; // Careful not to go out of string bounds
// Continuously append it, then pass the whole text to the textArea
builder.append( GIBBERISH.charAt(keyCounter++) );
return builder.toString();
}
}
FEEL like a hacker.
BE like a hacker. HUZZZAAA!
I'm really tired.
There is an interface called KeyListener but this only works with swing classes, and based on you're code this a console application. You could use JNativehook which allows you to use swing events in a console application. You should learn basic swing events before using this though.
Related
This question already has answers here:
Java - checking if parseInt throws exception
(8 answers)
Closed 1 year ago.
So I tried to look a bit in forums and StackOverflow but nothing worked for me I need when enter is pressed to stop my code this is my code `
JFrame f;
JTextField I;
// JButton
JToggleButton b;
// label to display text
JLabel l;
f = new JFrame("AutoClicker");
i = new JTextField("100");
// create a label to display text
l = new JLabel("clicks/seconds");
// create a new buttons
b = new JToggleButton("Start");
// create a panel to add buttons
JPanel p = new JPanel();
// add buttons and textfield to panel
p.add(b);
p.add(i);
p.add(l);
// setbackground of panel
p.setBackground(Color.red);
// add panel to frame
f.add(p);
// set the size of frame
f.setSize(280, 80);
f.setVisible(true);
b.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
int jml = Integer.parseInt(i.getText());
if(jml < 50)
{
jml = 50;
}
AutoClicker(jml);
}
});
}
static void AutoClicker(int jml)
{
while(true)
{
try{
Robot r = new Robot();
int button = InputEvent.BUTTON1_DOWN_MASK;
r.mousePress(button);
Thread.sleep(jml);
r.mouseRelease(button);
Thread.sleep(jml);
}
catch(Exception e){
e.printStackTrace();
System.out.println("not good");
}
}
}
}`
I tried to add a KeyListener but it did not work.
I don't understand why it doesn't work so if you can just help me know why it doesn't work it would be much apreciated.
KeyListener isn't going to solve the problem of the fact that you are simply not handling the potential of Integer.parseInt to throw an exception - I mean, how can it convert "" or "This is not a number" to an int. In those cases it throws an exception
The JavaDocs clearly state
Throws:NumberFormatException - if the string does not contain a
parsable integer.
Go back and have a look at the original error you were getting from your previous question on this exact topic
java.lang.NumberFormatException: For input string: "Enter"
It's telling you exactly what the problem is - the text "Enter" can not be converted to an int value.
YOU have to handle this possibility. No offence, but this is honestly basic Java 101. See Catching and Handling Exceptions
Another option which "might" help is to use a formatted text field
You also don't seem to have a firm grip on the concept of what a "event driven environment" is or what the potential risk of what doing something like while (true) will do if executed within the context of the Event Dispatching Thread. This makes me think you've got yourself in over all head.
You're going to want to learn about Concurrency in Swing as AutoClicker should never be called within the context of the Event Dispatching Thread, which is going to lead you another area of complexity, concurrency and all the joys that brings.
Updated
Wow, you changed the title. Maybe a better description of the problem you're trying to solve would have a gotten a better answer. In short, you can't, not natively in Java anyway. The only way you can detect keyboard input out side of the app is using native integration, JNA/JNI. Plenty of examples about, for example
Im creating a GUI program with multiple buttons. I'm only able to use one of the buttons at the moment. Here is my Button Listener class. I want to be able to use the "Test" button and then use the "Yes" or "No" button after. Let me know if you need to see any more of my code.
public class ButtonListener implements ActionListener
{
public void actionPerformed(ActionEvent e)
{
if(e.getSource()==TestButton)
{
TestWord = (Text_Input.getText());
StringBuilder RevTestWord = new StringBuilder();
RevTestWord.append(TestWord);
RevTestWord = RevTestWord.reverse();
DisplayText = "Is " + RevTestWord + " a real word?";
Test_Anadrome.setText(DisplayText);
if(e.getSource()==YesButton)
{
DisplayText = "Word added to Anadrome list.";
Test_Anadrome.setText(DisplayText);
}
if(e.getSource()==NoButton)
{
DisplayText = "Type a different word and press the 'Test Word' Button.";
Test_Anadrome.setText(DisplayText);
}
}
}
}
Sorry I'm pretty new to Java.
It looks like your if/else statements for your YesButton and NoButton are inside of your if statement for TestButton, so as a result those statements are only being checked if source==TestButton. Try moving this code outside of the if statement:
if(e.getSource()==YesButton)
{
DisplayText = "Word added to Anadrome list.";
Test_Anadrome.setText(DisplayText);
}
if(e.getSource()==NoButton)
{
DisplayText = "Type a different word and press the 'Test Word' Button.";
Test_Anadrome.setText(DisplayText);
}
You need to have all your testing at the same level. The nested ifs are causing problems. And remember to use if/else. No sense in continuing to do other checks if the previous one succeeds.
You can also set the ActionCommand which is a String. For components that use the actionListener, you can do for example button.setActionCommand("mycommand").
Then in the actionPerformed(ActionEvent e) you can do
String cmd = e.getActionCommand();
That allows you do discern between buttons or other components without having direct access to their instance.
If you don't set the ActionCommand it defaults to the button's text.
I'm creating a text adventure and I need to completely disable the mouse cursor. Not just hide it, although I already know how to do that, but disable it completely so that you must use Alt-Tab or a built-in quit button to stop. The main reason for this is because people can scroll with the mouse cursor and I need to disable that, I thought about canceling MouseEvents when they're fired but I couldn't get it to work (the listener that is.)
If someone knows how then please speak up and tell me! :)
EDIT: Whoops, I forgot my code. Here is my Console class.
This is started by another class with new Console();
EDIT 2: Here are some snippets of me trying to create an invisible cursor and a mouse listener. The first one works, but the latter does not.
// Invisible cursor
Toolkit toolkit = Toolkit.getDefaultToolkit();
Point hotSpot = new Point(0,0);
BufferedImage cursorImage = new BufferedImage(1, 1, BufferedImage.TRANSLUCENT);
Cursor invisibleCursor = toolkit.createCustomCursor(cursorImage, hotSpot, "InvisibleCursor");
frame.setCursor(invisibleCursor);
// Adding mouse listener
frame.addMouseListener(new MouseAdapter() {
public void mousePressed(MouseEvent me) {
System.out.println(me);
}
});
EDIT 3: To elaborate on the mouse listener it simply does not work. It doesn't print anything.
If you just want to prevent users from seeing old text, remove the old text from the JTextArea.
The easiest way to do it is to leave the JTextArea in a JScrollPane, and keep track of the lines yourself:
private static final int MAX_VISIBLE_LINES = 12;
private final Deque<String> lines = new LinkedList<>();
void appendLine(String line,
JTextArea textArea) {
lines.addLast(line);
if (lines.size() > MAX_VISIBLE_LINES) {
lines.removeFirst();
}
String text = String.join("\n", lines);
textArea.setText(text);
textArea.setCaretPosition(text.length());
try {
textArea.scrollRectToVisible(
textArea.modelToView(text.length()));
} catch (BadLocationException e) {
throw new RuntimeException(e);
}
}
Trying to commandeer the mouse on a multitasking desktop is just going to make users angry. Would you want an application preventing you from reading your e-mail?
Update:
If you want to base the number of lines of text on the JTextArea’s current height, use the JTextArea’s font metrics. I assume you don’t need to get it exactly right and it’s okay if the number is off by one or two lines. (To account for things like line wrapping would be considerably more difficult.)
private final Deque<String> lines = new LinkedList<>();
void appendLine(String line,
JTextArea textArea) {
FontMetrics metrics = textArea.getFontMetrics(textArea.getFont());
JViewport viewport = (JViewport) textArea.getParent();
int visibleLineCount = viewport.getExtentSize().height / metrics.getHeight();
lines.addLast(line);
while (lines.size() > visibleLineCount) {
lines.removeFirst();
}
String text = String.join("\n", lines);
textArea.setText(text);
textArea.setCaretPosition(text.length());
try {
textArea.scrollRectToVisible(
textArea.modelToView(text.length()));
} catch (BadLocationException e) {
throw new RuntimeException(e);
}
}
I have a Java SWT GUI that I've built using Eclipse. I'm using a while loop to reference a text file. The while loop iterates through each line of the text file and builds a series of combo or text boxes for specific items on each line. Each line represents one visual column in the GUI and, depending on how many items I have in the text file, the GUI builds to the right. For simplicity's sake I am including just the code that I am trying to figure out.
For instance, assume I have three lines that create six combo boxes in the GUI (three columns by two rows). I would like a change on the top row in the second column to execute a Listener on the bottom row, also in the second column. However, right now the Listener loops through all of the combo's and makes a change to all three, not just the one I want. I can't figure out how to make this work. See the code below. I appreciate the help.
private void buildMultipleSatPulldowns() {
try {
FileReader fr = new FileReader("MultipleSatellites.txt");
BufferedReader br = new BufferedReader(fr);
String line = null;
String[] tempS;
String constellation = null;
String satellite = null;
while ((line = br.readLine()) != null) {
tempS = line.split("~");
constellation = tempS[4];
satellite = tempS[6];
constNameCombo = new Combo(satellitesComposite2, SWT.NONE);
constNameCombo.setToolTipText("Pulldown constellation name");
constNameCombo.setBounds(startX + x2, 71, 125, 28);
constNameCombo.setItems(constNameArray);
constNameCombo.setText(constellation);
constNameCombos.add(constNameCombo);
constNameCombo.addModifyListener(new ModifyListener() { // captures changed combo values
public void modifyText(ModifyEvent arg0) {
setConstellationPD();
}
});
sPullDown(constellation); // builds the satellite array for the constellation and populates each pulldown
satNameCombo = new Combo(satellitesComposite2, SWT.NONE);
satNameCombo.setToolTipText("Pulldown satellite name");
satNameCombo.setBounds(startX + x2, 106, 125, 28);
satNameCombo.setItems(satNameArray);
satNameCombo.setText(satellite);
satNameCombos.add(satNameCombo);
startX = startX + nextX;
}
br.close();
} catch (Exception ex) {
ex.printStackTrace();
}
}
private void setConstellationPD() {
int constellations = 0;
for (Combo constNameCombo : constNameCombos) {
// What do I do here so that only the desired satNameCombo changes to reflect the desired pull down?
setSatellitesPD(constellations, constNameCombo)
constellations++;
}
}
private void setSatellitesPD(int c, String cN) {
int satellites = 0;
for (Combo satNameCombo : satNameCombos) {
if (c == satellites) {
satNameCombo.setText(satNameCombos.get(satellites).toString());
satNameCombo.removeAll();
sPullDown(cN);
satNameCombo.setText("select Satellite");
}
satellites++;
}
}
private void sPullDown(String cName) {
// sPullDown takes the constellation name and returns a String Array of all objects in the constellation. This code works correctly when called.
}
If I understood correctly, you need a way to know which combo fired the event in order to affect some other components.
SWT events like ModifyEvent have the method getSource() which will return the object on which the event occurred.
Having that you just need to properly identify it; for example you could simply use constNameCombos.indexOf(eventCombo) to retrieve its index.
Or, more efficiently, you could attach some data to your combos with the method setData and retrieve it inside the event with getData, for example inside the loop:
// "i" would be the index of the combo
constNameCombo.setData("index", i);
i++;
and in the event:
Combo eventCombo = (Combo) arg0.getSource();
int index = eventCombo.getData("index");
With these information you should be able to identify the other components that you want to change.
So I have been having some trouble trying to create a teletype effect for my swing program. I essentially want to update a JFrame at 40ms increments with a new letter, "typing" out a message to the user. However, it flickers a lot when I try to do this. The method is below:
public static void animateTeletype(String input, JTextArea displayArea)
throws InterruptedException {
displayArea.setText("");
String s = "";
for(int i = 0; i<input.length(); i++) {
s += input.substring(i, i+1);
displayArea.setText(textToDisplay);
Thread.sleep(40);
displayArea.update(displayArea.getGraphics());
}
}
I figure the problem stems from updating the text too fast, and it has to update more than it can handle. I am not sure how I would go about this issue, as reducing tick time will make text scroll too slowly. Any advice is appreciated!
** I've solved the problem. This is my new code:
static Timer timer = null;
public static void animateTeletype(final String input, final JTextArea displayArea) throws InterruptedException
{
final String[] s = new String[1];
s[0] = " ";
final int[] i = new int[1];
i[0] = 0;
displayArea.setText("");
timer = new Timer(30, new ActionListener()
{
#Override
public void actionPerformed(ActionEvent e)
{
s[0] = input.substring(i[0], i[0]+1);
i[0]++;
displayArea.append(s[0]);
if(displayArea.getText().equals(input))
timer.stop();
}
});
timer.start();
}
displayArea.update(displayArea.getGraphics());
Don't use the update() method. There is never any reason to do that. Get rid of that statement.
Swing components will automatically repaint themselves.
displayArea.setText(textToDisplay);
Don't uset setText(...) to add new text.
Instead you should be using:
displayArea.append( "some more text" );
Don't use Thread.sleep(40) for animation. It you want animation then use a Swing Timer to schedule the animation.
I suggest you look at other section of the tutorial for Swing basics. Maybe something like How to Use Text Fields.