Compare commits
44 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
12568fb5a9 | ||
|
824e1cd95d | ||
|
2573ed8c6b | ||
|
25d9cdc88f | ||
|
962b8d3814 | ||
|
122cf3ad0f | ||
|
5edfdeff50 | ||
|
221d8fd866 | ||
|
3300164065 | ||
|
55843480ff | ||
|
5fde2d730c | ||
|
1b7b72c0e9 | ||
|
bbf0f65284 | ||
|
1d1d5da43f | ||
|
48f4768d33 | ||
|
53eb7f0774 | ||
|
5544bf8524 | ||
|
7ca4b61922 | ||
|
b7f640ca76 | ||
|
436b5394bb | ||
|
cd0d2d0de5 | ||
|
6a292e11d3 | ||
|
3e3f93c971 | ||
|
9136c122f8 | ||
|
cc4b93b330 | ||
|
d40d1e4024 | ||
|
b2ab0af905 | ||
|
d898d4a6fc | ||
|
7c0cb18681 | ||
|
e52b4797d3 | ||
|
498d89f4b3 | ||
|
d5f3f7c126 | ||
|
e9ed5d7571 | ||
|
806aa9bc67 | ||
|
dc7081a823 | ||
|
fd177582ad | ||
|
dee506c096 | ||
|
78b2f120e5 | ||
|
ce7d3855f4 | ||
|
4eebefada7 | ||
|
71b52416d8 | ||
|
bf324c38e3 | ||
|
f40b564683 | ||
|
2843e7f995 |
73
Makefile
73
Makefile
@ -68,37 +68,8 @@ PATH_ELEMENTS := $(subst /, ,$(STARTING_DIR))
|
||||
# Initialize the path elements list for further processing
|
||||
$(eval $(call NEXT_PATH_ELEMENT))
|
||||
|
||||
# This function sets the KEYBOARD; KEYMAP and SUBPROJECT to the correct
|
||||
# variables depending on which directory you stand in.
|
||||
# It's really a very simple if else chain, if you squint enough,
|
||||
# but the makefile syntax makes it very verbose.
|
||||
# If we are in a subfolder of keyboards
|
||||
#
|
||||
# *** No longer needed **
|
||||
#
|
||||
# ifeq ($(CURRENT_PATH_ELEMENT),keyboards)
|
||||
# $(eval $(call NEXT_PATH_ELEMENT))
|
||||
# KEYBOARD := $(CURRENT_PATH_ELEMENT)
|
||||
# $(eval $(call NEXT_PATH_ELEMENT))
|
||||
# # If we are in a subfolder of keymaps, or in other words in a keymap
|
||||
# # folder
|
||||
# ifeq ($(CURRENT_PATH_ELEMENT),keymaps)
|
||||
# $(eval $(call NEXT_PATH_ELEMENT))
|
||||
# KEYMAP := $(CURRENT_PATH_ELEMENT)
|
||||
# # else if we are not in the keyboard folder itself
|
||||
# else ifneq ($(CURRENT_PATH_ELEMENT),)
|
||||
# # the we can assume it's a subproject, as no other folders
|
||||
# # should have make files in them
|
||||
# SUBPROJECT := $(CURRENT_PATH_ELEMENT)
|
||||
# $(eval $(call NEXT_PATH_ELEMENT))
|
||||
# # if we are inside a keymap folder of a subproject
|
||||
# ifeq ($(CURRENT_PATH_ELEMENT),keymaps)
|
||||
# $(eval $(call NEXT_PATH_ELEMENT))
|
||||
# KEYMAP := $(CURRENT_PATH_ELEMENT)
|
||||
# endif
|
||||
# endif
|
||||
# endif
|
||||
|
||||
# Phony targets to enable a few simple make commands outside the main processing below.
|
||||
.PHONY: list-keyboards
|
||||
list-keyboards:
|
||||
util/list_keyboards.sh | sort -u | tr '\n' ' '
|
||||
@ -131,7 +102,6 @@ endif
|
||||
# Uncomment these for debugging
|
||||
# $(info Keyboard: $(KEYBOARD))
|
||||
# $(info Keymap: $(KEYMAP))
|
||||
# $(info Subproject: $(SUBPROJECT))
|
||||
|
||||
|
||||
# Set the default goal depending on where we are running make from
|
||||
@ -189,7 +159,6 @@ endef
|
||||
# A recursive helper function for finding the longest match
|
||||
# $1 The list to be checked
|
||||
# It works by always removing the currently matched item from the list
|
||||
# and call itself recursively, until a match is found
|
||||
define TRY_TO_MATCH_RULE_FROM_LIST_HELPER2
|
||||
# Stop the recursion when the list is empty
|
||||
ifneq ($1,)
|
||||
@ -386,23 +355,6 @@ define PARSE_ALL_KEYBOARDS
|
||||
$$(eval $$(call PARSE_ALL_IN_LIST,PARSE_KEYBOARD,$(shell util/list_keyboards.sh noci | sort -u)))
|
||||
endef
|
||||
|
||||
# $1 Subproject
|
||||
# When entering this, the keyboard and subproject are known, so now we need
|
||||
# to determine which keymaps are going to get compiled
|
||||
# define PARSE_SUBPROJECT
|
||||
|
||||
# endef
|
||||
|
||||
# If we want to parse all subprojects, but the keyboard doesn't have any,
|
||||
# then use defaultsp instead
|
||||
# define PARSE_ALL_SUBPROJECTS
|
||||
# ifeq ($$(SUBPROJECTS),)
|
||||
# $$(eval $$(call PARSE_SUBPROJECT,defaultsp))
|
||||
# else
|
||||
# $$(eval $$(call PARSE_ALL_IN_LIST,PARSE_SUBPROJECT,$$(SUBPROJECTS)))
|
||||
# endif
|
||||
# endef
|
||||
|
||||
# Prints a list of all known keymaps for the given keyboard
|
||||
define LIST_ALL_KEYMAPS
|
||||
COMMAND_true_LIST_KEYMAPS := \
|
||||
@ -544,12 +496,12 @@ if [ $$error_occurred -gt 0 ]; then $(HANDLE_ERROR); fi;
|
||||
|
||||
endef
|
||||
|
||||
# Let's match everything, we handle all the rule parsing ourselves
|
||||
# Catch everything and parse the command line ourselves.
|
||||
.PHONY: %
|
||||
%:
|
||||
# Check if we have the CMP tool installed
|
||||
cmp $(ROOT_DIR)/Makefile $(ROOT_DIR)/Makefile >/dev/null 2>&1; if [ $$? -gt 0 ]; then printf "$(MSG_NO_CMP)"; exit 1; fi;
|
||||
# Ensure that bin/qmk works. This will be a failing check after the next develop merge on 2020 Aug 29.
|
||||
# Ensure that bin/qmk works. This will be a failing check after the next develop merge
|
||||
if ! bin/qmk hello 1> /dev/null 2>&1; then printf "$(MSG_PYTHON_MISSING)"; fi
|
||||
# Check if the submodules are dirty, and display a warning if they are
|
||||
ifndef SKIP_GIT
|
||||
@ -580,25 +532,6 @@ endif
|
||||
$(foreach TEST,$(sort $(TESTS)),$(RUN_TEST))
|
||||
if [ -f $(ERROR_FILE) ]; then printf "$(MSG_ERRORS)" & exit 1; fi;
|
||||
|
||||
# These no longer work because of the colon system
|
||||
|
||||
# All should compile everything
|
||||
# .PHONY: all
|
||||
# all: all-keyboards test-all
|
||||
|
||||
# Define some shortcuts, mostly for compatibility with the old syntax
|
||||
# .PHONY: all-keyboards
|
||||
# all-keyboards: all\:all\:all
|
||||
|
||||
# .PHONY: all-keyboards-defaults
|
||||
# all-keyboards-defaults: all\:default
|
||||
|
||||
# .PHONY: test
|
||||
# test: test-all
|
||||
|
||||
# .PHONY: test-clean
|
||||
# test-clean: test-all-clean
|
||||
|
||||
lib/%:
|
||||
git submodule sync $?
|
||||
git submodule update --init $?
|
||||
|
@ -30,4 +30,4 @@ $(TEST)_SRC += $(patsubst $(ROOTDIR)/%,%,$(wildcard $(TEST_PATH)/*.cpp))
|
||||
|
||||
$(TEST)_DEFS=$(TMK_COMMON_DEFS) $(OPT_DEFS)
|
||||
$(TEST)_CONFIG=$(TEST_PATH)/config.h
|
||||
VPATH+=$(TOP_DIR)/tests/test_common
|
||||
VPATH+=$(TOP_DIR)/tests/test_common
|
||||
|
@ -17,7 +17,7 @@ OUTPUTS := $(TEST_OBJ)/$(TEST) $(GTEST_OUTPUT)
|
||||
GTEST_INC := \
|
||||
$(LIB_PATH)/googletest/googletest/include\
|
||||
$(LIB_PATH)/googletest/googlemock/include\
|
||||
|
||||
|
||||
GTEST_INTERNAL_INC :=\
|
||||
$(LIB_PATH)/googletest/googletest\
|
||||
$(LIB_PATH)/googletest/googlemock
|
||||
@ -27,7 +27,7 @@ $(GTEST_OUTPUT)_SRC :=\
|
||||
googletest/src/gtest_main.cc\
|
||||
googlemock/src/gmock-all.cc
|
||||
|
||||
$(GTEST_OUTPUT)_DEFS :=
|
||||
$(GTEST_OUTPUT)_DEFS :=
|
||||
$(GTEST_OUTPUT)_INC := $(GTEST_INC) $(GTEST_INTERNAL_INC)
|
||||
|
||||
LDFLAGS += -lstdc++ -lpthread -shared-libgcc
|
||||
@ -66,4 +66,3 @@ include $(TMK_PATH)/rules.mk
|
||||
|
||||
$(shell mkdir -p $(BUILD_DIR)/test 2>/dev/null)
|
||||
$(shell mkdir -p $(TEST_OBJ) 2>/dev/null)
|
||||
|
||||
|
@ -50,4 +50,3 @@ This document marks the inaugural Breaking Change merge. A list of changes follo
|
||||
* `KC_DELT` was a redundant, undocumented alias for `KC_DELETE`
|
||||
* It has been removed and all its uses replaced with the more common `KC_DEL` alias
|
||||
* Around 90 keymaps (mostly for ErgoDox boards) have been modified as a result
|
||||
|
||||
|
@ -24,7 +24,7 @@ Totally new to QMK? There are two ways to get started:
|
||||
|
||||
## Make It Yours
|
||||
|
||||
QMK has lots of [features](features.md) to explore, and a good deal of reference documentation to dig through. Most features are taken advantage of by modifying your [keymap](keymap.md), and changing the [keycodes](keycodes.md).
|
||||
QMK has lots of features to explore, and a good deal of reference documentation to dig through. Most features are taken advantage of by modifying your [keymap](keymap.md), and changing the [keycodes](keycodes.md).
|
||||
|
||||
## Need help?
|
||||
|
||||
|
@ -14,16 +14,11 @@ Some keyboards may have specific instructions for entering the bootloader. For e
|
||||
To put a device in bootloader mode with USBaspLoader, tap the `RESET` button while holding down the `BOOT` button.
|
||||
Alternatively, hold `BOOT` while inserting the USB cable.
|
||||
|
||||
Zadig will automatically detect the bootloader device. You may sometimes need to check **Options → List All Devices**.
|
||||
|
||||
- For keyboards with Atmel AVR MCUs, the bootloader will be named something similar to `ATm32U4DFU`, and have a Vendor ID of `03EB`.
|
||||
- USBasp bootloaders will appear as `USBasp`, with a VID/PID of `16C0:05DC`.
|
||||
- AVR keyboards flashed with the QMK-DFU bootloader will be named `<keyboard name> Bootloader` and will also have the VID `03EB`.
|
||||
- For most ARM keyboards, it will be called `STM32 BOOTLOADER`, and have a VID/PID of `0483:DF11`.
|
||||
Zadig should automatically detect the bootloader device, but you may sometimes need to check **Options → List All Devices** and select the device from the dropdown instead.
|
||||
|
||||
!> If Zadig lists one or more devices with the `HidUsb` driver, your keyboard is probably not in bootloader mode. The arrow will be colored orange and you will be asked to confirm modifying a system driver. **Do not** proceed if this is the case!
|
||||
|
||||
If the arrow appears green, select the driver, and click **Install Driver**. The `libusb-win32` driver will usually work for AVR, and `WinUSB` for ARM, but if you still cannot flash the board, try installing a different driver from the list. USBAspLoader devices must use the `libusbK` driver.
|
||||
If the arrow appears green, select the driver, and click **Install Driver**. See the [list of known bootloaders](#list-of-known-bootloaders) for the correct driver to install.
|
||||
|
||||
![Zadig with a bootloader driver correctly installed](https://i.imgur.com/b8VgXzx.png)
|
||||
|
||||
@ -43,6 +38,40 @@ Right-click it and hit **Uninstall device**. Make sure to tick **Delete the driv
|
||||
|
||||
![The Device Uninstall dialog, with the "delete driver" checkbox ticked](https://i.imgur.com/aEs2RuA.png)
|
||||
|
||||
Click **Action → Scan for hardware changes**. At this point, you should be able to type again. Double check in Zadig that the keyboard device(s) are using the `HidUsb` driver. If so, you're all done, and your board should be functional again!
|
||||
Click **Action → Scan for hardware changes**. At this point, you should be able to type again. Double check in Zadig that the keyboard device(s) are using the `HidUsb` driver. If so, you're all done, and your board should be functional again! Otherwise, repeat the process until Zadig reports the correct driver.
|
||||
|
||||
?> A full reboot of your computer may sometimes be necessary at this point, to get Windows to pick up the new driver.
|
||||
|
||||
## List of Known Bootloaders
|
||||
|
||||
This is a list of known bootloader devices and their USB vendor and product IDs, as well as the correct driver to assign for flashing with QMK. Note that the usbser and HidUsb drivers are built in to Windows, and cannot be assigned with Zadig - if your device has an incorrect driver, you must use the Device Manager to uninstall it as described in the previous section.
|
||||
|
||||
The device name here is the name that appears in Zadig, and may not be what the Device Manager or QMK Toolbox displays.
|
||||
|
||||
|Bootloader |Device Name |VID/PID |Driver |
|
||||
|-------------|------------------------------|--------------|-------|
|
||||
|`atmel-dfu` |ATmega16u2 DFU |`03EB:2FEF` |libusb0|
|
||||
|`atmel-dfu` |ATmega32U2 DFU |`03EB:2FF0` |libusb0|
|
||||
|`atmel-dfu` |ATm16U4 DFU V1.0.2 |`03EB:2FF3` |libusb0|
|
||||
|`atmel-dfu` |ATm32U4DFU |`03EB:2FF4` |libusb0|
|
||||
|`atmel-dfu` |*none* (AT90USB64) |`03EB:2FF9` |libusb0|
|
||||
|`atmel-dfu` |AT90USB128 DFU |`03EB:2FFB` |libusb0|
|
||||
|`qmk-dfu` |(keyboard name) Bootloader |As `atmel-dfu`|libusb0|
|
||||
|`halfkay` |*none* |`16C0:0478` |HidUsb |
|
||||
|`caterina` |Pro Micro 3.3V |`1B4F:9203` |usbser |
|
||||
|`caterina` |Pro Micro 5V |`1B4F:9205` |usbser |
|
||||
|`caterina` |LilyPadUSB |`1B4F:9207` |usbser |
|
||||
|`caterina` |Pololu A-Star 32U4 Bootloader |`1FFB:0101` |usbser |
|
||||
|`caterina` |Arduino Leonardo |`2341:0036` |usbser |
|
||||
|`caterina` |Arduino Micro |`2341:0037` |usbser |
|
||||
|`caterina` |Adafruit Feather 32u4 |`239A:000C` |usbser |
|
||||
|`caterina` |Adafruit ItsyBitsy 32u4 3V |`239A:000D` |usbser |
|
||||
|`caterina` |Adafruit ItsyBitsy 32u4 5V |`239A:000E` |usbser |
|
||||
|`caterina` |Arduino Leonardo |`2A03:0036` |usbser |
|
||||
|`caterina` |Arduino Micro |`2A03:0037` |usbser |
|
||||
|`bootloadHID`|HIDBoot |`16C0:05DF` |HidUsb |
|
||||
|`USBasp` |USBasp |`16C0:05DC` |libusbK|
|
||||
|`apm32-dfu` |??? |`314B:0106` |WinUSB |
|
||||
|`stm32-dfu` |STM32 BOOTLOADER |`0483:DF11` |WinUSB |
|
||||
|`kiibohd` |Kiibohd DFU Bootloader |`1C11:B007` |WinUSB |
|
||||
|`stm32duino` |Maple 003 |`1EAF:0003` |WinUSB |
|
||||
|
@ -33,4 +33,3 @@ Soporte para hasta 2 controladores. Cada controlador implementa 2 matrices charl
|
||||
## IS31FL3733
|
||||
|
||||
Soporte para hasta un solo controlador con espacio para expansión. Cada controlador puede controlar 192 LEDs individuales o 64 LEDs RGB. Para obtener más información sobre cómo configurar el controlador, consulta la página de [Matriz RGB](feature_rgb_matrix.md).
|
||||
|
||||
|
@ -148,4 +148,3 @@ The following old names for existing algorithms will continue to be supported, h
|
||||
* eager_pk - old name for sym_eager_pk
|
||||
* sym_pk - old name for sym_defer_pk
|
||||
* eager_pr - old name for sym_eager_pr
|
||||
|
||||
|
@ -209,7 +209,7 @@ SEND_STRING(".."SS_TAP(X_END));
|
||||
|
||||
There are some functions you may find useful in macro-writing. Keep in mind that while you can write some fairly advanced code within a macro, if your functionality gets too complex you may want to define a custom keycode instead. Macros are meant to be simple.
|
||||
|
||||
?> You can also use the functions described in [Useful function](ref_functions.md) for additional functionality. For example `reset_keyboard()` allows you to reset the keyboard as part of a macro.
|
||||
?> You can also use the functions described in [Useful functions](ref_functions.md) for additional functionality. For example `reset_keyboard()` allows you to reset the keyboard as part of a macro.
|
||||
|
||||
### `record->event.pressed`
|
||||
|
||||
|
@ -29,7 +29,7 @@ void raw_hid_receive(uint8_t *data, uint8_t length) {
|
||||
}
|
||||
```
|
||||
|
||||
`raw_hid_receive` can receive variable size packets from host with maximum length `RAW_EPSIZE`. `raw_hid_send` on the other hand can send packets to host of exactly `RAW_EPSIZE` length, therefore it should be used with data of length `RAW_EPSIZE`.
|
||||
These two functions send and receive packets of length `RAW_EPSIZE` bytes to and from the host (32 on LUFA/ChibiOS/V-USB, 64 on ATSAM).
|
||||
|
||||
Make sure to flash raw enabled firmware before proceeding with working on the host side.
|
||||
|
||||
|
@ -306,6 +306,12 @@ To declare new effects, create a new `rgb_matrix_user/kb.inc` that looks somethi
|
||||
`rgb_matrix_user.inc` should go in the root of the keymap directory.
|
||||
`rgb_matrix_kb.inc` should go in the root of the keyboard directory.
|
||||
|
||||
To use custom effects in your code, simply prepend `RGB_MATRIX_CUSTOM_` to the effect name specified in `RGB_MATRIX_EFFECT()`. For example, an effect declared as `RGB_MATRIX_EFFECT(my_cool_effect)` would be referenced with:
|
||||
|
||||
```c
|
||||
rgb_matrix_mode(RGB_MATRIX_CUSTOM_my_cool_effect);
|
||||
```
|
||||
|
||||
```c
|
||||
// !!! DO NOT ADD #pragma once !!! //
|
||||
|
||||
|
@ -85,4 +85,3 @@ While the tempo defines the absolute speed at which the sequencer goes through t
|
||||
|`void sequencer_activate_track(uint8_t track);` |Activate the `track` |
|
||||
|`void sequencer_deactivate_track(uint8_t track);` |Deactivate the `track` |
|
||||
|`void sequencer_toggle_single_active_track(uint8_t track);` |Set `track` as the only active track or deactivate all |
|
||||
|
||||
|
@ -129,4 +129,3 @@ As defined in `keymap_steno.h`.
|
||||
|`STN_RES1`||(GeminiPR only)|
|
||||
|`STN_RES2`||(GeminiPR only)|
|
||||
|`STN_PWR`||(GeminiPR only)|
|
||||
|
||||
|
@ -47,4 +47,3 @@ This configuration is from usbasploader's Makefile.
|
||||
# | | +----- LB 2..1 (No memory lock features enabled)
|
||||
# | +--------- BLB0 2..1 (No restrictions for SPM or LPM accessing the Application section)
|
||||
# +--------------- BLB1 2..1 (No restrictions for SPM or LPM accessing the Boot Loader section)
|
||||
|
||||
|
@ -64,4 +64,4 @@
|
||||
```
|
||||
|
||||
מקמו את התיעוד שלכם בתוך `docs/feature_<my_cool_feature>.md`, והוסיפו קישור לקובץ זה במקום המתאים ב `docs/_sidebar.md`. אם הוספתם קודי מקשים נוספים, תקפידו להוסיף אותם ל- `docs/keycodes.md` עם לינק לעמוד היכולת שלכם.
|
||||
</div>
|
||||
</div>
|
||||
|
@ -5,4 +5,4 @@
|
||||
* [בנייה או קומפילציה של QMK](faq_build.md)
|
||||
* [דיבאגינג ופתרון בעיות של QMK](faq_debug.md)
|
||||
* [מיפוי מקשים](faq_keymap.md)
|
||||
</div>
|
||||
</div>
|
||||
|
@ -14,4 +14,4 @@ TMK עוצב ומומש במקור ע״י [Jun Wako](https://github.com/tmk). QM
|
||||
מנק׳ מבט של הפרוייקט וניהול הקהילה, TMK מנהל את כל המקלדות הנתמכות בעצמו, עם מעט תמיכה מהקהילה. כל אחד יכול לעשות פורק מהפרוייקט עבור מקלדות אחרות. רק מס׳ מיפויי מקשים נמצאים בברירת המחדל כך שאנשים בד״כ לא משתפים מיפויי מקשים זה עם זה. QMK מעודד את השיתוף של המקלדות וקודי המקשים דרך רפוזיטורי בניהול מרכזי, אשר מקבל את כל בקשות ה- Pull Requests שעומדות בסטנדרט האיכות. רובם מנוהלות ע״י הקהילה, אבל הצוות של QMK עוזר כשנדרש.
|
||||
|
||||
לשתי הגישות יש יתרונות וחסרונות וקוד עובר בחופשיות בין TMK ל- QMK כשצריך.
|
||||
</div>
|
||||
</div>
|
||||
|
@ -14,4 +14,4 @@
|
||||
## סוגיות GitHub
|
||||
|
||||
ניתן לפתוח [סוגייה ב-GitHub](https://github.com/qmk/qmk_firmware/issues). הדבר שימושי במיוחד כאשר הסוגיה דורשת דיון עמוק וארוך או דיבאגינג.
|
||||
</div>
|
||||
</div>
|
||||
|
@ -7,4 +7,4 @@ QMK רצה על מגוון של חומרות. אם המעבד שלך יכול ל
|
||||
* [מעבדי AVR](hardware_avr.md)
|
||||
* מעבדי ARM (TBD)
|
||||
* [מנהלי התקנים](hardware_drivers.md)
|
||||
</div>
|
||||
</div>
|
||||
|
@ -13,4 +13,4 @@
|
||||
מקורות לפקודות שורה (Command Line):
|
||||
|
||||
* [מדריך טוב על Command Line](https://www.codecademy.com/learn/learn-the-command-line)
|
||||
</div>
|
||||
</div>
|
||||
|
@ -126,6 +126,10 @@
|
||||
headings: 'h1, h2',
|
||||
title: 'Table of Contents',
|
||||
},
|
||||
tabs: {
|
||||
persist : false,
|
||||
tabComments: false,
|
||||
},
|
||||
plugins: [
|
||||
function (hook, vm) {
|
||||
hook.beforeEach(function (html) {
|
||||
@ -148,6 +152,7 @@
|
||||
<script src="//unpkg.com/docsify/lib/docsify.min.js"></script>
|
||||
<script src="//unpkg.com/docsify/lib/plugins/search.min.js"></script>
|
||||
<script src="//unpkg.com/docsify/lib/plugins/emoji.min.js"></script>
|
||||
<script src="//unpkg.com/docsify-tabs@1"></script>
|
||||
<script src="//unpkg.com/docsify-copy-code@2"></script>
|
||||
<script src="//unpkg.com/docsify-toc@1.0.0/dist/toc.js"></script>
|
||||
<script src="//unpkg.com/prismjs/components/prism-bash.min.js"></script>
|
||||
|
@ -43,5 +43,3 @@ endif
|
||||
* eager_pk - キーごとにデバウンスします。状態が変化すると、応答は即座に行われ、その後そのキーは ```DEBOUNCE``` ミリ秒の間入力されません。
|
||||
* sym_g - キーボードごとにデバウンスします。状態が変化すると、グローバルタイマが設定されます。```DEBOUNCE``` ミリ秒の間何も変化がなければ、全ての入力の変更がプッシュされます。
|
||||
* sym_pk - キーごとにデバウンスします。状態が変化すると、キーごとのタイマーが設定されます。```DEBOUNCE``` ミリ秒の間そのキーに変化がなければ、キーの状態の変更がプッシュされます。
|
||||
|
||||
|
||||
|
@ -171,4 +171,3 @@
|
||||
* `device` 関連するデバイス
|
||||
|
||||
* `func` 登録するコールバック関数
|
||||
|
||||
|
@ -124,17 +124,17 @@ See also: [Basic Keycodes](keycodes_basic.md)
|
||||
|`KC_F22` | |F22 |✔ | |✔ |
|
||||
|`KC_F23` | |F23 |✔ | |✔ |
|
||||
|`KC_F24` | |F24 |✔ | |✔ |
|
||||
|`KC_EXECUTE` |`KC_EXEC` |Execute | | |✔ |
|
||||
|`KC_HELP` | |Help | | |✔ |
|
||||
|`KC_MENU` | |Menu | | |✔ |
|
||||
|`KC_SELECT` |`KC_SLCT` |Select | | |✔ |
|
||||
|`KC_STOP` | |Stop | | |✔ |
|
||||
|`KC_AGAIN` |`KC_AGIN` |Again | | |✔ |
|
||||
|`KC_UNDO` | |Undo | | |✔ |
|
||||
|`KC_CUT` | |Cut | | |✔ |
|
||||
|`KC_COPY` | |Copy | | |✔ |
|
||||
|`KC_PASTE` |`KC_PSTE` |Paste | | |✔ |
|
||||
|`KC_FIND` | |Find | | |✔ |
|
||||
|`KC_EXECUTE` |`KC_EXEC` |Execute | | |✔ |
|
||||
|`KC_HELP` | |Help | | |✔ |
|
||||
|`KC_MENU` | |Menu | | |✔ |
|
||||
|`KC_SELECT` |`KC_SLCT` |Select | | |✔ |
|
||||
|`KC_STOP` | |Stop | | |✔ |
|
||||
|`KC_AGAIN` |`KC_AGIN` |Again | | |✔ |
|
||||
|`KC_UNDO` | |Undo | | |✔ |
|
||||
|`KC_CUT` | |Cut | | |✔ |
|
||||
|`KC_COPY` | |Copy | | |✔ |
|
||||
|`KC_PASTE` |`KC_PSTE` |Paste | | |✔ |
|
||||
|`KC_FIND` | |Find | | |✔ |
|
||||
|`KC__MUTE` | |Mute | |✔ |✔ |
|
||||
|`KC__VOLUP` | |Volume Up | |✔ |✔ |
|
||||
|`KC__VOLDOWN` | |Volume Down | |✔ |✔ |
|
||||
|
@ -144,48 +144,48 @@ The basic set of keycodes are based on the [HID Keyboard/Keypad Usage Page (0x07
|
||||
|
||||
## Commands
|
||||
|
||||
|Key |Aliases |Description |
|
||||
|------------------|------------------------------|------------------------------|
|
||||
|`KC_PSCREEN` |`KC_PSCR` |Print Screen |
|
||||
|`KC_PAUSE` |`KC_PAUS`, `KC_BRK`, `KC_BRMU`|Pause, Brightness Up (macOS) |
|
||||
|`KC_INSERT` |`KC_INS` |Insert |
|
||||
|`KC_HOME` | |Home |
|
||||
|`KC_PGUP` | |Page Up |
|
||||
|`KC_DELETE` |`KC_DEL` |Forward Delete |
|
||||
|`KC_END` | |End |
|
||||
|`KC_PGDOWN` |`KC_PGDN` |Page Down |
|
||||
|`KC_RIGHT` |`KC_RGHT` |Right Arrow |
|
||||
|`KC_LEFT` | |Left Arrow |
|
||||
|`KC_DOWN` | |Down Arrow |
|
||||
|`KC_UP` | |Up Arrow |
|
||||
|`KC_APPLICATION` |`KC_APP` |Application (Windows Menu Key)|
|
||||
|`KC_POWER` | |System Power (macOS/Linux) |
|
||||
|`KC_EXECUTE` |`KC_EXEC` |Execute |
|
||||
|`KC_HELP` | |Help |
|
||||
|`KC_MENU` | |Menu |
|
||||
|`KC_SELECT` |`KC_SLCT` |Select |
|
||||
|`KC_STOP` | |Stop |
|
||||
|`KC_AGAIN` |`KC_AGIN` |Again |
|
||||
|`KC_UNDO` | |Undo |
|
||||
|`KC_CUT` | |Cut |
|
||||
|`KC_COPY` | |Copy |
|
||||
|`KC_PASTE` |`KC_PSTE` |Paste |
|
||||
|`KC_FIND` | |Find |
|
||||
|`KC__MUTE` | |Mute (macOS) |
|
||||
|`KC__VOLUP` | |Volume Up (macOS) |
|
||||
|`KC__VOLDOWN` | |Volume Down (macOS) |
|
||||
|`KC_ALT_ERASE` |`KC_ERAS` |Alternate Erase |
|
||||
|`KC_SYSREQ` | |SysReq/Attention |
|
||||
|`KC_CANCEL` | |Cancel |
|
||||
|`KC_CLEAR` |`KC_CLR` |Clear |
|
||||
|`KC_PRIOR` | |Prior |
|
||||
|`KC_RETURN` | |Return |
|
||||
|`KC_SEPARATOR` | |Separator |
|
||||
|`KC_OUT` | |Out |
|
||||
|`KC_OPER` | |Oper |
|
||||
|`KC_CLEAR_AGAIN` | |Clear/Again |
|
||||
|`KC_CRSEL` | |CrSel/Props |
|
||||
|`KC_EXSEL` | |ExSel |
|
||||
|Key |Aliases |Description |
|
||||
|------------------|------------------------------|--------------------------------------|
|
||||
|`KC_PSCREEN` |`KC_PSCR` |Print Screen |
|
||||
|`KC_PAUSE` |`KC_PAUS`, `KC_BRK`, `KC_BRMU`|Pause, Brightness Up (macOS) |
|
||||
|`KC_INSERT` |`KC_INS` |Insert |
|
||||
|`KC_HOME` | |Home |
|
||||
|`KC_PGUP` | |Page Up |
|
||||
|`KC_DELETE` |`KC_DEL` |Forward Delete |
|
||||
|`KC_END` | |End |
|
||||
|`KC_PGDOWN` |`KC_PGDN` |Page Down |
|
||||
|`KC_RIGHT` |`KC_RGHT` |Right Arrow |
|
||||
|`KC_LEFT` | |Left Arrow |
|
||||
|`KC_DOWN` | |Down Arrow |
|
||||
|`KC_UP` | |Up Arrow |
|
||||
|`KC_APPLICATION` |`KC_APP` |Application (Windows Context Menu Key)|
|
||||
|`KC_POWER` | |System Power |
|
||||
|`KC_EXECUTE` |`KC_EXEC` |Execute |
|
||||
|`KC_HELP` | |Help |
|
||||
|`KC_MENU` | |Menu |
|
||||
|`KC_SELECT` |`KC_SLCT` |Select |
|
||||
|`KC_STOP` | |Stop |
|
||||
|`KC_AGAIN` |`KC_AGIN` |Again |
|
||||
|`KC_UNDO` | |Undo |
|
||||
|`KC_CUT` | |Cut |
|
||||
|`KC_COPY` | |Copy |
|
||||
|`KC_PASTE` |`KC_PSTE` |Paste |
|
||||
|`KC_FIND` | |Find |
|
||||
|`KC__MUTE` | |Mute |
|
||||
|`KC__VOLUP` | |Volume Up |
|
||||
|`KC__VOLDOWN` | |Volume Down |
|
||||
|`KC_ALT_ERASE` |`KC_ERAS` |Alternate Erase |
|
||||
|`KC_SYSREQ` | |SysReq/Attention |
|
||||
|`KC_CANCEL` | |Cancel |
|
||||
|`KC_CLEAR` |`KC_CLR` |Clear |
|
||||
|`KC_PRIOR` | |Prior |
|
||||
|`KC_RETURN` | |Return |
|
||||
|`KC_SEPARATOR` | |Separator |
|
||||
|`KC_OUT` | |Out |
|
||||
|`KC_OPER` | |Oper |
|
||||
|`KC_CLEAR_AGAIN` | |Clear/Again |
|
||||
|`KC_CRSEL` | |CrSel/Props |
|
||||
|`KC_EXSEL` | |ExSel |
|
||||
|
||||
## Media Keys
|
||||
|
||||
@ -193,34 +193,34 @@ These keycodes are not part of the Keyboard/Keypad usage page. The `SYSTEM_` key
|
||||
|
||||
?> Some of these keycodes may behave differently depending on the OS. For example, on macOS, the keycodes `KC_MEDIA_FAST_FORWARD`, `KC_MEDIA_REWIND`, `KC_MEDIA_NEXT_TRACK` and `KC_MEDIA_PREV_TRACK` skip within the current track when held, but skip the entire track when tapped.
|
||||
|
||||
|Key |Aliases |Description |
|
||||
|-----------------------|---------|-----------------------------|
|
||||
|`KC_SYSTEM_POWER` |`KC_PWR` |System Power Down |
|
||||
|`KC_SYSTEM_SLEEP` |`KC_SLEP`|System Sleep |
|
||||
|`KC_SYSTEM_WAKE` |`KC_WAKE`|System Wake |
|
||||
|`KC_AUDIO_MUTE` |`KC_MUTE`|Mute |
|
||||
|`KC_AUDIO_VOL_UP` |`KC_VOLU`|Volume Up |
|
||||
|`KC_AUDIO_VOL_DOWN` |`KC_VOLD`|Volume Down |
|
||||
|`KC_MEDIA_NEXT_TRACK` |`KC_MNXT`|Next Track |
|
||||
|`KC_MEDIA_PREV_TRACK` |`KC_MPRV`|Previous Track |
|
||||
|`KC_MEDIA_STOP` |`KC_MSTP`|Stop Track (Windows) |
|
||||
|`KC_MEDIA_PLAY_PAUSE` |`KC_MPLY`|Play/Pause Track |
|
||||
|`KC_MEDIA_SELECT` |`KC_MSEL`|Launch Media Player (Windows)|
|
||||
|`KC_MEDIA_EJECT` |`KC_EJCT`|Eject (macOS) |
|
||||
|`KC_MAIL` | |Launch Mail (Windows) |
|
||||
|`KC_CALCULATOR` |`KC_CALC`|Launch Calculator (Windows) |
|
||||
|`KC_MY_COMPUTER` |`KC_MYCM`|Launch My Computer (Windows) |
|
||||
|`KC_WWW_SEARCH` |`KC_WSCH`|Browser Search (Windows) |
|
||||
|`KC_WWW_HOME` |`KC_WHOM`|Browser Home (Windows) |
|
||||
|`KC_WWW_BACK` |`KC_WBAK`|Browser Back (Windows) |
|
||||
|`KC_WWW_FORWARD` |`KC_WFWD`|Browser Forward (Windows) |
|
||||
|`KC_WWW_STOP` |`KC_WSTP`|Browser Stop (Windows) |
|
||||
|`KC_WWW_REFRESH` |`KC_WREF`|Browser Refresh (Windows) |
|
||||
|`KC_WWW_FAVORITES` |`KC_WFAV`|Browser Favorites (Windows) |
|
||||
|`KC_MEDIA_FAST_FORWARD`|`KC_MFFD`|Next Track (macOS) |
|
||||
|`KC_MEDIA_REWIND` |`KC_MRWD`|Previous Track (macOS) |
|
||||
|`KC_BRIGHTNESS_UP` |`KC_BRIU`|Brightness Up |
|
||||
|`KC_BRIGHTNESS_DOWN` |`KC_BRID`|Brightness Down |
|
||||
|Key |Aliases |Description |
|
||||
|-----------------------|---------|-------------------|
|
||||
|`KC_SYSTEM_POWER` |`KC_PWR` |System Power Down |
|
||||
|`KC_SYSTEM_SLEEP` |`KC_SLEP`|System Sleep |
|
||||
|`KC_SYSTEM_WAKE` |`KC_WAKE`|System Wake |
|
||||
|`KC_AUDIO_MUTE` |`KC_MUTE`|Mute |
|
||||
|`KC_AUDIO_VOL_UP` |`KC_VOLU`|Volume Up |
|
||||
|`KC_AUDIO_VOL_DOWN` |`KC_VOLD`|Volume Down |
|
||||
|`KC_MEDIA_NEXT_TRACK` |`KC_MNXT`|Next Track |
|
||||
|`KC_MEDIA_PREV_TRACK` |`KC_MPRV`|Previous Track |
|
||||
|`KC_MEDIA_STOP` |`KC_MSTP`|Stop Track |
|
||||
|`KC_MEDIA_PLAY_PAUSE` |`KC_MPLY`|Play/Pause Track |
|
||||
|`KC_MEDIA_SELECT` |`KC_MSEL`|Launch Media Player|
|
||||
|`KC_MEDIA_EJECT` |`KC_EJCT`|Eject |
|
||||
|`KC_MAIL` | |Launch Mail |
|
||||
|`KC_CALCULATOR` |`KC_CALC`|Launch Calculator |
|
||||
|`KC_MY_COMPUTER` |`KC_MYCM`|Launch My Computer |
|
||||
|`KC_WWW_SEARCH` |`KC_WSCH`|Browser Search |
|
||||
|`KC_WWW_HOME` |`KC_WHOM`|Browser Home |
|
||||
|`KC_WWW_BACK` |`KC_WBAK`|Browser Back |
|
||||
|`KC_WWW_FORWARD` |`KC_WFWD`|Browser Forward |
|
||||
|`KC_WWW_STOP` |`KC_WSTP`|Browser Stop |
|
||||
|`KC_WWW_REFRESH` |`KC_WREF`|Browser Refresh |
|
||||
|`KC_WWW_FAVORITES` |`KC_WFAV`|Browser Favorites |
|
||||
|`KC_MEDIA_FAST_FORWARD`|`KC_MFFD`|Next Track |
|
||||
|`KC_MEDIA_REWIND` |`KC_MRWD`|Previous Track |
|
||||
|`KC_BRIGHTNESS_UP` |`KC_BRIU`|Brightness Up |
|
||||
|`KC_BRIGHTNESS_DOWN` |`KC_BRID`|Brightness Down |
|
||||
|
||||
## Number Pad
|
||||
|
||||
@ -248,7 +248,7 @@ These keycodes are not part of the Keyboard/Keypad usage page. The `SYSTEM_` key
|
||||
|
||||
## Special Keys
|
||||
|
||||
In addition to these, keycodes in the range of `0xA5-DF` are reserved for internal use by TMK.
|
||||
In addition to these, keycodes in the range of `0xA5-DF` are reserved for internal use.
|
||||
|
||||
|Key |Aliases |Description |
|
||||
|----------------|--------------------|---------------------------------------|
|
||||
|
@ -37,26 +37,45 @@ We've tried to make QMK as easy to set up as possible. You only have to prepare
|
||||
[Must Know Linux Commands](https://www.guru99.com/must-know-linux-commands.html)<br>
|
||||
[Some Basic Unix Commands](https://www.tjhsst.edu/~dhyatt/superap/unixcmd.html)
|
||||
|
||||
### Windows
|
||||
<!-- tabs:start -->
|
||||
|
||||
You will need to install MSYS2, Git, and the QMK CLI.
|
||||
### ** Windows **
|
||||
|
||||
Follow the installation instructions on the [MSYS2 homepage](http://www.msys2.org). Close any open MSYS terminals and open a new MinGW 64-bit terminal. **NOTE: This is *not* the same as the MSYS terminal that opens when installation is completed.**
|
||||
#### Prerequisites
|
||||
|
||||
Then, run the following:
|
||||
You will need to install MSYS2, Git and Python. Follow the installation instructions on https://www.msys2.org.
|
||||
|
||||
Once MSYS2 is installed, close any open MSYS terminals and open a new MinGW 64-bit terminal.
|
||||
|
||||
!> **NOTE:** The MinGW 64-bit terminal is *not* the same as the MSYS terminal that opens when installation is completed. Your prompt should say "MINGW64" in purple text, rather than "MSYS". See [this page](https://www.msys2.org/wiki/MSYS2-introduction/#subsystems) for more information on the differences.
|
||||
|
||||
Then run the following command:
|
||||
|
||||
pacman --needed --noconfirm --disable-download-timeout -S git mingw-w64-x86_64-toolchain mingw-w64-x86_64-python3-pip
|
||||
|
||||
#### Installation
|
||||
|
||||
Install the QMK CLI by running:
|
||||
|
||||
python3 -m pip install qmk
|
||||
|
||||
### macOS
|
||||
### ** macOS **
|
||||
|
||||
You will need to install Homebrew. Follow the instructions on the [Homebrew homepage](https://brew.sh).
|
||||
QMK maintains a Homebrew tap and formula which will automatically install the CLI and all necessary dependencies.
|
||||
|
||||
After Homebrew is installed run this command:
|
||||
#### Prerequisites
|
||||
|
||||
You will need to install Homebrew. Follow the instructions on https://brew.sh.
|
||||
|
||||
#### Installation
|
||||
|
||||
Install the QMK CLI by running:
|
||||
|
||||
brew install qmk/qmk/qmk
|
||||
|
||||
### Linux
|
||||
### ** Linux/WSL **
|
||||
|
||||
#### Prerequisites
|
||||
|
||||
You will need to install Git and Python. It's very likely that you already have both, but if not, one of the following commands should install them:
|
||||
|
||||
@ -66,30 +85,63 @@ You will need to install Git and Python. It's very likely that you already have
|
||||
* Void: `sudo xbps-install -y git python3-pip`
|
||||
* Solus: `sudo eopkg -y install git python3`
|
||||
* Sabayon: `sudo equo install dev-vcs/git dev-python/pip`
|
||||
* Gentoo: `sudo emerge dev-vcs/git dev-python/pip`
|
||||
|
||||
Install the global CLI to bootstrap your system:
|
||||
#### Installation
|
||||
|
||||
`python3 -m pip install --user qmk` (on Arch-based distros you can also try the `qmk` package from AUR (**note**: it's maintained by a community member): `yay -S qmk`)
|
||||
Install the QMK CLI by running:
|
||||
|
||||
### FreeBSD
|
||||
python3 -m pip install --user qmk
|
||||
|
||||
On Arch-based distros you can also try the `qmk` package from AUR (**NOTE**: this package is maintained by a community member, and at the time of writing marks some dependencies as optional that should not be):
|
||||
|
||||
yay -S qmk
|
||||
|
||||
### ** FreeBSD **
|
||||
|
||||
#### Prerequisites
|
||||
|
||||
You will need to install Git and Python. It's possible that you already have both, but if not, run the following commands to install them:
|
||||
|
||||
pkg install git python3
|
||||
|
||||
Make sure that `$HOME/.local/bin` is added to your `$PATH` so that locally install Python packages are available.
|
||||
Make sure that `$HOME/.local/bin` is added to your `$PATH` so that locally installed Python packages are available.
|
||||
|
||||
Once installed, you can install QMK CLI:
|
||||
#### Installation
|
||||
|
||||
Install the QMK CLI by running:
|
||||
|
||||
python3 -m pip install --user qmk
|
||||
|
||||
<!-- tabs:end -->
|
||||
|
||||
## 3. Run QMK Setup :id=set-up-qmk
|
||||
|
||||
<!-- tabs:start -->
|
||||
|
||||
### ** Windows **
|
||||
|
||||
After installing QMK you can set it up with this command:
|
||||
|
||||
qmk setup
|
||||
|
||||
In most situations you will want to answer Yes to all of the prompts.
|
||||
In most situations you will want to answer `y` to all of the prompts.
|
||||
|
||||
### ** macOS **
|
||||
|
||||
After installing QMK you can set it up with this command:
|
||||
|
||||
qmk setup
|
||||
|
||||
In most situations you will want to answer `y` to all of the prompts.
|
||||
|
||||
### ** Linux/WSL **
|
||||
|
||||
After installing QMK you can set it up with this command:
|
||||
|
||||
qmk setup
|
||||
|
||||
In most situations you will want to answer `y` to all of the prompts.
|
||||
|
||||
?>**Note on Debian, Ubuntu and their derivatives**:
|
||||
It's possible, that you will get an error saying something like: `bash: qmk: command not found`.
|
||||
@ -97,12 +149,22 @@ This is due to a [bug](https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=839155)
|
||||
Sadly, Ubuntu reitroduced this bug and is [yet to fix it](https://bugs.launchpad.net/ubuntu/+source/bash/+bug/1588562).
|
||||
Luckily, the fix is easy. Run this as your user: `echo 'PATH="$HOME/.local/bin:$PATH"' >> $HOME/.bashrc && source $HOME/.bashrc`
|
||||
|
||||
### ** FreeBSD **
|
||||
|
||||
After installing QMK you can set it up with this command:
|
||||
|
||||
qmk setup
|
||||
|
||||
In most situations you will want to answer `y` to all of the prompts.
|
||||
|
||||
?>**Note on FreeBSD**:
|
||||
It is suggested to run `qmk setup` as a non-`root` user to start with, but this will likely identify packages that need to be installed to your
|
||||
base system using `pkg`. However the installation will probably fail when run as an unprivileged user.
|
||||
To manually install the base dependencies, run `./util/qmk_install.sh` either as `root`, or with `sudo`.
|
||||
Once that completes, re-run `qmk setup` to complete the setup and checks.
|
||||
|
||||
<!-- tabs:end -->
|
||||
|
||||
?> If you already know [how to use GitHub](getting_started_github.md), we recommend that you create your own fork and use `qmk setup <github_username>/qmk_firmware` to clone your personal fork. If you don't know what that means you can safely ignore this message.
|
||||
|
||||
## 4. Test Your Build Environment
|
||||
|
@ -61,4 +61,4 @@ To implement your own version of this function, in your keyboard's source files:
|
||||
void board_init(void) {
|
||||
// initialize anything that requires ChibiOS
|
||||
}
|
||||
```
|
||||
```
|
||||
|
@ -27,3 +27,20 @@
|
||||
.markdown-section hr, .search {
|
||||
border-bottom: 1px solid #777 !important;
|
||||
}
|
||||
|
||||
|
||||
:root {
|
||||
--docsifytabs-border-color: #555;
|
||||
--docsifytabs-tab-highlight-color: var(--theme-color,#ea6f5a);
|
||||
|
||||
--docsifytabs-tab-background: #444;
|
||||
--docsifytabs-tab-background-active: #3f3f3f;
|
||||
}
|
||||
|
||||
.docsify-tabs__tab:focus {
|
||||
outline: none !important;
|
||||
}
|
||||
|
||||
.docsify-tabs__content .anchor {
|
||||
transition: none;
|
||||
}
|
||||
|
@ -28,3 +28,20 @@
|
||||
.markdown-section pre {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
|
||||
:root {
|
||||
--docsifytabs-border-color: #ddd;
|
||||
--docsifytabs-tab-highlight-color: var(--theme-color, #0074d9);
|
||||
|
||||
--docsifytabs-tab-background: #f8f8f8;
|
||||
--docsifytabs-tab-background-active: transparent;
|
||||
}
|
||||
|
||||
.docsify-tabs__tab:focus {
|
||||
outline: none !important;
|
||||
}
|
||||
|
||||
.docsify-tabs__content .anchor {
|
||||
transition: none;
|
||||
}
|
||||
|
@ -1,5 +1,3 @@
|
||||
#ifndef LCD_H
|
||||
#define LCD_H
|
||||
/*************************************************************************
|
||||
Title : C include file for the HD44780U LCD library (lcd.c)
|
||||
Author: Peter Fleury <pfleury@gmx.ch> http://tinyurl.com/peterfleury
|
||||
@ -43,6 +41,8 @@
|
||||
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <avr/pgmspace.h>
|
||||
|
||||
@ -346,5 +346,3 @@ extern void lcd_data(uint8_t data);
|
||||
#define lcd_puts_P(__s) lcd_puts_p(PSTR(__s))
|
||||
|
||||
/**@}*/
|
||||
|
||||
#endif // LCD_H
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user