{"record":{"id":"6c1f79218f5dde97","repo":"m1k1o/neko","slug":"debounced-button-v","errorCode":null,"errorMessage":"debounced button %v","messagePattern":"debounced button (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"info","filePath":"server/pkg/xorg/xorg.go","lineNumber":109,"sourceCode":"\nfunc Scroll(deltaX, deltaY int, controlKey bool) {\n\tmu.Lock()\n\tdefer mu.Unlock()\n\n\tif controlKey {\n\t\tC.XSetKeyboardModifier(C.uchar(C.ControlMask), 1)\n\t\tdefer C.XSetKeyboardModifier(C.uchar(C.ControlMask), 0)\n\t}\n\n\tC.XScroll(C.int(deltaX), C.int(deltaY))\n}\n\nfunc ButtonDown(code uint32) error {\n\tmu.Lock()\n\tdefer mu.Unlock()\n\n\tif _, ok := debounce_button[code]; ok {\n\t\treturn fmt.Errorf(\"debounced button %v\", code)\n\t}\n\n\tdebounce_button[code] = time.Now()\n\n\tC.XButton(C.uint(code), C.int(1))\n\treturn nil\n}\n\nfunc KeyDown(code uint32) error {\n\tmu.Lock()\n\tdefer mu.Unlock()\n\n\tif _, ok := debounce_key[code]; ok {\n\t\treturn fmt.Errorf(\"debounced key %v\", code)\n\t}\n\n\tdebounce_key[code] = time.Now()\n","sourceCodeStart":91,"sourceCodeEnd":127,"githubUrl":"https://github.com/m1k1o/neko/blob/b0f01cedea68893e85a3fd852c0521238c285695/server/pkg/xorg/xorg.go#L91-L127","documentation":"ButtonDown injects an X11 button press but debounces repeated presses: if the same button code was pressed too recently (present in debounce_button), the call is refused with 'debounced button %v'. This prevents duplicate press events from rapid retransmission. It is an intentional rate-limit rejection, not a hardware failure.","triggerScenarios":"Calling ButtonDown(code) twice in quick succession without an intervening ButtonUp(code); ButtonPress dispatching a code already held down.","commonSituations":"Client autorepeat generating repeated keydown-like events for held mouse buttons; network retransmission duplicating a click event; event pipeline calling both ButtonPress and ButtonDown for the same input.","solutions":["Wait for ButtonUp(code) before issuing another ButtonDown(code)","Deduplicate press events client-side before sending (ignore repeats for a held button)","Increase the debounce window removal logic / clear debounce_button entry via ButtonUp if the state is stale","Treat this error as a benign no-op in the caller (the button is already down)"],"exampleFix":"// before\nif err := xorg.ButtonDown(btn); err != nil { log.Fatal(err) }\n// after\nif err := xorg.ButtonDown(btn); err != nil {\n    // button already down from a recent press; ignore debounce rejection\n    log.Printf(\"button %d already down: %v\", btn, err)\n}","handlingStrategy":"validation","validationCode":"// track pressed state; only press when not already pressed\nvar pressed = map[uint32]bool{}\nfunc safeButtonDown(code uint32) error {\n    if pressed[code] { return nil }\n    if err := xorg.ButtonDown(code); err != nil { return err }\n    pressed[code] = true\n    return nil\n}","typeGuard":"func isDebouncedButton(err error) bool {\n    return err != nil && strings.Contains(err.Error(), \"debounced button\")\n}","tryCatchPattern":"if err := xorg.ButtonDown(code); err != nil && !isDebouncedButton(err) {\n    return err // real failure; debounce rejection is benign\n}","preventionTips":["Only send ButtonDown when the button is not already marked down","Disable client-side autorepeat for mouse buttons","Deduplicate duplicated input events before forwarding","Always release (ButtonUp) to clear the debounce entry"],"tags":["input","debounce","mouse","x11"],"backgroundTag":"debounced-input-event","analyzedSha":"b0f01cedea68893e85a3fd852c0521238c285695","analyzedAt":"2026-09-01T10:35:56.638Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T15:18:49.778Z"}