Skip to content
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

Programmable Button API refactor and improve docs #18641

Merged
merged 2 commits into from
Oct 15, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
200 changes: 135 additions & 65 deletions docs/feature_programmable_button.md
Original file line number Diff line number Diff line change
@@ -1,74 +1,144 @@
## Programmable Button
# Programmable Button :id=programmable-button

Programmable button is a feature that can be used to send keys that have no
predefined meaning.
This means they can be processed on the host side by custom software without
colliding without the operating system trying to interpret these keys.
Programmable Buttons are keys that have no predefined meaning. This means they can be processed on the host side by custom software without the operating system trying to interpret them.

The keycodes are emitted according to the HID usage
"Telephony Device Page" (0x0B), "Programmable button usage" (0x07).
On Linux (> 5.14) they are handled automatically and translated to `KEY_MACRO#`
keycodes.
(Up to `KEY_MACRO30`)
The keycodes are emitted according to the HID Telephony Device page (`0x0B`), Programmable Button usage (`0x07`). On Linux (> 5.14) they are handled automatically and translated to `KEY_MACRO#` keycodes (up to `KEY_MACRO30`).

### Enabling Programmable Button support
?> Currently there is no known support in Windows or macOS. It may be possible to write a custom HID driver to receive these usages, but this is out of the scope of the QMK documentation.

To enable Programmable Button, add the following line to your keymap’s `rules.mk`:
## Usage :id=usage

```c
Add the following to your `rules.mk`:

```make
PROGRAMMABLE_BUTTON_ENABLE = yes
```

### Mapping

In your keymap you can use the following keycodes to map key presses to Programmable Buttons:

|Key |Description |
|------------------------|----------------------|
|`PROGRAMMABLE_BUTTON_1` |Programmable button 1 |
|`PROGRAMMABLE_BUTTON_2` |Programmable button 2 |
|`PROGRAMMABLE_BUTTON_3` |Programmable button 3 |
|`PROGRAMMABLE_BUTTON_4` |Programmable button 4 |
|`PROGRAMMABLE_BUTTON_5` |Programmable button 5 |
|`PROGRAMMABLE_BUTTON_6` |Programmable button 6 |
|`PROGRAMMABLE_BUTTON_7` |Programmable button 7 |
|`PROGRAMMABLE_BUTTON_8` |Programmable button 8 |
|`PROGRAMMABLE_BUTTON_9` |Programmable button 9 |
|`PROGRAMMABLE_BUTTON_10`|Programmable button 10|
|`PROGRAMMABLE_BUTTON_11`|Programmable button 11|
|`PROGRAMMABLE_BUTTON_12`|Programmable button 12|
|`PROGRAMMABLE_BUTTON_13`|Programmable button 13|
|`PROGRAMMABLE_BUTTON_14`|Programmable button 14|
|`PROGRAMMABLE_BUTTON_15`|Programmable button 15|
|`PROGRAMMABLE_BUTTON_16`|Programmable button 16|
|`PROGRAMMABLE_BUTTON_17`|Programmable button 17|
|`PROGRAMMABLE_BUTTON_18`|Programmable button 18|
|`PROGRAMMABLE_BUTTON_19`|Programmable button 19|
|`PROGRAMMABLE_BUTTON_20`|Programmable button 20|
|`PROGRAMMABLE_BUTTON_21`|Programmable button 21|
|`PROGRAMMABLE_BUTTON_22`|Programmable button 22|
|`PROGRAMMABLE_BUTTON_23`|Programmable button 23|
|`PROGRAMMABLE_BUTTON_24`|Programmable button 24|
|`PROGRAMMABLE_BUTTON_25`|Programmable button 25|
|`PROGRAMMABLE_BUTTON_26`|Programmable button 26|
|`PROGRAMMABLE_BUTTON_27`|Programmable button 27|
|`PROGRAMMABLE_BUTTON_28`|Programmable button 28|
|`PROGRAMMABLE_BUTTON_29`|Programmable button 29|
|`PROGRAMMABLE_BUTTON_30`|Programmable button 30|
|`PROGRAMMABLE_BUTTON_31`|Programmable button 31|
|`PROGRAMMABLE_BUTTON_32`|Programmable button 32|
|`PB_1` to `PB_32` |Aliases for keymaps |

### API

You can also use a dedicated API defined in `programmable_button.h` to interact with this feature:
## Keycodes :id=keycodes

```
void programmable_button_clear(void);
void programmable_button_send(void);
void programmable_button_on(uint8_t code);
void programmable_button_off(uint8_t code);
bool programmable_button_is_on(uint8_t code);
uint32_t programmable_button_get_report(void);
void programmable_button_set_report(uint32_t report);
```
|Key |Aliases|Description |
|------------------------|-------|----------------------|
|`PROGRAMMABLE_BUTTON_1` |`PB_1` |Programmable button 1 |
|`PROGRAMMABLE_BUTTON_2` |`PB_2` |Programmable button 2 |
|`PROGRAMMABLE_BUTTON_3` |`PB_3` |Programmable button 3 |
|`PROGRAMMABLE_BUTTON_4` |`PB_4` |Programmable button 4 |
|`PROGRAMMABLE_BUTTON_5` |`PB_5` |Programmable button 5 |
|`PROGRAMMABLE_BUTTON_6` |`PB_6` |Programmable button 6 |
|`PROGRAMMABLE_BUTTON_7` |`PB_7` |Programmable button 7 |
|`PROGRAMMABLE_BUTTON_8` |`PB_8` |Programmable button 8 |
|`PROGRAMMABLE_BUTTON_9` |`PB_9` |Programmable button 9 |
|`PROGRAMMABLE_BUTTON_10`|`PB_10`|Programmable button 10|
|`PROGRAMMABLE_BUTTON_11`|`PB_11`|Programmable button 11|
|`PROGRAMMABLE_BUTTON_12`|`PB_12`|Programmable button 12|
|`PROGRAMMABLE_BUTTON_13`|`PB_13`|Programmable button 13|
|`PROGRAMMABLE_BUTTON_14`|`PB_14`|Programmable button 14|
|`PROGRAMMABLE_BUTTON_15`|`PB_15`|Programmable button 15|
|`PROGRAMMABLE_BUTTON_16`|`PB_16`|Programmable button 16|
|`PROGRAMMABLE_BUTTON_17`|`PB_17`|Programmable button 17|
|`PROGRAMMABLE_BUTTON_18`|`PB_18`|Programmable button 18|
|`PROGRAMMABLE_BUTTON_19`|`PB_19`|Programmable button 19|
|`PROGRAMMABLE_BUTTON_20`|`PB_20`|Programmable button 20|
|`PROGRAMMABLE_BUTTON_21`|`PB_21`|Programmable button 21|
|`PROGRAMMABLE_BUTTON_22`|`PB_22`|Programmable button 22|
|`PROGRAMMABLE_BUTTON_23`|`PB_23`|Programmable button 23|
|`PROGRAMMABLE_BUTTON_24`|`PB_24`|Programmable button 24|
|`PROGRAMMABLE_BUTTON_25`|`PB_25`|Programmable button 25|
|`PROGRAMMABLE_BUTTON_26`|`PB_26`|Programmable button 26|
|`PROGRAMMABLE_BUTTON_27`|`PB_27`|Programmable button 27|
|`PROGRAMMABLE_BUTTON_28`|`PB_28`|Programmable button 28|
|`PROGRAMMABLE_BUTTON_29`|`PB_29`|Programmable button 29|
|`PROGRAMMABLE_BUTTON_30`|`PB_30`|Programmable button 30|
|`PROGRAMMABLE_BUTTON_31`|`PB_31`|Programmable button 31|
|`PROGRAMMABLE_BUTTON_32`|`PB_32`|Programmable button 32|

## API :id=api

### `void programmable_button_clear(void)` :id=api-programmable-button-clear

Clear the programmable button report.

---

### `void programmable_button_add(uint8_t index)` :id=api-programmable-button-add

Set the state of a button.

#### Arguments :id=api-programmable-button-add-arguments

- `uint8_t index`
The index of the button to press, from 0 to 31.

---

### `void programmable_button_remove(uint8_t index)` :id=api-programmable-button-remove

Reset the state of a button.

#### Arguments :id=api-programmable-button-remove-arguments

- `uint8_t index`
The index of the button to release, from 0 to 31.

---

### `void programmable_button_register(uint8_t index)` :id=api-programmable-button-register

Set the state of a button, and flush the report.

#### Arguments :id=api-programmable-button-register-arguments

- `uint8_t index`
The index of the button to press, from 0 to 31.

---

### `void programmable_button_unregister(uint8_t index)` :id=api-programmable-button-unregister

Reset the state of a button, and flush the report.

#### Arguments :id=api-programmable-button-unregister-arguments

- `uint8_t index`
The index of the button to release, from 0 to 31.

---

### `bool programmable_button_is_on(uint8_t index)` :id=api-programmable-button-is-on

Get the state of a button.

#### Arguments :id=api-programmable-button-is-on-arguments

- `uint8_t index`
The index of the button to check, from 0 to 31.

#### Return Value :id=api-programmable-button-is-on-return

`true` if the button is pressed.

---

### `void programmable_button_flush(void)` :id=api-programmable-button-flush

Send the programmable button report to the host.

---

### `uint32_t programmable_button_get_report(void)` :id=api-programmable-button-get-report

Get the programmable button report.

#### Return Value :id=api-programmable-button-get-report-return

The bitmask of programmable button states.

---

### `void programmable_button_set_report(uint32_t report)` :id=api-programmable-button-set-report

Set the programmable button report.

#### Arguments :id=api-programmable-button-set-report-arguments

- `uint32_t report`
A bitmask of programmable button states.
1 change: 0 additions & 1 deletion quantum/action.c
Original file line number Diff line number Diff line change
Expand Up @@ -1081,7 +1081,6 @@ void clear_keyboard_but_mods_and_keys() {
#endif
#ifdef PROGRAMMABLE_BUTTON_ENABLE
programmable_button_clear();
programmable_button_send();
#endif
}

Expand Down
7 changes: 0 additions & 7 deletions quantum/keyboard.c
Original file line number Diff line number Diff line change
Expand Up @@ -66,9 +66,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#ifdef JOYSTICK_ENABLE
# include "process_joystick.h"
#endif
#ifdef PROGRAMMABLE_BUTTON_ENABLE
# include "programmable_button.h"
#endif
#ifdef HD44780_ENABLE
# include "hd44780.h"
#endif
Expand Down Expand Up @@ -669,10 +666,6 @@ void keyboard_task(void) {
digitizer_task();
#endif

#ifdef PROGRAMMABLE_BUTTON_ENABLE
programmable_button_send();
#endif

#ifdef BLUETOOTH_ENABLE
bluetooth_task();
#endif
Expand Down
4 changes: 2 additions & 2 deletions quantum/process_keycode/process_programmable_button.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,9 @@ bool process_programmable_button(uint16_t keycode, keyrecord_t *record) {
if (keycode >= PROGRAMMABLE_BUTTON_MIN && keycode <= PROGRAMMABLE_BUTTON_MAX) {
uint8_t button = keycode - PROGRAMMABLE_BUTTON_MIN + 1;
if (record->event.pressed) {
programmable_button_on(button);
programmable_button_register(button);
} else {
programmable_button_off(button);
programmable_button_unregister(button);
}
}
return true;
Expand Down
27 changes: 19 additions & 8 deletions quantum/programmable_button.c
Original file line number Diff line number Diff line change
Expand Up @@ -24,27 +24,38 @@ static uint32_t programmable_button_report = 0;

void programmable_button_clear(void) {
programmable_button_report = 0;
programmable_button_flush();
}

void programmable_button_send(void) {
host_programmable_button_send(programmable_button_report);
}

void programmable_button_on(uint8_t index) {
void programmable_button_add(uint8_t index) {
programmable_button_report |= REPORT_BIT(index);
}

void programmable_button_off(uint8_t index) {
void programmable_button_remove(uint8_t index) {
programmable_button_report &= ~REPORT_BIT(index);
}

void programmable_button_register(uint8_t index) {
programmable_button_add(index);
programmable_button_flush();
}

void programmable_button_unregister(uint8_t index) {
programmable_button_remove(index);
programmable_button_flush();
}

bool programmable_button_is_on(uint8_t index) {
return !!(programmable_button_report & REPORT_BIT(index));
};
}

void programmable_button_flush(void) {
host_programmable_button_send(programmable_button_report);
}

uint32_t programmable_button_get_report(void) {
return programmable_button_report;
};
}

void programmable_button_set_report(uint32_t report) {
programmable_button_report = report;
Expand Down
75 changes: 68 additions & 7 deletions quantum/programmable_button.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,73 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.

#include <stdint.h>
#include <stdbool.h>
#include "report.h"

void programmable_button_clear(void);
void programmable_button_send(void);
void programmable_button_on(uint8_t index);
void programmable_button_off(uint8_t index);
bool programmable_button_is_on(uint8_t index);
/**
* \defgroup programmable_button
*
* HID Programmable Buttons
* \{
*/

/**
* \brief Clear the programmable button report.
*/
void programmable_button_clear(void);

/**
* \brief Set the state of a button.
*
* \param index The index of the button to press, from 0 to 31.
*/
void programmable_button_add(uint8_t index);

/**
* \brief Reset the state of a button.
*
* \param index The index of the button to release, from 0 to 31.
*/
void programmable_button_remove(uint8_t index);

/**
* \brief Set the state of a button, and flush the report.
*
* \param index The index of the button to press, from 0 to 31.
*/
void programmable_button_register(uint8_t index);

/**
* \brief Reset the state of a button, and flush the report.
*
* \param index The index of the button to release, from 0 to 31.
*/
void programmable_button_unregister(uint8_t index);

/**
* \brief Get the state of a button.
*
* \param index The index of the button to check, from 0 to 31.
*
* \return `true` if the button is pressed.
*/
bool programmable_button_is_on(uint8_t index);

/**
* \brief Send the programmable button report to the host.
*/
void programmable_button_flush(void);

/**
* \brief Get the programmable button report.
*
* \return The bitmask of programmable button states.
*/
uint32_t programmable_button_get_report(void);
void programmable_button_set_report(uint32_t report);

/**
* \brief Set the programmable button report.
*
* \param report A bitmask of programmable button states.
*/
void programmable_button_set_report(uint32_t report);

/** \} */