-1

I have a java program that sends some data over the network. I also capture all the keys pressed on the client and send them to the server therefore server maintains a buffer containing all the keys pressed on the client.

I need to create a file containing the final text produced by client. Take the following sequence as an example:

press j
press h
press BACKSPACE
press H
press e
press l
press HOME
press DEL
press END
press l
press o

Processing this sequence produces:

Hello

This is a simple example but notice that it can contain arrow keys as well.

Processing this buffer can be error prone and time consuming. I'd appreciate it if anyone could introduce a library that does these things or shows a simple way for doing it.

EDIT: I changed my question to ask a specific question instead of looking for a library.

I don't want to create a console parser and no need for history or tab completion. So my question is different from readline-like library in java.

Thanks.

AKJ88
  • 713
  • 2
  • 10
  • 20
  • Possible duplicate of [readline-like library for Java](https://stackoverflow.com/questions/2828291/readline-like-library-for-java) –  Aug 26 '18 at 09:51
  • Why negative points???! – AKJ88 Aug 26 '18 at 09:56
  • Probably because it seems you did not read the [help/on-topic], nor noticed that questions asking to recommend libraries are off-topic. – RealSkeptic Aug 26 '18 at 10:11
  • About the "Why negative points" comments -- (1) it's perceived to be voting abuse at worst (as it can manipulate voting), and not needed at best (as it's not a clarification request etc.), so don't leave it. (2) generally if somebody downvote without leaving a comment then the downvote reason is already in the [help] or close reason, or the question cannot be improved. (3) if you still want to leave the comment, it would be better to phrase it in a more constructive way, or to ask on meta instead. – user202729 Aug 26 '18 at 10:59
  • About the question: Practically, people would use a library anyway. Without a library, the question is asking for too much -- there are ~100 keys on the keyboard. – user202729 Aug 26 '18 at 11:01
  • [Related](https://stackoverflow.com/questions/19614500/convert-a-list-of-keyevent-objects-to-a-string). – user202729 Aug 26 '18 at 11:08
  • How do you know when a sequence starts and a sequence ends? What do HOME/END... keys have to do with your application (they mean nothing when focus is on a button)? So, it sounds to me like you are trying to capture text typed into a text component. What if somebody types some text and then uses the mouse to select the text and then use the BACK_SPACE key all the text will be lost. Your approach of doesn't seem complete to me. – camickr Aug 26 '18 at 19:45
  • Maybe you should be using `KeyboardFocusManager`. You can use a `PropertyChangeListener` to listen for focus changes. Then maybe you add a DocumentLIstener or DocumentFilter to the text component to listen for changes in the text. Then when the component loses focus you know the sequence is complete and you can log the text. – camickr Aug 26 '18 at 19:46
  • @camickr The user cannot use the mouse but can press any keys on the keyboard and I get one key at a time, therefore I end up having a sequence of any possible key and I want the final possible text. – AKJ88 Aug 27 '18 at 09:55
  • I understand your basic requirement. You don't understand my basic concern. 1) how do you know the start/stop of a sequence? 2) Even if the user can't use the mouse they can still select all the text with the keyboard and then press Delete (for instance) which would remove all the text. You can't get the text that was removed by using a KeyLIstener. – camickr Aug 27 '18 at 14:16

2 Answers2

1

sounds like you're building a key logger. I guess this is the reason why 2 people down voted you already. Funny that I'm writing my master's degree thesis about this kind of stuff at the moment :P https://github.com/kamiljano/CloudDoorThesis My POC doesn't do any key logging though, just allows you to remotely download files from a remote device.

Anyway, judging from your input you're communicating with the server over a TCP socket. Don't! Firewall will never let you through. Stick to something more common, like HTTP. Then you can have an endpoint like http://server.com/keys and send a JSON requsts to it like

{
  "strokes": [
     "a", "b", "c", "backspace"
  ]
}

Don't upload your stuff every time the user presses a button -> that generates a lot of stress on the network. So you will generate an HTTP PUT request every 20 key strokes, or every 1 minute. Make sure that the request is done by the key logger in a separate thread, or the user will notice that it takes 0.5-2 seconds for the character to appear on the screen. Don't store the keys in the memory of the application -> you will run out of memory as soon as 10 users write a new post on Facebook. Instead store every change in a database. At that point you first write a small piece of code like

String result = "";
for (String key : strokes) {
   if ("backspace".equals(key) && result.size() > 0) {
     result = result.substring(0, result.size() - 2);
   } else if ("del".equals(key) && result.size() > 0) {
     result = result.subscring(1, result.size() - 1);
   } else {
     result += key;
   }
}
updateDatabaseEntry(userId, result);
Kamil Janowski
  • 1,872
  • 2
  • 21
  • 43
1

so there are no libraries for what you want to do. I would suggest implementing your own class that collects all the changes and builds a string one key stroke at a time. As a kickstarter for you I wrote the following class (although it obviously needs to be extended with the logic for additional keys that you want to be able to process)

public class KeyBuffer {

  private static final String SIMPLE_CHARACTERS = "abcdefghijklmopqrstuvqxyz;?!#$%^&&*()_+";//TODO: extend with all characters that the users can enter

  private String buffer = "";
  private int position = 0;

  private String[] splitAtCurrentPosition() {
    return new String[]{
      buffer.substring(0, position),
      buffer.substring(position, buffer.length() == position ? position : buffer.length())
    };
  }

  private void addCharacter(String character) {
    String[] parts = splitAtCurrentPosition();
    buffer = parts[0].substring(0, parts[0].length()) + character + parts[1];
    position++;
  }

  public void add(String key) {
    if (SIMPLE_CHARACTERS.contains(key)) {
      addCharacter(key);
      return;
    }
    if ("backspace".equals(key) && buffer.length() > 0) {
      String[] parts = splitAtCurrentPosition();
      buffer = parts[0].substring(0, parts[0].length() - 1) + parts[1];
      position --;
    } else if ("arrow_left".equals(key)) {
      if (position > 0) {
        position --;
      }
    } else {
      throw new UnsupportedOperationException("The key " + key + " is not supported");
    }

    //TODO: add logic for all remaining special keys
  }

  @Override
  public String toString() {
    return buffer;
  }
}

Quickly tested with the following junit tests:

public class KeyBufferTest {

  @Test
  public void addSimpleCharacter() {
    KeyBuffer buffer = new KeyBuffer();
    buffer.add("a");
    buffer.add("b");
    buffer.add("c");

    assertEquals("abc", buffer.toString());
  }

  @Test
  public void addUsingArrows() {
    KeyBuffer buffer = new KeyBuffer();
    buffer.add("a");
    buffer.add("b");
    buffer.add("arrow_left");
    buffer.add("c");

    assertEquals("acb", buffer.toString());
  }

  @Test
  public void addBackspace() {
    KeyBuffer buffer = new KeyBuffer();
    buffer.add("a");
    buffer.add("b");
    buffer.add("arrow_left");
    buffer.add("backspace");
    buffer.add("c");

    assertEquals("cb", buffer.toString());
  }

}
Kamil Janowski
  • 1,872
  • 2
  • 21
  • 43