Compare commits
10 Commits
4a3ca5c83a
...
d78bcd4638
Author | SHA1 | Date |
---|---|---|
|
d78bcd4638 | |
|
fa4ccdfeae | |
|
85089fee11 | |
|
cbb98e4a88 | |
|
99399030f2 | |
|
ff70bdafb5 | |
|
92baf1a2f2 | |
|
79fd4068b6 | |
|
d345b11da5 | |
|
7c0fa3e20a |
|
@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 3.6)
|
||||||
|
|
||||||
## Version Configuration
|
## Version Configuration
|
||||||
set(VERSION_MAJOR 00)
|
set(VERSION_MAJOR 00)
|
||||||
set(VERSION_MINOR 161)
|
set(VERSION_MINOR 162)
|
||||||
|
|
||||||
## Release Type Selection
|
## Release Type Selection
|
||||||
option(DH_DEBUG "Build a debug version" OFF)
|
option(DH_DEBUG "Build a debug version" OFF)
|
||||||
|
|
|
@ -10,7 +10,7 @@ All I wanted was a way to use a keyboard shortcut to quickly switch outputs, pai
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
|
|
||||||
- Completely **free and open source**
|
- Completely **[free and open source](https://certification.oshwa.org/de000149.html)**
|
||||||
- No noticeable delay when switching
|
- No noticeable delay when switching
|
||||||
- Simply drag the mouse pointer between computers
|
- Simply drag the mouse pointer between computers
|
||||||
- No software installed
|
- No software installed
|
||||||
|
@ -19,9 +19,9 @@ All I wanted was a way to use a keyboard shortcut to quickly switch outputs, pai
|
||||||
- Full Galvanic isolation between your outputs
|
- Full Galvanic isolation between your outputs
|
||||||
- Works with Linux, macOS and Windows
|
- Works with Linux, macOS and Windows
|
||||||
|
|
||||||
{width=240}
|
[User Manual](user-manual.pdf) is now available
|
||||||
[Proudly certified](https://certification.oshwa.org/de000149.html) by the Open Source Hardware Association (oshwa.org)
|
|
||||||
|
|
||||||
|

|
||||||
------
|
------
|
||||||
|
|
||||||
## How it works
|
## How it works
|
||||||
|
@ -53,9 +53,6 @@ It also remembers the LED state for each computer, so you can pick up exactly ho
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
## User Manual
|
|
||||||
To help you set up, configure and program the board available [read the manual provided here](user-manual.pdf).
|
|
||||||
|
|
||||||
## How to build
|
## How to build
|
||||||
|
|
||||||
To avoid version mismatch and reported path issues when building, as well as to save you from having to download a large SDK, the project now bundles minimal pico sdk and tinyusb.
|
To avoid version mismatch and reported path issues when building, as well as to save you from having to download a large SDK, the project now bundles minimal pico sdk and tinyusb.
|
||||||
|
|
42
img/oshw.svg
42
img/oshw.svg
File diff suppressed because one or more lines are too long
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 10 KiB |
|
@ -39,7 +39,7 @@ void _get_border_position(device_t *state, border_size_t *border) {
|
||||||
border->top = state->pointer_y;
|
border->top = state->pointer_y;
|
||||||
}
|
}
|
||||||
|
|
||||||
void _screensaver_set(device_t *state, bool value) {
|
void _screensaver_set(device_t *state, uint8_t value) {
|
||||||
if (CURRENT_BOARD_IS_ACTIVE_OUTPUT)
|
if (CURRENT_BOARD_IS_ACTIVE_OUTPUT)
|
||||||
state->config.output[BOARD_ROLE].screensaver.mode = value;
|
state->config.output[BOARD_ROLE].screensaver.mode = value;
|
||||||
else
|
else
|
||||||
|
@ -123,12 +123,18 @@ void mouse_zoom_hotkey_handler(device_t *state, hid_keyboard_report_t *report) {
|
||||||
|
|
||||||
/* When pressed, enables the screensaver on active output */
|
/* When pressed, enables the screensaver on active output */
|
||||||
void enable_screensaver_hotkey_handler(device_t *state, hid_keyboard_report_t *report) {
|
void enable_screensaver_hotkey_handler(device_t *state, hid_keyboard_report_t *report) {
|
||||||
_screensaver_set(state, true);
|
uint8_t desired_mode = state->config.output[BOARD_ROLE].screensaver.mode;
|
||||||
|
|
||||||
|
/* If the user explicitly asks for screensaver to be active, ignore config and turn it on */
|
||||||
|
if (desired_mode == DISABLED)
|
||||||
|
desired_mode = PONG;
|
||||||
|
|
||||||
|
_screensaver_set(state, desired_mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* When pressed, disables the screensaver on active output */
|
/* When pressed, disables the screensaver on active output */
|
||||||
void disable_screensaver_hotkey_handler(device_t *state, hid_keyboard_report_t *report) {
|
void disable_screensaver_hotkey_handler(device_t *state, hid_keyboard_report_t *report) {
|
||||||
_screensaver_set(state, false);
|
_screensaver_set(state, DISABLED);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Put the device into a special configuration mode */
|
/* Put the device into a special configuration mode */
|
||||||
|
|
|
@ -206,9 +206,10 @@ enum screen_pos_e {
|
||||||
};
|
};
|
||||||
|
|
||||||
enum screensaver_mode_e {
|
enum screensaver_mode_e {
|
||||||
DISABLED = 0,
|
DISABLED = 0,
|
||||||
PONG = 1,
|
PONG = 1,
|
||||||
JITTER = 2,
|
JITTER = 2,
|
||||||
|
MAX_SS_VAL = JITTER,
|
||||||
};
|
};
|
||||||
|
|
||||||
#define ITF_NUM_HID 0
|
#define ITF_NUM_HID 0
|
||||||
|
|
|
@ -66,7 +66,7 @@
|
||||||
HID_COLLECTION ( HID_COLLECTION_PHYSICAL ) ,\
|
HID_COLLECTION ( HID_COLLECTION_PHYSICAL ) ,\
|
||||||
HID_USAGE_PAGE ( HID_USAGE_PAGE_BUTTON ) ,\
|
HID_USAGE_PAGE ( HID_USAGE_PAGE_BUTTON ) ,\
|
||||||
HID_USAGE_MIN ( 1 ) ,\
|
HID_USAGE_MIN ( 1 ) ,\
|
||||||
HID_USAGE_MAX ( 5 ) ,\
|
HID_USAGE_MAX ( 8 ) ,\
|
||||||
HID_LOGICAL_MIN ( 0 ) ,\
|
HID_LOGICAL_MIN ( 0 ) ,\
|
||||||
HID_LOGICAL_MAX ( 1 ) ,\
|
HID_LOGICAL_MAX ( 1 ) ,\
|
||||||
\
|
\
|
||||||
|
|
23
src/mouse.c
23
src/mouse.c
|
@ -17,6 +17,9 @@
|
||||||
|
|
||||||
#include "main.h"
|
#include "main.h"
|
||||||
|
|
||||||
|
#define MACOS_SWITCH_MOVE_X 10
|
||||||
|
#define MACOS_SWITCH_MOVE_COUNT 5
|
||||||
|
|
||||||
/* Move mouse coordinate 'position' by 'offset', but don't fall off the screen */
|
/* Move mouse coordinate 'position' by 'offset', but don't fall off the screen */
|
||||||
int32_t move_and_keep_on_screen(int position, int offset) {
|
int32_t move_and_keep_on_screen(int position, int offset) {
|
||||||
/* Lowest we can go is 0 */
|
/* Lowest we can go is 0 */
|
||||||
|
@ -122,7 +125,7 @@ int16_t scale_y_coordinate(int screen_from, int screen_to, device_t *state) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void switch_screen(
|
void switch_screen(
|
||||||
device_t *state, output_t *output, int new_x, int output_from, int output_to, int direction) {
|
device_t *state, output_t *output, int output_to, int direction) {
|
||||||
uint8_t *mouse_park_pos = &state->config.output[state->active_output].mouse_park_pos;
|
uint8_t *mouse_park_pos = &state->config.output[state->active_output].mouse_park_pos;
|
||||||
|
|
||||||
int16_t mouse_y = (*mouse_park_pos == 0) ? MIN_SCREEN_COORD : /* Top */
|
int16_t mouse_y = (*mouse_park_pos == 0) ? MIN_SCREEN_COORD : /* Top */
|
||||||
|
@ -137,17 +140,21 @@ void switch_screen(
|
||||||
state->pointer_y = scale_y_coordinate(output->number, 1 - output->number, state);
|
state->pointer_y = scale_y_coordinate(output->number, 1 - output->number, state);
|
||||||
}
|
}
|
||||||
|
|
||||||
void switch_desktop(device_t *state, output_t *output, int new_index, int direction) {
|
void switch_desktop_macos(device_t *state, int direction) {
|
||||||
/* 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
|
uint16_t move = (direction == LEFT) ? -MACOS_SWITCH_MOVE_X : MACOS_SWITCH_MOVE_X;
|
||||||
= {.x = (direction == LEFT) ? -5 : 5, .mode = RELATIVE};
|
mouse_report_t move_relative_one = {.x = move, .mode = RELATIVE};
|
||||||
|
|
||||||
|
/* Once doesn't seem reliable enough, do it a few times */
|
||||||
|
for (int i = 0; i < MACOS_SWITCH_MOVE_COUNT; i++)
|
||||||
|
output_mouse_report(&move_relative_one, state);
|
||||||
|
}
|
||||||
|
|
||||||
|
void switch_desktop(device_t *state, output_t *output, int new_index, int direction) {
|
||||||
switch (output->os) {
|
switch (output->os) {
|
||||||
case MACOS:
|
case MACOS:
|
||||||
/* Once doesn't seem reliable enough, do it a few times */
|
switch_desktop_macos(state, direction);
|
||||||
for (int i = 0; i < 5; i++)
|
|
||||||
output_mouse_report(&move_relative_one, state);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case WINDOWS:
|
case WINDOWS:
|
||||||
|
@ -199,7 +206,7 @@ void check_screen_switch(const mouse_values_t *values, device_t *state) {
|
||||||
if (state->mouse_buttons)
|
if (state->mouse_buttons)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
switch_screen(state, output, new_x, state->active_output, 1 - state->active_output, direction);
|
switch_screen(state, 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
|
||||||
|
|
66
src/tasks.c
66
src/tasks.c
|
@ -59,22 +59,51 @@ void usb_host_task(device_t *state) {
|
||||||
tuh_task();
|
tuh_task();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mouse_report_t *screensaver_pong(device_t *state) {
|
||||||
|
static mouse_report_t report = {0};
|
||||||
|
static int dx = 20, dy = 25;
|
||||||
|
|
||||||
|
/* Check if we are bouncing off the walls and reverse direction in that case. */
|
||||||
|
if (report.x + dx < MIN_SCREEN_COORD || report.x + dx > MAX_SCREEN_COORD)
|
||||||
|
dx = -dx;
|
||||||
|
|
||||||
|
if (report.y + dy < MIN_SCREEN_COORD || report.y + dy > MAX_SCREEN_COORD)
|
||||||
|
dy = -dy;
|
||||||
|
|
||||||
|
report.x += dx;
|
||||||
|
report.y += dy;
|
||||||
|
|
||||||
|
return &report;
|
||||||
|
}
|
||||||
|
|
||||||
|
mouse_report_t *screensaver_jitter(device_t *state) {
|
||||||
|
const int16_t jitter_distance = 2;
|
||||||
|
static mouse_report_t report = {
|
||||||
|
.y = jitter_distance,
|
||||||
|
.mode = RELATIVE,
|
||||||
|
};
|
||||||
|
report.y = -report.y;
|
||||||
|
|
||||||
|
return &report;
|
||||||
|
}
|
||||||
|
|
||||||
/* Have something fun and entertaining when idle. */
|
/* Have something fun and entertaining when idle. */
|
||||||
void screensaver_task(device_t *state) {
|
void screensaver_task(device_t *state) {
|
||||||
const int mouse_move_delay = 5000;
|
const uint32_t delays[] = {
|
||||||
|
0, /* DISABLED, unused index 0 */
|
||||||
|
5000, /* PONG, move mouse every 5 ms for a high framerate */
|
||||||
|
10000000, /* JITTER, once every 10 sec is more than enough */
|
||||||
|
};
|
||||||
|
static int last_pointer_move = 0;
|
||||||
screensaver_t *screensaver = &state->config.output[BOARD_ROLE].screensaver;
|
screensaver_t *screensaver = &state->config.output[BOARD_ROLE].screensaver;
|
||||||
uint64_t inactivity_period = time_us_64() - state->last_activity[BOARD_ROLE];
|
uint64_t inactivity_period = time_us_64() - state->last_activity[BOARD_ROLE];
|
||||||
|
|
||||||
static mouse_report_t report = {0};
|
|
||||||
static int last_pointer_move = 0;
|
|
||||||
static int dx = 20, dy = 25, jitter = 1;
|
|
||||||
|
|
||||||
/* If we're not enabled, nothing to do here. */
|
/* If we're not enabled, nothing to do here. */
|
||||||
if (screensaver->mode == DISABLED)
|
if (screensaver->mode == DISABLED)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/* System is still not idle for long enough to activate or we've been running for too long */
|
/* System is still not idle for long enough to activate or screensaver mode is not supported */
|
||||||
if (inactivity_period < screensaver->idle_time_us)
|
if (inactivity_period < screensaver->idle_time_us || screensaver->mode > MAX_SS_VAL)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/* We exceeded the maximum permitted screensaver runtime */
|
/* We exceeded the maximum permitted screensaver runtime */
|
||||||
|
@ -87,32 +116,25 @@ void screensaver_task(device_t *state) {
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/* We're active! Now check if it's time to move the cursor yet. */
|
/* We're active! Now check if it's time to move the cursor yet. */
|
||||||
if ((time_us_32()) - last_pointer_move < mouse_move_delay)
|
if (time_us_32() - last_pointer_move < delays[screensaver->mode])
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
mouse_report_t *report;
|
||||||
switch (screensaver->mode) {
|
switch (screensaver->mode) {
|
||||||
case PONG:
|
case PONG:
|
||||||
/* Check if we are bouncing off the walls and reverse direction in that case. */
|
report = screensaver_pong(state);
|
||||||
if (report.x + dx < MIN_SCREEN_COORD || report.x + dx > MAX_SCREEN_COORD)
|
|
||||||
dx = -dx;
|
|
||||||
|
|
||||||
if (report.y + dy < MIN_SCREEN_COORD || report.y + dy > MAX_SCREEN_COORD)
|
|
||||||
dy = -dy;
|
|
||||||
|
|
||||||
report.x += dx;
|
|
||||||
report.y += dy;
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case JITTER:
|
case JITTER:
|
||||||
report.x = state->pointer_x + jitter;
|
report = screensaver_jitter(state);
|
||||||
report.y = state->pointer_y + jitter;
|
|
||||||
jitter = -jitter;
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Move mouse pointer */
|
/* Move mouse pointer */
|
||||||
queue_mouse_report(&report, state);
|
queue_mouse_report(report, state);
|
||||||
|
|
||||||
/* Update timer of the last pointer move */
|
/* Update timer of the last pointer move */
|
||||||
last_pointer_move = time_us_32();
|
last_pointer_move = time_us_32();
|
||||||
|
|
Loading…
Reference in New Issue