The image behind contains

JavaScript I didn't use


I needed an image, ok?

Why does this exist? Well, I'm providing the source code as a download, so there is nothing stopping anyone from opening it and looking inside.
Might as well explain myself at that point.

Lines numbers in the code blocks on this website are almost the same as in flickspeed.java.

How it Works

flickspeed is based on the Java Swing GUI framework. I will cover the main logic of the program, then delve into framework-specific methods and workings.

Logic

Normal usage is based around the existence of a data.dat file in the same directory as the program. This file contains 4 integer values and 1 boolean value for specific configurations in the program. If this file does not exist in the directory that the program is in, the program setup will run.
Example data.dat file:
400
0.5
2
1
true

The program setup aims to get these 5 values and saves them into a new data.dat file.
On a normal, non-setup start, flickspeed will read the values from the data.dat file and store them into global variables, namely:
static double DPI;
static double NOTIFY_SPEED;
static int NOTIFY_TIMER;
static int CONVERSION;
static boolean PERSISTENT_OVERLAY;

DPI is the inputted mouse dpi, used for calculation of speed.
NOTIFY_SPEED is the speed which is needed to trigger the flick! window appearing.
NOTIFY_TIMER is the amount of time that the flick! notification pauses the thread and stays on-screen.
CONVERSION is a constant that dictates the type of conversion that is performed on the raw speed taken from the display.
PERSISTENT_OVERLAY dictates whether the persistent overlay starts when launching the program.

After receiving these values, flickspeed will run the main program loop, which:
  1. Defines relevant variables
  2. Determines if the persistent overlay is enabled
    • If yes, then creates and displays the overlay
  3. Creates the system tray icon and menu
  4. Loops the following:
    1. Calculates the speed of the mouse in pixels/100ms
      public static double calculateSpeed(double dpi) {
          Point p = MouseInfo.getPointerInfo().getLocation();
          try {
              TimeUnit.MILLISECONDS.sleep(200);
          }
          catch (InterruptedException e) { Thread.currentThread().interrupt();}
          Point n = MouseInfo.getPointerInfo().getLocation();
      
          return Math.abs(n.distance(p));
      }
    2. Determines and uses the correct formula to translate to the right units
    3. Updates the persistent overlay (if applicable)
    4. Determines whether the calculated speed is over the defined threshold
      • If so, creates the flick! frame.

I/O


A java.io.File object is created on launch to check for existence of a file.
File f = new File("data.dat");
if (f.exists() && !f.isDirectory()) {}

If it does exist, a java.util.Scanner object is created to scan the file's contents.
Scanner fileScan = new Scanner(f);
String line;
for (int i = 1; i < 6; i++) {
    // Scan lines
}

The values are extracted from the file using a switch() and casted to their various types.

To write/overwrite a file, a java.nio.file.Path object is created as a placeholder for the predetermined path of the new file. It is then placed into the static method java.nio.file.Files.write(), which will write the data collected to a file. After this, the program is terminated.
Path file = Paths.get("data.dat");
Files.write(file, lines);

Swing

brace for impact.

Global variables are used to store common GUI elements, to (hopefully) avoid memory waste at runtime.
final static Color COLOR_BG = new Color(22, 32, 53, 255);
final static Font DEFAULT_FONT = new Font(FONT_NAME, Font.PLAIN, 16);
final static Font DEFAULT_FONT_SMALL = new Font(FONT_NAME, Font.PLAIN, 13);
final static Font DEFAULT_TITLE = new Font(FONT_NAME, Font.BOLD, 22);

The windows that the program creates are javax.swing.JFrame objects.

When the setup is run due to there being no data.dat file or run straight from the tray menu, a JFrame independent of the other JFrames is created. It is given a set of properties and a java.awt.LayoutManager to organize the elements in the frame.
JFrame firstRunFrame = new JFrame("flickspeed Setup");
firstRunFrame.setIconImage(new ImageIcon("res/logo.png").getImage());
firstRunFrame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
firstRunFrame.getContentPane().setMaximumSize(new Dimension(344, 379));
firstRunFrame.setResizable(false);

firstRunFrame.getContentPane().setLayout(new BorderLayout());
JPanel panel = new JPanel(new GridLayout(0, 1));
before you ask, yes, I know those dimensions are strangely specific.

A javax.swing.JPanel is created inside the frame for easier management, and then all UI elements are defined and given properties.
Example - Mouse DPI Field:
JLabel insertDPI = new JLabel("Mouse DPI:");
insertDPI.setForeground(Color.white);
insertDPI.setFont(DEFAULT_FONT);
JTextField dpiField = new JTextField();
dpiField.setBackground(COLOR_BG);
dpiField.setForeground(Color.white);
dpiField.setFont(DEFAULT_FONT_SMALL);

When the "Save and Exit" button is pressed, flickspeed checks each field of input with regex made to detect bad inputs. If a bad input is detected, an error label (previously hidden) is made visible.
if (time.matches("\\d+")) {
JLabel errorLabel1 = new JLabel("Please enter a valid number.");
errorLabel1.setVisible(false);
errorLabel1.setForeground(Color.red);
errorLabel1.setFont(DEFAULT_FONT_SMALL);
else { errorLabel1.setVisible(true);}


In the main loop, a JLabel is created to provide easier access to changing the persistent overlay.
JLabel spLb = null;
if (PERSISTENT_OVERLAY) {
    spLb = createPersistentOverlay();
updatePersistentOverlay(spLb, speed);
public static void updatePersistentOverlay(JLabel label, double speed) {
    String labelText = String.format("%.2f", speed);
    labelText += UNIT;
    label.setText(labelText);
}

Because the persistent overlay is toggle-able, the JFrame for the persistent overlay must have the ability to recreate/dispose of itself. This is accomplished by using javax.swing.SwingUtilities.getRoot(), which returns the JFrame that the provided object is in.

Creating and disposing of the persistent overlay:

Creation

spLb = createPersistentOverlay();
public static JLabel createPersistentOverlay() {
    JFrame frame = new JFrame("flickspeed Persistent Overlay");
    frame.setUndecorated(true);
    frame.setAlwaysOnTop(true);
    frame.setVisible(true);
    frame.setFocusableWindowState(false);
    frame.setAutoRequestFocus(false);

    frame.getRootPane().putClientProperty("apple.awt.draggableWindowBackground", false);

Deletion

JFrame frame = (JFrame) SwingUtilities.getRoot(spLb);
frame.dispose();

When the speed threshold is crossed, the larger flick! JFrame is created.
if (speed >= NOTIFY_SPEED) {
    createFrame(speed);
}
public static void createFrame(double speed) {
    JFrame frame = new JFrame("flickspeed");
    frame.setUndecorated(true);
    frame.setAlwaysOnTop(true);
    frame.setVisible(true);
    frame.setFocusableWindowState(false);
    frame.setAutoRequestFocus(false);

    frame.getRootPane().putClientProperty("apple.awt.draggableWindowBackground", false);

The frame is auto-deleted after the defined amount of seconds passes.
frame.pack();
frame.transferFocusBackward();

try {
    TimeUnit.SECONDS.sleep(NOTIFY_TIMER);
}
catch(InterruptedException e) { Thread.currentThread().interrupt();}

frame.setVisible(false);
frame.dispose();


The Website

There's more!?

Kidding.

Unless...

The website was made using HTML5, CSS3, JQuery, Bootstrap and Prism.js. The landing page was a journey in and of itself that I don't quite want to recall.

aaaand it's over. i'm tired asf. you can go home now.