DeskHop 0.63 (Bugfixes, small features)
- add gaming mode (use left shift + right shift + G to toggle) - rework HID queue, smoother operation of rotary dials (no packets lost) - fix dragging across multiple screens on the same output - improve read reliability for UI - move default keyboard hotkey for output switching to LCtrl + Caps Lock - change default X/Y speed to match 16:9 geometry
This commit is contained in:
parent
1fd0049039
commit
a249aa50f1
|
@ -1,7 +1,7 @@
|
||||||
cmake_minimum_required(VERSION 3.6)
|
cmake_minimum_required(VERSION 3.6)
|
||||||
|
|
||||||
set(VERSION_MAJOR 00)
|
set(VERSION_MAJOR 00)
|
||||||
set(VERSION_MINOR 147)
|
set(VERSION_MINOR 156)
|
||||||
|
|
||||||
set(PICO_SDK_FETCH_FROM_GIT off)
|
set(PICO_SDK_FETCH_FROM_GIT off)
|
||||||
set(PICO_BOARD=pico)
|
set(PICO_BOARD=pico)
|
||||||
|
|
|
@ -42,7 +42,7 @@ The actual switch happens at the very moment when one arrow stops moving and the
|
||||||
|
|
||||||
## Keyboard
|
## Keyboard
|
||||||
|
|
||||||
Acting as a USB Host and querying your keyboard periodically, it looks for a preconfigured hotkey in the hid report (usually Caps Lock for me). When found, it will forward all subsequent characters to the other output.
|
Acting as a USB Host and querying your keyboard periodically, it looks for a preconfigured hotkey in the hid report (usually Ctrl + Caps Lock for me). When found, it will forward all subsequent characters to the other output.
|
||||||
|
|
||||||
To have a visual indication which output you are using at any given moment, you can repurpose keyboard LEDs and have them provide the necessary feedback.
|
To have a visual indication which output you are using at any given moment, you can repurpose keyboard LEDs and have them provide the necessary feedback.
|
||||||
|
|
||||||
|
@ -101,6 +101,10 @@ This will make sure you won't accidentally leave your current screen. To turn of
|
||||||
You can lock both computers at once by using ```RIGHT CTRL + L```.
|
You can lock both computers at once by using ```RIGHT CTRL + L```.
|
||||||
To make use of this feature, first set up the OS for each output in config (since the shortcuts are different).
|
To make use of this feature, first set up the OS for each output in config (since the shortcuts are different).
|
||||||
|
|
||||||
|
### Gaming Mode
|
||||||
|
|
||||||
|
If you're gaming, there is a chance your game might not work properly with absolute mouse mode. To address that issue, a **gaming mode** is introduced, toggled by ```LEFT SHIFT + RIGHT SHIFT + G```. When in gaming mode, you are locked to the current screen and your mouse behaves like a standard relative mouse. This should also fix various virtual machine issues, currently unsupported operating systems etc.
|
||||||
|
|
||||||
### Screensaver
|
### Screensaver
|
||||||
|
|
||||||
Supposedly built in to prevent computer from entering standby, but truth be told - it is just fun to watch. **Off by default**, will make your mouse pointer bounce around the screen like a Pong ball. When enabled, it activates after a period of inactivity defined in user config header and automatically switches off as soon as you send any output towards that screen.
|
Supposedly built in to prevent computer from entering standby, but truth be told - it is just fun to watch. **Off by default**, will make your mouse pointer bounce around the screen like a Pong ball. When enabled, it activates after a period of inactivity defined in user config header and automatically switches off as soon as you send any output towards that screen.
|
||||||
|
@ -216,7 +220,8 @@ _Usage_
|
||||||
- ```Right CTRL + Right ALT``` - Toggle slower mouse mode
|
- ```Right CTRL + Right ALT``` - Toggle slower mouse mode
|
||||||
- ```Right CTRL + K``` - Lock/Unlock mouse desktop switching
|
- ```Right CTRL + K``` - Lock/Unlock mouse desktop switching
|
||||||
- ```Right CTRL + L``` - Lock both outputs at once (set output OS before, see shortcuts below)
|
- ```Right CTRL + L``` - Lock both outputs at once (set output OS before, see shortcuts below)
|
||||||
- ```Caps Lock``` - Switch between outputs
|
- ```Left Shift + Right Shift + G``` - Toggle gaming mode (lock to screen, act as standard mouse)
|
||||||
|
- ```Left CTRL + Caps Lock``` - Switch between outputs
|
||||||
|
|
||||||
### Switch cursor height calibration
|
### Switch cursor height calibration
|
||||||
|
|
||||||
|
|
BIN
disk/disk.img
BIN
disk/disk.img
Binary file not shown.
|
@ -67,6 +67,12 @@ void switchlock_hotkey_handler(device_t *state, hid_keyboard_report_t *report) {
|
||||||
send_value(state->switch_lock, SWITCH_LOCK_MSG);
|
send_value(state->switch_lock, SWITCH_LOCK_MSG);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* This key combo toggles gaming mode */
|
||||||
|
void toggle_relative_mode_handler(device_t *state, hid_keyboard_report_t *report) {
|
||||||
|
state->relative_mouse ^= 1;
|
||||||
|
send_value(state->relative_mouse, RELATIVE_MODE_MSG);
|
||||||
|
};
|
||||||
|
|
||||||
/* This key combo locks both outputs simultaneously */
|
/* This key combo locks both outputs simultaneously */
|
||||||
void screenlock_hotkey_handler(device_t *state, hid_keyboard_report_t *report) {
|
void screenlock_hotkey_handler(device_t *state, hid_keyboard_report_t *report) {
|
||||||
hid_keyboard_report_t lock_report = {0}, release_keys = {0};
|
hid_keyboard_report_t lock_report = {0}, release_keys = {0};
|
||||||
|
@ -199,9 +205,9 @@ void handle_wipe_config_msg(uart_packet_t *packet, device_t *state) {
|
||||||
load_config(state);
|
load_config(state);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Process consumer control message, TODO: use queue instead of sending directly */
|
/* Process consumer control message */
|
||||||
void handle_consumer_control_msg(uart_packet_t *packet, device_t *state) {
|
void handle_consumer_control_msg(uart_packet_t *packet, device_t *state) {
|
||||||
tud_hid_n_report(0, REPORT_ID_CONSUMER, &packet->data[0], CONSUMER_CONTROL_LENGTH);
|
queue_cc_packet(packet->data, state);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Process request to store config to flash */
|
/* Process request to store config to flash */
|
||||||
|
@ -219,6 +225,11 @@ void handle_proxy_msg(uart_packet_t *packet, device_t *state) {
|
||||||
queue_packet(&packet->data[1], (enum packet_type_e)packet->data[0], PACKET_DATA_LENGTH - 1);
|
queue_packet(&packet->data[1], (enum packet_type_e)packet->data[0], PACKET_DATA_LENGTH - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Process request to reboot the board */
|
||||||
|
void handle_toggle_relative_msg(uart_packet_t *packet, device_t *state) {
|
||||||
|
state->relative_mouse = packet->data[0];
|
||||||
|
}
|
||||||
|
|
||||||
/* Process api communication messages */
|
/* Process api communication messages */
|
||||||
void handle_api_msgs(uart_packet_t *packet, device_t *state) {
|
void handle_api_msgs(uart_packet_t *packet, device_t *state) {
|
||||||
uint8_t value_idx = packet->data[0];
|
uint8_t value_idx = packet->data[0];
|
||||||
|
@ -239,15 +250,24 @@ void handle_api_msgs(uart_packet_t *packet, device_t *state) {
|
||||||
memcpy(ptr, &packet->data[1], map->len);
|
memcpy(ptr, &packet->data[1], map->len);
|
||||||
}
|
}
|
||||||
else if (packet->type == GET_VAL_MSG) {
|
else if (packet->type == GET_VAL_MSG) {
|
||||||
uart_packet_t response = {.type=GET_VAL_MSG, .data={0}};
|
uart_packet_t response = {.type=GET_VAL_MSG, .data={[0] = value_idx}};
|
||||||
memcpy(response.data, ptr, map->len);
|
memcpy(&response.data[1], ptr, map->len);
|
||||||
queue_try_add(&state->cfg_queue_out, &response);
|
queue_cfg_packet(&response, state);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* With each GET/SET message, we reset the configuration mode timeout */
|
/* With each GET/SET message, we reset the configuration mode timeout */
|
||||||
reset_config_timer(state);
|
reset_config_timer(state);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Handle the "read all" message by calling our "read one" handler for each type */
|
||||||
|
void handle_api_read_all_msg(uart_packet_t *packet, device_t *state) {
|
||||||
|
uart_packet_t result = {.type=GET_VAL_MSG};
|
||||||
|
|
||||||
|
for (int i = 0; i < get_field_map_length(); i++) {
|
||||||
|
result.data[0] = get_field_map_index(i)->idx;
|
||||||
|
handle_api_msgs(&result, state);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Process request packet and create a response */
|
/* Process request packet and create a response */
|
||||||
void handle_request_byte_msg(uart_packet_t *packet, device_t *state) {
|
void handle_request_byte_msg(uart_packet_t *packet, device_t *state) {
|
||||||
|
|
|
@ -122,12 +122,14 @@ enum packet_type_e {
|
||||||
FLASH_LED_MSG = 9,
|
FLASH_LED_MSG = 9,
|
||||||
WIPE_CONFIG_MSG = 10,
|
WIPE_CONFIG_MSG = 10,
|
||||||
HEARTBEAT_MSG = 12,
|
HEARTBEAT_MSG = 12,
|
||||||
|
RELATIVE_MODE_MSG = 13,
|
||||||
CONSUMER_CONTROL_MSG = 14,
|
CONSUMER_CONTROL_MSG = 14,
|
||||||
SYSTEM_CONTROL_MSG = 15,
|
SYSTEM_CONTROL_MSG = 15,
|
||||||
SAVE_CONFIG_MSG = 18,
|
SAVE_CONFIG_MSG = 18,
|
||||||
REBOOT_MSG = 19,
|
REBOOT_MSG = 19,
|
||||||
GET_VAL_MSG = 20,
|
GET_VAL_MSG = 20,
|
||||||
SET_VAL_MSG = 21,
|
SET_VAL_MSG = 21,
|
||||||
|
GET_ALL_VALS_MSG = 22,
|
||||||
PROXY_PACKET_MSG = 23,
|
PROXY_PACKET_MSG = 23,
|
||||||
REQUEST_BYTE_MSG = 24,
|
REQUEST_BYTE_MSG = 24,
|
||||||
RESPONSE_BYTE_MSG = 25,
|
RESPONSE_BYTE_MSG = 25,
|
||||||
|
@ -166,7 +168,7 @@ typedef struct {
|
||||||
#define RAW_PACKET_LENGTH (START_LENGTH + PACKET_LENGTH)
|
#define RAW_PACKET_LENGTH (START_LENGTH + PACKET_LENGTH)
|
||||||
|
|
||||||
#define UART_QUEUE_LENGTH 256
|
#define UART_QUEUE_LENGTH 256
|
||||||
#define CFG_QUEUE_LENGTH 128
|
#define HID_QUEUE_LENGTH 128
|
||||||
#define KBD_QUEUE_LENGTH 128
|
#define KBD_QUEUE_LENGTH 128
|
||||||
#define MOUSE_QUEUE_LENGTH 512
|
#define MOUSE_QUEUE_LENGTH 512
|
||||||
|
|
||||||
|
@ -345,6 +347,25 @@ typedef struct TU_ATTR_PACKED {
|
||||||
uint8_t mode;
|
uint8_t mode;
|
||||||
} mouse_report_t;
|
} mouse_report_t;
|
||||||
|
|
||||||
|
/* Used to work around OS issues with absolute coordinates on
|
||||||
|
multiple desktops (Windows/MacOS) */
|
||||||
|
typedef struct {
|
||||||
|
uint8_t tip_pressure;
|
||||||
|
uint8_t buttons; // Buttons
|
||||||
|
uint16_t x; // X coordinate (0-32767)
|
||||||
|
uint16_t y; // Y coordinate (0-32767)
|
||||||
|
} touch_report_t;
|
||||||
|
|
||||||
|
/* This stores various packets other than kbd/mouse to go out
|
||||||
|
(configuration, consumer control, system...) */
|
||||||
|
typedef struct {
|
||||||
|
uint8_t instance;
|
||||||
|
uint8_t report_id;
|
||||||
|
uint8_t type;
|
||||||
|
uint8_t len;
|
||||||
|
uint8_t data[RAW_PACKET_LENGTH];
|
||||||
|
} hid_generic_pkt_t;
|
||||||
|
|
||||||
typedef enum { IDLE, READING_PACKET, PROCESSING_PACKET } receiver_state_t;
|
typedef enum { IDLE, READING_PACKET, PROCESSING_PACKET } receiver_state_t;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
@ -370,7 +391,7 @@ typedef struct {
|
||||||
int16_t mouse_buttons; // Store and update the state of mouse buttons
|
int16_t mouse_buttons; // Store and update the state of mouse buttons
|
||||||
|
|
||||||
config_t config; // Device configuration, loaded from flash or defaults used
|
config_t config; // Device configuration, loaded from flash or defaults used
|
||||||
queue_t cfg_queue_out; // Queue that stores outgoing vendor config messages
|
queue_t hid_queue_out; // Queue that stores outgoing hid messages
|
||||||
queue_t kbd_queue; // Queue that stores keyboard reports
|
queue_t kbd_queue; // Queue that stores keyboard reports
|
||||||
queue_t mouse_queue; // Queue that stores mouse reports
|
queue_t mouse_queue; // Queue that stores mouse reports
|
||||||
queue_t uart_tx_queue; // Queue that stores outgoing packets
|
queue_t uart_tx_queue; // Queue that stores outgoing packets
|
||||||
|
@ -427,6 +448,8 @@ void process_consumer_report(uint8_t *, int, uint8_t, hid_interface_t *);
|
||||||
void process_system_report(uint8_t *, int, uint8_t, hid_interface_t *);
|
void process_system_report(uint8_t *, int, uint8_t, hid_interface_t *);
|
||||||
void release_all_keys(device_t *);
|
void release_all_keys(device_t *);
|
||||||
void queue_kbd_report(hid_keyboard_report_t *, device_t *);
|
void queue_kbd_report(hid_keyboard_report_t *, device_t *);
|
||||||
|
void queue_cc_packet(uint8_t *, device_t *);
|
||||||
|
void queue_system_packet(uint8_t *, device_t *);
|
||||||
void send_key(hid_keyboard_report_t *, device_t *);
|
void send_key(hid_keyboard_report_t *, device_t *);
|
||||||
void send_consumer_control(uint8_t *, device_t *);
|
void send_consumer_control(uint8_t *, device_t *);
|
||||||
bool key_in_report(uint8_t, const hid_keyboard_report_t *);
|
bool key_in_report(uint8_t, const hid_keyboard_report_t *);
|
||||||
|
@ -474,7 +497,7 @@ void reboot(void);
|
||||||
/********* Tasks **********/
|
/********* Tasks **********/
|
||||||
void process_uart_tx_task(device_t *);
|
void process_uart_tx_task(device_t *);
|
||||||
void process_mouse_queue_task(device_t *);
|
void process_mouse_queue_task(device_t *);
|
||||||
void process_cfg_queue_task(device_t *);
|
void process_hid_queue_task(device_t *);
|
||||||
void process_kbd_queue_task(device_t *);
|
void process_kbd_queue_task(device_t *);
|
||||||
void usb_device_task(device_t *);
|
void usb_device_task(device_t *);
|
||||||
void kick_watchdog_task(device_t *);
|
void kick_watchdog_task(device_t *);
|
||||||
|
@ -495,7 +518,10 @@ void reset_config_timer(device_t *);
|
||||||
|
|
||||||
extern const field_map_t api_field_map[];
|
extern const field_map_t api_field_map[];
|
||||||
const field_map_t* get_field_map_entry(uint32_t);
|
const field_map_t* get_field_map_entry(uint32_t);
|
||||||
|
const field_map_t* get_field_map_index(uint32_t);
|
||||||
|
size_t get_field_map_length(void);
|
||||||
bool validate_packet(uart_packet_t *);
|
bool validate_packet(uart_packet_t *);
|
||||||
|
void queue_cfg_packet(uart_packet_t *, device_t *);
|
||||||
|
|
||||||
/********* Handlers **********/
|
/********* Handlers **********/
|
||||||
void output_toggle_hotkey_handler(device_t *, hid_keyboard_report_t *);
|
void output_toggle_hotkey_handler(device_t *, hid_keyboard_report_t *);
|
||||||
|
@ -505,6 +531,7 @@ void fw_upgrade_hotkey_handler_B(device_t *, hid_keyboard_report_t *);
|
||||||
void mouse_zoom_hotkey_handler(device_t *, hid_keyboard_report_t *);
|
void mouse_zoom_hotkey_handler(device_t *, hid_keyboard_report_t *);
|
||||||
void all_keys_released_handler(device_t *);
|
void all_keys_released_handler(device_t *);
|
||||||
void switchlock_hotkey_handler(device_t *, hid_keyboard_report_t *);
|
void switchlock_hotkey_handler(device_t *, hid_keyboard_report_t *);
|
||||||
|
void toggle_relative_mode_handler(device_t *, hid_keyboard_report_t *);
|
||||||
void screenlock_hotkey_handler(device_t *, hid_keyboard_report_t *);
|
void screenlock_hotkey_handler(device_t *, hid_keyboard_report_t *);
|
||||||
void output_config_hotkey_handler(device_t *, hid_keyboard_report_t *);
|
void output_config_hotkey_handler(device_t *, hid_keyboard_report_t *);
|
||||||
void wipe_config_hotkey_handler(device_t *, hid_keyboard_report_t *);
|
void wipe_config_hotkey_handler(device_t *, hid_keyboard_report_t *);
|
||||||
|
@ -530,6 +557,8 @@ void handle_response_byte_msg(uart_packet_t *, device_t *);
|
||||||
void handle_heartbeat_msg(uart_packet_t *, device_t *);
|
void handle_heartbeat_msg(uart_packet_t *, device_t *);
|
||||||
void handle_proxy_msg(uart_packet_t *, device_t *);
|
void handle_proxy_msg(uart_packet_t *, device_t *);
|
||||||
void handle_api_msgs(uart_packet_t *, device_t *);
|
void handle_api_msgs(uart_packet_t *, device_t *);
|
||||||
|
void handle_api_read_all_msg(uart_packet_t *, device_t *);
|
||||||
|
void handle_toggle_relative_msg(uart_packet_t *, device_t *);
|
||||||
|
|
||||||
void switch_output(device_t *, uint8_t);
|
void switch_output(device_t *, uint8_t);
|
||||||
|
|
||||||
|
|
|
@ -151,4 +151,48 @@ HID_COLLECTION_END \
|
||||||
HID_OUTPUT ( HID_DATA | HID_ARRAY | HID_ABSOLUTE ) ,\
|
HID_OUTPUT ( HID_DATA | HID_ARRAY | HID_ABSOLUTE ) ,\
|
||||||
HID_COLLECTION_END \
|
HID_COLLECTION_END \
|
||||||
|
|
||||||
|
#define TUD_HID_REPORT_DESC_MOUSEHELP(...) \
|
||||||
|
HID_USAGE_PAGE ( HID_USAGE_PAGE_DESKTOP ) ,\
|
||||||
|
HID_USAGE ( HID_USAGE_DESKTOP_MOUSE ) ,\
|
||||||
|
HID_COLLECTION ( HID_COLLECTION_APPLICATION ) ,\
|
||||||
|
/* Report ID if any */\
|
||||||
|
__VA_ARGS__ \
|
||||||
|
HID_USAGE ( HID_USAGE_DESKTOP_POINTER ) ,\
|
||||||
|
HID_COLLECTION ( HID_COLLECTION_PHYSICAL ) ,\
|
||||||
|
HID_USAGE_PAGE ( HID_USAGE_PAGE_BUTTON ) ,\
|
||||||
|
HID_USAGE_MIN ( 1 ) ,\
|
||||||
|
HID_USAGE_MAX ( 5 ) ,\
|
||||||
|
HID_LOGICAL_MIN ( 0 ) ,\
|
||||||
|
HID_LOGICAL_MAX ( 1 ) ,\
|
||||||
|
/* Left, Right, Middle, Backward, Forward buttons */ \
|
||||||
|
HID_REPORT_COUNT( 5 ) ,\
|
||||||
|
HID_REPORT_SIZE ( 1 ) ,\
|
||||||
|
HID_INPUT ( HID_DATA | HID_VARIABLE | HID_ABSOLUTE ) ,\
|
||||||
|
/* 3 bit padding */ \
|
||||||
|
HID_REPORT_COUNT( 1 ) ,\
|
||||||
|
HID_REPORT_SIZE ( 3 ) ,\
|
||||||
|
HID_INPUT ( HID_CONSTANT ) ,\
|
||||||
|
HID_USAGE_PAGE ( HID_USAGE_PAGE_DESKTOP ) ,\
|
||||||
|
/* X, Y position [-127, 127] */ \
|
||||||
|
HID_USAGE ( HID_USAGE_DESKTOP_X ) ,\
|
||||||
|
HID_USAGE ( HID_USAGE_DESKTOP_Y ) ,\
|
||||||
|
HID_LOGICAL_MIN_N ( 0x8000, 2 ) ,\
|
||||||
|
HID_LOGICAL_MAX_N ( 0x7fff, 2 ) ,\
|
||||||
|
HID_REPORT_SIZE ( 16 ) ,\
|
||||||
|
HID_REPORT_COUNT( 2 ) ,\
|
||||||
|
HID_INPUT ( HID_DATA | HID_VARIABLE | HID_RELATIVE ) ,\
|
||||||
|
/* Vertical wheel scroll [-127, 127] */ \
|
||||||
|
HID_USAGE ( HID_USAGE_DESKTOP_WHEEL ) ,\
|
||||||
|
HID_LOGICAL_MIN ( 0x81 ) ,\
|
||||||
|
HID_LOGICAL_MAX ( 0x7f ) ,\
|
||||||
|
HID_REPORT_COUNT( 1 ) ,\
|
||||||
|
HID_REPORT_SIZE ( 8 ) ,\
|
||||||
|
HID_INPUT ( HID_DATA | HID_VARIABLE | HID_RELATIVE ) ,\
|
||||||
|
/* Mouse mode (0 = absolute, 1 = relative) */ \
|
||||||
|
HID_REPORT_COUNT( 1 ), \
|
||||||
|
HID_REPORT_SIZE ( 8 ), \
|
||||||
|
HID_INPUT ( HID_CONSTANT ), \
|
||||||
|
HID_COLLECTION_END , \
|
||||||
|
HID_COLLECTION_END \
|
||||||
|
|
||||||
#endif /* USB_DESCRIPTORS_H_ */
|
#endif /* USB_DESCRIPTORS_H_ */
|
||||||
|
|
|
@ -23,6 +23,10 @@
|
||||||
*
|
*
|
||||||
* defined as HID_KEY_<something>
|
* defined as HID_KEY_<something>
|
||||||
*
|
*
|
||||||
|
* In addition, keyboard.c defines right ctrl as a modifier key required to
|
||||||
|
* activate this. So, the current shortcut is RIGHT CTRL + whatever is defined
|
||||||
|
* here.
|
||||||
|
*
|
||||||
* If you do not want to use a key for switching outputs, you may be tempted
|
* If you do not want to use a key for switching outputs, you may be tempted
|
||||||
* to select HID_KEY_NONE here; don't do that! That code appears in many HID
|
* to select HID_KEY_NONE here; don't do that! That code appears in many HID
|
||||||
* messages and the result will be a non-functional keyboard. Instead, choose
|
* messages and the result will be a non-functional keyboard. Instead, choose
|
||||||
|
@ -32,7 +36,7 @@
|
||||||
*
|
*
|
||||||
* */
|
* */
|
||||||
|
|
||||||
#define HOTKEY_TOGGLE HID_KEY_F24
|
#define HOTKEY_TOGGLE HID_KEY_CAPS_LOCK
|
||||||
|
|
||||||
/**================================================== *
|
/**================================================== *
|
||||||
* ============== Mouse Speed Factor ============== *
|
* ============== Mouse Speed Factor ============== *
|
||||||
|
@ -53,13 +57,13 @@
|
||||||
*
|
*
|
||||||
* */
|
* */
|
||||||
|
|
||||||
/* Output A values */
|
/* Output A values, default is for the most common ~ 16:9 ratio screen */
|
||||||
#define MOUSE_SPEED_A_FACTOR_X 16
|
#define MOUSE_SPEED_A_FACTOR_X 16
|
||||||
#define MOUSE_SPEED_A_FACTOR_Y 16
|
#define MOUSE_SPEED_A_FACTOR_Y 28
|
||||||
|
|
||||||
/* Output B values */
|
/* Output B values, default is for the most common ~ 16:9 ratio screen */
|
||||||
#define MOUSE_SPEED_B_FACTOR_X 16
|
#define MOUSE_SPEED_B_FACTOR_X 16
|
||||||
#define MOUSE_SPEED_B_FACTOR_Y 16
|
#define MOUSE_SPEED_B_FACTOR_Y 28
|
||||||
|
|
||||||
#define JUMP_THRESHOLD 0
|
#define JUMP_THRESHOLD 0
|
||||||
|
|
||||||
|
|
|
@ -23,7 +23,7 @@
|
||||||
|
|
||||||
hotkey_combo_t hotkeys[] = {
|
hotkey_combo_t hotkeys[] = {
|
||||||
/* Main keyboard switching hotkey */
|
/* Main keyboard switching hotkey */
|
||||||
{.modifier = 0,
|
{.modifier = KEYBOARD_MODIFIER_LEFTCTRL,
|
||||||
.keys = {HOTKEY_TOGGLE},
|
.keys = {HOTKEY_TOGGLE},
|
||||||
.key_count = 1,
|
.key_count = 1,
|
||||||
.pass_to_os = false,
|
.pass_to_os = false,
|
||||||
|
@ -51,6 +51,13 @@ hotkey_combo_t hotkeys[] = {
|
||||||
.acknowledge = true,
|
.acknowledge = true,
|
||||||
.action_handler = &screenlock_hotkey_handler},
|
.action_handler = &screenlock_hotkey_handler},
|
||||||
|
|
||||||
|
/* Toggle gaming mode */
|
||||||
|
{.modifier = KEYBOARD_MODIFIER_LEFTSHIFT | KEYBOARD_MODIFIER_RIGHTSHIFT,
|
||||||
|
.keys = {HID_KEY_G},
|
||||||
|
.key_count = 1,
|
||||||
|
.acknowledge = true,
|
||||||
|
.action_handler = &toggle_relative_mode_handler},
|
||||||
|
|
||||||
/* Erase stored config */
|
/* Erase stored config */
|
||||||
{.modifier = KEYBOARD_MODIFIER_RIGHTSHIFT,
|
{.modifier = KEYBOARD_MODIFIER_RIGHTSHIFT,
|
||||||
.keys = {HID_KEY_F12, HID_KEY_D},
|
.keys = {HID_KEY_F12, HID_KEY_D},
|
||||||
|
@ -185,7 +192,7 @@ void send_key(hid_keyboard_report_t *report, device_t *state) {
|
||||||
/* Decide if consumer control reports go local or to the other board */
|
/* Decide if consumer control reports go local or to the other board */
|
||||||
void send_consumer_control(uint8_t *raw_report, device_t *state) {
|
void send_consumer_control(uint8_t *raw_report, device_t *state) {
|
||||||
if (CURRENT_BOARD_IS_ACTIVE_OUTPUT) {
|
if (CURRENT_BOARD_IS_ACTIVE_OUTPUT) {
|
||||||
tud_hid_n_report(0, REPORT_ID_CONSUMER, raw_report, CONSUMER_CONTROL_LENGTH);
|
queue_cc_packet(raw_report, state);
|
||||||
state->last_activity[BOARD_ROLE] = time_us_64();
|
state->last_activity[BOARD_ROLE] = time_us_64();
|
||||||
} else {
|
} else {
|
||||||
queue_packet((uint8_t *)raw_report, CONSUMER_CONTROL_MSG, CONSUMER_CONTROL_LENGTH);
|
queue_packet((uint8_t *)raw_report, CONSUMER_CONTROL_MSG, CONSUMER_CONTROL_LENGTH);
|
||||||
|
@ -195,7 +202,7 @@ void send_consumer_control(uint8_t *raw_report, device_t *state) {
|
||||||
/* Decide if consumer control reports go local or to the other board */
|
/* Decide if consumer control reports go local or to the other board */
|
||||||
void send_system_control(uint8_t *raw_report, device_t *state) {
|
void send_system_control(uint8_t *raw_report, device_t *state) {
|
||||||
if (CURRENT_BOARD_IS_ACTIVE_OUTPUT) {
|
if (CURRENT_BOARD_IS_ACTIVE_OUTPUT) {
|
||||||
tud_hid_n_report(0, REPORT_ID_SYSTEM, raw_report, SYSTEM_CONTROL_LENGTH);
|
queue_system_packet(raw_report, state);
|
||||||
state->last_activity[BOARD_ROLE] = time_us_64();
|
state->last_activity[BOARD_ROLE] = time_us_64();
|
||||||
} else {
|
} else {
|
||||||
queue_packet((uint8_t *)raw_report, SYSTEM_CONTROL_MSG, SYSTEM_CONTROL_LENGTH);
|
queue_packet((uint8_t *)raw_report, SYSTEM_CONTROL_MSG, SYSTEM_CONTROL_LENGTH);
|
||||||
|
|
|
@ -35,7 +35,7 @@ int main(void) {
|
||||||
[1] = {.exec = &kick_watchdog_task, .frequency = _HZ(30)}, // | Verify core1 is still running and if so, reset watchdog timer
|
[1] = {.exec = &kick_watchdog_task, .frequency = _HZ(30)}, // | Verify core1 is still running and if so, reset watchdog timer
|
||||||
[2] = {.exec = &process_kbd_queue_task, .frequency = _HZ(2000)}, // | Check if there were any keypresses and send them
|
[2] = {.exec = &process_kbd_queue_task, .frequency = _HZ(2000)}, // | Check if there were any keypresses and send them
|
||||||
[3] = {.exec = &process_mouse_queue_task, .frequency = _HZ(2000)}, // | Check if there were any mouse movements and send them
|
[3] = {.exec = &process_mouse_queue_task, .frequency = _HZ(2000)}, // | Check if there were any mouse movements and send them
|
||||||
[4] = {.exec = &process_cfg_queue_task, .frequency = _HZ(1000)}, // | Check if there are any packets to send over vendor link
|
[4] = {.exec = &process_hid_queue_task, .frequency = _HZ(1000)}, // | Check if there are any packets to send over vendor link
|
||||||
[5] = {.exec = &process_uart_tx_task, .frequency = _TOP()}, // | Check if there are any packets to send over UART
|
[5] = {.exec = &process_uart_tx_task, .frequency = _TOP()}, // | Check if there are any packets to send over UART
|
||||||
}; // `----- then go back and repeat forever
|
}; // `----- then go back and repeat forever
|
||||||
const int NUM_TASKS = ARRAY_SIZE(tasks_core0);
|
const int NUM_TASKS = ARRAY_SIZE(tasks_core0);
|
||||||
|
|
30
src/mouse.c
30
src/mouse.c
|
@ -64,6 +64,10 @@ void update_mouse_position(device_t *state, mouse_values_t *values) {
|
||||||
output_t *current = &state->config.output[state->active_output];
|
output_t *current = &state->config.output[state->active_output];
|
||||||
uint8_t reduce_speed = 0;
|
uint8_t reduce_speed = 0;
|
||||||
|
|
||||||
|
/* If relative mouse mode is active, just pass mouse movements and update nothing */
|
||||||
|
if (state->relative_mouse)
|
||||||
|
return;
|
||||||
|
|
||||||
/* Check if we are configured to move slowly */
|
/* Check if we are configured to move slowly */
|
||||||
if (state->mouse_zoom)
|
if (state->mouse_zoom)
|
||||||
reduce_speed = MOUSE_ZOOM_SCALING_FACTOR;
|
reduce_speed = MOUSE_ZOOM_SCALING_FACTOR;
|
||||||
|
@ -141,13 +145,13 @@ void switch_desktop(device_t *state, output_t *output, int new_index, int direct
|
||||||
/* Fix for MACOS: Send relative mouse movement here, one or two pixels in the
|
/* Fix for MACOS: Send relative mouse movement here, one or two pixels in the
|
||||||
direction of movement, BEFORE absolute report sets X to 0 */
|
direction of movement, BEFORE absolute report sets X to 0 */
|
||||||
mouse_report_t move_relative_one
|
mouse_report_t move_relative_one
|
||||||
= {.x = (direction == LEFT) ? SCREEN_MIDPOINT - 2 : SCREEN_MIDPOINT + 2, .mode = RELATIVE};
|
= {.x = (direction == LEFT) ? -5 : 5, .mode = RELATIVE};
|
||||||
|
|
||||||
switch (output->os) {
|
switch (output->os) {
|
||||||
case MACOS:
|
case MACOS:
|
||||||
/* Once doesn't seem reliable enough, do it twice */
|
/* Once doesn't seem reliable enough, do it a few times */
|
||||||
output_mouse_report(&move_relative_one, state);
|
for (int i = 0; i < 5; i++)
|
||||||
output_mouse_report(&move_relative_one, state);
|
output_mouse_report(&move_relative_one, state);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case WINDOWS:
|
case WINDOWS:
|
||||||
|
@ -184,8 +188,8 @@ void check_screen_switch(const mouse_values_t *values, device_t *state) {
|
||||||
|
|
||||||
int direction = jump_left ? LEFT : RIGHT;
|
int direction = jump_left ? LEFT : RIGHT;
|
||||||
|
|
||||||
/* No switching allowed if explicitly disabled or mouse button is held */
|
/* No switching allowed if explicitly disabled */
|
||||||
if (state->switch_lock || state->mouse_buttons)
|
if (state->switch_lock)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/* No jump condition met == nothing to do, return */
|
/* No jump condition met == nothing to do, return */
|
||||||
|
@ -194,9 +198,13 @@ void check_screen_switch(const mouse_values_t *values, device_t *state) {
|
||||||
|
|
||||||
/* We want to jump in the direction of the other computer */
|
/* We want to jump in the direction of the other computer */
|
||||||
if (output->pos != direction) {
|
if (output->pos != direction) {
|
||||||
if (output->screen_index == 1) /* We are at the border -> switch outputs */
|
if (output->screen_index == 1) { /* We are at the border -> switch outputs */
|
||||||
switch_screen(state, output, new_x, state->active_output, 1 - state->active_output, direction);
|
/* No switching allowed if mouse button is held. Should only apply to the border! */
|
||||||
|
if (state->mouse_buttons)
|
||||||
|
return;
|
||||||
|
|
||||||
|
switch_screen(state, output, new_x, state->active_output, 1 - state->active_output, direction);
|
||||||
|
}
|
||||||
/* If here, this output has multiple desktops and we are not on the main one */
|
/* If here, this output has multiple desktops and we are not on the main one */
|
||||||
else
|
else
|
||||||
switch_desktop(state, output, output->screen_index - 1, direction);
|
switch_desktop(state, output, output->screen_index - 1, direction);
|
||||||
|
@ -240,11 +248,9 @@ mouse_report_t create_mouse_report(device_t *state, mouse_values_t *values) {
|
||||||
|
|
||||||
/* Workaround for Windows multiple desktops */
|
/* Workaround for Windows multiple desktops */
|
||||||
if (state->relative_mouse) {
|
if (state->relative_mouse) {
|
||||||
mouse_report.x = SCREEN_MIDPOINT + values->move_x;
|
mouse_report.x = values->move_x;
|
||||||
mouse_report.y = SCREEN_MIDPOINT + values->move_y;
|
mouse_report.y = values->move_y;
|
||||||
mouse_report.mode = RELATIVE;
|
mouse_report.mode = RELATIVE;
|
||||||
mouse_report.buttons = values->buttons;
|
|
||||||
mouse_report.wheel = values->wheel;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return mouse_report;
|
return mouse_report;
|
||||||
|
|
|
@ -66,4 +66,39 @@ const field_map_t* get_field_map_entry(uint32_t index) {
|
||||||
}
|
}
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const field_map_t* get_field_map_index(uint32_t index) {
|
||||||
|
return &api_field_map[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t get_field_map_length(void) {
|
||||||
|
return ARRAY_SIZE(api_field_map);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _queue_packet(uint8_t *payload, device_t *state, uint8_t type, uint8_t len, uint8_t id, uint8_t inst) {
|
||||||
|
hid_generic_pkt_t generic_packet = {
|
||||||
|
.instance = inst,
|
||||||
|
.report_id = id,
|
||||||
|
.type = type,
|
||||||
|
.len = len,
|
||||||
|
};
|
||||||
|
|
||||||
|
memcpy(generic_packet.data, payload, len);
|
||||||
|
queue_try_add(&state->hid_queue_out, &generic_packet);
|
||||||
|
}
|
||||||
|
|
||||||
|
void queue_cfg_packet(uart_packet_t *packet, device_t *state) {
|
||||||
|
uint8_t raw_packet[RAW_PACKET_LENGTH];
|
||||||
|
write_raw_packet(raw_packet, packet);
|
||||||
|
_queue_packet(raw_packet, state, 0, RAW_PACKET_LENGTH, REPORT_ID_VENDOR, ITF_NUM_HID_VENDOR);
|
||||||
|
}
|
||||||
|
|
||||||
|
void queue_cc_packet(uint8_t *payload, device_t *state) {
|
||||||
|
_queue_packet(payload, state, 1, CONSUMER_CONTROL_LENGTH, REPORT_ID_CONSUMER, ITF_NUM_HID);
|
||||||
|
}
|
||||||
|
|
||||||
|
void queue_system_packet(uint8_t *payload, device_t *state) {
|
||||||
|
_queue_packet(payload, state, 2, SYSTEM_CONTROL_LENGTH, REPORT_ID_SYSTEM, ITF_NUM_HID);
|
||||||
|
}
|
||||||
|
|
|
@ -237,8 +237,8 @@ void initial_setup(device_t *state) {
|
||||||
queue_init(&state->kbd_queue, sizeof(hid_keyboard_report_t), KBD_QUEUE_LENGTH);
|
queue_init(&state->kbd_queue, sizeof(hid_keyboard_report_t), KBD_QUEUE_LENGTH);
|
||||||
queue_init(&state->mouse_queue, sizeof(mouse_report_t), MOUSE_QUEUE_LENGTH);
|
queue_init(&state->mouse_queue, sizeof(mouse_report_t), MOUSE_QUEUE_LENGTH);
|
||||||
|
|
||||||
/* Initialize vendor config protocol queue */
|
/* Initialize generic HID packet queue */
|
||||||
queue_init(&state->cfg_queue_out, sizeof(uart_packet_t), CFG_QUEUE_LENGTH);
|
queue_init(&state->hid_queue_out, sizeof(hid_generic_pkt_t), HID_QUEUE_LENGTH);
|
||||||
|
|
||||||
/* Initialize UART queue */
|
/* Initialize UART queue */
|
||||||
queue_init(&state->uart_tx_queue, sizeof(uart_packet_t), UART_QUEUE_LENGTH);
|
queue_init(&state->uart_tx_queue, sizeof(uart_packet_t), UART_QUEUE_LENGTH);
|
||||||
|
@ -267,4 +267,4 @@ void initial_setup(device_t *state) {
|
||||||
watchdog_enable(WATCHDOG_TIMEOUT, WATCHDOG_PAUSE_ON_DEBUG);
|
watchdog_enable(WATCHDOG_TIMEOUT, WATCHDOG_PAUSE_ON_DEBUG);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ========== End of Initial Board Setup ========== */
|
/* ========== End of Initial Board Setup ========== */
|
||||||
|
|
20
src/tasks.c
20
src/tasks.c
|
@ -148,25 +148,23 @@ void heartbeat_output_task(device_t *state) {
|
||||||
queue_try_add(&global_state.uart_tx_queue, &packet);
|
queue_try_add(&global_state.uart_tx_queue, &packet);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Process outgoing config report messages. */
|
|
||||||
void process_cfg_queue_task(device_t *state) {
|
|
||||||
uint8_t raw_packet[RAW_PACKET_LENGTH] = {[0] = START1, [1] = START2, [11] = 0};
|
|
||||||
uart_packet_t packet;
|
|
||||||
|
|
||||||
if (!queue_try_peek(&state->cfg_queue_out, &packet))
|
/* Process other outgoing hid report messages. */
|
||||||
|
void process_hid_queue_task(device_t *state) {
|
||||||
|
hid_generic_pkt_t packet;
|
||||||
|
|
||||||
|
if (!queue_try_peek(&state->hid_queue_out, &packet))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (!tud_hid_n_ready(ITF_NUM_HID_VENDOR))
|
if (!tud_hid_n_ready(packet.instance))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
write_raw_packet(raw_packet, &packet);
|
|
||||||
|
|
||||||
/* ... try sending it to the host, if it's successful */
|
/* ... try sending it to the host, if it's successful */
|
||||||
bool succeeded = tud_hid_n_report(ITF_NUM_HID_VENDOR, REPORT_ID_VENDOR, raw_packet, RAW_PACKET_LENGTH);
|
bool succeeded = tud_hid_n_report(packet.instance, packet.report_id, packet.data, packet.len);
|
||||||
|
|
||||||
/* ... then we can remove it from the queue. Race conditions shouldn't happen [tm] */
|
/* ... then we can remove it from the queue. Race conditions shouldn't happen [tm] */
|
||||||
if (succeeded)
|
if (succeeded)
|
||||||
queue_try_remove(&state->cfg_queue_out, &packet);
|
queue_try_remove(&state->hid_queue_out, &packet);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Task that handles copying firmware from the other device to ours */
|
/* Task that handles copying firmware from the other device to ours */
|
||||||
|
@ -221,4 +219,4 @@ void packet_receiver_task(device_t *state) {
|
||||||
state->dma_ptr = NEXT_RING_IDX(state->dma_ptr);
|
state->dma_ptr = NEXT_RING_IDX(state->dma_ptr);
|
||||||
delta--;
|
delta--;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -76,6 +76,7 @@ const uart_handler_t uart_handler[] = {
|
||||||
{.type = SWITCH_LOCK_MSG, .handler = handle_switch_lock_msg},
|
{.type = SWITCH_LOCK_MSG, .handler = handle_switch_lock_msg},
|
||||||
{.type = SYNC_BORDERS_MSG, .handler = handle_sync_borders_msg},
|
{.type = SYNC_BORDERS_MSG, .handler = handle_sync_borders_msg},
|
||||||
{.type = FLASH_LED_MSG, .handler = handle_flash_led_msg},
|
{.type = FLASH_LED_MSG, .handler = handle_flash_led_msg},
|
||||||
|
{.type = RELATIVE_MODE_MSG, .handler = handle_toggle_relative_msg},
|
||||||
{.type = CONSUMER_CONTROL_MSG, .handler = handle_consumer_control_msg},
|
{.type = CONSUMER_CONTROL_MSG, .handler = handle_consumer_control_msg},
|
||||||
|
|
||||||
/* Config */
|
/* Config */
|
||||||
|
@ -83,6 +84,7 @@ const uart_handler_t uart_handler[] = {
|
||||||
{.type = SAVE_CONFIG_MSG, .handler = handle_save_config_msg},
|
{.type = SAVE_CONFIG_MSG, .handler = handle_save_config_msg},
|
||||||
{.type = REBOOT_MSG, .handler = handle_reboot_msg},
|
{.type = REBOOT_MSG, .handler = handle_reboot_msg},
|
||||||
{.type = GET_VAL_MSG, .handler = handle_api_msgs},
|
{.type = GET_VAL_MSG, .handler = handle_api_msgs},
|
||||||
|
{.type = GET_ALL_VALS_MSG, .handler = handle_api_read_all_msg},
|
||||||
{.type = SET_VAL_MSG, .handler = handle_api_msgs},
|
{.type = SET_VAL_MSG, .handler = handle_api_msgs},
|
||||||
|
|
||||||
/* Firmware */
|
/* Firmware */
|
||||||
|
|
|
@ -58,7 +58,7 @@ uint8_t const desc_hid_report[] = {TUD_HID_REPORT_DESC_KEYBOARD(HID_REPORT_ID(RE
|
||||||
TUD_HID_REPORT_DESC_SYSTEM_CONTROL(HID_REPORT_ID(REPORT_ID_SYSTEM))
|
TUD_HID_REPORT_DESC_SYSTEM_CONTROL(HID_REPORT_ID(REPORT_ID_SYSTEM))
|
||||||
};
|
};
|
||||||
|
|
||||||
uint8_t const desc_hid_report_relmouse[] = {TUD_HID_REPORT_DESC_MOUSE(HID_REPORT_ID(REPORT_ID_RELMOUSE))};
|
uint8_t const desc_hid_report_relmouse[] = {TUD_HID_REPORT_DESC_MOUSEHELP(HID_REPORT_ID(REPORT_ID_RELMOUSE))};
|
||||||
|
|
||||||
uint8_t const desc_hid_report_vendor[] = {TUD_HID_REPORT_DESC_VENDOR_CTRL(HID_REPORT_ID(REPORT_ID_VENDOR))};
|
uint8_t const desc_hid_report_vendor[] = {TUD_HID_REPORT_DESC_VENDOR_CTRL(HID_REPORT_ID(REPORT_ID_VENDOR))};
|
||||||
|
|
||||||
|
@ -82,15 +82,16 @@ uint8_t const *tud_hid_descriptor_report_cb(uint8_t instance) {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool tud_mouse_report(uint8_t mode, uint8_t buttons, int16_t x, int16_t y, int8_t wheel) {
|
bool tud_mouse_report(uint8_t mode, uint8_t buttons, int16_t x, int16_t y, int8_t wheel) {
|
||||||
|
mouse_report_t report = {.buttons = buttons, .wheel = wheel, .x = x, .y = y, .mode = mode};
|
||||||
|
uint8_t instance = ITF_NUM_HID;
|
||||||
|
uint8_t report_id = REPORT_ID_MOUSE;
|
||||||
|
|
||||||
if (mode == ABSOLUTE) {
|
if (mode == RELATIVE) {
|
||||||
mouse_report_t report = {.buttons = buttons, .x = x, .y = y, .wheel = wheel};
|
instance = ITF_NUM_HID_REL_M;
|
||||||
return tud_hid_n_report(ITF_NUM_HID, REPORT_ID_MOUSE, &report, sizeof(report));
|
report_id = REPORT_ID_RELMOUSE;
|
||||||
} else {
|
|
||||||
hid_mouse_report_t report
|
|
||||||
= {.buttons = buttons, .x = x - SCREEN_MIDPOINT, .y = y - SCREEN_MIDPOINT, .wheel = wheel, .pan = 0};
|
|
||||||
return tud_hid_n_report(ITF_NUM_HID_REL_M, REPORT_ID_RELMOUSE, &report, sizeof(report));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return tud_hid_n_report(instance, report_id, &report, sizeof(report));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -195,6 +195,7 @@ bool validate_packet(uart_packet_t *packet) {
|
||||||
const enum packet_type_e ALLOWED_PACKETS[] = {
|
const enum packet_type_e ALLOWED_PACKETS[] = {
|
||||||
FLASH_LED_MSG,
|
FLASH_LED_MSG,
|
||||||
GET_VAL_MSG,
|
GET_VAL_MSG,
|
||||||
|
GET_ALL_VALS_MSG,
|
||||||
SET_VAL_MSG,
|
SET_VAL_MSG,
|
||||||
WIPE_CONFIG_MSG,
|
WIPE_CONFIG_MSG,
|
||||||
SAVE_CONFIG_MSG,
|
SAVE_CONFIG_MSG,
|
||||||
|
|
|
@ -1,2 +1,2 @@
|
||||||
render:
|
render:
|
||||||
python3 render.py
|
python3 -B render.py
|
||||||
|
|
|
@ -24,7 +24,7 @@
|
||||||
:root {
|
:root {
|
||||||
--highlight-color: #384955;
|
--highlight-color: #384955;
|
||||||
--font-color: #384955;
|
--font-color: #384955;
|
||||||
--highlight-color2: #5e9f41;
|
--highlight-color2: #5e9f41;
|
||||||
}
|
}
|
||||||
|
|
||||||
html {
|
html {
|
||||||
|
@ -492,7 +492,7 @@ input[type='number'].input-inline {
|
||||||
@media (min-width: 40rem) {
|
@media (min-width: 40rem) {
|
||||||
.row {
|
.row {
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
|
|
||||||
width: calc(100% + 2.0rem);
|
width: calc(100% + 2.0rem);
|
||||||
}
|
}
|
||||||
.row .column {
|
.row .column {
|
||||||
|
@ -681,14 +681,14 @@ img {
|
||||||
|
|
||||||
<main class="wrapper">
|
<main class="wrapper">
|
||||||
|
|
||||||
<section class="container">
|
<section class="container">
|
||||||
|
|
||||||
<div class="row" id="warning" style="display: none;">
|
<div class="row" id="warning" style="display: none;">
|
||||||
<blockquote>
|
<blockquote>
|
||||||
<h3> Oh, no! </h3>
|
<h3> Oh, no! </h3>
|
||||||
Unfortunately, your browser does not support WebHID or the Permissions Policy is blocking its usage. Please try Chromium <br />
|
Unfortunately, your browser does not support WebHID or the Permissions Policy is blocking its usage. Please try Chromium <br />
|
||||||
(or Chrome if you have to). Apologies for the inconvenience, hopefully a cross-browser solution happens soon.
|
(or Chrome if you have to). Apologies for the inconvenience, hopefully a cross-browser solution happens soon.
|
||||||
</blockquote>
|
</blockquote>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
|
@ -716,7 +716,7 @@ img {
|
||||||
<path d="m 104.01516,99.341366 a 1.8639801,1.8639801 0 0 0 -1.86329,1.863284 1.8639801,1.8639801 0 0 0 1.86329,1.86328 h 27.4375 a 1.8639801,1.8639801 0 0 0 1.86718,-1.86328 1.8639801,1.8639801 0 0 0 -1.86718,-1.863284 z" />
|
<path d="m 104.01516,99.341366 a 1.8639801,1.8639801 0 0 0 -1.86329,1.863284 1.8639801,1.8639801 0 0 0 1.86329,1.86328 h 27.4375 a 1.8639801,1.8639801 0 0 0 1.86718,-1.86328 1.8639801,1.8639801 0 0 0 -1.86718,-1.863284 z" />
|
||||||
</g>
|
</g>
|
||||||
</svg>
|
</svg>
|
||||||
|
|
||||||
<div id="menu-buttons">
|
<div id="menu-buttons">
|
||||||
<button data-handler="connectHandler" class="button button-clear button-shifted">Connect</button><br />
|
<button data-handler="connectHandler" class="button button-clear button-shifted">Connect</button><br />
|
||||||
<button data-handler="readHandler" class="button button-clear button-shifted online">Read</button><br />
|
<button data-handler="readHandler" class="button button-clear button-shifted online">Read</button><br />
|
||||||
|
@ -727,8 +727,8 @@ img {
|
||||||
<button data-handler="blinkHandler" class="button button-clear button-shifted online">Blink</button><br />
|
<button data-handler="blinkHandler" class="button button-clear button-shifted online">Blink</button><br />
|
||||||
<button data-handler="blinkBothHandler" class="button button-clear button-shifted online">Blink both</button><br />
|
<button data-handler="blinkBothHandler" class="button button-clear button-shifted online">Blink both</button><br />
|
||||||
<button data-handler="enterBootloaderHandler" class="button button-clear button-shifted online">Bootloader</button><br />
|
<button data-handler="enterBootloaderHandler" class="button button-clear button-shifted online">Bootloader</button><br />
|
||||||
<button data-handler="wipeConfigHandler" class="button button-clear button-shifted online">Wipe Config</button><br />
|
<button data-handler="wipeConfigHandler" class="button button-clear button-shifted online">Wipe Config</button><br />
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
@ -757,20 +757,20 @@ img {
|
||||||
|
|
||||||
<label class=""> Screen Count</label>
|
<label class=""> Screen Count</label>
|
||||||
|
|
||||||
<select class="api" data-type="uint32" data-key="11" required>
|
<select class="api" data-type="uint32" data-key="11" required>
|
||||||
<option disabled selected value></option>
|
<option disabled selected value></option>
|
||||||
|
|
||||||
|
|
||||||
<option value="1">1</option>
|
<option value="1">1</option>
|
||||||
|
|
||||||
<option value="2">2</option>
|
<option value="2">2</option>
|
||||||
|
|
||||||
<option value="3">3</option>
|
<option value="3">3</option>
|
||||||
|
|
||||||
</select><br />
|
</select><br />
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -789,22 +789,22 @@ img {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<input class="input-inline" type="number" name="aInput12" data-type="int32" data-key="12"
|
<input class="input-inline" type="number" name="aInput12" data-type="int32" data-key="12"
|
||||||
onchange="valueChangedHandler(this)"
|
onchange="valueChangedHandler(this)"
|
||||||
|
|
||||||
readonly oninput="this.form.aRange12.value=this.value" />
|
readonly oninput="this.form.aRange12.value=this.value" />
|
||||||
|
|
||||||
|
|
||||||
|
<input class="range api" type="range" name="aRange12" data-type="int32" data-key="12"
|
||||||
<input class="range api" type="range" name="aRange12" data-type="int32" data-key="12"
|
|
||||||
onchange="valueChangedHandler(this)"
|
onchange="valueChangedHandler(this)"
|
||||||
|
|
||||||
min="" max="" oninput="this.form.aInput12.value=this.value" />
|
min="" max="" oninput="this.form.aInput12.value=this.value" />
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -823,22 +823,22 @@ img {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<input class="input-inline" type="number" name="aInput13" data-type="int32" data-key="13"
|
<input class="input-inline" type="number" name="aInput13" data-type="int32" data-key="13"
|
||||||
onchange="valueChangedHandler(this)"
|
onchange="valueChangedHandler(this)"
|
||||||
|
|
||||||
readonly oninput="this.form.aRange13.value=this.value" />
|
readonly oninput="this.form.aRange13.value=this.value" />
|
||||||
|
|
||||||
|
|
||||||
|
<input class="range api" type="range" name="aRange13" data-type="int32" data-key="13"
|
||||||
<input class="range api" type="range" name="aRange13" data-type="int32" data-key="13"
|
|
||||||
onchange="valueChangedHandler(this)"
|
onchange="valueChangedHandler(this)"
|
||||||
|
|
||||||
min="" max="" oninput="this.form.aInput13.value=this.value" />
|
min="" max="" oninput="this.form.aInput13.value=this.value" />
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -854,12 +854,12 @@ img {
|
||||||
<label class=""> Border Top</label>
|
<label class=""> Border Top</label>
|
||||||
|
|
||||||
|
|
||||||
<input class="api" type="text" name="name14" data-type="int32" data-key="14"
|
<input class="api" type="text" name="name14" data-type="int32" data-key="14"
|
||||||
onchange="valueChangedHandler(this)"
|
onchange="valueChangedHandler(this)"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -875,12 +875,12 @@ img {
|
||||||
<label class=""> Border Bottom</label>
|
<label class=""> Border Bottom</label>
|
||||||
|
|
||||||
|
|
||||||
<input class="api" type="text" name="name15" data-type="int32" data-key="15"
|
<input class="api" type="text" name="name15" data-type="int32" data-key="15"
|
||||||
onchange="valueChangedHandler(this)"
|
onchange="valueChangedHandler(this)"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -895,24 +895,24 @@ img {
|
||||||
|
|
||||||
<label class=""> Operating System</label>
|
<label class=""> Operating System</label>
|
||||||
|
|
||||||
<select class="api" data-type="uint8" data-key="16" required>
|
<select class="api" data-type="uint8" data-key="16" required>
|
||||||
<option disabled selected value></option>
|
<option disabled selected value></option>
|
||||||
|
|
||||||
|
|
||||||
<option value="1">Linux</option>
|
<option value="1">Linux</option>
|
||||||
|
|
||||||
<option value="2">MacOS</option>
|
<option value="2">MacOS</option>
|
||||||
|
|
||||||
<option value="3">Windows</option>
|
<option value="3">Windows</option>
|
||||||
|
|
||||||
<option value="4">Android</option>
|
<option value="4">Android</option>
|
||||||
|
|
||||||
<option value="255">Other</option>
|
<option value="255">Other</option>
|
||||||
|
|
||||||
</select><br />
|
</select><br />
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -927,18 +927,18 @@ img {
|
||||||
|
|
||||||
<label class=""> Screen Position</label>
|
<label class=""> Screen Position</label>
|
||||||
|
|
||||||
<select class="api" data-type="uint8" data-key="17" required>
|
<select class="api" data-type="uint8" data-key="17" required>
|
||||||
<option disabled selected value></option>
|
<option disabled selected value></option>
|
||||||
|
|
||||||
|
|
||||||
<option value="1">Left</option>
|
<option value="1">Left</option>
|
||||||
|
|
||||||
<option value="2">Right</option>
|
<option value="2">Right</option>
|
||||||
|
|
||||||
</select><br />
|
</select><br />
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -953,20 +953,20 @@ img {
|
||||||
|
|
||||||
<label class=""> Cursor Park Position</label>
|
<label class=""> Cursor Park Position</label>
|
||||||
|
|
||||||
<select class="api" data-type="uint8" data-key="18" required>
|
<select class="api" data-type="uint8" data-key="18" required>
|
||||||
<option disabled selected value></option>
|
<option disabled selected value></option>
|
||||||
|
|
||||||
|
|
||||||
<option value="0">Top</option>
|
<option value="0">Top</option>
|
||||||
|
|
||||||
<option value="1">Bottom</option>
|
<option value="1">Bottom</option>
|
||||||
|
|
||||||
<option value="3">Previous</option>
|
<option value="3">Previous</option>
|
||||||
|
|
||||||
</select><br />
|
</select><br />
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -983,7 +983,7 @@ img {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -998,20 +998,20 @@ img {
|
||||||
|
|
||||||
<label class=""> Mode</label>
|
<label class=""> Mode</label>
|
||||||
|
|
||||||
<select class="api" data-type="uint8" data-key="19" required>
|
<select class="api" data-type="uint8" data-key="19" required>
|
||||||
<option disabled selected value></option>
|
<option disabled selected value></option>
|
||||||
|
|
||||||
|
|
||||||
<option value="0">Disabled</option>
|
<option value="0">Disabled</option>
|
||||||
|
|
||||||
<option value="1">Pong</option>
|
<option value="1">Pong</option>
|
||||||
|
|
||||||
<option value="2">Jitter</option>
|
<option value="2">Jitter</option>
|
||||||
|
|
||||||
</select><br />
|
</select><br />
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -1026,16 +1026,16 @@ img {
|
||||||
<div class="clearfix">
|
<div class="clearfix">
|
||||||
|
|
||||||
<label class="label-inline"> Only If Inactive</label>
|
<label class="label-inline"> Only If Inactive</label>
|
||||||
|
|
||||||
|
|
||||||
|
<input class="api" type="checkbox" name="name20" data-type="uint8" data-key="20"
|
||||||
<input class="api" type="checkbox" name="name20" data-type="uint8" data-key="20"
|
|
||||||
onchange="valueChangedHandler(this)"
|
onchange="valueChangedHandler(this)"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -1051,12 +1051,12 @@ img {
|
||||||
<label class=""> Idle Time (μs)</label>
|
<label class=""> Idle Time (μs)</label>
|
||||||
|
|
||||||
|
|
||||||
<input class="api" type="text" name="name21" data-type="uint64" data-key="21"
|
<input class="api" type="text" name="name21" data-type="uint64" data-key="21"
|
||||||
onchange="valueChangedHandler(this)"
|
onchange="valueChangedHandler(this)"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -1072,12 +1072,12 @@ img {
|
||||||
<label class=""> Max Time (μs)</label>
|
<label class=""> Max Time (μs)</label>
|
||||||
|
|
||||||
|
|
||||||
<input class="api" type="text" name="name22" data-type="uint64" data-key="22"
|
<input class="api" type="text" name="name22" data-type="uint64" data-key="22"
|
||||||
onchange="valueChangedHandler(this)"
|
onchange="valueChangedHandler(this)"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
@ -1088,7 +1088,7 @@ img {
|
||||||
<line x1="50" y1="90" x2="50" y2="75" stroke="black" stroke-width="2" />
|
<line x1="50" y1="90" x2="50" y2="75" stroke="black" stroke-width="2" />
|
||||||
<rect x="30" y="90" width="40" height="3" stroke="black" stroke-width="2" fill="#d7e5f0" rx="5" ry="5" />
|
<rect x="30" y="90" width="40" height="3" stroke="black" stroke-width="2" fill="#d7e5f0" rx="5" ry="5" />
|
||||||
</svg>
|
</svg>
|
||||||
|
|
||||||
<h3>Output B</h3>
|
<h3>Output B</h3>
|
||||||
|
|
||||||
|
|
||||||
|
@ -1105,20 +1105,20 @@ img {
|
||||||
|
|
||||||
<label class=""> Screen Count</label>
|
<label class=""> Screen Count</label>
|
||||||
|
|
||||||
<select class="api" data-type="uint32" data-key="41" required>
|
<select class="api" data-type="uint32" data-key="41" required>
|
||||||
<option disabled selected value></option>
|
<option disabled selected value></option>
|
||||||
|
|
||||||
|
|
||||||
<option value="1">1</option>
|
<option value="1">1</option>
|
||||||
|
|
||||||
<option value="2">2</option>
|
<option value="2">2</option>
|
||||||
|
|
||||||
<option value="3">3</option>
|
<option value="3">3</option>
|
||||||
|
|
||||||
</select><br />
|
</select><br />
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -1137,22 +1137,22 @@ img {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<input class="input-inline" type="number" name="aInput42" data-type="int32" data-key="42"
|
<input class="input-inline" type="number" name="aInput42" data-type="int32" data-key="42"
|
||||||
onchange="valueChangedHandler(this)"
|
onchange="valueChangedHandler(this)"
|
||||||
|
|
||||||
readonly oninput="this.form.aRange42.value=this.value" />
|
readonly oninput="this.form.aRange42.value=this.value" />
|
||||||
|
|
||||||
|
|
||||||
|
<input class="range api" type="range" name="aRange42" data-type="int32" data-key="42"
|
||||||
<input class="range api" type="range" name="aRange42" data-type="int32" data-key="42"
|
|
||||||
onchange="valueChangedHandler(this)"
|
onchange="valueChangedHandler(this)"
|
||||||
|
|
||||||
min="" max="" oninput="this.form.aInput42.value=this.value" />
|
min="" max="" oninput="this.form.aInput42.value=this.value" />
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -1171,22 +1171,22 @@ img {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<input class="input-inline" type="number" name="aInput43" data-type="int32" data-key="43"
|
<input class="input-inline" type="number" name="aInput43" data-type="int32" data-key="43"
|
||||||
onchange="valueChangedHandler(this)"
|
onchange="valueChangedHandler(this)"
|
||||||
|
|
||||||
readonly oninput="this.form.aRange43.value=this.value" />
|
readonly oninput="this.form.aRange43.value=this.value" />
|
||||||
|
|
||||||
|
|
||||||
|
<input class="range api" type="range" name="aRange43" data-type="int32" data-key="43"
|
||||||
<input class="range api" type="range" name="aRange43" data-type="int32" data-key="43"
|
|
||||||
onchange="valueChangedHandler(this)"
|
onchange="valueChangedHandler(this)"
|
||||||
|
|
||||||
min="" max="" oninput="this.form.aInput43.value=this.value" />
|
min="" max="" oninput="this.form.aInput43.value=this.value" />
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -1202,12 +1202,12 @@ img {
|
||||||
<label class=""> Border Top</label>
|
<label class=""> Border Top</label>
|
||||||
|
|
||||||
|
|
||||||
<input class="api" type="text" name="name44" data-type="int32" data-key="44"
|
<input class="api" type="text" name="name44" data-type="int32" data-key="44"
|
||||||
onchange="valueChangedHandler(this)"
|
onchange="valueChangedHandler(this)"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -1223,12 +1223,12 @@ img {
|
||||||
<label class=""> Border Bottom</label>
|
<label class=""> Border Bottom</label>
|
||||||
|
|
||||||
|
|
||||||
<input class="api" type="text" name="name45" data-type="int32" data-key="45"
|
<input class="api" type="text" name="name45" data-type="int32" data-key="45"
|
||||||
onchange="valueChangedHandler(this)"
|
onchange="valueChangedHandler(this)"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -1243,24 +1243,24 @@ img {
|
||||||
|
|
||||||
<label class=""> Operating System</label>
|
<label class=""> Operating System</label>
|
||||||
|
|
||||||
<select class="api" data-type="uint8" data-key="46" required>
|
<select class="api" data-type="uint8" data-key="46" required>
|
||||||
<option disabled selected value></option>
|
<option disabled selected value></option>
|
||||||
|
|
||||||
|
|
||||||
<option value="1">Linux</option>
|
<option value="1">Linux</option>
|
||||||
|
|
||||||
<option value="2">MacOS</option>
|
<option value="2">MacOS</option>
|
||||||
|
|
||||||
<option value="3">Windows</option>
|
<option value="3">Windows</option>
|
||||||
|
|
||||||
<option value="4">Android</option>
|
<option value="4">Android</option>
|
||||||
|
|
||||||
<option value="255">Other</option>
|
<option value="255">Other</option>
|
||||||
|
|
||||||
</select><br />
|
</select><br />
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -1275,18 +1275,18 @@ img {
|
||||||
|
|
||||||
<label class=""> Screen Position</label>
|
<label class=""> Screen Position</label>
|
||||||
|
|
||||||
<select class="api" data-type="uint8" data-key="47" required>
|
<select class="api" data-type="uint8" data-key="47" required>
|
||||||
<option disabled selected value></option>
|
<option disabled selected value></option>
|
||||||
|
|
||||||
|
|
||||||
<option value="1">Left</option>
|
<option value="1">Left</option>
|
||||||
|
|
||||||
<option value="2">Right</option>
|
<option value="2">Right</option>
|
||||||
|
|
||||||
</select><br />
|
</select><br />
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -1301,20 +1301,20 @@ img {
|
||||||
|
|
||||||
<label class=""> Cursor Park Position</label>
|
<label class=""> Cursor Park Position</label>
|
||||||
|
|
||||||
<select class="api" data-type="uint8" data-key="48" required>
|
<select class="api" data-type="uint8" data-key="48" required>
|
||||||
<option disabled selected value></option>
|
<option disabled selected value></option>
|
||||||
|
|
||||||
|
|
||||||
<option value="0">Top</option>
|
<option value="0">Top</option>
|
||||||
|
|
||||||
<option value="1">Bottom</option>
|
<option value="1">Bottom</option>
|
||||||
|
|
||||||
<option value="3">Previous</option>
|
<option value="3">Previous</option>
|
||||||
|
|
||||||
</select><br />
|
</select><br />
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -1331,7 +1331,7 @@ img {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -1346,20 +1346,20 @@ img {
|
||||||
|
|
||||||
<label class=""> Mode</label>
|
<label class=""> Mode</label>
|
||||||
|
|
||||||
<select class="api" data-type="uint8" data-key="49" required>
|
<select class="api" data-type="uint8" data-key="49" required>
|
||||||
<option disabled selected value></option>
|
<option disabled selected value></option>
|
||||||
|
|
||||||
|
|
||||||
<option value="0">Disabled</option>
|
<option value="0">Disabled</option>
|
||||||
|
|
||||||
<option value="1">Pong</option>
|
<option value="1">Pong</option>
|
||||||
|
|
||||||
<option value="2">Jitter</option>
|
<option value="2">Jitter</option>
|
||||||
|
|
||||||
</select><br />
|
</select><br />
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -1374,16 +1374,16 @@ img {
|
||||||
<div class="clearfix">
|
<div class="clearfix">
|
||||||
|
|
||||||
<label class="label-inline"> Only If Inactive</label>
|
<label class="label-inline"> Only If Inactive</label>
|
||||||
|
|
||||||
|
|
||||||
|
<input class="api" type="checkbox" name="name50" data-type="uint8" data-key="50"
|
||||||
<input class="api" type="checkbox" name="name50" data-type="uint8" data-key="50"
|
|
||||||
onchange="valueChangedHandler(this)"
|
onchange="valueChangedHandler(this)"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -1399,12 +1399,12 @@ img {
|
||||||
<label class=""> Idle Time (μs)</label>
|
<label class=""> Idle Time (μs)</label>
|
||||||
|
|
||||||
|
|
||||||
<input class="api" type="text" name="name51" data-type="uint64" data-key="51"
|
<input class="api" type="text" name="name51" data-type="uint64" data-key="51"
|
||||||
onchange="valueChangedHandler(this)"
|
onchange="valueChangedHandler(this)"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -1420,14 +1420,14 @@ img {
|
||||||
<label class=""> Max Time (μs)</label>
|
<label class=""> Max Time (μs)</label>
|
||||||
|
|
||||||
|
|
||||||
<input class="api" type="text" name="name52" data-type="uint64" data-key="52"
|
<input class="api" type="text" name="name52" data-type="uint64" data-key="52"
|
||||||
onchange="valueChangedHandler(this)"
|
onchange="valueChangedHandler(this)"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
@ -1459,7 +1459,7 @@ img {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -1474,16 +1474,16 @@ img {
|
||||||
<div class="clearfix">
|
<div class="clearfix">
|
||||||
|
|
||||||
<label class="label-inline"> Force Mouse Boot Mode</label>
|
<label class="label-inline"> Force Mouse Boot Mode</label>
|
||||||
|
|
||||||
|
|
||||||
|
<input class="api" type="checkbox" name="name71" data-type="uint8" data-key="71"
|
||||||
<input class="api" type="checkbox" name="name71" data-type="uint8" data-key="71"
|
|
||||||
onchange="valueChangedHandler(this)"
|
onchange="valueChangedHandler(this)"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -1498,16 +1498,16 @@ img {
|
||||||
<div class="clearfix">
|
<div class="clearfix">
|
||||||
|
|
||||||
<label class="label-inline"> Enable Acceleration</label>
|
<label class="label-inline"> Enable Acceleration</label>
|
||||||
|
|
||||||
|
|
||||||
|
<input class="api" type="checkbox" name="name75" data-type="uint8" data-key="75"
|
||||||
<input class="api" type="checkbox" name="name75" data-type="uint8" data-key="75"
|
|
||||||
onchange="valueChangedHandler(this)"
|
onchange="valueChangedHandler(this)"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -1526,22 +1526,22 @@ img {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<input class="input-inline" type="number" name="aInput77" data-type="uint16" data-key="77"
|
<input class="input-inline" type="number" name="aInput77" data-type="uint16" data-key="77"
|
||||||
onchange="valueChangedHandler(this)"
|
onchange="valueChangedHandler(this)"
|
||||||
|
|
||||||
readonly oninput="this.form.aRange77.value=this.value" />
|
readonly oninput="this.form.aRange77.value=this.value" />
|
||||||
|
|
||||||
|
|
||||||
|
<input class="range api" type="range" name="aRange77" data-type="uint16" data-key="77"
|
||||||
<input class="range api" type="range" name="aRange77" data-type="uint16" data-key="77"
|
|
||||||
onchange="valueChangedHandler(this)"
|
onchange="valueChangedHandler(this)"
|
||||||
|
|
||||||
min="" max="" oninput="this.form.aInput77.value=this.value" />
|
min="" max="" oninput="this.form.aInput77.value=this.value" />
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -1558,7 +1558,7 @@ img {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -1573,16 +1573,16 @@ img {
|
||||||
<div class="clearfix">
|
<div class="clearfix">
|
||||||
|
|
||||||
<label class="label-inline"> Force KBD Boot Protocol</label>
|
<label class="label-inline"> Force KBD Boot Protocol</label>
|
||||||
|
|
||||||
|
|
||||||
|
<input class="api" type="checkbox" name="name72" data-type="uint8" data-key="72"
|
||||||
<input class="api" type="checkbox" name="name72" data-type="uint8" data-key="72"
|
|
||||||
onchange="valueChangedHandler(this)"
|
onchange="valueChangedHandler(this)"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -1597,16 +1597,16 @@ img {
|
||||||
<div class="clearfix">
|
<div class="clearfix">
|
||||||
|
|
||||||
<label class="label-inline"> KBD LED as Indicator</label>
|
<label class="label-inline"> KBD LED as Indicator</label>
|
||||||
|
|
||||||
|
|
||||||
|
<input class="api" type="checkbox" name="name73" data-type="uint8" data-key="73"
|
||||||
<input class="api" type="checkbox" name="name73" data-type="uint8" data-key="73"
|
|
||||||
onchange="valueChangedHandler(this)"
|
onchange="valueChangedHandler(this)"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -1621,16 +1621,16 @@ img {
|
||||||
<div class="clearfix">
|
<div class="clearfix">
|
||||||
|
|
||||||
<label class="label-inline"> Enforce Ports</label>
|
<label class="label-inline"> Enforce Ports</label>
|
||||||
|
|
||||||
|
|
||||||
|
<input class="api" type="checkbox" name="name76" data-type="uint8" data-key="76"
|
||||||
<input class="api" type="checkbox" name="name76" data-type="uint8" data-key="76"
|
|
||||||
onchange="valueChangedHandler(this)"
|
onchange="valueChangedHandler(this)"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<input type="submit" value="Save" id="submitButton">
|
<input type="submit" value="Save" id="submitButton">
|
||||||
|
@ -1654,12 +1654,12 @@ img {
|
||||||
<label class="label-inline"> Running FW version:</label>
|
<label class="label-inline"> Running FW version:</label>
|
||||||
|
|
||||||
|
|
||||||
<input class="content api" type="text" name="name78" data-type="uint16" data-key="78"
|
<input class="content api" type="text" name="name78" data-type="uint16" data-key="78"
|
||||||
onchange="valueChangedHandler(this)"
|
onchange="valueChangedHandler(this)"
|
||||||
data-hex readonly />
|
data-hex readonly />
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -1675,12 +1675,12 @@ img {
|
||||||
<label class="label-inline"> Running FW checksum:</label>
|
<label class="label-inline"> Running FW checksum:</label>
|
||||||
|
|
||||||
|
|
||||||
<input class="content api" type="text" name="name79" data-type="uint32" data-key="79"
|
<input class="content api" type="text" name="name79" data-type="uint32" data-key="79"
|
||||||
onchange="valueChangedHandler(this)"
|
onchange="valueChangedHandler(this)"
|
||||||
data-hex readonly />
|
data-hex readonly />
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
@ -1697,7 +1697,7 @@ var device;
|
||||||
const packetType = {
|
const packetType = {
|
||||||
keyboardReportMsg: 1, mouseReportMsg: 2, outputSelectMsg: 3, firmwareUpgradeMsg: 4, switchLockMsg: 7,
|
keyboardReportMsg: 1, mouseReportMsg: 2, outputSelectMsg: 3, firmwareUpgradeMsg: 4, switchLockMsg: 7,
|
||||||
syncBordersMsg: 8, flashLedMsg: 9, wipeConfigMsg: 10, readConfigMsg: 16, writeConfigMsg: 17, saveConfigMsg: 18,
|
syncBordersMsg: 8, flashLedMsg: 9, wipeConfigMsg: 10, readConfigMsg: 16, writeConfigMsg: 17, saveConfigMsg: 18,
|
||||||
rebootMsg: 19, getValMsg: 20, setValMsg: 21, proxyPacketMsg: 23
|
rebootMsg: 19, getValMsg: 20, setValMsg: 21, getValAllMsg: 22, proxyPacketMsg: 23
|
||||||
};
|
};
|
||||||
|
|
||||||
function calcChecksum(report) {
|
function calcChecksum(report) {
|
||||||
|
@ -1710,26 +1710,26 @@ function calcChecksum(report) {
|
||||||
|
|
||||||
async function sendReport(type, payload = [], sendBoth = false) {
|
async function sendReport(type, payload = [], sendBoth = false) {
|
||||||
if (!device || !device.opened)
|
if (!device || !device.opened)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/* First send this one, if the first one gets e.g. rebooted */
|
/* First send this one, if the first one gets e.g. rebooted */
|
||||||
if (sendBoth) {
|
if (sendBoth) {
|
||||||
var reportProxy = makeReport(type, payload, true);
|
var reportProxy = makeReport(type, payload, true);
|
||||||
await device.sendReport(mgmtReportId, reportProxy);
|
await device.sendReport(mgmtReportId, reportProxy);
|
||||||
}
|
}
|
||||||
|
|
||||||
var report = makeReport(type, payload, false);
|
var report = makeReport(type, payload, false);
|
||||||
await device.sendReport(mgmtReportId, report);
|
await device.sendReport(mgmtReportId, report);
|
||||||
}
|
}
|
||||||
|
|
||||||
function makeReport(type, payload, proxy=false) {
|
function makeReport(type, payload, proxy=false) {
|
||||||
var dataOffset = proxy ? 4 : 3;
|
var dataOffset = proxy ? 4 : 3;
|
||||||
report = new Uint8Array([0xaa, 0x55, type, ...new Array(9).fill(0)]);
|
report = new Uint8Array([0xaa, 0x55, type, ...new Array(9).fill(0)]);
|
||||||
|
|
||||||
if (proxy)
|
if (proxy)
|
||||||
report = new Uint8Array([0xaa, 0x55, packetType.proxyPacketMsg, type, ...new Array(7).fill(0), type]);
|
report = new Uint8Array([0xaa, 0x55, packetType.proxyPacketMsg, type, ...new Array(7).fill(0), type]);
|
||||||
|
|
||||||
if (payload) {
|
if (payload) {
|
||||||
report.set([...payload], dataOffset);
|
report.set([...payload], dataOffset);
|
||||||
report[report.length - 1] = calcChecksum(report);
|
report[report.length - 1] = calcChecksum(report);
|
||||||
}
|
}
|
||||||
|
@ -1784,7 +1784,8 @@ async function connectHandler() {
|
||||||
});
|
});
|
||||||
|
|
||||||
device = devices[0];
|
device = devices[0];
|
||||||
device.open().then(async () => {
|
device.open().then(async () => {
|
||||||
|
device.addEventListener('inputreport', handleInputReport);
|
||||||
document.querySelectorAll('.online').forEach(element => { element.style.opacity = 1.0; });
|
document.querySelectorAll('.online').forEach(element => { element.style.opacity = 1.0; });
|
||||||
await readHandler();
|
await readHandler();
|
||||||
});
|
});
|
||||||
|
@ -1816,8 +1817,12 @@ function setValue(element, value) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function updateElement(element, event, dataType) {
|
function updateElement(key, event) {
|
||||||
var dataOffset = 3;
|
var dataOffset = 4;
|
||||||
|
var element = document.querySelector(`[data-key="${key}"]`);
|
||||||
|
|
||||||
|
if (!element)
|
||||||
|
return;
|
||||||
|
|
||||||
const methods = {
|
const methods = {
|
||||||
"uint32": event.data.getUint32,
|
"uint32": event.data.getUint32,
|
||||||
|
@ -1829,6 +1834,8 @@ function updateElement(element, event, dataType) {
|
||||||
"int8": event.data.getInt8
|
"int8": event.data.getInt8
|
||||||
};
|
};
|
||||||
|
|
||||||
|
dataType = element.getAttribute('data-type');
|
||||||
|
|
||||||
if (dataType in methods) {
|
if (dataType in methods) {
|
||||||
var value = methods[dataType].call(event.data, dataOffset, true);
|
var value = methods[dataType].call(event.data, dataOffset, true);
|
||||||
setValue(element, value);
|
setValue(element, value);
|
||||||
|
@ -1842,24 +1849,14 @@ async function readHandler() {
|
||||||
if (!device || !device.opened)
|
if (!device || !device.opened)
|
||||||
await connectHandler();
|
await connectHandler();
|
||||||
|
|
||||||
const elements = document.querySelectorAll('.api');
|
await sendReport(packetType.getValAllMsg);
|
||||||
|
}
|
||||||
|
|
||||||
for (const element of elements) {
|
async function handleInputReport(event) {
|
||||||
var key = element.getAttribute('data-key');
|
var data = new Uint8Array(event.data.buffer);
|
||||||
var dataType = element.getAttribute('data-type');
|
var key = data[3];
|
||||||
|
|
||||||
await sendReport(packetType.getValMsg, [key]);
|
updateElement(key, event);
|
||||||
|
|
||||||
let incomingReport = await new Promise((resolve, reject) => {
|
|
||||||
const handleInputReport = (event) => {
|
|
||||||
updateElement(element, event, dataType);
|
|
||||||
|
|
||||||
device.removeEventListener('inputreport', handleInputReport);
|
|
||||||
resolve();
|
|
||||||
}
|
|
||||||
device.addEventListener('inputreport', handleInputReport);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async function rebootHandler() {
|
async function rebootHandler() {
|
||||||
|
@ -1879,7 +1876,7 @@ async function valueChangedHandler(element) {
|
||||||
|
|
||||||
if (origValue != newValue) {
|
if (origValue != newValue) {
|
||||||
uintBuffer = packValue(element, key, dataType);
|
uintBuffer = packValue(element, key, dataType);
|
||||||
|
|
||||||
/* Send to both devices */
|
/* Send to both devices */
|
||||||
await sendReport(packetType.setValMsg, uintBuffer, true);
|
await sendReport(packetType.setValMsg, uintBuffer, true);
|
||||||
|
|
||||||
|
@ -1901,7 +1898,7 @@ async function saveHandler() {
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (origValue != getValue(element))
|
if (origValue != getValue(element))
|
||||||
await valueChangedHandler(element);
|
await valueChangedHandler(element);
|
||||||
}
|
}
|
||||||
await sendReport(packetType.saveConfigMsg, [], true);
|
await sendReport(packetType.saveConfigMsg, [], true);
|
||||||
}
|
}
|
||||||
|
|
File diff suppressed because one or more lines are too long
|
@ -12,12 +12,12 @@ class FormField:
|
||||||
elem: str | None = None
|
elem: str | None = None
|
||||||
|
|
||||||
SHORTCUTS = {
|
SHORTCUTS = {
|
||||||
0x73: "None",
|
0x73: "None",
|
||||||
0x2A: "Backspace",
|
0x2A: "Backspace",
|
||||||
0x39: "Caps Lock",
|
0x39: "Caps Lock",
|
||||||
0x2B: "Tab",
|
0x2B: "Tab",
|
||||||
0x46: "Print Screen",
|
0x46: "Print Screen",
|
||||||
0x47: "Scroll Lock",
|
0x47: "Scroll Lock",
|
||||||
0x53: "Num Lock",
|
0x53: "Num Lock",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -26,18 +26,18 @@ STATUS_ = [
|
||||||
FormField(79, "Running FW checksum", None, {}, "uint32", elem="hex_info"),
|
FormField(79, "Running FW checksum", None, {}, "uint32", elem="hex_info"),
|
||||||
]
|
]
|
||||||
|
|
||||||
CONFIG_ = [
|
CONFIG_ = [
|
||||||
FormField(1001, "Mouse", elem="label"),
|
FormField(1001, "Mouse", elem="label"),
|
||||||
FormField(71, "Force Mouse Boot Mode", None, {}, "uint8", "checkbox"),
|
FormField(71, "Force Mouse Boot Mode", None, {}, "uint8", "checkbox"),
|
||||||
FormField(75, "Enable Acceleration", None, {}, "uint8", "checkbox"),
|
FormField(75, "Enable Acceleration", None, {}, "uint8", "checkbox"),
|
||||||
FormField(77, "Jump Treshold", 0, {"min": 0, "max": 1024}, "uint16", "range"),
|
FormField(77, "Jump Treshold", 0, {"min": 0, "max": 1024}, "uint16", "range"),
|
||||||
|
|
||||||
FormField(1002, "Keyboard", elem="label"),
|
FormField(1002, "Keyboard", elem="label"),
|
||||||
FormField(72, "Force KBD Boot Protocol", None, {}, "uint8", "checkbox"),
|
FormField(72, "Force KBD Boot Protocol", None, {}, "uint8", "checkbox"),
|
||||||
FormField(73, "KBD LED as Indicator", None, {}, "uint8", "checkbox"),
|
FormField(73, "KBD LED as Indicator", None, {}, "uint8", "checkbox"),
|
||||||
|
|
||||||
FormField(76, "Enforce Ports", None, {}, "uint8", "checkbox"),
|
FormField(76, "Enforce Ports", None, {}, "uint8", "checkbox"),
|
||||||
]
|
]
|
||||||
|
|
||||||
OUTPUT_ = [
|
OUTPUT_ = [
|
||||||
FormField(1, "Screen Count", 1, {1: "1", 2: "2", 3: "3"}, "uint32"),
|
FormField(1, "Screen Count", 1, {1: "1", 2: "2", 3: "3"}, "uint32"),
|
||||||
|
@ -48,7 +48,7 @@ OUTPUT_ = [
|
||||||
FormField(6, "Operating System", 1, {1: "Linux", 2: "MacOS", 3: "Windows", 4: "Android", 255: "Other"}, "uint8"),
|
FormField(6, "Operating System", 1, {1: "Linux", 2: "MacOS", 3: "Windows", 4: "Android", 255: "Other"}, "uint8"),
|
||||||
FormField(7, "Screen Position", 1, {1: "Left", 2: "Right"}, "uint8"),
|
FormField(7, "Screen Position", 1, {1: "Left", 2: "Right"}, "uint8"),
|
||||||
FormField(8, "Cursor Park Position", 0, {0: "Top", 1: "Bottom", 3: "Previous"}, "uint8"),
|
FormField(8, "Cursor Park Position", 0, {0: "Top", 1: "Bottom", 3: "Previous"}, "uint8"),
|
||||||
FormField(1003, "Screensaver", elem="label"),
|
FormField(1003, "Screensaver", elem="label"),
|
||||||
FormField(9, "Mode", 0, {0: "Disabled", 1: "Pong", 2: "Jitter"}, "uint8"),
|
FormField(9, "Mode", 0, {0: "Disabled", 1: "Pong", 2: "Jitter"}, "uint8"),
|
||||||
FormField(10, "Only If Inactive", None, {}, "uint8", "checkbox"),
|
FormField(10, "Only If Inactive", None, {}, "uint8", "checkbox"),
|
||||||
FormField(11, "Idle Time (μs)", None, {}, "uint64"),
|
FormField(11, "Idle Time (μs)", None, {}, "uint64"),
|
||||||
|
|
|
@ -37,12 +37,12 @@ def encode_file(payload):
|
||||||
return base64_compressed_data
|
return base64_compressed_data
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
# Read main template contents
|
# Read main template contents
|
||||||
webpage = render(
|
webpage = render(
|
||||||
INPUT_FILENAME,
|
INPUT_FILENAME,
|
||||||
screen_A=output_A(),
|
screen_A=output_A(),
|
||||||
screen_B=output_B(),
|
screen_B=output_B(),
|
||||||
status=output_status(),
|
status=output_status(),
|
||||||
config=output_config(),
|
config=output_config(),
|
||||||
)
|
)
|
||||||
|
@ -56,6 +56,6 @@ if __name__ == "__main__":
|
||||||
|
|
||||||
# Write data to output filename
|
# Write data to output filename
|
||||||
write_file(self_extracting_webpage)
|
write_file(self_extracting_webpage)
|
||||||
|
|
||||||
# Write unpacked webpage
|
# Write unpacked webpage
|
||||||
write_file(webpage, OUTPUT_UNPACKED)
|
write_file(webpage, OUTPUT_UNPACKED)
|
|
@ -3,7 +3,7 @@
|
||||||
{% set key = item.key %}
|
{% set key = item.key %}
|
||||||
|
|
||||||
{% macro input(item, type='text', class='api', name='name') %}
|
{% macro input(item, type='text', class='api', name='name') %}
|
||||||
<input class="{{ class }}" type="{{ type }}" name="{{ name }}{{ key }}" data-type="{{ item.type }}" data-key="{{ key }}"
|
<input class="{{ class }}" type="{{ type }}" name="{{ name }}{{ key }}" data-type="{{ item.type }}" data-key="{{ key }}"
|
||||||
onchange="valueChangedHandler(this)"
|
onchange="valueChangedHandler(this)"
|
||||||
{% endmacro %}
|
{% endmacro %}
|
||||||
|
|
||||||
|
@ -26,26 +26,26 @@
|
||||||
|
|
||||||
{{ input(item, class='input-inline', type='number', name='aInput') }}
|
{{ input(item, class='input-inline', type='number', name='aInput') }}
|
||||||
readonly oninput="this.form.aRange{{ key }}.value=this.value" />
|
readonly oninput="this.form.aRange{{ key }}.value=this.value" />
|
||||||
|
|
||||||
{{ input(item, class='range api', type='range', name='aRange') }}
|
{{ input(item, class='range api', type='range', name='aRange') }}
|
||||||
min="{{ item.values.min }}" max="{{ item.values.max }}" oninput="this.form.aInput{{key}}.value=this.value" />
|
min="{{ item.values.min }}" max="{{ item.values.max }}" oninput="this.form.aInput{{key}}.value=this.value" />
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{% elif item.get("elem") == "checkbox" %}
|
{% elif item.get("elem") == "checkbox" %}
|
||||||
<div class="clearfix">
|
<div class="clearfix">
|
||||||
{{ label(item) }}
|
{{ label(item) }}
|
||||||
{{ input(item, type="checkbox") }} />
|
{{ input(item, type="checkbox") }} />
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{% elif item["values"] %}
|
{% elif item["values"] %}
|
||||||
{{ label(item, class='') }}
|
{{ label(item, class='') }}
|
||||||
<select class="api" data-type="{{ item.type }}" data-key="{{ key }}" required>
|
<select class="api" data-type="{{ item.type }}" data-key="{{ key }}" required>
|
||||||
<option disabled selected value></option>
|
<option disabled selected value></option>
|
||||||
|
|
||||||
{% for k, v in item["values"].items() %}
|
{% for k, v in item["values"].items() %}
|
||||||
<option value="{{ k }}">{{ v }}</option>
|
<option value="{{ k }}">{{ v }}</option>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</select><br />
|
</select><br />
|
||||||
|
|
|
@ -17,14 +17,14 @@
|
||||||
|
|
||||||
<main class="wrapper">
|
<main class="wrapper">
|
||||||
|
|
||||||
<section class="container">
|
<section class="container">
|
||||||
|
|
||||||
<div class="row" id="warning" style="display: none;">
|
<div class="row" id="warning" style="display: none;">
|
||||||
<blockquote>
|
<blockquote>
|
||||||
<h3> Oh, no! </h3>
|
<h3> Oh, no! </h3>
|
||||||
Unfortunately, your browser does not support WebHID or the Permissions Policy is blocking its usage. Please try Chromium <br />
|
Unfortunately, your browser does not support WebHID or the Permissions Policy is blocking its usage. Please try Chromium <br />
|
||||||
(or Chrome if you have to). Apologies for the inconvenience, hopefully a cross-browser solution happens soon.
|
(or Chrome if you have to). Apologies for the inconvenience, hopefully a cross-browser solution happens soon.
|
||||||
</blockquote>
|
</blockquote>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
|
@ -52,7 +52,7 @@
|
||||||
<path d="m 104.01516,99.341366 a 1.8639801,1.8639801 0 0 0 -1.86329,1.863284 1.8639801,1.8639801 0 0 0 1.86329,1.86328 h 27.4375 a 1.8639801,1.8639801 0 0 0 1.86718,-1.86328 1.8639801,1.8639801 0 0 0 -1.86718,-1.863284 z" />
|
<path d="m 104.01516,99.341366 a 1.8639801,1.8639801 0 0 0 -1.86329,1.863284 1.8639801,1.8639801 0 0 0 1.86329,1.86328 h 27.4375 a 1.8639801,1.8639801 0 0 0 1.86718,-1.86328 1.8639801,1.8639801 0 0 0 -1.86718,-1.863284 z" />
|
||||||
</g>
|
</g>
|
||||||
</svg>
|
</svg>
|
||||||
|
|
||||||
<div id="menu-buttons">
|
<div id="menu-buttons">
|
||||||
<button data-handler="connectHandler" class="button button-clear button-shifted">Connect</button><br />
|
<button data-handler="connectHandler" class="button button-clear button-shifted">Connect</button><br />
|
||||||
<button data-handler="readHandler" class="button button-clear button-shifted online">Read</button><br />
|
<button data-handler="readHandler" class="button button-clear button-shifted online">Read</button><br />
|
||||||
|
@ -63,8 +63,8 @@
|
||||||
<button data-handler="blinkHandler" class="button button-clear button-shifted online">Blink</button><br />
|
<button data-handler="blinkHandler" class="button button-clear button-shifted online">Blink</button><br />
|
||||||
<button data-handler="blinkBothHandler" class="button button-clear button-shifted online">Blink both</button><br />
|
<button data-handler="blinkBothHandler" class="button button-clear button-shifted online">Blink both</button><br />
|
||||||
<button data-handler="enterBootloaderHandler" class="button button-clear button-shifted online">Bootloader</button><br />
|
<button data-handler="enterBootloaderHandler" class="button button-clear button-shifted online">Bootloader</button><br />
|
||||||
<button data-handler="wipeConfigHandler" class="button button-clear button-shifted online">Wipe Config</button><br />
|
<button data-handler="wipeConfigHandler" class="button button-clear button-shifted online">Wipe Config</button><br />
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
@ -80,7 +80,7 @@
|
||||||
<h3>Output A</h3>
|
<h3>Output A</h3>
|
||||||
|
|
||||||
{% for item in screen_A %}
|
{% for item in screen_A %}
|
||||||
{% include "form.html" with context %}
|
{% include "form.html" with context %}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
@ -91,13 +91,13 @@
|
||||||
<line x1="50" y1="90" x2="50" y2="75" stroke="black" stroke-width="2" />
|
<line x1="50" y1="90" x2="50" y2="75" stroke="black" stroke-width="2" />
|
||||||
<rect x="30" y="90" width="40" height="3" stroke="black" stroke-width="2" fill="#d7e5f0" rx="5" ry="5" />
|
<rect x="30" y="90" width="40" height="3" stroke="black" stroke-width="2" fill="#d7e5f0" rx="5" ry="5" />
|
||||||
</svg>
|
</svg>
|
||||||
|
|
||||||
<h3>Output B</h3>
|
<h3>Output B</h3>
|
||||||
|
|
||||||
{% for item in screen_B %}
|
{% for item in screen_B %}
|
||||||
{% include "form.html" with context %}
|
{% include "form.html" with context %}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
@ -114,7 +114,7 @@
|
||||||
<h3>Common Config</h3>
|
<h3>Common Config</h3>
|
||||||
|
|
||||||
{% for item in config %}
|
{% for item in config %}
|
||||||
{% include "form.html" with context %}
|
{% include "form.html" with context %}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|
||||||
<input type="submit" value="Save" id="submitButton">
|
<input type="submit" value="Save" id="submitButton">
|
||||||
|
@ -124,7 +124,7 @@
|
||||||
<h3>Device Status</h3>
|
<h3>Device Status</h3>
|
||||||
|
|
||||||
{% for item in status %}
|
{% for item in status %}
|
||||||
{% include "form.html" with context %}
|
{% include "form.html" with context %}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -4,7 +4,7 @@ var device;
|
||||||
const packetType = {
|
const packetType = {
|
||||||
keyboardReportMsg: 1, mouseReportMsg: 2, outputSelectMsg: 3, firmwareUpgradeMsg: 4, switchLockMsg: 7,
|
keyboardReportMsg: 1, mouseReportMsg: 2, outputSelectMsg: 3, firmwareUpgradeMsg: 4, switchLockMsg: 7,
|
||||||
syncBordersMsg: 8, flashLedMsg: 9, wipeConfigMsg: 10, readConfigMsg: 16, writeConfigMsg: 17, saveConfigMsg: 18,
|
syncBordersMsg: 8, flashLedMsg: 9, wipeConfigMsg: 10, readConfigMsg: 16, writeConfigMsg: 17, saveConfigMsg: 18,
|
||||||
rebootMsg: 19, getValMsg: 20, setValMsg: 21, proxyPacketMsg: 23
|
rebootMsg: 19, getValMsg: 20, setValMsg: 21, getValAllMsg: 22, proxyPacketMsg: 23
|
||||||
};
|
};
|
||||||
|
|
||||||
function calcChecksum(report) {
|
function calcChecksum(report) {
|
||||||
|
@ -17,26 +17,26 @@ function calcChecksum(report) {
|
||||||
|
|
||||||
async function sendReport(type, payload = [], sendBoth = false) {
|
async function sendReport(type, payload = [], sendBoth = false) {
|
||||||
if (!device || !device.opened)
|
if (!device || !device.opened)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/* First send this one, if the first one gets e.g. rebooted */
|
/* First send this one, if the first one gets e.g. rebooted */
|
||||||
if (sendBoth) {
|
if (sendBoth) {
|
||||||
var reportProxy = makeReport(type, payload, true);
|
var reportProxy = makeReport(type, payload, true);
|
||||||
await device.sendReport(mgmtReportId, reportProxy);
|
await device.sendReport(mgmtReportId, reportProxy);
|
||||||
}
|
}
|
||||||
|
|
||||||
var report = makeReport(type, payload, false);
|
var report = makeReport(type, payload, false);
|
||||||
await device.sendReport(mgmtReportId, report);
|
await device.sendReport(mgmtReportId, report);
|
||||||
}
|
}
|
||||||
|
|
||||||
function makeReport(type, payload, proxy=false) {
|
function makeReport(type, payload, proxy=false) {
|
||||||
var dataOffset = proxy ? 4 : 3;
|
var dataOffset = proxy ? 4 : 3;
|
||||||
report = new Uint8Array([0xaa, 0x55, type, ...new Array(9).fill(0)]);
|
report = new Uint8Array([0xaa, 0x55, type, ...new Array(9).fill(0)]);
|
||||||
|
|
||||||
if (proxy)
|
if (proxy)
|
||||||
report = new Uint8Array([0xaa, 0x55, packetType.proxyPacketMsg, type, ...new Array(7).fill(0), type]);
|
report = new Uint8Array([0xaa, 0x55, packetType.proxyPacketMsg, type, ...new Array(7).fill(0), type]);
|
||||||
|
|
||||||
if (payload) {
|
if (payload) {
|
||||||
report.set([...payload], dataOffset);
|
report.set([...payload], dataOffset);
|
||||||
report[report.length - 1] = calcChecksum(report);
|
report[report.length - 1] = calcChecksum(report);
|
||||||
}
|
}
|
||||||
|
@ -91,7 +91,8 @@ async function connectHandler() {
|
||||||
});
|
});
|
||||||
|
|
||||||
device = devices[0];
|
device = devices[0];
|
||||||
device.open().then(async () => {
|
device.open().then(async () => {
|
||||||
|
device.addEventListener('inputreport', handleInputReport);
|
||||||
document.querySelectorAll('.online').forEach(element => { element.style.opacity = 1.0; });
|
document.querySelectorAll('.online').forEach(element => { element.style.opacity = 1.0; });
|
||||||
await readHandler();
|
await readHandler();
|
||||||
});
|
});
|
||||||
|
@ -123,8 +124,12 @@ function setValue(element, value) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function updateElement(element, event, dataType) {
|
function updateElement(key, event) {
|
||||||
var dataOffset = 3;
|
var dataOffset = 4;
|
||||||
|
var element = document.querySelector(`[data-key="${key}"]`);
|
||||||
|
|
||||||
|
if (!element)
|
||||||
|
return;
|
||||||
|
|
||||||
const methods = {
|
const methods = {
|
||||||
"uint32": event.data.getUint32,
|
"uint32": event.data.getUint32,
|
||||||
|
@ -136,6 +141,8 @@ function updateElement(element, event, dataType) {
|
||||||
"int8": event.data.getInt8
|
"int8": event.data.getInt8
|
||||||
};
|
};
|
||||||
|
|
||||||
|
dataType = element.getAttribute('data-type');
|
||||||
|
|
||||||
if (dataType in methods) {
|
if (dataType in methods) {
|
||||||
var value = methods[dataType].call(event.data, dataOffset, true);
|
var value = methods[dataType].call(event.data, dataOffset, true);
|
||||||
setValue(element, value);
|
setValue(element, value);
|
||||||
|
@ -149,24 +156,14 @@ async function readHandler() {
|
||||||
if (!device || !device.opened)
|
if (!device || !device.opened)
|
||||||
await connectHandler();
|
await connectHandler();
|
||||||
|
|
||||||
const elements = document.querySelectorAll('.api');
|
await sendReport(packetType.getValAllMsg);
|
||||||
|
}
|
||||||
|
|
||||||
for (const element of elements) {
|
async function handleInputReport(event) {
|
||||||
var key = element.getAttribute('data-key');
|
var data = new Uint8Array(event.data.buffer);
|
||||||
var dataType = element.getAttribute('data-type');
|
var key = data[3];
|
||||||
|
|
||||||
await sendReport(packetType.getValMsg, [key]);
|
updateElement(key, event);
|
||||||
|
|
||||||
let incomingReport = await new Promise((resolve, reject) => {
|
|
||||||
const handleInputReport = (event) => {
|
|
||||||
updateElement(element, event, dataType);
|
|
||||||
|
|
||||||
device.removeEventListener('inputreport', handleInputReport);
|
|
||||||
resolve();
|
|
||||||
}
|
|
||||||
device.addEventListener('inputreport', handleInputReport);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async function rebootHandler() {
|
async function rebootHandler() {
|
||||||
|
@ -186,7 +183,7 @@ async function valueChangedHandler(element) {
|
||||||
|
|
||||||
if (origValue != newValue) {
|
if (origValue != newValue) {
|
||||||
uintBuffer = packValue(element, key, dataType);
|
uintBuffer = packValue(element, key, dataType);
|
||||||
|
|
||||||
/* Send to both devices */
|
/* Send to both devices */
|
||||||
await sendReport(packetType.setValMsg, uintBuffer, true);
|
await sendReport(packetType.setValMsg, uintBuffer, true);
|
||||||
|
|
||||||
|
@ -208,7 +205,7 @@ async function saveHandler() {
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (origValue != getValue(element))
|
if (origValue != getValue(element))
|
||||||
await valueChangedHandler(element);
|
await valueChangedHandler(element);
|
||||||
}
|
}
|
||||||
await sendReport(packetType.saveConfigMsg, [], true);
|
await sendReport(packetType.saveConfigMsg, [], true);
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,7 +15,7 @@
|
||||||
:root {
|
:root {
|
||||||
--highlight-color: #384955;
|
--highlight-color: #384955;
|
||||||
--font-color: #384955;
|
--font-color: #384955;
|
||||||
--highlight-color2: #5e9f41;
|
--highlight-color2: #5e9f41;
|
||||||
}
|
}
|
||||||
|
|
||||||
html {
|
html {
|
||||||
|
@ -483,7 +483,7 @@ input[type='number'].input-inline {
|
||||||
@media (min-width: 40rem) {
|
@media (min-width: 40rem) {
|
||||||
.row {
|
.row {
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
|
|
||||||
width: calc(100% + 2.0rem);
|
width: calc(100% + 2.0rem);
|
||||||
}
|
}
|
||||||
.row .column {
|
.row .column {
|
||||||
|
|
Loading…
Reference in New Issue