forked from mirror/qmk_firmware
Compare commits
19 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0269eea2c9 | ||
|
|
1836382f66 | ||
|
|
504533b3b4 | ||
|
|
ba9642c83d | ||
|
|
c2f7a5b5c5 | ||
|
|
ccc6c6ce0b | ||
|
|
c93ef27143 | ||
|
|
15e8658e81 | ||
|
|
c6475e0476 | ||
|
|
3001d81e3d | ||
|
|
407e6e242e | ||
|
|
18ed7c6caf | ||
|
|
92c0e2cee1 | ||
|
|
6a11370434 | ||
|
|
2bd8e43256 | ||
|
|
933cb8cc35 | ||
|
|
1426eedfc1 | ||
|
|
e4b998ccb0 | ||
|
|
b5af7a3390 |
19
.github/workflows/ci_build_major_branch.yml
vendored
19
.github/workflows/ci_build_major_branch.yml
vendored
@@ -32,6 +32,7 @@ jobs:
|
||||
container: ghcr.io/qmk/qmk_cli
|
||||
|
||||
outputs:
|
||||
keymaps: ${{ steps.generate_slice_length.outputs.keymaps }}
|
||||
slice_length: ${{ steps.generate_slice_length.outputs.slice_length }}
|
||||
|
||||
steps:
|
||||
@@ -47,12 +48,20 @@ jobs:
|
||||
|
||||
- name: Determine concurrency
|
||||
id: generate_slice_length
|
||||
shell: 'bash {0}'
|
||||
run: |
|
||||
target_count=$( {
|
||||
qmk find -km default 2>/dev/null
|
||||
qmk find -km xap 2>/dev/null
|
||||
} | sort | uniq | wc -l)
|
||||
targets=()
|
||||
target_count=0
|
||||
for target in "default" "xap"; do
|
||||
count=$(qmk find -km $target 2>/dev/null | wc -l)
|
||||
if [ $count -gt 0 ]; then
|
||||
target_count=$(($target_count + $count))
|
||||
targets+=($target)
|
||||
fi
|
||||
done
|
||||
keymaps=$(jq -c -n '$ARGS.positional' --args "${targets[@]}")
|
||||
slice_length=$((target_count / ($CONCURRENT_JOBS - 1))) # Err on the side of caution
|
||||
echo "keymaps=$keymaps" >> $GITHUB_OUTPUT
|
||||
echo "slice_length=$slice_length" >> $GITHUB_OUTPUT
|
||||
|
||||
build_targets:
|
||||
@@ -61,7 +70,7 @@ jobs:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
keymap: [default, xap]
|
||||
keymap: ${{ fromJson(needs.determine_concurrency.outputs.keymaps) }}
|
||||
uses: ./.github/workflows/ci_build_major_branch_keymap.yml
|
||||
with:
|
||||
branch: ${{ inputs.branch || github.ref_name }}
|
||||
|
||||
@@ -38,17 +38,18 @@ jobs:
|
||||
run: pip3 install -r requirements-dev.txt
|
||||
|
||||
- name: Generate build targets
|
||||
shell: 'bash {0}'
|
||||
id: generate_targets
|
||||
run: |
|
||||
{ # Intentionally use `shuf` here so that we share manufacturers across all build groups -- some have a lot of ARM-based boards which inherently take longer
|
||||
counter=0
|
||||
echo -n '{'
|
||||
qmk find -km ${{ inputs.keymap }} 2>/dev/null | sort | uniq | shuf | xargs -L${{ inputs.slice_length }} | while IFS=$'\n' read target ; do
|
||||
qmk find -km ${{ inputs.keymap }} 2>/dev/null | sort | uniq | shuf --random-source=<(openssl enc -aes-256-ctr -pass pass:qmk -nosalt </dev/zero 2>/dev/null) | xargs -L${{ inputs.slice_length }} | while IFS=$'\n' read target ; do
|
||||
if [ $counter -gt 0 ]; then
|
||||
echo -n ','
|
||||
fi
|
||||
counter=$((counter+1))
|
||||
printf "\"group %02d\":{" $counter
|
||||
printf "\"group-%02d\":{" $counter
|
||||
echo -n '"targets":"'
|
||||
echo $target | tr ' ' '\n' | sort | uniq | xargs echo -n
|
||||
echo -n '"}'
|
||||
@@ -72,6 +73,9 @@ jobs:
|
||||
container: ghcr.io/qmk/qmk_cli
|
||||
continue-on-error: true
|
||||
|
||||
env:
|
||||
CCACHE_CONFIGPATH: ~/.cache
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
target: ${{ fromJson(needs.generate_targets.outputs.targets) }}
|
||||
@@ -83,6 +87,8 @@ jobs:
|
||||
|
||||
- name: Checkout QMK Firmware
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
submodules: recursive
|
||||
|
||||
- name: Install dependencies
|
||||
run: pip3 install -r requirements-dev.txt
|
||||
@@ -93,24 +99,47 @@ jobs:
|
||||
name: targets-${{ inputs.keymap }}
|
||||
path: .
|
||||
|
||||
- name: Deploy submodules
|
||||
run: |
|
||||
qmk git-submodule -f
|
||||
|
||||
- name: Dump targets
|
||||
run: |
|
||||
jq -r '.["${{ matrix.target }}"].targets' targets.json | tr ' ' '\n' | sort
|
||||
|
||||
- name: Restore Cache
|
||||
id: cache
|
||||
uses: actions/cache/restore@v5
|
||||
with:
|
||||
path: ${{ env.CCACHE_CONFIGPATH }}
|
||||
key: compile-${{ inputs.keymap }}-${{ matrix.target }}
|
||||
|
||||
- name: Build targets
|
||||
continue-on-error: true
|
||||
run: |
|
||||
export NCPUS=$(( $(nproc 2>/dev/null || sysctl -n hw.ncpu 2>/dev/null || getconf _NPROCESSORS_ONLN 2>/dev/null) -1 ))
|
||||
targets=$(jq -r '.["${{ matrix.target }}"].targets' targets.json | tr ' ' '\n' | sort)
|
||||
if [ -z "${targets}" ]; then
|
||||
echo "Zero build targets detected"
|
||||
exit 0
|
||||
fi
|
||||
qmk mass-compile -t -j $NCPUS -e DUMP_CI_METADATA=yes $targets || touch .failed
|
||||
qmk mass-compile -t -j $(nproc) -e DUMP_CI_METADATA=yes -e USE_CCACHE=yes $targets || touch .failed
|
||||
|
||||
- name: Dump ccache stats
|
||||
run: |
|
||||
ccache -s
|
||||
|
||||
# Delete the old cache on hit to emulate a cache update. See https://github.com/actions/cache/issues/342.
|
||||
- name: Delete old cache
|
||||
env:
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
if: steps.cache.outputs.cache-hit
|
||||
run: |
|
||||
count=$(gh cache list --ref ${{ github.ref }} --key ${{ steps.cache.outputs.cache-primary-key }} --json id | jq length)
|
||||
if [ $count -gt 0 ]; then
|
||||
gh cache delete --ref ${{ github.ref }} ${{ steps.cache.outputs.cache-primary-key }}
|
||||
fi
|
||||
|
||||
- name: Save Cache
|
||||
uses: actions/cache/save@v5
|
||||
with:
|
||||
path: ${{ env.CCACHE_CONFIGPATH }}
|
||||
key: compile-${{ inputs.keymap }}-${{ matrix.target }}
|
||||
|
||||
- name: Upload binaries
|
||||
uses: actions/upload-artifact@v7
|
||||
|
||||
2
.github/workflows/develop_docs.yml
vendored
2
.github/workflows/develop_docs.yml
vendored
@@ -22,7 +22,7 @@ jobs:
|
||||
steps:
|
||||
- name: Deploy Develop
|
||||
if: ${{ github.repository == 'qmk/qmk_firmware' }}
|
||||
uses: actions/github-script@v8
|
||||
uses: actions/github-script@v9
|
||||
with:
|
||||
github-token: ${{ secrets.QMK_BOT_TOKEN }}
|
||||
script: |
|
||||
|
||||
18
.github/workflows/lint.yml
vendored
18
.github/workflows/lint.yml
vendored
@@ -89,23 +89,7 @@ jobs:
|
||||
if: always()
|
||||
shell: 'bash {0}'
|
||||
run: |
|
||||
exit_code=0
|
||||
|
||||
for file in $(find keyboards/ -name rules.mk | grep -v /keymaps/ | grep -v /common/ | grep -v /lib/); do
|
||||
dir=$(dirname $file)
|
||||
|
||||
$(find $dir -name keyboard.json -exec false {} +)
|
||||
if [[ $? == 0 ]]; then
|
||||
echo "$dir::Legacy target detected"
|
||||
|
||||
((++exit_code))
|
||||
fi
|
||||
done
|
||||
|
||||
if [[ $exit_code -gt 255 ]]; then
|
||||
exit 255
|
||||
fi
|
||||
exit $exit_code
|
||||
qmk ci-validate-keyboard-targets
|
||||
|
||||
- name: Verify keyboard aliases
|
||||
if: always()
|
||||
|
||||
3
Makefile
3
Makefile
@@ -43,8 +43,9 @@ QMK_BIN := qmk
|
||||
|
||||
# Try to determine userspace from qmk config, if set. Handle direct query on qmk_cli>=1.1.7
|
||||
# falling back to legacy method of only supporting user.overlay_dir config
|
||||
# sort is used to buffer 'qmk env' output and avoid BrokenPipeError errors
|
||||
export override QMK_USERSPACE := $(shell \
|
||||
$(QMK_BIN) env | grep -q QMK_USERSPACE \
|
||||
$(QMK_BIN) env | sort | grep -q QMK_USERSPACE \
|
||||
&& $(QMK_BIN) env QMK_USERSPACE \
|
||||
|| $(QMK_BIN) config -ro user.overlay_dir | cut -d= -f2 | sed -e 's@^None$$@@g')
|
||||
|
||||
|
||||
@@ -72,6 +72,8 @@ endif
|
||||
endif
|
||||
CFLAGS += -Wall
|
||||
CFLAGS += -Wstrict-prototypes
|
||||
CFLAGS += $(call cc-option,-Wunused-but-set-variable=1,-Wunused-but-set-variable)
|
||||
CFLAGS += $(call cc-option,-Wunused-but-set-parameter=1,-Wunused-but-set-parameter)
|
||||
ifneq ($(strip $(ALLOW_WARNINGS)), yes)
|
||||
CFLAGS += -Werror
|
||||
endif
|
||||
@@ -89,7 +91,8 @@ CXXFLAGS += -O$(OPT)
|
||||
CXXFLAGS += -w
|
||||
CXXFLAGS += -Wall
|
||||
CXXFLAGS += -Wundef
|
||||
|
||||
CXXFLAGS += $(call cc-option,-Wunused-but-set-variable=1,-Wunused-but-set-variable)
|
||||
CXXFLAGS += $(call cc-option,-Wunused-but-set-parameter=1,-Wunused-but-set-parameter)
|
||||
ifneq ($(strip $(ALLOW_WARNINGS)), yes)
|
||||
CXXFLAGS += -Werror
|
||||
endif
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
# $(2) = option to use if $(1) is not supported
|
||||
# $(3) = additional arguments to pass to the compiler during the test, but aren't contained in the output
|
||||
cc-option = $(shell \
|
||||
if { echo 'int main(){return 0;}' | $(CC) $(1) $(3) -o /dev/null -x c /dev/null >/dev/null 2>&1; }; \
|
||||
if { echo 'int main(){return 0;}' | $(CC) $(1) $(3) -Wl,--unresolved-symbols=ignore-all -o /dev/null -x c /dev/null >/dev/null 2>&1; }; \
|
||||
then echo "$(1)"; else echo "$(2)"; fi)
|
||||
|
||||
# Helper to pass comma character to make functions (use with `$(,)` to pass in `$(call ...)` arguments)
|
||||
|
||||
41
docs/cli.md
41
docs/cli.md
@@ -4,47 +4,18 @@
|
||||
|
||||
The QMK CLI (command line interface) makes building and working with QMK keyboards easier. We have provided a number of commands to simplify and streamline tasks such as obtaining and compiling the QMK firmware, creating keymaps, and more.
|
||||
|
||||
### Requirements {#requirements}
|
||||
### Installation {#installation}
|
||||
|
||||
QMK requires Python 3.9 or greater. We try to keep the number of requirements small but you will also need to install the packages listed in [`requirements.txt`](https://github.com/qmk/qmk_firmware/blob/master/requirements.txt). These are installed automatically when you install the QMK CLI.
|
||||
|
||||
### Install Using Homebrew (macOS, some Linux) {#install-using-homebrew}
|
||||
|
||||
If you have installed [Homebrew](https://brew.sh) you can tap and install QMK:
|
||||
The recommended way to install the QMK CLI and all necessary dependencies (toolchains, flashing utilities, udev rules on Linux) is to use the bootstrapper script:
|
||||
|
||||
```
|
||||
brew install qmk/qmk/qmk
|
||||
export QMK_HOME='~/qmk_firmware' # Optional, set the location for `qmk_firmware`
|
||||
qmk setup # This will clone `qmk/qmk_firmware` and optionally set up your build environment
|
||||
curl -fsSL https://install.qmk.fm | sh
|
||||
```
|
||||
|
||||
### Install Using uv {#install-using-uv}
|
||||
|
||||
If you have installed [uv](https://docs.astral.sh/uv/), the QMK CLI can be installed and managed as a uv tool:
|
||||
For more options, run:
|
||||
|
||||
```
|
||||
uv tool install qmk
|
||||
export QMK_HOME='~/qmk_firmware' # Optional, set the location for `qmk_firmware`
|
||||
qmk setup # This will clone `qmk/qmk_firmware` and optionally set up your build environment
|
||||
curl -fsSL https://install.qmk.fm | sh -s -- --help
|
||||
```
|
||||
|
||||
This installation can be updated via `uv tool upgrade qmk`. See [Upgrading tools](https://docs.astral.sh/uv/guides/tools/#upgrading-tools) for more information.
|
||||
|
||||
### Install Using pip {#install-using-easy_install-or-pip}
|
||||
|
||||
If your system is not listed above you can install QMK manually. First ensure that you have Python 3.9 (or later) installed and have installed pip. Then install QMK with this command:
|
||||
|
||||
```
|
||||
python3 -m pip install qmk
|
||||
export QMK_HOME='~/qmk_firmware' # Optional, set the location for `qmk_firmware`
|
||||
qmk setup # This will clone `qmk/qmk_firmware` and optionally set up your build environment
|
||||
```
|
||||
|
||||
### Packaging For Other Operating Systems {#packaging-for-other-operating-systems}
|
||||
|
||||
We are looking for people to create and maintain a `qmk` package for more operating systems. If you would like to create a package for your OS please follow these guidelines:
|
||||
|
||||
* Follow best practices for your OS when they conflict with these guidelines
|
||||
* Document why in a comment when you do deviate
|
||||
* Install using a virtualenv
|
||||
* Instruct the user to set the environment variable `QMK_HOME` to have the firmware source checked out somewhere other than `~/qmk_firmware`.
|
||||
For detailed setup instructions, see [Setting Up Your QMK Environment](newbs_getting_started#set-up-your-environment).
|
||||
|
||||
@@ -12,11 +12,11 @@ If you intend to maintain keyboards and/or contribute to QMK, you can enable the
|
||||
|
||||
`qmk config user.developer=True`
|
||||
|
||||
This will allow you to see all available subcommands.
|
||||
**Note:** You will have to install additional requirements:
|
||||
```
|
||||
python3 -m pip install -r requirements-dev.txt
|
||||
```
|
||||
This will allow you to see all available subcommands.
|
||||
|
||||
::: tip
|
||||
If you installed QMK using the bootstrapper (`curl -fsSL https://install.qmk.fm | sh`), the development requirements are already installed.
|
||||
:::
|
||||
|
||||
# Subcommands
|
||||
|
||||
|
||||
@@ -19,13 +19,10 @@ Note that running `make` with `sudo` is generally ***not*** a good idea, and you
|
||||
|
||||
### Linux `udev` Rules {#linux-udev-rules}
|
||||
|
||||
On Linux, you'll need proper privileges to communicate with the bootloader device. You can either use `sudo` when flashing firmware (not recommended), or place [this file](https://github.com/qmk/qmk_firmware/tree/master/util/udev/50-qmk.rules) into `/etc/udev/rules.d/`.
|
||||
|
||||
Once added, run the following:
|
||||
On Linux, you'll need proper privileges to communicate with the bootloader device. You can either use `sudo` when flashing firmware (not recommended), or install the udev rules from the [qmk_udev](https://github.com/qmk/qmk_udev) repository by running:
|
||||
|
||||
```
|
||||
sudo udevadm control --reload-rules
|
||||
sudo udevadm trigger
|
||||
util/install_udev.sh
|
||||
```
|
||||
|
||||
**Note:** With older versions of ModemManager (< 1.12), filtering only works when not in strict mode. The following commands can update that setting:
|
||||
|
||||
@@ -1,14 +1,20 @@
|
||||
# Persistent Configuration (EEPROM)
|
||||
|
||||
This allows you to configure persistent settings for your keyboard. These settings are stored in the EEPROM of your controller, and are retained even after power loss. The settings can be read with `eeconfig_read_kb` and `eeconfig_read_user`, and can be written to using `eeconfig_update_kb` and `eeconfig_update_user`. This is useful for features that you want to be able to toggle (like toggling rgb layer indication). Additionally, you can use `eeconfig_init_kb` and `eeconfig_init_user` to set the default values for the EEPROM.
|
||||
|
||||
The complicated part here, is that there are a bunch of ways that you can store and access data via EEPROM, and there is no "correct" way to do this. However, you only have a DWORD (4 bytes) for each function.
|
||||
This allows you to configure persistent settings for your keyboard. These settings are stored in the EEPROM of your controller, and are retained even after power loss.
|
||||
|
||||
Keep in mind that EEPROM has a limited number of writes. While this is very high, it's not the only thing writing to the EEPROM, and if you write too often, you can potentially drastically shorten the life of your MCU.
|
||||
|
||||
* If you don't understand the example, then you may want to avoid using this feature, as it is rather complicated.
|
||||
::: tip
|
||||
If you don't understand the examples, then you may want to avoid using this feature, as it is rather complicated.
|
||||
:::
|
||||
|
||||
## Example Implementation
|
||||
## Basic
|
||||
|
||||
The settings can be read with `eeconfig_read_kb` and `eeconfig_read_user`, and can be written to using `eeconfig_update_kb` and `eeconfig_update_user`. This is useful for features that you want to be able to toggle (like toggling rgb layer indication). Additionally, you can use `eeconfig_init_kb` and `eeconfig_init_user` to set the default values for the EEPROM.
|
||||
|
||||
The complicated part here, is that there are a bunch of ways that you can store and access data via EEPROM, and there is no "correct" way to do this. However, you only have a DWORD (4 bytes) for each function.
|
||||
|
||||
### Example Implementation
|
||||
|
||||
This is an example of how to add settings, and read and write it. We're using the user keymap for the example here. This is a complex function, and has a lot going on. In fact, it uses a lot of the above functions to work!
|
||||
|
||||
@@ -126,9 +132,111 @@ void eeconfig_init_user(void) { // EEPROM is getting reset!
|
||||
|
||||
And you're done. The RGB layer indication will only work if you want it to. And it will be saved, even after unplugging the board. And if you use any of the RGB codes, it will disable the layer indication, so that it stays on the mode and color that you set it to.
|
||||
|
||||
## 'EECONFIG' Function Documentation
|
||||
### Basic API
|
||||
|
||||
* Keyboard/Revision: `void eeconfig_init_kb(void)`, `uint32_t eeconfig_read_kb(void)` and `void eeconfig_update_kb(uint32_t val)`
|
||||
* Keymap: `void eeconfig_init_user(void)`, `uint32_t eeconfig_read_user(void)` and `void eeconfig_update_user(uint32_t val)`
|
||||
|
||||
The `val` is the value of the data that you want to write to EEPROM. And the `eeconfig_read_*` function return a 32 bit (DWORD) value from the EEPROM.
|
||||
|
||||
## Datablock {#datablock}
|
||||
|
||||
An extended form exists that allows larger blocks of data to be allocated.
|
||||
|
||||
::: info
|
||||
When using datablock, the [basic API](#eeconfig-function-documentation) is unavailable.
|
||||
:::
|
||||
|
||||
:::::tabs
|
||||
|
||||
==== keyboard
|
||||
|
||||
In `config.h`, define the size required, and optionally a version number:
|
||||
|
||||
| Define | Default | Description |
|
||||
|------------------------------|---------------------------|------------------------------------------------------------------|
|
||||
| `EECONFIG_KB_DATA_SIZE` | `0` | Size in bytes for the persistent block of data |
|
||||
| `EECONFIG_KB_DATA_VERSION` | `EECONFIG_KB_DATA_SIZE` | Version number that can be incremented to invalidate stored data |
|
||||
|
||||
Which exposes the following API:
|
||||
|
||||
```c
|
||||
bool eeconfig_is_kb_datablock_valid(void);
|
||||
uint32_t eeconfig_read_kb_datablock(void *data, uint32_t offset, uint32_t length) __attribute__((nonnull));
|
||||
uint32_t eeconfig_update_kb_datablock(const void *data, uint32_t offset, uint32_t length) __attribute__((nonnull));
|
||||
void eeconfig_init_kb_datablock(void);
|
||||
# define eeconfig_read_kb_datablock_field(__object, __field) eeconfig_read_kb_datablock(&(__object.__field), offsetof(typeof(__object), __field), sizeof(__object.__field))
|
||||
# define eeconfig_update_kb_datablock_field(__object, __field) eeconfig_update_kb_datablock(&(__object.__field), offsetof(typeof(__object), __field), sizeof(__object.__field))
|
||||
```
|
||||
|
||||
==== keymap
|
||||
|
||||
In `config.h`, define the size required, and optionally a version number:
|
||||
|
||||
| Define | Default | Description |
|
||||
|------------------------------|---------------------------|------------------------------------------------------------------|
|
||||
| `EECONFIG_USER_DATA_SIZE` | `0` | Size in bytes for the persistent block of data |
|
||||
| `EECONFIG_USER_DATA_VERSION` | `EECONFIG_USER_DATA_SIZE` | Version number that can be incremented to invalidate stored data |
|
||||
|
||||
Which exposes the following API:
|
||||
|
||||
```c
|
||||
bool eeconfig_is_user_datablock_valid(void);
|
||||
uint32_t eeconfig_read_user_datablock(void *data, uint32_t offset, uint32_t length) __attribute__((nonnull));
|
||||
uint32_t eeconfig_update_user_datablock(const void *data, uint32_t offset, uint32_t length) __attribute__((nonnull));
|
||||
void eeconfig_init_user_datablock(void);
|
||||
# define eeconfig_read_user_datablock_field(__object, __field) eeconfig_read_user_datablock(&(__object.__field), offsetof(typeof(__object), __field), sizeof(__object.__field))
|
||||
# define eeconfig_update_user_datablock_field(__object, __field) eeconfig_update_user_datablock(&(__object.__field), offsetof(typeof(__object), __field), sizeof(__object.__field))
|
||||
```
|
||||
|
||||
:::::
|
||||
|
||||
### Example
|
||||
|
||||
This is an example of how to add settings, and read and write it. We're using the user keymap for the example here.
|
||||
|
||||
In your `config.h` add:
|
||||
|
||||
```c
|
||||
#define EECONFIG_USER_DATA_SIZE 8
|
||||
```
|
||||
|
||||
In your keymap.c file, add:
|
||||
|
||||
```c
|
||||
#include "debug.h"
|
||||
#include "timer.h"
|
||||
#include "eeconfig.h"
|
||||
|
||||
typedef struct my_config_t {
|
||||
uint64_t data;
|
||||
} my_config_t;
|
||||
|
||||
static my_config_t config;
|
||||
|
||||
void keyboard_post_init_user(void) {
|
||||
if (!eeconfig_is_user_datablock_valid()) {
|
||||
eeconfig_init_user_datablock();
|
||||
}
|
||||
|
||||
eeconfig_read_user_datablock(&config, 0, sizeof(my_config_t));
|
||||
}
|
||||
|
||||
bool process_record_user(uint16_t keycode, keyrecord_t *record) {
|
||||
if (!record->event.pressed) {
|
||||
config.data += 1;
|
||||
eeconfig_update_user_datablock(&config, 0, sizeof(my_config_t));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void housekeeping_task_user(void) {
|
||||
static uint32_t last_sync = 0;
|
||||
if (timer_elapsed32(last_sync) > 1000) {
|
||||
last_sync = timer_read32();
|
||||
|
||||
dprintf("Config: %ld\n", config.data);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
@@ -217,8 +217,8 @@ To generate this bootloader, use the `bootloader` target, eg. `make planck/rev4:
|
||||
|
||||
Compatible flashers:
|
||||
|
||||
* TBD
|
||||
* Currently, you need to either use the [Python script](https://github.com/qmk/lufa/tree/master/Bootloaders/HID/HostLoaderApp_python), or compile [`hid_bootloader_cli`](https://github.com/qmk/lufa/tree/master/Bootloaders/HID/HostLoaderApp), from the LUFA repo. Homebrew may (will) have support for this directly (via `brew install qmk/qmk/hid_bootloader_cli`).
|
||||
* [QMK Toolbox](https://github.com/qmk/qmk_toolbox/releases) (recommended GUI)
|
||||
* [hid_bootloader_cli](https://github.com/qmk/lufa/tree/master/Bootloaders/HID/HostLoaderApp) / `:qmk-hid` target in QMK (recommended command line)
|
||||
|
||||
Flashing sequence:
|
||||
|
||||
|
||||
@@ -2,65 +2,68 @@
|
||||
// A simple ringbuffer holding Size elements of type T
|
||||
template <typename T, uint8_t Size>
|
||||
class RingBuffer {
|
||||
protected:
|
||||
T buf_[Size];
|
||||
uint8_t head_{0}, tail_{0};
|
||||
public:
|
||||
inline uint8_t nextPosition(uint8_t position) {
|
||||
return (position + 1) % Size;
|
||||
}
|
||||
protected:
|
||||
T buf_[Size];
|
||||
uint8_t head_{0}, tail_{0};
|
||||
|
||||
inline uint8_t prevPosition(uint8_t position) {
|
||||
if (position == 0) {
|
||||
return Size - 1;
|
||||
}
|
||||
return position - 1;
|
||||
}
|
||||
|
||||
inline bool enqueue(const T &item) {
|
||||
static_assert(Size > 1, "RingBuffer size must be > 1");
|
||||
uint8_t next = nextPosition(head_);
|
||||
if (next == tail_) {
|
||||
// Full
|
||||
return false;
|
||||
public:
|
||||
inline uint8_t nextPosition(uint8_t position) {
|
||||
return (position + 1) % Size;
|
||||
}
|
||||
|
||||
buf_[head_] = item;
|
||||
head_ = next;
|
||||
return true;
|
||||
}
|
||||
|
||||
inline bool get(T &dest, bool commit = true) {
|
||||
auto tail = tail_;
|
||||
if (tail == head_) {
|
||||
// No more data
|
||||
return false;
|
||||
inline uint8_t prevPosition(uint8_t position) {
|
||||
if (position == 0) {
|
||||
return Size - 1;
|
||||
}
|
||||
return position - 1;
|
||||
}
|
||||
|
||||
dest = buf_[tail];
|
||||
tail = nextPosition(tail);
|
||||
inline bool enqueue(const T &item) {
|
||||
static_assert(Size > 1, "RingBuffer size must be > 1");
|
||||
uint8_t next = nextPosition(head_);
|
||||
if (next == tail_) {
|
||||
// Full
|
||||
return false;
|
||||
}
|
||||
|
||||
if (commit) {
|
||||
tail_ = tail;
|
||||
buf_[head_] = item;
|
||||
head_ = next;
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
inline bool empty() const { return head_ == tail_; }
|
||||
inline bool get(T &dest, bool commit = true) {
|
||||
auto tail = tail_;
|
||||
if (tail == head_) {
|
||||
// No more data
|
||||
return false;
|
||||
}
|
||||
|
||||
inline uint8_t size() const {
|
||||
int diff = head_ - tail_;
|
||||
if (diff >= 0) {
|
||||
return diff;
|
||||
dest = buf_[tail];
|
||||
tail = nextPosition(tail);
|
||||
|
||||
if (commit) {
|
||||
tail_ = tail;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return Size + diff;
|
||||
}
|
||||
|
||||
inline T& front() {
|
||||
return buf_[tail_];
|
||||
}
|
||||
inline bool empty() const {
|
||||
return head_ == tail_;
|
||||
}
|
||||
|
||||
inline bool peek(T &item) {
|
||||
return get(item, false);
|
||||
}
|
||||
inline uint8_t size() const {
|
||||
int diff = head_ - tail_;
|
||||
if (diff >= 0) {
|
||||
return diff;
|
||||
}
|
||||
return Size + diff;
|
||||
}
|
||||
|
||||
inline T &front() {
|
||||
return buf_[tail_];
|
||||
}
|
||||
|
||||
inline bool peek(T &item) {
|
||||
return get(item, false);
|
||||
}
|
||||
};
|
||||
|
||||
50
keyboards/handwired/sector245/s245/keyboard.json
Normal file
50
keyboards/handwired/sector245/s245/keyboard.json
Normal file
@@ -0,0 +1,50 @@
|
||||
{
|
||||
"keyboard_name": "S245 Streamdeck",
|
||||
"manufacturer": "sector245",
|
||||
"maintainer": "sector245",
|
||||
"processor": "RP2040",
|
||||
"bootloader": "rp2040",
|
||||
"debounce": 20,
|
||||
"usb": {
|
||||
"vid": "0x5345",
|
||||
"pid": "0x0001",
|
||||
"device_version": "1.0.0"
|
||||
},
|
||||
"features": {
|
||||
"bootmagic": true,
|
||||
"extrakey": true,
|
||||
"encoder": true
|
||||
},
|
||||
"matrix_pins": {
|
||||
"direct": [
|
||||
["GP2", "GP3", "GP13"],
|
||||
["GP4", "GP5", "GP6"],
|
||||
["GP7", "GP8", "GP9"]
|
||||
]
|
||||
},
|
||||
"encoder": {
|
||||
"rotary": [
|
||||
{
|
||||
"pin_a": "GP10",
|
||||
"pin_b": "GP11",
|
||||
"resolution": 2
|
||||
}
|
||||
]
|
||||
},
|
||||
"community_layouts": ["ortho_3x3"],
|
||||
"layouts": {
|
||||
"LAYOUT_ortho_3x3": {
|
||||
"layout": [
|
||||
{"matrix": [0, 0], "x": 0, "y": 0},
|
||||
{"matrix": [0, 1], "x": 1, "y": 0},
|
||||
{"matrix": [0, 2], "x": 2, "y": 0, "encoder": 0},
|
||||
{"matrix": [1, 0], "x": 0, "y": 1},
|
||||
{"matrix": [1, 1], "x": 1, "y": 1},
|
||||
{"matrix": [1, 2], "x": 2, "y": 1},
|
||||
{"matrix": [2, 0], "x": 0, "y": 2},
|
||||
{"matrix": [2, 1], "x": 1, "y": 2},
|
||||
{"matrix": [2, 2], "x": 2, "y": 2}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
18
keyboards/handwired/sector245/s245/keymaps/default/keymap.c
Normal file
18
keyboards/handwired/sector245/s245/keymaps/default/keymap.c
Normal file
@@ -0,0 +1,18 @@
|
||||
// Copyright 2025 sector245 (@sector245)
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include QMK_KEYBOARD_H
|
||||
|
||||
const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
|
||||
[0] = LAYOUT_ortho_3x3(
|
||||
KC_A, KC_B, KC_C,
|
||||
KC_D, KC_E, KC_F,
|
||||
KC_G, KC_H, KC_I
|
||||
)
|
||||
};
|
||||
|
||||
#if defined(ENCODER_MAP_ENABLE)
|
||||
const uint16_t PROGMEM encoder_map[][NUM_ENCODERS][NUM_DIRECTIONS] = {
|
||||
[0] = { ENCODER_CCW_CW(KC_VOLD, KC_VOLU) }
|
||||
};
|
||||
#endif
|
||||
@@ -0,0 +1 @@
|
||||
ENCODER_MAP_ENABLE = yes
|
||||
24
keyboards/handwired/sector245/s245/readme.md
Normal file
24
keyboards/handwired/sector245/s245/readme.md
Normal file
@@ -0,0 +1,24 @@
|
||||
# S245 Streamdeck
|
||||
|
||||
A 3x3 macropad with rotary encoder.
|
||||
|
||||
* Keyboard Maintainer: [sector245](https://github.com/sinomau)
|
||||
* Hardware Supported: S245 Streamdeck PCB, RP2040
|
||||
|
||||
Make example for this keyboard (after setting up your build environment):
|
||||
|
||||
make handwired/sector245/s245:default
|
||||
|
||||
Flashing example for this keyboard:
|
||||
|
||||
make handwired/sector245/s245:default:flash
|
||||
|
||||
See the [build environment setup](https://docs.qmk.fm/#/getting_started_build_tools) and the [make instructions](https://docs.qmk.fm/#/getting_started_make_guide) for more information. Brand new to QMK? Start with our [Complete Newbs Guide](https://docs.qmk.fm/#/newbs).
|
||||
|
||||
## Bootloader
|
||||
|
||||
Enter the bootloader in 3 ways:
|
||||
|
||||
* **Bootmagic reset**: Hold down the key at (0,0) in the matrix (top left key) and plug in the keyboard
|
||||
* **Physical reset button**: Hold the BOOTSEL button on the Pico and plug in the keyboard
|
||||
* **Keycode in layout**: Press the key mapped to `QK_BOOT` if it is available
|
||||
206
keyboards/kbd0/curve0/75_ansi/keyboard.json
Normal file
206
keyboards/kbd0/curve0/75_ansi/keyboard.json
Normal file
@@ -0,0 +1,206 @@
|
||||
{
|
||||
"manufacturer": "kbd0",
|
||||
"keyboard_name": "kbd0/curve0/75_ansi",
|
||||
"maintainer": "kbd0",
|
||||
"bootloader": "rp2040",
|
||||
"bootloader_instructions": "Hold the little button on the main PCB (inside the keyboard, near the spacebar) while plugging in the keyboard to enter bootloader.",
|
||||
"diode_direction": "COL2ROW",
|
||||
"features": {
|
||||
"bootmagic": true,
|
||||
"extrakey": true,
|
||||
"mousekey": true,
|
||||
"nkro": true
|
||||
},
|
||||
"matrix_pins": {
|
||||
"cols": ["GP6", "GP5", "GP4", "GP7", "GP10", "GP9", "GP11", "GP12", "GP13", "GP14", "GP25", "GP20", "GP19", "GP18", "GP16", "GP3"],
|
||||
"rows": ["GP2", "GP23", "GP22", "GP21", "GP24", "GP17"]
|
||||
},
|
||||
"processor": "RP2040",
|
||||
"url": "https://kbd0.com/item/curve0",
|
||||
"usb": {
|
||||
"device_version": "1.0.0",
|
||||
"pid": "0xC001",
|
||||
"vid": "0xCBD0"
|
||||
},
|
||||
"community_layouts": ["75_ansi"],
|
||||
"layouts": {
|
||||
"LAYOUT_all": {
|
||||
"layout": [
|
||||
{"matrix": [0, 0], "x": 0, "y": 0},
|
||||
{"matrix": [0, 1], "x": 1, "y": 0},
|
||||
{"matrix": [0, 2], "x": 2, "y": 0},
|
||||
{"matrix": [0, 3], "x": 3, "y": 0},
|
||||
{"matrix": [0, 4], "x": 4, "y": 0},
|
||||
{"matrix": [0, 5], "x": 5, "y": 0},
|
||||
{"matrix": [0, 6], "x": 6, "y": 0},
|
||||
{"matrix": [0, 7], "x": 7, "y": 0},
|
||||
{"matrix": [0, 8], "x": 8, "y": 0},
|
||||
{"matrix": [0, 9], "x": 9, "y": 0},
|
||||
{"matrix": [0, 10], "x": 10, "y": 0},
|
||||
{"matrix": [0, 11], "x": 11, "y": 0},
|
||||
{"matrix": [0, 12], "x": 12, "y": 0},
|
||||
{"matrix": [0, 13], "x": 13, "y": 0},
|
||||
{"matrix": [0, 14], "x": 14, "y": 0},
|
||||
{"matrix": [0, 15], "x": 15, "y": 0},
|
||||
{"matrix": [1, 0], "x": 0, "y": 1},
|
||||
{"matrix": [1, 1], "x": 1, "y": 1},
|
||||
{"matrix": [1, 2], "x": 2, "y": 1},
|
||||
{"matrix": [1, 3], "x": 3, "y": 1},
|
||||
{"matrix": [1, 4], "x": 4, "y": 1},
|
||||
{"matrix": [1, 5], "x": 5, "y": 1},
|
||||
{"matrix": [1, 6], "x": 6, "y": 1},
|
||||
{"matrix": [1, 7], "x": 7, "y": 1},
|
||||
{"matrix": [1, 8], "x": 8, "y": 1},
|
||||
{"matrix": [1, 9], "x": 9, "y": 1},
|
||||
{"matrix": [1, 10], "x": 10, "y": 1},
|
||||
{"matrix": [1, 11], "x": 11, "y": 1},
|
||||
{"matrix": [1, 12], "x": 12, "y": 1},
|
||||
{"matrix": [1, 13], "x": 13, "y": 1},
|
||||
{"matrix": [1, 14], "x": 14, "y": 1},
|
||||
{"matrix": [1, 15], "x": 15, "y": 1},
|
||||
{"matrix": [2, 0], "x": 0, "y": 2, "w": 1.5},
|
||||
{"matrix": [2, 1], "x": 1.5, "y": 2},
|
||||
{"matrix": [2, 2], "x": 2.5, "y": 2},
|
||||
{"matrix": [2, 3], "x": 3.5, "y": 2},
|
||||
{"matrix": [2, 4], "x": 4.5, "y": 2},
|
||||
{"matrix": [2, 5], "x": 5.5, "y": 2},
|
||||
{"matrix": [2, 6], "x": 6.5, "y": 2},
|
||||
{"matrix": [2, 7], "x": 7.5, "y": 2},
|
||||
{"matrix": [2, 8], "x": 8.5, "y": 2},
|
||||
{"matrix": [2, 9], "x": 9.5, "y": 2},
|
||||
{"matrix": [2, 10], "x": 10.5, "y": 2},
|
||||
{"matrix": [2, 11], "x": 11.5, "y": 2},
|
||||
{"matrix": [2, 12], "x": 12.5, "y": 2},
|
||||
{"matrix": [2, 13], "x": 13.5, "y": 2, "w": 1.5},
|
||||
{"matrix": [2, 15], "x": 15, "y": 2},
|
||||
{"matrix": [3, 0], "x": 0, "y": 3, "w": 1.75},
|
||||
{"matrix": [3, 1], "x": 1.75, "y": 3},
|
||||
{"matrix": [3, 2], "x": 2.75, "y": 3},
|
||||
{"matrix": [3, 3], "x": 3.75, "y": 3},
|
||||
{"matrix": [3, 4], "x": 4.75, "y": 3},
|
||||
{"matrix": [3, 5], "x": 5.75, "y": 3},
|
||||
{"matrix": [3, 6], "x": 6.75, "y": 3},
|
||||
{"matrix": [3, 7], "x": 7.75, "y": 3},
|
||||
{"matrix": [3, 8], "x": 8.75, "y": 3},
|
||||
{"matrix": [3, 9], "x": 9.75, "y": 3},
|
||||
{"matrix": [3, 10], "x": 10.75, "y": 3},
|
||||
{"matrix": [3, 11], "x": 11.75, "y": 3},
|
||||
{"matrix": [3, 12], "x": 12.75, "y": 3, "w": 2.25},
|
||||
{"matrix": [3, 15], "x": 15, "y": 3},
|
||||
{"matrix": [4, 0], "x": 0, "y": 4, "w": 1.25},
|
||||
{"matrix": [4, 1], "x": 1.25, "y": 4},
|
||||
{"matrix": [4, 2], "x": 2.25, "y": 4},
|
||||
{"matrix": [4, 3], "x": 3.25, "y": 4},
|
||||
{"matrix": [4, 4], "x": 4.25, "y": 4},
|
||||
{"matrix": [4, 5], "x": 5.25, "y": 4},
|
||||
{"matrix": [4, 6], "x": 6.25, "y": 4},
|
||||
{"matrix": [4, 7], "x": 7.25, "y": 4},
|
||||
{"matrix": [4, 8], "x": 8.25, "y": 4},
|
||||
{"matrix": [4, 9], "x": 9.25, "y": 4},
|
||||
{"matrix": [4, 10], "x": 10.25, "y": 4},
|
||||
{"matrix": [4, 11], "x": 11.25, "y": 4},
|
||||
{"matrix": [4, 12], "x": 12.25, "y": 4, "w": 1.75},
|
||||
{"matrix": [4, 14], "x": 14, "y": 4},
|
||||
{"matrix": [4, 15], "x": 15, "y": 4},
|
||||
{"matrix": [5, 0], "x": 0, "y": 5, "w": 1.25},
|
||||
{"matrix": [5, 1], "x": 1.25, "y": 5, "w": 1.25},
|
||||
{"matrix": [5, 2], "x": 2.5, "y": 5, "w": 1.25},
|
||||
{"matrix": [5, 6], "x": 3.75, "y": 5, "w": 6.25},
|
||||
{"matrix": [5, 10], "x": 10, "y": 5},
|
||||
{"matrix": [5, 11], "x": 11, "y": 5},
|
||||
{"matrix": [5, 12], "x": 12, "y": 5},
|
||||
{"matrix": [5, 13], "x": 13, "y": 5},
|
||||
{"matrix": [5, 14], "x": 14, "y": 5},
|
||||
{"matrix": [5, 15], "x": 15, "y": 5}
|
||||
]
|
||||
},
|
||||
"LAYOUT_75_ansi": {
|
||||
"layout": [
|
||||
{"matrix": [0, 0], "x": 0, "y": 0},
|
||||
{"matrix": [0, 1], "x": 1, "y": 0},
|
||||
{"matrix": [0, 2], "x": 2, "y": 0},
|
||||
{"matrix": [0, 3], "x": 3, "y": 0},
|
||||
{"matrix": [0, 4], "x": 4, "y": 0},
|
||||
{"matrix": [0, 5], "x": 5, "y": 0},
|
||||
{"matrix": [0, 6], "x": 6, "y": 0},
|
||||
{"matrix": [0, 7], "x": 7, "y": 0},
|
||||
{"matrix": [0, 8], "x": 8, "y": 0},
|
||||
{"matrix": [0, 9], "x": 9, "y": 0},
|
||||
{"matrix": [0, 10], "x": 10, "y": 0},
|
||||
{"matrix": [0, 11], "x": 11, "y": 0},
|
||||
{"matrix": [0, 12], "x": 12, "y": 0},
|
||||
{"matrix": [0, 13], "x": 13, "y": 0},
|
||||
{"matrix": [0, 14], "x": 14, "y": 0},
|
||||
{"matrix": [0, 15], "x": 15, "y": 0},
|
||||
{"matrix": [1, 0], "x": 0, "y": 1},
|
||||
{"matrix": [1, 1], "x": 1, "y": 1},
|
||||
{"matrix": [1, 2], "x": 2, "y": 1},
|
||||
{"matrix": [1, 3], "x": 3, "y": 1},
|
||||
{"matrix": [1, 4], "x": 4, "y": 1},
|
||||
{"matrix": [1, 5], "x": 5, "y": 1},
|
||||
{"matrix": [1, 6], "x": 6, "y": 1},
|
||||
{"matrix": [1, 7], "x": 7, "y": 1},
|
||||
{"matrix": [1, 8], "x": 8, "y": 1},
|
||||
{"matrix": [1, 9], "x": 9, "y": 1},
|
||||
{"matrix": [1, 10], "x": 10, "y": 1},
|
||||
{"matrix": [1, 11], "x": 11, "y": 1},
|
||||
{"matrix": [1, 12], "x": 12, "y": 1},
|
||||
{"matrix": [1, 14], "x": 13, "y": 1, "w": 2},
|
||||
{"matrix": [1, 15], "x": 15, "y": 1},
|
||||
{"matrix": [2, 0], "x": 0, "y": 2, "w": 1.5},
|
||||
{"matrix": [2, 1], "x": 1.5, "y": 2},
|
||||
{"matrix": [2, 2], "x": 2.5, "y": 2},
|
||||
{"matrix": [2, 3], "x": 3.5, "y": 2},
|
||||
{"matrix": [2, 4], "x": 4.5, "y": 2},
|
||||
{"matrix": [2, 5], "x": 5.5, "y": 2},
|
||||
{"matrix": [2, 6], "x": 6.5, "y": 2},
|
||||
{"matrix": [2, 7], "x": 7.5, "y": 2},
|
||||
{"matrix": [2, 8], "x": 8.5, "y": 2},
|
||||
{"matrix": [2, 9], "x": 9.5, "y": 2},
|
||||
{"matrix": [2, 10], "x": 10.5, "y": 2},
|
||||
{"matrix": [2, 11], "x": 11.5, "y": 2},
|
||||
{"matrix": [2, 12], "x": 12.5, "y": 2},
|
||||
{"matrix": [2, 13], "x": 13.5, "y": 2, "w": 1.5},
|
||||
{"matrix": [2, 15], "x": 15, "y": 2},
|
||||
{"matrix": [3, 0], "x": 0, "y": 3, "w": 1.75},
|
||||
{"matrix": [3, 1], "x": 1.75, "y": 3},
|
||||
{"matrix": [3, 2], "x": 2.75, "y": 3},
|
||||
{"matrix": [3, 3], "x": 3.75, "y": 3},
|
||||
{"matrix": [3, 4], "x": 4.75, "y": 3},
|
||||
{"matrix": [3, 5], "x": 5.75, "y": 3},
|
||||
{"matrix": [3, 6], "x": 6.75, "y": 3},
|
||||
{"matrix": [3, 7], "x": 7.75, "y": 3},
|
||||
{"matrix": [3, 8], "x": 8.75, "y": 3},
|
||||
{"matrix": [3, 9], "x": 9.75, "y": 3},
|
||||
{"matrix": [3, 10], "x": 10.75, "y": 3},
|
||||
{"matrix": [3, 11], "x": 11.75, "y": 3},
|
||||
{"matrix": [3, 12], "x": 12.75, "y": 3, "w": 2.25},
|
||||
{"matrix": [3, 15], "x": 15, "y": 3},
|
||||
{"matrix": [4, 0], "x": 0, "y": 4, "w": 2.25},
|
||||
{"matrix": [4, 2], "x": 2.25, "y": 4},
|
||||
{"matrix": [4, 3], "x": 3.25, "y": 4},
|
||||
{"matrix": [4, 4], "x": 4.25, "y": 4},
|
||||
{"matrix": [4, 5], "x": 5.25, "y": 4},
|
||||
{"matrix": [4, 6], "x": 6.25, "y": 4},
|
||||
{"matrix": [4, 7], "x": 7.25, "y": 4},
|
||||
{"matrix": [4, 8], "x": 8.25, "y": 4},
|
||||
{"matrix": [4, 9], "x": 9.25, "y": 4},
|
||||
{"matrix": [4, 10], "x": 10.25, "y": 4},
|
||||
{"matrix": [4, 11], "x": 11.25, "y": 4},
|
||||
{"matrix": [4, 12], "x": 12.25, "y": 4, "w": 1.75},
|
||||
{"matrix": [4, 14], "x": 14, "y": 4},
|
||||
{"matrix": [4, 15], "x": 15, "y": 4},
|
||||
{"matrix": [5, 0], "x": 0, "y": 5, "w": 1.25},
|
||||
{"matrix": [5, 1], "x": 1.25, "y": 5, "w": 1.25},
|
||||
{"matrix": [5, 2], "x": 2.5, "y": 5, "w": 1.25},
|
||||
{"matrix": [5, 6], "x": 3.75, "y": 5, "w": 6.25},
|
||||
{"matrix": [5, 10], "x": 10, "y": 5},
|
||||
{"matrix": [5, 11], "x": 11, "y": 5},
|
||||
{"matrix": [5, 12], "x": 12, "y": 5},
|
||||
{"matrix": [5, 13], "x": 13, "y": 5},
|
||||
{"matrix": [5, 14], "x": 14, "y": 5},
|
||||
{"matrix": [5, 15], "x": 15, "y": 5}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
16
keyboards/kbd0/curve0/75_ansi/keymaps/75_ansi/keymap.json
Normal file
16
keyboards/kbd0/curve0/75_ansi/keymaps/75_ansi/keymap.json
Normal file
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"author": "kbd0",
|
||||
"keyboard": "kbd0/curve0/75_ansi",
|
||||
"keymap": "75_ansi",
|
||||
"layout": "LAYOUT_75_ansi",
|
||||
"layers": [
|
||||
[
|
||||
"KC_ESC", "KC_F1", "KC_F2", "KC_F3", "KC_F4", "KC_F5", "KC_F6", "KC_F7", "KC_F8", "KC_F9", "KC_F10", "KC_F11", "KC_F12", "KC_PRINT_SCREEN", "KC_DELETE", "KC_INSERT",
|
||||
"KC_GRAVE", "KC_1", "KC_2", "KC_3", "KC_4", "KC_5", "KC_6", "KC_7", "KC_8", "KC_9", "KC_0", "KC_MINS", "KC_EQL", "KC_BSPC", "KC_HOME",
|
||||
"KC_TAB", "KC_Q", "KC_W", "KC_E", "KC_R", "KC_T", "KC_Y", "KC_U", "KC_I", "KC_O", "KC_P", "KC_LBRC", "KC_RBRC", "KC_BSLS", "KC_END",
|
||||
"KC_CAPS", "KC_A", "KC_S", "KC_D", "KC_F", "KC_G", "KC_H", "KC_J", "KC_K", "KC_L", "KC_SCLN", "KC_QUOT", "KC_ENT", "KC_PGUP",
|
||||
"KC_LSFT", "KC_Z", "KC_X", "KC_C", "KC_V", "KC_B", "KC_N", "KC_M", "KC_COMM", "KC_DOT", "KC_SLSH", "KC_RSFT", "KC_UP", "KC_PGDN",
|
||||
"KC_LCTL", "KC_LGUI", "KC_LALT", "KC_SPC", "KC_RALT", "KC_APP", "KC_RCTL", "KC_LEFT", "KC_DOWN", "KC_RIGHT"
|
||||
]
|
||||
]
|
||||
}
|
||||
16
keyboards/kbd0/curve0/75_ansi/keymaps/default/keymap.json
Normal file
16
keyboards/kbd0/curve0/75_ansi/keymaps/default/keymap.json
Normal file
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"author": "kbd0",
|
||||
"keyboard": "kbd0/curve0/75_ansi",
|
||||
"keymap": "default",
|
||||
"layout": "LAYOUT_all",
|
||||
"layers": [
|
||||
[
|
||||
"KC_ESC", "KC_F1", "KC_F2", "KC_F3", "KC_F4", "KC_F5", "KC_F6", "KC_F7", "KC_F8", "KC_F9", "KC_F10", "KC_F11", "KC_F12", "KC_PRINT_SCREEN", "KC_DELETE", "KC_INSERT",
|
||||
"KC_GRAVE", "KC_1", "KC_2", "KC_3", "KC_4", "KC_5", "KC_6", "KC_7", "KC_8", "KC_9", "KC_0", "KC_MINS", "KC_EQL", "KC_BSLS", "KC_BSPC", "KC_HOME",
|
||||
"KC_TAB", "KC_Q", "KC_W", "KC_E", "KC_R", "KC_T", "KC_Y", "KC_U", "KC_I", "KC_O", "KC_P", "KC_LBRC", "KC_RBRC", "KC_BSLS", "KC_END",
|
||||
"KC_CAPS", "KC_A", "KC_S", "KC_D", "KC_F", "KC_G", "KC_H", "KC_J", "KC_K", "KC_L", "KC_SCLN", "KC_QUOT", "KC_ENT", "KC_PGUP",
|
||||
"KC_LSFT", "KC_NUBS", "KC_Z", "KC_X", "KC_C", "KC_V", "KC_B", "KC_N", "KC_M", "KC_COMM", "KC_DOT", "KC_SLSH", "KC_RSFT", "KC_UP", "KC_PGDN",
|
||||
"KC_LCTL", "KC_LGUI", "KC_LALT", "KC_SPC", "KC_RALT", "KC_APP", "KC_RCTL", "KC_LEFT", "KC_DOWN", "KC_RIGHT"
|
||||
]
|
||||
]
|
||||
}
|
||||
27
keyboards/kbd0/curve0/75_ansi/readme.md
Normal file
27
keyboards/kbd0/curve0/75_ansi/readme.md
Normal file
@@ -0,0 +1,27 @@
|
||||
# kbd0/curve0/75_ansi
|
||||
|
||||

|
||||
|
||||
Curve0 - Curved stainless steel keyboard by Kbd0
|
||||
|
||||
* Keyboard Maintainer: [kbd0](https://github.com/kbd0)
|
||||
* Hardware Supported: Curve0 PCB
|
||||
* Hardware Availability: [kbd0.com](https://kbd0.com/item/curve0)
|
||||
|
||||
Make example for this keyboard (after setting up your build environment):
|
||||
|
||||
make kbd0/curve0/75_ansi:default
|
||||
|
||||
Flashing example for this keyboard:
|
||||
|
||||
make kbd0/curve0/75_ansi:default:flash
|
||||
|
||||
See the [build environment setup](https://docs.qmk.fm/#/getting_started_build_tools) and the [make instructions](https://docs.qmk.fm/#/getting_started_make_guide) for more information. Brand new to QMK? Start with our [Complete Newbs Guide](https://docs.qmk.fm/#/newbs).
|
||||
|
||||
## Bootloader
|
||||
|
||||
Enter the bootloader in 3 ways:
|
||||
|
||||
* **Bootmagic reset**: Hold the top left key of the keyboard while plugging in the keyboard
|
||||
* **Physical reset button**: Hold the little button on the main PCB (inside the keyboard, near the spacebar) while plugging in the keyboard
|
||||
* **Keycode in layout**: Press the key mapped to `QK_BOOT` if it is available
|
||||
21
keyboards/keebio/sinc_lm/info.json
Normal file
21
keyboards/keebio/sinc_lm/info.json
Normal file
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"manufacturer": "Keebio",
|
||||
"url": "https://keeb.io",
|
||||
"maintainer": "nooges",
|
||||
"usb": {
|
||||
"vid": "0xCB10"
|
||||
},
|
||||
"features": {
|
||||
"bootmagic": true,
|
||||
"console": true,
|
||||
"extrakey": true,
|
||||
"mousekey": true,
|
||||
"nkro": false
|
||||
},
|
||||
"split": {
|
||||
"enabled": true
|
||||
},
|
||||
"build": {
|
||||
"lto": true
|
||||
}
|
||||
}
|
||||
23
keyboards/keebio/sinc_lm/keymaps/default/keymap.c
Normal file
23
keyboards/keebio/sinc_lm/keymaps/default/keymap.c
Normal file
@@ -0,0 +1,23 @@
|
||||
// Copyright 2026 Keebio (@keebio)
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include QMK_KEYBOARD_H
|
||||
|
||||
const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
|
||||
[0] = LAYOUT(
|
||||
KC_MUTE, RM_NEXT, KC_ESC, KC_F1, KC_F2, KC_F3, KC_F4, KC_F5, KC_F6, KC_F7, KC_F8, KC_F9, KC_F10, KC_F11, KC_F12, KC_VOLD, KC_VOLU,
|
||||
KC_F1, KC_F2, KC_GRV, KC_1, KC_2, KC_3, KC_4, KC_5, KC_6, KC_7, KC_8, KC_9, KC_0, KC_MINS, KC_EQL, KC_BSPC, KC_DEL,
|
||||
KC_F3, KC_F4, KC_TAB, KC_Q, KC_W, KC_E, KC_R, KC_T, KC_Y, KC_U, KC_I, KC_O, KC_P, KC_LBRC, KC_RBRC, KC_BSLS, KC_HOME,
|
||||
KC_F5, KC_F6, KC_CAPS, KC_A, KC_S, KC_D, KC_F, KC_G, KC_H, KC_J, KC_K, KC_L, KC_SCLN, KC_QUOT, KC_ENT, KC_PGUP,
|
||||
KC_F7, KC_F8, KC_LSFT, KC_Z, KC_X, KC_C, KC_V, KC_B, KC_N, KC_M, KC_COMM, KC_DOT, KC_SLSH, KC_RSFT, KC_UP, KC_PGDN,
|
||||
KC_F9, KC_F10, MO(1), KC_LCTL, KC_LALT, KC_LGUI, KC_SPC, KC_SPC, MO(1), KC_RALT, KC_RCTL, KC_LEFT, KC_DOWN, KC_RGHT
|
||||
),
|
||||
[1] = LAYOUT(
|
||||
_______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______,
|
||||
RM_HUEU, RM_HUED, KC_GRV, KC_F1, KC_F2, KC_F3, KC_F4, KC_F5, KC_F6, KC_F7, KC_F8, KC_F9, KC_F10, KC_F11, KC_F12, _______, _______,
|
||||
RM_SATU, RM_SATD, RM_TOGG, RM_NEXT, KC_UP, _______, QK_BOOT, _______, _______, _______, _______, _______, _______, _______, _______, _______, KC_END,
|
||||
RM_VALU, RM_VALD, _______, KC_LEFT, KC_DOWN, KC_RGHT, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______,
|
||||
RM_SPDU, RM_SPDD, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______,
|
||||
_______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______
|
||||
)
|
||||
};
|
||||
27
keyboards/keebio/sinc_lm/readme.md
Normal file
27
keyboards/keebio/sinc_lm/readme.md
Normal file
@@ -0,0 +1,27 @@
|
||||
# Sinc LM
|
||||
|
||||
A split 75%/TKL staggered low-profile keyboard made and sold by Keebio. [More info at Keebio](https://keeb.io).
|
||||
|
||||
* Keyboard Maintainer: [Bakingpy/nooges](https://github.com/nooges)
|
||||
* Hardware Availability: [Keebio](https://keeb.io/)
|
||||
|
||||
Make example for this keyboard (after setting up your build environment):
|
||||
|
||||
make keebio/sinc_lm/rev1:default
|
||||
|
||||
Example of flashing this keyboard:
|
||||
|
||||
make keebio/sinc_lm/rev1:default:flash
|
||||
|
||||
Handedness detection is already hardwired onto the PCB, so no need to deal with `EE_HANDS` or flashing .eep files.
|
||||
|
||||
See the [build environment setup](https://docs.qmk.fm/#/getting_started_build_tools) and the [make instructions](https://docs.qmk.fm/#/getting_started_make_guide) for more information. Brand new to QMK? Start with our [Complete Newbs Guide](https://docs.qmk.fm/#/newbs).
|
||||
|
||||
## Bootloader
|
||||
|
||||
Enter the bootloader in one of these ways:
|
||||
|
||||
* **Physical reset button**: Press and hold the button on the back of the PCB for at least 2 seconds and let go, or double-press the button
|
||||
* **Keycode in layout**: Press the key mapped to `QK_BOOT` if it is available
|
||||
|
||||
A build guide for this keyboard can be found here: [Keebio Build Guides](https://docs.keeb.io)
|
||||
23
keyboards/keebio/sinc_lm/rev1/config.h
Normal file
23
keyboards/keebio/sinc_lm/rev1/config.h
Normal file
@@ -0,0 +1,23 @@
|
||||
// Copyright 2026 Keebio (@keebio)
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
/* Defines for the split keyboard setup */
|
||||
#define SERIAL_USART_DRIVER SD3 // USART 3
|
||||
#define SERIAL_USART_TX_PIN B10
|
||||
#define SERIAL_USART_RX_PIN B11
|
||||
#define SERIAL_USART_TX_PAL_MODE 7
|
||||
#define SERIAL_USART_RX_PAL_MODE 7
|
||||
#define SERIAL_USART_FULL_DUPLEX
|
||||
#define SERIAL_USART_PIN_SWAP
|
||||
|
||||
#define USB_VBUS_PIN C6
|
||||
|
||||
/* Defines for the RGB matrix */
|
||||
#define WS2812_PWM_DRIVER PWMD3
|
||||
#define WS2812_PWM_CHANNEL 4
|
||||
#define WS2812_PWM_PAL_MODE 10
|
||||
#define WS2812_DMA_STREAM STM32_DMA1_STREAM2
|
||||
#define WS2812_DMA_CHANNEL 2
|
||||
#define WS2812_DMAMUX_ID STM32_DMAMUX1_TIM3_UP
|
||||
10
keyboards/keebio/sinc_lm/rev1/halconf.h
Normal file
10
keyboards/keebio/sinc_lm/rev1/halconf.h
Normal file
@@ -0,0 +1,10 @@
|
||||
// Copyright 2026 Keebio (@keebio)
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#define HAL_USE_SERIAL TRUE
|
||||
|
||||
#define HAL_USE_PWM TRUE
|
||||
|
||||
#include_next <halconf.h>
|
||||
358
keyboards/keebio/sinc_lm/rev1/keyboard.json
Normal file
358
keyboards/keebio/sinc_lm/rev1/keyboard.json
Normal file
@@ -0,0 +1,358 @@
|
||||
{
|
||||
"manufacturer": "Keebio",
|
||||
"keyboard_name": "Sinc LM Rev. 1",
|
||||
"maintainer": "nooges",
|
||||
"bootloader": "stm32-dfu",
|
||||
"bootmagic": {
|
||||
"matrix": [0, 2]
|
||||
},
|
||||
"diode_direction": "COL2ROW",
|
||||
"features": {
|
||||
"bootmagic": true,
|
||||
"extrakey": true,
|
||||
"mousekey": true,
|
||||
"rgb_matrix": true
|
||||
},
|
||||
"matrix_pins": {
|
||||
"cols": ["B13", "B14", "B2", "F0", "C10", "B6", "C13", "C14", "C15"],
|
||||
"rows": ["B4", "C11", "B12", "B5", "F1", "B1"]
|
||||
},
|
||||
"processor": "STM32G431",
|
||||
"rgb_matrix": {
|
||||
"animations": {
|
||||
"alphas_mods": true,
|
||||
"gradient_up_down": true,
|
||||
"gradient_left_right": true,
|
||||
"breathing": true,
|
||||
"band_sat": true,
|
||||
"band_val": true,
|
||||
"band_pinwheel_sat": true,
|
||||
"band_pinwheel_val": true,
|
||||
"band_spiral_sat": true,
|
||||
"band_spiral_val": true,
|
||||
"cycle_all": true,
|
||||
"cycle_left_right": true,
|
||||
"cycle_up_down": true,
|
||||
"cycle_out_in": true,
|
||||
"cycle_out_in_dual": true,
|
||||
"rainbow_moving_chevron": true,
|
||||
"cycle_pinwheel": true,
|
||||
"cycle_spiral": true,
|
||||
"dual_beacon": true,
|
||||
"rainbow_beacon": true,
|
||||
"rainbow_pinwheels": true,
|
||||
"flower_blooming": true,
|
||||
"raindrops": true,
|
||||
"jellybean_raindrops": true,
|
||||
"hue_breathing": true,
|
||||
"hue_pendulum": true,
|
||||
"hue_wave": true,
|
||||
"pixel_fractal": true,
|
||||
"pixel_flow": true,
|
||||
"pixel_rain": true,
|
||||
"typing_heatmap": true,
|
||||
"digital_rain": true,
|
||||
"solid_reactive_simple": true,
|
||||
"solid_reactive": true,
|
||||
"solid_reactive_wide": true,
|
||||
"solid_reactive_multiwide": true,
|
||||
"solid_reactive_cross": true,
|
||||
"solid_reactive_multicross": true,
|
||||
"solid_reactive_nexus": true,
|
||||
"solid_reactive_multinexus": true,
|
||||
"splash": true,
|
||||
"multisplash": true,
|
||||
"solid_splash": true,
|
||||
"solid_multisplash": true,
|
||||
"starlight": true,
|
||||
"starlight_smooth": true,
|
||||
"starlight_dual_hue": true,
|
||||
"starlight_dual_sat": true,
|
||||
"riverflow": true
|
||||
},
|
||||
"driver": "ws2812",
|
||||
"layout": [
|
||||
{ "matrix": [5, 2], "x": 30, "y": 4, "flags": 4 },
|
||||
{ "x": 32, "y": 10, "flags": 2 },
|
||||
{ "matrix": [5, 3], "x": 45, "y": 4, "flags": 4 },
|
||||
{ "matrix": [5, 4], "x": 58, "y": 4, "flags": 4 },
|
||||
{ "matrix": [5, 5], "x": 70, "y": 4, "flags": 4 },
|
||||
{ "x": 76, "y": 2, "flags": 2 },
|
||||
{ "matrix": [5, 6], "x": 82, "y": 4, "flags": 4 },
|
||||
{ "matrix": [5, 7], "x": 97, "y": 4, "flags": 4 },
|
||||
{ "matrix": [5, 8], "x": 109, "y": 4, "flags": 4 },
|
||||
{ "x": 103, "y": 10, "flags": 2 },
|
||||
|
||||
{ "matrix": [0, 8], "x": 103, "y": 18, "flags": 4 },
|
||||
{ "matrix": [0, 7], "x": 91, "y": 18, "flags": 4 },
|
||||
{ "matrix": [0, 6], "x": 79, "y": 18, "flags": 4 },
|
||||
{ "matrix": [0, 5], "x": 67, "y": 18, "flags": 4 },
|
||||
{ "matrix": [0, 4], "x": 54, "y": 18, "flags": 4 },
|
||||
{ "matrix": [0, 3], "x": 42, "y": 18, "flags": 4 },
|
||||
{ "matrix": [0, 2], "x": 30, "y": 18, "flags": 4 },
|
||||
|
||||
{ "matrix": [1, 2], "x": 33, "y": 30, "flags": 4 },
|
||||
{ "matrix": [1, 3], "x": 48, "y": 30, "flags": 4 },
|
||||
{ "matrix": [1, 4], "x": 61, "y": 30, "flags": 4 },
|
||||
{ "matrix": [1, 5], "x": 73, "y": 30, "flags": 4 },
|
||||
{ "matrix": [1, 6], "x": 85, "y": 30, "flags": 4 },
|
||||
{ "matrix": [1, 7], "x": 97, "y": 30, "flags": 4 },
|
||||
|
||||
{ "matrix": [2, 7], "x": 100, "y": 41, "flags": 4 },
|
||||
{ "matrix": [2, 6], "x": 88, "y": 41, "flags": 4 },
|
||||
{ "matrix": [2, 5], "x": 76, "y": 41, "flags": 4 },
|
||||
{ "matrix": [2, 4], "x": 64, "y": 41, "flags": 4 },
|
||||
{ "matrix": [2, 3], "x": 51, "y": 41, "flags": 4 },
|
||||
{ "matrix": [2, 2], "x": 35, "y": 41, "flags": 4 },
|
||||
|
||||
{ "matrix": [3, 2], "x": 38, "y": 53, "flags": 4 },
|
||||
{ "matrix": [3, 4], "x": 58, "y": 53, "flags": 4 },
|
||||
{ "matrix": [3, 5], "x": 70, "y": 53, "flags": 4 },
|
||||
{ "matrix": [3, 6], "x": 82, "y": 53, "flags": 4 },
|
||||
{ "matrix": [3, 7], "x": 94, "y": 53, "flags": 4 },
|
||||
{ "x": 100, "y": 46, "flags": 2 },
|
||||
{ "matrix": [3, 8], "x": 106, "y": 53, "flags": 4 },
|
||||
|
||||
{ "matrix": [4, 7], "x": 98, "y": 64, "flags": 4 },
|
||||
{ "x": 85, "y": 64, "flags": 2 },
|
||||
{ "matrix": [4, 5], "x": 77, "y": 64, "flags": 4 },
|
||||
{ "matrix": [4, 4], "x": 62, "y": 64, "flags": 4 },
|
||||
{ "matrix": [4, 3], "x": 47, "y": 64, "flags": 4 },
|
||||
{ "x": 39, "y": 60, "flags": 4 },
|
||||
{ "matrix": [4, 2], "x": 32, "y": 64, "flags": 4 },
|
||||
|
||||
{ "matrix": [4, 1], "x": 12, "y": 64, "flags": 4 },
|
||||
{ "x": 6, "y": 60, "flags": 2 },
|
||||
{ "matrix": [4, 0], "x": 0, "y": 64, "flags": 4 },
|
||||
{ "matrix": [3, 0], "x": 0, "y": 53, "flags": 4 },
|
||||
{ "matrix": [3, 1], "x": 12, "y": 53, "flags": 4 },
|
||||
{ "matrix": [2, 1], "x": 12, "y": 41, "flags": 4 },
|
||||
{ "matrix": [2, 0], "x": 0, "y": 41, "flags": 4 },
|
||||
{ "matrix": [1, 0], "x": 0, "y": 30, "flags": 4 },
|
||||
{ "matrix": [1, 1], "x": 12, "y": 30, "flags": 4 },
|
||||
{ "matrix": [0, 1], "x": 12, "y": 18, "flags": 4 },
|
||||
{ "matrix": [0, 0], "x": 0, "y": 18, "flags": 4 },
|
||||
{ "matrix": [5, 0], "x": 0, "y": 4, "flags": 4 },
|
||||
{ "x": 6, "y": 2, "flags": 2 },
|
||||
{ "matrix": [5, 1], "x": 12, "y": 4, "flags": 4 },
|
||||
|
||||
{ "x": 224, "y": 10, "flags": 2 },
|
||||
{ "matrix": [11, 8], "x": 224, "y": 4, "flags": 4 },
|
||||
{ "matrix": [11, 7], "x": 212, "y": 4, "flags": 4 },
|
||||
{ "matrix": [11, 6], "x": 197, "y": 4, "flags": 4 },
|
||||
{ "x": 191, "y": 10, "flags": 2 },
|
||||
{ "matrix": [11, 5], "x": 185, "y": 4, "flags": 4 },
|
||||
{ "matrix": [11, 4], "x": 173, "y": 4, "flags": 4 },
|
||||
{ "x": 166, "y": 10, "flags": 2 },
|
||||
{ "matrix": [11, 3], "x": 160, "y": 4, "flags": 4 },
|
||||
{ "matrix": [11, 2], "x": 145, "y": 4, "flags": 4 },
|
||||
{ "x": 139, "y": 10, "flags": 2 },
|
||||
{ "matrix": [11, 1], "x": 133, "y": 4, "flags": 4 },
|
||||
|
||||
{ "matrix": [6, 0], "x": 127, "y": 18, "flags": 4 },
|
||||
{ "matrix": [6, 1], "x": 139, "y": 18, "flags": 4 },
|
||||
{ "matrix": [6, 2], "x": 151, "y": 18, "flags": 4 },
|
||||
{ "matrix": [6, 3], "x": 163, "y": 18, "flags": 4 },
|
||||
{ "matrix": [6, 4], "x": 176, "y": 18, "flags": 4 },
|
||||
{ "matrix": [6, 5], "x": 188, "y": 18, "flags": 4 },
|
||||
{ "matrix": [6, 7], "x": 206, "y": 18, "flags": 4 },
|
||||
{ "matrix": [6, 8], "x": 224, "y": 18, "flags": 4 },
|
||||
|
||||
{ "matrix": [7, 8], "x": 224, "y": 30, "flags": 4 },
|
||||
{ "matrix": [7, 7], "x": 209, "y": 30, "flags": 4 },
|
||||
{ "matrix": [7, 6], "x": 194, "y": 30, "flags": 4 },
|
||||
{ "matrix": [7, 5], "x": 182, "y": 30, "flags": 4 },
|
||||
{ "matrix": [7, 4], "x": 170, "y": 30, "flags": 4 },
|
||||
{ "matrix": [7, 3], "x": 157, "y": 30, "flags": 4 },
|
||||
{ "matrix": [7, 2], "x": 145, "y": 30, "flags": 4 },
|
||||
{ "matrix": [7, 1], "x": 133, "y": 30, "flags": 4 },
|
||||
{ "matrix": [7, 0], "x": 121, "y": 30, "flags": 4 },
|
||||
|
||||
{ "matrix": [8, 0], "x": 124, "y": 41, "flags": 4 },
|
||||
{ "matrix": [8, 1], "x": 136, "y": 41, "flags": 4 },
|
||||
{ "matrix": [8, 2], "x": 148, "y": 41, "flags": 4 },
|
||||
{ "matrix": [8, 3], "x": 160, "y": 41, "flags": 4 },
|
||||
{ "matrix": [8, 4], "x": 173, "y": 41, "flags": 4 },
|
||||
{ "matrix": [8, 5], "x": 185, "y": 41, "flags": 4 },
|
||||
{ "matrix": [8, 7], "x": 204, "y": 41, "flags": 4 },
|
||||
{ "matrix": [8, 8], "x": 224, "y": 41, "flags": 4 },
|
||||
|
||||
{ "matrix": [9, 8], "x": 224, "y": 53, "flags": 4 },
|
||||
{ "matrix": [9, 7], "x": 212, "y": 53, "flags": 4 },
|
||||
{ "matrix": [9, 6], "x": 195, "y": 53, "flags": 4 },
|
||||
{ "matrix": [9, 4], "x": 179, "y": 53, "flags": 4 },
|
||||
{ "matrix": [9, 3], "x": 166, "y": 53, "flags": 4 },
|
||||
{ "matrix": [9, 2], "x": 154, "y": 53, "flags": 4 },
|
||||
{ "matrix": [9, 1], "x": 142, "y": 53, "flags": 4 },
|
||||
{ "matrix": [9, 0], "x": 130, "y": 53, "flags": 4 },
|
||||
|
||||
{ "x": 127, "y": 64, "flags": 2 },
|
||||
{ "matrix": [10, 1], "x": 141, "y": 64, "flags": 4 },
|
||||
{ "x": 157, "y": 64, "flags": 2 },
|
||||
{ "matrix": [10, 2], "x": 163, "y": 64, "flags": 4 },
|
||||
{ "matrix": [10, 3], "x": 176, "y": 64, "flags": 4 },
|
||||
{ "matrix": [10, 4], "x": 188, "y": 64, "flags": 4 },
|
||||
{ "x": 194, "y": 64, "flags": 2 },
|
||||
{ "matrix": [10, 6], "x": 200, "y": 64, "flags": 4 },
|
||||
{ "matrix": [10, 7], "x": 212, "y": 64, "flags": 4 },
|
||||
{ "x": 218, "y": 64, "flags": 2 },
|
||||
{ "matrix": [10, 8], "x": 224, "y": 64, "flags": 4 }
|
||||
],
|
||||
"max_brightness": 120,
|
||||
"sleep": true,
|
||||
"split_count": [57, 56]
|
||||
},
|
||||
"split": {
|
||||
"bootmagic": {
|
||||
"matrix": [11, 8]
|
||||
},
|
||||
"enabled": true,
|
||||
"handedness": {
|
||||
"pin": "A0"
|
||||
},
|
||||
|
||||
"matrix_pins": {
|
||||
"right": {
|
||||
"cols": ["B2", "A15", "A2", "A1", "A4", "B15", "B6", "C13", "C14"],
|
||||
"rows": ["B12", "B13", "B14", "B5", "F1", "B1"]
|
||||
}
|
||||
},
|
||||
"serial": {
|
||||
"driver": "usart"
|
||||
},
|
||||
"transport": {
|
||||
"sync": {
|
||||
"matrix_state": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"url": "https://keeb.io",
|
||||
"usb": {
|
||||
"device_version": "1.0.0",
|
||||
"pid": "0x1667",
|
||||
"vid": "0xCB10"
|
||||
},
|
||||
"ws2812": {
|
||||
"driver": "pwm",
|
||||
"pin": "B7"
|
||||
},
|
||||
"layouts": {
|
||||
"LAYOUT": {
|
||||
"layout": [
|
||||
{"label": "Mute", "matrix": [5, 0], "x": 0, "y": 0},
|
||||
{"label": "Play", "matrix": [5, 1], "x": 1, "y": 0},
|
||||
{"label": "Esc", "matrix": [5, 2], "x": 2.25, "y": 0},
|
||||
{"label": "F1", "matrix": [5, 3], "x": 3.5, "y": 0},
|
||||
{"label": "F2", "matrix": [5, 4], "x": 4.5, "y": 0},
|
||||
{"label": "F3", "matrix": [5, 5], "x": 5.5, "y": 0},
|
||||
{"label": "F4", "matrix": [5, 6], "x": 6.5, "y": 0},
|
||||
{"label": "F5", "matrix": [5, 7], "x": 7.75, "y": 0},
|
||||
{"label": "F6", "matrix": [5, 8], "x": 8.75, "y": 0},
|
||||
|
||||
{"label": "F7", "matrix": [11, 1], "x": 10.75, "y": 0},
|
||||
{"label": "F8", "matrix": [11, 2], "x": 11.75, "y": 0},
|
||||
{"label": "F9", "matrix": [11, 3], "x": 13, "y": 0},
|
||||
{"label": "F10", "matrix": [11, 4], "x": 14, "y": 0},
|
||||
{"label": "F11", "matrix": [11, 5], "x": 15, "y": 0},
|
||||
{"label": "F12", "matrix": [11, 6], "x": 16, "y": 0},
|
||||
{"label": "Volume Up", "matrix": [11, 7], "x": 17.25, "y": 0},
|
||||
{"label": "Volume Down", "matrix": [11, 8], "x": 18.25, "y": 0},
|
||||
|
||||
{"label": "F1", "matrix": [0, 0], "x": 0, "y": 1.25},
|
||||
{"label": "F2", "matrix": [0, 1], "x": 1, "y": 1.25},
|
||||
|
||||
{"label": "Grave", "matrix": [0, 2], "x": 2.25, "y": 1.25},
|
||||
{"label": "1", "matrix": [0, 3], "x": 3.25, "y": 1.25},
|
||||
{"label": "2", "matrix": [0, 4], "x": 4.25, "y": 1.25},
|
||||
{"label": "3", "matrix": [0, 5], "x": 5.25, "y": 1.25},
|
||||
{"label": "4", "matrix": [0, 6], "x": 6.25, "y": 1.25},
|
||||
{"label": "5", "matrix": [0, 7], "x": 7.25, "y": 1.25},
|
||||
{"label": "6", "matrix": [0, 8], "x": 8.25, "y": 1.25},
|
||||
|
||||
{"label": "7", "matrix": [6, 0], "x": 10.25, "y": 1.25},
|
||||
{"label": "8", "matrix": [6, 1], "x": 11.25, "y": 1.25},
|
||||
{"label": "9", "matrix": [6, 2], "x": 12.25, "y": 1.25},
|
||||
{"label": "0", "matrix": [6, 3], "x": 13.25, "y": 1.25},
|
||||
{"label": "-", "matrix": [6, 4], "x": 14.25, "y": 1.25},
|
||||
{"label": "=", "matrix": [6, 5], "x": 15.25, "y": 1.25},
|
||||
{"label": "Bksp", "matrix": [6, 7], "x": 16.25, "y": 1.25, "w": 2},
|
||||
{"label": "Del", "matrix": [6, 8], "x": 18.25, "y": 1.25},
|
||||
|
||||
{"label": "F3", "matrix": [1, 0], "x": 0, "y": 2.25},
|
||||
{"label": "F4", "matrix": [1, 1], "x": 1, "y": 2.25},
|
||||
|
||||
{"label": "Tab", "matrix": [1, 2], "x": 2.25, "y": 2.25, "w": 1.5},
|
||||
{"label": "Q", "matrix": [1, 3], "x": 3.75, "y": 2.25},
|
||||
{"label": "W", "matrix": [1, 4], "x": 4.75, "y": 2.25},
|
||||
{"label": "E", "matrix": [1, 5], "x": 5.75, "y": 2.25},
|
||||
{"label": "R", "matrix": [1, 6], "x": 6.75, "y": 2.25},
|
||||
{"label": "T", "matrix": [1, 7], "x": 7.75, "y": 2.25},
|
||||
|
||||
{"label": "Y", "matrix": [7, 0], "x": 9.75, "y": 2.25},
|
||||
{"label": "U", "matrix": [7, 1], "x": 10.75, "y": 2.25},
|
||||
{"label": "I", "matrix": [7, 2], "x": 11.75, "y": 2.25},
|
||||
{"label": "O", "matrix": [7, 3], "x": 12.75, "y": 2.25},
|
||||
{"label": "P", "matrix": [7, 4], "x": 13.75, "y": 2.25},
|
||||
{"label": "{", "matrix": [7, 5], "x": 14.75, "y": 2.25},
|
||||
{"label": "}", "matrix": [7, 6], "x": 15.75, "y": 2.25},
|
||||
{"label": "|", "matrix": [7, 7], "x": 16.75, "y": 2.25, "w": 1.5},
|
||||
{"label": "Home", "matrix": [7, 8], "x": 18.25, "y": 2.25},
|
||||
|
||||
{"label": "F5", "matrix": [2, 0], "x": 0, "y": 3.25},
|
||||
{"label": "F6", "matrix": [2, 1], "x": 1, "y": 3.25},
|
||||
|
||||
{"label": "Caps Lock", "matrix": [2, 2], "x": 2.25, "y": 3.25, "w": 1.75},
|
||||
{"label": "A", "matrix": [2, 3], "x": 4, "y": 3.25},
|
||||
{"label": "S", "matrix": [2, 4], "x": 5, "y": 3.25},
|
||||
{"label": "D", "matrix": [2, 5], "x": 6, "y": 3.25},
|
||||
{"label": "F", "matrix": [2, 6], "x": 7, "y": 3.25},
|
||||
{"label": "G", "matrix": [2, 7], "x": 8, "y": 3.25},
|
||||
|
||||
{"label": "H", "matrix": [8, 0], "x": 10, "y": 3.25},
|
||||
{"label": "J", "matrix": [8, 1], "x": 11, "y": 3.25},
|
||||
{"label": "K", "matrix": [8, 2], "x": 12, "y": 3.25},
|
||||
{"label": "L", "matrix": [8, 3], "x": 13, "y": 3.25},
|
||||
{"label": ":", "matrix": [8, 4], "x": 14, "y": 3.25},
|
||||
{"label": "\"", "matrix": [8, 5], "x": 15, "y": 3.25},
|
||||
{"label": "Enter", "matrix": [8, 7], "x": 16, "y": 3.25, "w": 2.25},
|
||||
{"label": "PgUp", "matrix": [8, 8], "x": 18.25, "y": 3.25},
|
||||
|
||||
{"label": "F7", "matrix": [3, 0], "x": 0, "y": 4.25},
|
||||
{"label": "F8", "matrix": [3, 1], "x": 1, "y": 4.25},
|
||||
|
||||
{"label": "Shift", "matrix": [3, 2], "x": 2.25, "y": 4.25, "w": 2.25},
|
||||
{"label": "Z", "matrix": [3, 4], "x": 4.5, "y": 4.25},
|
||||
{"label": "X", "matrix": [3, 5], "x": 5.5, "y": 4.25},
|
||||
{"label": "C", "matrix": [3, 6], "x": 6.5, "y": 4.25},
|
||||
{"label": "V", "matrix": [3, 7], "x": 7.5, "y": 4.25},
|
||||
{"label": "B", "matrix": [3, 8], "x": 8.5, "y": 4.25},
|
||||
|
||||
{"label": "N", "matrix": [9, 0], "x": 10.5, "y": 4.25},
|
||||
{"label": "M", "matrix": [9, 1], "x": 11.5, "y": 4.25},
|
||||
{"label": ",", "matrix": [9, 2], "x": 12.5, "y": 4.25},
|
||||
{"label": ".", "matrix": [9, 3], "x": 13.5, "y": 4.25},
|
||||
{"label": "/", "matrix": [9, 4], "x": 14.5, "y": 4.25},
|
||||
{"label": "Shift", "matrix": [9, 6], "x": 15.5, "y": 4.25, "w": 1.75},
|
||||
{"label": "Up", "matrix": [9, 7], "x": 17.25, "y": 4.25},
|
||||
{"label": "PgDn", "matrix": [9, 8], "x": 18.25, "y": 4.25},
|
||||
|
||||
{"label": "F9", "matrix": [4, 0], "x": 0, "y": 5.25},
|
||||
{"label": "F10", "matrix": [4, 1], "x": 1, "y": 5.25},
|
||||
|
||||
{"label": "Fn", "matrix": [4, 2], "x": 2.25, "y": 5.25, "w": 1.25},
|
||||
{"label": "Ctrl", "matrix": [4, 3], "x": 3.5, "y": 5.25, "w": 1.25},
|
||||
{"label": "Alt", "matrix": [4, 4], "x": 4.75, "y": 5.25, "w": 1.25},
|
||||
{"label": "Win", "matrix": [4, 5], "x": 6, "y": 5.25, "w": 1.25},
|
||||
{"label": "Space", "matrix": [4, 7], "x": 7.25, "y": 5.25, "w": 2.25},
|
||||
|
||||
{"label": "Space", "matrix": [10, 1], "x": 10.5, "y": 5.25, "w": 2.75},
|
||||
{"label": "Fn", "matrix": [10, 2], "x": 13.25, "y": 5.25},
|
||||
{"label": "Alt", "matrix": [10, 3], "x": 14.25, "y": 5.25},
|
||||
{"label": "Ctrl", "matrix": [10, 4], "x": 15.25, "y": 5.25},
|
||||
{"label": "Left", "matrix": [10, 6], "x": 16.25, "y": 5.25},
|
||||
{"label": "Down", "matrix": [10, 7], "x": 17.25, "y": 5.25},
|
||||
{"label": "Right", "matrix": [10, 8], "x": 18.25, "y": 5.25}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
14
keyboards/keebio/sinc_lm/rev1/mcuconf.h
Normal file
14
keyboards/keebio/sinc_lm/rev1/mcuconf.h
Normal file
@@ -0,0 +1,14 @@
|
||||
// Copyright 2026 Keebio (@keebio)
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include_next <mcuconf.h>
|
||||
|
||||
/* enable USART3, used for split comms */
|
||||
#undef STM32_SERIAL_USE_USART3
|
||||
#define STM32_SERIAL_USE_USART3 TRUE
|
||||
|
||||
/* enable TIM3, used for RGB LED PWM driver */
|
||||
#undef STM32_PWM_USE_TIM3
|
||||
#define STM32_PWM_USE_TIM3 TRUE
|
||||
11
keyboards/keebio/sinc_lm/rev1/rev1.c
Normal file
11
keyboards/keebio/sinc_lm/rev1/rev1.c
Normal file
@@ -0,0 +1,11 @@
|
||||
// Copyright 2026 Keebio (@keebio)
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "quantum.h"
|
||||
|
||||
void keyboard_pre_init_kb(void) {
|
||||
// Disable the PD peripheral in pre-init because its pins are being used in the matrix:
|
||||
PWR->CR3 |= PWR_CR3_UCPD_DBDIS;
|
||||
// Call the corresponding _user() function (see https://docs.qmk.fm/#/custom_quantum_functions)
|
||||
keyboard_pre_init_user();
|
||||
}
|
||||
@@ -18,3 +18,6 @@
|
||||
|
||||
/* Enable caps-lock LED */
|
||||
#define CAPS_LOCK_LED_INDEX 54
|
||||
|
||||
/* Enable num-lock LED */
|
||||
#define NUM_LOCK_LED_INDEX 33
|
||||
|
||||
@@ -21,3 +21,6 @@
|
||||
|
||||
/* Enable caps-lock LED */
|
||||
#define CAPS_LOCK_LED_INDEX 52
|
||||
|
||||
/* Enable num-lock LED */
|
||||
#define NUM_LOCK_LED_INDEX 31
|
||||
|
||||
@@ -18,3 +18,6 @@
|
||||
|
||||
/* Enable caps-lock LED */
|
||||
#define CAPS_LOCK_LED_INDEX 53
|
||||
|
||||
/* Enable num-lock LED */
|
||||
#define NUM_LOCK_LED_INDEX 33
|
||||
|
||||
@@ -21,3 +21,6 @@
|
||||
|
||||
/* Enable caps-lock LED */
|
||||
#define CAPS_LOCK_LED_INDEX 51
|
||||
|
||||
/* Enable num-lock LED */
|
||||
#define NUM_LOCK_LED_INDEX 31
|
||||
|
||||
@@ -30,7 +30,7 @@ bool dip_switch_update_kb(uint8_t index, bool active) {
|
||||
|
||||
#endif // DIP_SWITCH_ENABLE
|
||||
|
||||
#if defined(RGB_MATRIX_ENABLE) && defined(CAPS_LOCK_LED_INDEX)
|
||||
#if defined(RGB_MATRIX_ENABLE) && (defined(CAPS_LOCK_LED_INDEX) || defined(NUM_LOCK_LED_INDEX))
|
||||
|
||||
bool process_record_kb(uint16_t keycode, keyrecord_t *record) {
|
||||
if (!process_record_user(keycode, record)) { return false; }
|
||||
@@ -69,6 +69,15 @@ bool rgb_matrix_indicators_advanced_kb(uint8_t led_min, uint8_t led_max) {
|
||||
RGB_MATRIX_INDICATOR_SET_COLOR(CAPS_LOCK_LED_INDEX, 0, 0, 0);
|
||||
}
|
||||
}
|
||||
#ifdef NUM_LOCK_LED_INDEX
|
||||
if (host_keyboard_led_state().num_lock) {
|
||||
RGB_MATRIX_INDICATOR_SET_COLOR(NUM_LOCK_LED_INDEX, 255, 255, 255);
|
||||
} else {
|
||||
if (!rgb_matrix_get_flags()) {
|
||||
RGB_MATRIX_INDICATOR_SET_COLOR(NUM_LOCK_LED_INDEX, 0, 0, 0);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
6
keyboards/nifty_numpad/config.h
Normal file
6
keyboards/nifty_numpad/config.h
Normal file
@@ -0,0 +1,6 @@
|
||||
// Copyright 2023 Isaac Rex (@Acliad)
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#define EECONFIG_KB_DATA_SIZE 10
|
||||
150
keyboards/nifty_numpad/keyboard.json
Normal file
150
keyboards/nifty_numpad/keyboard.json
Normal file
@@ -0,0 +1,150 @@
|
||||
{
|
||||
"manufacturer": "Isaac Rex",
|
||||
"keyboard_name": "Nifty Numpad",
|
||||
"maintainer": "Acliad",
|
||||
"bootloader": "rp2040",
|
||||
"diode_direction": "ROW2COL",
|
||||
"features": {
|
||||
"bootmagic": true,
|
||||
"command": false,
|
||||
"console": false,
|
||||
"extrakey": true,
|
||||
"mousekey": true,
|
||||
"nkro": true,
|
||||
"rgb_matrix": true
|
||||
},
|
||||
"matrix_pins": {
|
||||
"cols": ["GP17", "GP18", "GP15", "GP13", "GP14", "GP12"],
|
||||
"rows": ["GP20", "GP21", "GP22", "GP23", "GP24", "GP25"]
|
||||
},
|
||||
"processor": "RP2040",
|
||||
"rgb_matrix": {
|
||||
"animations": {
|
||||
"band_pinwheel_sat": true,
|
||||
"band_pinwheel_val": true,
|
||||
"band_sat": true,
|
||||
"band_spiral_sat": true,
|
||||
"band_spiral_val": true,
|
||||
"band_val": true,
|
||||
"breathing": true,
|
||||
"cycle_all": true,
|
||||
"cycle_left_right": true,
|
||||
"cycle_out_in": true,
|
||||
"cycle_out_in_dual": true,
|
||||
"cycle_pinwheel": true,
|
||||
"cycle_spiral": true,
|
||||
"cycle_up_down": true,
|
||||
"digital_rain": true,
|
||||
"dual_beacon": true,
|
||||
"gradient_up_down": true,
|
||||
"jellybean_raindrops": true,
|
||||
"multisplash": true,
|
||||
"rainbow_beacon": true,
|
||||
"rainbow_moving_chevron": true,
|
||||
"rainbow_pinwheels": true,
|
||||
"raindrops": true,
|
||||
"solid_multisplash": true,
|
||||
"solid_reactive": true,
|
||||
"solid_reactive_cross": true,
|
||||
"solid_reactive_multicross": true,
|
||||
"solid_reactive_multinexus": true,
|
||||
"solid_reactive_multiwide": true,
|
||||
"solid_reactive_nexus": true,
|
||||
"solid_reactive_simple": true,
|
||||
"solid_reactive_wide": true,
|
||||
"solid_splash": true,
|
||||
"splash": true,
|
||||
"typing_heatmap": false
|
||||
},
|
||||
"default": {
|
||||
"animation": "solid_color",
|
||||
"hue": 127,
|
||||
"speed": 100
|
||||
},
|
||||
"driver": "ws2812",
|
||||
"layout": [
|
||||
{"matrix": [0, 0], "x": 0, "y": 0, "flags": 4},
|
||||
{"matrix": [0, 1], "x": 43, "y": 0, "flags": 4},
|
||||
{"matrix": [0, 2], "x": 96, "y": 0, "flags": 4},
|
||||
{"matrix": [0, 3], "x": 139, "y": 0, "flags": 4},
|
||||
{"matrix": [0, 4], "x": 181, "y": 0, "flags": 4},
|
||||
{"matrix": [0, 5], "x": 224, "y": 0, "flags": 4},
|
||||
{"matrix": [1, 0], "x": 0, "y": 17, "flags": 4},
|
||||
{"matrix": [1, 1], "x": 43, "y": 17, "flags": 4},
|
||||
{"matrix": [1, 2], "x": 96, "y": 17, "flags": 4},
|
||||
{"matrix": [1, 3], "x": 139, "y": 17, "flags": 4},
|
||||
{"matrix": [1, 4], "x": 181, "y": 17, "flags": 4},
|
||||
{"matrix": [1, 5], "x": 224, "y": 17, "flags": 4},
|
||||
{"matrix": [2, 0], "x": 0, "y": 29, "flags": 4},
|
||||
{"matrix": [2, 1], "x": 43, "y": 29, "flags": 4},
|
||||
{"matrix": [2, 2], "x": 96, "y": 29, "flags": 4},
|
||||
{"matrix": [2, 3], "x": 139, "y": 29, "flags": 4},
|
||||
{"matrix": [2, 4], "x": 181, "y": 29, "flags": 4},
|
||||
{"matrix": [2, 5], "x": 224, "y": 35, "flags": 4},
|
||||
{"matrix": [3, 0], "x": 0, "y": 41, "flags": 4},
|
||||
{"matrix": [3, 1], "x": 43, "y": 41, "flags": 4},
|
||||
{"matrix": [3, 2], "x": 96, "y": 41, "flags": 4},
|
||||
{"matrix": [3, 3], "x": 139, "y": 41, "flags": 4},
|
||||
{"matrix": [3, 4], "x": 181, "y": 41, "flags": 4},
|
||||
{"matrix": [4, 0], "x": 0, "y": 52, "flags": 4},
|
||||
{"matrix": [4, 1], "x": 43, "y": 52, "flags": 4},
|
||||
{"matrix": [4, 2], "x": 96, "y": 52, "flags": 4},
|
||||
{"matrix": [4, 3], "x": 139, "y": 52, "flags": 4},
|
||||
{"matrix": [4, 4], "x": 181, "y": 52, "flags": 4},
|
||||
{"matrix": [4, 5], "x": 224, "y": 58, "flags": 4},
|
||||
{"matrix": [5, 0], "x": 0, "y": 64, "flags": 4},
|
||||
{"matrix": [5, 1], "x": 43, "y": 64, "flags": 4},
|
||||
{"matrix": [5, 2], "x": 117, "y": 64, "flags": 4},
|
||||
{"matrix": [5, 3], "x": 181, "y": 64, "flags": 4}
|
||||
]
|
||||
},
|
||||
"url": "https://gitlab.com/Acliad/nifty-numpad",
|
||||
"usb": {
|
||||
"device_version": "1.0.0",
|
||||
"pid": "0x0000",
|
||||
"vid": "0x4E4E"
|
||||
},
|
||||
"ws2812": {
|
||||
"driver": "vendor",
|
||||
"pin": "GP19"
|
||||
},
|
||||
"layouts": {
|
||||
"LAYOUT_numpad_6x6": {
|
||||
"layout": [
|
||||
{"label": "F13", "matrix": [0, 0], "x": 0, "y": 0},
|
||||
{"label": "F19", "matrix": [0, 1], "x": 1, "y": 0},
|
||||
{"label": "BACKSPACE", "matrix": [0, 2], "x": 2.25, "y": 0},
|
||||
{"label": "TASK VIEW", "matrix": [0, 3], "x": 3.25, "y": 0},
|
||||
{"label": "EXPLORER", "matrix": [0, 4], "x": 4.25, "y": 0},
|
||||
{"label": "SCREENSHOT", "matrix": [0, 5], "x": 5.25, "y": 0},
|
||||
{"label": "F14", "matrix": [1, 0], "x": 0, "y": 1.5},
|
||||
{"label": "F20", "matrix": [1, 1], "x": 1, "y": 1.5},
|
||||
{"label": "NUM LOCK", "matrix": [1, 2], "x": 2.25, "y": 1.5},
|
||||
{"label": "/", "matrix": [1, 3], "x": 3.25, "y": 1.5},
|
||||
{"label": "*", "matrix": [1, 4], "x": 4.25, "y": 1.5},
|
||||
{"label": "-", "matrix": [1, 5], "x": 5.25, "y": 1.5},
|
||||
{"label": "F15", "matrix": [2, 0], "x": 0, "y": 2.5},
|
||||
{"label": "F21", "matrix": [2, 1], "x": 1, "y": 2.5},
|
||||
{"label": "7", "matrix": [2, 2], "x": 2.25, "y": 2.5},
|
||||
{"label": "8", "matrix": [2, 3], "x": 3.25, "y": 2.5},
|
||||
{"label": "9", "matrix": [2, 4], "x": 4.25, "y": 2.5},
|
||||
{"label": "+", "matrix": [2, 5], "x": 5.25, "y": 2.5, "h": 2},
|
||||
{"label": "F16", "matrix": [3, 0], "x": 0, "y": 3.5},
|
||||
{"label": "F22", "matrix": [3, 1], "x": 1, "y": 3.5},
|
||||
{"label": "4", "matrix": [3, 2], "x": 2.25, "y": 3.5},
|
||||
{"label": "5", "matrix": [3, 3], "x": 3.25, "y": 3.5},
|
||||
{"label": "6", "matrix": [3, 4], "x": 4.25, "y": 3.5},
|
||||
{"label": "F17", "matrix": [4, 0], "x": 0, "y": 4.5},
|
||||
{"label": "F23", "matrix": [4, 1], "x": 1, "y": 4.5},
|
||||
{"label": "1", "matrix": [4, 2], "x": 2.25, "y": 4.5},
|
||||
{"label": "2", "matrix": [4, 3], "x": 3.25, "y": 4.5},
|
||||
{"label": "3", "matrix": [4, 4], "x": 4.25, "y": 4.5},
|
||||
{"label": "ENTER", "matrix": [4, 5], "x": 5.25, "y": 4.5, "h": 2},
|
||||
{"label": "F18", "matrix": [5, 0], "x": 0, "y": 5.5},
|
||||
{"label": "F24", "matrix": [5, 1], "x": 1, "y": 5.5},
|
||||
{"label": "0", "matrix": [5, 2], "x": 2.25, "y": 5.5, "w": 2},
|
||||
{"label": ".", "matrix": [5, 4], "x": 4.25, "y": 5.5}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
31
keyboards/nifty_numpad/keymaps/default/keymap.c
Normal file
31
keyboards/nifty_numpad/keymaps/default/keymap.c
Normal file
@@ -0,0 +1,31 @@
|
||||
// Copyright 2023 Isaac Rex (@Acliad)
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include QMK_KEYBOARD_H
|
||||
|
||||
// Layers
|
||||
// NOTE: LAYER_RGB is defined in nifty_numpad.h
|
||||
enum LAYERS {
|
||||
LAYER_BL,
|
||||
};
|
||||
|
||||
// Setup keymap
|
||||
const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
|
||||
[LAYER_BL] = LAYOUT_numpad_6x6(
|
||||
KC_F13, KC_F19, LT(LAYER_RGB, KC_BSPC), RGUI(KC_TAB), RGUI(KC_E), RGUI(RSFT(KC_S)),
|
||||
KC_F14, KC_F20, KC_NUM, KC_PSLS, KC_PAST, KC_PMNS,
|
||||
KC_F15, KC_F21, KC_P7, KC_P8, KC_P9, KC_PPLS,
|
||||
KC_F16, KC_F22, KC_P4, KC_P5, KC_P6,
|
||||
KC_F17, KC_F23, KC_P1, KC_P2, KC_P3, KC_PENT,
|
||||
KC_F18, KC_F24, KC_P0, KC_PDOT
|
||||
),
|
||||
|
||||
[LAYER_RGB] = LAYOUT_numpad_6x6(
|
||||
_______, _______, _______, RM_HUEU, RM_SATU, RM_VALU,
|
||||
_______, _______, _______, RM_HUED, RM_SATD, RM_VALD,
|
||||
_______, _______, _______, RM_NEXT, _______, RM_SPDU,
|
||||
_______, _______, _______, _______, _______,
|
||||
_______, _______, _______, _______, _______, RM_SPDD,
|
||||
_______, _______, _______, _______
|
||||
)
|
||||
};
|
||||
107
keyboards/nifty_numpad/keymaps/idle_rgb_example/keymap.c
Normal file
107
keyboards/nifty_numpad/keymaps/idle_rgb_example/keymap.c
Normal file
@@ -0,0 +1,107 @@
|
||||
// Copyright 2023 Isaac Rex (@Acliad)
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include QMK_KEYBOARD_H
|
||||
|
||||
// Layers
|
||||
// NOTE: LAYER_RGB is defined in nifty_numpad.h
|
||||
enum LAYERS {
|
||||
LAYER_BL = 0,
|
||||
LAYER_MOD,
|
||||
};
|
||||
|
||||
// Layer Indicator LED index
|
||||
#define _NUM_LED_INDEX 8
|
||||
|
||||
// Tap Dance Declarations
|
||||
enum {
|
||||
TD_NUM_TOGGLE = 0,
|
||||
TD_EDIT_GEN_TOGGLE,
|
||||
TD_M1,
|
||||
TD_M2,
|
||||
TD_M3,
|
||||
TD_M4,
|
||||
TD_M5,
|
||||
TD_M6,
|
||||
TD_M7,
|
||||
TD_M8,
|
||||
TD_M9,
|
||||
TD_M10,
|
||||
TD_M11,
|
||||
TD_M12,
|
||||
};
|
||||
|
||||
// TD function for 1 tap, toggle layer; 2 taps, press numlock
|
||||
void tap_dance_num_toggle(tap_dance_state_t *state, void *user_data){
|
||||
switch(state->count){
|
||||
case 1:
|
||||
layer_invert(LAYER_MOD);
|
||||
break;
|
||||
case 2:
|
||||
tap_code16(KC_NUM);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Tap Dance Definitions
|
||||
tap_dance_action_t tap_dance_actions[] = {
|
||||
[TD_NUM_TOGGLE] = ACTION_TAP_DANCE_FN(tap_dance_num_toggle),
|
||||
|
||||
[TD_M1] = ACTION_TAP_DANCE_DOUBLE(KC_F13, LCTL(KC_F13)),
|
||||
[TD_M2] = ACTION_TAP_DANCE_DOUBLE(KC_F14, LCTL(KC_F14)),
|
||||
[TD_M3] = ACTION_TAP_DANCE_DOUBLE(KC_F15, LCTL(KC_F15)),
|
||||
[TD_M4] = ACTION_TAP_DANCE_DOUBLE(KC_F16, LCTL(KC_F16)),
|
||||
[TD_M5] = ACTION_TAP_DANCE_DOUBLE(KC_F17, LCTL(KC_F17)),
|
||||
[TD_M6] = ACTION_TAP_DANCE_DOUBLE(KC_F18, LCTL(KC_F18)),
|
||||
[TD_M7] = ACTION_TAP_DANCE_DOUBLE(KC_F19, LCTL(KC_F19)),
|
||||
[TD_M8] = ACTION_TAP_DANCE_DOUBLE(KC_F20, LCTL(KC_F20)),
|
||||
[TD_M9] = ACTION_TAP_DANCE_DOUBLE(KC_F21, LCTL(KC_F21)),
|
||||
[TD_M10] = ACTION_TAP_DANCE_DOUBLE(KC_F22, LCTL(KC_F22)),
|
||||
[TD_M11] = ACTION_TAP_DANCE_DOUBLE(KC_F23, LCTL(KC_F23)),
|
||||
[TD_M12] = ACTION_TAP_DANCE_DOUBLE(KC_F24, LCTL(KC_F24))
|
||||
};
|
||||
|
||||
// Setup keymap
|
||||
const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
|
||||
[LAYER_BL] = LAYOUT_numpad_6x6(
|
||||
TD(TD_M1), TD(TD_M7) , LT(LAYER_RGB, KC_BSPC), RGUI(KC_TAB), RGUI(KC_E), RGUI(RSFT(KC_S)),
|
||||
TD(TD_M2), TD(TD_M8) , TD(TD_NUM_TOGGLE), KC_PSLS, KC_PAST, KC_PMNS,
|
||||
TD(TD_M3), TD(TD_M9) , KC_P7, KC_P8, KC_P9, KC_PPLS,
|
||||
TD(TD_M4), TD(TD_M10), KC_P4, KC_P5, KC_P6,
|
||||
TD(TD_M5), TD(TD_M11), KC_P1, KC_P2, KC_P3, KC_PENT,
|
||||
TD(TD_M6), TD(TD_M12), KC_P0, KC_PDOT
|
||||
),
|
||||
|
||||
[LAYER_MOD] = LAYOUT_numpad_6x6(
|
||||
_______, _______, KC_F9, KC_F10, KC_F11, KC_F12,
|
||||
_______, _______, TD(TD_NUM_TOGGLE), RCTL(KC_PSLS), RCTL(KC_PAST), _______,
|
||||
_______, _______, RCTL(KC_P7), RCTL(KC_P8), RCTL(KC_P9), _______,
|
||||
_______, _______, RCTL(KC_P4), RCTL(KC_P5), RCTL(KC_P6),
|
||||
_______, _______, RCTL(KC_P1), RCTL(KC_P2), RCTL(KC_P3), _______,
|
||||
_______, _______, RCTL(KC_P0), RCTL(KC_PDOT)
|
||||
),
|
||||
|
||||
[LAYER_RGB] = LAYOUT_numpad_6x6(
|
||||
_______, _______, _______, RM_HUEU, RM_SATU, RM_VALU,
|
||||
_______, _______, _______, RM_HUED, RM_SATD, RM_VALD,
|
||||
_______, _______, _______, RM_DMOD, RM_IMOD, RM_SPDU,
|
||||
_______, _______, _______, _______, _______,
|
||||
_______, _______, _______, _______, _______, RM_SPDD,
|
||||
_______, _______, _______, _______
|
||||
)
|
||||
};
|
||||
|
||||
// Set the layer toggle key to an indication of the active layer. This is a
|
||||
// bit janky and should be done better, but I'm trying to avoid scope creep.
|
||||
bool rgb_matrix_indicators_advanced_user(uint8_t led_min, uint8_t led_max) {
|
||||
if (layer_state_is(LAYER_MOD) && !rgb_matrix_idle_mode()) {
|
||||
// Get a hue that contrasts with current hue
|
||||
uint8_t hue = rgb_matrix_get_hue() + 127;
|
||||
// Make sure saturation is high enough to distiguish between hues
|
||||
uint8_t sat = 255;
|
||||
uint8_t val = MIN((uint16_t) rgb_matrix_get_val() + 50, 255);
|
||||
RGB rgb = hsv_to_rgb((HSV) {hue, sat, val});
|
||||
rgb_matrix_set_color(_NUM_LED_INDEX, rgb.r, rgb.g, rgb.b);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
2
keyboards/nifty_numpad/keymaps/idle_rgb_example/rules.mk
Normal file
2
keyboards/nifty_numpad/keymaps/idle_rgb_example/rules.mk
Normal file
@@ -0,0 +1,2 @@
|
||||
TAP_DANCE_ENABLE=yes
|
||||
RGB_IDLE_ENABLE=yes
|
||||
229
keyboards/nifty_numpad/nifty_numpad.c
Normal file
229
keyboards/nifty_numpad/nifty_numpad.c
Normal file
@@ -0,0 +1,229 @@
|
||||
/* Copyright 2023 Acliad
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include QMK_KEYBOARD_H
|
||||
|
||||
#ifdef RGB_IDLE_ENABLE
|
||||
typedef struct {
|
||||
uint8_t mode;
|
||||
uint8_t speed;
|
||||
HSV hsv;
|
||||
} rgb_matrix_state_t;
|
||||
|
||||
_Static_assert(sizeof(rgb_matrix_state_t) == 5, "Invalid size for rgb_matrix_state_t");
|
||||
|
||||
typedef struct {
|
||||
rgb_matrix_state_t active_rgb_matrix;
|
||||
rgb_matrix_state_t idle_rgb_matrix;
|
||||
} kb_config_t;
|
||||
|
||||
_Static_assert(sizeof(kb_config_t) == EECONFIG_KB_DATA_SIZE, "Invalid size for kb_config_t");
|
||||
|
||||
bool rgb_idle_mode = false;
|
||||
bool rgb_idle_edit_mode = false;
|
||||
static rgb_matrix_state_t active_rgb_matrix;
|
||||
static rgb_matrix_state_t idle_rgb_matrix;
|
||||
static kb_config_t config;
|
||||
|
||||
// Returns true if current RGB matrix mode is idle
|
||||
bool rgb_matrix_idle_mode(void) {
|
||||
return rgb_idle_mode;
|
||||
}
|
||||
|
||||
// Stores the current mode, HSV, and speed of the RGB matrix into state
|
||||
void rgb_matrix_state_save(rgb_matrix_state_t* state) {
|
||||
state->mode = rgb_matrix_get_mode();
|
||||
state->hsv = rgb_matrix_get_hsv();
|
||||
state->speed = rgb_matrix_get_speed();
|
||||
}
|
||||
|
||||
// Restores the mode, HSV, and speed of the RGB matrix from previous state
|
||||
void rgb_matrix_state_restore(rgb_matrix_state_t* state) {
|
||||
HSV hsv = state->hsv;
|
||||
rgb_matrix_mode_noeeprom(state->mode);
|
||||
rgb_matrix_sethsv_noeeprom(hsv.h, hsv.s, hsv.v);
|
||||
rgb_matrix_set_speed_noeeprom(state->speed);
|
||||
}
|
||||
#endif
|
||||
|
||||
void housekeeping_task_kb(void) {
|
||||
#ifdef RGB_IDLE_ENABLE
|
||||
// Check if enough time has passed since last keypress to go into idle mode
|
||||
if (last_input_activity_elapsed() > RGB_IDLE_TIMEOUT_MS && !rgb_idle_mode) {
|
||||
rgb_matrix_state_save(&active_rgb_matrix);
|
||||
rgb_idle_mode = true;
|
||||
|
||||
rgb_matrix_state_restore(&idle_rgb_matrix);
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
layer_state_t layer_state_set_kb(layer_state_t state) {
|
||||
#ifdef RGB_IDLE_ENABLE
|
||||
// Track if the last layer was the RGB edit layer
|
||||
static bool rgb_was_on = false;
|
||||
|
||||
if (IS_LAYER_ON_STATE(state, LAYER_RGB)) {
|
||||
rgb_was_on = true;
|
||||
}
|
||||
|
||||
// Not in RGB edit layer, but previously were
|
||||
if (!IS_LAYER_ON_STATE(state, LAYER_RGB) && rgb_was_on) {
|
||||
rgb_was_on = false;
|
||||
if (rgb_idle_edit_mode) {
|
||||
// If we were editing the RGB idle mode, we are done now.
|
||||
// Restore to active mode
|
||||
rgb_idle_edit_mode = false;
|
||||
rgb_matrix_state_restore(&active_rgb_matrix);
|
||||
}
|
||||
// Done changing stuff, save settings in "EEPROM"
|
||||
config.active_rgb_matrix = active_rgb_matrix;
|
||||
config.idle_rgb_matrix = idle_rgb_matrix;
|
||||
eeconfig_update_kb_datablock(&config, 0, EECONFIG_KB_DATA_SIZE);
|
||||
}
|
||||
#endif
|
||||
|
||||
return layer_state_set_user(state);
|
||||
}
|
||||
|
||||
// Process custom keycodes
|
||||
bool process_record_kb(uint16_t keycode, keyrecord_t* record) {
|
||||
#ifdef RGB_IDLE_ENABLE
|
||||
// If we were idling and a key was pressed, restore active RGB
|
||||
if (record->event.pressed) {
|
||||
if (rgb_idle_mode) {
|
||||
rgb_matrix_state_restore(&active_rgb_matrix);
|
||||
rgb_idle_mode = false;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
switch (keycode) {
|
||||
#ifdef RGB_IDLE_ENABLE
|
||||
// Handle all the RGB settings
|
||||
case RM_DMOD:
|
||||
if (record->event.pressed) {
|
||||
// Change the RGB matrix state to active if editing idle
|
||||
if (rgb_idle_edit_mode) {
|
||||
rgb_matrix_state_restore(&active_rgb_matrix);
|
||||
rgb_idle_edit_mode = false;
|
||||
}
|
||||
rgb_matrix_step_noeeprom();
|
||||
rgb_matrix_state_save(&active_rgb_matrix);
|
||||
}
|
||||
return false;
|
||||
case RM_IMOD:
|
||||
if (record->event.pressed) {
|
||||
// Change the RGB matrix state to idle
|
||||
if (!rgb_idle_edit_mode) {
|
||||
rgb_matrix_state_restore(&idle_rgb_matrix);
|
||||
rgb_idle_edit_mode = true;
|
||||
} else {
|
||||
rgb_matrix_step_noeeprom();
|
||||
rgb_matrix_state_save(&idle_rgb_matrix);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
case RM_SATU:
|
||||
if (record->event.pressed) {
|
||||
rgb_matrix_increase_sat_noeeprom();
|
||||
rgb_idle_edit_mode ? rgb_matrix_state_save(&idle_rgb_matrix) : rgb_matrix_state_save(&active_rgb_matrix);
|
||||
}
|
||||
return false;
|
||||
case RM_SATD:
|
||||
if (record->event.pressed) {
|
||||
rgb_matrix_decrease_sat_noeeprom();
|
||||
rgb_idle_edit_mode ? rgb_matrix_state_save(&idle_rgb_matrix) : rgb_matrix_state_save(&active_rgb_matrix);
|
||||
}
|
||||
return false;
|
||||
case RM_VALU:
|
||||
if (record->event.pressed) {
|
||||
rgb_matrix_increase_val_noeeprom();
|
||||
rgb_idle_edit_mode ? rgb_matrix_state_save(&idle_rgb_matrix) : rgb_matrix_state_save(&active_rgb_matrix);
|
||||
}
|
||||
return false;
|
||||
case RM_VALD:
|
||||
if (record->event.pressed) {
|
||||
rgb_matrix_decrease_val_noeeprom();
|
||||
rgb_idle_edit_mode ? rgb_matrix_state_save(&idle_rgb_matrix) : rgb_matrix_state_save(&active_rgb_matrix);
|
||||
}
|
||||
return false;
|
||||
case RM_HUEU:
|
||||
if (record->event.pressed) {
|
||||
rgb_matrix_increase_hue_noeeprom();
|
||||
rgb_idle_edit_mode ? rgb_matrix_state_save(&idle_rgb_matrix) : rgb_matrix_state_save(&active_rgb_matrix);
|
||||
}
|
||||
return false;
|
||||
case RM_HUED:
|
||||
if (record->event.pressed) {
|
||||
rgb_matrix_decrease_hue_noeeprom();
|
||||
rgb_idle_edit_mode ? rgb_matrix_state_save(&idle_rgb_matrix) : rgb_matrix_state_save(&active_rgb_matrix);
|
||||
}
|
||||
return false;
|
||||
case RM_SPDU:
|
||||
if (record->event.pressed) {
|
||||
rgb_matrix_increase_speed_noeeprom();
|
||||
rgb_idle_edit_mode ? rgb_matrix_state_save(&idle_rgb_matrix) : rgb_matrix_state_save(&active_rgb_matrix);
|
||||
}
|
||||
return false;
|
||||
case RM_SPDD:
|
||||
if (record->event.pressed) {
|
||||
rgb_matrix_decrease_speed_noeeprom();
|
||||
rgb_idle_edit_mode ? rgb_matrix_state_save(&idle_rgb_matrix) : rgb_matrix_state_save(&active_rgb_matrix);
|
||||
}
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
return process_record_user(keycode, record);
|
||||
};
|
||||
|
||||
void keyboard_post_init_kb(void) {
|
||||
#ifdef RGB_IDLE_ENABLE
|
||||
// Read in the RGB Matrices from before
|
||||
eeconfig_read_kb_datablock(&config, 0, EECONFIG_KB_DATA_SIZE);
|
||||
active_rgb_matrix = config.active_rgb_matrix;
|
||||
idle_rgb_matrix = config.idle_rgb_matrix;
|
||||
// Restore the active matrix
|
||||
rgb_matrix_state_restore(&active_rgb_matrix);
|
||||
#endif
|
||||
|
||||
keyboard_post_init_user();
|
||||
}
|
||||
|
||||
// Setup default EEPROM config values
|
||||
void eeconfig_init_kb_datablock(void) {
|
||||
#ifdef RGB_IDLE_ENABLE
|
||||
rgb_matrix_state_t default_active_rgb_matrix;
|
||||
rgb_matrix_state_t default_idle_rgb_matrix;
|
||||
|
||||
default_active_rgb_matrix.mode = RGB_MATRIX_GRADIENT_UP_DOWN;
|
||||
default_active_rgb_matrix.hsv = (HSV){127, 255, 100};
|
||||
default_active_rgb_matrix.speed = 127;
|
||||
|
||||
default_idle_rgb_matrix.mode = RGB_MATRIX_BREATHING;
|
||||
default_idle_rgb_matrix.hsv = (HSV){127, 255, 100};
|
||||
default_idle_rgb_matrix.speed = 127;
|
||||
|
||||
config.active_rgb_matrix = default_active_rgb_matrix;
|
||||
config.idle_rgb_matrix = default_idle_rgb_matrix;
|
||||
|
||||
eeconfig_update_kb_datablock(&config, 0, EECONFIG_KB_DATA_SIZE);
|
||||
|
||||
# if (EECONFIG_USER_DATA_SIZE) > 0
|
||||
eeconfig_init_user_datablock();
|
||||
# endif // EECONFIG_USER_DATA_SIZE
|
||||
#endif // RGB_IDLE_ENABLE
|
||||
}
|
||||
34
keyboards/nifty_numpad/nifty_numpad.h
Normal file
34
keyboards/nifty_numpad/nifty_numpad.h
Normal file
@@ -0,0 +1,34 @@
|
||||
/* Copyright 2023 Acliad
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "quantum.h"
|
||||
|
||||
enum custom_keycodes {
|
||||
RM_DMOD = QK_KB,
|
||||
RM_IMOD
|
||||
};
|
||||
#define LAYER_RGB (MAX_LAYER - 1)
|
||||
|
||||
#ifdef RGB_IDLE_ENABLE
|
||||
|
||||
#define RGB_IDLE_TIMEOUT_MS (10*60*1000)
|
||||
|
||||
// Functions exposed by nifty_numpad.c
|
||||
bool rgb_matrix_idle_mode(void);
|
||||
|
||||
#endif
|
||||
3
keyboards/nifty_numpad/post_rules.mk
Normal file
3
keyboards/nifty_numpad/post_rules.mk
Normal file
@@ -0,0 +1,3 @@
|
||||
ifeq ($(strip $(RGB_IDLE_ENABLE)), yes)
|
||||
OPT_DEFS += -DRGB_IDLE_ENABLE
|
||||
endif
|
||||
35
keyboards/nifty_numpad/readme.md
Normal file
35
keyboards/nifty_numpad/readme.md
Normal file
@@ -0,0 +1,35 @@
|
||||
# Nifty Numpad
|
||||
|
||||

|
||||
|
||||
Nifty Numpad is a full sized numpad with an extra row and two extra columns of macro keys. It was created because I wanted a companion to my TKL keyboard for work. My main workflow involves heavy use of ECAD programs, so the design was tailored for that, but it is generic enough to be nice for many workflows!
|
||||
|
||||
|
||||
The main features are:
|
||||
- Full sized numpad with row of macro/function keys on the top
|
||||
- Two extra columns of macro keys
|
||||
- Cherry MX style socketed switches
|
||||
- Key Backlights
|
||||
- 3D printable case (FDM or resin)
|
||||
|
||||
### Development Information:
|
||||
* Keyboard Maintainer: [Isaac Rex](https://github.com/Acliad/)
|
||||
* Hardware Supported: RP2040
|
||||
* Hardware Availability: See [The GitLab Page](https://gitlab.com/Acliad/nifty-numpad) for full details
|
||||
|
||||
Make example for this keyboard (after setting up your build environment):
|
||||
|
||||
make nifty_numpad:default
|
||||
|
||||
Flashing example for this keyboard:
|
||||
|
||||
make nifty_numpad:default:flash
|
||||
|
||||
See the [build environment setup](https://docs.qmk.fm/#/getting_started_build_tools) and the [make instructions](https://docs.qmk.fm/#/getting_started_make_guide) for more information. Brand new to QMK? Start with our [Complete Newbs Guide](https://docs.qmk.fm/#/newbs).
|
||||
|
||||
## Bootloader
|
||||
|
||||
Enter the bootloader in 2 ways:
|
||||
|
||||
* **Bootmagic reset**: Hold down the key at (0,0) in the matrix (top left) and plug in the keyboard
|
||||
* **Physical reset button**: Press the `RST` button while holding the `BOOT_SEL` button on the back of the PCB
|
||||
48
keyboards/pad9/keyboard.json
Normal file
48
keyboards/pad9/keyboard.json
Normal file
@@ -0,0 +1,48 @@
|
||||
{
|
||||
"manufacturer": "prkrln",
|
||||
"keyboard_name": "pad9",
|
||||
"maintainer": "prkrln",
|
||||
"diode_direction": "COL2ROW",
|
||||
"bootloader": "rp2040",
|
||||
"processor": "RP2040",
|
||||
"features": {
|
||||
"bootmagic": true,
|
||||
"encoder": true,
|
||||
"extrakey": true,
|
||||
"mousekey": true,
|
||||
"nkro": true
|
||||
},
|
||||
"encoder": {
|
||||
"rotary": [
|
||||
{"pin_a": "GP27", "pin_b": "GP26"}
|
||||
]
|
||||
},
|
||||
"matrix_pins": {
|
||||
"direct": [
|
||||
["GP6", "GP1", "GP3"],
|
||||
["GP29", "GP7", "GP4"],
|
||||
["GP28", "GP0", "GP2"]
|
||||
]
|
||||
},
|
||||
"usb": {
|
||||
"device_version": "1.0.0",
|
||||
"pid": "0x5009",
|
||||
"vid": "0x504B"
|
||||
},
|
||||
"community_layouts": ["ortho_3x3"],
|
||||
"layouts": {
|
||||
"LAYOUT_ortho_3x3": {
|
||||
"layout": [
|
||||
{"matrix": [0, 0], "x": 0, "y": 0, "encoder": 0},
|
||||
{"matrix": [0, 1], "x": 1, "y": 0},
|
||||
{"matrix": [0, 2], "x": 2, "y": 0},
|
||||
{"matrix": [1, 0], "x": 0, "y": 1},
|
||||
{"matrix": [1, 1], "x": 1, "y": 1},
|
||||
{"matrix": [1, 2], "x": 2, "y": 1},
|
||||
{"matrix": [2, 0], "x": 0, "y": 2},
|
||||
{"matrix": [2, 1], "x": 1, "y": 2},
|
||||
{"matrix": [2, 2], "x": 2, "y": 2}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
18
keyboards/pad9/keymaps/default/keymap.c
Normal file
18
keyboards/pad9/keymaps/default/keymap.c
Normal file
@@ -0,0 +1,18 @@
|
||||
// Copyright 2023 QMK
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include QMK_KEYBOARD_H
|
||||
|
||||
#if defined(ENCODER_MAP_ENABLE)
|
||||
const uint16_t PROGMEM encoder_map[][NUM_ENCODERS][NUM_DIRECTIONS] = {
|
||||
[0] = { ENCODER_CCW_CW(KC_VOLD, KC_VOLU) },
|
||||
};
|
||||
#endif
|
||||
|
||||
const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
|
||||
[0] = LAYOUT_ortho_3x3(
|
||||
KC_1, KC_2, KC_3,
|
||||
KC_4, KC_5, KC_6,
|
||||
KC_7, KC_8, KC_9
|
||||
)
|
||||
};
|
||||
1
keyboards/pad9/keymaps/default/rules.mk
Normal file
1
keyboards/pad9/keymaps/default/rules.mk
Normal file
@@ -0,0 +1 @@
|
||||
ENCODER_MAP_ENABLE = yes
|
||||
26
keyboards/pad9/readme.md
Normal file
26
keyboards/pad9/readme.md
Normal file
@@ -0,0 +1,26 @@
|
||||
# pad9
|
||||
|
||||

|
||||
A cheap small macropad with the mcu underneath the switches.
|
||||
|
||||
* Keyboard Maintainer: [prkrln](https://github.com/prkrln)
|
||||
* Hardware Supported: [XAIO RP2040](https://wiki.seeedstudio.com/XIAO-RP2040)
|
||||
* Hardware Availability: [Seeed](https://www.seeedstudio.com/XIAO-RP2040-v1-0-p-5026.html), [Digikey](https://www.digikey.com/en/products/detail/seeed-technology-co-ltd/102010428/14672129)
|
||||
|
||||
Make example for this keyboard (after setting up your build environment):
|
||||
|
||||
make pad9:default
|
||||
|
||||
Flashing example for this keyboard:
|
||||
|
||||
make pad9:default:flash
|
||||
|
||||
See the [build environment setup](https://docs.qmk.fm/#/getting_started_build_tools) and the [make instructions](https://docs.qmk.fm/#/getting_started_make_guide) for more information. Brand new to QMK? Start with our [Complete Newbs Guide](https://docs.qmk.fm/#/newbs).
|
||||
|
||||
## Bootloader
|
||||
|
||||
Enter the bootloader in 3 ways:
|
||||
|
||||
* **Bootmagic reset**: Hold down the encoder or top left key and plug in the keyboard
|
||||
* **Physical reset button**: Briefly press the button on the back of the MCU
|
||||
* **Keycode in layout**: Press the key mapped to `QK_BOOT` if it is available
|
||||
@@ -45,7 +45,7 @@ def strip_multiline_comment(string):
|
||||
|
||||
|
||||
def c_source_files(dir_names):
|
||||
"""Returns a list of all *.c, *.h, and *.cpp files for a given list of directories
|
||||
"""Returns a list of all *.c, *.h, *.cpp, and *.hpp files for a given list of directories
|
||||
|
||||
Args:
|
||||
|
||||
@@ -54,7 +54,7 @@ def c_source_files(dir_names):
|
||||
"""
|
||||
files = []
|
||||
for dir in dir_names:
|
||||
files.extend(file for file in Path(dir).glob('**/*') if file.suffix in ['.c', '.h', '.cpp'])
|
||||
files.extend(file for file in Path(dir).glob('**/*') if file.suffix in ['.c', '.h', '.cpp', '.hpp'])
|
||||
return files
|
||||
|
||||
|
||||
|
||||
@@ -56,6 +56,7 @@ safe_commands = [
|
||||
|
||||
subcommands = [
|
||||
'qmk.cli.ci.validate_aliases',
|
||||
'qmk.cli.ci.validate_keyboard_targets',
|
||||
'qmk.cli.bux',
|
||||
'qmk.cli.c2json',
|
||||
'qmk.cli.cd',
|
||||
|
||||
28
lib/python/qmk/cli/ci/validate_keyboard_targets.py
Normal file
28
lib/python/qmk/cli/ci/validate_keyboard_targets.py
Normal file
@@ -0,0 +1,28 @@
|
||||
"""Validates the list of keyboard targets.
|
||||
"""
|
||||
from milc import cli
|
||||
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
@cli.subcommand('Validates the list of keyboard targets.', hidden=True)
|
||||
def ci_validate_keyboard_targets(cli):
|
||||
errors = set()
|
||||
|
||||
for rules_mk in Path('keyboards').glob('**/rules.mk'):
|
||||
if any({'keymaps', 'common', 'lib'} & set(rules_mk.parts)):
|
||||
continue
|
||||
|
||||
folder = rules_mk.parent
|
||||
if not any(folder.glob('**/keyboard.json')):
|
||||
errors.add(folder)
|
||||
|
||||
for keymap in Path('keyboards').glob('**/keymaps/'):
|
||||
folder = keymap.parent
|
||||
if not any(folder.glob('**/keyboard.json')):
|
||||
errors.add(folder)
|
||||
|
||||
for error in errors:
|
||||
print(f"{error}::Legacy target detected")
|
||||
|
||||
exit(min(len(errors), 255))
|
||||
@@ -1,62 +1,23 @@
|
||||
"""OS-specific functions for: Linux
|
||||
"""
|
||||
import platform
|
||||
import shutil
|
||||
from pathlib import Path
|
||||
|
||||
from milc import cli
|
||||
|
||||
from qmk.constants import QMK_FIRMWARE, BOOTLOADER_VIDS_PIDS
|
||||
from qmk.constants import QMK_FIRMWARE
|
||||
from .check import CheckStatus, release_info
|
||||
|
||||
QMK_UDEV_INSTALL_SCRIPT = 'util/install_udev.sh'
|
||||
|
||||
|
||||
def _is_wsl():
|
||||
return 'microsoft' in platform.uname().release.lower()
|
||||
|
||||
|
||||
def _udev_rule(vid, pid=None, *args):
|
||||
""" Helper function that return udev rules
|
||||
"""
|
||||
rule = ""
|
||||
if pid:
|
||||
rule = 'SUBSYSTEMS=="usb", ATTRS{idVendor}=="%s", ATTRS{idProduct}=="%s", TAG+="uaccess"' % (
|
||||
vid,
|
||||
pid,
|
||||
)
|
||||
else:
|
||||
rule = 'SUBSYSTEMS=="usb", ATTRS{idVendor}=="%s", TAG+="uaccess"' % vid
|
||||
if args:
|
||||
rule = ', '.join([rule, *args])
|
||||
return rule
|
||||
|
||||
|
||||
def _generate_desired_rules(bootloader_vids_pids):
|
||||
rules = dict()
|
||||
for bl in bootloader_vids_pids.keys():
|
||||
rules[bl] = set()
|
||||
for vid_pid in bootloader_vids_pids[bl]:
|
||||
if bl == 'caterina' or bl == 'md-boot':
|
||||
rules[bl].add(_udev_rule(vid_pid[0], vid_pid[1], 'ENV{ID_MM_DEVICE_IGNORE}="1"'))
|
||||
else:
|
||||
rules[bl].add(_udev_rule(vid_pid[0], vid_pid[1]))
|
||||
return rules
|
||||
|
||||
|
||||
def _deprecated_udev_rule(vid, pid=None):
|
||||
""" Helper function that return udev rules
|
||||
|
||||
Note: these are no longer the recommended rules, this is just used to check for them
|
||||
"""
|
||||
if pid:
|
||||
return 'SUBSYSTEMS=="usb", ATTRS{idVendor}=="%s", ATTRS{idProduct}=="%s", MODE:="0666"' % (vid, pid)
|
||||
else:
|
||||
return 'SUBSYSTEMS=="usb", ATTRS{idVendor}=="%s", MODE:="0666"' % vid
|
||||
|
||||
|
||||
def check_udev_rules():
|
||||
"""Make sure the udev rules look good.
|
||||
"""
|
||||
rc = CheckStatus.OK
|
||||
udev_dirs = [
|
||||
Path("/usr/lib/udev/rules.d/"),
|
||||
Path("/usr/local/lib/udev/rules.d/"),
|
||||
@@ -64,24 +25,15 @@ def check_udev_rules():
|
||||
Path("/etc/udev/rules.d/"),
|
||||
]
|
||||
|
||||
desired_rules = _generate_desired_rules(BOOTLOADER_VIDS_PIDS)
|
||||
if not any(udev_dir.exists() for udev_dir in udev_dirs):
|
||||
cli.log.warning("{fg_yellow}Can't find udev rules directories, skipping udev rule checking...")
|
||||
cli.log.debug("Checked directories: %s", ', '.join(str(udev_dir) for udev_dir in udev_dirs))
|
||||
return CheckStatus.WARNING
|
||||
|
||||
# These rules are no longer recommended, only use them to check for their presence.
|
||||
deprecated_rules = {
|
||||
'atmel-dfu': {_deprecated_udev_rule("03eb", "2ff4"), _deprecated_udev_rule("03eb", "2ffb"), _deprecated_udev_rule("03eb", "2ff0")},
|
||||
'kiibohd': {_deprecated_udev_rule("1c11")},
|
||||
'stm32': {_deprecated_udev_rule("1eaf", "0003"), _deprecated_udev_rule("0483", "df11")},
|
||||
'bootloadhid': {_deprecated_udev_rule("16c0", "05df")},
|
||||
'caterina': {'ATTRS{idVendor}=="2a03", ENV{ID_MM_DEVICE_IGNORE}="1"', 'ATTRS{idVendor}=="2341", ENV{ID_MM_DEVICE_IGNORE}="1"'},
|
||||
'tmk': {_deprecated_udev_rule("feed")}
|
||||
}
|
||||
|
||||
if any(udev_dir.exists() for udev_dir in udev_dirs):
|
||||
udev_rules = [rule_file for udev_dir in udev_dirs for rule_file in udev_dir.glob('*.rules')]
|
||||
current_rules = set()
|
||||
|
||||
# Collect all rules from the config files
|
||||
for rule_file in udev_rules:
|
||||
# Collect all non-comment lines from QMK-related rules files
|
||||
current_rules = set()
|
||||
for udev_dir in udev_dirs:
|
||||
for rule_file in udev_dir.glob('*qmk*'):
|
||||
try:
|
||||
for line in rule_file.read_text(encoding='utf-8').split('\n'):
|
||||
line = line.strip()
|
||||
@@ -90,45 +42,17 @@ def check_udev_rules():
|
||||
except (PermissionError, FileNotFoundError):
|
||||
cli.log.debug("Failed to read: %s", rule_file)
|
||||
|
||||
# Check if the desired rules are among the currently present rules
|
||||
for bootloader, rules in desired_rules.items():
|
||||
if not rules.issubset(current_rules):
|
||||
deprecated_rule = deprecated_rules.get(bootloader)
|
||||
if deprecated_rule and deprecated_rule.issubset(current_rules):
|
||||
cli.log.warning("{fg_yellow}Found old, deprecated udev rules for '%s' boards. The new rules on https://docs.qmk.fm/#/faq_build?id=linux-udev-rules offer better security with the same functionality.", bootloader)
|
||||
else:
|
||||
# For caterina, check if ModemManager is running
|
||||
if bootloader == "caterina" and check_modem_manager():
|
||||
cli.log.warning("{fg_yellow}Detected ModemManager without the necessary udev rules. Please either disable it or set the appropriate udev rules if you are using a Pro Micro.")
|
||||
if not current_rules:
|
||||
cli.log.warning("{fg_yellow}Missing udev rules for QMK boards. Please run '%s' to install the rules", QMK_UDEV_INSTALL_SCRIPT)
|
||||
return CheckStatus.WARNING
|
||||
|
||||
rc = CheckStatus.WARNING
|
||||
cli.log.warning("{fg_yellow}Missing or outdated udev rules for '%s' boards. Run 'sudo cp %s/util/udev/50-qmk.rules /etc/udev/rules.d/'.", bootloader, QMK_FIRMWARE)
|
||||
# Check for the qmk_udev ID_QMK marker
|
||||
if any('ID_QMK' in rule for rule in current_rules):
|
||||
return CheckStatus.OK
|
||||
|
||||
else:
|
||||
cli.log.warning("{fg_yellow}Can't find udev rules, skipping udev rule checking...")
|
||||
cli.log.debug("Checked directories: %s", ', '.join(str(udev_dir) for udev_dir in udev_dirs))
|
||||
|
||||
return rc
|
||||
|
||||
|
||||
def check_systemd():
|
||||
"""Check if it's a systemd system
|
||||
"""
|
||||
return bool(shutil.which("systemctl"))
|
||||
|
||||
|
||||
def check_modem_manager():
|
||||
"""Returns True if ModemManager is running.
|
||||
|
||||
"""
|
||||
if check_systemd():
|
||||
mm_check = cli.run(["systemctl", "--quiet", "is-active", "ModemManager.service"], timeout=10)
|
||||
if mm_check.returncode == 0:
|
||||
return True
|
||||
else:
|
||||
"""(TODO): Add check for non-systemd systems
|
||||
"""
|
||||
return False
|
||||
# Legacy rules found (TAG+="uaccess" without ID_QMK)
|
||||
cli.log.warning("{fg_yellow}Found legacy udev rules. Please run '%s' to install the latest rules", QMK_UDEV_INSTALL_SCRIPT)
|
||||
return CheckStatus.WARNING
|
||||
|
||||
|
||||
def os_test_linux():
|
||||
|
||||
@@ -18,8 +18,8 @@ from qmk.makefile import parse_rules_mk_file
|
||||
from qmk.math_ops import compute
|
||||
from qmk.util import maybe_exit, truthy
|
||||
|
||||
true_values = ['1', 'on', 'yes']
|
||||
false_values = ['0', 'off', 'no']
|
||||
TRUE_VALUES = ['true', '1', 'on', 'yes']
|
||||
FALSE_VALUES = ['false', '0', 'off', 'no']
|
||||
|
||||
|
||||
class LedFlags(IntFlag):
|
||||
@@ -319,7 +319,7 @@ def _extract_features(info_data, rules):
|
||||
for key, value in rules.items():
|
||||
if key.endswith('_ENABLE'):
|
||||
key = '_'.join(key.split('_')[:-1]).lower()
|
||||
value = True if value.lower() in true_values else False if value.lower() in false_values else value
|
||||
value = True if value.lower() in TRUE_VALUES else False if value.lower() in FALSE_VALUES else value
|
||||
|
||||
if key in ['lto']:
|
||||
continue
|
||||
@@ -657,7 +657,7 @@ def _config_to_json(key_type, config_value):
|
||||
elif key_type in ['bool', 'flag']:
|
||||
if isinstance(config_value, bool):
|
||||
return config_value
|
||||
return config_value in true_values
|
||||
return config_value in TRUE_VALUES
|
||||
|
||||
elif key_type == 'hex':
|
||||
return '0x' + config_value[2:].upper()
|
||||
|
||||
@@ -19,21 +19,21 @@
|
||||
#include <ostream>
|
||||
#include "gmock/gmock.h"
|
||||
|
||||
bool operator==(const report_keyboard_t& lhs, const report_keyboard_t& rhs);
|
||||
bool operator==(const report_keyboard_t& lhs, const report_keyboard_t& rhs);
|
||||
std::ostream& operator<<(std::ostream& stream, const report_keyboard_t& value);
|
||||
|
||||
class KeyboardReportMatcher : public testing::MatcherInterface<report_keyboard_t&> {
|
||||
public:
|
||||
public:
|
||||
KeyboardReportMatcher(const std::vector<uint8_t>& keys);
|
||||
virtual bool MatchAndExplain(report_keyboard_t& report, testing::MatchResultListener* listener) const override;
|
||||
virtual void DescribeTo(::std::ostream* os) const override;
|
||||
virtual void DescribeNegationTo(::std::ostream* os) const override;
|
||||
private:
|
||||
|
||||
private:
|
||||
report_keyboard_t m_report;
|
||||
};
|
||||
|
||||
|
||||
template<typename... Ts>
|
||||
template <typename... Ts>
|
||||
inline testing::Matcher<report_keyboard_t&> KeyboardReport(Ts... keys) {
|
||||
return testing::MakeMatcher(new KeyboardReportMatcher(std::vector<uint8_t>({keys...})));
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
|
||||
class TestLogger : public std::ostream {
|
||||
public:
|
||||
TestLogger() : std::ostream(&m_log){};
|
||||
TestLogger() : std::ostream(&m_log) {};
|
||||
TestLogger& info();
|
||||
TestLogger& trace();
|
||||
TestLogger& error();
|
||||
|
||||
@@ -357,7 +357,7 @@ __EOT__
|
||||
|
||||
install_uv() {
|
||||
# Install `uv` (or update as necessary)
|
||||
download_url https://astral.sh/uv/install.sh - | TMPDIR="$(windows_ish_path "${TMPDIR:-}")" UV_INSTALL_DIR="$(windows_ish_path "${UV_INSTALL_DIR:-}")" sh
|
||||
download_url https://astral.sh/uv/install.sh - | TMPDIR="$(posix_ish_path "${TMPDIR:-}")" UV_INSTALL_DIR="$(windows_ish_path "${UV_INSTALL_DIR:-}")" sh
|
||||
}
|
||||
|
||||
setup_paths() {
|
||||
@@ -464,27 +464,49 @@ __EOT__
|
||||
}
|
||||
|
||||
install_linux_udev_rules() {
|
||||
# Download the udev rules to the toolchains location
|
||||
echo "Downloading QMK udev rules file..." >&2
|
||||
local qmk_rules_target_file="$QMK_DISTRIB_DIR/50-qmk.rules"
|
||||
download_url "https://raw.githubusercontent.com/qmk/qmk_firmware/refs/heads/master/util/udev/50-qmk.rules" "$qmk_rules_target_file"
|
||||
# Get the latest qmk_udev release
|
||||
local latest_udev_release=$(github_api_call repos/qmk/qmk_udev/releases/latest - | grep -oE '"tag_name": "[^"]+' | grep -oE '[^"]+$')
|
||||
if [ -z "$latest_udev_release" ]; then
|
||||
echo "Could not determine latest qmk_udev release." >&2
|
||||
exit 1
|
||||
fi
|
||||
echo "Using qmk_udev release: $latest_udev_release" >&2
|
||||
|
||||
# Install the udev rules -- path list is aligned with qmk doctor's linux.py
|
||||
local udev_rules_paths="
|
||||
/usr/lib/udev/rules.d
|
||||
/usr/local/lib/udev/rules.d
|
||||
/run/udev/rules.d
|
||||
/etc/udev/rules.d
|
||||
"
|
||||
for udev_rules_dir in $udev_rules_paths; do
|
||||
if [ -d "$udev_rules_dir" ]; then
|
||||
echo "Installing udev rules to $udev_rules_dir/50-qmk.rules ..." >&2
|
||||
$(nsudo) mv "$qmk_rules_target_file" "$udev_rules_dir"
|
||||
$(nsudo) chown 0:0 "$udev_rules_dir/50-qmk.rules"
|
||||
$(nsudo) chmod 644 "$udev_rules_dir/50-qmk.rules"
|
||||
break
|
||||
# Download the udev rules file
|
||||
local qmk_rules_file="$QMK_DISTRIB_DIR/50-qmk.rules"
|
||||
local release_base="https://github.com/qmk/qmk_udev/releases/download/$latest_udev_release"
|
||||
download_url "$release_base/50-qmk.rules" "$qmk_rules_file"
|
||||
|
||||
# Download the architecture-appropriate qmk_id binary
|
||||
local arch="$(fn_arch)"
|
||||
local qmk_id_file="$QMK_DISTRIB_DIR/qmk_id"
|
||||
download_url "$release_base/qmk_id-linux${arch}" "$qmk_id_file"
|
||||
|
||||
# Remove existing QMK udev rules and qmk_id helpers from all standard locations
|
||||
echo "Removing existing QMK udev rules and helpers..." >&2
|
||||
for dir in /etc/udev/rules.d /run/udev/rules.d /usr/lib/udev/rules.d /usr/local/lib/udev/rules.d /lib/udev/rules.d; do
|
||||
if [ -d "$dir" ]; then
|
||||
for f in "$dir"/*-qmk.rules; do
|
||||
[ -e "$f" ] && echo "Removing $f" >&2 && $(nsudo) rm -f "$f"
|
||||
done
|
||||
fi
|
||||
done
|
||||
for dir in /usr/lib/udev /usr/local/lib/udev /lib/udev; do
|
||||
[ -e "$dir/qmk_id" ] && echo "Removing $dir/qmk_id" >&2 && $(nsudo) rm -f "$dir/qmk_id"
|
||||
done
|
||||
|
||||
# Install qmk_id binary
|
||||
echo "Installing /usr/lib/udev/qmk_id ..." >&2
|
||||
$(nsudo) install -d -m 0755 /usr/lib/udev
|
||||
$(nsudo) install -m 0755 "$qmk_id_file" /usr/lib/udev/qmk_id
|
||||
|
||||
# Install udev rules
|
||||
echo "Installing /etc/udev/rules.d/50-qmk.rules ..." >&2
|
||||
$(nsudo) install -d -m 0755 /etc/udev/rules.d
|
||||
$(nsudo) install -m 0644 "$qmk_rules_file" /etc/udev/rules.d/50-qmk.rules
|
||||
|
||||
# Clean up downloaded files
|
||||
rm -f "$qmk_rules_file" "$qmk_id_file" || true
|
||||
|
||||
# Reload udev rules
|
||||
if command -v udevadm >/dev/null 2>&1; then
|
||||
|
||||
126
util/install_udev.sh
Executable file
126
util/install_udev.sh
Executable file
@@ -0,0 +1,126 @@
|
||||
#!/usr/bin/env sh
|
||||
# Copyright 2025 Nick Brassel (@tzarc)
|
||||
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
################################################################################
|
||||
# Installs the latest QMK udev rules and qmk_id helper from
|
||||
# https://github.com/qmk/qmk_udev
|
||||
################################################################################
|
||||
|
||||
set -e
|
||||
|
||||
nsudo() {
|
||||
if [ "$(id -u)" -ne 0 ]; then
|
||||
if [ -n "$(command -v sudo 2>/dev/null || true)" ]; then
|
||||
echo "sudo"
|
||||
elif [ -n "$(command -v doas 2>/dev/null || true)" ]; then
|
||||
echo "doas"
|
||||
else
|
||||
echo "Please install 'sudo' or 'doas' to continue." >&2
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
true
|
||||
}
|
||||
|
||||
download_url() {
|
||||
local url=$1
|
||||
local filename=${2:-$(basename "$url")}
|
||||
if [ -n "$(command -v curl 2>/dev/null || true)" ]; then
|
||||
curl -LSf -o "$filename" "$url"
|
||||
elif [ -n "$(command -v wget 2>/dev/null || true)" ]; then
|
||||
wget "-O$filename" "$url"
|
||||
else
|
||||
echo "Please install 'curl' or 'wget' to continue." >&2
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
github_api_call() {
|
||||
local url="$1"
|
||||
local token="${GITHUB_TOKEN:-${GH_TOKEN:-}}"
|
||||
if [ -n "${token:-}" ]; then
|
||||
if [ -n "$(command -v curl 2>/dev/null || true)" ]; then
|
||||
curl -fsSL -H "Authorization: token $token" -H "Accept: application/vnd.github.v3+json" "https://api.github.com/$url"
|
||||
elif [ -n "$(command -v wget 2>/dev/null || true)" ]; then
|
||||
wget -q --header="Authorization: token $token" --header="Accept: application/vnd.github.v3+json" "https://api.github.com/$url" -O -
|
||||
fi
|
||||
else
|
||||
download_url "https://api.github.com/$url" -
|
||||
fi
|
||||
}
|
||||
|
||||
fn_arch() {
|
||||
local arch_name=$(uname -m | tr 'A-Z' 'a-z')
|
||||
case "$arch_name" in
|
||||
*arm64* | *aarch64*)
|
||||
echo ARM64
|
||||
;;
|
||||
*riscv64*)
|
||||
echo RV64
|
||||
;;
|
||||
*x86_64* | *x64*)
|
||||
echo X64
|
||||
;;
|
||||
*)
|
||||
echo "Unsupported architecture: $arch_name" >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
if [ "$(uname -s 2>/dev/null || true)" != "Linux" ]; then
|
||||
echo "This script is only intended for Linux." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Create a temporary directory for downloads
|
||||
tmpdir=$(mktemp -d)
|
||||
trap 'rm -rf "$tmpdir"' EXIT
|
||||
|
||||
# Get the latest qmk_udev release
|
||||
echo "Fetching latest qmk_udev release..." >&2
|
||||
latest_release=$(github_api_call repos/qmk/qmk_udev/releases/latest | grep -oE '"tag_name": "[^"]+' | grep -oE '[^"]+$')
|
||||
if [ -z "$latest_release" ]; then
|
||||
echo "Could not determine latest qmk_udev release." >&2
|
||||
exit 1
|
||||
fi
|
||||
echo "Using qmk_udev release: $latest_release" >&2
|
||||
|
||||
release_base="https://github.com/qmk/qmk_udev/releases/download/$latest_release"
|
||||
|
||||
# Download the udev rules file and architecture-appropriate qmk_id binary
|
||||
download_url "$release_base/50-qmk.rules" "$tmpdir/50-qmk.rules"
|
||||
download_url "$release_base/qmk_id-linux$(fn_arch)" "$tmpdir/qmk_id"
|
||||
|
||||
# Remove existing QMK udev rules and qmk_id helpers from all standard locations
|
||||
echo "Removing existing QMK udev rules and helpers..." >&2
|
||||
for dir in /etc/udev/rules.d /run/udev/rules.d /usr/lib/udev/rules.d /usr/local/lib/udev/rules.d /lib/udev/rules.d; do
|
||||
if [ -d "$dir" ]; then
|
||||
for f in "$dir"/*-qmk.rules; do
|
||||
[ -e "$f" ] && echo "Removing $f" >&2 && $(nsudo) rm -f "$f"
|
||||
done
|
||||
fi
|
||||
done
|
||||
for dir in /usr/lib/udev /usr/local/lib/udev /lib/udev; do
|
||||
[ -e "$dir/qmk_id" ] && echo "Removing $dir/qmk_id" >&2 && $(nsudo) rm -f "$dir/qmk_id"
|
||||
done
|
||||
|
||||
# Install qmk_id binary and udev rules
|
||||
echo "Installing /usr/lib/udev/qmk_id ..." >&2
|
||||
$(nsudo) install -d -m 0755 /usr/lib/udev
|
||||
$(nsudo) install -m 0755 "$tmpdir/qmk_id" /usr/lib/udev/qmk_id
|
||||
echo "Installing /etc/udev/rules.d/50-qmk.rules ..." >&2
|
||||
$(nsudo) install -d -m 0755 /etc/udev/rules.d
|
||||
$(nsudo) install -m 0644 "$tmpdir/50-qmk.rules" /etc/udev/rules.d/50-qmk.rules
|
||||
|
||||
# Reload udev rules
|
||||
if command -v udevadm >/dev/null 2>&1; then
|
||||
echo "Reloading udev rules..." >&2
|
||||
$(nsudo) udevadm control --reload-rules || true
|
||||
$(nsudo) udevadm trigger || true
|
||||
else
|
||||
echo "udevadm not found, skipping udev rules reload." >&2
|
||||
fi
|
||||
|
||||
echo "Done." >&2
|
||||
@@ -1,89 +0,0 @@
|
||||
# Atmel DFU
|
||||
### ATmega16U2
|
||||
SUBSYSTEMS=="usb", ATTRS{idVendor}=="03eb", ATTRS{idProduct}=="2fef", TAG+="uaccess"
|
||||
### ATmega32U2
|
||||
SUBSYSTEMS=="usb", ATTRS{idVendor}=="03eb", ATTRS{idProduct}=="2ff0", TAG+="uaccess"
|
||||
### ATmega16U4
|
||||
SUBSYSTEMS=="usb", ATTRS{idVendor}=="03eb", ATTRS{idProduct}=="2ff3", TAG+="uaccess"
|
||||
### ATmega32U4
|
||||
SUBSYSTEMS=="usb", ATTRS{idVendor}=="03eb", ATTRS{idProduct}=="2ff4", TAG+="uaccess"
|
||||
### AT90USB64
|
||||
SUBSYSTEMS=="usb", ATTRS{idVendor}=="03eb", ATTRS{idProduct}=="2ff9", TAG+="uaccess"
|
||||
### AT90USB162
|
||||
SUBSYSTEMS=="usb", ATTRS{idVendor}=="03eb", ATTRS{idProduct}=="2ffa", TAG+="uaccess"
|
||||
### AT90USB128
|
||||
SUBSYSTEMS=="usb", ATTRS{idVendor}=="03eb", ATTRS{idProduct}=="2ffb", TAG+="uaccess"
|
||||
|
||||
# Input Club
|
||||
SUBSYSTEMS=="usb", ATTRS{idVendor}=="1c11", ATTRS{idProduct}=="b007", TAG+="uaccess"
|
||||
|
||||
# STM32duino
|
||||
SUBSYSTEMS=="usb", ATTRS{idVendor}=="1eaf", ATTRS{idProduct}=="0003", TAG+="uaccess"
|
||||
# STM32 DFU
|
||||
SUBSYSTEMS=="usb", ATTRS{idVendor}=="0483", ATTRS{idProduct}=="df11", TAG+="uaccess"
|
||||
|
||||
# BootloadHID
|
||||
SUBSYSTEMS=="usb", ATTRS{idVendor}=="16c0", ATTRS{idProduct}=="05df", TAG+="uaccess"
|
||||
|
||||
# USBAspLoader
|
||||
SUBSYSTEMS=="usb", ATTRS{idVendor}=="16c0", ATTRS{idProduct}=="05dc", TAG+="uaccess"
|
||||
|
||||
# USBtinyISP
|
||||
SUBSYSTEMS=="usb", ATTRS{idVendor}=="1782", ATTRS{idProduct}=="0c9f", TAG+="uaccess"
|
||||
|
||||
# ModemManager should ignore the following devices
|
||||
# Atmel SAM-BA (Massdrop)
|
||||
SUBSYSTEMS=="usb", ATTRS{idVendor}=="03eb", ATTRS{idProduct}=="6124", TAG+="uaccess", ENV{ID_MM_DEVICE_IGNORE}="1"
|
||||
|
||||
# Caterina (Pro Micro)
|
||||
## pid.codes shared PID
|
||||
### Keyboardio Atreus 2 Bootloader
|
||||
SUBSYSTEMS=="usb", ATTRS{idVendor}=="1209", ATTRS{idProduct}=="2302", TAG+="uaccess", ENV{ID_MM_DEVICE_IGNORE}="1"
|
||||
## Spark Fun Electronics
|
||||
### Pro Micro 3V3/8MHz
|
||||
SUBSYSTEMS=="usb", ATTRS{idVendor}=="1b4f", ATTRS{idProduct}=="9203", TAG+="uaccess", ENV{ID_MM_DEVICE_IGNORE}="1"
|
||||
### Pro Micro 5V/16MHz
|
||||
SUBSYSTEMS=="usb", ATTRS{idVendor}=="1b4f", ATTRS{idProduct}=="9205", TAG+="uaccess", ENV{ID_MM_DEVICE_IGNORE}="1"
|
||||
### LilyPad 3V3/8MHz (and some Pro Micro clones)
|
||||
SUBSYSTEMS=="usb", ATTRS{idVendor}=="1b4f", ATTRS{idProduct}=="9207", TAG+="uaccess", ENV{ID_MM_DEVICE_IGNORE}="1"
|
||||
## Pololu Electronics
|
||||
### A-Star 32U4
|
||||
SUBSYSTEMS=="usb", ATTRS{idVendor}=="1ffb", ATTRS{idProduct}=="0101", TAG+="uaccess", ENV{ID_MM_DEVICE_IGNORE}="1"
|
||||
## Arduino SA
|
||||
### Leonardo
|
||||
SUBSYSTEMS=="usb", ATTRS{idVendor}=="2341", ATTRS{idProduct}=="0036", TAG+="uaccess", ENV{ID_MM_DEVICE_IGNORE}="1"
|
||||
### Micro
|
||||
SUBSYSTEMS=="usb", ATTRS{idVendor}=="2341", ATTRS{idProduct}=="0037", TAG+="uaccess", ENV{ID_MM_DEVICE_IGNORE}="1"
|
||||
## Adafruit Industries LLC
|
||||
### Feather 32U4
|
||||
SUBSYSTEMS=="usb", ATTRS{idVendor}=="239a", ATTRS{idProduct}=="000c", TAG+="uaccess", ENV{ID_MM_DEVICE_IGNORE}="1"
|
||||
### ItsyBitsy 32U4 3V3/8MHz
|
||||
SUBSYSTEMS=="usb", ATTRS{idVendor}=="239a", ATTRS{idProduct}=="000d", TAG+="uaccess", ENV{ID_MM_DEVICE_IGNORE}="1"
|
||||
### ItsyBitsy 32U4 5V/16MHz
|
||||
SUBSYSTEMS=="usb", ATTRS{idVendor}=="239a", ATTRS{idProduct}=="000e", TAG+="uaccess", ENV{ID_MM_DEVICE_IGNORE}="1"
|
||||
## dog hunter AG
|
||||
### Leonardo
|
||||
SUBSYSTEMS=="usb", ATTRS{idVendor}=="2a03", ATTRS{idProduct}=="0036", TAG+="uaccess", ENV{ID_MM_DEVICE_IGNORE}="1"
|
||||
### Micro
|
||||
SUBSYSTEMS=="usb", ATTRS{idVendor}=="2a03", ATTRS{idProduct}=="0037", TAG+="uaccess", ENV{ID_MM_DEVICE_IGNORE}="1"
|
||||
|
||||
# hid_listen
|
||||
KERNEL=="hidraw*", MODE="0660", GROUP="plugdev", TAG+="uaccess", TAG+="udev-acl"
|
||||
|
||||
# hid bootloaders
|
||||
## QMK HID
|
||||
SUBSYSTEMS=="usb", ATTRS{idVendor}=="03eb", ATTRS{idProduct}=="2067", TAG+="uaccess"
|
||||
## PJRC's HalfKay
|
||||
SUBSYSTEMS=="usb", ATTRS{idVendor}=="16c0", ATTRS{idProduct}=="0478", TAG+="uaccess"
|
||||
|
||||
# APM32 DFU
|
||||
SUBSYSTEMS=="usb", ATTRS{idVendor}=="314b", ATTRS{idProduct}=="0106", TAG+="uaccess"
|
||||
|
||||
# GD32V DFU
|
||||
SUBSYSTEMS=="usb", ATTRS{idVendor}=="28e9", ATTRS{idProduct}=="0189", TAG+="uaccess"
|
||||
|
||||
# WB32 DFU
|
||||
SUBSYSTEMS=="usb", ATTRS{idVendor}=="342d", ATTRS{idProduct}=="dfa0", TAG+="uaccess"
|
||||
|
||||
# AT32 DFU
|
||||
SUBSYSTEMS=="usb", ATTRS{idVendor}=="2e3c", ATTRS{idProduct}=="df11", TAG+="uaccess"
|
||||
Reference in New Issue
Block a user