mirror of
https://github.com/qmk/qmk_firmware.git
synced 2025-04-26 00:51:29 +00:00
Custom keycodes in JSON
This commit is contained in:
parent
6498acd2d3
commit
2731667ff4
@ -71,6 +71,38 @@
|
|||||||
"type": "string",
|
"type": "string",
|
||||||
"pattern": "^[0-9a-z][0-9a-z_/]*$"
|
"pattern": "^[0-9a-z][0-9a-z_/]*$"
|
||||||
},
|
},
|
||||||
|
"keycode": {
|
||||||
|
"type": "string",
|
||||||
|
"minLength": 2,
|
||||||
|
"maxLength": 50,
|
||||||
|
"pattern": "^[A-Z][A-Zs_0-9]*$"
|
||||||
|
},
|
||||||
|
"keycode_short": {
|
||||||
|
"type": "string",
|
||||||
|
"minLength": 2,
|
||||||
|
"maxLength": 7,
|
||||||
|
"pattern": "^[A-Z][A-Zs_0-9]*$"
|
||||||
|
},
|
||||||
|
"keycode_decl": {
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"key"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"key": {"$ref": "#/keycode"},
|
||||||
|
"label": {"$ref": "#/text_identifier"},
|
||||||
|
"aliases": {
|
||||||
|
"type": "array",
|
||||||
|
"minItems": 1,
|
||||||
|
"items": {"$ref": "#/keycode_short"}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"keycode_decl_array": {
|
||||||
|
"type": "array",
|
||||||
|
"minItems": 1
|
||||||
|
"items": {"$ref": "#/keycode_decl"}
|
||||||
|
},
|
||||||
"mcu_pin_array": {
|
"mcu_pin_array": {
|
||||||
"type": "array",
|
"type": "array",
|
||||||
"items": {"$ref": "#/mcu_pin"}
|
"items": {"$ref": "#/mcu_pin"}
|
||||||
|
@ -246,6 +246,7 @@
|
|||||||
"on_state": {"$ref": "qmk.definitions.v1#/bit"}
|
"on_state": {"$ref": "qmk.definitions.v1#/bit"}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"keycodes": {"$ref": "qmk.definitions.v1#/keycode_decl_array"},
|
||||||
"layout_aliases": {
|
"layout_aliases": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"additionalProperties": {"$ref": "qmk.definitions.v1#/layout_macro"}
|
"additionalProperties": {"$ref": "qmk.definitions.v1#/layout_macro"}
|
||||||
|
@ -8,11 +8,7 @@
|
|||||||
"type": "string",
|
"type": "string",
|
||||||
"minLength": 2,
|
"minLength": 2,
|
||||||
"maxLength": 50,
|
"maxLength": 50,
|
||||||
"pattern": "^[A-Zs_0-9]*$"
|
"pattern": "^[A-Z][A-Zs_0-9]*$"
|
||||||
},
|
|
||||||
"hex_number_4d": {
|
|
||||||
"type": "string",
|
|
||||||
"pattern": "^0x[0-9A-F]{4}$"
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"properties": {
|
"properties": {
|
||||||
@ -34,10 +30,10 @@
|
|||||||
"keycodes": {
|
"keycodes": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"propertyNames": {
|
"propertyNames": {
|
||||||
"$ref": "#/definitions/hex_number_4d"
|
"$ref": "qmk.definitions.v1#/hex_number_4d"
|
||||||
},
|
},
|
||||||
"additionalProperties": {
|
"additionalProperties": {
|
||||||
"type": "object",
|
"type": "object", // use 'qmk.definitions.v1#/keycode_decl' when problem keycodes are removed
|
||||||
"required": [
|
"required": [
|
||||||
"key"
|
"key"
|
||||||
],
|
],
|
||||||
|
@ -67,6 +67,7 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"keycodes": {"$ref": "qmk.definitions.v1#/keycode_decl_array"},
|
||||||
"config": {"$ref": "qmk.keyboard.v1"},
|
"config": {"$ref": "qmk.keyboard.v1"},
|
||||||
"notes": {
|
"notes": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
|
@ -13,9 +13,8 @@
|
|||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
#include QMK_KEYBOARD_H
|
||||||
#include "hal.h"
|
#include "hal.h"
|
||||||
#include "annepro2.h"
|
|
||||||
#include "annepro2_ble.h"
|
#include "annepro2_ble.h"
|
||||||
#include "spi_master.h"
|
#include "spi_master.h"
|
||||||
#include "ap2_led.h"
|
#include "ap2_led.h"
|
||||||
|
@ -57,23 +57,3 @@ extern ble_capslock_t ble_capslock;
|
|||||||
/* ROW5 */ { K40, KC_NO, K42, K43, KC_NO, KC_NO, K46, KC_NO, KC_NO, K49, K4A, K4B, K4C, KC_NO}, \
|
/* ROW5 */ { K40, KC_NO, K42, K43, KC_NO, KC_NO, K46, KC_NO, KC_NO, K49, K4A, K4B, K4C, KC_NO}, \
|
||||||
}
|
}
|
||||||
// clang-format on
|
// clang-format on
|
||||||
|
|
||||||
enum AP2KeyCodes {
|
|
||||||
KC_AP2_BT1 = QK_KB_0,
|
|
||||||
KC_AP2_BT2,
|
|
||||||
KC_AP2_BT3,
|
|
||||||
KC_AP2_BT4,
|
|
||||||
KC_AP2_BT_UNPAIR,
|
|
||||||
KC_AP2_USB,
|
|
||||||
KC_AP_LED_ON,
|
|
||||||
KC_AP_LED_OFF,
|
|
||||||
KC_AP_LED_TOG,
|
|
||||||
KC_AP_LED_NEXT_PROFILE,
|
|
||||||
KC_AP_LED_PREV_PROFILE,
|
|
||||||
KC_AP_LED_NEXT_INTENSITY,
|
|
||||||
KC_AP_LED_SPEED,
|
|
||||||
KC_AP_RGB_VAI,
|
|
||||||
KC_AP_RGB_VAD,
|
|
||||||
KC_AP_RGB_TOG,
|
|
||||||
KC_AP_RGB_MOD,
|
|
||||||
};
|
|
||||||
|
@ -6,6 +6,25 @@
|
|||||||
"vid": "0xFEED",
|
"vid": "0xFEED",
|
||||||
"device_version": "13.3.7"
|
"device_version": "13.3.7"
|
||||||
},
|
},
|
||||||
|
"keycodes": [
|
||||||
|
{ "key": "KC_AP2_BT1", "aliases": ["AP2_BT1"] },
|
||||||
|
{ "key": "KC_AP2_BT2", "aliases": ["AP2_BT2"] },
|
||||||
|
{ "key": "KC_AP2_BT3", "aliases": ["AP2_BT3"] },
|
||||||
|
{ "key": "KC_AP2_BT4", "aliases": ["AP2_BT4"] },
|
||||||
|
{ "key": "KC_AP2_BT_UNPAIR" },
|
||||||
|
{ "key": "KC_AP2_USB" },
|
||||||
|
{ "key": "KC_AP_LED_ON" },
|
||||||
|
{ "key": "KC_AP_LED_OFF" },
|
||||||
|
{ "key": "KC_AP_LED_TOG" },
|
||||||
|
{ "key": "KC_AP_LED_NEXT_PROFILE" },
|
||||||
|
{ "key": "KC_AP_LED_PREV_PROFILE" },
|
||||||
|
{ "key": "KC_AP_LED_NEXT_INTENSITY" },
|
||||||
|
{ "key": "KC_AP_LED_SPEED" },
|
||||||
|
{ "key": "KC_AP_RGB_VAI" },
|
||||||
|
{ "key": "KC_AP_RGB_VAD" },
|
||||||
|
{ "key": "KC_AP_RGB_TOG" },
|
||||||
|
{ "key": "KC_AP_RGB_MOD" }
|
||||||
|
],
|
||||||
"layouts": {
|
"layouts": {
|
||||||
"LAYOUT_60_ansi": {
|
"LAYOUT_60_ansi": {
|
||||||
"layout": [
|
"layout": [
|
||||||
|
@ -0,0 +1,12 @@
|
|||||||
|
{
|
||||||
|
"keyboard": "handwired/pytest/basic",
|
||||||
|
"keymap": "default_json",
|
||||||
|
"layout": "LAYOUT_ortho_1x1",
|
||||||
|
"layers": [["EXAMPLE_1"]],
|
||||||
|
"keycodes": [
|
||||||
|
{ "key": "EXAMPLE_1" }
|
||||||
|
],
|
||||||
|
"author": "qmk",
|
||||||
|
"notes": "This file is a keymap.json file for handwired/pytest/basic",
|
||||||
|
"version": 1
|
||||||
|
}
|
@ -67,6 +67,12 @@ def _filtered_copy(src, dst):
|
|||||||
dst.write_text(json.dumps(data), encoding='utf-8')
|
dst.write_text(json.dumps(data), encoding='utf-8')
|
||||||
return dst
|
return dst
|
||||||
|
|
||||||
|
if dst.suffix == '.jsonschema':
|
||||||
|
data = json_load(src)
|
||||||
|
|
||||||
|
dst.write_text(json.dumps(data), encoding='utf-8')
|
||||||
|
return dst
|
||||||
|
|
||||||
return shutil.copy2(src, dst)
|
return shutil.copy2(src, dst)
|
||||||
|
|
||||||
|
|
||||||
|
@ -11,12 +11,9 @@ from qmk.keyboard import keyboard_completer, keyboard_folder
|
|||||||
from qmk.constants import COL_LETTERS, ROW_LETTERS, GPL2_HEADER_C_LIKE, GENERATED_HEADER_C_LIKE
|
from qmk.constants import COL_LETTERS, ROW_LETTERS, GPL2_HEADER_C_LIKE, GENERATED_HEADER_C_LIKE
|
||||||
|
|
||||||
|
|
||||||
def _generate_layouts(keyboard):
|
def _generate_layouts(keyboard, kb_info_json):
|
||||||
"""Generates the layouts.h file.
|
"""Generates the layouts macros.
|
||||||
"""
|
"""
|
||||||
# Build the info.json file
|
|
||||||
kb_info_json = info_json(keyboard)
|
|
||||||
|
|
||||||
if 'matrix_size' not in kb_info_json:
|
if 'matrix_size' not in kb_info_json:
|
||||||
cli.log.error(f'{keyboard}: Invalid matrix config.')
|
cli.log.error(f'{keyboard}: Invalid matrix config.')
|
||||||
return []
|
return []
|
||||||
@ -65,6 +62,32 @@ def _generate_layouts(keyboard):
|
|||||||
return lines
|
return lines
|
||||||
|
|
||||||
|
|
||||||
|
def _generate_keycodes(kb_info_json):
|
||||||
|
"""Generates keyboard level keycodes.
|
||||||
|
"""
|
||||||
|
if 'keycodes' not in kb_info_json:
|
||||||
|
return []
|
||||||
|
|
||||||
|
lines = []
|
||||||
|
lines.append('enum keyboard_keycodes {')
|
||||||
|
|
||||||
|
for index, item in enumerate(kb_info_json.get('keycodes')):
|
||||||
|
key = item["key"]
|
||||||
|
if index == 0:
|
||||||
|
lines.append(f' {key} = QK_KB_0,')
|
||||||
|
else:
|
||||||
|
lines.append(f' {key},')
|
||||||
|
|
||||||
|
lines.append('};')
|
||||||
|
|
||||||
|
for item in kb_info_json.get('keycodes', []):
|
||||||
|
key = item["key"]
|
||||||
|
for alias in item.get("aliases", []):
|
||||||
|
lines.append(f'#define {alias} {key}')
|
||||||
|
|
||||||
|
return lines
|
||||||
|
|
||||||
|
|
||||||
@cli.argument('-i', '--include', nargs='?', arg_only=True, help='Optional file to include')
|
@cli.argument('-i', '--include', nargs='?', arg_only=True, help='Optional file to include')
|
||||||
@cli.argument('-o', '--output', arg_only=True, type=normpath, help='File to write to')
|
@cli.argument('-o', '--output', arg_only=True, type=normpath, help='File to write to')
|
||||||
@cli.argument('-q', '--quiet', arg_only=True, action='store_true', help="Quiet mode, only output error messages")
|
@cli.argument('-q', '--quiet', arg_only=True, action='store_true', help="Quiet mode, only output error messages")
|
||||||
@ -73,8 +96,12 @@ def _generate_layouts(keyboard):
|
|||||||
def generate_keyboard_h(cli):
|
def generate_keyboard_h(cli):
|
||||||
"""Generates the keyboard.h file.
|
"""Generates the keyboard.h file.
|
||||||
"""
|
"""
|
||||||
|
# Build the info.json file
|
||||||
|
kb_info_json = info_json(cli.args.keyboard)
|
||||||
|
|
||||||
keyboard_h = cli.args.include
|
keyboard_h = cli.args.include
|
||||||
dd_layouts = _generate_layouts(cli.args.keyboard)
|
dd_layouts = _generate_layouts(cli.args.keyboard, kb_info_json)
|
||||||
|
dd_keycodes = _generate_keycodes(kb_info_json)
|
||||||
valid_config = dd_layouts or keyboard_h
|
valid_config = dd_layouts or keyboard_h
|
||||||
|
|
||||||
# Build the layouts.h file.
|
# Build the layouts.h file.
|
||||||
@ -87,6 +114,11 @@ def generate_keyboard_h(cli):
|
|||||||
if keyboard_h:
|
if keyboard_h:
|
||||||
keyboard_h_lines.append(f'#include "{Path(keyboard_h).name}"')
|
keyboard_h_lines.append(f'#include "{Path(keyboard_h).name}"')
|
||||||
|
|
||||||
|
keyboard_h_lines.append('')
|
||||||
|
keyboard_h_lines.append('// Keycode content')
|
||||||
|
if dd_keycodes:
|
||||||
|
keyboard_h_lines.extend(dd_keycodes)
|
||||||
|
|
||||||
# Protect against poorly configured keyboards
|
# Protect against poorly configured keyboards
|
||||||
if not valid_config:
|
if not valid_config:
|
||||||
keyboard_h_lines.append('#error("<keyboard>.h is required unless your keyboard uses data-driven configuration. Please rename your keyboard\'s header file to <keyboard>.h")')
|
keyboard_h_lines.append('#error("<keyboard>.h is required unless your keyboard uses data-driven configuration. Please rename your keyboard\'s header file to <keyboard>.h")')
|
||||||
|
@ -93,6 +93,12 @@ def _validate(keyboard, info_data):
|
|||||||
if layout_name not in layouts and layout_name not in layout_aliases:
|
if layout_name not in layouts and layout_name not in layout_aliases:
|
||||||
_log_error(info_data, 'Claims to support community layout %s but no %s() macro found' % (layout, layout_name))
|
_log_error(info_data, 'Claims to support community layout %s but no %s() macro found' % (layout, layout_name))
|
||||||
|
|
||||||
|
# keycodes with length > 7 must have short forms for visualisation purposes
|
||||||
|
for decl in info_data.get('keycodes', []):
|
||||||
|
if len(decl["key"]) > 7:
|
||||||
|
if not decl.get("aliases", []):
|
||||||
|
_log_error(info_data, f'Keycode {decl["key"]} has no short form alias')
|
||||||
|
|
||||||
|
|
||||||
def info_json(keyboard):
|
def info_json(keyboard):
|
||||||
"""Generate the info.json data for a specific keyboard.
|
"""Generate the info.json data for a specific keyboard.
|
||||||
|
@ -25,6 +25,7 @@ __INCLUDES__
|
|||||||
* This file was generated by qmk json2c. You may or may not want to
|
* This file was generated by qmk json2c. You may or may not want to
|
||||||
* edit it directly.
|
* edit it directly.
|
||||||
*/
|
*/
|
||||||
|
__KEYCODE_OUTPUT_GOES_HERE__
|
||||||
|
|
||||||
const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
|
const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
|
||||||
__KEYMAP_GOES_HERE__
|
__KEYMAP_GOES_HERE__
|
||||||
@ -123,6 +124,29 @@ def _generate_macros_function(keymap_json):
|
|||||||
return macro_txt
|
return macro_txt
|
||||||
|
|
||||||
|
|
||||||
|
def _generate_keycodes_function(keymap_json):
|
||||||
|
"""Generates keymap level keycodes.
|
||||||
|
"""
|
||||||
|
lines = []
|
||||||
|
lines.append('enum keymap_keycodes {')
|
||||||
|
|
||||||
|
for index, item in enumerate(keymap_json.get('keycodes', [])):
|
||||||
|
key = item["key"]
|
||||||
|
if index == 0:
|
||||||
|
lines.append(f' {key} = QK_USER_0,')
|
||||||
|
else:
|
||||||
|
lines.append(f' {key},')
|
||||||
|
|
||||||
|
lines.append('};')
|
||||||
|
|
||||||
|
for item in keymap_json.get('keycodes', []):
|
||||||
|
key = item["key"]
|
||||||
|
for alias in item.get("aliases", []):
|
||||||
|
lines.append(f'#define {alias} {key}')
|
||||||
|
|
||||||
|
return lines
|
||||||
|
|
||||||
|
|
||||||
def template_json(keyboard):
|
def template_json(keyboard):
|
||||||
"""Returns a `keymap.json` template for a keyboard.
|
"""Returns a `keymap.json` template for a keyboard.
|
||||||
|
|
||||||
@ -317,6 +341,12 @@ def generate_c(keymap_json):
|
|||||||
hostlang = f'#include "keymap_{keymap_json["host_language"]}.h"\n#include "sendstring_{keymap_json["host_language"]}.h"\n'
|
hostlang = f'#include "keymap_{keymap_json["host_language"]}.h"\n#include "sendstring_{keymap_json["host_language"]}.h"\n'
|
||||||
new_keymap = new_keymap.replace('__INCLUDES__', hostlang)
|
new_keymap = new_keymap.replace('__INCLUDES__', hostlang)
|
||||||
|
|
||||||
|
keycodes = ''
|
||||||
|
if 'keycodes' in keymap_json and keymap_json['keycodes'] is not None:
|
||||||
|
keycodes_txt = _generate_keycodes_function(keymap_json)
|
||||||
|
keycodes = '\n'.join(keycodes_txt)
|
||||||
|
new_keymap = new_keymap.replace('__KEYCODE_OUTPUT_GOES_HERE__', keycodes)
|
||||||
|
|
||||||
return new_keymap
|
return new_keymap
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user