Compare commits

...

6 Commits

Author SHA1 Message Date
c6f47a0981 CMakeLists.txt: improve searching for hidapi
All checks were successful
Alpine 3.21 Success
Debian-based distributions don't include the CMake module.
2025-08-02 18:55:44 +02:00
c8f3b9ba38 eizoctl: fix compatibility with newer MinGW-w64
All checks were successful
Alpine 3.21 Success
2025-08-02 17:47:40 +02:00
d8b01cdaee eizoctl: add an option to filter by serial number
All checks were successful
Alpine 3.21 Success
It turns out that this is actually critical when switching inputs
in certain wild setups.
2025-07-31 21:16:16 +02:00
135f336a7c eizoctl: add an option to list monitors 2025-07-31 21:15:26 +02:00
b4c1817c10 Update README.adoc
All checks were successful
Alpine 3.20 Success
2025-01-22 13:36:34 +01:00
32ea934947 Update README.adoc
All checks were successful
Alpine 3.20 Success
2025-01-22 13:25:39 +01:00
3 changed files with 95 additions and 14 deletions

View File

@@ -41,13 +41,16 @@ pkg_check_modules (libusb libusb-1.0)
# On MSYS2, the CMake package cannot link statically, but pkg-config can.
# On macOS, we explicitly want to use the CMake package.
if (WIN32)
pkg_search_module (hidapi hidapi hidapi-hidraw hidapi-libusb)
else ()
find_package (hidapi)
if (NOT WIN32)
find_package (hidapi QUIET)
if (hidapi_FOUND)
set (hidapi_INCLUDE_DIRS)
set (hidapi_LIBRARY_DIRS)
set (hidapi_LIBRARIES hidapi::hidapi)
endif ()
endif ()
if (NOT hidapi_FOUND)
pkg_search_module (hidapi hidapi hidapi-hidraw hidapi-libusb)
endif ()
option (WITH_LIBUSB "Compile with libusb-based utilities" ${libusb_FOUND})

View File

@@ -1,6 +1,7 @@
USB drivers
===========
:compact-option:
:source-highlighter: chroma
_usb-drivers_ is a collection of utilities to control various hardware over USB.
@@ -26,6 +27,60 @@ it will also suspend or power off the system, respectively.
image:eizoctltray-win.png["eizoctltray on Windows with expanded menu", 343, 278]
image:eizoctltray-mac.png["eizoctltray on macOS with expanded menu", 343, 278]
Installation
^^^^^^^^^^^^
On Windows, copy it to
__Users\*\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup__.
On macOS, copy it to the _Applications_ folder,
then add it in _System Settings → General → Login Items → Open at Login_.
Automation
^^^^^^^^^^
_eizoctltray_ can also be used the same way as _eizoctl_, just with any output
redirected to message windows, rather than a console window or a terminal.
This is useful for automation, such as with AutoHotkey.
Beware that Windows is not a fan of how rapidly EIZO monitors switch upstream
USB ports. Thus, if you invoke port switching with keyboard shortcuts,
remember to add a small delay, so that pressed modifier keys are not remembered.
You will also want to silence any error messages.
.AutoHotkey example
```autohotkey
#Requires AutoHotkey v2.0
exe := A_Startup . "\eizoctltray.exe"
^#F1:: { ; Windows + Control + F1
Sleep 500
Run exe " -qq --input HDMI"
}
^#F2:: { ; Windows + Control + F2
Sleep 500
Run exe " -qq --input DP"
}
^#F3:: { ; Windows + Control + F3
Sleep 500
Run exe " -qq --input USB-C"
}
#Home:: { ; Windows + Home
Run exe " -q --brightness +0.1"
}
#End:: { ; Windows + End
Run exe " -q --brightness -0.1"
}
```
On macOS, the simplest way to bind keyboard shortcuts is the Shortcuts app,
with _Run Shell Scripts_ actions:
```
/Applications/eizoctltray.app/Contents/MacOS/eizoctltray -q --input HDMI
```
If you have issues with entering a specific key combination, like I did
with ^⌘F1 etc., try changing it later within _System Settings_ → _Keyboard_ →
_Keyboard Shortcuts..._ → _Services_ → _Shortcuts_.
elksmart-comm
~~~~~~~~~~~~~
_elksmart-comm_ interfaces with ELK Smart infrared dongles EKX4S and EKX5S-T,
@@ -53,7 +108,7 @@ Regular releases are sporadic. git master should be stable enough.
You can get a package with the latest development version
as a https://git.janouch.name/p/nixexprs[Nix derivation].
Windows binaries can be downloaded from
Windows/macOS binaries can be downloaded from
https://git.janouch.name/p/usb-drivers/releases[the Releases page on Gitea].
Building

View File

@@ -1037,6 +1037,10 @@ eizo_watch(struct eizo_monitor *m, print_fn output, print_fn error)
}
static const char *usage = "Usage: %s OPTION...\n\n"
" -l, --list\n"
" List all connected EIZO monitors, with their serial number.\n"
" -s, --serial SERIAL\n"
" Only act on the monitor matching the specified serial number.\n"
" -b, --brightness [+-]BRIGHTNESS\n"
" Change monitor brightness; values go from 0 to 1 and may be relative.\n"
" -i, --input NAME\n"
@@ -1057,6 +1061,8 @@ run(int argc, char *argv[], print_fn output, print_fn error)
{
const char *name = argv[0];
static struct option opts[] = {
{"list", no_argument, NULL, 'l'},
{"serial", required_argument, NULL, 's'},
{"brightness", required_argument, NULL, 'b'},
{"input", required_argument, NULL, 'i'},
{"restart", no_argument, NULL, 'r'},
@@ -1069,11 +1075,17 @@ run(int argc, char *argv[], print_fn output, print_fn error)
int quiet = 0;
double brightness = NAN;
bool relative = false, restart = false, events = false;
const char *port = NULL;
bool list = false, relative = false, restart = false, events = false;
const char *serial = NULL, *port = NULL;
int c = 0;
while ((c = getopt_long(argc, argv, "b:i:reqhV", opts, NULL)) != -1)
while ((c = getopt_long(argc, argv, "ls:b:i:reqhV", opts, NULL)) != -1)
switch (c) {
case 'l':
list = true;
break;
case 's':
serial = optarg;
break;
case 'b':
relative = *optarg == '+' || *optarg == '-';
if (sscanf(optarg, "%lf", &brightness) && isfinite(brightness))
@@ -1123,8 +1135,6 @@ run(int argc, char *argv[], print_fn output, print_fn error)
if (quiet > 1)
error = print_dummy;
// It should be possible to choose a particular monitor,
// but it is generally more useful to operate on all of them.
struct hid_device_info *devs = hid_enumerate(USB_VID_EIZO, 0), *p = devs;
for (; p; p = p->next) {
struct eizo_monitor m = {};
@@ -1133,6 +1143,15 @@ run(int argc, char *argv[], print_fn output, print_fn error)
continue;
}
if (list)
output("%s %s\n", m.product, m.serial);
// Generously assuming that different products/models
// don't share serial numbers,
// which would otherwise deserve another filtering option.
if (serial && strcmp(serial, m.serial))
goto next;
if (isfinite(brightness)) {
double prev = 0.;
if (!eizo_get_brightness(&m, &prev)) {
@@ -1177,6 +1196,7 @@ run(int argc, char *argv[], print_fn output, print_fn error)
error("%s\n", m.error);
}
next:
eizo_monitor_close(&m);
}
hid_free_enumeration(devs);
@@ -1231,10 +1251,13 @@ message_printf(const char *format, va_list ap)
return NULL;
mbstowcs(format_wide, format, format_wide_len);
int message_len = vswprintf(NULL, 0, format_wide, ap) + 1;
// Note that just vswprintf() cannot be used like this
// (at least since mingw-w64 commit c85d64),
// and vsnwprintf() is a MinGW extension, acting like C11 vsnwprintf_s.
int message_len = vsnwprintf(NULL, 0, format_wide, ap) + 1;
wchar_t *message = calloc(message_len, sizeof *message);
if (message_len > 0 && message)
vswprintf(message, message_len, format_wide, ap);
vsnwprintf(message, message_len, format_wide, ap);
free(format_wide);
return message;