Skip to content

Instantly share code, notes, and snippets.

@mark99i
Created July 2, 2025 11:58
Show Gist options
  • Save mark99i/ead82504a5f829a58c664e618826969d to your computer and use it in GitHub Desktop.
Save mark99i/ead82504a5f829a58c664e618826969d to your computer and use it in GitHub Desktop.
Detect click+long click+double click+holding on Android
import android.os.Handler;
import org.jetbrains.annotations.NotNull;
public class KeyDetector {
private final Handler handler = new Handler();
private final Settings settings;
private final KeyDetectedEvent listener;
public KeyDetector(@NotNull Settings settings, @NotNull KeyDetectedEvent listener) {
this.settings = settings;
this.listener = listener;
}
public static class Settings {
boolean handleClick = true;
boolean handleLongClick = false;
boolean handleDoubleClick = false;
boolean handleHolding = true;
int longClickDelayMs = 600;
int doubleClickDelayMs = 400;
int holdingDelayMs = 500;
int holdingInterval = 200;
}
public interface KeyDetectedEvent {
void onClick();
void onLongClick();
void onDoubleClick();
void onHolding();
}
private int clickCount = 0;
private boolean keyNowPressed = false;
private boolean nowIsHolding = false;
private void clearCurrentTap() {
clickCount = 0;
keyNowPressed = false;
nowIsHolding = false;
handler.removeCallbacksAndMessages(null);
}
private void notifyClickIfDoubleClickEnabled() {
if (clickCount == 0 || keyNowPressed) return;
clearCurrentTap();
listener.onClick();
}
private void handleLongClick() {
if (clickCount == 0) return;
clearCurrentTap();
listener.onLongClick();
}
private void handleHolding() {
if (!keyNowPressed) {
clearCurrentTap();
return;
}
nowIsHolding = true;
listener.onHolding();
handler.postDelayed(this::handleHolding, settings.holdingInterval);
}
public void inEventPressed() {
if (keyNowPressed) return;
keyNowPressed = true;
if (settings.handleClick && !settings.handleDoubleClick && !settings.handleLongClick && !settings.handleHolding) {
clearCurrentTap();
listener.onClick();
return;
}
if (settings.handleLongClick && clickCount == 0) {
handler.postDelayed(this::handleLongClick, settings.longClickDelayMs);
}
if (settings.handleHolding && clickCount == 0) {
if (settings.handleClick && !settings.handleDoubleClick && !settings.handleLongClick) {
listener.onClick();
}
handler.postDelayed(this::handleHolding, settings.holdingDelayMs);
}
if (settings.handleDoubleClick) {
if (clickCount == 0) {
handler.postDelayed(this::notifyClickIfDoubleClickEnabled, settings.doubleClickDelayMs);
}
if (clickCount == 1) {
clearCurrentTap();
listener.onDoubleClick();
return;
}
}
clickCount += 1;
}
public void inEventReleased() {
if (!keyNowPressed) return;
keyNowPressed = false;
if (settings.handleClick && clickCount == 1 && !settings.handleDoubleClick && !settings.handleHolding) {
clearCurrentTap();
listener.onClick();
}
if (settings.handleHolding) {
clearCurrentTap();
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment