-
Notifications
You must be signed in to change notification settings - Fork 61
Konkr button profiles #331
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
b3n0b1
wants to merge
5
commits into
hhd-dev:master
Choose a base branch
from
b3n0b1:konkr-button-profiles
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
+391
−13
Open
Changes from all commits
Commits
Show all changes
5 commits
Select commit
Hold shift + click to select a range
ce250f3
add Konkr Fit (AYANEO sub-brand) controller support
b3n0b1 5a22c00
konkr fit: quad paddles + map BTN_MODE to guide
b3n0b1 7946130
konkr fit: per-button remap UI for the six system buttons
b3n0b1 ae82a3a
konkr fit: add HHD Overlay / HHD Side Menu button actions
b3n0b1 338a595
konkr fit: use official action names; hide Aya Button Map
b3n0b1 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -515,6 +515,83 @@ def produce(self, fds: Sequence[int]) -> Sequence[Event]: | |
| return out | ||
|
|
||
|
|
||
| class ChordGamepadEvdev(GenericGamepadEvdev): | ||
| """A key-only ``GenericGamepadEvdev`` where a single physical key resolves | ||
| to one of two actions depending on whether a modifier key is held when it | ||
| is pressed. | ||
|
|
||
| Used by the AYANEO Konkr, whose right-top and konkr (right-bottom-left) | ||
| buttons both emit ``KEY_F23`` -- the right-top button just also holds Ctrl. | ||
| The resolved action is latched on press so the release matches even if the | ||
| modifier is released first. Pass ``mod_btn``/``plain_btn`` as ``None`` to | ||
| leave that combination unmapped. Every other key uses the normal btn_map. | ||
| """ | ||
|
|
||
| def __init__( | ||
| self, | ||
| *args, | ||
| mod_code: int, | ||
| plain_code: int, | ||
| mod_btn: Button | None, | ||
| plain_btn: Button | None, | ||
| **kwargs, | ||
| ) -> None: | ||
| super().__init__(*args, **kwargs) | ||
| self.mod_code = mod_code | ||
| self.plain_code = plain_code | ||
| self.mod_btn = mod_btn | ||
| self.plain_btn = plain_btn | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This belongs on the ayaneo file. Avoid modifying this file |
||
| self.mod_held = False | ||
| self.chord_active: Button | None = None | ||
|
|
||
| def produce(self, fds: Sequence[int]) -> Sequence[Event]: | ||
| if not self.dev or self.fd not in fds: | ||
| return [] | ||
|
|
||
| out: list[Event] = [] | ||
| while can_read(self.fd): | ||
| for e in self.dev.read(): | ||
| if e.type != B("EV_KEY"): | ||
| continue | ||
| if e.code == self.mod_code: | ||
| # Track the modifier but never emit it directly. | ||
| self.mod_held = e.value != 0 | ||
| continue | ||
| if e.code == self.plain_code: | ||
| if e.value == 1: | ||
| self.chord_active = ( | ||
| self.mod_btn if self.mod_held else self.plain_btn | ||
| ) | ||
| if self.chord_active is not None: | ||
| out.append( | ||
| { | ||
| "type": "button", | ||
| "code": self.chord_active, | ||
| "value": True, | ||
| } | ||
| ) | ||
| elif e.value == 0: | ||
| if self.chord_active is not None: | ||
| out.append( | ||
| { | ||
| "type": "button", | ||
| "code": self.chord_active, | ||
| "value": False, | ||
| } | ||
| ) | ||
| self.chord_active = None | ||
| continue | ||
| if e.code in self.btn_map and e.value in (0, 1): | ||
| out.append( | ||
| { | ||
| "type": "button", | ||
| "code": self.btn_map[e.code], | ||
| "value": bool(e.value), | ||
| } | ||
| ) | ||
| return out | ||
|
|
||
|
|
||
| _kbd_raw: dict[KeyboardButton, Sequence[int]] = { | ||
| "key_esc": [B("KEY_ESC")], # 1 | ||
| "key_enter": [B("KEY_ENTER")], # 28 | ||
|
|
@@ -687,4 +764,11 @@ def produce(self, fds: Sequence[int]) -> Sequence[Event]: | |
|
|
||
| KEYBOARD_MAP: dict[int, KeyboardButton] = to_map(_kbd_raw) | ||
|
|
||
| __all__ = ["GenericGamepadEvdev", "XBOX_BUTTON_MAP", "XBOX_AXIS_MAP", "B", "to_map"] | ||
| __all__ = [ | ||
| "GenericGamepadEvdev", | ||
| "ChordGamepadEvdev", | ||
| "XBOX_BUTTON_MAP", | ||
| "XBOX_AXIS_MAP", | ||
| "B", | ||
| "to_map", | ||
| ] | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,127 @@ | ||
| # AYANEO Konkr Fit (HX470) — controller notes | ||
|
|
||
| Reference for the Konkr Fit's controller hardware and how HHD maps it. Keep | ||
| this in sync if the firmware or mappings change. | ||
|
|
||
| ## Identification | ||
|
|
||
| - DMI `product_name` = `KONKR FIT` (matched in `const.py` → `CONFS`). | ||
| - Konkr is an AYANEO sub-brand; the controller hardware is the **same as the | ||
| AYANEO 3**: | ||
| - `1c4f:0002` — AYANEO COMPOSITE DEVICE (`AYA_VID`/`AYA_PID`). Carries the | ||
| extra buttons and the right-side system buttons as keyboard keys. | ||
| - `045e:028e` — Xbox-style gamepad (`GAMEPAD_VID`/`GAMEPAD_PID`). Carries the | ||
| sticks, triggers, ABXY, d-pad, and the three left-side system buttons. | ||
| - Unlike the AYANEO 3 it has **no detachable modules** (no `ayaneo-ec` EC | ||
| sysfs interface), so `magic_modules` is off. | ||
|
|
||
| ## Physical button layout | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. drop the md file |
||
|
|
||
| Six "system / face" buttons surround the screen, plus four extra buttons | ||
| (two rear paddles + two LC/RC buttons). Looking at the device face-on: | ||
|
|
||
| ``` | ||
| LEFT module RIGHT module | ||
| [ left-top ] [ right-top ] | ||
| [ L-sel ][ L-start ] [ konkr ][ R-bottom ] | ||
| ``` | ||
|
|
||
| - **LC / RC** = the two inner buttons under each grip. | ||
| - **rear-left / rear-right** = the two back paddles. | ||
|
|
||
| ## Raw evdev codes (captured on-device) | ||
|
|
||
| | # | Physical button | Device | Sends (evdev) | | ||
| |---|-----------------------|------------------|--------------------------| | ||
| | 1 | left-top | gamepad (028e) | `BTN_MODE` (316) | | ||
| | 2 | left-bottom-left | gamepad (028e) | `BTN_SELECT` (314) | | ||
| | 3 | left-bottom-right | gamepad (028e) | `BTN_START` (315) | | ||
| | 4 | right-top | composite (0002) | `Ctrl` (29) + `F23` (193)| | ||
| | 5 | konkr (right-btm-left)| composite (0002) | `F23` (193) alone | | ||
| | 6 | right-bottom-right | composite (0002) | `Meta` (125) + `D` (32) | | ||
| | - | LC | composite (0002) | `F21` (191) | | ||
| | - | RC | composite (0002) | `F22` (192) | | ||
| | - | rear-left paddle | composite (0002) | `KEY_L` (38) | | ||
| | - | rear-right paddle | composite (0002) | `KEY_R` (19) | | ||
|
|
||
| > **Important gotcha:** right-top (#4) and konkr (#5) emit the **same** key | ||
| > (`F23`). right-top just also holds `Ctrl`. A plain one-code → one-action map | ||
| > can't tell them apart — see the chord handling below. | ||
|
|
||
| ## How HHD maps them | ||
|
|
||
| ### Extra buttons (LC/RC + rear paddles) | ||
| `extra_buttons: "quad"`. These map to `extra_l1/l2/r1/r2` and are exposed as | ||
| DualSense Edge / Xbox Elite back paddles — remappable in **Steam Input**: | ||
|
|
||
| | Button | evdev | Output | | ||
| |------------|---------|------------| | ||
| | rear-left | `KEY_L` | `extra_l1` | | ||
| | rear-right | `KEY_R` | `extra_r1` | | ||
| | LC | `F21` | `extra_l2` | | ||
| | RC | `F22` | `extra_r2` | | ||
|
|
||
| ### The six system/face buttons — "Konkr Button Map" | ||
| Enabled by the `face_remap` flag in `const.py`. Each button gets a dropdown | ||
| (`konkr_buttons.yml`, injected in `__init__.py:settings()`), applied in | ||
| `base.py`. Values/labels mirror `plugins/overlay/shortcuts.yml` (HHD's | ||
| official vocabulary): | ||
|
|
||
| | Dropdown value | Label | Result | | ||
| |------------------|-----------------|--------| | ||
| | `disabled` | Disabled | Button does nothing | | ||
| | `mode` | Steam / Guide | Opens Steam (guide button) | | ||
| | `select` | Select (View) | gamepad Select/View | | ||
| | `start` | Start (Menu) | gamepad Start/Menu | | ||
| | `steam_qam` | Steam Side Menu | Opens Steam's own QAM | | ||
| | `steam_expanded` | Steam Overlay | Opens Steam's expanded menu | | ||
| | `hhd_qam` | HHD Side Menu | Opens the HHD QAM side menu (`open_qam`) | | ||
| | `hhd_expanded` | HHD Overlay | Opens the expanded HHD overlay (`open_expanded`) | | ||
|
|
||
| `mode`/`select`/`start` are plain gamepad buttons. The four menu actions are | ||
| not real gamepad buttons -- they are sentinel codes handled in | ||
| `controller/base.py` (the multiplexer), which clears the code so it never | ||
| reaches the virtual controller: | ||
|
|
||
| - `hhd_qam` -> emits `special` event `overlay` -> `open_qam` (HHD side menu). | ||
| - `hhd_expanded` -> emits `special` event `qam_triple` -> `open_expanded`. | ||
| Both bypass the multi-tap QAM state machine, so they are deterministic. | ||
| - `steam_qam` / `steam_expanded` -> set `send_steam_qam` / `send_steam_expand`, | ||
| so the multiplexer opens Steam's menu through the normal Steam path at the | ||
| end of `process()` (intercept-aware, with the guide+A chord fallback if | ||
| gamescope isn't handling it). | ||
|
|
||
| > The standard **Aya Button Map** (`swap_guide`) dropdown is hidden on the | ||
| > Konkr (removed in `__init__.py:settings()`), since this per-button map | ||
| > supersedes it. With it gone, `base.py` falls back to `swap_guide="oem"` | ||
| > (no swap), which is correct for the custom map. | ||
|
|
||
| | Dropdown key | Physical button | Source code | Default | | ||
| |--------------------|-------------------|----------------|------------| | ||
| | `btn_left_top` | left-top | `BTN_MODE` | `mode` | | ||
| | `btn_left_select` | left-bottom-left | `BTN_SELECT` | `select` | | ||
| | `btn_left_start` | left-bottom-right | `BTN_START` | `start` | | ||
| | `btn_right_top` | right-top | `Ctrl`+`F23` | `disabled` | | ||
| | `btn_konkr` | konkr | `F23` | `disabled` | | ||
| | `btn_right_bottom` | right-bottom-right| `KEY_D` | `share` | | ||
|
|
||
| - Left-side three go through the gamepad: `base.py` overrides | ||
| `XBOX_BUTTON_MAP` for `BTN_MODE/SELECT/START`; `disabled` drops the key. | ||
| - Right-side three go through the composite keyboard: | ||
| - `KEY_D` → `btn_right_bottom`. | ||
| - `F23` is split by **`ChordGamepadEvdev`** (`evdev.py`): if `Ctrl` is held | ||
| it resolves to `btn_right_top`, otherwise `btn_konkr`. The action is | ||
| **latched on press** so the release matches even if `Ctrl` is let go | ||
| first (prevents stuck buttons). | ||
|
|
||
| Defaults reproduce the pre-remap behavior, so existing users see no change | ||
| until they touch a dropdown. Everything is gated on `face_remap`, so the | ||
| AYANEO 3's identical gamepad buttons are never affected. | ||
|
|
||
| ## Files | ||
|
|
||
| - `const.py` — `CONFS["KONKR FIT"]` device entry + flags. | ||
| - `konkr_buttons.yml` — the six dropdowns (UI schema). | ||
| - `__init__.py` — injects the schema when `face_remap` is set. | ||
| - `base.py` — reads the dropdowns and builds the evdev button maps. | ||
| - `../../controller/physical/evdev.py` — `ChordGamepadEvdev`. | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we need to figure out how to do shortcuts for extra extra buttons in a unified way. The legion go 2 needs this as well