Java Keypress Generator

The following is a keypress generator using the Robot class in Java. If you provide a string to the constructor and call the simulate() method, each of the characters in the string is generated as a keypress event. In other words, the program simulates the pressing of a key on physical keyboard. This may be used to redirect input to another window.

Usage

java Typer [options] [string] [string] [...]

Options
--delay Sets the processing interval between strings in milliseconds [default: 0 (0 milliseconds)]

[string] represents the set of characters used to generate keypress events; multiple strings may be passed when separated by a space.

Example

The following illustrates the code being compiled and executed using the sample input “test1”, “test2”, “test3” and “test4”. Each keypress event is delayed by 2 seconds (2000 milliseconds). The program is executed and I immediately (manually) move the window focus to the Notepad window. As the program executes, the generated keypress events are received in Notepad because that is the window with active focus.

Executing the Java Keypress Generator
Executing the Keypress Generator

Source Code

import java.awt.Robot;
import java.awt.event.KeyEvent;
public class Typer {
  private Robot robot = null;
  private String characters = null;
  private int iDelay = 0;
  public static void main(String[] args) {
    Typer typerBot = null;
    int iDelay = 0;
    boolean bDelayArg = false;
    for(String s: args) {
      if(bDelayArg) {
        bDelayArg = false;
        try {
          iDelay = Integer.parseInt(s);
          if(iDelay < 0) {
            throw new NumberFormatException("Negative Integer");
          }
        } catch (NumberFormatException e) {
          System.out.println("Error: Delay must be a positive integer in milliseconds.");
          System.exit(1);
        }
      }
      if(s.equalsIgnoreCase("--delay")) {
        bDelayArg = true;
      }
    }
    bDelayArg = false;
    for(String s: args) {
      if(s.equalsIgnoreCase("--delay")) {
        bDelayArg = true;
      } else {
        if(!bDelayArg) {
          System.out.println("Initiating simulation for string: "+s);
          typerBot = new Typer(s, iDelay);
          typerBot.delay();
          typerBot.simulate();
          System.out.println("");
        } else {
          bDelayArg = false;
        }
      }
    }
 
    return;
  }
  public Typer(String characters) {
    if((characters == null) || ("").equals(characters.trim())) {
      characters = "";
    }
    this.characters = characters;
    try {
      robot = new Robot();
    } catch(Exception e) {
    }
    return;
  }
  public Typer(String characters, int iDelay) {
    if((characters == null) || ("").equals(characters.trim())) {
      characters = "";
    }
    this.characters = characters;
    this.iDelay = iDelay;
    try {
      robot = new Robot();
    } catch(Exception e) {
    }
    return;
  }
  public String getCharacters() {
    return characters;
  }
  protected boolean delay() {
    if(this.robot != null) {
      robot.delay(this.iDelay);
      return true;
    }
    return false;
  }
  protected boolean delay(int iDelay) {
    if(this.robot != null) {
      robot.delay(iDelay);
      return true;
    }
    return false;
  }
  private int getKeyCode(char c) {
    int iKeyCode = 0;
    try {
      iKeyCode = KeyEvent.getExtendedKeyCodeForChar(c);
    } catch(Exception e) {
    }
  
    return iKeyCode;
  }
  public boolean simulate() {
    int iKeyCode = 0;
    if(robot == null) {
      return false;
    }
    for(int i = 0; i < this.getCharacters().length(); i++) {
      iKeyCode = getKeyCode(this.getCharacters().charAt(i));
      robot.keyPress(iKeyCode);
      robot.keyRelease(iKeyCode);
    }
    robot.keyPress(KeyEvent.VK_ENTER);
    robot.keyRelease(KeyEvent.VK_ENTER);
    return true;
  }
}

Windows Utility to Keep PC Awake and Prevent Sleep

Since I consolidate and backup the photos from all of the devices in my family, I end up with a lot of duplicate files as these photos get shared between people and devices. As part of my backup process, I run de-duplication software across the files to reduce my backup storage needs. This de-duplication process usually takes over 12+ hours to run as it attempts fuzzy/visual matching across 50,000+ files (it’s an older PC).

So, why do I need this utility? Just change the sleep setting to “Never” and the PC will stay awake. Well, the Power & Sleep settings are locked by the Administrator and the PC is set to sleep after 15 minutes. Okay — just sit at the PC and move the mouse every few minutes for 12+ hours? No, thank you.

This Windows utility, which is written in C++, simulates a keypress at a defined interval of time. The keypress event resets the internal Windows idle clock which bypasses the Power & Sleep settings. I’ve programmed the utility to simulate a Win+F14 keypress since that combination is typically unused. There are many variations of this type of utility available, but I wanted to write one myself to meet my exact needs.

While the de-duplication software executes, this utility runs in the background and prevents the PC from going to sleep.

Usage

awake.exe [options]

Options:
 --interval Sets the keypress interval in seconds [default: 300 (5 minutes)]
 --freq Sets the frequency to check idle time in seconds [default: 1 (1 second)]
 --nodisplay Hides the console window
 --settings Displays the current settings at runtime
 --help Displays usage information 

Examples

On the Windows taskbar, I’ve pinned a shortcut to the utility with my preferred options present.

awake.exe --nodisplay

This launches the utility and immediately hides the console window so that the utility isn’t visible (nodisplay). All other options are set to their default values. The utility continues running in the background until the machine is powered down or the application is terminated in the Task Manager.

awake.exe --nodisplay --interval 60

This example behaves the same as the prior example except the interval is reduced to 30 seconds. If the machine is set to sleep after 1 minute in the Power & Sleep settings, this option causes the utility to reset the idle clock every 30 seconds in order to keep the machine awake. The interval option should always be set to a value less than the Sleep setting in Power & Sleep settings.

Source Code

I’ve compiled the code (C++) in Visual Studio 2019 and tested on a Windows 10 machine.

#include <windows.h>
#include <iostream>

using namespace std;

void simulate_win_d_keypress() {
    INPUT simulated_user_input[4];
    ZeroMemory(simulated_user_input, sizeof(simulated_user_input));

    simulated_user_input[0].type = INPUT_KEYBOARD;
    simulated_user_input[0].ki.wVk = VK_LWIN;

    simulated_user_input[1].type = INPUT_KEYBOARD;
    simulated_user_input[1].ki.wVk = VK_F14;

    simulated_user_input[2].type = INPUT_KEYBOARD;
    simulated_user_input[2].ki.wVk = VK_F14;
    simulated_user_input[2].ki.dwFlags = KEYEVENTF_KEYUP;

    simulated_user_input[3].type = INPUT_KEYBOARD;
    simulated_user_input[3].ki.wVk = VK_LWIN;
    simulated_user_input[3].ki.dwFlags = KEYEVENTF_KEYUP;

    SendInput(ARRAYSIZE(simulated_user_input), simulated_user_input, sizeof(INPUT));
}

int main(int argc, char* argv[]) {
    LASTINPUTINFO last_user_input;
    ULONGLONG idle_time = 0;
    unsigned int idle_threshold_milliseconds = 1000 * 5;
    unsigned int frequency_check_milliseconds = 1000;
    int user_arg_idle_threshold_seconds = 0;
    int user_arg_frequency_check_seconds = 0;
    bool b_show_settings = false;
    bool b_hide_console = false;
    bool b_arg_issue = false;

    last_user_input.cbSize = sizeof(last_user_input);

    for (int i_argv_iterator = 1; i_argv_iterator < argc; i_argv_iterator++) {
        if (string(argv[i_argv_iterator]) == "--interval") {
            if ((i_argv_iterator + 1) < argc) {
                user_arg_idle_threshold_seconds = atoi(argv[i_argv_iterator + 1]);

                if (user_arg_idle_threshold_seconds <= 0) {
                    b_arg_issue = true;
                }
                else {
                    idle_threshold_milliseconds = user_arg_idle_threshold_seconds * 1000;
                }

                i_argv_iterator++;
            }
            else {
                b_arg_issue = true;
            }
        }
        else if (string(argv[i_argv_iterator]) == "--freq") {
            if ((i_argv_iterator + 1) < argc) {
                user_arg_frequency_check_seconds = atoi(argv[i_argv_iterator + 1]);

                if (user_arg_frequency_check_seconds <= 0) {
                    b_arg_issue = true;
                }
                else {
                    frequency_check_milliseconds = user_arg_frequency_check_seconds * 1000;
                }

                i_argv_iterator++;
            }
            else {
                b_arg_issue = true;
            }
        }
        else if (string(argv[i_argv_iterator]) == "--settings") {
            b_show_settings = true;
        }
        else if (string(argv[i_argv_iterator]) == "--nodisplay") {
            b_hide_console = true;
        }
        else if (string(argv[i_argv_iterator]) == "--help") {
            b_arg_issue = true;
        }
        else {
            b_arg_issue = true;
        }
    }

    if (b_arg_issue) {
        cout << "Usage:\n";
        cout << "  awake.exe [options]\n\n";
        cout << "Options:\n";
        cout << "  --interval <integer>  Sets the keypress interval in seconds [default: 300 (5 minutes)]\n";
        cout << "  --freq <integer>      Sets the frequency to check idle time in seconds [default: 1 (1 second)]\n";
        cout << "  --nodisplay           Hides the console window\n";
        cout << "  --settings            Displays the current settings at runtime\n";
        cout << "  --help                Displays usage information\n";

        return 1;
    }

    if (b_show_settings) {
        cout << "Interval set to ";
        cout << (idle_threshold_milliseconds / 1000);
        cout << " second";
        cout << (((idle_threshold_milliseconds / 1000) > 1) ? "s" : "");
        cout << " with idle check every ";
        cout << (frequency_check_milliseconds / 1000);
        cout << " second";
        cout << (((frequency_check_milliseconds / 1000) > 1) ? "s" : "");
        cout << ".\n";
    }

    if (b_hide_console) {
        FreeConsole();
    }

    SetThreadExecutionState(ES_CONTINUOUS | ES_SYSTEM_REQUIRED | ES_AWAYMODE_REQUIRED);

    for (;;) {
        if (!GetLastInputInfo(&last_user_input)) {
            return 1;
        }

        idle_time = GetTickCount64() - last_user_input.dwTime;

        if (idle_time >= idle_threshold_milliseconds) {
            simulate_win_d_keypress();
        }
        Sleep(frequency_check_milliseconds);
    }
}

Display the File Last Updated Date Using jQuery in SharePoint

In this example, assume there is a dashboard page on a SharePoint site that displays a number of graphs and charts. This dashboard is based on data contained in a single file located in a document library on the same site. Whenever this file is updated, the last modified date of the file needs to be automatically reflected on the dashboard page. This allows the page viewer to know the freshness of the dashboard data without requiring the content owner to edit the dashboard page itself with every data change. The following code will display the file last updated date using jQuery, the SharePoint Client Object Model (sp.js), and a bit of HTML. The formatDate function is used to format the file last modified timestamp in dd-mon-yyyy format.

Add a Content Editor Web Part to the dashboard page and include the following script in the source (or as a reference to a script file).

Change the FileUrl variable in getFileInfo() to the appropriate file path. When the code executes, it will replace the contents of the “data_last_update_date” container with the formatted last modified timestamp.

Source Code

<script src="http://code.jquery.com/jquery-latest.min.js"></script>

<script language='javascript'>
  function getFileInfo() {
    var clientContext = SP.ClientContext.get_current();
    var web = clientContext.get_web();
    var FileUrl = '/path/to/file.txt';
    var file = web.getFileByServerRelativeUrl(FileUrl);

    clientContext.load(file);

    clientContext.executeQueryAsync(
      function() {
        $('#data_last_update_date').html("Data Last Updated: " + formatDate(file.get_timeLastModified()));
      },
      function(sender, args) {
        console.log('Function getFileInfo() failed: ' + args.get_message());
      }
    );
  }

  function formatDate(timestamp) {
    var month_names = new Array("Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec");
    var pad = "00";

    if(timestamp) {
      var d = new Date(timestamp);

      return (pad + d.getDate()).slice(-pad.length) + "-" + month_names[d.getMonth()] + "-" + d.getFullYear();
    }
  }

  $(document).ready(function() {
    ExecuteOrDelayUntilScriptLoaded(getFileInfo, "sp.js");
  });
</script>

<p> </p>
<div id='data_last_update_date' style='text-align:center; width:100%;'></div>