Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

macOS: Add support for Bluetooth devices #2730

Merged
merged 4 commits into from
Jan 1, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions Release_Notes.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# Notes on Major Changes in Releases

## Version 1.1.15

* Solaar supports configuration of Bluetooth devices on macOS.

## Version 1.1.13

* Solaar will drop support for Python 3.7 immediately after version 1.1.13.
Expand Down
30 changes: 14 additions & 16 deletions lib/hidapi/hidapi_impl.py
Original file line number Diff line number Diff line change
Expand Up @@ -181,15 +181,8 @@ def _enumerate_devices():
p = p.contents.next
_hidapi.hid_free_enumeration(c_devices)

keyboard_or_mouse = {d["path"] for d in devices if d["usage_page"] == 1 and d["usage"] in (6, 2)}
unique_devices = {}
for device in devices:
# On macOS we cannot access keyboard or mouse devices without special permissions. Since
# we don't need them anyway we remove them so opening them doesn't cause errors later.
if device["path"] in keyboard_or_mouse:
# print(f"Ignoring keyboard or mouse device: {device}")
continue

# hidapi returns separate entries for each usage page of a device.
# Deduplicate by path to only keep one device entry.
if device["path"] not in unique_devices:
Expand Down Expand Up @@ -255,15 +248,20 @@ def _match(
device_handle = None
try:
device_handle = open_path(device["path"])
report = _get_input_report(device_handle, 0x10, 32)
if len(report) == 1 + 6 and report[0] == 0x10:
device["hidpp_short"] = True
report = _get_input_report(device_handle, 0x11, 32)
if len(report) == 1 + 19 and report[0] == 0x11:
device["hidpp_long"] = True
except HIDError as e: # noqa: F841
if logger.isEnabledFor(logging.INFO):
logger.info(f"Error opening device {device['path']} ({bus_id}/{vid:04X}/{pid:04X}) for hidpp check: {e}") # noqa
try:
report = _get_input_report(device_handle, 0x10, 32)
if len(report) == 1 + 6 and report[0] == 0x10:
device["hidpp_short"] = True
except HIDError as e:
if logger.isEnabledFor(logging.INFO):
logger.info(f"Error opening device {device['path']} ({bus_id}/{vid:04X}/{pid:04X}) for hidpp check: {e}")
try:
report = _get_input_report(device_handle, 0x11, 32)
if len(report) == 1 + 19 and report[0] == 0x11:
device["hidpp_long"] = True
except HIDError as e:
if logger.isEnabledFor(logging.INFO):
logger.info(f"Error opening device {device['path']} ({bus_id}/{vid:04X}/{pid:04X}) for hidpp check: {e}")
finally:
if device_handle:
close(device_handle)
Expand Down
2 changes: 1 addition & 1 deletion lib/logitech_receiver/diversion.py
Original file line number Diff line number Diff line change
Expand Up @@ -366,7 +366,7 @@ def simulate_uinput(what, code, arg):
def simulate_key(code, event): # X11 keycode but Solaar event code
if not wayland and simulate_xtest(code, event):
return True
if simulate_uinput(evdev.ecodes.EV_KEY, code - 8, event):
if evdev and simulate_uinput(evdev.ecodes.EV_KEY, code - 8, event):
return True
logger.warning("no way to simulate key input")

Expand Down
4 changes: 2 additions & 2 deletions lib/solaar/cli/show.py
Original file line number Diff line number Diff line change
Expand Up @@ -151,8 +151,8 @@ def _print_device(dev, num=None):
if isinstance(feature, str):
feature_bytes = bytes.fromhex(feature[-4:])
else:
feature_bytes = feature.to_bytes(2, byteorder="big")
feature_int = int.from_bytes(feature_bytes, byteorder="big")
feature_bytes = feature.to_bytes(2, byteorder="little")
feature_int = int.from_bytes(feature_bytes, byteorder="little")
flags = dev.request(0x0000, feature_bytes)
flags = 0 if flags is None else ord(flags[1:2])
flags = common.flag_names(hidpp20_constants.FeatureFlag, flags)
Expand Down
3 changes: 2 additions & 1 deletion lib/solaar/gtk.py
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,8 @@ def main():

udev_file = "42-logitech-unify-permissions.rules"
if (
logger.isEnabledFor(logging.WARNING)
platform.system() == "Linux"
and logger.isEnabledFor(logging.WARNING)
and not os.path.isfile("/etc/udev/rules.d/" + udev_file)
and not os.path.isfile("/usr/lib/udev/rules.d/" + udev_file)
and not os.path.isfile("/usr/local/lib/udev/rules.d/" + udev_file)
Expand Down
Loading