mirror of
https://github.com/qmk/qmk_firmware.git
synced 2024-12-04 08:55:10 +00:00
Compare commits
5 Commits
3ad2c37c08
...
9c3c159286
Author | SHA1 | Date | |
---|---|---|---|
|
9c3c159286 | ||
|
74c033eaf2 | ||
|
5ace174cd3 | ||
|
b5cf96f1dd | ||
|
b1e6b3798a |
@ -21,9 +21,9 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#include <stdbool.h>
|
||||
|
||||
/**
|
||||
* \defgroup hd44780
|
||||
* \file
|
||||
*
|
||||
* HD44780 Character LCD Driver
|
||||
* \defgroup hd44780 HD44780 Character LCD Driver
|
||||
* \{
|
||||
*/
|
||||
|
||||
|
19
keyboards/hazel/bad_wings/config.h
Normal file
19
keyboards/hazel/bad_wings/config.h
Normal file
@ -0,0 +1,19 @@
|
||||
// Copyright 2023 Jason Hazel (@jasonhazel)
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#define SPI_SCK_PIN GP2
|
||||
#define SPI_MOSI_PIN GP3
|
||||
#define SPI_MISO_PIN GP4
|
||||
|
||||
#define SHIFTREG_MATRIX_COL_CS GP0
|
||||
#define SHIFTREG_DIVISOR 8
|
||||
#define SHIFTREG_ROWS 5
|
||||
#define SHIFTREG_COLS 8
|
||||
|
||||
#define MATRIX_ROW_PINS_SR { GP26, GP27, GP28, GP29, GP6 }
|
||||
|
||||
#define POINTING_DEVICE_CS_PIN GP1
|
||||
#define CIRQUE_PINNACLE_DIAMETER_MM 35
|
||||
#define POINTING_DEVICE_ROTATION_90
|
12
keyboards/hazel/bad_wings/halconf.h
Normal file
12
keyboards/hazel/bad_wings/halconf.h
Normal file
@ -0,0 +1,12 @@
|
||||
// Copyright 2023 Jason Hazel (@jasonhazel)
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#define HAL_USE_SPI TRUE
|
||||
#define HAL_USE_I2C TRUE
|
||||
#define HAL_USE_PWM TRUE
|
||||
#define SPI_USE_WAIT TRUE
|
||||
#define SPI_SELECT_MODE SPI_SELECT_MODE_PAD
|
||||
|
||||
#include_next <halconf.h>
|
66
keyboards/hazel/bad_wings/info.json
Normal file
66
keyboards/hazel/bad_wings/info.json
Normal file
@ -0,0 +1,66 @@
|
||||
{
|
||||
"keyboard_name": "Bad Wings",
|
||||
"manufacturer": "Hazel",
|
||||
"maintainer": "jasonhazel",
|
||||
"url": "https://shop.hazel.cc/products/bad-wings",
|
||||
"usb": {
|
||||
"vid": "0x4A48",
|
||||
"pid": "0x4257",
|
||||
"device_version": "1.0.0"
|
||||
},
|
||||
"processor": "RP2040",
|
||||
"bootloader": "rp2040",
|
||||
"matrix_size": {
|
||||
"cols": 8,
|
||||
"rows": 5
|
||||
},
|
||||
"diode_direction": "COL2ROW",
|
||||
"features": {
|
||||
"bootmagic": true,
|
||||
"deferred_exec": true,
|
||||
"nkro": false
|
||||
},
|
||||
"community_layouts": [ "split_3x5_3" ],
|
||||
"layouts": {
|
||||
"LAYOUT_split_3x5_3": {
|
||||
"layout": [
|
||||
{ "label": "K00", "matrix": [0, 0], "w": 1, "x": 0, "y": 0.75 },
|
||||
{ "label": "K10", "matrix": [1, 0], "w": 1, "x": 1, "y": 0.5 },
|
||||
{ "label": "K20", "matrix": [2, 0], "w": 1, "x": 2, "y": 0 },
|
||||
{ "label": "K30", "matrix": [3, 0], "w": 1, "x": 3, "y": 0.25 },
|
||||
{ "label": "K40", "matrix": [4, 0], "w": 1, "x": 4, "y": 0.36 },
|
||||
{ "label": "K44", "matrix": [4, 4], "w": 1, "x": 8, "y": 0.36 },
|
||||
{ "label": "K34", "matrix": [3, 4], "w": 1, "x": 9, "y": 0.25 },
|
||||
{ "label": "K24", "matrix": [2, 4], "w": 1, "x": 10, "y": 0 },
|
||||
{ "label": "K14", "matrix": [1, 4], "w": 1, "x": 11, "y": 0.5 },
|
||||
{ "label": "K04", "matrix": [0, 4], "w": 1, "x": 12, "y": 0.75 },
|
||||
{ "label": "K01", "matrix": [0, 1], "w": 1, "x": 0, "y": 1.75 },
|
||||
{ "label": "K11", "matrix": [1, 1], "w": 1, "x": 1, "y": 1.5 },
|
||||
{ "label": "K21", "matrix": [2, 1], "w": 1, "x": 2, "y": 1 },
|
||||
{ "label": "K31", "matrix": [3, 1], "w": 1, "x": 3, "y": 1.25 },
|
||||
{ "label": "K41", "matrix": [4, 1], "w": 1, "x": 4, "y": 1.36 },
|
||||
{ "label": "K45", "matrix": [4, 5], "w": 1, "x": 8, "y": 1.36 },
|
||||
{ "label": "K35", "matrix": [3, 5], "w": 1, "x": 9, "y": 1.25 },
|
||||
{ "label": "K25", "matrix": [2, 5], "w": 1, "x": 10, "y": 1 },
|
||||
{ "label": "K15", "matrix": [1, 5], "w": 1, "x": 11, "y": 1.5 },
|
||||
{ "label": "K05", "matrix": [0, 5], "w": 1, "x": 12, "y": 1.75 },
|
||||
{ "label": "K02", "matrix": [0, 2], "w": 1, "x": 0, "y": 2.75 },
|
||||
{ "label": "K12", "matrix": [1, 2], "w": 1, "x": 1, "y": 2.5 },
|
||||
{ "label": "K22", "matrix": [2, 2], "w": 1, "x": 2, "y": 2 },
|
||||
{ "label": "K32", "matrix": [3, 2], "w": 1, "x": 3, "y": 2.25 },
|
||||
{ "label": "K42", "matrix": [4, 2], "w": 1, "x": 4, "y": 2.36 },
|
||||
{ "label": "K46", "matrix": [4, 6], "w": 1, "x": 8, "y": 2.36 },
|
||||
{ "label": "K36", "matrix": [3, 6], "w": 1, "x": 9, "y": 2.25 },
|
||||
{ "label": "K26", "matrix": [2, 6], "w": 1, "x": 10, "y": 2 },
|
||||
{ "label": "K16", "matrix": [1, 6], "w": 1, "x": 11, "y": 2.5 },
|
||||
{ "label": "K06", "matrix": [0, 6], "w": 1, "x": 12, "y": 2.75 },
|
||||
{ "label": "K23", "matrix": [2, 3], "w": 1, "x": 3, "y": 3.25 },
|
||||
{ "label": "K33", "matrix": [3, 3], "w": 1, "x": 4, "y": 3.36 },
|
||||
{ "label": "K43", "matrix": [4, 3], "w": 1, "x": 5, "y": 3.47 },
|
||||
{ "label": "K47", "matrix": [4, 7], "w": 1, "x": 7, "y": 3.47 },
|
||||
{ "label": "K37", "matrix": [3, 7], "w": 1, "x": 8, "y": 3.36 },
|
||||
{ "label": "K27", "matrix": [2, 7], "w": 1, "x": 9, "y": 3.25 }
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
16
keyboards/hazel/bad_wings/keymaps/default/config.h
Normal file
16
keyboards/hazel/bad_wings/keymaps/default/config.h
Normal file
@ -0,0 +1,16 @@
|
||||
// Copyright 2023 Jason Hazel (@jasonhazel)
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#define TAPPING_TERM 200
|
||||
#define PERMISSIVE_HOLD
|
||||
#define IGNORE_MOD_TAP_INTERRUPT
|
||||
#define TAPPING_FORCE_HOLD
|
||||
#define TAPPING_TERM_PER_KEY
|
||||
#define ONESHOT_TAP_TOGGLE 10
|
||||
#define ONESHOT_TIMEOUT 500
|
||||
#define DOUBLE_TAP_SHIFT_TURNS_ON_CAPS_WORD
|
||||
#define CIRQUE_PINNACLE_TAP_ENABLE
|
||||
#define CIRQUE_PINNACLE_POSITION_MODE CIRQUE_PINNACLE_ABSOLUTE_MODE
|
||||
#define CIRQUE_DEVICE_GESTURES_SCROLL_ENABLE
|
35
keyboards/hazel/bad_wings/keymaps/default/keymap.c
Normal file
35
keyboards/hazel/bad_wings/keymaps/default/keymap.c
Normal file
@ -0,0 +1,35 @@
|
||||
// Copyright 2023 Jason Hazel (@jasonhazel)
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#include QMK_KEYBOARD_H
|
||||
|
||||
layer_state_t layer_state_set_user(layer_state_t state) {
|
||||
return update_tri_layer_state(state, 1, 2, 3);
|
||||
}
|
||||
|
||||
const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
|
||||
[0] = LAYOUT_split_3x5_3(
|
||||
KC_Q, KC_W, KC_E, KC_R, KC_T, KC_Y, KC_U, KC_I, KC_O, KC_P, \
|
||||
KC_A, KC_S, KC_D, KC_F, KC_G, KC_H, KC_J, KC_K, KC_L, KC_QUOT, \
|
||||
KC_Z, LGUI_T(KC_X), LALT_T(KC_C), KC_V, KC_B, KC_N, KC_M, KC_COMM, KC_DOT, KC_SLSH, \
|
||||
KC_LCTL, OSL(1), OSM(MOD_LSFT), KC_SPC, LT(2, KC_BSPC), KC_ENT
|
||||
),
|
||||
[1] = LAYOUT_split_3x5_3(
|
||||
KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_RBRC, KC_RCBR, KC_RPRN, KC_RABK, KC_NO, \
|
||||
KC_GRV, KC_TILD, KC_UNDS, KC_EQL, KC_NO, KC_LBRC, KC_LCBR, KC_LPRN, KC_LABK, KC_BACKSLASH, \
|
||||
KC_NO, KC_NO, KC_PLUS, KC_MINS, KC_NO, KC_NO, KC_NO, KC_COLN, KC_DOT, KC_SCLN, \
|
||||
KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS
|
||||
),
|
||||
[2] = LAYOUT_split_3x5_3(
|
||||
KC_EXLM, KC_AT, KC_HASH, KC_DLR, KC_PERC, KC_CIRC, KC_AMPR, KC_ASTR, KC_PIPE, KC_NO, \
|
||||
KC_1, KC_2, KC_3, KC_4, KC_5, KC_6, KC_7, KC_8, KC_9, KC_0, \
|
||||
KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_DOT, KC_NO, \
|
||||
KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS
|
||||
),
|
||||
[3] = LAYOUT_split_3x5_3(
|
||||
KC_ESC, KC_F1, KC_F4, KC_F7, KC_F10, KC_NO, KC_HOME, KC_UP, KC_END, KC_BSPC, \
|
||||
KC_TAB, KC_F2, KC_F5, KC_F8, KC_F11, KC_NO, KC_LEFT, KC_DOWN, KC_RIGHT, KC_ENT, \
|
||||
KC_NO, KC_F3, KC_F6, KC_F9, KC_F12, KC_NO, KC_MPRV, KC_MPLY, KC_MNXT, KC_DEL, \
|
||||
KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS
|
||||
)
|
||||
};
|
2
keyboards/hazel/bad_wings/keymaps/default/rules.mk
Normal file
2
keyboards/hazel/bad_wings/keymaps/default/rules.mk
Normal file
@ -0,0 +1,2 @@
|
||||
MOUSEKEY_ENABLE = yes
|
||||
EXTRAKEY_ENABLE = yes
|
137
keyboards/hazel/bad_wings/matrix.c
Normal file
137
keyboards/hazel/bad_wings/matrix.c
Normal file
@ -0,0 +1,137 @@
|
||||
// Copyright 2022 @sadekbaroudi (Sadek Baroudi)
|
||||
// Copyright 2023 @jasonhazel (Jason Hazel)
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#include "quantum.h"
|
||||
#include "spi_master.h"
|
||||
#include <string.h> /* memset */
|
||||
#include <unistd.h> /* close */
|
||||
#include "quantum.h"
|
||||
#include "matrix.h"
|
||||
|
||||
#if (!defined(SHIFTREG_MATRIX_COL_CS))
|
||||
# error Missing shift register I/O pin definitions
|
||||
#endif
|
||||
|
||||
int matrixArraySize = SHIFTREG_ROWS * sizeof(matrix_row_t);
|
||||
matrix_row_t oldMatrix[SHIFTREG_ROWS];
|
||||
|
||||
#define SHIFTREG_OUTPUT_BITS 8
|
||||
pin_t rowPinsSR[SHIFTREG_ROWS] = MATRIX_ROW_PINS_SR;
|
||||
|
||||
// semaphore to make sure SPI doesn't get called multiple times
|
||||
static bool shiftRegisterSPILocked = false;
|
||||
|
||||
void semaphore_lock(bool value) {
|
||||
shiftRegisterSPILocked = value;
|
||||
}
|
||||
|
||||
bool semaphore_is_locked(void) {
|
||||
return shiftRegisterSPILocked;
|
||||
}
|
||||
|
||||
void sr_74hc595_spi_stop(void) {
|
||||
spi_stop();
|
||||
semaphore_lock(false);
|
||||
}
|
||||
|
||||
bool sr_74hc595_spi_start(void) {
|
||||
if (!spi_start(SHIFTREG_MATRIX_COL_CS, false, 0, SHIFTREG_DIVISOR)) {
|
||||
dprintf("74hc595 matrix: failed to start spi\n");
|
||||
sr_74hc595_spi_stop();
|
||||
return false;
|
||||
}
|
||||
|
||||
semaphore_lock(true);
|
||||
wait_us(1); // not sure if I need this
|
||||
return true;
|
||||
}
|
||||
|
||||
bool sr_74hc595_spi_send_byte(uint8_t data) {
|
||||
sr_74hc595_spi_start();
|
||||
writePinLow(SHIFTREG_MATRIX_COL_CS);
|
||||
matrix_io_delay();
|
||||
spi_write(data);
|
||||
matrix_io_delay();
|
||||
writePinHigh(SHIFTREG_MATRIX_COL_CS);
|
||||
sr_74hc595_spi_stop();
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the entire shift register to be full of inactive bits
|
||||
*/
|
||||
void clearColumns(void) {
|
||||
uint8_t value = 0b00000000;
|
||||
sr_74hc595_spi_send_byte(value);
|
||||
}
|
||||
|
||||
void setColumn(int columnShift, bool test_run) {
|
||||
uint8_t columnShiftByte = ((uint8_t)1 << columnShift);
|
||||
if(test_run) {
|
||||
dprintf("byte sent: %d\n", columnShiftByte);
|
||||
}
|
||||
sr_74hc595_spi_send_byte(columnShiftByte);
|
||||
}
|
||||
|
||||
/*
|
||||
* override of the qmk intialization function
|
||||
*/
|
||||
void matrix_init_custom(void) {
|
||||
wait_ms(300);
|
||||
spi_init();
|
||||
// Set up the initial states for all the row pins
|
||||
for (int r = 0; r < SHIFTREG_ROWS; r++) {
|
||||
// Note: This needs to use the internal pull down resistors, and atmegas do *not* support that
|
||||
setPinInputLow(rowPinsSR[r]);
|
||||
}
|
||||
|
||||
// Set the CS to low by default, and specify as an output pin
|
||||
writePinHigh(SHIFTREG_MATRIX_COL_CS); // should be high when using SPI?
|
||||
setPinOutput(SHIFTREG_MATRIX_COL_CS);
|
||||
|
||||
// Since it's the init, deactivate all the columns. We'll activate once we get to the matrix scan
|
||||
clearColumns();
|
||||
}
|
||||
|
||||
bool matrix_scan_custom(matrix_row_t current_matrix[]) {
|
||||
// respect the semaphore
|
||||
if (semaphore_is_locked()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Keep track of if something was modified
|
||||
bool matrix_has_changed = false;
|
||||
|
||||
// reset the current matrix, as we'll be updating and comparing to the old matrix
|
||||
memset(current_matrix, 0, matrixArraySize);
|
||||
|
||||
|
||||
bool debug_output = false;
|
||||
// Loop through the columns, activating one at a time, and read the rows, and place in the new current_matrix
|
||||
for (int c = 0; c < SHIFTREG_COLS; c++) {
|
||||
if (debug_output) {
|
||||
dprintf("column iteration: %d\n", c);
|
||||
}
|
||||
setColumn(c, debug_output);
|
||||
matrix_io_delay();
|
||||
|
||||
for (int r = 0; r < SHIFTREG_ROWS; r++) {
|
||||
current_matrix[r] |= ((readPin(rowPinsSR[r]) ? 1 : 0) << c);
|
||||
}
|
||||
}
|
||||
|
||||
matrix_has_changed = memcmp(current_matrix, oldMatrix, matrixArraySize) != 0;
|
||||
memcpy(oldMatrix, current_matrix, matrixArraySize);
|
||||
|
||||
if (matrix_has_changed) {
|
||||
matrix_print();
|
||||
}
|
||||
|
||||
|
||||
// Deactivate all the columns for the next run.
|
||||
clearColumns();
|
||||
matrix_io_delay();
|
||||
|
||||
return matrix_has_changed;
|
||||
}
|
11
keyboards/hazel/bad_wings/mcuconf.c
Normal file
11
keyboards/hazel/bad_wings/mcuconf.c
Normal file
@ -0,0 +1,11 @@
|
||||
// Copyright 2023 Jason Hazel (@jasonhazel)
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include_next "mcuconf.h"
|
||||
|
||||
#undef RP_SPI_USE_SPI0
|
||||
#define RP_SPI_USE_SPI0 TRUE
|
||||
#undef RP_I2C_USE_I2C1
|
||||
#define RP_I2C_USE_I2C1 TRUE
|
27
keyboards/hazel/bad_wings/readme.md
Normal file
27
keyboards/hazel/bad_wings/readme.md
Normal file
@ -0,0 +1,27 @@
|
||||
# Bad Wings
|
||||
|
||||
![Bad Wings](https://i.imgur.com/QpfcEj8h.png)
|
||||
|
||||
36 key unibody split
|
||||
|
||||
* Keyboard Maintainer: [Jason Hazel](https://github.com/jasonhazel)
|
||||
* Hardware Supported: Bad Wings v1
|
||||
* Hardware Availability: [Hazel's Garage](https://shop.hazel.cc/products/bad-wings)
|
||||
|
||||
Make example for this keyboard (after setting up your build environment):
|
||||
|
||||
make hazel/bad_wings:default
|
||||
|
||||
Flashing example for this keyboard:
|
||||
|
||||
make hazel/bad_wings: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 top-left key and plug in the keyboard
|
||||
* **Physical reset button**: Hold Xiao B button, press Xiao R button, release B
|
||||
* **Keycode in layout**: There is no key mapped to `QK_BOOT` in the pre-created keymaps, but you may assign this key in any keymaps you create
|
10
keyboards/hazel/bad_wings/rules.mk
Normal file
10
keyboards/hazel/bad_wings/rules.mk
Normal file
@ -0,0 +1,10 @@
|
||||
TRI_LAYER_ENABLE = yes
|
||||
CAPS_WORD_ENABLE = yes
|
||||
|
||||
SRC += matrix.c
|
||||
|
||||
QUANTUM_LIB_SRC += spi_master.c
|
||||
CUSTOM_MATRIX = lite
|
||||
|
||||
POINTING_DEVICE_DRIVER = cirque_pinnacle_spi
|
||||
POINTING_DEVICE_ENABLE = yes
|
@ -13,17 +13,15 @@
|
||||
* 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"
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
/**
|
||||
* \defgroup digitizer
|
||||
* \file
|
||||
*
|
||||
* HID Digitizer
|
||||
* defgroup digitizer HID Digitizer
|
||||
* \{
|
||||
*/
|
||||
|
||||
|
@ -22,9 +22,9 @@
|
||||
#include "gpio.h"
|
||||
|
||||
/**
|
||||
* \defgroup joystick
|
||||
* \file
|
||||
*
|
||||
* HID Joystick
|
||||
* \defgroup joystick HID Joystick
|
||||
* \{
|
||||
*/
|
||||
|
||||
|
@ -5,9 +5,9 @@
|
||||
#include <stdint.h>
|
||||
|
||||
/**
|
||||
* \defgroup leader
|
||||
* \file
|
||||
*
|
||||
* Leader Key
|
||||
* \defgroup leader Leader Key
|
||||
* \{
|
||||
*/
|
||||
|
||||
|
@ -21,9 +21,9 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#include <stdbool.h>
|
||||
|
||||
/**
|
||||
* \defgroup programmable_button
|
||||
* \file
|
||||
*
|
||||
* HID Programmable Buttons
|
||||
* \defgroup programmable_button HID Programmable Buttons
|
||||
* \{
|
||||
*/
|
||||
|
||||
|
@ -3,10 +3,15 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
/** \file
|
||||
/**
|
||||
* \file
|
||||
*
|
||||
* Exposes a set of functionality to act as a virtual padlock for your device
|
||||
* ... As long as that padlock is made of paper and its currently raining.
|
||||
* \defgroup secure Secure API
|
||||
*
|
||||
* \brief Exposes a set of functionality to act as a virtual padlock for your device
|
||||
* ...as long as that padlock is made of paper and it's currently raining.
|
||||
*
|
||||
* \{
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
@ -77,3 +82,5 @@ bool secure_hook_user(secure_status_t secure_status);
|
||||
/** \brief keyboard hook called when changing secure status device
|
||||
*/
|
||||
bool secure_hook_kb(secure_status_t secure_status);
|
||||
|
||||
/** \} */
|
||||
|
@ -15,9 +15,11 @@
|
||||
*/
|
||||
|
||||
/**
|
||||
* \defgroup send_string
|
||||
* \file
|
||||
*
|
||||
* Send String API. These functions allow you to create macros by typing out sequences of keystrokes.
|
||||
* \defgroup send_string Send String API
|
||||
*
|
||||
* \brief These functions allow you to create macros by typing out sequences of keystrokes.
|
||||
* \{
|
||||
*/
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user