mirror of
https://github.com/hrvach/deskhop.git
synced 2024-11-24 16:54:18 +01:00
Features and fixes
- Auto switch-lock when dragging or resizing windows. * This was super annoying for me, resizing a window and you get too close to the left border, making it shrink suddenly. Now if you drag while holding a mouse button pressed, it will not switch. - Added Mac OS multiple desktop workaround * you need to tweak defaults.c and set screen_count to e.g. 2 if you have 2 desktops on a single mac output, and set OUTPUT_A_OS (or OUTPUT_B_OS) to MACOS in user_config.h, then rebuild * This will be keyboard-configurable in the future without rebuilding * Support still experimental - HID report protocol default for port B - Added support for swapping output order * defaults.c, output has "pos" you can set to either LEFT or RIGHT * this will be hotkey-configurable - Bugfixes - Added debugging mode (serial CDC device for printf things) - Refactored screensaver a bit
This commit is contained in:
parent
f0b36569c9
commit
9c69dc3cd6
@ -14,8 +14,16 @@ const config_t default_config = {
|
||||
.bottom = MAX_SCREEN_COORD,
|
||||
},
|
||||
.screen_count = 1,
|
||||
.screen_index = 0,
|
||||
},
|
||||
.screen_index = 1,
|
||||
.os = OUTPUT_A_OS,
|
||||
.pos = LEFT,
|
||||
.screensaver = {
|
||||
.enabled = SCREENSAVER_A_ENABLED,
|
||||
.only_if_inactive = SCREENSAVER_A_ONLY_IF_INACTIVE,
|
||||
.idle_time_us = SCREENSAVER_A_IDLE_TIME_SEC * 1000000,
|
||||
.max_time_us = SCREENSAVER_A_MAX_TIME_SEC * 1000000,
|
||||
}
|
||||
},
|
||||
.output[OUTPUT_B] =
|
||||
{
|
||||
.number = OUTPUT_B,
|
||||
@ -26,20 +34,14 @@ const config_t default_config = {
|
||||
.bottom = MAX_SCREEN_COORD,
|
||||
},
|
||||
.screen_count = 1,
|
||||
.screen_index = 0,
|
||||
.screen_index = 1,
|
||||
.os = OUTPUT_B_OS,
|
||||
.pos = RIGHT,
|
||||
.screensaver = {
|
||||
.enabled = SCREENSAVER_B_ENABLED,
|
||||
.only_if_inactive = SCREENSAVER_B_ONLY_IF_INACTIVE,
|
||||
.idle_time_us = SCREENSAVER_B_IDLE_TIME_SEC * 1000000,
|
||||
.max_time_us = SCREENSAVER_B_MAX_TIME_SEC * 1000000,
|
||||
}
|
||||
},
|
||||
.screensaver[OUTPUT_A] =
|
||||
{
|
||||
.enabled = SCREENSAVER_A_ENABLED,
|
||||
.only_if_inactive = SCREENSAVER_A_ONLY_IF_INACTIVE,
|
||||
.idle_time_us = SCREENSAVER_A_IDLE_TIME_SEC * 1000000,
|
||||
.max_time_us = SCREENSAVER_A_MAX_TIME_SEC * 1000000,
|
||||
},
|
||||
.screensaver[OUTPUT_B] =
|
||||
{
|
||||
.enabled = SCREENSAVER_B_ENABLED,
|
||||
.only_if_inactive = SCREENSAVER_B_ONLY_IF_INACTIVE,
|
||||
.idle_time_us = SCREENSAVER_B_IDLE_TIME_SEC * 1000000,
|
||||
.max_time_us = SCREENSAVER_B_MAX_TIME_SEC * 1000000,
|
||||
},
|
||||
};
|
||||
};
|
@ -31,18 +31,24 @@ void output_toggle_hotkey_handler(device_t *state) {
|
||||
switch_output(state, state->active_output);
|
||||
};
|
||||
|
||||
/* This key combo records switch y top coordinate for different-size monitors */
|
||||
void screen_border_hotkey_handler(device_t *state) {
|
||||
border_size_t *border = &state->config.output[state->active_output].border;
|
||||
|
||||
void get_border_position(device_t *state, border_size_t *border) {
|
||||
/* To avoid having 2 different keys, if we're above half, it's the top coord */
|
||||
if (state->mouse_y > (MAX_SCREEN_COORD / 2))
|
||||
border->bottom = state->mouse_y;
|
||||
else
|
||||
border->top = state->mouse_y;
|
||||
}
|
||||
|
||||
|
||||
/* This key combo records switch y top coordinate for different-size monitors */
|
||||
void screen_border_hotkey_handler(device_t *state) {
|
||||
border_size_t *border = &state->config.output[state->active_output].border;
|
||||
if (CURRENT_BOARD_IS_ACTIVE_OUTPUT) {
|
||||
get_border_position(state, border);
|
||||
save_config(state);
|
||||
}
|
||||
|
||||
send_packet((uint8_t *)border, SYNC_BORDERS_MSG, sizeof(border_size_t));
|
||||
save_config(state);
|
||||
};
|
||||
|
||||
/* This key combo puts board A in firmware upgrade mode */
|
||||
@ -69,8 +75,8 @@ void wipe_config_hotkey_handler(device_t *state) {
|
||||
}
|
||||
|
||||
void screensaver_hotkey_handler(device_t *state) {
|
||||
state->config.screensaver[BOARD_ROLE].enabled ^= 1;
|
||||
send_value(state->config.screensaver[BOARD_ROLE].enabled, SCREENSAVER_MSG);
|
||||
state->config.output[BOARD_ROLE].screensaver.enabled ^= 1;
|
||||
send_value(state->config.output[BOARD_ROLE].screensaver.enabled, SCREENSAVER_MSG);
|
||||
}
|
||||
|
||||
/* When pressed, toggles the current mouse zoom mode state */
|
||||
@ -87,19 +93,18 @@ void mouse_zoom_hotkey_handler(device_t *state) {
|
||||
void handle_keyboard_uart_msg(uart_packet_t *packet, device_t *state) {
|
||||
queue_kbd_report((hid_keyboard_report_t *)packet->data, state);
|
||||
state->last_activity[BOARD_ROLE] = time_us_64();
|
||||
state->screensaver_max_time_reached[BOARD_ROLE] = false;
|
||||
}
|
||||
|
||||
/* Function handles received mouse moves from the other board */
|
||||
void handle_mouse_abs_uart_msg(uart_packet_t *packet, device_t *state) {
|
||||
mouse_abs_report_t *mouse_report = (mouse_abs_report_t *)packet->data;
|
||||
mouse_report_t *mouse_report = (mouse_report_t *)packet->data;
|
||||
queue_mouse_report(mouse_report, state);
|
||||
|
||||
state->mouse_x = mouse_report->x;
|
||||
state->mouse_y = mouse_report->y;
|
||||
state->mouse_buttons = mouse_report->buttons;
|
||||
|
||||
state->last_activity[BOARD_ROLE] = time_us_64();
|
||||
state->screensaver_max_time_reached[BOARD_ROLE] = false;
|
||||
}
|
||||
|
||||
/* Function handles request to switch output */
|
||||
@ -135,7 +140,14 @@ void handle_switch_lock_msg(uart_packet_t *packet, device_t *state) {
|
||||
/* Handle border syncing message that lets the other device know about monitor height offset */
|
||||
void handle_sync_borders_msg(uart_packet_t *packet, device_t *state) {
|
||||
border_size_t *border = &state->config.output[state->active_output].border;
|
||||
memcpy(border, packet->data, sizeof(border_size_t));
|
||||
|
||||
if (CURRENT_BOARD_IS_ACTIVE_OUTPUT) {
|
||||
get_border_position(state, border);
|
||||
send_packet((uint8_t *)border, SYNC_BORDERS_MSG, sizeof(border_size_t));
|
||||
}
|
||||
else
|
||||
memcpy(border, packet->data, sizeof(border_size_t));
|
||||
|
||||
save_config(state);
|
||||
}
|
||||
|
||||
@ -151,7 +163,7 @@ void handle_wipe_config_msg(uart_packet_t *packet, device_t *state) {
|
||||
}
|
||||
|
||||
void handle_screensaver_msg(uart_packet_t *packet, device_t *state) {
|
||||
state->config.screensaver[BOARD_ROLE].enabled = packet->data[0];
|
||||
state->config.output[BOARD_ROLE].screensaver.enabled = packet->data[0];
|
||||
}
|
||||
|
||||
/**==================================================== *
|
||||
|
@ -21,7 +21,6 @@
|
||||
#include "main.h"
|
||||
|
||||
#define IS_BLOCK_END (collection.start == collection.end)
|
||||
#define MAX_BUTTONS 16
|
||||
|
||||
enum { SIZE_0_BIT = 0, SIZE_8_BIT = 1, SIZE_16_BIT = 2, SIZE_32_BIT = 3 };
|
||||
|
||||
|
@ -88,11 +88,11 @@ typedef struct {
|
||||
uint8_t usage_count;
|
||||
uint8_t global_usage;
|
||||
uint32_t offset_in_bits;
|
||||
uint8_t usages[64];
|
||||
uint8_t usages[256];
|
||||
uint8_t *p_usage;
|
||||
|
||||
collection_t collection;
|
||||
usage_map_t *map;
|
||||
|
||||
globals_t globals[16]; /* as tag is 4 bits, there can be 16 different tags in global header type */
|
||||
} parser_state_t;
|
||||
} parser_state_t;
|
||||
|
@ -162,7 +162,6 @@ void send_key(hid_keyboard_report_t *report, device_t *state) {
|
||||
if (CURRENT_BOARD_IS_ACTIVE_OUTPUT) {
|
||||
queue_kbd_report(report, state);
|
||||
state->last_activity[BOARD_ROLE] = time_us_64();
|
||||
state->screensaver_max_time_reached[BOARD_ROLE] = false;
|
||||
} else {
|
||||
send_packet((uint8_t *)report, KEYBOARD_REPORT_MSG, KBD_REPORT_LENGTH);
|
||||
}
|
||||
|
70
src/main.h
70
src/main.h
@ -47,6 +47,9 @@
|
||||
#define ENABLE 1
|
||||
#define DISABLE 0
|
||||
|
||||
#define ABSOLUTE 0
|
||||
#define RELATIVE 1
|
||||
|
||||
#define MAX_REPORT_ITEMS 16
|
||||
#define MOUSE_BOOT_REPORT_LEN 4
|
||||
|
||||
@ -103,6 +106,9 @@ enum packet_type_e {
|
||||
FLASH_LED_MSG = 9,
|
||||
SCREENSAVER_MSG = 10,
|
||||
WIPE_CONFIG_MSG = 11,
|
||||
REL_MOUSE_REPORT_MSG = 12,
|
||||
SWAP_OUTPUTS_MSG = 13,
|
||||
HEARTBEAT_MSG = 14,
|
||||
};
|
||||
|
||||
/*
|
||||
@ -146,7 +152,25 @@ typedef struct {
|
||||
|
||||
/********* Configuration storage definitions **********/
|
||||
|
||||
#define CURRENT_CONFIG_VERSION 3
|
||||
#define CURRENT_CONFIG_VERSION 4
|
||||
|
||||
enum os_type_e {
|
||||
LINUX = 1,
|
||||
MACOS = 2,
|
||||
WINDOWS = 3,
|
||||
OTHER = 255,
|
||||
};
|
||||
|
||||
enum screen_pos_e {
|
||||
LEFT = 1,
|
||||
RIGHT = 2,
|
||||
MIDDLE = 3,
|
||||
};
|
||||
|
||||
enum itf_num_e {
|
||||
ITF_NUM_HID = 0,
|
||||
ITF_NUM_HID_REL_M = 1,
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
int top; // When jumping from a smaller to a bigger screen, go to THIS top height
|
||||
@ -154,16 +178,6 @@ typedef struct {
|
||||
// height
|
||||
} border_size_t;
|
||||
|
||||
/* Define output parameters */
|
||||
typedef struct {
|
||||
int number; // Number of this output (e.g. OUTPUT_A = 0 etc)
|
||||
int screen_count; // How many monitors per output (e.g. Output A is Windows with 3 monitors)
|
||||
int screen_index; // Current active screen
|
||||
int speed_x; // Mouse speed per output, in direction X
|
||||
int speed_y; // Mouse speed per output, in direction Y
|
||||
border_size_t border; // Screen border size/offset to keep cursor at same height when switching
|
||||
} output_t;
|
||||
|
||||
/* Define screensaver parameters */
|
||||
typedef struct {
|
||||
uint8_t enabled;
|
||||
@ -172,13 +186,26 @@ typedef struct {
|
||||
uint64_t max_time_us;
|
||||
} screensaver_t;
|
||||
|
||||
/* Define output parameters */
|
||||
typedef struct {
|
||||
int number; // Number of this output (e.g. OUTPUT_A = 0 etc)
|
||||
int screen_count; // How many monitors per output (e.g. Output A is Windows with 3 monitors)
|
||||
int screen_index; // Current active screen
|
||||
int speed_x; // Mouse speed per output, in direction X
|
||||
int speed_y; // Mouse speed per output, in direction Y
|
||||
border_size_t border; // Screen border size/offset to keep cursor at same height when switching
|
||||
enum os_type_e os; // Operating system on this output
|
||||
enum screen_pos_e pos; // Screen position on this output
|
||||
screensaver_t screensaver; // Screensaver parameters for this output
|
||||
} output_t;
|
||||
|
||||
/* Data structure defining how configuration is stored */
|
||||
typedef struct {
|
||||
uint32_t magic_header;
|
||||
uint32_t version;
|
||||
uint8_t force_mouse_boot_mode;
|
||||
output_t output[NUM_SCREENS];
|
||||
screensaver_t screensaver[NUM_SCREENS];
|
||||
uint8_t screensaver_enabled;
|
||||
// Keep checksum at the end of the struct
|
||||
uint32_t checksum;
|
||||
} config_t;
|
||||
@ -211,8 +238,8 @@ typedef struct TU_ATTR_PACKED {
|
||||
int16_t x;
|
||||
int16_t y;
|
||||
int8_t wheel;
|
||||
int8_t pan;
|
||||
} mouse_abs_report_t;
|
||||
uint8_t mode;
|
||||
} mouse_report_t;
|
||||
|
||||
typedef enum { IDLE, READING_PACKET, PROCESSING_PACKET } receiver_state_t;
|
||||
|
||||
@ -222,13 +249,13 @@ typedef struct {
|
||||
|
||||
uint8_t keyboard_leds[NUM_SCREENS]; // State of keyboard LEDs (index 0 = A, index 1 = B)
|
||||
uint64_t last_activity[NUM_SCREENS]; // Timestamp of the last input activity (-||-)
|
||||
bool screensaver_max_time_reached[NUM_SCREENS]; // Screensaver maximum time has been reached (will be reset at the next input activity)
|
||||
receiver_state_t receiver_state; // Storing the state for the simple receiver state machine
|
||||
uint64_t core1_last_loop_pass; // Timestamp of last core1 loop execution
|
||||
uint8_t active_output; // Currently selected output (0 = A, 1 = B)
|
||||
|
||||
int16_t mouse_x; // Store and update the location of our mouse pointer
|
||||
int16_t mouse_y;
|
||||
int16_t mouse_buttons; // Store and update the state of mouse buttons
|
||||
|
||||
config_t config; // Device configuration, loaded from flash or defaults used
|
||||
mouse_t mouse_dev; // Mouse device specifics, e.g. stores locations for keys in report
|
||||
@ -241,9 +268,9 @@ typedef struct {
|
||||
bool mouse_connected; // True when a mouse is connected locally
|
||||
|
||||
/* Feature flags */
|
||||
bool mouse_zoom; // True when "mouse zoom" is enabled
|
||||
bool switch_lock; // True when device is prevented from switching
|
||||
bool onboard_led_state; // True when LED is ON
|
||||
bool mouse_zoom; // True when "mouse zoom" is enabled
|
||||
bool switch_lock; // True when device is prevented from switching
|
||||
bool onboard_led_state; // True when LED is ON
|
||||
|
||||
/* Onboard LED blinky (provide feedback when e.g. mouse connected) */
|
||||
int32_t blinks_left; // How many blink transitions are left
|
||||
@ -265,16 +292,15 @@ void process_kbd_queue_task(device_t *);
|
||||
void send_key(hid_keyboard_report_t *, device_t *);
|
||||
|
||||
/********* Mouse **********/
|
||||
bool tud_hid_abs_mouse_report(
|
||||
uint8_t report_id, uint8_t buttons, int16_t x, int16_t y, int8_t vertical, int8_t horizontal);
|
||||
bool tud_mouse_report(uint8_t mode, uint8_t buttons, int16_t x, int16_t y, int8_t wheel);
|
||||
|
||||
void process_mouse_report(uint8_t *, int, device_t *);
|
||||
uint8_t
|
||||
parse_report_descriptor(mouse_t *mouse, uint8_t arr_count, uint8_t const *desc_report, uint16_t desc_len);
|
||||
int32_t get_report_value(uint8_t *report, report_val_t *val);
|
||||
void process_mouse_queue_task(device_t *);
|
||||
void queue_mouse_report(mouse_abs_report_t *, device_t *);
|
||||
void output_mouse_report(mouse_abs_report_t *, device_t *);
|
||||
void queue_mouse_report(mouse_report_t *, device_t *);
|
||||
void output_mouse_report(mouse_report_t *, device_t *);
|
||||
|
||||
/********* UART **********/
|
||||
void receive_char(uart_packet_t *, device_t *);
|
||||
|
103
src/mouse.c
103
src/mouse.c
@ -46,14 +46,16 @@ void update_mouse_position(device_t *state, mouse_values_t *values) {
|
||||
/* Update movement */
|
||||
state->mouse_x = move_and_keep_on_screen(state->mouse_x, offset_x);
|
||||
state->mouse_y = move_and_keep_on_screen(state->mouse_y, offset_y);
|
||||
|
||||
/* Update buttons state */
|
||||
state->mouse_buttons = values->buttons;
|
||||
}
|
||||
|
||||
/* If we are active output, queue packet to mouse queue, else send them through UART */
|
||||
void output_mouse_report(mouse_abs_report_t *report, device_t *state) {
|
||||
void output_mouse_report(mouse_report_t *report, device_t *state) {
|
||||
if (CURRENT_BOARD_IS_ACTIVE_OUTPUT) {
|
||||
queue_mouse_report(report, state);
|
||||
state->last_activity[BOARD_ROLE] = time_us_64();
|
||||
state->screensaver_max_time_reached[BOARD_ROLE] = false;
|
||||
} else {
|
||||
send_packet((uint8_t *)report, MOUSE_REPORT_MSG, MOUSE_REPORT_LENGTH);
|
||||
}
|
||||
@ -90,31 +92,81 @@ int16_t scale_y_coordinate(int screen_from, int screen_to, device_t *state) {
|
||||
return ((state->mouse_y - from->border.top) * MAX_SCREEN_COORD) / size_from;
|
||||
}
|
||||
|
||||
void switch_screen(device_t *state, int new_x, int output_from, int output_to) {
|
||||
mouse_abs_report_t hidden_pointer = {.y = MIN_SCREEN_COORD, .x = MAX_SCREEN_COORD};
|
||||
void switch_screen(device_t *state, output_t *output, int new_x, int output_from, int output_to, int direction) {
|
||||
mouse_report_t hidden_pointer = {.y = MIN_SCREEN_COORD, .x = MAX_SCREEN_COORD};
|
||||
|
||||
output_mouse_report(&hidden_pointer, state);
|
||||
switch_output(state, output_to);
|
||||
state->mouse_x = (output_to == OUTPUT_A) ? MIN_SCREEN_COORD : MAX_SCREEN_COORD;
|
||||
state->mouse_y = scale_y_coordinate(output_from, output_to, state);
|
||||
state->mouse_x = (direction == LEFT) ? MAX_SCREEN_COORD : MIN_SCREEN_COORD;
|
||||
state->mouse_y = scale_y_coordinate(output->number, 1 - output->number, state);
|
||||
}
|
||||
|
||||
void check_screen_switch(const mouse_values_t *values, device_t *state) {
|
||||
int new_x = state->mouse_x + values->move_x;
|
||||
void switch_desktop(device_t *state, output_t *output, int new_index, int direction) {
|
||||
switch (output->os) {
|
||||
case MACOS:
|
||||
/* Send relative mouse movement here as well, one or two pixels in the direction of
|
||||
movement, BEFORE absolute report sets X to 0 */
|
||||
mouse_report_t move_relative_one = {.x = (direction == LEFT) ? 16384-2 : 16384+2, .mode = RELATIVE};
|
||||
|
||||
/* No switching allowed if explicitly disabled */
|
||||
if (state->switch_lock)
|
||||
/* Once doesn't seem reliable enough, do it twice */
|
||||
output_mouse_report(&move_relative_one, state);
|
||||
output_mouse_report(&move_relative_one, state);
|
||||
|
||||
break;
|
||||
|
||||
case WINDOWS:
|
||||
/* TODO: Switch to relative-only if index > 1, but keep tabs to switch back */
|
||||
break;
|
||||
|
||||
case LINUX:
|
||||
case OTHER:
|
||||
/* Linux should treat all desktops as a single virtual screen, so you should leave
|
||||
screen_count at 1 and it should just work */
|
||||
break;
|
||||
}
|
||||
|
||||
state->mouse_x = (direction == RIGHT) ? MIN_SCREEN_COORD : MAX_SCREEN_COORD;
|
||||
output->screen_index = new_index;
|
||||
}
|
||||
|
||||
/* BORDER
|
||||
|
|
||||
.---------. .---------. | .---------. .---------. .---------.
|
||||
|| B2 || || B1 || | || A1 || || A2 || || A3 || (output, index)
|
||||
|| extra || || main || | || main || || extra || || extra || (main or extra)
|
||||
'---------' '---------' | '---------' '---------' '---------'
|
||||
)___( )___( | )___( )___( )___(
|
||||
*/
|
||||
void check_screen_switch(const mouse_values_t *values, device_t *state) {
|
||||
int new_x = state->mouse_x + values->move_x;
|
||||
output_t *output = &state->config.output[state->active_output];
|
||||
|
||||
bool jump_left = new_x < MIN_SCREEN_COORD - JUMP_THRESHOLD;
|
||||
bool jump_right = new_x > MAX_SCREEN_COORD + JUMP_THRESHOLD;
|
||||
|
||||
int direction = jump_left ? LEFT : RIGHT;
|
||||
|
||||
/* No switching allowed if explicitly disabled or mouse button is held */
|
||||
if (state->switch_lock || state->mouse_buttons)
|
||||
return;
|
||||
|
||||
/* End of screen left switches screen A->B TODO: make configurable */
|
||||
if (new_x < MIN_SCREEN_COORD - JUMP_THRESHOLD && state->active_output == OUTPUT_A) {
|
||||
switch_screen(state, new_x, OUTPUT_A, OUTPUT_B);
|
||||
/* No jump condition met == nothing to do, return */
|
||||
if (!jump_left && !jump_right)
|
||||
return;
|
||||
|
||||
/* We want to jump in the direction of the other computer */
|
||||
if (output->pos != direction) {
|
||||
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);
|
||||
|
||||
/* If here, this output has multiple desktops and we are not on the main one */
|
||||
else
|
||||
switch_desktop(state, output, output->screen_index - 1, direction);
|
||||
}
|
||||
|
||||
/* End of screen right switches screen B->A TODO: make configurable */
|
||||
else if (new_x > MAX_SCREEN_COORD + JUMP_THRESHOLD && state->active_output == OUTPUT_B) {
|
||||
switch_screen(state, new_x, OUTPUT_B, OUTPUT_A);
|
||||
}
|
||||
/* We want to jump away from the other computer, only possible if there is another screen to jump to */
|
||||
else if (output->screen_index < output->screen_count)
|
||||
switch_desktop(state, output, output->screen_index + 1, direction);
|
||||
}
|
||||
|
||||
void extract_report_values(uint8_t *raw_report, device_t *state, mouse_values_t *values) {
|
||||
@ -139,12 +191,13 @@ void extract_report_values(uint8_t *raw_report, device_t *state, mouse_values_t
|
||||
values->buttons = get_report_value(raw_report, &state->mouse_dev.buttons);
|
||||
}
|
||||
|
||||
mouse_abs_report_t create_mouse_report(device_t *state, mouse_values_t *values) {
|
||||
mouse_abs_report_t abs_mouse_report = {.buttons = values->buttons,
|
||||
mouse_report_t create_mouse_report(device_t *state, mouse_values_t *values) {
|
||||
mouse_report_t abs_mouse_report = {.buttons = values->buttons,
|
||||
.x = state->mouse_x,
|
||||
.y = state->mouse_y,
|
||||
.wheel = values->wheel,
|
||||
.pan = 0};
|
||||
.mode = ABSOLUTE,
|
||||
};
|
||||
return abs_mouse_report;
|
||||
}
|
||||
|
||||
@ -158,7 +211,7 @@ void process_mouse_report(uint8_t *raw_report, int len, device_t *state) {
|
||||
update_mouse_position(state, &values);
|
||||
|
||||
/* Create the report for the output PC based on the updated values */
|
||||
mouse_abs_report_t report = create_mouse_report(state, &values);
|
||||
mouse_report_t report = create_mouse_report(state, &values);
|
||||
|
||||
/* Move the mouse, depending where the output is supposed to go */
|
||||
output_mouse_report(&report, state);
|
||||
@ -172,7 +225,7 @@ void process_mouse_report(uint8_t *raw_report, int len, device_t *state) {
|
||||
* ==================================================== */
|
||||
|
||||
void process_mouse_queue_task(device_t *state) {
|
||||
mouse_abs_report_t report = {0};
|
||||
mouse_report_t report = {0};
|
||||
|
||||
/* We need to be connected to the host to send messages */
|
||||
if (!state->tud_connected)
|
||||
@ -187,15 +240,15 @@ void process_mouse_queue_task(device_t *state) {
|
||||
tud_remote_wakeup();
|
||||
|
||||
/* ... try sending it to the host, if it's successful */
|
||||
bool succeeded = tud_hid_abs_mouse_report(
|
||||
REPORT_ID_MOUSE, report.buttons, report.x, report.y, report.wheel, report.pan);
|
||||
bool succeeded = tud_mouse_report(
|
||||
report.mode, report.buttons, report.x, report.y, report.wheel);
|
||||
|
||||
/* ... then we can remove it from the queue */
|
||||
if (succeeded)
|
||||
queue_try_remove(&state->mouse_queue, &report);
|
||||
}
|
||||
|
||||
void queue_mouse_report(mouse_abs_report_t *report, device_t *state) {
|
||||
void queue_mouse_report(mouse_report_t *report, device_t *state) {
|
||||
/* It wouldn't be fun to queue up a bunch of messages and then dump them all on host */
|
||||
if (!state->tud_connected)
|
||||
return;
|
||||
|
12
src/setup.c
12
src/setup.c
@ -54,6 +54,12 @@ void pio_usb_host_config(void) {
|
||||
/* tuh_configure() must be called before tuh_init() */
|
||||
static pio_usb_configuration_t config = PIO_USB_DEFAULT_CONFIG;
|
||||
config.pin_dp = PIO_USB_DP_PIN_DEFAULT;
|
||||
|
||||
/* Make HID protocol the default for port B as a fix for devices enumerating
|
||||
themselves as both keyboards and mice, but having just a single common mode */
|
||||
if(BOARD_ROLE == OUTPUT_B)
|
||||
tuh_hid_set_default_protocol(HID_PROTOCOL_REPORT);
|
||||
|
||||
tuh_configure(BOARD_TUH_RHPORT, TUH_CFGID_RPI_PIO_USB_CONFIGURATION, &config);
|
||||
|
||||
/* Initialize and configure TinyUSB Host */
|
||||
@ -80,15 +86,15 @@ void initial_setup(device_t *state) {
|
||||
|
||||
/* Initialize keyboard and mouse queues */
|
||||
queue_init(&state->kbd_queue, sizeof(hid_keyboard_report_t), KBD_QUEUE_LENGTH);
|
||||
queue_init(&state->mouse_queue, sizeof(mouse_abs_report_t), MOUSE_QUEUE_LENGTH);
|
||||
queue_init(&state->mouse_queue, sizeof(mouse_report_t), MOUSE_QUEUE_LENGTH);
|
||||
|
||||
/* Setup RP2040 Core 1 */
|
||||
multicore_reset_core1();
|
||||
multicore_launch_core1(core1_main);
|
||||
|
||||
/* Initialize and configure TinyUSB Device */
|
||||
tud_init(BOARD_TUD_RHPORT);
|
||||
|
||||
tud_init(BOARD_TUD_RHPORT);
|
||||
|
||||
/* Initialize and configure TinyUSB Host */
|
||||
pio_usb_host_config();
|
||||
|
||||
|
@ -49,11 +49,6 @@ extern "C" {
|
||||
#define CFG_TUH_ENABLED 1
|
||||
#define CFG_TUH_RPI_PIO_USB 1
|
||||
|
||||
// defined by board.mk
|
||||
#ifndef CFG_TUSB_MCU
|
||||
#error CFG_TUSB_MCU must be defined
|
||||
#endif
|
||||
|
||||
// RHPort number used for device can be defined by board.mk, default to port 0
|
||||
#ifndef BOARD_DEVICE_RHPORT_NUM
|
||||
#define BOARD_DEVICE_RHPORT_NUM 0
|
||||
@ -62,22 +57,13 @@ extern "C" {
|
||||
// RHPort max operational speed can defined by board.mk
|
||||
// Default to Highspeed for MCU with internal HighSpeed PHY (can be port specific), otherwise FullSpeed
|
||||
#ifndef BOARD_DEVICE_RHPORT_SPEED
|
||||
#if (CFG_TUSB_MCU == OPT_MCU_LPC18XX || CFG_TUSB_MCU == OPT_MCU_LPC43XX \
|
||||
|| CFG_TUSB_MCU == OPT_MCU_MIMXRT10XX || CFG_TUSB_MCU == OPT_MCU_NUC505 \
|
||||
|| CFG_TUSB_MCU == OPT_MCU_CXD56 || CFG_TUSB_MCU == OPT_MCU_SAMX7X)
|
||||
#define BOARD_DEVICE_RHPORT_SPEED OPT_MODE_HIGH_SPEED
|
||||
#else
|
||||
#define BOARD_DEVICE_RHPORT_SPEED OPT_MODE_FULL_SPEED
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Device mode with rhport and speed defined by board.mk
|
||||
#define CFG_TUSB_RHPORT0_MODE (OPT_MODE_DEVICE | BOARD_DEVICE_RHPORT_SPEED)
|
||||
#define CFG_TUSB_RHPORT1_MODE (OPT_MODE_HOST | BOARD_DEVICE_RHPORT_SPEED)
|
||||
|
||||
// CFG_TUSB_DEBUG is defined by compiler in DEBUG build
|
||||
// #define CFG_TUSB_DEBUG 0
|
||||
|
||||
/* USB DMA on some MCUs can only access a specific SRAM region with restriction on alignment.
|
||||
* Tinyusb use follows macros to declare transferring memory so that they can be put
|
||||
* into those specific section.
|
||||
@ -101,9 +87,25 @@ extern "C" {
|
||||
#define CFG_TUD_ENDPOINT0_SIZE 64
|
||||
#endif
|
||||
|
||||
//------------- DEBUG -------------//
|
||||
#ifdef DH_DEBUG
|
||||
#define CFG_TUD_CDC 1
|
||||
#define CFG_TUSB_DEBUG 2
|
||||
#define CFG_TUD_LOG_LEVEL 3
|
||||
#define CFG_TUSB_DEBUG_PRINTF dh_debug_printf
|
||||
extern int dh_debug_printf(const char *__restrict __format, ...);
|
||||
|
||||
#define CFG_TUD_CDC_RX_BUFSIZE 64
|
||||
#define CFG_TUD_CDC_TX_BUFSIZE 64
|
||||
#define CFG_TUH_CDC_LINE_CODING_ON_ENUM \
|
||||
{ 921600, CDC_LINE_CONDING_STOP_BITS_1, CDC_LINE_CODING_PARITY_NONE, 8 }
|
||||
|
||||
#else
|
||||
#define CFG_TUD_CDC 0
|
||||
#endif
|
||||
|
||||
//------------- CLASS -------------//
|
||||
#define CFG_TUD_HID 1
|
||||
#define CFG_TUD_CDC 0
|
||||
#define CFG_TUD_HID 2
|
||||
#define CFG_TUD_MSC 0
|
||||
#define CFG_TUD_MIDI 0
|
||||
#define CFG_TUD_VENDOR 0
|
||||
@ -116,7 +118,7 @@ extern "C" {
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
// Size of buffer to hold descriptors and other data used for enumeration
|
||||
#define CFG_TUH_ENUMERATION_BUFSIZE 256
|
||||
#define CFG_TUH_ENUMERATION_BUFSIZE 512
|
||||
|
||||
#define CFG_TUH_HUB 1
|
||||
// max device support (excluding hub device)
|
||||
|
@ -114,7 +114,9 @@ void tuh_hid_mount_cb(uint8_t dev_addr, uint8_t instance, uint8_t const *desc_re
|
||||
at least we get all the information we need (looking at you, mouse wheel) */
|
||||
if (tuh_hid_get_protocol(dev_addr, instance) == HID_PROTOCOL_BOOT) {
|
||||
tuh_hid_set_protocol(dev_addr, instance, HID_PROTOCOL_REPORT);
|
||||
}
|
||||
}
|
||||
|
||||
global_state.mouse_dev.protocol = tuh_hid_get_protocol(dev_addr, instance);
|
||||
parse_report_descriptor(&global_state.mouse_dev, MAX_REPORTS, desc_report, desc_len);
|
||||
|
||||
global_state.mouse_connected = true;
|
||||
|
@ -59,132 +59,66 @@ uint8_t const *tud_descriptor_device_cb(void) {
|
||||
// HID Report Descriptor
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
// Relative mouse is used to overcome limitations of multiple desktops on MacOS and Windows
|
||||
|
||||
uint8_t const desc_hid_report[] = {TUD_HID_REPORT_DESC_KEYBOARD(HID_REPORT_ID(REPORT_ID_KEYBOARD)),
|
||||
TUD_HID_REPORT_DESC_ABSMOUSE(HID_REPORT_ID(REPORT_ID_MOUSE))};
|
||||
|
||||
uint8_t const desc_hid_report_relmouse[] = {TUD_HID_REPORT_DESC_MOUSE(HID_REPORT_ID(REPORT_ID_RELMOUSE))};
|
||||
|
||||
// Invoked when received GET HID REPORT DESCRIPTOR
|
||||
// Application return pointer to descriptor
|
||||
// Descriptor contents must exist long enough for transfer to complete
|
||||
uint8_t const *tud_hid_descriptor_report_cb(uint8_t instance) {
|
||||
(void)instance;
|
||||
if (instance == ITF_NUM_HID_REL_M) {
|
||||
return desc_hid_report_relmouse;
|
||||
}
|
||||
|
||||
/* Default */
|
||||
return desc_hid_report;
|
||||
}
|
||||
|
||||
bool tud_hid_n_abs_mouse_report(uint8_t instance,
|
||||
uint8_t report_id,
|
||||
uint8_t buttons,
|
||||
int16_t x,
|
||||
int16_t y,
|
||||
int8_t vertical,
|
||||
int8_t horizontal) {
|
||||
mouse_abs_report_t report = {.buttons = buttons, .x = x, .y = y, .wheel = vertical, .pan = horizontal};
|
||||
return tud_hid_n_report(instance, report_id, &report, sizeof(report));
|
||||
bool tud_mouse_report(uint8_t mode,
|
||||
uint8_t buttons,
|
||||
int16_t x,
|
||||
int16_t y,
|
||||
int8_t wheel) {
|
||||
|
||||
if (mode == ABSOLUTE) {
|
||||
mouse_report_t report = {.buttons = buttons, .x = x, .y = y, .wheel = wheel};
|
||||
return tud_hid_n_report(ITF_NUM_HID, REPORT_ID_MOUSE, &report, sizeof(report));
|
||||
}
|
||||
else {
|
||||
hid_mouse_report_t report = {.buttons = buttons, .x = x - 16384, .y = y - 16384, .wheel = wheel, .pan = 0};
|
||||
return tud_hid_n_report(ITF_NUM_HID_REL_M, REPORT_ID_RELMOUSE, &report, sizeof(report));
|
||||
}
|
||||
}
|
||||
|
||||
bool tud_hid_abs_mouse_report(
|
||||
uint8_t report_id, uint8_t buttons, int16_t x, int16_t y, int8_t vertical, int8_t horizontal) {
|
||||
return tud_hid_n_abs_mouse_report(0, report_id, buttons, x, y, vertical, horizontal);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Configuration Descriptor
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
enum { ITF_NUM_HID, ITF_NUM_TOTAL };
|
||||
|
||||
#define CONFIG_TOTAL_LEN (TUD_CONFIG_DESC_LEN + TUD_HID_DESC_LEN)
|
||||
|
||||
#define EPNUM_HID 0x81
|
||||
|
||||
uint8_t const desc_configuration[] = {
|
||||
// Config number, interface count, string index, total length, attribute, power in mA
|
||||
TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, 0, CONFIG_TOTAL_LEN, TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP, 500),
|
||||
|
||||
// Interface number, string index, protocol, report descriptor len, EP In address, size &
|
||||
// polling interval
|
||||
TUD_HID_DESCRIPTOR(ITF_NUM_HID,
|
||||
0,
|
||||
HID_ITF_PROTOCOL_NONE,
|
||||
sizeof(desc_hid_report),
|
||||
EPNUM_HID,
|
||||
CFG_TUD_HID_EP_BUFSIZE,
|
||||
1)};
|
||||
|
||||
#if TUD_OPT_HIGH_SPEED
|
||||
// Per USB specs: high speed capable device must report device_qualifier and
|
||||
// other_speed_configuration
|
||||
|
||||
// other speed configuration
|
||||
uint8_t desc_other_speed_config[CONFIG_TOTAL_LEN];
|
||||
|
||||
// device qualifier is mostly similar to device descriptor since we don't change configuration based
|
||||
// on speed
|
||||
tusb_desc_device_qualifier_t const desc_device_qualifier = {.bLength = sizeof(tusb_desc_device_qualifier_t),
|
||||
.bDescriptorType = TUSB_DESC_DEVICE_QUALIFIER,
|
||||
.bcdUSB = USB_BCD,
|
||||
|
||||
.bDeviceClass = 0x00,
|
||||
.bDeviceSubClass = 0x00,
|
||||
.bDeviceProtocol = 0x00,
|
||||
|
||||
.bMaxPacketSize0 = CFG_TUD_ENDPOINT0_SIZE,
|
||||
.bNumConfigurations = 0x01,
|
||||
.bReserved = 0x00};
|
||||
|
||||
// Invoked when received GET DEVICE QUALIFIER DESCRIPTOR request
|
||||
// Application return pointer to descriptor, whose contents must exist long enough for transfer to
|
||||
// complete. device_qualifier descriptor describes information about a high-speed capable device
|
||||
// that would change if the device were operating at the other speed. If not highspeed capable stall
|
||||
// this request.
|
||||
uint8_t const *tud_descriptor_device_qualifier_cb(void) {
|
||||
return (uint8_t const *)&desc_device_qualifier;
|
||||
}
|
||||
|
||||
// Invoked when received GET OTHER SEED CONFIGURATION DESCRIPTOR request
|
||||
// Application return pointer to descriptor, whose contents must exist long enough for transfer to
|
||||
// complete Configuration descriptor in the other speed e.g if high speed then this is for full
|
||||
// speed and vice versa
|
||||
uint8_t const *tud_descriptor_other_speed_configuration_cb(uint8_t index) {
|
||||
(void)index; // for multiple configurations
|
||||
|
||||
// other speed config is basically configuration with type = OHER_SPEED_CONFIG
|
||||
memcpy(desc_other_speed_config, desc_configuration, CONFIG_TOTAL_LEN);
|
||||
desc_other_speed_config[1] = TUSB_DESC_OTHER_SPEED_CONFIG;
|
||||
|
||||
// this example use the same configuration for both high and full speed mode
|
||||
return desc_other_speed_config;
|
||||
}
|
||||
|
||||
#endif // highspeed
|
||||
|
||||
// Invoked when received GET CONFIGURATION DESCRIPTOR
|
||||
// Application return pointer to descriptor
|
||||
// Descriptor contents must exist long enough for transfer to complete
|
||||
uint8_t const *tud_descriptor_configuration_cb(uint8_t index) {
|
||||
(void)index; // for multiple configurations
|
||||
|
||||
// This example use the same configuration for both high and full speed mode
|
||||
return desc_configuration;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// String Descriptors
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
// String Descriptor Index
|
||||
enum {
|
||||
STRID_LANGID = 0,
|
||||
STRID_MANUFACTURER,
|
||||
STRID_PRODUCT,
|
||||
STRID_SERIAL,
|
||||
};
|
||||
|
||||
// array of pointer to string descriptors
|
||||
char const *string_desc_arr[] = {
|
||||
(const char[]){0x09, 0x04}, // 0: is supported language is English (0x0409)
|
||||
"Hrvoje Cavrak", // 1: Manufacturer
|
||||
"DeskHop Switch", // 2: Product
|
||||
"0", // 3: Serials, should use chip ID
|
||||
"MouseHelper", // 4: Relative mouse to work around OS issues
|
||||
#ifdef DH_DEBUG
|
||||
"Debug Interface", // 5: Debug Interface
|
||||
#endif
|
||||
};
|
||||
|
||||
// String Descriptor Index
|
||||
enum {
|
||||
STRID_LANGID = 0,
|
||||
STRID_MANUFACTURER,
|
||||
STRID_PRODUCT,
|
||||
STRID_SERIAL,
|
||||
STRID_MOUSE,
|
||||
STRID_DEBUG,
|
||||
};
|
||||
|
||||
static uint16_t _desc_str[32];
|
||||
@ -225,3 +159,60 @@ uint16_t const *tud_descriptor_string_cb(uint8_t index, uint16_t langid) {
|
||||
|
||||
return _desc_str;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Configuration Descriptor
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
#define EPNUM_HID 0x81
|
||||
#define EPNUM_HID_REL_M 0x82
|
||||
|
||||
#ifndef DH_DEBUG
|
||||
|
||||
enum { ITF_NUM_TOTAL = 2 };
|
||||
#define CONFIG_TOTAL_LEN (TUD_CONFIG_DESC_LEN + TUD_HID_DESC_LEN + TUD_HID_DESC_LEN)
|
||||
|
||||
#else
|
||||
|
||||
enum { ITF_NUM_CDC = 2, ITF_NUM_TOTAL = 3 };
|
||||
#define CONFIG_TOTAL_LEN (TUD_CONFIG_DESC_LEN + TUD_HID_DESC_LEN + TUD_HID_DESC_LEN + TUD_CDC_DESC_LEN)
|
||||
#define EPNUM_CDC_NOTIF 0x83
|
||||
#define EPNUM_CDC_OUT 0x04
|
||||
#define EPNUM_CDC_IN 0x84
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
uint8_t const desc_configuration[] = {
|
||||
// Config number, interface count, string index, total length, attribute, power in mA
|
||||
TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, 0, CONFIG_TOTAL_LEN, TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP, 500),
|
||||
|
||||
// Interface number, string index, protocol, report descriptor len, EP In address, size & polling interval
|
||||
TUD_HID_DESCRIPTOR(ITF_NUM_HID,
|
||||
STRID_PRODUCT,
|
||||
HID_ITF_PROTOCOL_NONE,
|
||||
sizeof(desc_hid_report),
|
||||
EPNUM_HID,
|
||||
CFG_TUD_HID_EP_BUFSIZE,
|
||||
1),
|
||||
|
||||
TUD_HID_DESCRIPTOR(ITF_NUM_HID_REL_M,
|
||||
STRID_MOUSE,
|
||||
HID_ITF_PROTOCOL_NONE,
|
||||
sizeof(desc_hid_report_relmouse),
|
||||
EPNUM_HID_REL_M,
|
||||
CFG_TUD_HID_EP_BUFSIZE,
|
||||
20),
|
||||
|
||||
#ifdef DH_DEBUG
|
||||
// Interface number, string index, EP notification address and size, EP data address (out, in) and size.
|
||||
TUD_CDC_DESCRIPTOR(
|
||||
ITF_NUM_CDC, STRID_DEBUG, EPNUM_CDC_NOTIF, 8, EPNUM_CDC_OUT, EPNUM_CDC_IN, CFG_TUD_CDC_EP_BUFSIZE),
|
||||
#endif
|
||||
|
||||
};
|
||||
|
||||
uint8_t const *tud_descriptor_configuration_cb(uint8_t index) {
|
||||
(void)index; // for multiple configurations
|
||||
return desc_configuration;
|
||||
}
|
||||
|
@ -29,10 +29,14 @@ enum
|
||||
{
|
||||
REPORT_ID_KEYBOARD = 1,
|
||||
REPORT_ID_MOUSE,
|
||||
REPORT_ID_CONSUMER_CONTROL,
|
||||
REPORT_ID_COUNT
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
REPORT_ID_RELMOUSE = 1,
|
||||
};
|
||||
|
||||
#define TUD_HID_REPORT_DESC_ABSMOUSE(...) \
|
||||
HID_USAGE_PAGE ( HID_USAGE_PAGE_DESKTOP ) ,\
|
||||
HID_USAGE ( HID_USAGE_DESKTOP_MOUSE ) ,\
|
||||
@ -74,92 +78,12 @@ HID_COLLECTION ( HID_COLLECTION_APPLICATION ) ,\
|
||||
HID_REPORT_COUNT( 1 ) ,\
|
||||
HID_REPORT_SIZE ( 8 ) ,\
|
||||
HID_INPUT ( HID_DATA | HID_VARIABLE | HID_RELATIVE ) ,\
|
||||
HID_USAGE_PAGE ( HID_USAGE_PAGE_CONSUMER ), \
|
||||
\
|
||||
/* Horizontal wheel scroll [-127, 127] */ \
|
||||
HID_USAGE_N ( HID_USAGE_CONSUMER_AC_PAN, 2 ), \
|
||||
HID_LOGICAL_MIN ( 0x81 ), \
|
||||
HID_LOGICAL_MAX ( 0x7f ), \
|
||||
/* Mouse mode (0 = absolute, 1 = relative) */ \
|
||||
HID_REPORT_COUNT( 1 ), \
|
||||
HID_REPORT_SIZE ( 8 ), \
|
||||
HID_INPUT ( HID_DATA | HID_VARIABLE | HID_RELATIVE ), \
|
||||
HID_INPUT ( HID_CONSTANT ), \
|
||||
HID_COLLECTION_END , \
|
||||
HID_COLLECTION_END \
|
||||
|
||||
/* Generated report */
|
||||
/* */
|
||||
/* 0x05, 0x01, Usage Page (Desktop), */
|
||||
/* 0x09, 0x06, Usage (Keyboard), */
|
||||
/* 0xA1, 0x01, Collection (Application), */
|
||||
/* 0x85, 0x01, Report ID (1), */
|
||||
/* 0x05, 0x07, Usage Page (Keyboard), */
|
||||
/* 0x19, 0xE0, Usage Minimum (KB Leftcontrol), */
|
||||
/* 0x29, 0xE7, Usage Maximum (KB Right GUI), */
|
||||
/* 0x15, 0x00, Logical Minimum (0), */
|
||||
/* 0x25, 0x01, Logical Maximum (1), */
|
||||
/* 0x95, 0x08, Report Count (8), */
|
||||
/* 0x75, 0x01, Report Size (1), */
|
||||
/* 0x81, 0x02, Input (Variable), */
|
||||
/* 0x95, 0x01, Report Count (1), */
|
||||
/* 0x75, 0x08, Report Size (8), */
|
||||
/* 0x81, 0x01, Input (Constant), */
|
||||
/* 0x05, 0x08, Usage Page (LED), */
|
||||
/* 0x19, 0x01, Usage Minimum (01h), */
|
||||
/* 0x29, 0x05, Usage Maximum (05h), */
|
||||
/* 0x95, 0x05, Report Count (5), */
|
||||
/* 0x75, 0x01, Report Size (1), */
|
||||
/* 0x91, 0x02, Output (Variable), */
|
||||
/* 0x95, 0x01, Report Count (1), */
|
||||
/* 0x75, 0x03, Report Size (3), */
|
||||
/* 0x91, 0x01, Output (Constant), */
|
||||
/* 0x05, 0x07, Usage Page (Keyboard), */
|
||||
/* 0x19, 0x00, Usage Minimum (None), */
|
||||
/* 0x2A, 0xFF, 0x00, Usage Maximum (FFh), */
|
||||
/* 0x15, 0x00, Logical Minimum (0), */
|
||||
/* 0x26, 0xFF, 0x00, Logical Maximum (255), */
|
||||
/* 0x95, 0x06, Report Count (6), */
|
||||
/* 0x75, 0x08, Report Size (8), */
|
||||
/* 0x81, 0x00, Input, */
|
||||
/* 0xC0, End Collection, */
|
||||
/* 0x05, 0x01, Usage Page (Desktop), */
|
||||
/* 0x09, 0x02, Usage (Mouse), */
|
||||
/* 0xA1, 0x01, Collection (Application), */
|
||||
/* 0x85, 0x02, Report ID (2), */
|
||||
/* 0x09, 0x01, Usage (Pointer), */
|
||||
/* 0xA1, 0x00, Collection (Physical), */
|
||||
/* 0x05, 0x09, Usage Page (Button), */
|
||||
/* 0x19, 0x01, Usage Minimum (01h), */
|
||||
/* 0x29, 0x05, Usage Maximum (05h), */
|
||||
/* 0x15, 0x00, Logical Minimum (0), */
|
||||
/* 0x25, 0x01, Logical Maximum (1), */
|
||||
/* 0x95, 0x05, Report Count (5), */
|
||||
/* 0x75, 0x01, Report Size (1), */
|
||||
/* 0x81, 0x02, Input (Variable), */
|
||||
/* 0x95, 0x01, Report Count (1), */
|
||||
/* 0x75, 0x03, Report Size (3), */
|
||||
/* 0x81, 0x01, Input (Constant), */
|
||||
/* 0x05, 0x01, Usage Page (Desktop), */
|
||||
/* 0x09, 0x30, Usage (X), */
|
||||
/* 0x09, 0x31, Usage (Y), */
|
||||
/* 0x15, 0x00, Logical Minimum (0), */
|
||||
/* 0x26, 0xFF, 0x7F, Logical Maximum (32767), */
|
||||
/* 0x75, 0x10, Report Size (16), */
|
||||
/* 0x95, 0x02, Report Count (2), */
|
||||
/* 0x81, 0x02, Input (Variable), */
|
||||
/* 0x09, 0x38, Usage (Wheel), */
|
||||
/* 0x15, 0x81, Logical Minimum (-127), */
|
||||
/* 0x25, 0x7F, Logical Maximum (127), */
|
||||
/* 0x95, 0x01, Report Count (1), */
|
||||
/* 0x75, 0x08, Report Size (8), */
|
||||
/* 0x81, 0x06, Input (Variable, Relative), */
|
||||
/* 0x05, 0x0C, Usage Page (Consumer), */
|
||||
/* 0x0A, 0x38, 0x02, Usage (AC Pan), */
|
||||
/* 0x15, 0x81, Logical Minimum (-127), */
|
||||
/* 0x25, 0x7F, Logical Maximum (127), */
|
||||
/* 0x95, 0x01, Report Count (1), */
|
||||
/* 0x75, 0x08, Report Size (8), */
|
||||
/* 0x81, 0x06, Input (Variable, Relative), */
|
||||
/* 0xC0, End Collection, */
|
||||
/* 0xC0 End Collection */
|
||||
|
||||
#endif /* USB_DESCRIPTORS_H_ */
|
||||
|
@ -29,6 +29,7 @@
|
||||
* a key that is unlikely to ever appear on a keyboard that you will use.
|
||||
* HID_KEY_F24 is probably a good choice as keyboards with 24 function keys
|
||||
* are rare.
|
||||
*
|
||||
* */
|
||||
|
||||
#define HOTKEY_TOGGLE HID_KEY_CAPS_LOCK
|
||||
@ -54,13 +55,12 @@
|
||||
#define MOUSE_SPEED_A_FACTOR_X 16
|
||||
#define MOUSE_SPEED_A_FACTOR_Y 16
|
||||
|
||||
/* Output B values */
|
||||
/* Output B values */
|
||||
#define MOUSE_SPEED_B_FACTOR_X 16
|
||||
#define MOUSE_SPEED_B_FACTOR_Y 16
|
||||
|
||||
#define JUMP_THRESHOLD 0
|
||||
|
||||
|
||||
/**================================================== *
|
||||
* ============== Screensaver Config ============== *
|
||||
* ================================================== *
|
||||
@ -104,8 +104,8 @@
|
||||
*
|
||||
**/
|
||||
|
||||
#define SCREENSAVER_A_ENABLED 1
|
||||
#define SCREENSAVER_B_ENABLED 0
|
||||
#define SCREENSAVER_A_ENABLED 0
|
||||
#define SCREENSAVER_B_ENABLED 0
|
||||
|
||||
/**================================================== *
|
||||
*
|
||||
@ -114,19 +114,18 @@
|
||||
*
|
||||
**/
|
||||
|
||||
#define SCREENSAVER_A_IDLE_TIME_SEC 60
|
||||
#define SCREENSAVER_A_IDLE_TIME_SEC 240
|
||||
#define SCREENSAVER_B_IDLE_TIME_SEC 240
|
||||
|
||||
/**================================================== *
|
||||
*
|
||||
* SCREENSAVER_{A|B}_MAX_TIME_SEC: Number of seconds that an output
|
||||
* can be inactive before the screensaver mode will be deactivated. If
|
||||
* zero, the screensaver will run indefinitely.
|
||||
* SCREENSAVER_{A|B}_MAX_TIME_SEC: Number of seconds that the screensaver
|
||||
* will run on an output before being deactivated. 0 for indefinitely.
|
||||
*
|
||||
**/
|
||||
|
||||
#define SCREENSAVER_A_MAX_TIME_SEC 120
|
||||
#define SCREENSAVER_B_MAX_TIME_SEC 0
|
||||
#define SCREENSAVER_A_MAX_TIME_SEC 0
|
||||
#define SCREENSAVER_B_MAX_TIME_SEC 0
|
||||
|
||||
/**================================================== *
|
||||
*
|
||||
@ -135,5 +134,22 @@
|
||||
*
|
||||
**/
|
||||
|
||||
#define SCREENSAVER_A_ONLY_IF_INACTIVE 1
|
||||
#define SCREENSAVER_B_ONLY_IF_INACTIVE 1
|
||||
#define SCREENSAVER_A_ONLY_IF_INACTIVE 0
|
||||
#define SCREENSAVER_B_ONLY_IF_INACTIVE 0
|
||||
|
||||
/**================================================== *
|
||||
* ================ Output OS Config =============== *
|
||||
* ==================================================
|
||||
*
|
||||
* Defines OS an output connects to. You will need to worry about this only if you have
|
||||
* multiple desktops and one of your outputs is MacOS or Windows.
|
||||
*
|
||||
* Available options: LINUX, MACOS, WINDOWS, OTHER (check main.h for details)
|
||||
*
|
||||
* OUTPUT_A_OS: OS for output A
|
||||
* OUTPUT_B_OS: OS for output B
|
||||
*
|
||||
* */
|
||||
|
||||
#define OUTPUT_A_OS LINUX
|
||||
#define OUTPUT_B_OS LINUX
|
||||
|
77
src/utils.c
77
src/utils.c
@ -104,56 +104,37 @@ void save_config(device_t *state) {
|
||||
restore_interrupts(ints);
|
||||
}
|
||||
|
||||
/* Have something fun and entertaining when idle */
|
||||
/* Have something fun and entertaining when idle. */
|
||||
void screensaver_task(device_t *state) {
|
||||
const int mouse_move_delay = 5000;
|
||||
const int mouse_move_delay = 5000;
|
||||
screensaver_t *screensaver = &state->config.output[BOARD_ROLE].screensaver;
|
||||
|
||||
static mouse_abs_report_t report = {.x = 0, .y = 0};
|
||||
static int last_pointer_move = 0;
|
||||
static mouse_report_t report = {.x = 0, .y = 0};
|
||||
static int last_pointer_move = 0;
|
||||
|
||||
uint64_t current_time = time_us_64();
|
||||
static uint64_t last_activation_time = 0;
|
||||
uint64_t current_time = time_us_64();
|
||||
uint64_t inactivity_period = current_time - state->last_activity[BOARD_ROLE];
|
||||
|
||||
/* "Randomly" chosen initial values */
|
||||
static int dx = 20;
|
||||
static int dy = 25;
|
||||
|
||||
/* If the maximum time has been reached, nothing to do here. */
|
||||
if (state->screensaver_max_time_reached[BOARD_ROLE]) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* If we're not enabled, nothing to do here. */
|
||||
if (!state->config.screensaver[BOARD_ROLE].enabled) {
|
||||
last_activation_time = 0;
|
||||
return;
|
||||
}
|
||||
if (!screensaver->enabled)
|
||||
return;
|
||||
|
||||
/* System is still not idle for long enough to activate or we've been running for too long */
|
||||
if (inactivity_period < screensaver->idle_time_us)
|
||||
return;
|
||||
|
||||
/* We exceeded the maximum permitted screensaver runtime */
|
||||
if (screensaver->max_time_us
|
||||
&& inactivity_period > (screensaver->max_time_us + screensaver->idle_time_us))
|
||||
return;
|
||||
|
||||
/* If we're not the selected output and that is required, nothing to do here. */
|
||||
if (state->config.screensaver[BOARD_ROLE].only_if_inactive &&
|
||||
CURRENT_BOARD_IS_ACTIVE_OUTPUT) {
|
||||
last_activation_time = 0;
|
||||
if (screensaver->only_if_inactive && CURRENT_BOARD_IS_ACTIVE_OUTPUT)
|
||||
return;
|
||||
}
|
||||
|
||||
/* We are enabled, but idle time still too small to activate. */
|
||||
if ((current_time - state->last_activity[BOARD_ROLE]) <
|
||||
state->config.screensaver[BOARD_ROLE].idle_time_us) {
|
||||
last_activation_time = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
if (last_activation_time == 0) {
|
||||
last_activation_time = current_time;
|
||||
} else {
|
||||
/* We are enabled, but max time has been reached. */
|
||||
if ((current_time - last_activation_time) >
|
||||
state->config.screensaver[BOARD_ROLE].max_time_us) {
|
||||
state->screensaver_max_time_reached[BOARD_ROLE] = true;
|
||||
last_activation_time = 0;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* We're active! Now check if it's time to move the cursor yet. */
|
||||
if ((time_us_32()) - last_pointer_move < mouse_move_delay)
|
||||
@ -175,3 +156,23 @@ void screensaver_task(device_t *state) {
|
||||
/* Update timer of the last pointer move */
|
||||
last_pointer_move = time_us_32();
|
||||
}
|
||||
|
||||
/* ================================================== *
|
||||
* Debug functions
|
||||
* ================================================== */
|
||||
#ifdef DH_DEBUG
|
||||
|
||||
int dh_debug_printf(const char *format, ...) {
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
char buffer[512];
|
||||
|
||||
int string_len = vsnprintf(buffer, 512, format, args);
|
||||
|
||||
tud_cdc_n_write(0, buffer, string_len);
|
||||
tud_cdc_write_flush();
|
||||
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue
Block a user