Compare commits
222 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3bc3da967c | ||
|
|
b50ffef327 | ||
|
|
ec223eb2e6 | ||
|
|
573d3d399e | ||
|
|
0f5beb619e | ||
|
|
89aff23c11 | ||
|
|
fd27957b57 | ||
|
|
554ee88c86 | ||
|
|
868d71a08b | ||
|
|
9b3c33a2fe | ||
|
|
109cc69da9 | ||
|
|
113bd4859e | ||
|
|
2a2b7487d4 | ||
|
|
2b4022dcbf | ||
|
|
7555cf1607 | ||
|
|
9c75a7cc7e | ||
|
|
0337ae41ab | ||
|
|
ff39e67615 | ||
|
|
7ba5563eeb | ||
|
|
968b9383d3 | ||
|
|
be6c381751 | ||
|
|
27a0db37d8 | ||
|
|
5858816b53 | ||
|
|
a1376180b4 | ||
|
|
75d1400206 | ||
|
|
78475a6d15 | ||
|
|
63f93111fb | ||
|
|
1ea21ed6ce | ||
|
|
18a8fb9651 | ||
|
|
2e836a40d3 | ||
|
|
c09872e589 | ||
|
|
575b7bce98 | ||
|
|
3e04abde30 | ||
|
|
790c5e90bd | ||
|
|
85a358e07c | ||
|
|
3af0544421 | ||
|
|
f69b4d53f6 | ||
|
|
cb4be02a56 | ||
|
|
bacdab2596 | ||
|
|
ec7bb2f63a | ||
|
|
74a5551a8d | ||
|
|
3e0c803a37 | ||
|
|
55682c3a5d | ||
|
|
ae9e287b8d | ||
|
|
03c264cec1 | ||
|
|
410e01de61 | ||
|
|
d167dfd83b | ||
|
|
9b7d8f5f24 | ||
|
|
366fbc3fda | ||
|
|
f1d20f1f35 | ||
|
|
558f59b52c | ||
|
|
1a3ef63519 | ||
|
|
17380baae9 | ||
|
|
314c3e2f78 | ||
|
|
6ba5cc3319 | ||
|
|
1148d172b5 | ||
|
|
a930cdad87 | ||
|
|
b951d83a64 | ||
|
|
f56df6b1d0 | ||
|
|
1e35b2ace6 | ||
|
|
e75c20a249 | ||
|
|
c63ffdd3ef | ||
|
|
40658c6d0e | ||
|
|
251efd3b40 | ||
|
|
94320099b0 | ||
|
|
f592cabcd7 | ||
|
|
a58096fade | ||
|
|
b140bc2827 | ||
|
|
aeaa69b9e1 | ||
|
|
a535897ae7 | ||
|
|
1074a2b2e6 | ||
|
|
51c1be3806 | ||
|
|
b9e647ccb8 | ||
|
|
e063aa3d2a | ||
|
|
9a74e30c64 | ||
|
|
f26de4bb29 | ||
|
|
e9008eeaba | ||
|
|
d5dc8eccd6 | ||
|
|
13736d0ced | ||
|
|
a926afe8de | ||
|
|
af78dc4ec2 | ||
|
|
1c85d77d56 | ||
|
|
c8929b50fa | ||
|
|
e58e79cb8d | ||
|
|
049e12b2eb | ||
|
|
5c71f9552d | ||
|
|
c3be9e1af1 | ||
|
|
186d626c40 | ||
|
|
dfc433cb74 | ||
|
|
ab2dae47af | ||
|
|
ec442b960d | ||
|
|
670720b40f | ||
|
|
0787e35964 | ||
|
|
9f4df9582c | ||
|
|
d282590746 | ||
|
|
9e5047976b | ||
|
|
d69a2ec5ba | ||
|
|
4bfd5d9a13 | ||
|
|
091e651831 | ||
|
|
d52c2c0320 | ||
|
|
cd71ce67b1 | ||
|
|
43f501907e | ||
|
|
d26d5b83f1 | ||
|
|
c401414310 | ||
|
|
c34fe85780 | ||
|
|
a19a79d33a | ||
|
|
8edf6e7609 | ||
|
|
835a694c4b | ||
|
|
a47492e62c | ||
|
|
186a1deda8 | ||
|
|
132212652f | ||
|
|
5a40d93a30 | ||
|
|
f62940c1e5 | ||
|
|
0f808ed387 | ||
|
|
d8edf2d9e4 | ||
|
|
6827f5ed81 | ||
|
|
f3208b499b | ||
|
|
94e0842a06 | ||
|
|
e0de98ba01 | ||
|
|
1adb147f6d | ||
|
|
b1c4bba3b2 | ||
|
|
cdbdcd23e6 | ||
|
|
23d1290b22 | ||
|
|
5edcdfba5b | ||
|
|
6d105a002c | ||
|
|
3b1a41f154 | ||
|
|
0153efbf9c | ||
|
|
db34ab5255 | ||
|
|
52e10d029f | ||
|
|
1c94ef5c56 | ||
|
|
5efd83fc41 | ||
|
|
33966989db | ||
|
|
c56c76e07d | ||
|
|
8440a36f92 | ||
|
|
3e31b45db0 | ||
|
|
548a40dba6 | ||
|
|
c437882e96 | ||
|
|
4a61dc413b | ||
|
|
59df7defdb | ||
|
|
77fa6a1e65 | ||
|
|
0f8031c201 | ||
|
|
5842dccc2a | ||
|
|
0c5b1998a5 | ||
|
|
f52ebd0dba | ||
|
|
1857378a76 | ||
|
|
d2600583bb | ||
|
|
e2a4684f83 | ||
|
|
ed39cf3dee | ||
|
|
c4d3b1e606 | ||
|
|
be1fb30751 | ||
|
|
a2b3c32124 | ||
|
|
26e7237010 | ||
|
|
26a6215122 | ||
|
|
376adfdf2a | ||
|
|
d990e3f027 | ||
|
|
2473f66cb3 | ||
|
|
8e9bf7b48a | ||
|
|
7edae05b37 | ||
|
|
909749fc00 | ||
|
|
15b4b4a3ca | ||
|
|
cad05f1256 | ||
|
|
703e1f6f0d | ||
|
|
19451f9df7 | ||
|
|
3314b41202 | ||
|
|
f636fd8f53 | ||
|
|
77847f570c | ||
|
|
afaf3fa83d | ||
|
|
4c7f644599 | ||
|
|
692f7f008a | ||
|
|
0a62c3dfa8 | ||
|
|
7cd2cfed44 | ||
|
|
c31e11d385 | ||
|
|
efe6021e76 | ||
|
|
8d67389042 | ||
|
|
4037587f74 | ||
|
|
94daeb1444 | ||
|
|
937b30c415 | ||
|
|
6f0242f05b | ||
|
|
921837fd0f | ||
|
|
d06cdcc53c | ||
|
|
5828355426 | ||
|
|
50dc321b7b | ||
|
|
43f033db80 | ||
|
|
623c53f1e4 | ||
|
|
39762718b9 | ||
|
|
ae3804f7b4 | ||
|
|
0dd08dfb84 | ||
|
|
bb23f68d53 | ||
|
|
83345a17d2 | ||
|
|
b9f6554767 | ||
|
|
7eadd20879 | ||
|
|
3844a60837 | ||
|
|
6cdf8a901a | ||
|
|
c868c43179 | ||
|
|
01ca2a6de7 | ||
|
|
d64af72f74 | ||
|
|
c2fe745813 | ||
|
|
ddefbf95a3 | ||
|
|
a2b651985e | ||
|
|
788c261ce9 | ||
|
|
35070cc17e | ||
|
|
79be057e91 | ||
|
|
aa8f506dd0 | ||
|
|
c6486b1960 | ||
|
|
2f8e3a1610 | ||
|
|
432d32bedc | ||
|
|
8cb2d21ff5 | ||
|
|
1103c208a8 | ||
|
|
7e59f0f974 | ||
|
|
c647d6df99 | ||
|
|
97a927bb7d | ||
|
|
7c650aeeca | ||
|
|
3fd7cd0137 | ||
|
|
7e97936f0e | ||
|
|
643a4a89f4 | ||
|
|
cfd93cf332 | ||
|
|
340e5b7d86 | ||
|
|
be624fe943 | ||
|
|
cb102e115c | ||
|
|
952eb1cf0e | ||
|
|
709ffa37b2 | ||
|
|
f4f206f3e5 |
303
DBusInterface.md
@@ -1,303 +0,0 @@
|
||||
The ratbagd DBus-Interface
|
||||
--------------------------
|
||||
|
||||
Note: **the DBus interface is subject to change**
|
||||
|
||||
Interfaces:
|
||||
- org.freedesktop.ratbag1.Manager
|
||||
- org.freedesktop.ratbag1.Device
|
||||
- org.freedesktop.ratbag1.Profile
|
||||
- org.freedesktop.ratbag1.Resolution
|
||||
- org.freedesktop.ratbag1.Button
|
||||
- org.freedesktop.ratbag1.Led
|
||||
|
||||
For a list of dbus types as used below, see https://dbus.freedesktop.org/doc/dbus-specification.html
|
||||
|
||||
Properties marked as 'constant' do not change for the lifetime of the
|
||||
object. Properties marked as 'mutable' may change, and a
|
||||
`org.freedesktop.DBus.Properties.PropertyChanged` signal is sent for those
|
||||
unless otherwise specified.
|
||||
|
||||
org.freedesktop.ratbag1.Manager
|
||||
===============================
|
||||
|
||||
The **org.freedesktop.ratbag1.Manager** interface is the entry point to
|
||||
interact with ratbagd.
|
||||
|
||||
### Properties:
|
||||
|
||||
#### `Devices`
|
||||
- type `ao`, read-only, mutable
|
||||
|
||||
Provides the object paths of all current devices, see **org.freedesktop.ratbag1.Device**
|
||||
|
||||
#### `Themes`
|
||||
- type `as`, read-only, constant
|
||||
|
||||
Provides the list of available theme names. This list is guaranteed to have
|
||||
one theme available ('default'). Other themes are implementation defined.
|
||||
A theme listed here is only a guarantee that the theme is known to libratbag
|
||||
and that SVGs *may* exist, it is not a guarantee that the SVG for any
|
||||
specific device exists. In other words, a device may not have an SVG for a
|
||||
specific theme.
|
||||
|
||||
This list is static for the lifetime of ratbagd.
|
||||
|
||||
org.freedesktop.ratbag1.Device
|
||||
==============================
|
||||
|
||||
The **org.freedesktop.ratbag1.Device** interface describes a single device
|
||||
known to ratbagd.
|
||||
|
||||
### Properties:
|
||||
|
||||
#### `Id`
|
||||
- type: `s`, read-only, constant
|
||||
|
||||
An ID describing this device. This ID should not be used for presentation to
|
||||
the user.
|
||||
|
||||
#### `Description`
|
||||
- type: `s`, read-only, constant
|
||||
|
||||
The device's name, suitable for presentation to the user.
|
||||
|
||||
#### `Capabilities`
|
||||
- type: `au`, read-only, constant
|
||||
|
||||
The capabilities supported by this device. see `enum
|
||||
ratbag_device_capability` in libratbag.h for the list of permissible
|
||||
capabilities.
|
||||
|
||||
|
||||
#### `Svg`
|
||||
- type: `s`, read-only, constant
|
||||
|
||||
The device's SVG file name, without path.
|
||||
|
||||
#### `Profiles`
|
||||
- type: `ao`, read-only, mutable
|
||||
|
||||
This property is mutable if the device supports adding and removing
|
||||
profiles.
|
||||
|
||||
Provides the list of profile paths for all profiles on this device, see
|
||||
**org.freedesktop.ratbag1.Profile**.
|
||||
|
||||
### Methods:
|
||||
|
||||
#### `Commit() → ()`
|
||||
|
||||
Commits the changes to the device. Changes to the device are batched; they
|
||||
are not written to the hardware until `Commit()` is invoked.
|
||||
|
||||
#### `GetSvg(s) → (s)`
|
||||
|
||||
Returns the full path to the SVG for the given theme or an empty string if
|
||||
none is available. The theme must be one of
|
||||
**org.freedesktop.ratbag1.Manager.Themes**. The theme 'default' is
|
||||
guaranteed to be available. ratbagd may return the path to a file that
|
||||
doesn't exist. This is the case if the device has SVGs available but not for
|
||||
the given theme.
|
||||
|
||||
org.freedesktop.ratbag1.Profile
|
||||
===============================
|
||||
|
||||
### Properties:
|
||||
|
||||
#### `Index`
|
||||
- type: `u`, read-only, constant
|
||||
|
||||
The index of this profile
|
||||
|
||||
#### `Enabled`
|
||||
- type: `b`, read-write, mutable
|
||||
|
||||
True if this is the profile is enabled, false otherwise.
|
||||
|
||||
Note that a disabled profile might not have correct bindings, so it's
|
||||
a good thing to rebind everything before calling `Commit()` on the
|
||||
**org.freedesktop.ratbag1.Device**.
|
||||
|
||||
#### `Resolutions`
|
||||
- type: `ao`, read-only, mutable
|
||||
|
||||
This property is mutable if the device supports adding and removing
|
||||
resolutions.
|
||||
|
||||
Provides the object paths of all resolutions in this profile, see
|
||||
**org.freedesktop.ratbag1.Resolution**
|
||||
|
||||
#### `Buttons`
|
||||
- type: `ao`, read-only, constant
|
||||
|
||||
Provides the object paths of all buttons in this profile, see
|
||||
**org.freedesktop.ratbag1.Button**
|
||||
|
||||
#### `Leds`
|
||||
- type: `ao`, read-only, constant
|
||||
|
||||
Provides the object paths of all LEDs in this profile, see
|
||||
**org.freedesktop.ratbag1.Led**
|
||||
|
||||
### `IsActive`
|
||||
- type: `b`, read-only, mutable
|
||||
|
||||
True if this is the currently active profile, false otherwise.
|
||||
|
||||
Profiles can only be set to active, but never to not active - at least one
|
||||
profile must be active at all times. This property is read-only, use the
|
||||
`SetActive()` method to activate a profile.
|
||||
|
||||
### Methods:
|
||||
|
||||
#### `SetActive() → ()`
|
||||
Set this profile to be the active profile
|
||||
|
||||
org.freedesktop.ratbag1.Resolution
|
||||
==================================
|
||||
|
||||
### Properties:
|
||||
#### `Index`
|
||||
- type: `u`, read-only, constant
|
||||
|
||||
Index of the resolution
|
||||
#### `Capabilities`
|
||||
- type: `au`, read-only, constant
|
||||
|
||||
Array of uints with the capabilities enum from libratbag
|
||||
|
||||
#### `IsActive`
|
||||
- type: `b`, read-only, mutable
|
||||
|
||||
True if this is the currently active resolution, false otherwise.
|
||||
|
||||
Resolutions can only be set to active, but never to not active - at least
|
||||
one resoultion must be active at all times. This property is read-only, use the
|
||||
`SetActive()` method to set a resolution as the active resolution.
|
||||
|
||||
#### `IsDefault`
|
||||
- type: `b`, read-only, mutable
|
||||
|
||||
True if this is the currently default resolution, false otherwise. If the
|
||||
device does not have the default resolution capability, this property is
|
||||
always false.
|
||||
|
||||
Resolutions can only be set to default, but never to not default - at least
|
||||
one resolution must be default at all times. This property is read-only, use the
|
||||
`SetDefault()` method to set a resolution as the default resolution.
|
||||
|
||||
#### `Resolution`
|
||||
- type: `uu`, read-write, mutable
|
||||
|
||||
uint for the x and y resolution assigned to this entry, respectively
|
||||
|
||||
#### `ReportRate`
|
||||
- type: `u`, read-write, mutable
|
||||
|
||||
uint for the report rate in Hz assigned to this entry
|
||||
|
||||
#### `Maximum`
|
||||
- type: `u`, read-only, constant
|
||||
|
||||
uint for the maximum possible resolution
|
||||
#### `Minimum`
|
||||
- type: `u`, read-only, constant
|
||||
|
||||
uint for the minimum possible resolution
|
||||
|
||||
### Methods:
|
||||
|
||||
#### `SetDefault() → () `
|
||||
|
||||
Set this resolution to be the default
|
||||
#### `SetActive() → () `
|
||||
|
||||
Set this resolution to be the active one
|
||||
|
||||
org.freedesktop.ratbag1.Button
|
||||
==============================
|
||||
|
||||
### Properties:
|
||||
#### `Index`
|
||||
- type: `u`, read-only, constant
|
||||
|
||||
Index of the button
|
||||
#### `Type`
|
||||
- type: `u`, read-only, constant
|
||||
|
||||
Enum describing the button physical type. This type is unrelated to the
|
||||
logical button mapping and serves to easily identify the button on the
|
||||
device.
|
||||
#### `ButtonMapping`
|
||||
- type: `u`, read-write, mutable
|
||||
|
||||
uint of the current button mapping (if mapping to button)
|
||||
#### `SpecialMapping`
|
||||
- type: `u`, read-write, mutable
|
||||
|
||||
Enum describing the current special mapping (if mapped to special)
|
||||
#### `KeyMapping`
|
||||
- type: `au`, read-write, mutable
|
||||
|
||||
Array of uints, first entry is the keycode, other entries, if any, are
|
||||
modifiers (if mapped to key)
|
||||
#### `Macro`
|
||||
-type: `a(uu)`, read-write, mutable
|
||||
|
||||
Array of (type, keycode), where type may be one of
|
||||
`RATBAG_MACRO_EVENT_KEY_PRESSED` or `RATBAG_MACRO_EVENT_KEY_RELEASED`.
|
||||
#### `ActionType`
|
||||
- type: `u`, read-only, mutable
|
||||
|
||||
An enum describing the action type of the button, see
|
||||
ratbag\_button\_get\_action\_type for the list of enums.
|
||||
This decides which *Mapping* property has a value.
|
||||
#### `ActionTypes`
|
||||
- type: `au`, read-only, constant
|
||||
Array of enum ratbag\_button\_action\_type, possible values for ActionType
|
||||
on the current device
|
||||
|
||||
### Methods:
|
||||
#### `Disable() → ()`
|
||||
Disable this button
|
||||
|
||||
org.freedesktop.ratbag1.Led
|
||||
===========================
|
||||
|
||||
### Properties:
|
||||
#### `Index`
|
||||
- type: `u`, read-only, constant
|
||||
|
||||
Index of the LED
|
||||
|
||||
#### `Mode`
|
||||
- type: `u`, read-write, mutable
|
||||
|
||||
uint mapping to the mode enum from libratbag
|
||||
|
||||
#### `Type`
|
||||
- type: `u`, read-only, mutable
|
||||
|
||||
enum describing the LED type
|
||||
|
||||
#### `Color`
|
||||
- type: `(uuu)`, read-write, mutable
|
||||
uint triplet (RGB) of the LED's color
|
||||
|
||||
#### `EffectRate`
|
||||
- type: `u`, read-write, mutable
|
||||
|
||||
The effect rate in Hz, possible values are in the range 100 - 20000
|
||||
|
||||
#### `Brightness`
|
||||
- type: `u`, read-write, mutable
|
||||
|
||||
The brightness of the LED, possible values are in the range 0 - 255
|
||||
|
||||
For easier debugging, objects paths are constructed from the device. e.g.
|
||||
`/org/freedesktop/ratbag/button/event5/p0/b10` is the button interface for
|
||||
button 10 on profile 0 on event5. The naming is subject to change. Do not
|
||||
rely on a constructed object path in your application.
|
||||
|
||||
|
||||
33
README.md
@@ -80,33 +80,16 @@ library in the future, if other projects require it.
|
||||
Adding Devices to libratbag
|
||||
---------------------------
|
||||
|
||||
As of commit 3605bede4 libratbag now uses a hwdb entry to match the device
|
||||
with the drivers. To access a device through libratbag, the udev property
|
||||
RATBAG_DRIVER must be set for a device's event node. Check with
|
||||
libratbag relies on a device database to match a device with the drivers.
|
||||
See the data/devices/ directory for the set of known devices. These files
|
||||
are usually installed into $prefix/$datadir (e.g. /usr/share/libratbag/).
|
||||
|
||||
sudo udevadm info /sys/class/input/eventX | grep RATBAG_DRIVER
|
||||
To add a new device to libratbag, simply drop a new device file into that
|
||||
directory and restart ratbagd. See the data/devices/device.example file for
|
||||
guidance on what information must be set.
|
||||
|
||||
If your device is not yet assigned the property, it is not in the hwdb. It
|
||||
may however be supported by one of our existing drivers. Try enabling it by
|
||||
adding the device vendor-id/product-id to the hwdb file in
|
||||
`hwdb/70-libratbag-mouse.hwdb`. For example, for a HID++ 1.0 device, edit
|
||||
the 70-libratbag-mouse.hwdb file and add an entry with `RATBAG_DRIVER=hidpp10`.
|
||||
For the other drivers, look for the id of the driver in driver-{drivername}.c
|
||||
file and do the same.
|
||||
|
||||
Once your device is added to the hwdb, install libratbag and trigger a hwdb
|
||||
update:
|
||||
|
||||
sudo udevadm hwdb --update
|
||||
sudo udevadm control --reload
|
||||
|
||||
Then unplug/replug your mouse. `RATBAG_DRIVER` should appear in the udev
|
||||
properties of your device with the value you previously set. If the property
|
||||
is not assigned, the hwdb entry does not correctly match your device or the
|
||||
installed udev rules/hwdb entries are not picked up by udev.
|
||||
|
||||
If the device doesn't work, you'll have to start reverse-engineering the
|
||||
device-specific protocol. Good luck :)
|
||||
If the device doesn't work after adding the device file, you'll have to
|
||||
start reverse-engineering the device-specific protocol. Good luck :)
|
||||
|
||||
Source
|
||||
------
|
||||
|
||||
118
circle.yml
@@ -1,6 +1,9 @@
|
||||
# vim: set expandtab shiftwidth=2 tabstop=8:
|
||||
libratbag_references:
|
||||
default_settings: &default_settings
|
||||
working_directory: ~/libratbag
|
||||
environment:
|
||||
LANG: C.UTF-8
|
||||
build_default: &build_default
|
||||
name: Build
|
||||
command: |
|
||||
@@ -16,6 +19,12 @@ libratbag_references:
|
||||
name: Build and test
|
||||
environment:
|
||||
NINJA_ARGS: test
|
||||
build_with_docs: &build_with_docs
|
||||
run:
|
||||
<<: *build_default
|
||||
name: Build with documentation
|
||||
environment:
|
||||
MESON_PARAMS: -Ddocumentation=true
|
||||
install: &install
|
||||
run:
|
||||
name: Installing
|
||||
@@ -52,16 +61,34 @@ libratbag_references:
|
||||
mkdir /run/dbus
|
||||
/usr/bin/dbus-daemon --system --fork
|
||||
|
||||
fedora_prep_cache: &fedora_prep_cache
|
||||
<<: *default_settings
|
||||
steps:
|
||||
- run:
|
||||
name: Initializing Fedora dnf cache
|
||||
command: dnf install -y --downloadonly libsolv tree git gcc gcc-c++ meson check-devel libudev-devel libevdev-devel valgrind python3-gobject python3-evdev glib2-devel python3-lxml
|
||||
- persist_to_workspace:
|
||||
root: /var/cache/
|
||||
paths:
|
||||
- dnf/*
|
||||
|
||||
fedora_fetch_cache: &fedora_fetch_cache
|
||||
attach_workspace:
|
||||
at: /var/cache/
|
||||
|
||||
fedora_install: &fedora_install
|
||||
run:
|
||||
name: Install prerequisites
|
||||
command: dnf install -y tree git gcc gcc-c++ meson check-devel libudev-devel libevdev-devel doxygen graphviz valgrind python3-gobject python3-evdev
|
||||
command: |
|
||||
echo keepcache=1 >> /etc/dnf/dnf.conf
|
||||
dnf upgrade -y libsolv
|
||||
dnf install -y tree git gcc gcc-c++ meson check-devel libudev-devel libevdev-devel valgrind python3-gobject python3-evdev glib2-devel python3-lxml python3-devel swig
|
||||
|
||||
|
||||
fedora_settings: &fedora_settings
|
||||
<<: *default_settings
|
||||
steps:
|
||||
- *fedora_fetch_cache
|
||||
- *fedora_install
|
||||
- checkout
|
||||
- *start_dbus
|
||||
@@ -81,7 +108,7 @@ ubuntu_settings: &ubuntu_settings
|
||||
apt-get install -y software-properties-common
|
||||
add-apt-repository universe
|
||||
apt-get update
|
||||
apt-get install -y tree git gcc g++ pkg-config meson check libudev-dev libevdev-dev libsystemd-dev doxygen graphviz valgrind python3-gi python3-evdev
|
||||
apt-get install -y tree git gcc g++ pkg-config meson check libudev-dev libevdev-dev libsystemd-dev valgrind python3-gi python3-evdev libglib2.0-dev python3-lxml python3-dev swig
|
||||
- checkout
|
||||
- *start_dbus
|
||||
- *build_and_test
|
||||
@@ -93,6 +120,7 @@ ubuntu_settings: &ubuntu_settings
|
||||
scan_build_run: &scan_build_run
|
||||
<<: *default_settings
|
||||
steps:
|
||||
- *fedora_fetch_cache
|
||||
- *fedora_install
|
||||
- run:
|
||||
name: Install clang and find
|
||||
@@ -104,6 +132,61 @@ scan_build_run: &scan_build_run
|
||||
name: Check scan-build results
|
||||
command: test ! -d ~/libratbag/build/meson-logs/scanbuild || test $(find ~/libratbag/build/meson-logs/scanbuild -maxdepth 0 ! -empty -exec echo "not empty" \; | wc -l) -eq 0 || (echo "Check scan-build results" && false)
|
||||
|
||||
doc_build: &doc_build
|
||||
<<: *default_settings
|
||||
steps:
|
||||
- *fedora_fetch_cache
|
||||
- *fedora_install
|
||||
- run:
|
||||
name: Install documentation build-deps
|
||||
command: dnf install -y python3-sphinx python3-sphinx_rtd_theme doxygen libxslt
|
||||
- checkout
|
||||
- *build_with_docs
|
||||
- *export_logs
|
||||
- store_artifacts:
|
||||
path: ~/libratbag/build/doc/html
|
||||
- persist_to_workspace:
|
||||
root: build
|
||||
paths:
|
||||
- doc/html/*
|
||||
|
||||
docs_deploy: &docs_deploy
|
||||
<<: *default_settings
|
||||
steps:
|
||||
- *fedora_fetch_cache
|
||||
- run:
|
||||
name: Install prerequisites
|
||||
command: dnf install -y git tree
|
||||
- checkout
|
||||
- attach_workspace:
|
||||
at: build
|
||||
- run:
|
||||
name: Setup the deploy SSH key
|
||||
command: |
|
||||
ssh-add -L | tail -n1 > ~/.ssh/deploy.pub
|
||||
cat <<EOF > ~/.ssh/config
|
||||
Host github.com
|
||||
IdentityFile /root/.ssh/deploy.pub
|
||||
IdentitiesOnly yes
|
||||
EOF
|
||||
- run:
|
||||
name: Clone doc repository
|
||||
command: |
|
||||
cd ~
|
||||
git clone ssh://git@github.com/${CIRCLE_PROJECT_REPONAME}/${CIRCLE_PROJECT_REPONAME}.github.io
|
||||
- run:
|
||||
name: Copy the doc, commit and push
|
||||
command: |
|
||||
set +e
|
||||
cd ~/${CIRCLE_PROJECT_REPONAME}.github.io
|
||||
\cp -r ~/${CIRCLE_PROJECT_REPONAME}/build/doc/html/* .
|
||||
if ! git diff-index --quiet HEAD --; then
|
||||
git config --global user.email "libratbag@librabtag.github.io"
|
||||
git config --global user.name "The libratbag crew"
|
||||
git add .
|
||||
git commit -m "update docs from ${CIRCLE_SHA1}"
|
||||
git push
|
||||
fi
|
||||
|
||||
version: 2
|
||||
jobs:
|
||||
@@ -111,6 +194,10 @@ jobs:
|
||||
<<: *fedora_settings
|
||||
docker:
|
||||
- image: fedora:rawhide
|
||||
fedora_cache:
|
||||
<<: *fedora_prep_cache
|
||||
docker:
|
||||
- image: fedora:latest
|
||||
fedora_latest:
|
||||
<<: *fedora_settings
|
||||
docker:
|
||||
@@ -119,10 +206,18 @@ jobs:
|
||||
<<: *ubuntu_settings
|
||||
docker:
|
||||
- image: ubuntu:zesty
|
||||
doc_build:
|
||||
<<: *doc_build
|
||||
docker:
|
||||
- image: fedora:latest
|
||||
scan_build:
|
||||
<<: *scan_build_run
|
||||
docker:
|
||||
- image: fedora:latest
|
||||
doc_deploy:
|
||||
<<: *docs_deploy
|
||||
docker:
|
||||
- image: fedora:latest
|
||||
|
||||
|
||||
workflows:
|
||||
@@ -130,6 +225,21 @@ workflows:
|
||||
compile_and_test:
|
||||
jobs:
|
||||
# - fedora_rawhide
|
||||
- scan_build
|
||||
- fedora_cache
|
||||
- scan_build:
|
||||
requires:
|
||||
- fedora_cache
|
||||
- ubuntu_17_04
|
||||
- fedora_latest
|
||||
- fedora_latest:
|
||||
requires:
|
||||
- fedora_cache
|
||||
- doc_build:
|
||||
requires:
|
||||
- fedora_cache
|
||||
- doc_deploy:
|
||||
requires:
|
||||
- fedora_cache
|
||||
- doc_build
|
||||
filters:
|
||||
branches:
|
||||
only: master
|
||||
|
||||
234
data/devices/data-parse-test.py
Executable file
@@ -0,0 +1,234 @@
|
||||
#!/usr/bin/env python3
|
||||
# vim: set expandtab shiftwidth=4 tabstop=4:
|
||||
#
|
||||
# Copyright © 2017 Red Hat, Inc.
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a
|
||||
# copy of this software and associated documentation files (the "Software"),
|
||||
# to deal in the Software without restriction, including without limitation
|
||||
# the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
# and/or sell copies of the Software, and to permit persons to whom the
|
||||
# Software is furnished to do so, subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice (including the next
|
||||
# paragraph) shall be included in all copies or substantial portions of the
|
||||
# Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
# DEALINGS IN THE SOFTWARE.
|
||||
#
|
||||
# Device data verification script
|
||||
#
|
||||
|
||||
import argparse
|
||||
import os
|
||||
import configparser
|
||||
|
||||
# Set on commandline with --svg-dir
|
||||
svg_dirs = []
|
||||
|
||||
|
||||
def check_svg_str(string):
|
||||
assert(string.endswith('.svg'))
|
||||
|
||||
svg_file_found = False
|
||||
for svg_dir in svg_dirs:
|
||||
files = os.listdir(svg_dir)
|
||||
if string in files:
|
||||
svg_file_found = True
|
||||
break
|
||||
assert(svg_file_found)
|
||||
|
||||
|
||||
def check_match_str(string):
|
||||
bustypes = ['usb', 'bluetooth']
|
||||
|
||||
matches = string.split(';')
|
||||
for match in matches:
|
||||
if not match: # empty string if trailing ;
|
||||
continue
|
||||
|
||||
parts = match.split(':')
|
||||
assert(len(parts) == 3)
|
||||
assert(parts[0] in bustypes)
|
||||
vid = parts[1]
|
||||
assert(vid == '{:04x}'.format(int(vid, 16)))
|
||||
pid = parts[2]
|
||||
assert(pid == '{:04x}'.format(int(pid, 16)))
|
||||
|
||||
|
||||
def check_ledtypes_str(string):
|
||||
permitted_types = ['logo', 'side', 'battery', 'dpi']
|
||||
|
||||
types = string.split(';')
|
||||
for t in types:
|
||||
if not t: # emtpy string if trailing ;
|
||||
continue
|
||||
|
||||
assert(t in permitted_types)
|
||||
|
||||
|
||||
def check_section_device(section):
|
||||
required_keys = ['Name', 'Driver', 'DeviceMatch']
|
||||
permitted_keys = required_keys + ['Svg', 'LedTypes']
|
||||
|
||||
for key in section.keys():
|
||||
assert(key in permitted_keys)
|
||||
|
||||
for r in required_keys:
|
||||
assert(r in section)
|
||||
|
||||
try:
|
||||
check_svg_str(section['Svg'])
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
try:
|
||||
check_ledtypes_str(section['LedTypes'])
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
check_match_str(section['DeviceMatch'])
|
||||
|
||||
|
||||
def check_dpi_range_str(string):
|
||||
import re
|
||||
|
||||
m = re.search('^([0-9]+):([0-9]+)@([0-9\.]+)$', string)
|
||||
assert(m is not None)
|
||||
min = int(m.group(1))
|
||||
max = int(m.group(2))
|
||||
steps = float(m.group(3))
|
||||
|
||||
assert(min >= 0 and min <= 400)
|
||||
assert(max >= 2000 and max <= 12000)
|
||||
assert(steps > 0 and steps <= 100)
|
||||
|
||||
if int(steps) == steps:
|
||||
steps = int(steps)
|
||||
|
||||
assert(string == '{}:{}@{}'.format(min, max, steps))
|
||||
|
||||
|
||||
def check_dpi_list_str(string):
|
||||
entries = string.split(';')
|
||||
# Remove possible empty last entry if trailing with a ;
|
||||
if not entries[len(entries) - 1]:
|
||||
entries = entries[:-1]
|
||||
|
||||
for idx, entry in enumerate(entries):
|
||||
dpi = int(entry)
|
||||
assert(dpi >= 0 and dpi <= 12000)
|
||||
if idx > 0:
|
||||
prev = entries[idx - 1]
|
||||
prev_dpi = int(prev)
|
||||
assert(dpi > prev_dpi)
|
||||
|
||||
|
||||
def check_profile_type_str(string):
|
||||
types = ['G9', 'G500', 'G700']
|
||||
assert(string in types)
|
||||
|
||||
|
||||
def check_section_hidpp10(section):
|
||||
permitted = ['Profiles', 'ProfileType', 'DpiRange', 'DpiList', 'DeviceIndex', 'Leds']
|
||||
for key in section.keys():
|
||||
assert(key in permitted)
|
||||
|
||||
try:
|
||||
nprofiles = int(section['Profiles'])
|
||||
# 10 is arbitrarily chosen
|
||||
assert(nprofiles > 0 and nprofiles < 10)
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
try:
|
||||
index = int(section['DeviceIndex'])
|
||||
# 10 is arbitrarily chosen
|
||||
assert(index > 0 and index < 10)
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
try:
|
||||
check_dpi_range_str(section['DpiRange'])
|
||||
assert('DpiList' not in section.keys())
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
try:
|
||||
check_dpi_list_str(section['DpiList'])
|
||||
assert('DpiRange' not in section.keys())
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
try:
|
||||
check_profile_type_str(section['ProfileType'])
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
try:
|
||||
leds = int(section['Leds'])
|
||||
# 10 is arbitrarily chosen
|
||||
assert(leds > 0 and leds < 10)
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
|
||||
def check_section_hidpp20(section):
|
||||
permitted = ['DeviceIndex']
|
||||
for key in section.keys():
|
||||
assert(key in permitted)
|
||||
|
||||
try:
|
||||
index = int(section['DeviceIndex'])
|
||||
# 10 is arbitrarily chosen
|
||||
assert(index > 0 and index < 10)
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
|
||||
def check_section_driver(driver, section):
|
||||
if driver == 'hidpp10':
|
||||
check_section_hidpp10(section)
|
||||
elif driver == 'hidpp20':
|
||||
check_section_hidpp20(section)
|
||||
else:
|
||||
assert('Unsupported driver section {}'.format(driver))
|
||||
|
||||
|
||||
def parse_data_file(path):
|
||||
print('Parsing file {}'.format(path))
|
||||
data = configparser.ConfigParser(strict=True)
|
||||
# Don't convert to lowercase
|
||||
data.optionxform = lambda option: option
|
||||
data.read(path)
|
||||
|
||||
assert('Device' in data.sections())
|
||||
check_section_device(data['Device'])
|
||||
|
||||
driver = data['Device']['Driver']
|
||||
driver_section = 'Driver/{}'.format(driver)
|
||||
|
||||
permitted_sections = ['Device', driver_section]
|
||||
for s in data.sections():
|
||||
assert(s in permitted_sections)
|
||||
|
||||
if data.has_section(driver_section):
|
||||
check_section_driver(driver, data[driver_section])
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
parser = argparse.ArgumentParser(description="Device data-file checker")
|
||||
parser.add_argument('file', nargs='+')
|
||||
parser.add_argument('--svg-dir', metavar='dir', action='append',
|
||||
type=str,
|
||||
help='Directory to check for SVG files (may be given multiple times)')
|
||||
args = parser.parse_args()
|
||||
svg_dirs = args.svg_dir
|
||||
for path in args.file:
|
||||
parse_data_file(path)
|
||||
57
data/devices/device.example
Normal file
@@ -0,0 +1,57 @@
|
||||
# Example description file for a libratbag device
|
||||
#
|
||||
# Make sure the file has a recognizable name with a '.device' suffix
|
||||
|
||||
[Device]
|
||||
# The kernel name of the device. This name is not used by libratbag, it is
|
||||
# used by debugging tools.
|
||||
Name=Logitech Example Device
|
||||
|
||||
# DeviceMatch is a triplet of bus:vid:pid, where bus is 'usb' or bluetooth'
|
||||
# and pid/vid are lowercase 4-digit hexadecimal numbers with preceding
|
||||
# zeroes.
|
||||
DeviceMatch=usb:12ab:00f2
|
||||
|
||||
# The file name of the SVG file representing this device
|
||||
Svg=logitech-example.svg
|
||||
|
||||
# The libratbag driver backend
|
||||
Driver=hidpp10
|
||||
|
||||
# The types of the LEDs, in the indexed order they appear in, separated by a
|
||||
# semicolon.
|
||||
# Allowed values: logo, side, battery, dpi
|
||||
LedTypes=logo;side
|
||||
|
||||
# Only one group of driver-specific properties is permitted and it must be
|
||||
# [Driver/<drivername>]. It is a bug do have any other [Driver/foo] group in
|
||||
# a device file, but this example file lists all.
|
||||
|
||||
[Driver/hidpp10]
|
||||
# The number of profiles, must be greater than 0
|
||||
Profiles=1
|
||||
|
||||
# The type of the profile
|
||||
ProfileType=G9
|
||||
|
||||
# The range of available resolutions in the form min:max@step
|
||||
# Mutually exclusive with DpiList
|
||||
DpiRange=50:5700@50
|
||||
|
||||
# The list of available resolutions, separated by semicolons.
|
||||
# Mutually exclusive with DpiRange
|
||||
# Where possible, DpiRange should be preferred
|
||||
DpiList=50;200;400;800
|
||||
|
||||
# The HID++ 1.0 device index
|
||||
# Should be unset unless required
|
||||
# DeviceIndex=1
|
||||
|
||||
# The number of LEDs
|
||||
Leds=1
|
||||
|
||||
|
||||
[Driver/hidpp20]
|
||||
# The HID++ 2.0 device index
|
||||
# Should be unset unless required
|
||||
# DeviceIndex=1
|
||||
6
data/devices/etekcity-fixme.device
Normal file
@@ -0,0 +1,6 @@
|
||||
# FIXME: which device is this exactly?
|
||||
[Device]
|
||||
Name=Etekcity FIXME
|
||||
DeviceMatch=usb:1ea7:4011
|
||||
Driver=etekcity
|
||||
Svg=etekcity.svg
|
||||
5
data/devices/gskill-MX-780.device
Normal file
@@ -0,0 +1,5 @@
|
||||
# G.Skill MX-780
|
||||
[Device]
|
||||
Name=G.Skill MX-780
|
||||
DeviceMatch=usb:28da:3101
|
||||
Driver=gskill
|
||||
5
data/devices/logitech-M325.device
Normal file
@@ -0,0 +1,5 @@
|
||||
# Logitech M325 over unifying
|
||||
[Device]
|
||||
Name=Logitech M325
|
||||
DeviceMatch=usb:046d:400a
|
||||
Driver=hidpp20
|
||||
5
data/devices/logitech-M570.device
Normal file
@@ -0,0 +1,5 @@
|
||||
# Logitech M570
|
||||
[Device]
|
||||
Name=Logitech M570
|
||||
DeviceMatch=usb:046d:1028
|
||||
Driver=hidpp10
|
||||
5
data/devices/logitech-M705.device
Normal file
@@ -0,0 +1,5 @@
|
||||
# Logitech M705
|
||||
[Device]
|
||||
Name=Logitech M705
|
||||
DeviceMatch=usb:046d:101b
|
||||
Driver=hidpp10
|
||||
6
data/devices/logitech-MX-Master.device
Normal file
@@ -0,0 +1,6 @@
|
||||
# Logitech MX Master
|
||||
[Device]
|
||||
Name=Logitech MX Master
|
||||
DeviceMatch=usb:046d:4041;bluetooth:046d:b012
|
||||
Driver=hidpp20
|
||||
Svg=logitech-mx_master.svg
|
||||
5
data/devices/logitech-T650.device
Normal file
@@ -0,0 +1,5 @@
|
||||
# Logitech T650 over unifying
|
||||
[Device]
|
||||
Name=Logitech T650
|
||||
DeviceMatch=usb:046d:4101
|
||||
Driver=hidpp20
|
||||
5
data/devices/logitech-Wireless-Touchpad.device
Normal file
@@ -0,0 +1,5 @@
|
||||
# Logitech Wireless Touchpad (Unifying)
|
||||
[Device]
|
||||
Name=Logitech Wireless Touchpad
|
||||
DeviceMatch=usb:046d:4011
|
||||
Driver=hidpp20
|
||||
6
data/devices/logitech-g300.device
Normal file
@@ -0,0 +1,6 @@
|
||||
# WARNING: this file was automatically converted and has not yet been vetted
|
||||
[Device]
|
||||
Name=Logitech G300
|
||||
DeviceMatch=usb:046d:c246
|
||||
Driver=logitech_g300
|
||||
Svg=logitech-g300.svg
|
||||
7
data/devices/logitech-g303.device
Normal file
@@ -0,0 +1,7 @@
|
||||
# G303 over USB
|
||||
[Device]
|
||||
Name=Logitech Gaming Mouse G303
|
||||
DeviceMatch=usb:046d:c080
|
||||
Svg=logitech-g303.svg
|
||||
Driver=hidpp20
|
||||
LedTypes=logo;side;
|
||||
6
data/devices/logitech-g403.device
Normal file
@@ -0,0 +1,6 @@
|
||||
# Logitech G403
|
||||
[Device]
|
||||
Name=Logitech G403
|
||||
DeviceMatch=usb:046d:c082;usb:046d:c083
|
||||
Driver=hidpp20
|
||||
Svg=logitech-g403.svg
|
||||
9
data/devices/logitech-g5-2007.device
Normal file
@@ -0,0 +1,9 @@
|
||||
# Name=Logitech G5 2007
|
||||
[Device]
|
||||
Name=Logitech G5
|
||||
DeviceMatch=usb:046d:c049
|
||||
Driver=hidpp10
|
||||
|
||||
[Driver/hidpp10]
|
||||
DpiList=400;800;1600;2000
|
||||
Profiles=1
|
||||
7
data/devices/logitech-g5.device
Normal file
@@ -0,0 +1,7 @@
|
||||
[Device]
|
||||
Name=G5
|
||||
DeviceMatch=usb:046d:c041
|
||||
Driver=hidpp10
|
||||
|
||||
[Driver/hidpp10]
|
||||
DpiList=400;800;1600;2000
|
||||
10
data/devices/logitech-g500.device
Normal file
@@ -0,0 +1,10 @@
|
||||
[Device]
|
||||
Name=Logitech G500
|
||||
DeviceMatch=usb:046d:c068
|
||||
Driver=hidpp10
|
||||
Svg=logitech-g500.svg
|
||||
|
||||
[Driver/hidpp10]
|
||||
DpiRange=0:5700@23.53
|
||||
ProfileType=G500
|
||||
Profiles=1
|
||||
10
data/devices/logitech-g500s.device
Normal file
@@ -0,0 +1,10 @@
|
||||
[Device]
|
||||
Name=Logitech G500s
|
||||
DeviceMatch=usb:046d:c24e
|
||||
Driver=hidpp10
|
||||
Svg=logitech-g500s.svg
|
||||
|
||||
[Driver/hidpp10]
|
||||
DpiRange=0:8200@50
|
||||
ProfileType=G500
|
||||
Profiles=1
|
||||
6
data/devices/logitech-g502-Proteus-Core-over-USB.device
Normal file
@@ -0,0 +1,6 @@
|
||||
# Logitech G502 Proteus Core over USB
|
||||
[Device]
|
||||
Name=Logitech G502 Proteus Core
|
||||
DeviceMatch=usb:046d:c07d
|
||||
Driver=hidpp20
|
||||
Svg=logitech-g502.svg
|
||||
@@ -0,0 +1,6 @@
|
||||
# Logitech G502 Proteus Spectrum over USB
|
||||
[Device]
|
||||
Name=Logitech G502 Proteus Spectrum
|
||||
DeviceMatch=usb:046d:c332
|
||||
Driver=hidpp20
|
||||
Svg=logitech-g502.svg
|
||||
8
data/devices/logitech-g602.device
Normal file
@@ -0,0 +1,8 @@
|
||||
# Logitech G602 over wireless USB
|
||||
[Device]
|
||||
Name=Logitech G602
|
||||
DeviceMatch=usb:046d:c537
|
||||
Driver=hidpp20
|
||||
|
||||
[Driver/hidpp20]
|
||||
DeviceIndex=1
|
||||
9
data/devices/logitech-g7.device
Normal file
@@ -0,0 +1,9 @@
|
||||
# Logitech G7
|
||||
# http://support.logitech.com/en_us/product/g7-laser-cordless-mouse/specs
|
||||
[Device]
|
||||
Name=Logitech G7
|
||||
DeviceMatch=usb:046d:c51a
|
||||
Driver=hidpp10
|
||||
|
||||
[Driver/hidpp10]
|
||||
Profiles=1
|
||||
12
data/devices/logitech-g700-wireless.device
Normal file
@@ -0,0 +1,12 @@
|
||||
# Logitech G700 over wireless USB
|
||||
# http://support.logitech.com/en_us/product/wireless-gaming-mouse-g700/specs
|
||||
[Device]
|
||||
Name=Logitech G700
|
||||
DeviceMatch=usb:046d:c531
|
||||
Driver=hidpp10
|
||||
|
||||
[Driver/hidpp10]
|
||||
DpiRange=0:5700@23.53
|
||||
ProfileType=G700
|
||||
DeviceIndex=1
|
||||
Profiles=5
|
||||
12
data/devices/logitech-g700.device
Normal file
@@ -0,0 +1,12 @@
|
||||
# Logitech G700 over USB
|
||||
# http://support.logitech.com/en_us/product/wireless-gaming-mouse-g700/specs
|
||||
[Device]
|
||||
Name=Logitech G700
|
||||
DeviceMatch=usb:046d:c06b
|
||||
Driver=hidpp10
|
||||
Svg=logitech-g700.svg
|
||||
|
||||
[Driver/hidpp10]
|
||||
DpiRange=0:5700@23.53
|
||||
ProfileType=G700
|
||||
Profiles=5
|
||||
13
data/devices/logitech-g700s-wireless.device
Normal file
@@ -0,0 +1,13 @@
|
||||
# Logitech G700s over wireless USB
|
||||
# http://support.logitech.com/en_us/product/g700s-rechargable-wireless-gaming-mouse/specs
|
||||
[Device]
|
||||
Name=Logitech G700s
|
||||
DeviceMatch=usb:046d:c531
|
||||
Driver=hidpp10
|
||||
Svg=logitech-g700.svg
|
||||
|
||||
[Driver/hidpp10]
|
||||
DpiRange=0:8200@50
|
||||
ProfileType=G700
|
||||
DeviceIndex=1
|
||||
Profiles=5
|
||||
12
data/devices/logitech-g700s.device
Normal file
@@ -0,0 +1,12 @@
|
||||
# Logitech G700s over USB
|
||||
# http://support.logitech.com/en_us/product/g700s-rechargable-wireless-gaming-mouse/specs
|
||||
[Device]
|
||||
Name=Logitech G700s
|
||||
DeviceMatch=usb:046d:c07c
|
||||
Driver=hidpp10
|
||||
Svg=logitech-g700.svg
|
||||
|
||||
[Driver/hidpp10]
|
||||
DpiRange=0:8200@50
|
||||
ProfileType=G700
|
||||
Profiles=5
|
||||
6
data/devices/logitech-g703.device
Normal file
@@ -0,0 +1,6 @@
|
||||
[Device]
|
||||
Name=Logitech G703
|
||||
DeviceMatch=usb:046d:c087
|
||||
Driver=hidpp20
|
||||
Svg=logitech-g703.svg
|
||||
|
||||
14
data/devices/logitech-g9.device
Normal file
@@ -0,0 +1,14 @@
|
||||
# Logitech G9
|
||||
# http://support.logitech.com/en_us/product/g9-laser-mouse/specs
|
||||
[Device]
|
||||
Name=Logitech G9
|
||||
DeviceMatch=usb:046d:c048
|
||||
LedTypes=dpi
|
||||
Driver=hidpp10
|
||||
Svg=logitech-g9.svg
|
||||
|
||||
[Driver/hidpp10]
|
||||
DpiList=200;400;600;800;1000;1200;1400;1600;1800;2000;2200;2400;2600;2800;3000;3200
|
||||
ProfileType=G9
|
||||
Profiles=5
|
||||
Leds=1
|
||||
9
data/devices/logitech-g900-wireless.device
Normal file
@@ -0,0 +1,9 @@
|
||||
# Logitech G900 and G403 over wireless USB
|
||||
[Device]
|
||||
Name=Logitech G900, G403
|
||||
DeviceMatch=usb:046d:c539
|
||||
Driver=hidpp20
|
||||
Svg=logitech-g900.svg
|
||||
|
||||
[Driver/hidpp20]
|
||||
DeviceIndex=1
|
||||
6
data/devices/logitech-g900.device
Normal file
@@ -0,0 +1,6 @@
|
||||
# Logitech G900 over USB
|
||||
[Device]
|
||||
Name=Logitech G900
|
||||
DeviceMatch=usb:046d:c081
|
||||
Driver=hidpp20
|
||||
Svg=logitech-g900.svg
|
||||
11
data/devices/logitech-g9x-[Call-of-Duty-MW3-Edition].device
Normal file
@@ -0,0 +1,11 @@
|
||||
# Logitech G9x [Call of Duty MW3 Edition]
|
||||
# http://support.logitech.com/en_us/product/laser-mouse-g9x/specs
|
||||
[Device]
|
||||
Name=Logitech G9x [Call of Duty MW3 Edition]
|
||||
DeviceMatch=usb:046d:c249
|
||||
Driver=hidpp10
|
||||
|
||||
[Driver/hidpp10]
|
||||
DpiRange=0:5700@23.53
|
||||
ProfileType=G500
|
||||
Profiles=5
|
||||
11
data/devices/logitech-g9x-[Original].device
Normal file
@@ -0,0 +1,11 @@
|
||||
# Logitech G9x [Original]
|
||||
# http://support.logitech.com/en_us/product/g9x-laser-mouse/specs
|
||||
[Device]
|
||||
Name=G9x [Original]
|
||||
DeviceMatch=usb:046d:c066
|
||||
Driver=hidpp10
|
||||
|
||||
[Driver/hidpp10]
|
||||
DpiRange=0:5700@23.53
|
||||
ProfileType=G500
|
||||
Profiles=5
|
||||
5
data/devices/roccat-kone-xtd.device
Normal file
@@ -0,0 +1,5 @@
|
||||
[Device]
|
||||
Name=Roccat Kone XTD
|
||||
DeviceMatch=usb:1e7d:2e22
|
||||
Driver=roccat
|
||||
Svg=roccat-kone-xtd.svg
|
||||
11
data/devices/steelseries-kinzu-v2.device
Normal file
@@ -0,0 +1,11 @@
|
||||
[Device]
|
||||
Name=SteelSeries Kinzu V2
|
||||
DeviceMatch=usb:1038:1378
|
||||
Driver=steelseries
|
||||
Svg=steelseries-kinzu-v2.svg
|
||||
|
||||
[Driver/steelseries]
|
||||
DeviceVersion=1
|
||||
Buttons=3
|
||||
Leds=0
|
||||
DpiList=400;800;1600;3200
|
||||
11
data/devices/steelseries-rival-310.device
Normal file
@@ -0,0 +1,11 @@
|
||||
[Device]
|
||||
Name=SteelSeries Rival 310
|
||||
DeviceMatch=usb:1038:1720
|
||||
Driver=steelseries
|
||||
Svg=steelseries-rival310.svg
|
||||
|
||||
[Driver/steelseries]
|
||||
DeviceVersion=2
|
||||
Buttons=6
|
||||
Leds=2
|
||||
DpiRange=100:12000@100
|
||||
118
data/gnome/check-svg.py
Executable file
@@ -0,0 +1,118 @@
|
||||
#!/usr/bin/python3
|
||||
# vim: set expandtab shiftwidth=4 tabstop=4:
|
||||
|
||||
import sys
|
||||
from lxml import etree
|
||||
import logging
|
||||
|
||||
ns = {'svg': 'http://www.w3.org/2000/svg'}
|
||||
style_query = '//svg:rect[@id=\"{}\"][contains(@style, \"{}\")]'
|
||||
|
||||
logger = None
|
||||
|
||||
class SVGLogger(logging.Logger):
|
||||
def __init__(self, name, level=logging.NOTSET):
|
||||
self.success = True
|
||||
return super().__init__(name, level)
|
||||
|
||||
def error(self, msg, *args, **kwargs):
|
||||
self.success = False
|
||||
return super().error(msg, *args, **kwargs)
|
||||
|
||||
@classmethod
|
||||
def get_logger(cls, path):
|
||||
logging.setLoggerClass(SVGLogger)
|
||||
logging.basicConfig(level=logging.DEBUG)
|
||||
return logging.getLogger(path)
|
||||
|
||||
|
||||
def check_size(root):
|
||||
width = float(root.attrib['width'])
|
||||
height = float(root.attrib['height'])
|
||||
if not 400 < width < 500:
|
||||
logger.error("Width is outside of range: {}".format(width))
|
||||
if not 400 < height < 500:
|
||||
logger.error("Height is outside of range: {}".format(height))
|
||||
|
||||
|
||||
def check_layers(root):
|
||||
"""
|
||||
Check there are layers (well, groups) for the components we require.
|
||||
"""
|
||||
layer_ids = [g.attrib['id'] for g in root.iterfind('svg:g', ns)]
|
||||
|
||||
for layer in ["Device", "Buttons", "LEDs"]:
|
||||
if layer not in layer_ids:
|
||||
logger.error("Missing layer: {}".format(layer))
|
||||
|
||||
|
||||
def check_elements(root, prefix, required=0):
|
||||
"""
|
||||
Checks for elements of the form 'prefixN' in the root tag. Any elements
|
||||
found must be consecutive or an error is printed, i.e. if there's a
|
||||
'button8' there has to be a 'button7'.
|
||||
|
||||
If required is nonzero, an error is logged for any missing element with
|
||||
an index less than required.
|
||||
"""
|
||||
|
||||
# elements can be paths and rects
|
||||
# This includes leaders and lines
|
||||
element_ids = [p.attrib['id'] for p in root.xpath('//svg:path', namespaces=ns) if p.attrib['id'].startswith(prefix)]
|
||||
element_ids += [p.attrib['id'] for p in root.xpath('//svg:rect', namespaces=ns) if p.attrib['id'].startswith(prefix)]
|
||||
element_ids += [g.attrib['id'] for g in root.xpath('//svg:g', namespaces=ns) if g.attrib['id'].startswith(prefix)]
|
||||
|
||||
idx = 0
|
||||
highest = -1
|
||||
for idx in range(0, 20):
|
||||
e = '{}{}'.format(prefix, idx)
|
||||
if e in element_ids:
|
||||
highest = idx
|
||||
previous = '{}{}'.format(prefix, idx - 1)
|
||||
if idx > 0 and previous not in element_ids:
|
||||
logger.error("Non-consecutive {}: {}".format(prefix, e))
|
||||
|
||||
leader = '{}{}-leader'.format(prefix, idx)
|
||||
if leader not in element_ids:
|
||||
logger.error("Missing {} for {}".format(leader, e))
|
||||
else:
|
||||
element = root.xpath(style_query.format(leader, 'text-align'), namespaces=ns)
|
||||
if element is None or len(element) != 1 or element[0] is None:
|
||||
logger.error("Missing style property for {}".format(leader))
|
||||
|
||||
path = '{}{}-path'.format(prefix, idx)
|
||||
if path not in element_ids:
|
||||
logger.error("Missing {} for {}".format(path, e))
|
||||
elif idx < required:
|
||||
logger.error("Missing {}: {}".format(prefix, e))
|
||||
|
||||
logger.info("Found {} {}s".format(highest + 1, prefix))
|
||||
|
||||
|
||||
def check_leds(root):
|
||||
check_elements(root, "led")
|
||||
|
||||
|
||||
def check_buttons(root):
|
||||
check_elements(root, "button", 3)
|
||||
|
||||
|
||||
def check_svg(path):
|
||||
svg = etree.parse(path)
|
||||
root = svg.getroot()
|
||||
|
||||
check_size(root)
|
||||
check_layers(root)
|
||||
check_buttons(root)
|
||||
check_leds(root)
|
||||
|
||||
if __name__ == "__main__":
|
||||
success = True
|
||||
for path in sys.argv[1:]:
|
||||
logger = SVGLogger.get_logger(path)
|
||||
check_svg(path)
|
||||
if not logger.success:
|
||||
success = False
|
||||
|
||||
if not success:
|
||||
sys.exit(1)
|
||||
506
data/gnome/fallback.svg
Normal file
@@ -0,0 +1,506 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="450"
|
||||
height="450"
|
||||
viewBox="0 0 450.00001 450.00001"
|
||||
id="svg4844"
|
||||
version="1.1"
|
||||
inkscape:version="0.91 r13725"
|
||||
sodipodi:docname="fallback.svg">
|
||||
<defs
|
||||
id="defs4846" />
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="1.4"
|
||||
inkscape:cx="162.83067"
|
||||
inkscape:cy="254.74718"
|
||||
inkscape:document-units="px"
|
||||
inkscape:current-layer="Device"
|
||||
showgrid="false"
|
||||
units="px"
|
||||
inkscape:window-width="1920"
|
||||
inkscape:window-height="1101"
|
||||
inkscape:window-x="1920"
|
||||
inkscape:window-y="28"
|
||||
inkscape:window-maximized="1"
|
||||
showguides="true"
|
||||
inkscape:guide-bbox="true">
|
||||
<sodipodi:guide
|
||||
position="20.203051,215.1625"
|
||||
orientation="1,0"
|
||||
id="guide6533" />
|
||||
<sodipodi:guide
|
||||
position="263.64982,40.406102"
|
||||
orientation="0,1"
|
||||
id="guide6535" />
|
||||
<sodipodi:guide
|
||||
position="119.198,430.32499"
|
||||
orientation="0,1"
|
||||
id="guide6537" />
|
||||
</sodipodi:namedview>
|
||||
<metadata
|
||||
id="metadata4849">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
inkscape:groupmode="layer"
|
||||
id="Device"
|
||||
inkscape:label="Device"
|
||||
style="display:inline">
|
||||
<g
|
||||
id="mouse"
|
||||
transform="matrix(1.4157338,0,0,1.4150394,-15.907361,-83.397825)"
|
||||
inkscape:label="#g5682">
|
||||
<path
|
||||
sodipodi:nodetypes="csssssscssssccccccccsccccscccccccc"
|
||||
inkscape:connector-curvature="0"
|
||||
id="path5554"
|
||||
d="m 107.18942,257.50398 c -4.99714,2.43535 -12.465604,2.63664 -17.258052,-1.44306 -13.182502,-11.22196 -9.97511,-20.42755 -11.852724,-27.60442 -2.086919,-7.9769 -8.394971,-14.22057 -14.204755,-19.22015 -2.452298,-2.11032 -15.074169,-8.92571 -22.581405,-6.39459 -7.284157,2.45591 -8.927109,7.96865 -7.039536,13.91417 0.942265,2.96796 6.341731,12.02153 3.965931,13.71887 -6.197029,4.42735 -6.062903,-6.5818 -10.547143,-6.17694 -3.155437,2.60598 5.722132,16.20922 13.501397,8.54975 5.287042,-5.20562 -7.079343,-19.36707 -3.390295,-23.44484 9.484404,-10.48379 25.055087,3.37163 28.181213,6.1766 3.122791,2.80198 9.248496,8.52414 9.875553,20.12323 0.843858,15.60941 10.74282,34.96801 34.650426,29.65168 5.06065,14.01778 13.49867,22.70826 23.95424,24.35573 -0.73268,4.29744 8.14899,6.47132 -4.44275,21.19745 3.06561,2.85685 8.01758,11.19489 5.36011,25.42154 -5.7187,3.96316 -16.72683,16.45412 0.58015,5.39321 7.47117,-0.31027 14.12258,9.86529 24.83436,3.31115 -4.03605,-1.39212 -8.28293,-7.96174 -18.1528,-9.13334 -0.39969,-10.26297 -0.36143,-17.7796 5.94065,-24.85378 14.19011,-17.96422 10.92982,-12.10811 13.41925,-19.23937 2.48943,-7.13126 2.52109,-11.34 2.33441,-19.25558 -2.9569,-16.18074 -2.70058,-16.2775 -0.11605,-1.49727 16.61294,-0.76638 32.95879,-6.2945 39.23502,-17.29952 9.79039,-1.32985 22.51147,-7.39605 29.90276,0.56675 -5.22785,1.2715 -19.1955,26.95192 0.95314,7.4515 11.02869,-10.67388 23.99028,5.40711 27.28604,-12.1447 -31.80018,1.43261 -37.30275,-17.43649 -56.67811,-17.25445 -7.30408,-0.27416 -20.44309,-0.17002 -25.52504,9.24102 9.11653,-12.47147 0.88952,-27.94431 -1.51863,-41.85017 -15.02015,-21.13729 -30.18152,-29.86148 -43.79923,-20.54814 -13.65771,11.51411 -22.41864,26.83759 -23.4676,44.34506 -1.03036,11.6519 -3.29737,12.1189 -3.40046,33.94261 z"
|
||||
style="fill:#d3d3ce;fill-opacity:1;fill-rule:evenodd;stroke:#bfc2bb;stroke-width:2.11956239;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||
<path
|
||||
sodipodi:nodetypes="zcsccczzczz"
|
||||
inkscape:connector-curvature="0"
|
||||
id="button6"
|
||||
d="m 125.00072,147.3762 c -3.94854,2.46476 -1.91248,4.22271 -6.56842,3.47664 -6.04044,-0.49004 -12.10893,4.61986 -13.01838,8.83118 -1.05538,4.887 0.82228,9.01123 6.09563,9.60013 4.20528,0.52222 4.02895,-1.99743 6.87568,-2.5868 4.10235,6.95899 19.61805,11.70942 26.38361,11.76956 4.71763,-0.6919 4.81094,-3.03006 11.87015,-12.70472 7.05921,-9.67466 6.92045,-10.39092 6.98781,-15.5586 0.0674,-5.16768 5.35659,-7.43289 0.64282,-10.74954 -1.91632,-0.43449 -6.15926,0.21143 -17.24225,0.33896 -11.08299,0.12753 -18.07811,5.11843 -22.02665,7.58319 z"
|
||||
style="fill:#d3d3ce;fill-opacity:1;fill-rule:evenodd;stroke:#babdb6;stroke-width:2.11956239;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
inkscape:label="#path5399" />
|
||||
<path
|
||||
sodipodi:nodetypes="ccc"
|
||||
inkscape:connector-curvature="0"
|
||||
id="path5405"
|
||||
d="m 163.20277,150.23723 c -1.06521,-0.0557 -3.7617,0.42888 -4.65914,1.09722 -2,1.49899 -2.78079,2.58243 -4.28466,4.28408"
|
||||
style="fill:none;fill-rule:evenodd;stroke:#bfc2bb;stroke-width:0.70652068px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
|
||||
<path
|
||||
sodipodi:nodetypes="zszzcz"
|
||||
inkscape:connector-curvature="0"
|
||||
id="path5414"
|
||||
d="m 140.75099,145.17797 c -1.18229,0.40938 -2.17328,0.089 -3.548,0.54388 -1.29024,0.42688 -0.38888,1.67372 0.70446,2.31451 1.09334,0.64079 4.0134,-0.29332 5.06491,-1.10649 1.05151,-0.81317 1.6576,-2.35673 1.26243,-2.48934 -0.39517,-0.13262 -2.30151,0.32805 -3.4838,0.73744 z"
|
||||
style="fill:none;fill-rule:evenodd;stroke:#bfc2bb;stroke-width:0.70652068px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
|
||||
<path
|
||||
sodipodi:nodetypes="cscccccccccc"
|
||||
inkscape:connector-curvature="0"
|
||||
id="button4"
|
||||
d="m 78.728764,157.07155 c 2.729308,11.45367 -4.592785,23.20521 4.683418,32.67799 4.193755,4.28262 13.716552,5.67648 28.077598,4.49959 -16.964136,7.07876 -15.435974,11.82485 -18.038124,14.76602 -0.367398,1.93959 3.51961,2.8971 16.874634,15.52043 5.69621,-9.78547 8.32004,-20.52393 15.45362,-28.52298 15.91171,-4.8206 -2.52533,-22.7944 -2.52533,-22.7944 0,0 -6.14675,-4.9701 -9.92352,3.09571 -7.99103,-6.69016 -16.706109,-2.41957 -17.256932,4.64391 1.356748,-6.41288 0.152959,-21.95234 -2.71781,-27.4956 -9.538417,1.9887 -10.559123,3.86954 -14.594684,3.59772 -0.398494,-4.23259 11.719989,-4.91038 14.599568,-3.59704"
|
||||
style="fill:#d3d3ce;fill-opacity:1;fill-rule:evenodd;stroke:#bfc2bb;stroke-width:2.11956239;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
inkscape:label="#path5425" />
|
||||
<path
|
||||
sodipodi:nodetypes="sscscccs"
|
||||
inkscape:connector-curvature="0"
|
||||
id="path5459"
|
||||
d="m 170.57402,194.85052 c 1.27147,3.99383 5.43056,12.02629 7.61859,15.67135 1.67031,2.78261 3.12076,3.57306 4.37974,10.16536 3.35106,-2.36328 2.26625,-4.37687 7.86716,-6.63393 6.78116,-2.73268 10.74994,-17.14078 7.59325,-20.21486 -2.56921,-1.4377 -13.90652,-7.54721 -16.5961,-8.75778 -8.64652,-2.75344 -18.11595,-5.26303 -26.29721,-3.34848 9.47658,1.68644 14.2189,9.2998 15.43457,13.11834 z"
|
||||
style="fill:#babdb6;fill-opacity:1;fill-rule:evenodd;stroke:#babdb6;stroke-width:2.11956239;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||
<path
|
||||
sodipodi:nodetypes="cccczccszccccc"
|
||||
inkscape:connector-curvature="0"
|
||||
id="button5"
|
||||
d="m 156.57364,174.60716 c 0.61451,3.45259 -4.17141,8.40305 2.31606,7.85954 11.99907,4.07348 25.62973,4.1469 36.30113,11.66165 7.04625,4.94297 4.95335,13.00607 7.04625,4.94297 1.1521,-9.09961 -1.67322,-15.30143 -7.75899,-16.73475 -6.08578,-1.43332 -8.13701,-3.55535 -13.61967,-4.14262 -2.80249,-1.72124 -8.8609,-0.0129 -18.78998,0.48317 7.50071,-0.84183 14.47216,-0.73196 18.56074,-2.80565 0,0 6.30334,-9.54951 7.53958,-14.37709 1.23624,-4.82758 1.50074,-6.5184 3.27709,-10.38873 -4.42899,-1.01319 -7.07586,-3.6542 -10.44975,-4.61991 -2.18062,4.20089 -3.52881,8.12787 -6.83587,11.50939 -4.41968,6.55835 -8.29193,5.97237 -14.60181,12.79024 -0.89825,2.92739 -2.98478,3.82179 -2.98478,3.82179 z"
|
||||
style="fill:#d3d3ce;fill-opacity:1;fill-rule:evenodd;stroke:#babdb6;stroke-width:2.11956239;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
inkscape:label="#path5453" />
|
||||
<path
|
||||
sodipodi:nodetypes="ccccc"
|
||||
inkscape:connector-curvature="0"
|
||||
id="button2"
|
||||
d="m 129.85315,182.50093 c 3.6135,2.58802 10.74551,5.75132 14.60758,1.93282 0.45507,-2.97455 -0.19296,-6.87423 -0.19285,-7.3212 -7.27257,-0.13193 -16.12143,-4.19401 -22.95494,-6.35683 1.4347,5.55248 6.71272,10.53825 8.54021,11.74521 z"
|
||||
style="fill:#d3d3ce;fill-opacity:1;fill-rule:evenodd;stroke:#bfc2bb;stroke-width:2.11956239;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
inkscape:label="#path5540" />
|
||||
<path
|
||||
sodipodi:nodetypes="cccc"
|
||||
inkscape:connector-curvature="0"
|
||||
id="button3"
|
||||
d="m 147.13503,177.00627 c 1.16519,3.28142 3.63994,3.84875 5.91906,6.18906 4.77775,-2.47336 5.12452,-13.43108 3.9723,-16.57185 -3.79251,3.28442 -5.96683,8.30504 -9.89136,10.38279 z"
|
||||
style="fill:#d3d3ce;fill-opacity:1;fill-rule:evenodd;stroke:#bfc2bb;stroke-width:2.11956239;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
inkscape:label="#path5547" />
|
||||
<path
|
||||
sodipodi:nodetypes="ccccc"
|
||||
inkscape:connector-curvature="0"
|
||||
id="button7"
|
||||
d="m 96.280703,132.06305 c 0,0 58.294677,-1.61611 100.929457,-0.83206 -1.27875,-12.91598 2.4481,-38.633128 2.05831,-56.889372 -46.40187,1.475128 -77.8249,2.200365 -105.250613,1.551238 4.495692,30.284264 2.262846,56.170194 2.262846,56.170194 z"
|
||||
style="fill:#d3d3ce;fill-opacity:1;fill-rule:evenodd;stroke:#bfc2bb;stroke-width:2.11956239;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
inkscape:label="#path5566" />
|
||||
<path
|
||||
sodipodi:nodetypes="cscsccsccscsccccc"
|
||||
inkscape:connector-curvature="0"
|
||||
id="button0"
|
||||
d="m 82.544643,155.53571 c 0.305172,-3.31535 0.980416,-11.89491 2.489066,-14.57767 2.810136,-4.99714 6.565433,-8.72285 8.454552,-11.91369 2.686043,-3.2364 2.701225,-4.20604 4.184853,-5.44313 1.47935,-1.23353 7.182396,-9.27661 8.097236,-8.77569 1.51464,3.42922 -5.03984,11.03401 -6.93589,13.34978 2.62462,-2.24644 4.10033,-4.85435 7.49772,-7.85092 3.00882,-2.65384 6.26227,-2.5427 3.72007,0.68937 -2.64048,3.02394 -3.55215,4.11719 -8.76065,8.25327 10.88502,-8.17285 19.09259,-9.06063 9.30462,-2.01748 -1.40825,1.01334 -8.4791,4.08043 -5.58663,2.88614 2.72294,-0.18651 10.84559,-2.68876 10.05588,-0.49162 -1.65227,4.59693 -8.23017,2.61804 -12.09164,4.12386 -2.17312,2.61683 -5.158266,3.64905 -7.879445,5.87814 -1.853363,2.41097 -3.914211,8.13746 -5.08138,13.723 -0.977626,0.29825 -5.450462,1.56098 -7.468362,2.16661 z"
|
||||
style="fill:#d3d3ce;fill-opacity:1;fill-rule:evenodd;stroke:#bfc2bb;stroke-width:1.41304147;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
inkscape:label="#path5561" />
|
||||
<text
|
||||
sodipodi:linespacing="100%"
|
||||
id="text5583"
|
||||
y="117.5"
|
||||
x="110.17857"
|
||||
style="font-style:italic;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:12px;line-height:100%;font-family:sans-serif;-inkscape-font-specification:'sans-serif Italic';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#bfc2bb;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
xml:space="preserve"><tspan
|
||||
style="font-style:italic;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:40px;font-family:sans-serif;-inkscape-font-specification:'sans-serif Italic';fill:#bfc2bb;fill-opacity:1"
|
||||
y="117.5"
|
||||
x="110.17857"
|
||||
id="tspan5585"
|
||||
sodipodi:role="line">404</tspan></text>
|
||||
<path
|
||||
sodipodi:nodetypes="cccccsscssccccc"
|
||||
inkscape:connector-curvature="0"
|
||||
id="button1"
|
||||
d="m 183.97321,147.27678 c 3.33335,-1.48288 3.09826,-6.77076 3.85156,-9.86053 -0.35674,-3.91061 0.37686,-5.05433 -1.93804,-6.90092 -2.10346,-1.08198 -0.13041,-3.85244 1.93457,-2.9861 2.92925,1.60616 0.94495,6.22838 4.12041,7.61394 0,0 1.87775,-1.15731 1.99206,-3.40725 0.1301,-2.56065 -1.15427,-11.79601 1.03251,-13.08991 0.96059,-0.56838 1.75458,9.82486 2.96125,11.86818 -0.30586,-2.13132 -0.65718,-12.83967 0.19291,-12.16594 3.65618,2.89768 1.37042,11.98208 3.4547,14.61683 1.72735,2.18354 -3.64795,6.53893 -6.93051,11.03314 -2.12109,2.77912 -2.89583,2.76412 -4.9476,6.04875 -2.40971,-1.47777 -3.69229,-1.95944 -5.72384,-2.77019 l 0,0 z"
|
||||
style="fill:#d3d3ce;fill-opacity:1;fill-rule:evenodd;stroke:#bfc2bb;stroke-width:1.41304147;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
inkscape:label="#path5587" />
|
||||
<path
|
||||
style="fill:#d3d3ce;fill-opacity:1;fill-rule:evenodd;stroke:#bfc2bb;stroke-width:3.02452755;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 129.71002,288.41558 c -7.1173,2.84692 -18.1026,3.61499 -24.6415,-2.32569 C 86.783262,269.47748 90.830889,256.94793 88.150941,246.7094 85.172248,235.32955 76.168664,226.42233 67.876267,219.28992 64.376063,216.27934 46.360664,206.5565 35.645466,210.16739 25.248672,213.671 22.903661,221.53548 25.597824,230.01736 c 1.34491,4.23409 9.051654,17.14992 5.660636,19.57135 -8.845118,6.31606 -8.653678,-9.3896 -15.054105,-8.81203 -4.503806,3.71769 8.16729,23.12409 19.27076,12.19708 7.546279,-7.42634 -10.10446,-27.62907 -4.839023,-33.44642 13.537242,-14.95619 35.761527,4.80997 40.223496,8.81154 4.45721,3.9973 13.200527,12.16054 14.095535,28.70781 1.204452,22.2684 15.333397,49.88539 49.444437,42.2623 -0.73591,-2.53682 -4.15602,-6.43263 -4.68954,-10.89341 z"
|
||||
id="led0"
|
||||
transform="matrix(0.7006157,0,0,0.70096699,16.318711,55.521354)"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="csssssscsssscc"
|
||||
inkscape:label="#path6431" />
|
||||
<path
|
||||
style="fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#bfc2bb;stroke-width:3.02452755;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 169.91186,400.60038 c -8.16239,5.65385 -23.87447,23.47346 0.82806,7.69396 10.66372,-0.44263 20.15739,14.07383 35.44648,4.72369 -5.76072,-1.986 -11.82236,-11.35822 -25.88738,-13.10742 -3.01274,0.0336 -8.44501,-0.32858 -10.38716,0.68977 z"
|
||||
id="path6437"
|
||||
transform="matrix(0.7006157,0,0,0.70096699,16.318711,55.521354)"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="ccccc" />
|
||||
</g>
|
||||
<path
|
||||
inkscape:label="#path6478"
|
||||
style="fill:#d3d3ce;fill-opacity:1;fill-rule:evenodd;stroke:#bfc2bb;stroke-width:3.00000024;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 175.72866,392.52094 c -8.09615,5.60803 -23.68073,23.28322 0.82135,7.6316 10.57718,-0.43903 19.9938,13.95978 35.15883,4.68542 -5.71397,-1.96992 -11.72643,-11.26617 -25.67731,-13.0012 -2.98831,0.0334 -8.37648,-0.32592 -10.30287,0.68418 z"
|
||||
id="led1"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="ccccc" />
|
||||
<path
|
||||
sodipodi:nodetypes="csccc"
|
||||
inkscape:connector-curvature="0"
|
||||
id="led2"
|
||||
d="m 314.43906,276.47676 c -7.40123,1.79921 -27.17571,38.13802 1.3494,10.54417 15.61369,-15.10398 33.96384,7.65126 38.62976,-17.18524 -11.69141,0.52644 -20.87204,-0.88448 -28.52139,-3.25631 -0.91845,1.9989 -7.62356,10.08149 -11.45777,9.89738 z"
|
||||
style="fill:#d3d3ce;fill-opacity:1;fill-rule:evenodd;stroke:#bfc2bb;stroke-width:3.00000024;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||
</g>
|
||||
<g
|
||||
inkscape:groupmode="layer"
|
||||
id="Buttons"
|
||||
inkscape:label="Buttons"
|
||||
style="display:inline">
|
||||
<g
|
||||
style="display:inline"
|
||||
id="button1-path"
|
||||
inkscape:label="#g131"
|
||||
transform="translate(12.063466,68.669278)">
|
||||
<path
|
||||
sodipodi:nodetypes="cc"
|
||||
style="color:#000000;overflow:visible;opacity:1;fill:none;fill-opacity:1;stroke:#888a85;stroke-width:1;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal"
|
||||
d="m 282.94764,50.505764 154.05236,0"
|
||||
id="path958"
|
||||
inkscape:connector-curvature="0" />
|
||||
<rect
|
||||
style="color:#000000;overflow:visible;opacity:1;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:2;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal"
|
||||
id="rect968"
|
||||
width="6.999999"
|
||||
height="6.999999"
|
||||
x="277"
|
||||
y="47.005764" />
|
||||
<rect
|
||||
inkscape:label="#rect867"
|
||||
style="color:#000000;text-align:start;overflow:visible;fill:#888a85;fill-opacity:1;stroke:none;stroke-linecap:round"
|
||||
id="button1-leader"
|
||||
width="1"
|
||||
height="1"
|
||||
x="437"
|
||||
y="50.005764" />
|
||||
</g>
|
||||
<g
|
||||
transform="translate(12.063466,28.669278)"
|
||||
inkscape:label="#g131"
|
||||
id="button0-path"
|
||||
style="display:inline">
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
id="path5628"
|
||||
d="m 282.94764,50.505764 154.05236,0"
|
||||
style="color:#000000;overflow:visible;opacity:1;fill:none;fill-opacity:1;stroke:#888a85;stroke-width:1;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal"
|
||||
sodipodi:nodetypes="cc" />
|
||||
<rect
|
||||
y="47.005764"
|
||||
x="277"
|
||||
height="6.999999"
|
||||
width="6.999999"
|
||||
id="rect5630"
|
||||
style="color:#000000;overflow:visible;opacity:1;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:2;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal" />
|
||||
<rect
|
||||
y="50.005764"
|
||||
x="437"
|
||||
height="1"
|
||||
width="1"
|
||||
id="button0-leader"
|
||||
style="color:#000000;text-align:start;overflow:visible;fill:#888a85;fill-opacity:1;stroke:none;stroke-linecap:round"
|
||||
inkscape:label="#rect867" />
|
||||
</g>
|
||||
<g
|
||||
transform="translate(12.063466,148.66928)"
|
||||
inkscape:label="#g131"
|
||||
id="button3-path"
|
||||
style="display:inline">
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
id="path5636"
|
||||
d="m 282.94764,50.505764 154.05236,0"
|
||||
style="color:#000000;overflow:visible;opacity:1;fill:none;fill-opacity:1;stroke:#888a85;stroke-width:1;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal"
|
||||
sodipodi:nodetypes="cc" />
|
||||
<rect
|
||||
y="47.005764"
|
||||
x="277"
|
||||
height="6.999999"
|
||||
width="6.999999"
|
||||
id="rect5638"
|
||||
style="color:#000000;overflow:visible;opacity:1;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:2;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal" />
|
||||
<rect
|
||||
y="50.005764"
|
||||
x="437"
|
||||
height="1"
|
||||
width="1"
|
||||
id="button3-leader"
|
||||
style="color:#000000;text-align:start;overflow:visible;fill:#888a85;fill-opacity:1;stroke:none;stroke-linecap:round"
|
||||
inkscape:label="#rect867" />
|
||||
</g>
|
||||
<g
|
||||
style="display:inline"
|
||||
id="button2-path"
|
||||
inkscape:label="#g131"
|
||||
transform="translate(12.063466,108.66928)">
|
||||
<path
|
||||
sodipodi:nodetypes="cc"
|
||||
style="color:#000000;overflow:visible;opacity:1;fill:none;fill-opacity:1;stroke:#888a85;stroke-width:1;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal"
|
||||
d="m 282.94764,50.505764 154.05236,0"
|
||||
id="path5644"
|
||||
inkscape:connector-curvature="0" />
|
||||
<rect
|
||||
style="color:#000000;overflow:visible;opacity:1;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:2;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal"
|
||||
id="rect5646"
|
||||
width="6.999999"
|
||||
height="6.999999"
|
||||
x="277"
|
||||
y="47.005764" />
|
||||
<rect
|
||||
inkscape:label="#rect867"
|
||||
style="color:#000000;text-align:start;overflow:visible;fill:#888a85;fill-opacity:1;stroke:none;stroke-linecap:round"
|
||||
id="button2-leader"
|
||||
width="1"
|
||||
height="1"
|
||||
x="437"
|
||||
y="50.005764" />
|
||||
</g>
|
||||
<g
|
||||
transform="translate(12.063466,228.66928)"
|
||||
inkscape:label="#g131"
|
||||
id="button5-path"
|
||||
style="display:inline">
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
id="path5652"
|
||||
d="m 282.94764,50.505764 154.05236,0"
|
||||
style="color:#000000;overflow:visible;opacity:1;fill:none;fill-opacity:1;stroke:#888a85;stroke-width:1;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal"
|
||||
sodipodi:nodetypes="cc" />
|
||||
<rect
|
||||
y="47.005764"
|
||||
x="277"
|
||||
height="6.999999"
|
||||
width="6.999999"
|
||||
id="rect5654"
|
||||
style="color:#000000;overflow:visible;opacity:1;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:2;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal" />
|
||||
<rect
|
||||
y="50.005764"
|
||||
x="437"
|
||||
height="1"
|
||||
width="1"
|
||||
id="button5-leader"
|
||||
style="color:#000000;text-align:start;overflow:visible;fill:#888a85;fill-opacity:1;stroke:none;stroke-linecap:round"
|
||||
inkscape:label="#rect867" />
|
||||
</g>
|
||||
<g
|
||||
style="display:inline"
|
||||
id="button4-path"
|
||||
inkscape:label="#g131"
|
||||
transform="translate(12.063466,188.66928)">
|
||||
<path
|
||||
sodipodi:nodetypes="cc"
|
||||
style="color:#000000;overflow:visible;opacity:1;fill:none;fill-opacity:1;stroke:#888a85;stroke-width:1;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal"
|
||||
d="m 282.94764,50.505764 154.05236,0"
|
||||
id="path5660"
|
||||
inkscape:connector-curvature="0" />
|
||||
<rect
|
||||
style="color:#000000;overflow:visible;opacity:1;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:2;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal"
|
||||
id="rect5662"
|
||||
width="6.999999"
|
||||
height="6.999999"
|
||||
x="277"
|
||||
y="47.005764" />
|
||||
<rect
|
||||
inkscape:label="#rect867"
|
||||
style="color:#000000;text-align:start;overflow:visible;fill:#888a85;fill-opacity:1;stroke:none;stroke-linecap:round"
|
||||
id="button4-leader"
|
||||
width="1"
|
||||
height="1"
|
||||
x="437"
|
||||
y="50.005764" />
|
||||
</g>
|
||||
<g
|
||||
style="display:inline"
|
||||
id="button7-path"
|
||||
inkscape:label="#g131"
|
||||
transform="translate(12.063466,308.66928)">
|
||||
<path
|
||||
sodipodi:nodetypes="cc"
|
||||
style="color:#000000;overflow:visible;opacity:1;fill:none;fill-opacity:1;stroke:#888a85;stroke-width:1;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal"
|
||||
d="m 282.94764,50.505764 154.05236,0"
|
||||
id="path5668"
|
||||
inkscape:connector-curvature="0" />
|
||||
<rect
|
||||
style="color:#000000;overflow:visible;opacity:1;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:2;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal"
|
||||
id="rect5670"
|
||||
width="6.999999"
|
||||
height="6.999999"
|
||||
x="277"
|
||||
y="47.005764" />
|
||||
<rect
|
||||
inkscape:label="#rect867"
|
||||
style="color:#000000;text-align:start;overflow:visible;fill:#888a85;fill-opacity:1;stroke:none;stroke-linecap:round"
|
||||
id="button7-leader"
|
||||
width="1"
|
||||
height="1"
|
||||
x="437"
|
||||
y="50.005764" />
|
||||
</g>
|
||||
<g
|
||||
transform="translate(12.063466,268.66928)"
|
||||
inkscape:label="#g131"
|
||||
id="button6-path"
|
||||
style="display:inline">
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
id="path5676"
|
||||
d="m 282.94764,50.505764 154.05236,0"
|
||||
style="color:#000000;overflow:visible;opacity:1;fill:none;fill-opacity:1;stroke:#888a85;stroke-width:1;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal"
|
||||
sodipodi:nodetypes="cc" />
|
||||
<rect
|
||||
y="47.005764"
|
||||
x="277"
|
||||
height="6.999999"
|
||||
width="6.999999"
|
||||
id="rect5678"
|
||||
style="color:#000000;overflow:visible;opacity:1;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:2;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal" />
|
||||
<rect
|
||||
y="50.005764"
|
||||
x="437"
|
||||
height="1"
|
||||
width="1"
|
||||
id="button6-leader"
|
||||
style="color:#000000;text-align:start;overflow:visible;fill:#888a85;fill-opacity:1;stroke:none;stroke-linecap:round"
|
||||
inkscape:label="#rect867" />
|
||||
</g>
|
||||
</g>
|
||||
<g
|
||||
inkscape:groupmode="layer"
|
||||
id="LEDs"
|
||||
inkscape:label="LEDs">
|
||||
<g
|
||||
style="display:inline"
|
||||
id="led0-path"
|
||||
inkscape:label="#g131"
|
||||
transform="translate(12.063466,28.669278)">
|
||||
<path
|
||||
sodipodi:nodetypes="cc"
|
||||
style="color:#000000;overflow:visible;opacity:1;fill:none;fill-opacity:1;stroke:#888a85;stroke-width:1;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal"
|
||||
d="m 282.94764,50.505764 154.05236,0"
|
||||
id="path5785"
|
||||
inkscape:connector-curvature="0" />
|
||||
<rect
|
||||
style="color:#000000;overflow:visible;opacity:1;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:2;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal"
|
||||
id="rect5787"
|
||||
width="6.999999"
|
||||
height="6.999999"
|
||||
x="277"
|
||||
y="47.005764" />
|
||||
<rect
|
||||
inkscape:label="#rect867"
|
||||
style="color:#000000;text-align:start;overflow:visible;fill:#888a85;fill-opacity:1;stroke:none;stroke-linecap:round"
|
||||
id="led0-leader"
|
||||
width="1"
|
||||
height="1"
|
||||
x="437"
|
||||
y="50.005764" />
|
||||
</g>
|
||||
<g
|
||||
transform="translate(12.063466,68.669278)"
|
||||
inkscape:label="#g131"
|
||||
id="led1-path"
|
||||
style="display:inline">
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
id="path5797"
|
||||
d="m 282.94764,50.505764 154.05236,0"
|
||||
style="color:#000000;overflow:visible;opacity:1;fill:none;fill-opacity:1;stroke:#888a85;stroke-width:1;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal"
|
||||
sodipodi:nodetypes="cc" />
|
||||
<rect
|
||||
y="47.005764"
|
||||
x="277"
|
||||
height="6.999999"
|
||||
width="6.999999"
|
||||
id="rect5799"
|
||||
style="color:#000000;overflow:visible;opacity:1;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:2;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal" />
|
||||
<rect
|
||||
y="50.005764"
|
||||
x="437"
|
||||
height="1"
|
||||
width="1"
|
||||
id="led1-leader"
|
||||
style="color:#000000;text-align:start;overflow:visible;fill:#888a85;fill-opacity:1;stroke:none;stroke-linecap:round"
|
||||
inkscape:label="#rect867" />
|
||||
</g>
|
||||
<g
|
||||
style="display:inline"
|
||||
id="led2-path"
|
||||
inkscape:label="#g131"
|
||||
transform="translate(12.063466,108.66928)">
|
||||
<path
|
||||
sodipodi:nodetypes="cc"
|
||||
style="color:#000000;overflow:visible;opacity:1;fill:none;fill-opacity:1;stroke:#888a85;stroke-width:1;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal"
|
||||
d="m 282.94764,50.505764 154.05236,0"
|
||||
id="path6411"
|
||||
inkscape:connector-curvature="0" />
|
||||
<rect
|
||||
style="color:#000000;overflow:visible;opacity:1;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:2;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal"
|
||||
id="rect6413"
|
||||
width="6.999999"
|
||||
height="6.999999"
|
||||
x="277"
|
||||
y="47.005764" />
|
||||
<rect
|
||||
inkscape:label="#rect867"
|
||||
style="color:#000000;text-align:start;overflow:visible;fill:#888a85;fill-opacity:1;stroke:none;stroke-linecap:round"
|
||||
id="led2-leader"
|
||||
width="1"
|
||||
height="1"
|
||||
x="437"
|
||||
y="50.005764" />
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 31 KiB |
514
data/gnome/logitech-g300.svg
Normal file
@@ -0,0 +1,514 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="490"
|
||||
height="490"
|
||||
viewBox="0 0 129.64583 129.64583"
|
||||
version="1.1"
|
||||
id="svg8"
|
||||
sodipodi:docname="logitech-g300.svg"
|
||||
inkscape:version="0.92.2 (5c3e80d, 2017-08-06)">
|
||||
<defs
|
||||
id="defs2" />
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="1.4142136"
|
||||
inkscape:cx="202.78034"
|
||||
inkscape:cy="279.63686"
|
||||
inkscape:document-units="px"
|
||||
inkscape:current-layer="LEDs"
|
||||
inkscape:document-rotation="0"
|
||||
showgrid="false"
|
||||
showguides="false"
|
||||
inkscape:window-width="1920"
|
||||
inkscape:window-height="1163"
|
||||
inkscape:window-x="1920"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-maximized="1"
|
||||
showborder="true"
|
||||
inkscape:guide-bbox="true"
|
||||
units="px"
|
||||
inkscape:snap-global="false"
|
||||
inkscape:measure-start="200.26,379.645"
|
||||
inkscape:measure-end="199.294,334.274">
|
||||
<inkscape:grid
|
||||
type="xygrid"
|
||||
id="grid78" />
|
||||
<sodipodi:guide
|
||||
position="58.722772,112.40709"
|
||||
orientation="0,1"
|
||||
id="guide79"
|
||||
inkscape:locked="false" />
|
||||
<sodipodi:guide
|
||||
position="39.611923,100.54373"
|
||||
orientation="0,1"
|
||||
id="guide81"
|
||||
inkscape:locked="false" />
|
||||
<sodipodi:guide
|
||||
position="51.756014,88.614617"
|
||||
orientation="0,1"
|
||||
id="guide83"
|
||||
inkscape:locked="false" />
|
||||
<sodipodi:guide
|
||||
position="57.778386,76.729167"
|
||||
orientation="0,1"
|
||||
id="guide85"
|
||||
inkscape:locked="false" />
|
||||
<sodipodi:guide
|
||||
position="45.047078,64.795712"
|
||||
orientation="0,1"
|
||||
inkscape:locked="false"
|
||||
id="guide87" />
|
||||
<sodipodi:guide
|
||||
position="57.646696,52.899321"
|
||||
orientation="0,1"
|
||||
id="guide89"
|
||||
inkscape:locked="false" />
|
||||
</sodipodi:namedview>
|
||||
<metadata
|
||||
id="metadata5">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title />
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
inkscape:groupmode="layer"
|
||||
id="Device"
|
||||
inkscape:label="Device"
|
||||
style="display:inline;opacity:1"
|
||||
transform="translate(0,-167.35416)">
|
||||
<path
|
||||
id="path41-6"
|
||||
style="display:inline;opacity:1;fill:#d3d3ce;fill-opacity:1;stroke:#babdb6;stroke-width:0.98645592;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 64.822903,179.22931 h -3.479995 l -3.915,-6.09 c 0,0 -11.305381,-0.13059 -17.399991,5.22 0,0 -8.990317,5.04814 -8.69995,26.96998 0,0 -0.262683,13.22939 2.609964,26.96999 -8.15696,17.08865 -6.959951,19.57498 -6.959951,19.57498 3.486257,28.75756 24.359929,38.27998 24.359929,38.27998 4.318847,1.41447 22.65114,1.41447 26.969986,0 0,0 20.873694,-9.52242 24.359955,-38.27998 0,0 1.19699,-2.48633 -6.959957,-19.57498 2.87265,-13.7406 2.609996,-26.96999 2.609996,-26.96999 0.290352,-21.92184 -8.700007,-26.96998 -8.700007,-26.96998 -6.094602,-5.35059 -17.399985,-5.22 -17.399985,-5.22 l -3.914995,6.09 h -3.479999"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="cccccccccccccccc" />
|
||||
<path
|
||||
style="fill:#eeeeec;fill-opacity:1;stroke:#babdb6;stroke-width:0.61653525;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 55.252905,176.68083 4.35,6.95997 h 10.439993 l 4.349999,-6.95997 c 0,0 4.713304,-0.60703 13.049968,4.34999 0,0 5.4795,2.46746 6.960015,18.26998 0,0 0.682398,10.45737 -0.869997,20.88 -6.631477,30.71466 -9.233113,35.45823 -12.179994,44.36996 -0.0055,0.3105 -0.606568,3.30574 -2.609998,12.17998 0,0 -1.945797,7.04942 -13.919989,6.96001 -13.44865,0.0748 -13.919991,-6.96001 -13.919991,-6.96001 -1.238296,-8.85308 -14.879861,-47.03985 -14.789987,-56.54994 0,0 -1.799981,-15.15662 -0.869993,-20.88 0,0 1.16252,-13.31705 6.089986,-18.26998 8.388589,-5.24851 13.919988,-4.34999 13.919988,-4.34999 z"
|
||||
id="path4607"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="ccccccccccccccc" />
|
||||
<path
|
||||
style="fill:none;stroke:#babdb6;stroke-width:0.61653525;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 64.822903,183.6408 c -0.06118,25.29724 0,55.68 0,55.68 v 0"
|
||||
id="path4530"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="ccc" />
|
||||
<path
|
||||
style="display:inline;fill:#d9dad7;fill-opacity:1;stroke:#babdb6;stroke-width:0.61653525;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 93.967914,196.69083 c 0,0 -3.141541,-12.93515 -4.350032,-13.05003 -2.701088,1.93408 -2.614239,2.22922 -4.349992,4.35002 2.394025,7.89236 3.479995,9.57001 3.479995,9.57001 z"
|
||||
id="button6"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="ccccc"
|
||||
inkscape:label="#path4541-3" />
|
||||
<rect
|
||||
style="fill:#d9dad7;fill-opacity:1;stroke:#babdb6;stroke-width:0.61653525;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
id="button2"
|
||||
width="8.6999846"
|
||||
height="14.789989"
|
||||
x="60.472919"
|
||||
y="189.29581"
|
||||
ry="3.9149992"
|
||||
inkscape:label="#rect4615" />
|
||||
<path
|
||||
style="fill:#eeeeec;fill-opacity:1;stroke:#babdb6;stroke-width:0.61653525;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 44.286958,270.37954 c -1.184921,4.53183 -5.479801,5.02739 -9.331541,1.1532 -3.062052,-4.76909 -6.934437,-16.17092 -6.816123,-19.86098 0.118269,-3.69003 1.372851,-5.59065 5.281209,-14.91112 1.954179,-4.66034 1.9368,-3.20903 2.958075,0.49871 1.190396,4.32175 9.093304,28.58842 7.90838,33.12019 z"
|
||||
id="path4617"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="zczssz" />
|
||||
<path
|
||||
sodipodi:type="arc"
|
||||
style="display:inline;fill:none;fill-opacity:0.39215686;stroke:#babdb6;stroke-width:2.08971024;stroke-linecap:square;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
id="led0-5"
|
||||
sodipodi:cx="64.773148"
|
||||
sodipodi:cy="257.64056"
|
||||
sodipodi:rx="3.7614744"
|
||||
sodipodi:ry="3.7614779"
|
||||
d="m 67.432912,254.9808 a 3.7614744,3.7614779 0 0 1 0,5.31953 3.7614744,3.7614779 0 0 1 -5.319528,0 3.7614744,3.7614779 0 0 1 -1e-6,-5.31953"
|
||||
sodipodi:start="5.4977871"
|
||||
sodipodi:end="3.9269907"
|
||||
sodipodi:open="true"
|
||||
sodipodi:arc-type="arc" />
|
||||
<path
|
||||
style="display:inline;opacity:1;fill:#eeeeec;fill-opacity:1;stroke:#babdb6;stroke-width:0.61653525;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 85.335258,270.71558 c 1.18491,4.53186 5.479785,5.02738 9.331555,1.15324 3.062033,-4.76913 6.934417,-16.17102 6.816127,-19.86101 -0.11829,-3.69003 -1.37286,-5.59071 -5.281228,-14.91121 -1.95418,-4.66025 -1.936795,-3.20892 -2.95807,0.49877 -1.190396,4.32176 -9.093291,28.58839 -7.908384,33.12021 z"
|
||||
id="path4617-5"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="zczssz" />
|
||||
<path
|
||||
style="display:inline;opacity:1;fill:#d9dad7;fill-opacity:1;stroke:#babdb6;stroke-width:0.61653525;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 93.967914,214.09081 c 0.815935,-16.75448 0,-17.39998 0,-17.39998 l -5.220029,0.87 c 0,0 0.239252,0.36327 -0.870008,12.17998 6.651607,6.71191 6.090037,4.35 6.090037,4.35 z"
|
||||
id="button5"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="ccccc"
|
||||
inkscape:label="#path4541-3-3" />
|
||||
<path
|
||||
style="display:inline;opacity:1;fill:#d9dad7;fill-opacity:1;stroke:#babdb6;stroke-width:0.61653525;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 35.737567,196.69083 c 0,0 3.141541,-12.93515 4.350032,-13.05003 2.701088,1.93408 2.614239,2.22922 4.349992,4.35002 -2.394025,7.89236 -3.479995,9.57001 -3.479995,9.57001 z"
|
||||
id="button4"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="ccccc"
|
||||
inkscape:label="#path4541-3-5" />
|
||||
<path
|
||||
style="display:inline;opacity:1;fill:#d9dad7;fill-opacity:1;stroke:#babdb6;stroke-width:0.61653525;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 35.737567,214.09081 c -0.815935,-16.75448 0,-17.39998 0,-17.39998 l 5.220029,0.87 c 0,0 -0.239252,0.36327 0.870008,12.17998 -6.651607,6.71191 -6.090037,4.35 -6.090037,4.35 z"
|
||||
id="button3"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="ccccc"
|
||||
inkscape:label="#path4541-3-3-6" />
|
||||
<path
|
||||
style="display:inline;opacity:1;fill:#d3d3ce;fill-opacity:1;stroke:#babdb6;stroke-width:0.61653525;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 60.426305,217.35644 v -6.74249 c -0.01103,-1.73802 1.304999,-1.74 1.304999,-1.74 h 6.089995 c 0,0 1.352705,0.0157 1.304999,1.74 v 6.74249 z"
|
||||
id="button8"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="ccccccc"
|
||||
inkscape:label="#path4589-9" />
|
||||
<path
|
||||
style="display:inline;opacity:1;fill:#d3d3ce;fill-opacity:1;stroke:#babdb6;stroke-width:0.61653525;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 60.426305,217.35644 v 6.74249 c -0.01103,1.73802 1.304999,1.74 1.304999,1.74 H 67.8213 c 0,0 1.352705,-0.0157 1.304998,-1.74 v -6.74249 z"
|
||||
id="button7"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="ccccccc"
|
||||
inkscape:label="#path4589-9-1" />
|
||||
<path
|
||||
style="fill:#eeeeec;fill-opacity:1;stroke:none;stroke-width:0.26458332px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="m 46.143947,189.21374 -3.642001,8.50625 1.101002,10.95189 16.221334,-7.70159 -0.921076,-16.08486 z"
|
||||
id="button0"
|
||||
inkscape:connector-curvature="0"
|
||||
inkscape:label="#path3664"
|
||||
sodipodi:nodetypes="cccccc" />
|
||||
<path
|
||||
style="fill:#eeeeec;fill-opacity:1;stroke:none;stroke-width:0.26458332px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="m 70.954987,185.09032 -1.109402,16.05391 16.940367,7.82608 0.477526,-11.0865 -3.352352,-9.32016 z"
|
||||
id="button1"
|
||||
inkscape:connector-curvature="0"
|
||||
inkscape:label="#path4486"
|
||||
sodipodi:nodetypes="cccccc" />
|
||||
</g>
|
||||
<g
|
||||
inkscape:groupmode="layer"
|
||||
id="Buttons"
|
||||
inkscape:label="Buttons"
|
||||
transform="translate(0,-2.6458338)"
|
||||
style="display:inline">
|
||||
<g
|
||||
transform="matrix(-0.28471359,0,0,-0.26458333,70.320391,74.101432)"
|
||||
style="display:inline;opacity:1"
|
||||
id="button4-path"
|
||||
inkscape:label="#g151">
|
||||
<path
|
||||
sodipodi:nodetypes="ccc"
|
||||
inkscape:connector-curvature="0"
|
||||
id="path964"
|
||||
d="m 109.31232,181.51438 38.69266,43.39973 h 98.98144"
|
||||
style="color:#000000;overflow:visible;opacity:1;vector-effect:none;fill:none;fill-opacity:1;stroke:#888a85;stroke-width:0.99999994;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal" />
|
||||
<rect
|
||||
inkscape:label="#rect875"
|
||||
style="color:#000000;text-align:end;overflow:visible;vector-effect:none;fill:#888a85;fill-opacity:1;stroke:none;stroke-linecap:round"
|
||||
id="button4-leader"
|
||||
width="1"
|
||||
height="1"
|
||||
x="245.98642"
|
||||
y="223.91411" />
|
||||
<rect
|
||||
y="177"
|
||||
x="105"
|
||||
height="6.999999"
|
||||
width="6.999999"
|
||||
id="rect974"
|
||||
style="color:#000000;overflow:visible;opacity:1;vector-effect:none;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:2;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal" />
|
||||
</g>
|
||||
<g
|
||||
transform="matrix(-0.30394757,0,0,0.26458333,100.78231,-2.4556928)"
|
||||
style="display:inline"
|
||||
id="button0-path"
|
||||
inkscape:label="#g141">
|
||||
<path
|
||||
sodipodi:nodetypes="cccc"
|
||||
inkscape:connector-curvature="0"
|
||||
id="path960"
|
||||
d="m 331.57794,109.27355 -66.76739,-0.0347 -34.51493,21.26646 h -68.95164"
|
||||
style="color:#000000;overflow:visible;opacity:1;vector-effect:none;fill:none;fill-opacity:1;stroke:#888a85;stroke-width:1;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal" />
|
||||
<rect
|
||||
y="127.00576"
|
||||
x="157"
|
||||
height="6.999999"
|
||||
width="6.999999"
|
||||
id="rect970"
|
||||
style="color:#000000;overflow:visible;opacity:1;vector-effect:none;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:2;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal" />
|
||||
<rect
|
||||
inkscape:label="#rect871"
|
||||
style="color:#000000;text-align:end;overflow:visible;vector-effect:none;fill:#888a85;fill-opacity:1;stroke:none;stroke-linecap:round"
|
||||
id="button0-leader"
|
||||
width="1"
|
||||
height="1"
|
||||
x="330.57794"
|
||||
y="108.28136" />
|
||||
</g>
|
||||
<g
|
||||
transform="matrix(-0.29294531,0,0,0.26458333,70.19679,-27.761975)"
|
||||
style="display:inline"
|
||||
id="button3-path"
|
||||
inkscape:label="#g156">
|
||||
<path
|
||||
sodipodi:nodetypes="cc"
|
||||
style="color:#000000;overflow:visible;opacity:1;vector-effect:none;fill:none;fill-opacity:1;stroke:#888a85;stroke-width:1;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal"
|
||||
d="m 114.17805,250.50576 125.44617,0.0352"
|
||||
id="path966"
|
||||
inkscape:connector-curvature="0" />
|
||||
<rect
|
||||
style="color:#000000;overflow:visible;opacity:1;vector-effect:none;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:2;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal"
|
||||
id="rect976"
|
||||
width="6.999999"
|
||||
height="6.999999"
|
||||
x="108"
|
||||
y="247.00577" />
|
||||
<rect
|
||||
y="250.00575"
|
||||
x="238.62422"
|
||||
height="1"
|
||||
width="1"
|
||||
id="button3-leader"
|
||||
style="color:#000000;text-align:end;overflow:visible;vector-effect:none;fill:#888a85;fill-opacity:1;stroke:none;stroke-linecap:round"
|
||||
inkscape:label="#rect875" />
|
||||
</g>
|
||||
<g
|
||||
transform="matrix(0.26458333,0,0,0.26458333,40.502648,-6.6313911)"
|
||||
style="display:inline"
|
||||
id="button5-path"
|
||||
inkscape:label="#g146">
|
||||
<path
|
||||
style="color:#000000;overflow:visible;opacity:1;vector-effect:none;fill:none;fill-opacity:1;stroke:#888a85;stroke-width:0.99999994;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal"
|
||||
d="m 336.91912,170.14213 -143.57514,0.36405"
|
||||
id="path51"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="cc" />
|
||||
<rect
|
||||
style="color:#000000;overflow:visible;opacity:1;vector-effect:none;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:2;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal"
|
||||
id="rect53"
|
||||
width="6.999999"
|
||||
height="6.999999"
|
||||
x="189"
|
||||
y="167" />
|
||||
<rect
|
||||
y="169.75269"
|
||||
x="336.91913"
|
||||
height="1"
|
||||
width="1"
|
||||
id="button5-leader"
|
||||
style="color:#000000;text-align:start;overflow:visible;vector-effect:none;fill:#888a85;fill-opacity:1;stroke:none;stroke-linecap:round"
|
||||
inkscape:label="#rect871" />
|
||||
</g>
|
||||
<g
|
||||
transform="matrix(-0.2847136,0,0,0.26458333,87.493539,-7.2646706)"
|
||||
style="display:inline;opacity:1"
|
||||
id="button2-path"
|
||||
inkscape:label="#g151">
|
||||
<path
|
||||
sodipodi:nodetypes="ccc"
|
||||
inkscape:connector-curvature="0"
|
||||
id="path964-6"
|
||||
d="m 79.210952,148.6933 62.691188,68.76371 165.40155,1e-5"
|
||||
style="color:#000000;overflow:visible;opacity:1;vector-effect:none;fill:none;fill-opacity:1;stroke:#888a85;stroke-width:0.99999994;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal" />
|
||||
<rect
|
||||
inkscape:label="#rect875"
|
||||
style="color:#000000;text-align:end;overflow:visible;vector-effect:none;fill:#888a85;fill-opacity:1;stroke:none;stroke-linecap:round"
|
||||
id="button2-leader"
|
||||
width="1"
|
||||
height="1"
|
||||
x="306.30368"
|
||||
y="216.45702" />
|
||||
<rect
|
||||
y="145.19263"
|
||||
x="76.187187"
|
||||
height="6.999999"
|
||||
width="6.999999"
|
||||
id="rect974-5"
|
||||
style="color:#000000;overflow:visible;opacity:1;vector-effect:none;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:2;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal" />
|
||||
</g>
|
||||
<g
|
||||
transform="matrix(0.26458333,0,0,0.26458333,13.746167,11.443545)"
|
||||
style="display:inline"
|
||||
id="button7-path"
|
||||
inkscape:label="#g146">
|
||||
<path
|
||||
style="color:#000000;overflow:visible;opacity:1;vector-effect:none;fill:none;fill-opacity:1;stroke:#888a85;stroke-width:0.99999994;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal"
|
||||
d="M 438.04598,191.7488 H 219.48839 l -26.14441,-21.24262"
|
||||
id="path51-1-9-6-8"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="ccc" />
|
||||
<rect
|
||||
style="color:#000000;overflow:visible;opacity:1;vector-effect:none;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:2;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal"
|
||||
id="rect53-2-3-2-7"
|
||||
width="6.999999"
|
||||
height="6.999999"
|
||||
x="189"
|
||||
y="167" />
|
||||
<rect
|
||||
y="191.3428"
|
||||
x="438.04599"
|
||||
height="1"
|
||||
width="1"
|
||||
id="button7-leader"
|
||||
style="color:#000000;text-align:start;overflow:visible;vector-effect:none;fill:#888a85;fill-opacity:1;stroke:none;stroke-linecap:round"
|
||||
inkscape:label="#rect871" />
|
||||
</g>
|
||||
<g
|
||||
transform="matrix(0.26458333,0,0,0.26458333,13.746167,3.106915)"
|
||||
style="display:inline"
|
||||
id="button8-path"
|
||||
inkscape:label="#g146">
|
||||
<path
|
||||
style="color:#000000;overflow:visible;opacity:1;vector-effect:none;fill:none;fill-opacity:1;stroke:#888a85;stroke-width:0.99999994;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal"
|
||||
d="M 438.04598,178.25732 H 203.75439 l -10.41041,-7.75114"
|
||||
id="path51-1-9-6-0"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="ccc" />
|
||||
<rect
|
||||
style="color:#000000;overflow:visible;opacity:1;vector-effect:none;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:2;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal"
|
||||
id="rect53-2-3-2-2"
|
||||
width="6.999999"
|
||||
height="6.999999"
|
||||
x="189"
|
||||
y="167" />
|
||||
<rect
|
||||
y="177.79317"
|
||||
x="438.04599"
|
||||
height="1"
|
||||
width="1"
|
||||
id="button8-leader"
|
||||
style="color:#000000;text-align:start;overflow:visible;vector-effect:none;fill:#888a85;fill-opacity:1;stroke:none;stroke-linecap:round"
|
||||
inkscape:label="#rect871" />
|
||||
</g>
|
||||
<g
|
||||
transform="matrix(0.2847136,0,0,-0.26458333,59.129968,74.101431)"
|
||||
style="display:inline;opacity:1"
|
||||
id="button6-path"
|
||||
inkscape:label="#g151">
|
||||
<path
|
||||
sodipodi:nodetypes="ccc"
|
||||
inkscape:connector-curvature="0"
|
||||
id="path964-67"
|
||||
d="m 109.31232,181.51438 38.69266,43.39973 h 99.66799"
|
||||
style="color:#000000;overflow:visible;opacity:1;vector-effect:none;fill:none;fill-opacity:1;stroke:#888a85;stroke-width:0.99999994;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal" />
|
||||
<rect
|
||||
inkscape:label="#rect875"
|
||||
style="color:#000000;text-align:start;overflow:visible;vector-effect:none;fill:#888a85;fill-opacity:1;stroke:none;stroke-linecap:round"
|
||||
id="button6-leader"
|
||||
width="1"
|
||||
height="1"
|
||||
x="247.67297"
|
||||
y="223.9144" />
|
||||
<rect
|
||||
y="177"
|
||||
x="105"
|
||||
height="6.999999"
|
||||
width="6.999999"
|
||||
id="rect974-3"
|
||||
style="color:#000000;overflow:visible;opacity:1;vector-effect:none;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:2;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal" />
|
||||
</g>
|
||||
<g
|
||||
transform="matrix(0.30394757,0,0,0.26458333,28.636101,-2.4556931)"
|
||||
style="display:inline"
|
||||
id="button1-path"
|
||||
inkscape:label="#g141">
|
||||
<path
|
||||
sodipodi:nodetypes="cccc"
|
||||
inkscape:connector-curvature="0"
|
||||
id="path960-6"
|
||||
d="m 332.32616,109.27355 -67.51561,-0.0347 -34.51493,21.26646 h -68.95164"
|
||||
style="color:#000000;overflow:visible;opacity:1;vector-effect:none;fill:none;fill-opacity:1;stroke:#888a85;stroke-width:1;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal" />
|
||||
<rect
|
||||
y="127.00576"
|
||||
x="157"
|
||||
height="6.999999"
|
||||
width="6.999999"
|
||||
id="rect970-2"
|
||||
style="color:#000000;overflow:visible;opacity:1;vector-effect:none;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:2;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal" />
|
||||
<rect
|
||||
inkscape:label="#rect871"
|
||||
style="color:#000000;text-align:start;overflow:visible;vector-effect:none;fill:#888a85;fill-opacity:1;stroke:none;stroke-linecap:round"
|
||||
id="button1-leader"
|
||||
width="1"
|
||||
height="1"
|
||||
x="332.32617"
|
||||
y="109.27355" />
|
||||
</g>
|
||||
<g
|
||||
id="led0"
|
||||
inkscape:label="#g4411"
|
||||
style="fill:#eeee35;fill-opacity:1">
|
||||
<g
|
||||
id="g4457">
|
||||
<path
|
||||
id="led0-0"
|
||||
style="color:#000000;display:inline;overflow:visible;opacity:1;fill:#eeeeec;fill-opacity:1;stroke:none;stroke-width:0.28991818;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal"
|
||||
d="M 36.851726,81.915105 C 41.99239,103.21594 40.604019,101.71476 43.62439,106.21567 44.61563,98.208963 38.156084,80.727537 35.152327,69.797094 Z"
|
||||
inkscape:label="#path5630"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="cccc" />
|
||||
<path
|
||||
id="led0-1"
|
||||
style="color:#000000;display:inline;overflow:visible;opacity:1;fill:#eeeeec;fill-opacity:1;stroke:none;stroke-width:0.28991818;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal"
|
||||
d="M 93.039402,81.561768 C 87.898738,102.8626 89.287109,101.36142 86.266738,105.86233 85.275498,97.855627 91.735044,80.3742 94.738801,69.443757 Z"
|
||||
inkscape:label="#path5630"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="cccc" />
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
<g
|
||||
inkscape:groupmode="layer"
|
||||
id="LEDs"
|
||||
inkscape:label="LEDs"
|
||||
transform="translate(0,-2.6458338)"
|
||||
style="display:inline">
|
||||
<g
|
||||
style="display:inline"
|
||||
id="led0-path"
|
||||
inkscape:label="#g161"
|
||||
transform="matrix(0.26458333,0,0,0.26458333,38.838972,19.46058)">
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
id="path877"
|
||||
d="M 343.20703,290.50577 H 208.64438 l -18.97696,-18.97696"
|
||||
style="color:#000000;display:inline;overflow:visible;opacity:1;fill:none;fill-opacity:1;stroke:#888a85;stroke-width:1;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal"
|
||||
sodipodi:nodetypes="ccc" />
|
||||
<rect
|
||||
y="269.96875"
|
||||
x="188.28125"
|
||||
height="6.999999"
|
||||
width="6.999999"
|
||||
id="rect879"
|
||||
style="color:#000000;display:inline;overflow:visible;opacity:1;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:2;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal" />
|
||||
<rect
|
||||
inkscape:label="#rect881"
|
||||
y="290.00577"
|
||||
x="343.20703"
|
||||
height="1"
|
||||
width="1"
|
||||
id="led0-leader"
|
||||
style="color:#000000;text-align:start;display:inline;overflow:visible;fill:#888a85;fill-opacity:1;stroke:none;stroke-linecap:round" />
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 27 KiB |
@@ -10,7 +10,7 @@
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="467.83105"
|
||||
height="398.87393"
|
||||
height="400.87393"
|
||||
viewBox="0 0 467.83105 398.87393"
|
||||
version="1.1"
|
||||
id="svg8"
|
||||
@@ -296,7 +296,7 @@
|
||||
height="1"
|
||||
width="1"
|
||||
id="button2-leader"
|
||||
style="color:#000000;overflow:visible;vector-effect:none;fill:#888a85;fill-opacity:1;stroke:none;stroke-linecap:round" />
|
||||
style="color:#000000;text-align:start;overflow:visible;vector-effect:none;fill:#888a85;fill-opacity:1;stroke:none;stroke-linecap:round" />
|
||||
</g>
|
||||
<g
|
||||
id="button6-path"
|
||||
|
||||
|
Before Width: | Height: | Size: 34 KiB After Width: | Height: | Size: 34 KiB |
1
data/gnome/logitech-g703.svg
Symbolic link
@@ -0,0 +1 @@
|
||||
logitech-g403.svg
|
||||
441
data/gnome/logitech-g9.svg
Normal file
@@ -0,0 +1,441 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="490"
|
||||
height="490"
|
||||
viewBox="0 0 129.64583 129.64583"
|
||||
version="1.1"
|
||||
id="svg8"
|
||||
sodipodi:docname="G9.svg"
|
||||
inkscape:version="0.92.2 (5c3e80d, 2017-08-06)"
|
||||
enable-background="new">
|
||||
<defs
|
||||
id="defs2">
|
||||
<clipPath
|
||||
clipPathUnits="userSpaceOnUse"
|
||||
id="clipPath145">
|
||||
<rect
|
||||
id="rect147"
|
||||
width="82.020836"
|
||||
height="120.65"
|
||||
x="20.902082"
|
||||
y="3.174999"
|
||||
style="stroke-width:0.26458332" />
|
||||
</clipPath>
|
||||
</defs>
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="1.4142136"
|
||||
inkscape:cx="108.9024"
|
||||
inkscape:cy="270.58583"
|
||||
inkscape:document-units="px"
|
||||
inkscape:current-layer="LEDs"
|
||||
inkscape:document-rotation="0"
|
||||
showgrid="false"
|
||||
showguides="false"
|
||||
inkscape:window-width="1920"
|
||||
inkscape:window-height="1136"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="27"
|
||||
inkscape:window-maximized="1"
|
||||
showborder="true"
|
||||
inkscape:guide-bbox="true"
|
||||
units="px"
|
||||
inkscape:snap-global="false"
|
||||
inkscape:measure-start="200.26,379.645"
|
||||
inkscape:measure-end="199.294,334.274">
|
||||
<inkscape:grid
|
||||
type="xygrid"
|
||||
id="grid78" />
|
||||
<sodipodi:guide
|
||||
position="58.722772,112.40709"
|
||||
orientation="0,1"
|
||||
id="guide79"
|
||||
inkscape:locked="false" />
|
||||
<sodipodi:guide
|
||||
position="39.611923,100.54373"
|
||||
orientation="0,1"
|
||||
id="guide81"
|
||||
inkscape:locked="false" />
|
||||
<sodipodi:guide
|
||||
position="51.756014,88.614617"
|
||||
orientation="0,1"
|
||||
id="guide83"
|
||||
inkscape:locked="false" />
|
||||
<sodipodi:guide
|
||||
position="57.778386,76.729167"
|
||||
orientation="0,1"
|
||||
id="guide85"
|
||||
inkscape:locked="false" />
|
||||
<sodipodi:guide
|
||||
position="45.047078,64.795712"
|
||||
orientation="0,1"
|
||||
inkscape:locked="false"
|
||||
id="guide87" />
|
||||
<sodipodi:guide
|
||||
position="57.646696,52.899321"
|
||||
orientation="0,1"
|
||||
id="guide89"
|
||||
inkscape:locked="false" />
|
||||
<sodipodi:guide
|
||||
position="64.822916,108.74375"
|
||||
orientation="1,0"
|
||||
id="guide141"
|
||||
inkscape:locked="false" />
|
||||
</sodipodi:namedview>
|
||||
<metadata
|
||||
id="metadata5">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title />
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
inkscape:groupmode="layer"
|
||||
id="Device"
|
||||
inkscape:label="Device"
|
||||
style="display:inline;opacity:1"
|
||||
transform="translate(0,-167.35416)">
|
||||
<path
|
||||
style="fill:#d3d3ce;fill-opacity:1;stroke:#babdb6;stroke-width:0.98636663;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 94.675437,179.69604 c 3.984039,23.55769 3.665039,48.23792 2.691228,71.79562 -2.08441,12.87379 -9.220213,24.06379 -17.197916,34.13125 -5.788734,2.89177 -12.325823,4.09974 -19.05,5.02708 -6.713477,-0.22178 -12.6786,-0.44356 -19.579166,-2.91041 -7.729571,-8.24539 -13.148669,-16.741 -17.727083,-25.4 -0.02339,-1.79858 0,-5.84224 0,-8.20209 -1.45391,-5.19812 -2.159466,-9.36726 -2.116667,-15.875 3.006557,-20.49321 9.287166,-40.14452 13.977522,-59.88937 2.143416,-0.99154 2.603034,-1.14118 4.278728,-1.75854 8.680505,-0.97549 16.051389,-1.76389 24.077083,-2.64584 h 7.14375 z"
|
||||
id="path4643"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="ccccccccccccc" />
|
||||
<path
|
||||
sodipodi:type="arc"
|
||||
style="display:inline;opacity:0.72399998;fill:none;fill-opacity:0.39215686;stroke:#eeeeec;stroke-width:2.089679;stroke-linecap:square;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
id="logo"
|
||||
sodipodi:cx="62.113438"
|
||||
sodipodi:cy="277.58575"
|
||||
sodipodi:rx="3.7614744"
|
||||
sodipodi:ry="3.7614779"
|
||||
d="m 64.773202,274.92599 a 3.7614744,3.7614779 0 0 1 0,5.31953 3.7614744,3.7614779 0 0 1 -5.319528,0 3.7614744,3.7614779 0 0 1 -10e-7,-5.31953"
|
||||
sodipodi:start="5.4977871"
|
||||
sodipodi:end="3.9269907"
|
||||
sodipodi:open="true"
|
||||
sodipodi:arc-type="arc"
|
||||
inkscape:label="path" />
|
||||
<path
|
||||
style="fill:none;stroke:#babdb6;stroke-width:0.98636663;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="M 36.247916,178.59895 C 31.541511,203.86131 25.993208,228.84304 23.8125,254.66666"
|
||||
id="path4820"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="cc" />
|
||||
<path
|
||||
style="fill:#eeeeec;fill-opacity:1;stroke:#babdb6;stroke-width:0.61647916;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 90.83155,179.22767 c 1.340802,7.60827 2.120337,15.21655 2.338607,22.82482 -0.06236,15.27891 -0.685992,30.65136 -2.15152,45.27546 -0.124725,1.27845 -0.997805,2.18271 -2.057974,2.71279 -9.011437,2.99341 -16.339078,5.7062 -27.595579,6.73519 -10.523737,-0.10917 -22.099849,-1.22387 -25.537604,-3.27405 -1.656483,-1.67598 -2.466318,-3.00581 -2.899876,-5.23849 -0.200352,-25.84328 2.343475,-44.91236 8.699625,-71.28078 7.577091,-0.93544 15.154181,-1.87089 22.731272,-2.80633 l 7.296459,0.0936 c 6.392197,1.6526 12.784393,3.30519 19.17659,4.95779 z"
|
||||
id="path4822"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="ccccccccccc" />
|
||||
<path
|
||||
style="fill:#d9dad7;fill-opacity:1;stroke:#babdb6;stroke-width:0.61647916;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 34.237226,219.26465 30.09955,-1.86805 -0.492771,5.00179 c -0.904262,2.26065 -1.153714,2.27624 -3.554685,3.55468 -3.25846,1.27844 -3.710591,1.10694 -7.249684,1.44994 -6.485741,0.3274 -12.971481,0.65481 -19.457222,0.98221 z"
|
||||
id="led0"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="ccccccc"
|
||||
inkscape:label="#path894" />
|
||||
<path
|
||||
style="fill:#d9dad7;fill-opacity:1;stroke:#babdb6;stroke-width:0.61647916;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 34.611402,214.21326 -0.467722,5.00462 16.18317,-1.07576 0.04677,-4.77076 z"
|
||||
id="button3"
|
||||
inkscape:connector-curvature="0"
|
||||
inkscape:label="#path896" />
|
||||
<path
|
||||
style="fill:#d9dad7;fill-opacity:1;stroke:#babdb6;stroke-width:0.61647916;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 64.405272,212.43591 -14.066729,0.93544 0.02888,4.76741 13.98589,-0.84138 z"
|
||||
id="button4"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="ccccc"
|
||||
inkscape:label="#path898" />
|
||||
<path
|
||||
style="fill:none;stroke:#babdb6;stroke-width:0.61647916;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 64.624478,173.96874 -0.264583,38.43073 z"
|
||||
id="path4589"
|
||||
inkscape:connector-curvature="0" />
|
||||
<rect
|
||||
style="display:inline;opacity:1;fill:#d9dad7;fill-opacity:1;stroke:#babdb6;stroke-width:0.6744734;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
id="button2"
|
||||
width="8.6420469"
|
||||
height="17.819014"
|
||||
x="64.999809"
|
||||
y="187.58092"
|
||||
ry="1.5417958"
|
||||
inkscape:label="#rect4615"
|
||||
rx="1.752861" />
|
||||
<path
|
||||
style="fill:#d9dad7;fill-opacity:1;stroke:#babdb6;stroke-width:0.61647916;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 24.274755,248.26339 c -0.124726,-9.60388 -0.342996,-10.78877 0.748354,-17.86696 0.576857,0.0935 1.153713,0.18709 1.73057,0.28063 -0.826308,5.86211 -1.652616,11.72422 -2.478924,17.58633 z"
|
||||
id="button6"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="cccc"
|
||||
inkscape:label="#path4606" />
|
||||
<path
|
||||
style="fill:#d9dad7;fill-opacity:1;stroke:#babdb6;stroke-width:0.61647916;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 27.104469,228.7594 c -0.561265,-0.0779 -1.122531,-0.15591 -1.683796,-0.23386 0.919852,-4.78635 2.120338,-8.77758 3.671614,-12.95589 -0.662606,4.39658 -1.325212,8.79317 -1.987818,13.18975 z"
|
||||
id="button5"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="cccc"
|
||||
inkscape:label="#path4608" />
|
||||
<path
|
||||
style="fill:#eeeeec;fill-opacity:1;stroke:#000000;stroke-width:0;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 41.814318,177.35679 -6.781966,36.38874 28.764883,-1.68379 0.467722,-37.41774 z"
|
||||
id="button0"
|
||||
inkscape:connector-curvature="0"
|
||||
inkscape:label="#path4610" />
|
||||
<path
|
||||
style="fill:#eeeeec;fill-opacity:1;stroke:#000000;stroke-width:0;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 65.054426,174.53098 -0.09922,12.60078 9.128124,-0.0661 0.03307,18.88463 -9.293489,-0.13229 -0.03307,6.15156 27.78125,-0.85989 0.132291,-9.1612 -0.959114,-13.32838 -1.35599,-9.09506 -18.884635,-4.89479 z"
|
||||
id="button1"
|
||||
inkscape:connector-curvature="0"
|
||||
inkscape:label="#path4612" />
|
||||
</g>
|
||||
<g
|
||||
inkscape:groupmode="layer"
|
||||
id="Buttons"
|
||||
inkscape:label="Buttons"
|
||||
transform="translate(0,-2.6458338)"
|
||||
style="display:inline">
|
||||
<g
|
||||
transform="matrix(0.26458333,0,0,0.26458333,40.502648,-13.272558)"
|
||||
style="display:inline"
|
||||
id="button2-path"
|
||||
inkscape:label="#g146">
|
||||
<path
|
||||
style="color:#000000;overflow:visible;opacity:1;vector-effect:none;fill:none;fill-opacity:1;stroke:#888a85;stroke-width:0.99999994;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal"
|
||||
d="m 336.91912,170.14213 -225.57514,0.36405"
|
||||
id="path51"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="cc" />
|
||||
<rect
|
||||
style="color:#000000;overflow:visible;opacity:1;vector-effect:none;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:2;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal"
|
||||
id="rect53"
|
||||
width="6.999999"
|
||||
height="6.999999"
|
||||
x="107.41756"
|
||||
y="166.91161" />
|
||||
<rect
|
||||
y="169.75269"
|
||||
x="336.91913"
|
||||
height="1"
|
||||
width="1"
|
||||
id="button2-leader"
|
||||
style="color:#000000;text-align:start;overflow:visible;vector-effect:none;fill:#888a85;fill-opacity:1;stroke:none;stroke-linecap:round"
|
||||
inkscape:label="#rect871" />
|
||||
</g>
|
||||
<g
|
||||
transform="matrix(-0.26458333,0,0,-0.26458333,116.08398,94.455601)"
|
||||
style="display:inline"
|
||||
id="button3-path"
|
||||
inkscape:label="#g146">
|
||||
<path
|
||||
style="color:#000000;overflow:visible;opacity:1;vector-effect:none;fill:none;fill-opacity:1;stroke:#888a85;stroke-width:0.99999994;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal"
|
||||
d="M 438.04598,191.7488 H 311.48839 l -34.64441,-29.86762"
|
||||
id="path51-1-9-6-8"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="ccc" />
|
||||
<rect
|
||||
style="color:#000000;overflow:visible;opacity:1;vector-effect:none;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:2;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal"
|
||||
id="rect53-2-3-2-7"
|
||||
width="6.999999"
|
||||
height="6.999999"
|
||||
x="273.625"
|
||||
y="158.5" />
|
||||
<rect
|
||||
y="191.3428"
|
||||
x="438.04599"
|
||||
height="1"
|
||||
width="1"
|
||||
id="button3-leader"
|
||||
style="color:#000000;text-align:end;overflow:visible;vector-effect:none;fill:#888a85;fill-opacity:1;stroke:none;stroke-linecap:round"
|
||||
inkscape:label="#rect871" />
|
||||
</g>
|
||||
<g
|
||||
transform="matrix(-0.29294531,0,0,0.26458333,70.284218,-46.390214)"
|
||||
style="display:inline"
|
||||
id="button0-path"
|
||||
inkscape:label="#g156">
|
||||
<path
|
||||
sodipodi:nodetypes="cc"
|
||||
style="color:#000000;overflow:visible;opacity:1;vector-effect:none;fill:none;fill-opacity:1;stroke:#888a85;stroke-width:1;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal"
|
||||
d="m 58.180682,250.50576 181.443538,0.0352"
|
||||
id="path966-9"
|
||||
inkscape:connector-curvature="0" />
|
||||
<rect
|
||||
style="color:#000000;overflow:visible;opacity:1;vector-effect:none;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:2;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal"
|
||||
id="rect976-8"
|
||||
width="6.999999"
|
||||
height="6.999999"
|
||||
x="55.471279"
|
||||
y="247.18254" />
|
||||
<rect
|
||||
y="250.00575"
|
||||
x="238.62422"
|
||||
height="1"
|
||||
width="1"
|
||||
id="button0-leader"
|
||||
style="color:#000000;text-align:end;overflow:visible;vector-effect:none;fill:#888a85;fill-opacity:1;stroke:none;stroke-linecap:round"
|
||||
inkscape:label="#rect875" />
|
||||
</g>
|
||||
<g
|
||||
transform="matrix(0.26458333,0,0,0.26458333,40.402294,-25.12739)"
|
||||
style="display:inline"
|
||||
id="button1-path"
|
||||
inkscape:label="#g146">
|
||||
<path
|
||||
style="color:#000000;overflow:visible;opacity:1;vector-effect:none;fill:none;fill-opacity:1;stroke:#888a85;stroke-width:0.99999994;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal"
|
||||
d="m 336.91912,170.14213 -189.57514,0.36405"
|
||||
id="path51-1"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="cc" />
|
||||
<rect
|
||||
style="color:#000000;overflow:visible;opacity:1;vector-effect:none;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:2;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal"
|
||||
id="rect53-0"
|
||||
width="6.999999"
|
||||
height="6.999999"
|
||||
x="143.59541"
|
||||
y="166.59467" />
|
||||
<rect
|
||||
y="169.75269"
|
||||
x="336.91913"
|
||||
height="1"
|
||||
width="1"
|
||||
id="button1-leader"
|
||||
style="color:#000000;text-align:start;overflow:visible;vector-effect:none;fill:#888a85;fill-opacity:1;stroke:none;stroke-linecap:round"
|
||||
inkscape:label="#rect871" />
|
||||
</g>
|
||||
<g
|
||||
transform="matrix(0.26458333,0,0,-0.26458333,13.573867,94.421678)"
|
||||
style="display:inline"
|
||||
id="button4-path"
|
||||
inkscape:label="#g146">
|
||||
<path
|
||||
style="color:#000000;overflow:visible;opacity:1;vector-effect:none;fill:none;fill-opacity:1;stroke:#888a85;stroke-width:0.99999994;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal"
|
||||
d="M 438.04598,191.7488 H 193.48839 l -29.95691,-26.43012"
|
||||
id="path51-1-9-6-8-4"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="ccc" />
|
||||
<rect
|
||||
style="color:#000000;overflow:visible;opacity:1;vector-effect:none;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:2;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal"
|
||||
id="rect53-2-3-2-7-4"
|
||||
width="6.999999"
|
||||
height="6.999999"
|
||||
x="160.13437"
|
||||
y="161.68198" />
|
||||
<rect
|
||||
y="191.3428"
|
||||
x="438.04599"
|
||||
height="1"
|
||||
width="1"
|
||||
id="button4-leader"
|
||||
style="color:#000000;text-align:start;overflow:visible;vector-effect:none;fill:#888a85;fill-opacity:1;stroke:none;stroke-linecap:round"
|
||||
inkscape:label="#rect871" />
|
||||
</g>
|
||||
<g
|
||||
transform="matrix(-0.26458333,0,0,-0.26458333,116.07548,106.30868)"
|
||||
style="display:inline"
|
||||
id="button5-path"
|
||||
inkscape:label="#g146">
|
||||
<path
|
||||
style="color:#000000;overflow:visible;opacity:1;vector-effect:none;fill:none;fill-opacity:1;stroke:#888a85;stroke-width:0.99999994;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal"
|
||||
d="M 438.04598,191.7488 H 359.48839 L 337.39512,173.19489"
|
||||
id="path51-1-9-6-8-7"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="ccc" />
|
||||
<rect
|
||||
style="color:#000000;overflow:visible;opacity:1;vector-effect:none;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:2;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal"
|
||||
id="rect53-2-3-2-7-6"
|
||||
width="6.999999"
|
||||
height="6.999999"
|
||||
x="333.90585"
|
||||
y="169.28337" />
|
||||
<rect
|
||||
y="191.3428"
|
||||
x="438.04599"
|
||||
height="1"
|
||||
width="1"
|
||||
id="button5-leader"
|
||||
style="color:#000000;text-align:end;overflow:visible;vector-effect:none;fill:#888a85;fill-opacity:1;stroke:none;stroke-linecap:round"
|
||||
inkscape:label="#rect871" />
|
||||
</g>
|
||||
<g
|
||||
transform="matrix(-0.26458333,0,0,-0.26458333,116.05287,118.29899)"
|
||||
style="display:inline"
|
||||
id="button6-path"
|
||||
inkscape:label="#g146">
|
||||
<path
|
||||
style="color:#000000;overflow:visible;opacity:1;vector-effect:none;fill:none;fill-opacity:1;stroke:#888a85;stroke-width:0.99999994;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal"
|
||||
d="M 438.04598,191.7488 H 359.48839 L 344.11263,179.02852"
|
||||
id="path51-1-9-6-8-7-7"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="ccc" />
|
||||
<rect
|
||||
style="color:#000000;overflow:visible;opacity:1;vector-effect:none;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:2;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal"
|
||||
id="rect53-2-3-2-7-6-5"
|
||||
width="6.999999"
|
||||
height="6.999999"
|
||||
x="340.26981"
|
||||
y="174.94023" />
|
||||
<rect
|
||||
y="191.3428"
|
||||
x="438.04599"
|
||||
height="1"
|
||||
width="1"
|
||||
id="button6-leader"
|
||||
style="color:#000000;text-align:end;overflow:visible;vector-effect:none;fill:#888a85;fill-opacity:1;stroke:none;stroke-linecap:round"
|
||||
inkscape:label="#rect871" />
|
||||
</g>
|
||||
</g>
|
||||
<g
|
||||
inkscape:groupmode="layer"
|
||||
id="LEDs"
|
||||
inkscape:label="LEDs"
|
||||
transform="translate(0,-2.6458338)"
|
||||
style="display:inline">
|
||||
<g
|
||||
transform="matrix(0.26458333,0,0,-0.26458333,13.686363,102.7808)"
|
||||
style="display:inline"
|
||||
id="led0-path"
|
||||
inkscape:label="#g146">
|
||||
<path
|
||||
style="color:#000000;overflow:visible;opacity:1;vector-effect:none;fill:none;fill-opacity:1;stroke:#888a85;stroke-width:0.99999994;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal"
|
||||
d="M 438.04598,178.25732 H 151.75439 l -10.41041,-7.75114"
|
||||
id="path51-1-9-6-0"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="ccc" />
|
||||
<rect
|
||||
style="color:#000000;overflow:visible;opacity:1;vector-effect:none;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:2;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal"
|
||||
id="rect53-2-3-2-2"
|
||||
width="6.999999"
|
||||
height="6.999999"
|
||||
x="137.02765"
|
||||
y="165.93933" />
|
||||
<rect
|
||||
y="177.79317"
|
||||
x="438.04599"
|
||||
height="1"
|
||||
width="1"
|
||||
id="led0-leader"
|
||||
style="color:#000000;text-align:start;overflow:visible;vector-effect:none;fill:#888a85;fill-opacity:1;stroke:none;stroke-linecap:round"
|
||||
inkscape:label="#rect871" />
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 22 KiB |
554
data/gnome/logitech-g900.svg
Normal file
@@ -0,0 +1,554 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="460"
|
||||
height="440"
|
||||
id="svg2"
|
||||
version="1.1"
|
||||
inkscape:version="0.92+devel unknown"
|
||||
sodipodi:docname="logitech-g900.svg"
|
||||
viewBox="0 0 460 440">
|
||||
<style
|
||||
id="style5346" />
|
||||
<defs
|
||||
id="defs4" />
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="2.8284271"
|
||||
inkscape:cx="333.51156"
|
||||
inkscape:cy="187.93422"
|
||||
inkscape:document-units="px"
|
||||
inkscape:current-layer="Device"
|
||||
showgrid="true"
|
||||
showguides="true"
|
||||
inkscape:guide-bbox="true"
|
||||
inkscape:window-width="1853"
|
||||
inkscape:window-height="1016"
|
||||
inkscape:window-x="1507"
|
||||
inkscape:window-y="27"
|
||||
inkscape:window-maximized="1"
|
||||
units="px"
|
||||
fit-margin-top="20"
|
||||
fit-margin-left="-40"
|
||||
fit-margin-right="-40"
|
||||
fit-margin-bottom="20"
|
||||
inkscape:document-rotation="0"
|
||||
inkscape:pagecheckerboard="false">
|
||||
<sodipodi:guide
|
||||
orientation="0,1"
|
||||
position="-115.05694,356.25"
|
||||
id="guide5340"
|
||||
inkscape:locked="false"
|
||||
inkscape:label=""
|
||||
inkscape:color="rgb(0,0,255)" />
|
||||
<sodipodi:guide
|
||||
orientation="0,1"
|
||||
position="-338.2349,318.75"
|
||||
id="guide5342"
|
||||
inkscape:locked="false"
|
||||
inkscape:label=""
|
||||
inkscape:color="rgb(0,0,255)" />
|
||||
<sodipodi:guide
|
||||
orientation="0,1"
|
||||
position="-411.98489,243.75"
|
||||
id="guide5344"
|
||||
inkscape:locked="false"
|
||||
inkscape:label=""
|
||||
inkscape:color="rgb(0,0,255)" />
|
||||
<sodipodi:guide
|
||||
orientation="0,1"
|
||||
position="-447.39711,281.25"
|
||||
id="guide5346"
|
||||
inkscape:locked="false"
|
||||
inkscape:label=""
|
||||
inkscape:color="rgb(0,0,255)" />
|
||||
<sodipodi:guide
|
||||
orientation="0,1"
|
||||
position="-458.85989,206.25"
|
||||
id="guide5348"
|
||||
inkscape:locked="false"
|
||||
inkscape:label=""
|
||||
inkscape:color="rgb(0,0,255)" />
|
||||
<sodipodi:guide
|
||||
orientation="0,1"
|
||||
position="-443.23489,168.75"
|
||||
id="guide5350"
|
||||
inkscape:locked="false"
|
||||
inkscape:label=""
|
||||
inkscape:color="rgb(0,0,255)" />
|
||||
<inkscape:grid
|
||||
type="xygrid"
|
||||
id="grid5352"
|
||||
empspacing="4"
|
||||
visible="true"
|
||||
enabled="true"
|
||||
snapvisiblegridlinesonly="true"
|
||||
originx="0"
|
||||
originy="0"
|
||||
spacingx="0.93749999"
|
||||
spacingy="0.93749999" />
|
||||
<sodipodi:guide
|
||||
orientation="0,1"
|
||||
position="-305.47013,131.25"
|
||||
id="guide5354"
|
||||
inkscape:locked="false"
|
||||
inkscape:label=""
|
||||
inkscape:color="rgb(0,0,255)" />
|
||||
<sodipodi:guide
|
||||
orientation="1,0"
|
||||
position="230,443.73334"
|
||||
id="guide3885"
|
||||
inkscape:locked="false"
|
||||
inkscape:label=""
|
||||
inkscape:color="rgb(0,0,255)" />
|
||||
<sodipodi:guide
|
||||
position="160,100"
|
||||
orientation="0,1"
|
||||
id="guide5247"
|
||||
inkscape:locked="false"
|
||||
inkscape:label=""
|
||||
inkscape:color="rgb(0,0,255)" />
|
||||
</sodipodi:namedview>
|
||||
<metadata
|
||||
id="metadata7">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title />
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
inkscape:groupmode="layer"
|
||||
id="Device"
|
||||
inkscape:label="Device"
|
||||
style="display:inline"
|
||||
transform="translate(0,2.6666495)">
|
||||
<path
|
||||
style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:#babdb6;stroke-width:1.875;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
|
||||
d="m 321.875,220.80227 -17.8125,-0.9375 10.3125,-93.75 c 7.5,33.75 8.4375,56.71875 7.5,94.6875 z"
|
||||
id="button6"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="cccc" />
|
||||
<path
|
||||
sodipodi:nodetypes="cccc"
|
||||
inkscape:connector-curvature="0"
|
||||
id="button4"
|
||||
d="m 137.20625,220.80227 17.8125,-0.9375 -10.3125,-93.75 c -7.5,33.75 -8.4375,56.71875 -7.5,94.6875 z"
|
||||
style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:#babdb6;stroke-width:1.875;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate" />
|
||||
<path
|
||||
id="path3894"
|
||||
style="display:inline;fill:#d3d3ce;fill-opacity:1;stroke:#babdb6;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 145.625,141.11478 c 0,0 -3.75,59.99999 0,84.37499 3.75,24.375 -9.375,25.82353 -9.375,61.875 0,67.5 39.375,116.25001 93.75,116.25 54.375,0 93.75,-48.75 93.75,-116.25 0,-36.05147 -13.125,-33.75 -9.375,-61.875 3.75,-28.125 0,-84.37499 0,-84.37499"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="czszszc" />
|
||||
<path
|
||||
id="path3891"
|
||||
style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#d9dad7;fill-opacity:1;fill-rule:nonzero;stroke:#babdb6;stroke-width:1.875;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
|
||||
d="m 254.375,134.55227 22.5,49.21875 -17.8125,46.40625 c -1.65577,5.51921 -10.3125,15 -16.875,15 h -24.375 c -6.5625,0 -15.21923,-9.48079 -16.875,-15 l -17.8125,-46.40625 22.5,-49.21875"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="cccssccc" />
|
||||
<path
|
||||
id="path3887"
|
||||
style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#d3d3ce;fill-opacity:1;fill-rule:nonzero;stroke:#babdb6;stroke-width:1.875;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
|
||||
d="m 220.625,231.11477 c -3.75,0 -5.82083,-5.76156 -8.4375,-15.9375 l -8.4375,-32.8125 c -0.9643,-3.75 -1.17686,-11.25 -0.9375,-15 L 211.25,35.177274 c 0.29859,-4.678 0.9375,-4.6875 2.8125,-4.6875 1.875,0 1.875,1.875 1.875,1.875 h 28.125 c 0,0 0,-1.875 1.875,-1.875 1.875,-1e-6 2.5139,0.0095 2.8125,4.6875 l 8.4375,132.187496 c 0.23936,3.75 0.0268,11.25 -0.9375,15 l -8.4375,32.8125 c -2.61667,10.17593 -4.6875,15.9375 -8.4375,15.9375 z"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="ssssszcczssssss" />
|
||||
<path
|
||||
style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#eeeeec;fill-opacity:1;fill-rule:nonzero;stroke:#babdb6;stroke-width:1.875;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
|
||||
d="m 248.75,36.114773 h 5.625 l 43.125,30 c 2.8125,1.956522 3.99101,3.729263 5.625,7.5 l 12.1875,28.124997 c 1.625,3.75 2.01562,9.375 1.875,13.125 l -2.8125,75 -3.75,3.75 -7.5,30 -41.25,-7.5 5.625,-28.125 c 1.125,-5.625 0.225,-9.375 -1.875,-15.9375 l -10.3125,-23.4375 z"
|
||||
id="button1"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="ccssssccccsscc" />
|
||||
<path
|
||||
style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:#babdb6;stroke-width:1.875;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
|
||||
d="m 320.9375,229.23977 -7.5,-0.9375 -15.9375,58.125 c -0.77117,2.8125 -1.53214,6.12475 0,6.5625 2.01565,0.57591 4.42284,-1.09513 5.625,-2.8125 l 6.5625,-9.375 c 1.6522,-2.3603 3.09783,-5.625 3.75,-9.375 z"
|
||||
id="button5"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="ccsssssc" />
|
||||
<path
|
||||
style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:#babdb6;stroke-width:1.875;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
|
||||
d="m 232.8125,176.73977 v 7.5 c 0,1.875 0.36208,2.76945 0.9375,4.6875 l 2.8125,9.375 c 0.5625,1.875 0.92837,1.875 2.8125,1.875 h 0.9375 c 1.875,0 2.37981,0 2.8125,-1.875 l 2.8125,-12.1875 c 0.43118,-1.86846 0.9375,-3.75 0.9375,-5.625 v -3.75 c 0,-1.875 -0.9375,-2.8125 -2.8125,-2.8125 h -8.4375 c -1.875,0 -2.8125,0.9375 -2.8125,2.8125 z"
|
||||
id="button8"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="sssssssssssss" />
|
||||
<path
|
||||
sodipodi:nodetypes="ccsssssc"
|
||||
inkscape:connector-curvature="0"
|
||||
id="button3"
|
||||
d="m 139.0625,229.23977 7.5,-0.9375 15.9375,58.125 c 0.77117,2.8125 1.53214,6.12476 0,6.5625 -2.01565,0.57591 -4.42284,-1.09513 -5.625,-2.8125 l -6.5625,-9.375 c -1.6522,-2.36028 -3.08377,-5.62747 -3.75,-9.375 z"
|
||||
style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:#babdb6;stroke-width:1.875;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate" />
|
||||
<path
|
||||
sodipodi:nodetypes="ccssssccccsscc"
|
||||
inkscape:connector-curvature="0"
|
||||
id="button0"
|
||||
d="m 211.25,36.114774 h -5.625 L 162.5,66.114773 c -2.8125,1.956522 -3.99101,3.729262 -5.625,7.5 l -12.1875,28.124997 c -1.625,3.75 -2.02163,9.37524 -1.875,13.12501 l 2.8125,74.99999 3.75,3.75 7.5,30 41.25,-7.5 -5.625,-28.125 c -1.125,-5.625 -0.25547,-9.38482 1.875,-15.9375 l 10.3125,-23.43749 z"
|
||||
style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#eeeeec;fill-opacity:1;fill-rule:nonzero;stroke:#babdb6;stroke-width:1.875;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate" />
|
||||
<path
|
||||
id="path4352"
|
||||
style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#babdb6;fill-opacity:1;stroke:none;stroke-width:9.375;stroke-linecap:square;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
|
||||
d="m 220.625,206.73977 c 1.875,0 2.68807,0.75516 2.8125,1.875 l 1.875,16.875 c 0.10424,0.93821 0,1.875 -0.9375,1.875 -1.875,0 -2.48162,-0.9375 -2.8125,-2.8125 l -2.8125,-15.9375 c -0.19581,-1.10959 0,-1.875 1.875,-1.875 z m 18.75,0 c -1.875,0 -2.68808,0.75516 -2.8125,1.875 l -1.875,16.875 c -0.10424,0.93821 0,1.875 0.9375,1.875 1.875,0 2.48162,-0.9375 2.8125,-2.8125 l 2.8125,-15.9375 c 0.19581,-1.10959 0,-1.875 -1.875,-1.875 z m -7.5,18.75 0.9375,-16.875 c 0.049,-0.88251 0.0604,-1.875 -2.78231,-1.875 -2.84269,0 -2.89172,0.99249 -2.84269,1.875 l 0.9375,16.875 c 0.049,0.88253 0,1.875 1.90519,1.875 1.90518,0 1.79581,-0.99247 1.84481,-1.875 z"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="sssssssssssssscszsczc" />
|
||||
<path
|
||||
id="button2"
|
||||
style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:#babdb6;stroke-width:1.875;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
|
||||
d="m 236.5625,135.48978 c 2.8125,0 5.625,-2.8125 5.625,-5.625 V 79.239773 c 0,-2.8125 -2.8125,-5.625 -5.625,-5.625 h -13.125 c -2.8125,0 -5.625,2.8125 -5.625,5.625 v 50.625007 c 0,2.8125 2.8125,5.625 5.625,5.625 z"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="sssssssss" />
|
||||
<path
|
||||
id="path3927"
|
||||
style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#eeeeec;fill-opacity:1;fill-rule:nonzero;stroke:#babdb6;stroke-width:1.875;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
|
||||
d="m 221.5625,142.98978 c -1.875,0 -2.70684,0.94013 -2.80606,2.81249 l -0.94394,17.81251 c -0.0992,1.87237 0.9375,2.81249 2.8125,2.81249 h 18.75 c 1.875,0 2.911,-0.94009 2.8125,-2.8125 l -0.9375,-17.8125 c -0.0985,-1.8724 -0.9375,-2.8125 -2.8125,-2.8125 z"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="sscsscsss" />
|
||||
<path
|
||||
sodipodi:nodetypes="sssssssssssss"
|
||||
inkscape:connector-curvature="0"
|
||||
id="button7"
|
||||
d="m 227.1875,176.73977 v 7.5 c 0,1.875 -0.36208,2.76945 -0.9375,4.6875 l -2.8125,9.375 c -0.5625,1.875 -0.92837,1.875 -2.8125,1.875 h -0.9375 c -1.875,0 -2.37981,0 -2.8125,-1.875 l -2.8125,-12.1875 c -0.43118,-1.86845 -0.9375,-3.75 -0.9375,-5.625 v -3.75 c 0,-1.875 0.9375,-2.8125 2.8125,-2.8125 h 8.4375 c 1.875,0 2.8125,0.9375 2.8125,2.8125 z"
|
||||
style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:#babdb6;stroke-width:1.875;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate" />
|
||||
<path
|
||||
sodipodi:type="arc"
|
||||
style="fill:none;fill-opacity:0.39215686;stroke:#babdb6;stroke-width:9.375;stroke-linecap:square;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
id="led0"
|
||||
sodipodi:cx="230"
|
||||
sodipodi:cy="317.36478"
|
||||
sodipodi:rx="16.875"
|
||||
sodipodi:ry="16.875002"
|
||||
d="m 241.93243,305.43235 a 16.875,16.875002 0 0 1 0,23.86485 16.875,16.875002 0 0 1 -23.86486,1e-5 16.875,16.875002 0 0 1 0,-23.86486"
|
||||
sodipodi:start="5.4977871"
|
||||
sodipodi:end="3.9269907"
|
||||
sodipodi:open="true"
|
||||
sodipodi:arc-type="arc" />
|
||||
<path
|
||||
style="opacity:1;vector-effect:none;fill:#babdb6;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:9.375;stroke-linecap:square;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
|
||||
d="m 202,104 v 2 l -2,2 2,2 v 2 l -4,-4 z"
|
||||
id="button9"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="ccccccc"
|
||||
transform="translate(0,-2.6666495)" />
|
||||
<path
|
||||
style="opacity:1;vector-effect:none;fill:#babdb6;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:9.375;stroke-linecap:square;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
|
||||
d="m 258,104 v 2 l 2,2 -2,2 v 2 l 4,-4 z"
|
||||
id="button10"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="ccccccc"
|
||||
transform="translate(0,-2.6666495)" />
|
||||
</g>
|
||||
<g
|
||||
inkscape:groupmode="layer"
|
||||
id="Buttons"
|
||||
inkscape:label="Buttons"
|
||||
style="display:inline">
|
||||
<g
|
||||
id="button0-path">
|
||||
<path
|
||||
sodipodi:nodetypes="cc"
|
||||
inkscape:connector-curvature="0"
|
||||
id="path4699"
|
||||
d="M 180,99.999995 H 1"
|
||||
style="opacity:1;vector-effect:none;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#888a85;stroke-width:1;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
|
||||
<rect
|
||||
y="96.5"
|
||||
x="176.5"
|
||||
height="7"
|
||||
width="7"
|
||||
id="rect4744-7"
|
||||
style="display:inline;opacity:1;vector-effect:none;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:0;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none" />
|
||||
<rect
|
||||
style="text-align:end;display:inline;fill:#888a85;fill-opacity:1;stroke:none;stroke-width:0.99999994"
|
||||
id="button0-leader"
|
||||
width="1"
|
||||
height="1"
|
||||
x="-6.0989584e-07"
|
||||
y="99.5"
|
||||
inkscape:label="#rect5374" />
|
||||
</g>
|
||||
<g
|
||||
id="button9-path">
|
||||
<path
|
||||
sodipodi:nodetypes="ccc"
|
||||
inkscape:connector-curvature="0"
|
||||
id="path4697"
|
||||
d="m 212,108 -32,32 H 1"
|
||||
style="opacity:1;vector-effect:none;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#888a85;stroke-width:1;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
|
||||
<rect
|
||||
y="104.5"
|
||||
x="208.5"
|
||||
height="7"
|
||||
width="7"
|
||||
id="rect4744"
|
||||
style="display:inline;opacity:1;vector-effect:none;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:0;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none" />
|
||||
<rect
|
||||
style="text-align:end;display:inline;fill:#888a85;fill-opacity:1;stroke:none;stroke-width:0.99999994"
|
||||
id="button9-leader"
|
||||
width="1"
|
||||
height="1"
|
||||
x="-6.0989584e-07"
|
||||
y="139.5"
|
||||
inkscape:label="#rect5374" />
|
||||
</g>
|
||||
<g
|
||||
id="button7-path">
|
||||
<path
|
||||
sodipodi:nodetypes="cc"
|
||||
inkscape:connector-curvature="0"
|
||||
id="path4695"
|
||||
d="M 221,180 H 1"
|
||||
style="opacity:1;vector-effect:none;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#888a85;stroke-width:1;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
|
||||
<rect
|
||||
y="176.5"
|
||||
x="216.5"
|
||||
height="7"
|
||||
width="7"
|
||||
id="rect4744-0"
|
||||
style="display:inline;opacity:1;vector-effect:none;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:0;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none" />
|
||||
<rect
|
||||
style="text-align:end;display:inline;fill:#888a85;fill-opacity:1;stroke:none;stroke-width:0.99999994"
|
||||
id="button7-leader"
|
||||
width="1"
|
||||
height="1"
|
||||
x="-6.0989584e-07"
|
||||
y="179.5"
|
||||
inkscape:label="#rect5374" />
|
||||
</g>
|
||||
<g
|
||||
id="button4-path">
|
||||
<path
|
||||
sodipodi:nodetypes="ccc"
|
||||
inkscape:connector-curvature="0"
|
||||
id="path4693"
|
||||
d="m 140,200 -20,20 H 1"
|
||||
style="opacity:1;vector-effect:none;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#888a85;stroke-width:1;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
|
||||
<rect
|
||||
y="196.5"
|
||||
x="136.5"
|
||||
height="7"
|
||||
width="7"
|
||||
id="rect4744-9"
|
||||
style="display:inline;opacity:1;vector-effect:none;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:0;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none" />
|
||||
<rect
|
||||
style="text-align:end;display:inline;fill:#888a85;fill-opacity:1;stroke:none;stroke-width:0.99999994"
|
||||
id="button4-leader"
|
||||
width="1"
|
||||
height="1"
|
||||
x="-6.0989584e-07"
|
||||
y="219.5"
|
||||
inkscape:label="#rect5374" />
|
||||
</g>
|
||||
<g
|
||||
id="button3-path">
|
||||
<path
|
||||
sodipodi:nodetypes="cc"
|
||||
inkscape:connector-curvature="0"
|
||||
id="path4691"
|
||||
d="M 148,260 H 1"
|
||||
style="opacity:1;vector-effect:none;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#888a85;stroke-width:1;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
|
||||
<rect
|
||||
y="256.5"
|
||||
x="144.5"
|
||||
height="7"
|
||||
width="7"
|
||||
id="rect4744-1"
|
||||
style="display:inline;opacity:1;vector-effect:none;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:0;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none" />
|
||||
<rect
|
||||
style="text-align:end;display:inline;fill:#888a85;fill-opacity:1;stroke:none;stroke-width:0.99999994"
|
||||
id="button3-leader"
|
||||
width="1"
|
||||
height="1"
|
||||
x="-6.0989584e-07"
|
||||
y="259.5"
|
||||
inkscape:label="#rect5374" />
|
||||
</g>
|
||||
<g
|
||||
id="button5-path">
|
||||
<path
|
||||
sodipodi:nodetypes="cc"
|
||||
inkscape:connector-curvature="0"
|
||||
id="path4711"
|
||||
d="M 312,260 H 459"
|
||||
style="opacity:1;vector-effect:none;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#888a85;stroke-width:1;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
|
||||
<rect
|
||||
y="256.5"
|
||||
x="308.5"
|
||||
height="7"
|
||||
width="7"
|
||||
id="rect4744-27"
|
||||
style="display:inline;opacity:1;vector-effect:none;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:0;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none" />
|
||||
<rect
|
||||
style="text-align:start;display:inline;fill:#888a85;fill-opacity:1;stroke:none;stroke-width:0.99999994"
|
||||
id="button5-leader"
|
||||
width="1"
|
||||
height="1"
|
||||
x="459"
|
||||
y="259.5"
|
||||
inkscape:label="#rect5374" />
|
||||
</g>
|
||||
<g
|
||||
id="button6-path">
|
||||
<path
|
||||
sodipodi:nodetypes="ccc"
|
||||
inkscape:connector-curvature="0"
|
||||
id="path4709"
|
||||
d="m 320,200 20,20 h 119"
|
||||
style="opacity:1;vector-effect:none;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#888a85;stroke-width:1;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
|
||||
<rect
|
||||
y="196.5"
|
||||
x="316.5"
|
||||
height="7"
|
||||
width="7"
|
||||
id="rect4744-2"
|
||||
style="display:inline;opacity:1;vector-effect:none;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:0;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none" />
|
||||
<rect
|
||||
style="text-align:start;display:inline;fill:#888a85;fill-opacity:1;stroke:none;stroke-width:0.99999994"
|
||||
id="button6-leader"
|
||||
width="1"
|
||||
height="1"
|
||||
x="459"
|
||||
y="219.5"
|
||||
inkscape:label="#rect5374" />
|
||||
</g>
|
||||
<g
|
||||
id="button8-path">
|
||||
<path
|
||||
sodipodi:nodetypes="cc"
|
||||
inkscape:connector-curvature="0"
|
||||
id="path4707"
|
||||
d="M 240,180 H 459"
|
||||
style="opacity:1;vector-effect:none;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#888a85;stroke-width:1;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
|
||||
<rect
|
||||
y="176.5"
|
||||
x="236.5"
|
||||
height="7"
|
||||
width="7"
|
||||
id="rect4744-93"
|
||||
style="display:inline;opacity:1;vector-effect:none;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:0;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none" />
|
||||
<rect
|
||||
style="text-align:start;display:inline;fill:#888a85;fill-opacity:1;stroke:none;stroke-width:0.99999994"
|
||||
id="button8-leader"
|
||||
width="1"
|
||||
height="1"
|
||||
x="459"
|
||||
y="179.5"
|
||||
inkscape:label="#rect5374" />
|
||||
</g>
|
||||
<g
|
||||
id="button10-path">
|
||||
<path
|
||||
sodipodi:nodetypes="ccc"
|
||||
inkscape:connector-curvature="0"
|
||||
id="path4701"
|
||||
d="m 248,108 32,32 h 179"
|
||||
style="opacity:1;vector-effect:none;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#888a85;stroke-width:1;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
|
||||
<rect
|
||||
y="104.5"
|
||||
x="244.5"
|
||||
height="7"
|
||||
width="7"
|
||||
id="rect4744-56"
|
||||
style="display:inline;opacity:1;vector-effect:none;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:0;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none" />
|
||||
<rect
|
||||
style="text-align:start;display:inline;fill:#888a85;fill-opacity:1;stroke:none;stroke-width:0.99999994"
|
||||
id="button10-leader"
|
||||
width="1"
|
||||
height="1"
|
||||
x="459"
|
||||
y="139.5"
|
||||
inkscape:label="#rect5374" />
|
||||
</g>
|
||||
<g
|
||||
id="button1-path">
|
||||
<path
|
||||
sodipodi:nodetypes="cc"
|
||||
inkscape:connector-curvature="0"
|
||||
id="path4703"
|
||||
d="M 280,99.999995 H 459"
|
||||
style="opacity:1;vector-effect:none;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#888a85;stroke-width:1;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
|
||||
<rect
|
||||
y="96.5"
|
||||
x="276.5"
|
||||
height="7"
|
||||
width="7"
|
||||
id="rect4744-3"
|
||||
style="display:inline;opacity:1;vector-effect:none;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:0;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none" />
|
||||
<rect
|
||||
style="text-align:start;display:inline;fill:#888a85;fill-opacity:1;stroke:none;stroke-width:0.99999994"
|
||||
id="button1-leader"
|
||||
width="1"
|
||||
height="1"
|
||||
x="459"
|
||||
y="99.5"
|
||||
inkscape:label="#rect5374" />
|
||||
</g>
|
||||
<g
|
||||
id="button2-path">
|
||||
<path
|
||||
sodipodi:nodetypes="ccc"
|
||||
inkscape:connector-curvature="0"
|
||||
id="path4705"
|
||||
d="M 230,87.999999 258,59.999995 H 459"
|
||||
style="opacity:1;vector-effect:none;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#888a85;stroke-width:1;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
|
||||
<rect
|
||||
y="84.5"
|
||||
x="226.5"
|
||||
height="7"
|
||||
width="7"
|
||||
id="rect4744-5"
|
||||
style="display:inline;opacity:1;vector-effect:none;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:0;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none" />
|
||||
<rect
|
||||
style="text-align:start;display:inline;fill:#888a85;fill-opacity:1;stroke:none;stroke-width:0.99999994"
|
||||
id="button2-leader"
|
||||
width="1"
|
||||
height="1"
|
||||
x="459"
|
||||
y="59.5"
|
||||
inkscape:label="#rect5374" />
|
||||
</g>
|
||||
</g>
|
||||
<g
|
||||
inkscape:groupmode="layer"
|
||||
id="LEDs"
|
||||
inkscape:label="LEDs">
|
||||
<g
|
||||
id="led0-path">
|
||||
<path
|
||||
sodipodi:nodetypes="cc"
|
||||
inkscape:connector-curvature="0"
|
||||
id="path4705-0"
|
||||
d="m 230,320 229.375,0"
|
||||
style="opacity:1;vector-effect:none;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#888a85;stroke-width:1;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
|
||||
<rect
|
||||
style="text-align:start;display:inline;fill:#888a85;fill-opacity:1;stroke:none;stroke-width:0.99999994"
|
||||
id="led0-leader"
|
||||
width="1"
|
||||
height="1"
|
||||
x="459"
|
||||
y="319.5"
|
||||
inkscape:label="#rect5374" />
|
||||
<rect
|
||||
y="316.5"
|
||||
x="226.5"
|
||||
height="7"
|
||||
width="7"
|
||||
id="rect4744-5-3"
|
||||
style="display:inline;opacity:1;vector-effect:none;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:0;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none" />
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 28 KiB |
@@ -102,23 +102,28 @@
|
||||
<sodipodi:guide
|
||||
position="125.24434,292.81279"
|
||||
orientation="1,0"
|
||||
id="guide4350" />
|
||||
id="guide4350"
|
||||
inkscape:locked="false" />
|
||||
<sodipodi:guide
|
||||
position="232.01745,389.68642"
|
||||
orientation="0,1"
|
||||
id="guide4352" />
|
||||
id="guide4352"
|
||||
inkscape:locked="false" />
|
||||
<sodipodi:guide
|
||||
position="339.49769,179.67571"
|
||||
orientation="1,0"
|
||||
id="guide4354" />
|
||||
id="guide4354"
|
||||
inkscape:locked="false" />
|
||||
<sodipodi:guide
|
||||
position="262.42305,21.283798"
|
||||
orientation="0,1"
|
||||
id="guide4356" />
|
||||
id="guide4356"
|
||||
inkscape:locked="false" />
|
||||
<sodipodi:guide
|
||||
position="61.51829,157.33126"
|
||||
orientation="1,0"
|
||||
id="guide5867" />
|
||||
id="guide5867"
|
||||
inkscape:locked="false" />
|
||||
</sodipodi:namedview>
|
||||
<metadata
|
||||
id="metadata5">
|
||||
@@ -128,7 +133,7 @@
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
<dc:title />
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
@@ -193,7 +198,7 @@
|
||||
<path
|
||||
sodipodi:nodetypes="ccccc"
|
||||
inkscape:connector-curvature="0"
|
||||
id="button9"
|
||||
id="button7"
|
||||
d="m 209.20722,524.3296 -0.65676,27.92859 -17.18836,0 -0.65677,-27.92859 z"
|
||||
style="color:#000000;overflow:visible;opacity:1;fill:#ffffff;fill-opacity:1;stroke:#babdb6;stroke-width:1;stroke-linecap:butt;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal"
|
||||
inkscape:label="#path942" />
|
||||
@@ -201,7 +206,7 @@
|
||||
inkscape:label="#path942"
|
||||
style="color:#000000;overflow:visible;opacity:1;fill:#ffffff;fill-opacity:1;stroke:#babdb6;stroke-width:1;stroke-linecap:butt;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal"
|
||||
d="m 208.41172,565.23341 -1.86126,32.17123 c -0.25984,4.4912 -1.83301,4.12045 -6.59419,4.12045 -4.76117,0 -6.33658,0.37088 -6.59417,-4.12045 l -1.94966,-31.99445 z"
|
||||
id="button10"
|
||||
id="button8"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="cssscc" />
|
||||
<path
|
||||
@@ -220,7 +225,7 @@
|
||||
<path
|
||||
sodipodi:nodetypes="ccccc"
|
||||
inkscape:connector-curvature="0"
|
||||
id="button11"
|
||||
id="button9"
|
||||
d="m 206.55097,441.9448 1.9995,15.20984 -17.18836,0 1.99948,-15.17859 z"
|
||||
style="color:#000000;overflow:visible;opacity:1;fill:#ffffff;fill-opacity:1;stroke:#babdb6;stroke-width:1;stroke-linecap:butt;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal"
|
||||
inkscape:label="#path942" />
|
||||
@@ -258,11 +263,11 @@
|
||||
<g
|
||||
id="button1-path"
|
||||
inkscape:label="#g131"
|
||||
transform="translate(8,72)">
|
||||
transform="translate(8,111.99976)">
|
||||
<path
|
||||
sodipodi:nodetypes="cc"
|
||||
sodipodi:nodetypes="ccc"
|
||||
style="color:#000000;overflow:visible;opacity:1;fill:none;fill-opacity:1;stroke:#888a85;stroke-width:1;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal"
|
||||
d="m 242.94764,50.505764 194.05236,0"
|
||||
d="M 221.19764,23.005764 248.71312,50.628685 437,50.505764"
|
||||
id="path958"
|
||||
inkscape:connector-curvature="0" />
|
||||
<rect
|
||||
@@ -270,8 +275,8 @@
|
||||
id="rect968"
|
||||
width="6.999999"
|
||||
height="6.999999"
|
||||
x="237"
|
||||
y="47.005764" />
|
||||
x="217.125"
|
||||
y="19.255764" />
|
||||
<rect
|
||||
inkscape:label="#rect867"
|
||||
style="color:#000000;text-align:start;overflow:visible;fill:#888a85;fill-opacity:1;stroke:none;stroke-linecap:round"
|
||||
@@ -282,7 +287,7 @@
|
||||
y="50.005764" />
|
||||
</g>
|
||||
<g
|
||||
id="button11-path"
|
||||
id="button9-path"
|
||||
inkscape:label="#g141"
|
||||
transform="translate(8,-88)">
|
||||
<path
|
||||
@@ -303,7 +308,7 @@
|
||||
<rect
|
||||
inkscape:label="#rect871"
|
||||
style="color:#000000;text-align:start;overflow:visible;fill:#888a85;fill-opacity:1;stroke:none;stroke-linecap:round"
|
||||
id="button11-leader"
|
||||
id="button9-leader"
|
||||
width="1"
|
||||
height="1"
|
||||
x="437"
|
||||
@@ -336,12 +341,12 @@
|
||||
y="92" />
|
||||
</g>
|
||||
<g
|
||||
id="button10-path"
|
||||
id="button8-path"
|
||||
inkscape:label="#g146"
|
||||
transform="translate(8,-8)">
|
||||
transform="matrix(1,0,0,-1,8,371.99953)">
|
||||
<path
|
||||
style="color:#000000;overflow:visible;opacity:1;fill:none;fill-opacity:1;stroke:#888a85;stroke-width:0.99999994;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal"
|
||||
d="m 436.55132,170.50615 -223.20734,0 -18.11371,18.15319"
|
||||
d="M 436.55132,170.50615 H 213.34398 l -18.11371,18.15319"
|
||||
id="path51"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="ccc" />
|
||||
@@ -357,14 +362,14 @@
|
||||
x="437"
|
||||
height="1"
|
||||
width="1"
|
||||
id="button10-leader"
|
||||
id="button8-leader"
|
||||
style="color:#000000;text-align:start;overflow:visible;fill:#888a85;fill-opacity:1;stroke:none;stroke-linecap:round"
|
||||
inkscape:label="#rect871" />
|
||||
</g>
|
||||
<g
|
||||
transform="translate(-72.0872,-77.953227)"
|
||||
style="display:inline"
|
||||
id="button9-path"
|
||||
id="button7-path"
|
||||
inkscape:label="#g191">
|
||||
<path
|
||||
style="color:#000000;overflow:visible;opacity:1;fill:none;fill-opacity:1;stroke:#888a85;stroke-width:1;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal"
|
||||
@@ -383,7 +388,7 @@
|
||||
<rect
|
||||
transform="scale(-1,-1)"
|
||||
style="color:#000000;text-align:end;overflow:visible;fill:#888a85;fill-opacity:1;stroke:none;stroke-linecap:round"
|
||||
id="button9-leader"
|
||||
id="button7-leader"
|
||||
width="1"
|
||||
height="1"
|
||||
x="-37.168953"
|
||||
@@ -452,12 +457,12 @@
|
||||
inkscape:label="#g191"
|
||||
id="button0-path"
|
||||
style="display:inline"
|
||||
transform="translate(-72.0872,-137.95323)">
|
||||
transform="translate(-72.0872,-177.95275)">
|
||||
<path
|
||||
sodipodi:nodetypes="cccc"
|
||||
inkscape:connector-curvature="0"
|
||||
id="button0-line"
|
||||
d="m 37.16895,320.50027 59.327469,0 99.344411,-99.98695 26.85261,0"
|
||||
d="m 37.16895,320.50027 h 59.327469 l 99.344411,-99.98695 h 26.85261"
|
||||
style="color:#000000;overflow:visible;opacity:1;fill:none;fill-opacity:1;stroke:#888a85;stroke-width:1;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal"
|
||||
inkscape:label="#path5841" />
|
||||
<rect
|
||||
@@ -467,7 +472,7 @@
|
||||
width="6.999999"
|
||||
id="button0-rect"
|
||||
style="color:#000000;overflow:visible;opacity:1;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:2;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal"
|
||||
transform="scale(-1,-1)"
|
||||
transform="scale(-1)"
|
||||
inkscape:label="#rect5843" />
|
||||
<rect
|
||||
inkscape:label="#rect873"
|
||||
@@ -477,7 +482,64 @@
|
||||
width="1"
|
||||
id="button0-leader"
|
||||
style="color:#000000;text-align:end;overflow:visible;fill:#888a85;fill-opacity:1;stroke:none;stroke-linecap:round"
|
||||
transform="scale(-1,-1)" />
|
||||
transform="scale(-1)" />
|
||||
</g>
|
||||
<g
|
||||
transform="translate(-72.0872,-137.95275)"
|
||||
style="display:inline"
|
||||
id="button5-path"
|
||||
inkscape:label="#g191">
|
||||
<path
|
||||
inkscape:label="#path5841"
|
||||
style="color:#000000;overflow:visible;opacity:1;fill:none;fill-opacity:1;stroke:#888a85;stroke-width:1;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal"
|
||||
d="m 37.16895,320.50027 h 59.327469 l 88.152021,-88.86195 h 55.67"
|
||||
id="path85"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="cccc" />
|
||||
<rect
|
||||
inkscape:label="#rect5843"
|
||||
transform="scale(-1)"
|
||||
style="color:#000000;overflow:visible;opacity:1;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:2;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal"
|
||||
id="rect87"
|
||||
width="6.999999"
|
||||
height="6.999999"
|
||||
x="-244.00287"
|
||||
y="-235.48463" />
|
||||
<rect
|
||||
transform="scale(-1)"
|
||||
style="color:#000000;text-align:end;overflow:visible;fill:#888a85;fill-opacity:1;stroke:none;stroke-linecap:round"
|
||||
id="button5-leader"
|
||||
width="1"
|
||||
height="1"
|
||||
x="-37.168953"
|
||||
y="-321.00027"
|
||||
inkscape:label="#rect873" />
|
||||
</g>
|
||||
<g
|
||||
transform="translate(10.625,71.49976)"
|
||||
inkscape:label="#g131"
|
||||
id="button6-path">
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
id="path93"
|
||||
d="m 221.19764,23.005764 27.51548,27.622921 185.72362,-0.122921"
|
||||
style="color:#000000;overflow:visible;opacity:1;fill:none;fill-opacity:1;stroke:#888a85;stroke-width:1;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal"
|
||||
sodipodi:nodetypes="ccc" />
|
||||
<rect
|
||||
y="19.255764"
|
||||
x="217.125"
|
||||
height="6.999999"
|
||||
width="6.999999"
|
||||
id="rect95"
|
||||
style="color:#000000;overflow:visible;opacity:1;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:2;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal" />
|
||||
<rect
|
||||
y="50.005764"
|
||||
x="434.37524"
|
||||
height="1"
|
||||
width="1"
|
||||
id="button6-leader"
|
||||
style="color:#000000;text-align:start;overflow:visible;fill:#888a85;fill-opacity:1;stroke:none;stroke-linecap:round"
|
||||
inkscape:label="#rect867" />
|
||||
</g>
|
||||
</g>
|
||||
<g
|
||||
|
||||
|
Before Width: | Height: | Size: 29 KiB After Width: | Height: | Size: 32 KiB |
300
data/gnome/steelseries-kinzu-v2.svg
Normal file
|
After Width: | Height: | Size: 739 KiB |
443
data/gnome/steelseries-rival310.svg
Normal file
@@ -0,0 +1,443 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="490"
|
||||
height="490"
|
||||
viewBox="0 0 129.64583 129.64583"
|
||||
version="1.1"
|
||||
id="svg8"
|
||||
sodipodi:docname="steelseries-rival310.svg"
|
||||
inkscape:version="0.92.2 (5c3e80d, 2017-08-06)">
|
||||
<defs
|
||||
id="defs2" />
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="1.4142136"
|
||||
inkscape:cx="158.34512"
|
||||
inkscape:cy="283.9471"
|
||||
inkscape:document-units="px"
|
||||
inkscape:current-layer="Device"
|
||||
inkscape:document-rotation="0"
|
||||
showgrid="false"
|
||||
showguides="false"
|
||||
inkscape:window-width="1920"
|
||||
inkscape:window-height="1163"
|
||||
inkscape:window-x="1920"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-maximized="1"
|
||||
showborder="true"
|
||||
inkscape:guide-bbox="true"
|
||||
units="px"
|
||||
inkscape:snap-global="false"
|
||||
inkscape:measure-start="241.5,424.5"
|
||||
inkscape:measure-end="193,423">
|
||||
<inkscape:grid
|
||||
type="xygrid"
|
||||
id="grid78" />
|
||||
<sodipodi:guide
|
||||
position="58.722772,112.40709"
|
||||
orientation="0,1"
|
||||
id="guide79"
|
||||
inkscape:locked="false" />
|
||||
<sodipodi:guide
|
||||
position="39.611923,100.54373"
|
||||
orientation="0,1"
|
||||
id="guide81"
|
||||
inkscape:locked="false" />
|
||||
<sodipodi:guide
|
||||
position="51.756014,88.614617"
|
||||
orientation="0,1"
|
||||
id="guide83"
|
||||
inkscape:locked="false" />
|
||||
<sodipodi:guide
|
||||
position="57.778386,76.729167"
|
||||
orientation="0,1"
|
||||
id="guide85"
|
||||
inkscape:locked="false" />
|
||||
<sodipodi:guide
|
||||
position="45.047078,64.795712"
|
||||
orientation="0,1"
|
||||
inkscape:locked="false"
|
||||
id="guide87" />
|
||||
<sodipodi:guide
|
||||
position="57.646696,52.899321"
|
||||
orientation="0,1"
|
||||
id="guide89"
|
||||
inkscape:locked="false" />
|
||||
<sodipodi:guide
|
||||
position="64.031094,118.70775"
|
||||
orientation="1,0"
|
||||
id="guide996"
|
||||
inkscape:locked="false" />
|
||||
<sodipodi:guide
|
||||
position="76.729165,115.65599"
|
||||
orientation="1,0"
|
||||
id="guide4799"
|
||||
inkscape:locked="false" />
|
||||
</sodipodi:namedview>
|
||||
<metadata
|
||||
id="metadata5">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title />
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
inkscape:groupmode="layer"
|
||||
id="Device"
|
||||
inkscape:label="Device"
|
||||
style="display:inline;opacity:1"
|
||||
transform="translate(0,-167.35416)">
|
||||
<path
|
||||
style="fill:#d3d3ce;fill-opacity:1;fill-rule:evenodd;stroke:#bfc2bb;stroke-width:0.98636663;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;opacity:1"
|
||||
d="m 39.422916,178.73125 c 8.753298,-5.1263 8.742273,-5.15937 19.909893,-6.35 0.86322,1.81872 1.399035,2.16412 3.571875,2.57968 0.815799,-0.022 1.631597,-0.0441 2.447396,-0.0661 1.808025,-0.44162 2.142728,-0.67277 3.108854,-2.4474 11.230355,1.36029 11.188618,1.38757 18.25625,6.74688 2.745052,3.1309 3.671094,5.00504 4.365625,8.59896 0.264583,5.1263 1.254823,10.18645 1.320969,15.27968 4.850693,20.06424 6.726771,34.70452 8.270172,54.63646 -0.57326,10.05417 -1.411108,14.15521 -6.879162,21.43125 -5.55625,5.60034 -10.31875,7.8934 -17.859375,10.84791 -7.805208,1.74184 -11.509375,1.76389 -18.653125,0.46302 -6.32795,-1.67569 -10.384244,-5.1794 -14.221351,-10.58333 -4.882794,-8.38114 -5.236545,-14.94896 -7.408333,-22.62187 -0.782726,-9.55807 -1.367014,-19.31459 -2.050521,-28.97188 l 2.38125,-0.39687 c -0.0441,-0.50712 -0.08819,-1.01423 -0.132292,-1.52135 l -2.38125,-0.99219 v -17.19792 c 0.617361,-1.6316 1.234723,-3.26319 1.852084,-4.89479 l 0.926041,-18.1901 c 0.496094,-3.10887 1.256771,-4.69638 3.175,-6.35004 z"
|
||||
id="path882"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="cccccccccccccccccccccc" />
|
||||
<path
|
||||
sodipodi:type="arc"
|
||||
style="display:inline;opacity:1;fill:none;fill-opacity:0.39215686;stroke:#babdb6;stroke-width:3.62082291;stroke-linecap:square;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
id="led0"
|
||||
sodipodi:cx="64.507607"
|
||||
sodipodi:cy="278.93338"
|
||||
sodipodi:rx="6.5174346"
|
||||
sodipodi:ry="6.5174408"
|
||||
d="m 69.116129,274.32485 a 6.5174346,6.5174408 0 0 1 0,9.21706 6.5174346,6.5174408 0 0 1 -9.217044,0 6.5174346,6.5174408 0 0 1 -10e-7,-9.21706"
|
||||
sodipodi:start="5.4977871"
|
||||
sodipodi:end="3.9269907"
|
||||
sodipodi:open="true"
|
||||
sodipodi:arc-type="arc"
|
||||
inkscape:label="#led1" />
|
||||
<path
|
||||
style="display:inline;opacity:1;fill:none;stroke:#babdb6;stroke-width:0.51011664;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 63.998032,175.33704 c -0.0617,17.18181 0,37.8177 0,37.8177 v 0"
|
||||
id="path4530-9"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="ccc" />
|
||||
<rect
|
||||
style="display:inline;opacity:1;fill:#eeeeec;fill-opacity:1;stroke:#bfc2bb;stroke-width:0.65934163;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
id="button2"
|
||||
width="8.6572962"
|
||||
height="16.992365"
|
||||
x="59.667027"
|
||||
y="183.8551"
|
||||
ry="1.5045637"
|
||||
inkscape:label="#rect4615"
|
||||
rx="2.8998742" />
|
||||
<rect
|
||||
style="display:inline;opacity:1;fill:#d3d3ce;fill-opacity:1;stroke:#bfc2bb;stroke-width:0.51011665;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
id="button5"
|
||||
width="4.0773749"
|
||||
height="11.664907"
|
||||
x="61.934288"
|
||||
y="213.306"
|
||||
ry="0.74915975"
|
||||
inkscape:label="#rect4615"
|
||||
rx="0.63142258" />
|
||||
<path
|
||||
style="fill:#eeeeec;fill-opacity:1;fill-rule:evenodd;stroke:#bfc2bb;stroke-width:0.65934163;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;opacity:1"
|
||||
d="m 92.234711,203.24519 c 0.280629,9.51034 -0.467724,16.09741 -0.467724,24.43845 -0.763945,13.64188 -1.153714,9.79098 -1.590254,28.48425 -0.04677,3.7028 1.344699,5.74518 2.50231,6.78196 1.157611,1.03679 4.41997,3.85091 6.618261,5.14494 0.941986,-4.54444 1.338226,-4.86758 1.335156,-10.49869 -0.4989,-10.35224 -1.350744,-19.81747 -3.369743,-31.52609 -1.652616,-7.76419 -1.878682,-12.53495 -5.028008,-22.82482 z"
|
||||
id="path959"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="cccsccccc" />
|
||||
<path
|
||||
style="fill:#eeeeec;fill-opacity:1;fill-rule:evenodd;stroke:#bfc2bb;stroke-width:0.65934163;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;opacity:1"
|
||||
d="m 37.603906,265.61379 c 1.378038,-1.69774 1.896181,-2.56866 2.447396,-4.49791 0.275607,-1.59853 0.319704,-2.27101 0.132291,-3.70417 -0.176389,-0.97014 -0.352777,-1.94028 -0.529166,-2.91042 -0.352778,0.022 -0.705556,0.0441 -1.058334,0.0661 -1.113455,-0.31971 -1.631597,-0.93707 -2.248958,-1.65365 -0.429948,-0.89297 -0.859896,-1.78593 -1.289844,-2.6789 0.176389,2.30408 0.352778,4.60816 0.529167,6.91224 0.672483,2.82224 1.344965,5.64447 2.017448,8.46671 z"
|
||||
id="path961"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="ccccccccc" />
|
||||
<path
|
||||
style="fill:#d3d3ce;fill-opacity:1;fill-rule:evenodd;stroke:#bfc2bb;stroke-width:0.51011665;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;opacity:1"
|
||||
d="m 39.662795,224.50314 c -1.418755,-15.53616 -1.294028,-30.04332 -0.748352,-45.27546 7.464057,-5.23848 10.578303,-5.75298 20.392662,-7.01583 0.604141,2.15932 2.552981,2.88039 4.583673,2.89988 0.06236,2.93106 -0.0039,5.75688 0.05847,8.68793 -0.966626,0.0156 -1.617539,-0.0389 -2.677709,0.15206 -0.576857,0.12082 -1.668207,0.59244 -1.683798,1.44993 0.03118,4.73958 0.06237,9.47916 0.09355,14.21874 0.428974,0.80223 0.791803,1.0753 1.683798,1.21608 h 2.666014 c 0.09354,3.89768 -0.04677,7.79536 0.04677,11.69304 -1.777343,0.0624 -3.554686,0.12473 -5.332029,0.18709 -4.677216,3.30523 -9.354432,6.61047 -14.031648,9.9157 -1.948383,1.15278 -3.036871,1.77639 -5.051401,1.87084 z"
|
||||
id="button0"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="ccccccccccccccc"
|
||||
inkscape:label="#path971" />
|
||||
<path
|
||||
style="display:inline;opacity:1;fill:#d3d3ce;fill-opacity:1;fill-rule:evenodd;stroke:#bfc2bb;stroke-width:0.51011664;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 88.538966,224.46383 c 1.418756,-15.53616 -0.763946,-29.5756 -1.309622,-44.80774 -6.341526,-5.61266 -8.520329,-6.2207 -18.334688,-7.48355 -0.604141,2.15932 -2.833614,2.83362 -4.864306,2.85311 -0.06236,2.93106 0.284533,5.80365 0.222163,8.7347 0.966626,0.0156 1.617539,-0.0389 2.677709,0.15206 0.576857,0.12082 1.668207,0.59244 1.683798,1.44993 -0.03118,4.73958 -0.06237,9.47916 -0.09355,14.21874 -0.428974,0.80223 -0.791803,1.0753 -1.683798,1.21608 h -2.80633 c -0.09354,3.89768 0.187088,7.79536 0.09354,11.69304 1.777343,0.0624 3.554686,0.12473 5.332029,0.18709 4.677216,3.30523 9.354432,6.61047 14.031649,9.9157 1.948382,1.15278 3.036871,1.77639 5.0514,1.87084 z"
|
||||
id="button1"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="ccccccccccccccc"
|
||||
inkscape:label="#path971-5" />
|
||||
<path
|
||||
style="fill:#d3d3ce;fill-opacity:1;fill-rule:evenodd;stroke:#bfc2bb;stroke-width:0.51011664;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;opacity:1"
|
||||
d="m 39.721262,254.48409 c -2.127995,-12.76601 -2.492187,-15.11204 -3.531298,-26.68352 -0.880877,0.16371 -1.761753,0.32741 -2.64263,0.49111 0.510597,7.26528 1.021194,14.53055 1.531791,21.79583 0.415673,1.21059 0.673654,1.8504 1.39147,2.98173 0.557369,0.65481 1.067966,1.08745 1.882582,1.5084 0.738934,0.12313 0.851361,0.031 1.368085,-0.0935 z"
|
||||
id="button3"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="ccccccc"
|
||||
inkscape:label="#path998" />
|
||||
<path
|
||||
style="fill:#d3d3ce;fill-opacity:1;fill-rule:evenodd;stroke:#bfc2bb;stroke-width:0.51011664;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;opacity:1"
|
||||
d="m 36.061341,226.30387 -2.595857,-0.95884 v -17.51617 l 2.128134,-4.89938 z"
|
||||
id="button4"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="ccccc"
|
||||
inkscape:label="#path1000" />
|
||||
<g
|
||||
id="g27"
|
||||
inkscape:label="#g84"
|
||||
style="opacity:1">
|
||||
<path
|
||||
inkscape:label="#path42"
|
||||
inkscape:connector-curvature="0"
|
||||
id="led1"
|
||||
d="m 60.202463,185.20746 c 0,14.31228 0,14.31228 0,14.31228"
|
||||
style="fill:#c8c8c8;fill-opacity:1;stroke:#babdb6;stroke-width:0.23228861px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
|
||||
<path
|
||||
inkscape:label="#path42"
|
||||
inkscape:connector-curvature="0"
|
||||
id="led0-3"
|
||||
d="m 67.749483,185.21452 c 0,14.31228 0,14.31228 0,14.31228"
|
||||
style="display:inline;opacity:1;fill:#c8c8c8;fill-opacity:1;stroke:#babdb6;stroke-width:0.23228861px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
|
||||
</g>
|
||||
</g>
|
||||
<g
|
||||
inkscape:groupmode="layer"
|
||||
id="Buttons"
|
||||
inkscape:label="Buttons"
|
||||
transform="translate(0,-2.6458338)"
|
||||
style="display:inline">
|
||||
<g
|
||||
transform="matrix(-0.29294531,0,0,0.26458333,70.19679,-46.28282)"
|
||||
style="display:inline"
|
||||
id="button0-path"
|
||||
inkscape:label="#g156">
|
||||
<path
|
||||
sodipodi:nodetypes="cc"
|
||||
style="color:#000000;overflow:visible;opacity:1;vector-effect:none;fill:none;fill-opacity:1;stroke:#888a85;stroke-width:1;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal"
|
||||
d="m 69.018882,250.50576 170.100828,0.008"
|
||||
id="path966"
|
||||
inkscape:connector-curvature="0" />
|
||||
<rect
|
||||
style="color:#000000;overflow:visible;opacity:1;vector-effect:none;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:2;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal"
|
||||
id="rect976"
|
||||
width="6.999999"
|
||||
height="6.999999"
|
||||
x="65.211685"
|
||||
y="247.25577" />
|
||||
<rect
|
||||
y="250.01747"
|
||||
x="238.66302"
|
||||
height="1"
|
||||
width="1"
|
||||
id="button0-leader"
|
||||
style="color:#000000;text-align:end;overflow:visible;vector-effect:none;fill:#888a85;fill-opacity:1;stroke:none;stroke-linecap:round"
|
||||
inkscape:label="#rect875" />
|
||||
</g>
|
||||
<g
|
||||
transform="matrix(0.26458333,0,0,0.26458333,40.502648,-25.152234)"
|
||||
style="display:inline"
|
||||
id="button1-path"
|
||||
inkscape:label="#g146">
|
||||
<path
|
||||
style="color:#000000;overflow:visible;opacity:1;vector-effect:none;fill:none;fill-opacity:1;stroke:#888a85;stroke-width:0.99999994;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal"
|
||||
d="m 336.41912,170.11088 -197.26264,0.0828"
|
||||
id="path51"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="cc" />
|
||||
<rect
|
||||
style="color:#000000;overflow:visible;opacity:1;vector-effect:none;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:2;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal"
|
||||
id="rect53"
|
||||
width="6.999999"
|
||||
height="6.999999"
|
||||
x="137"
|
||||
y="166.75" />
|
||||
<rect
|
||||
y="169.61206"
|
||||
x="335.92694"
|
||||
height="1"
|
||||
width="1"
|
||||
id="button1-leader"
|
||||
style="color:#000000;text-align:start;overflow:visible;vector-effect:none;fill:#888a85;fill-opacity:1;stroke:none;stroke-linecap:round"
|
||||
inkscape:label="#rect871" />
|
||||
</g>
|
||||
<g
|
||||
transform="matrix(0.26458333,0,0,0.26458333,39.927878,-13.516602)"
|
||||
style="display:inline"
|
||||
id="button2-path"
|
||||
inkscape:label="#g146">
|
||||
<path
|
||||
style="color:#000000;overflow:visible;opacity:1;vector-effect:none;fill:none;fill-opacity:1;stroke:#888a85;stroke-width:0.99999994;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal"
|
||||
d="M 338.62224,171.07963 91.069203,171.06803"
|
||||
id="path51-2"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="cc" />
|
||||
<rect
|
||||
style="color:#000000;overflow:visible;opacity:1;vector-effect:none;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:2;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal"
|
||||
id="rect53-3"
|
||||
width="6.999999"
|
||||
height="6.999999"
|
||||
x="87.596474"
|
||||
y="167.57452" />
|
||||
<rect
|
||||
y="170.56519"
|
||||
x="338.10663"
|
||||
height="1"
|
||||
width="1"
|
||||
id="button2-leader"
|
||||
style="color:#000000;text-align:start;overflow:visible;vector-effect:none;fill:#888a85;fill-opacity:1;stroke:none;stroke-linecap:round"
|
||||
inkscape:label="#rect871" />
|
||||
</g>
|
||||
<g
|
||||
transform="matrix(0.26458333,0,0,0.26458333,39.855422,10.357346)"
|
||||
style="display:inline"
|
||||
id="button5-path"
|
||||
inkscape:label="#g146">
|
||||
<path
|
||||
style="color:#000000;overflow:visible;opacity:1;vector-effect:none;fill:none;fill-opacity:1;stroke:#888a85;stroke-width:0.99999994;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal"
|
||||
d="M 338.91912,170.14213 91.343981,170.50618"
|
||||
id="path51-2-3"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="cc" />
|
||||
<rect
|
||||
style="color:#000000;overflow:visible;opacity:1;vector-effect:none;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:2;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal"
|
||||
id="rect53-3-4"
|
||||
width="6.999999"
|
||||
height="6.999999"
|
||||
x="88"
|
||||
y="167.375" />
|
||||
<rect
|
||||
y="169.65894"
|
||||
x="338.32538"
|
||||
height="1"
|
||||
width="1"
|
||||
id="button5-leader"
|
||||
style="color:#000000;text-align:start;overflow:visible;vector-effect:none;fill:#888a85;fill-opacity:1;stroke:none;stroke-linecap:round"
|
||||
inkscape:label="#rect871" />
|
||||
</g>
|
||||
<g
|
||||
transform="matrix(-0.29294531,0,0,0.26458333,70.354375,-10.600792)"
|
||||
style="display:inline"
|
||||
id="button4-path"
|
||||
inkscape:label="#g156">
|
||||
<path
|
||||
sodipodi:nodetypes="cc"
|
||||
style="color:#000000;overflow:visible;opacity:1;vector-effect:none;fill:none;fill-opacity:1;stroke:#888a85;stroke-width:1;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal"
|
||||
d="m 121.40352,250.50576 118.2207,0.0352"
|
||||
id="path966-1"
|
||||
inkscape:connector-curvature="0" />
|
||||
<rect
|
||||
style="color:#000000;overflow:visible;opacity:1;vector-effect:none;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:2;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal"
|
||||
id="rect976-3"
|
||||
width="6.999999"
|
||||
height="6.999999"
|
||||
x="118.01969"
|
||||
y="247.06827" />
|
||||
<rect
|
||||
y="250.06044"
|
||||
x="239.16049"
|
||||
height="1"
|
||||
width="1"
|
||||
id="button4-leader"
|
||||
style="color:#000000;text-align:end;overflow:visible;vector-effect:none;fill:#888a85;fill-opacity:1;stroke:none;stroke-linecap:round"
|
||||
inkscape:label="#rect875" />
|
||||
</g>
|
||||
<g
|
||||
transform="matrix(-0.29294531,0,0,0.26458333,70.260832,1.1857932)"
|
||||
style="display:inline"
|
||||
id="button3-path"
|
||||
inkscape:label="#g156">
|
||||
<path
|
||||
sodipodi:nodetypes="cc"
|
||||
style="color:#000000;overflow:visible;opacity:1;vector-effect:none;fill:none;fill-opacity:1;stroke:#888a85;stroke-width:1;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal"
|
||||
d="m 119.59715,250.50576 120.02707,0.0352"
|
||||
id="path966-2"
|
||||
inkscape:connector-curvature="0" />
|
||||
<rect
|
||||
style="color:#000000;overflow:visible;opacity:1;vector-effect:none;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:2;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal"
|
||||
id="rect976-8"
|
||||
width="6.999999"
|
||||
height="6.999999"
|
||||
x="116.24155"
|
||||
y="247.19327" />
|
||||
<rect
|
||||
y="250.00575"
|
||||
x="238.62422"
|
||||
height="1"
|
||||
width="1"
|
||||
id="button3-leader"
|
||||
style="color:#000000;text-align:end;overflow:visible;vector-effect:none;fill:#888a85;fill-opacity:1;stroke:none;stroke-linecap:round"
|
||||
inkscape:label="#rect875" />
|
||||
</g>
|
||||
</g>
|
||||
<g
|
||||
inkscape:groupmode="layer"
|
||||
id="LEDs"
|
||||
inkscape:label="LEDs"
|
||||
transform="translate(0,-2.6458338)"
|
||||
style="display:inline">
|
||||
<g
|
||||
transform="matrix(-0.29294531,0,0,0.26458333,69.912779,-34.520744)"
|
||||
style="display:inline"
|
||||
id="led1-path"
|
||||
inkscape:label="#g156">
|
||||
<path
|
||||
sodipodi:nodetypes="cc"
|
||||
style="color:#000000;overflow:visible;opacity:1;vector-effect:none;fill:none;fill-opacity:1;stroke:#888a85;stroke-width:1;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal"
|
||||
d="m 33.260958,250.40632 204.900782,0.0964"
|
||||
id="path966-0"
|
||||
inkscape:connector-curvature="0" />
|
||||
<rect
|
||||
style="color:#000000;overflow:visible;opacity:1;vector-effect:none;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:2;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal"
|
||||
id="rect976-2"
|
||||
width="6.999999"
|
||||
height="6.999999"
|
||||
x="29.527279"
|
||||
y="246.99062" />
|
||||
<rect
|
||||
y="249.97328"
|
||||
x="237.64519"
|
||||
height="1"
|
||||
width="1"
|
||||
id="led1-leader"
|
||||
style="color:#000000;text-align:end;overflow:visible;vector-effect:none;fill:#888a85;fill-opacity:1;stroke:none;stroke-linecap:round"
|
||||
inkscape:label="#rect875" />
|
||||
</g>
|
||||
<g
|
||||
transform="matrix(-0.29294531,0,0,0.26458333,69.953208,49.201431)"
|
||||
style="display:inline"
|
||||
id="led0-path"
|
||||
inkscape:label="#g156">
|
||||
<path
|
||||
sodipodi:nodetypes="cc"
|
||||
style="color:#000000;overflow:visible;opacity:1;vector-effect:none;fill:none;fill-opacity:1;stroke:#888a85;stroke-width:1;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal"
|
||||
d="m 19.28901,250.49471 219.01243,0.008"
|
||||
id="path966-0-2"
|
||||
inkscape:connector-curvature="0" />
|
||||
<rect
|
||||
style="color:#000000;overflow:visible;opacity:1;vector-effect:none;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:2;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal"
|
||||
id="rect976-2-1"
|
||||
width="6.999999"
|
||||
height="6.999999"
|
||||
x="16.834169"
|
||||
y="246.63705" />
|
||||
<rect
|
||||
y="249.97328"
|
||||
x="237.7849"
|
||||
height="1"
|
||||
width="1"
|
||||
id="led0-leader"
|
||||
style="color:#000000;text-align:end;overflow:visible;vector-effect:none;fill:#888a85;fill-opacity:1;stroke:none;stroke-linecap:round"
|
||||
inkscape:label="#rect875" />
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 23 KiB |
157
doc/conf.py.in
Normal file
@@ -0,0 +1,157 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# @PACKAGE_NAME@ documentation build configuration file, created by
|
||||
# sphinx-quickstart on Wed Oct 11 13:45:08 2017.
|
||||
#
|
||||
# This file is execfile()d with the current directory set to its
|
||||
# containing dir.
|
||||
#
|
||||
# Note that not all possible configuration values are present in this
|
||||
# autogenerated file.
|
||||
#
|
||||
# All configuration values have a default; values that are commented out
|
||||
# serve to show the default.
|
||||
|
||||
# If extensions (or modules to document with autodoc) are in another directory,
|
||||
# add these directories to sys.path here. If the directory is relative to the
|
||||
# documentation root, use os.path.abspath to make it absolute, like shown here.
|
||||
|
||||
import os
|
||||
import sys
|
||||
sys.path.insert(0, os.path.abspath('..'))
|
||||
|
||||
# -- General configuration ------------------------------------------------
|
||||
|
||||
# If your documentation needs a minimal Sphinx version, state it here.
|
||||
#
|
||||
# needs_sphinx = '1.0'
|
||||
|
||||
# Add any Sphinx extension module names here, as strings. They can be
|
||||
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
|
||||
# ones.
|
||||
extensions = []
|
||||
|
||||
# Add any paths that contain templates here, relative to this directory.
|
||||
templates_path = ['_templates']
|
||||
|
||||
# The suffix(es) of source filenames.
|
||||
# You can specify multiple suffix as a list of string:
|
||||
#
|
||||
# source_suffix = ['.rst', '.md']
|
||||
source_suffix = '.rst'
|
||||
|
||||
# The master toctree document.
|
||||
master_doc = 'index'
|
||||
|
||||
# General information about the project.
|
||||
project = '@PACKAGE_NAME@'
|
||||
copyright = '2017, The ratbaggers'
|
||||
author = 'The ratbaggers'
|
||||
|
||||
# The version info for the project you're documenting, acts as replacement for
|
||||
# |version| and |release|, also used in various other places throughout the
|
||||
# built documents.
|
||||
#
|
||||
# The short X.Y version.
|
||||
version = ''
|
||||
# The full version, including alpha/beta/rc tags.
|
||||
release = ''
|
||||
|
||||
# The language for content autogenerated by Sphinx. Refer to documentation
|
||||
# for a list of supported languages.
|
||||
#
|
||||
# This is also used if you do content translation via gettext catalogs.
|
||||
# Usually you set "language" from the command line for these cases.
|
||||
language = None
|
||||
|
||||
# List of patterns, relative to source directory, that match files and
|
||||
# directories to ignore when looking for source files.
|
||||
# This patterns also effect to html_static_path and html_extra_path
|
||||
exclude_patterns = []
|
||||
|
||||
# The name of the Pygments (syntax highlighting) style to use.
|
||||
pygments_style = 'sphinx'
|
||||
|
||||
# If true, `todo` and `todoList` produce output, else they produce nothing.
|
||||
todo_include_todos = False
|
||||
|
||||
|
||||
# -- Options for HTML output ----------------------------------------------
|
||||
|
||||
# The theme to use for HTML and HTML Help pages. See the documentation for
|
||||
# a list of builtin themes.
|
||||
#
|
||||
# html_theme = 'alabaster'
|
||||
html_theme = 'sphinx_rtd_theme'
|
||||
|
||||
# Theme options are theme-specific and customize the look and feel of a theme
|
||||
# further. For a list of options available for each theme, see the
|
||||
# documentation.
|
||||
#
|
||||
# html_theme_options = {}
|
||||
|
||||
# Add any paths that contain custom static files (such as style sheets) here,
|
||||
# relative to this directory. They are copied after the builtin static files,
|
||||
# so a file named "default.css" will overwrite the builtin "default.css".
|
||||
html_static_path = ['_static']
|
||||
|
||||
|
||||
# -- Options for HTMLHelp output ------------------------------------------
|
||||
|
||||
# Output file base name for HTML help builder.
|
||||
htmlhelp_basename = '@PACKAGE_NAME@doc'
|
||||
|
||||
|
||||
# -- Options for LaTeX output ---------------------------------------------
|
||||
|
||||
latex_elements = {
|
||||
# The paper size ('letterpaper' or 'a4paper').
|
||||
#
|
||||
# 'papersize': 'letterpaper',
|
||||
|
||||
# The font size ('10pt', '11pt' or '12pt').
|
||||
#
|
||||
# 'pointsize': '10pt',
|
||||
|
||||
# Additional stuff for the LaTeX preamble.
|
||||
#
|
||||
# 'preamble': '',
|
||||
|
||||
# Latex figure (float) alignment
|
||||
#
|
||||
# 'figure_align': 'htbp',
|
||||
}
|
||||
|
||||
# Grouping the document tree into LaTeX files. List of tuples
|
||||
# (source start file, target name, title,
|
||||
# author, documentclass [howto, manual, or own class]).
|
||||
latex_documents = [
|
||||
(master_doc, '@PACKAGE_NAME@.tex', '@PACKAGE_NAME@ Documentation',
|
||||
'The ratbaggers', 'manual'),
|
||||
]
|
||||
|
||||
|
||||
# -- Options for manual page output ---------------------------------------
|
||||
|
||||
# One entry per manual page. List of tuples
|
||||
# (source start file, name, description, authors, manual section).
|
||||
man_pages = [
|
||||
(master_doc, '@PACKAGE_NAME@', '@PACKAGE_NAME@ Documentation',
|
||||
[author], 1)
|
||||
]
|
||||
|
||||
|
||||
# -- Options for Texinfo output -------------------------------------------
|
||||
|
||||
# Grouping the document tree into Texinfo files. List of tuples
|
||||
# (source start file, target name, title, author,
|
||||
# dir menu entry, description, category)
|
||||
texinfo_documents = [
|
||||
(master_doc, '@PACKAGE_NAME@', '@PACKAGE_NAME@ Documentation',
|
||||
author, '@PACKAGE_NAME@', 'One line description of project.',
|
||||
'Miscellaneous'),
|
||||
]
|
||||
|
||||
|
||||
|
||||
446
doc/dbus.rst
Normal file
@@ -0,0 +1,446 @@
|
||||
********
|
||||
DBus API
|
||||
********
|
||||
|
||||
Note: **the DBus interface is subject to change**
|
||||
|
||||
Interfaces:
|
||||
|
||||
* org.freedesktop.ratbag1.Manager
|
||||
* org.freedesktop.ratbag1.Device
|
||||
* org.freedesktop.ratbag1.Profile
|
||||
* org.freedesktop.ratbag1.Resolution
|
||||
* org.freedesktop.ratbag1.Button
|
||||
* org.freedesktop.ratbag1.Led
|
||||
|
||||
For a list of dbus types as used below, see https://dbus.freedesktop.org/doc/dbus-specification.html
|
||||
|
||||
Properties marked as **constant** do not change for the lifetime of the
|
||||
object. Properties marked as **mutable** may change, and a
|
||||
``org.freedesktop.DBus.Properties.PropertyChanged`` signal is sent for those
|
||||
unless otherwise specified.
|
||||
|
||||
All setters (whether implicit for read-write properties or explicit) return
|
||||
success instead of the internal return value because DBus does not like
|
||||
non-standard error values. Upon a ratbag error, the `Resync` signal is emitted
|
||||
on the device, indicating that clients should resync their values.
|
||||
|
||||
Values listed as enums are defined in `libratbag-enums.h <https://github.com/libratbag/libratbag/blob/master/src/libratbag-enums.h>`_
|
||||
|
||||
org.freedesktop.ratbag1.Manager
|
||||
-------------------------------
|
||||
|
||||
.. js:class:: Manager
|
||||
|
||||
The **org.freedesktop.ratbag1.Manager** interface is the entry point to
|
||||
interact with ratbagd.
|
||||
|
||||
.. js:attribute:: Devices
|
||||
|
||||
:type: ao
|
||||
|
||||
An array of read-only **object paths** to :js:class:`Device` objects
|
||||
|
||||
.. js:attribute:: Themes
|
||||
|
||||
:type: as
|
||||
|
||||
:flags: read-only, constant
|
||||
|
||||
Provides the list of available theme names. This list is guaranteed to have
|
||||
one theme available ('default'). Other themes are implementation defined.
|
||||
A theme listed here is only a guarantee that the theme is known to libratbag
|
||||
and that SVGs *may* exist, it is not a guarantee that the SVG for any
|
||||
specific device exists. In other words, a device may not have an SVG for a
|
||||
specific theme.
|
||||
|
||||
This list is static for the lifetime of ratbagd.
|
||||
|
||||
org.freedesktop.ratbag1.Device
|
||||
-------------------------------
|
||||
|
||||
.. js:class:: Device
|
||||
|
||||
The **org.freedesktop.ratbag1.Device** interface describes a single device
|
||||
known to ratbagd.
|
||||
|
||||
.. js:attribute:: Id
|
||||
|
||||
:type: as
|
||||
|
||||
:flags: read-only, constant
|
||||
|
||||
An ID describing this device. This ID should not be used for presentation to
|
||||
the user. This ID is unique for the device for the lifetime of the device
|
||||
but may be recycled when the device is removed. No guarantee is given for
|
||||
the content of the ID, the client should treat it as an opaque string.
|
||||
|
||||
.. js:attribute:: Description
|
||||
|
||||
:type: s
|
||||
:flags: read-only, constant
|
||||
|
||||
The device's name, suitable for presentation to the user.
|
||||
|
||||
.. js:attribute:: Capabilities
|
||||
|
||||
:type: au
|
||||
:flags: read-only, constant
|
||||
|
||||
The capabilities supported by this device. see `enum
|
||||
ratbag_device_capability` in libratbag-enums.h for the list of permissible
|
||||
capabilities.
|
||||
|
||||
|
||||
.. js:attribute:: Svg
|
||||
|
||||
:type: s
|
||||
:flags: read-only, constant
|
||||
|
||||
The device's SVG file name, without path.
|
||||
|
||||
.. js:attribute:: Profiles
|
||||
|
||||
:type: ao
|
||||
:flags: read-only, mutable
|
||||
|
||||
This property is mutable if the device supports adding and removing
|
||||
profiles.
|
||||
|
||||
Provides the list of profile paths for all profiles on this device, see
|
||||
:js:class:`Profile`.
|
||||
|
||||
.. js:function:: Commit() → ()
|
||||
|
||||
Commits the changes to the device. Changes to the device are batched; they
|
||||
are not written to the hardware until :js:func:`Commit()` is invoked.
|
||||
|
||||
.. js:function:: GetSvg(s) → (s)
|
||||
|
||||
:param s: the theme name
|
||||
:returns: A full path to the SVG for the given theme
|
||||
|
||||
Returns the full path to the SVG for the given theme or an
|
||||
empty string if none is available. The theme must be one of
|
||||
:js:attr:`Themes`.
|
||||
|
||||
The theme **'default'** is guaranteed to be available.
|
||||
ratbagd may return the path to a file that doesn't exist.
|
||||
This is the case if the device has SVGs available but not
|
||||
for the given theme.
|
||||
|
||||
.. js:function:: Resync()
|
||||
|
||||
:type: Signal
|
||||
|
||||
Emitted when an internal error occurs. Upon receiving this
|
||||
signal, clients are expected to resync their values with
|
||||
ratbagd.
|
||||
|
||||
|
||||
org.freedesktop.ratbag1.Profile
|
||||
-------------------------------
|
||||
|
||||
.. js:class:: Profile
|
||||
|
||||
.. js:attribute:: Index
|
||||
|
||||
:type: u
|
||||
:flags: read-only, constant
|
||||
|
||||
The index of this profile
|
||||
|
||||
.. js:attribute:: Name
|
||||
|
||||
:type: s
|
||||
:flags: read-write, mutable
|
||||
|
||||
The name of this profile.
|
||||
|
||||
.. js:attribute:: Enabled
|
||||
|
||||
:type: b
|
||||
:flags: read-write, mutable
|
||||
|
||||
True if this is the profile is enabled, false otherwise.
|
||||
|
||||
Note that a disabled profile might not have correct bindings, so it's
|
||||
a good thing to rebind everything before calling :js:func:`Commit()` on the
|
||||
:js:class:`Device`.
|
||||
|
||||
.. js:attribute:: Resolutions
|
||||
|
||||
:type: ao
|
||||
:flags: read-only, mutable
|
||||
|
||||
This property is mutable if the device supports adding and removing
|
||||
resolutions.
|
||||
|
||||
Provides the object paths of all resolutions in this profile, see
|
||||
:js:class:`Resolution`
|
||||
|
||||
.. js:attribute:: Buttons
|
||||
|
||||
:type: ao
|
||||
:flags: read-only, constant
|
||||
|
||||
Provides the object paths of all buttons in this profile, see
|
||||
:js:class:`Button`
|
||||
|
||||
.. js:attribute:: Leds
|
||||
|
||||
:type: ao
|
||||
:flags: read-only, constant
|
||||
|
||||
Provides the object paths of all LEDs in this profile, see
|
||||
:js:class:`Led`
|
||||
|
||||
.. js:attribute:: IsActive
|
||||
|
||||
:type: b
|
||||
:flags: read-only, mutable
|
||||
|
||||
True if this is the currently active profile, false otherwise.
|
||||
|
||||
Profiles can only be set to active, but never to not active - at least one
|
||||
profile must be active at all times. This property is read-only, use the
|
||||
:js:func:`SetActive()` method to activate a profile.
|
||||
|
||||
.. js:function:: SetActive() → ()
|
||||
|
||||
Set this profile to be the active profile
|
||||
|
||||
org.freedesktop.ratbag1.Resolution
|
||||
----------------------------------
|
||||
|
||||
.. js:class:: Resolution
|
||||
|
||||
.. js:attribute:: Index
|
||||
|
||||
:type: u
|
||||
:flags: read-only, constant
|
||||
|
||||
Index of the resolution
|
||||
|
||||
.. js:attribute:: Capabilities
|
||||
|
||||
:type: au
|
||||
:flags: read-only, constant
|
||||
|
||||
Array of uints from the ratbag\_resolution\_capability from libratbag.h.
|
||||
|
||||
.. js:attribute:: IsActive
|
||||
|
||||
:type: b
|
||||
:flags: read-only, mutable
|
||||
|
||||
True if this is the currently active resolution, false otherwise.
|
||||
|
||||
Resolutions can only be set to active, but never to not
|
||||
active - at least one resoultion must be active at all
|
||||
times. This property is read-only, use the
|
||||
:js:func:`SetActive()` method to set a resolution as the
|
||||
active resolution.
|
||||
|
||||
.. js:attribute:: IsDefault
|
||||
|
||||
:type: b
|
||||
:flags: read-only, mutable
|
||||
|
||||
True if this is the currently default resolution, false
|
||||
otherwise. If the device does not have the default
|
||||
resolution capability, this property is always false.
|
||||
|
||||
Resolutions can only be set to default, but never to not
|
||||
default - at least one resolution must be default at all
|
||||
times. This property is read-only, use the
|
||||
:js:func:`SetDefault()` method to set a resolution as
|
||||
the default resolution.
|
||||
|
||||
.. js:attribute:: Resolution
|
||||
|
||||
:type: uu
|
||||
:flags: read-write, mutable
|
||||
|
||||
uint for the x and y resolution assigned to this entry,
|
||||
respectively. The value for the resolution must be equal to
|
||||
one of the values in :js:attr:`Resolutions`.
|
||||
|
||||
If the resolution does not support separate x/y resolutions,
|
||||
x and y must be the same value.
|
||||
|
||||
.. js:attribute:: Resolutions
|
||||
|
||||
:type: au
|
||||
:flags: read-only, constant
|
||||
|
||||
A list of permitted resolutions. Values in this list may be used in
|
||||
the :js:attr:`Resolution` property. This list is always sorted
|
||||
ascending, the lowest resolution is the first item in the list.
|
||||
|
||||
This list may be empty if the device does not support reading and/or
|
||||
writing to resolutions.
|
||||
|
||||
.. js:attribute:: ReportRate
|
||||
|
||||
:type: u
|
||||
:flags: read-write, mutable
|
||||
|
||||
uint for the report rate in Hz assigned to this entry
|
||||
|
||||
If the resolution does not have the individual report rate
|
||||
capability, changing the report rate on one resolution will
|
||||
change the report rate on all resolutions.
|
||||
|
||||
.. js:attribute:: ReportRates
|
||||
|
||||
:type: au
|
||||
:flags: read-write, constant
|
||||
|
||||
A list of permitted report rates. Values in this list may be used
|
||||
in the :js:attr:`ReportRate` property. This list is always sorted
|
||||
ascending, the lowest report rate is the first item in the list.
|
||||
|
||||
This list may be empty if the device does not support reading and/or
|
||||
writing to resolutions.
|
||||
|
||||
.. js:function:: SetDefault() → ()
|
||||
|
||||
Set this resolution to be the default
|
||||
|
||||
.. js:function:: SetActive() → ()
|
||||
|
||||
Set this resolution to be the active one
|
||||
|
||||
org.freedesktop.ratbag1.Button
|
||||
------------------------------
|
||||
|
||||
.. js:class:: Button
|
||||
|
||||
.. js:attribute:: Index
|
||||
|
||||
:type: u
|
||||
:flags: read-only, constant
|
||||
|
||||
Index of the button
|
||||
|
||||
.. js:attribute:: Type
|
||||
|
||||
:type: u
|
||||
:flags: read-only, constant
|
||||
|
||||
Enum describing the button physical type, see
|
||||
:cpp:enum:`ratbag_button_type`. This type is unrelated to the
|
||||
logical button mapping and serves to easily identify the button on
|
||||
the device.
|
||||
|
||||
.. js:attribute:: ButtonMapping
|
||||
|
||||
:type: u
|
||||
:flags: read-write, mutable
|
||||
|
||||
uint of the current button mapping (if mapping to button)
|
||||
|
||||
.. js:attribute:: SpecialMapping
|
||||
|
||||
:type: u
|
||||
:flags: read-write, mutable
|
||||
|
||||
Enum describing the current special mapping (if mapped to special)
|
||||
|
||||
.. js:attribute:: Macro
|
||||
|
||||
:type: a(uu)
|
||||
:flags: read-write, mutable
|
||||
|
||||
Array of (type, keycode), where type may be one of
|
||||
:cpp:enumerator:`RATBAG_MACRO_EVENT_KEY_PRESSED` or
|
||||
:cpp:enumerator:`RATBAG_MACRO_EVENT_KEY_RELEASED`.
|
||||
|
||||
.. js:attribute:: ActionType
|
||||
|
||||
:type: u
|
||||
:flags: read-only, mutable
|
||||
|
||||
An enum describing the action type of the button, see
|
||||
:cpp:enum:`ratbag_button_action_type` for the list of enums.
|
||||
This decides which one of :js:attr:`ButtonMapping`,
|
||||
:js:attr:`SpecialMapping` and :js:attr:`Macro` has a value.
|
||||
|
||||
.. js:attribute:: ActionTypes
|
||||
|
||||
:type: au
|
||||
:flags: read-only, constant
|
||||
|
||||
Array of :cpp:enum:`ratbag_button_action_type`, possible values
|
||||
for ActionType on the current device
|
||||
|
||||
.. js:function:: Disable() → ()
|
||||
|
||||
Disable this button
|
||||
|
||||
org.freedesktop.ratbag1.Led
|
||||
---------------------------
|
||||
|
||||
.. js:class:: Led
|
||||
|
||||
.. js:attribute:: Index
|
||||
|
||||
:type: u
|
||||
:flags: read-only, constant
|
||||
|
||||
Index of the LED
|
||||
|
||||
.. js:attribute:: Mode
|
||||
|
||||
:type: u
|
||||
:flags: read-write, mutable
|
||||
|
||||
uint mapping to the mode enum from libratbag
|
||||
|
||||
.. js:attribute:: Modes
|
||||
|
||||
:type: au
|
||||
:flags: read-only, constant
|
||||
|
||||
A list of modes supported by this LED
|
||||
|
||||
.. js:attribute:: Type
|
||||
|
||||
:type: u
|
||||
:flags: read-only, mutable
|
||||
|
||||
enum describing the LED type
|
||||
|
||||
.. js:attribute:: Color
|
||||
|
||||
:type: (uuu)
|
||||
:flags: read-write, mutable
|
||||
|
||||
uint triplet (RGB) of the LED's color
|
||||
|
||||
.. js:attribute:: ColorDepth
|
||||
|
||||
:type: u
|
||||
:flags: read-only, constant
|
||||
|
||||
The color depth of this LED as one of the constants in libratbag-enums.h
|
||||
|
||||
.. js:attribute:: EffectDuration
|
||||
|
||||
:type: u
|
||||
:flags: read-write, mutable
|
||||
|
||||
The effect duration in ms, possible values are in the range 0 - 10000
|
||||
|
||||
.. js:attribute:: Brightness
|
||||
|
||||
:type: u
|
||||
:flags: read-write, mutable
|
||||
|
||||
The brightness of the LED, possible values are in the range 0 - 255
|
||||
|
||||
For easier debugging, objects paths are constructed from the device. e.g.
|
||||
`/org/freedesktop/ratbag/button/event5/p0/b10` is the button interface for
|
||||
button 10 on profile 0 on event5. The naming is subject to change. Do not
|
||||
rely on a constructed object path in your application.
|
||||
53
doc/doxygen-enums-to-rst.xsl
Normal file
@@ -0,0 +1,53 @@
|
||||
<!-- XSLT script to combine the generated output into a single file.
|
||||
If you have xsltproc you could use:
|
||||
xsltproc combine.xslt index.xml >all.xml
|
||||
-->
|
||||
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
|
||||
<xsl:output method="text" indent="yes"/>
|
||||
<xsl:strip-space elements="detaileddescription briefdescription"/>
|
||||
|
||||
<xsl:template match="/">
|
||||
<xsl:text>
|
||||
************
|
||||
Enumerations
|
||||
************
|
||||
|
||||
This document contains the enums used by libratbag's DBus interface.
|
||||
|
||||
</xsl:text>
|
||||
<xsl:apply-templates select="//memberdef"/>
|
||||
</xsl:template>
|
||||
|
||||
<xsl:template match="memberdef">
|
||||
|
||||
<xsl:value-of select="name"/>
|
||||
---------------------------------------
|
||||
|
||||
<xsl:text>
</xsl:text>
|
||||
<xsl:if test="briefdescription != ''">
|
||||
<xsl:value-of select="briefdescription"/>
|
||||
</xsl:if>
|
||||
<xsl:if test="detaileddescription != ''">
|
||||
<xsl:value-of select="detaileddescription"/>
|
||||
</xsl:if>
|
||||
|
||||
.. cpp:enum:: <xsl:value-of select="name"/>
|
||||
|
||||
<xsl:text>

</xsl:text>
|
||||
<xsl:apply-templates select="./enumvalue"/>
|
||||
|
||||
</xsl:template>
|
||||
|
||||
<xsl:template match="enumvalue">
|
||||
.. cpp:enumerator:: <xsl:value-of select="name"/><xsl:text> </xsl:text><xsl:value-of select="initializer"/>
|
||||
<xsl:text>

</xsl:text>
|
||||
<xsl:if test="briefdescription != ''">
|
||||
<xsl:text> </xsl:text><xsl:value-of select="briefdescription"/>
|
||||
</xsl:if>
|
||||
<xsl:if test="detaileddescription != ''">
|
||||
<xsl:text> </xsl:text><xsl:value-of select="detaileddescription"/>
|
||||
</xsl:if>
|
||||
<xsl:text>

</xsl:text>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
|
||||
20
doc/index.rst
Normal file
@@ -0,0 +1,20 @@
|
||||
.. libratbag documentation master file, created by
|
||||
sphinx-quickstart on Wed Oct 11 13:45:08 2017.
|
||||
You can adapt this file completely to your liking, but it should at least
|
||||
contain the root `toctree` directive.
|
||||
|
||||
**********************
|
||||
The libratbag DBus API
|
||||
**********************
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
:caption: Contents:
|
||||
|
||||
The DBus Interfaces <dbus.rst>
|
||||
Enumerations <enums.rst>
|
||||
|
||||
This document describes the DBus API that is the public interface for
|
||||
libratbag.
|
||||
|
||||
Note: **the DBus interface is subject to change**
|
||||
15
doc/libratbag.doxygen.in
Normal file
@@ -0,0 +1,15 @@
|
||||
PROJECT_NAME = @PACKAGE_NAME@
|
||||
PROJECT_NUMBER = @PACKAGE_VERSION@
|
||||
PROJECT_BRIEF = "A mouse configuration library"
|
||||
JAVADOC_AUTOBRIEF = YES
|
||||
TAB_SIZE = 8
|
||||
OPTIMIZE_OUTPUT_FOR_C = YES
|
||||
EXTRACT_ALL = YES
|
||||
EXTRACT_STATIC = YES
|
||||
MAX_INITIALIZER_LINES = 0
|
||||
QUIET = YES
|
||||
# Keep this list in sync with meson.build
|
||||
INPUT = @top_srcdir@/src/libratbag-enums.h
|
||||
GENERATE_HTML = NO
|
||||
GENERATE_XML = YES
|
||||
GENERATE_LATEX = NO
|
||||
73
doc/meson.build
Normal file
@@ -0,0 +1,73 @@
|
||||
if get_option('documentation')
|
||||
|
||||
cmd_sphinx = find_program('sphinx-build-3', 'sphinx-build3')
|
||||
cmd_doxygen = find_program('doxygen')
|
||||
cmd_xsltproc = find_program('xsltproc')
|
||||
|
||||
doc_config = configuration_data()
|
||||
doc_config.set('PACKAGE_NAME', meson.project_name())
|
||||
doc_config.set('PACKAGE_VERSION', meson.project_version())
|
||||
doc_config.set('top_srcdir', meson.source_root())
|
||||
|
||||
# We have a dependency chain here:
|
||||
# - generate doxygen xml from the source
|
||||
# - convert the xml to rst with xstlproc
|
||||
# - generate the sphinx conf
|
||||
# - run sphinx against the generated rst
|
||||
doxyfile = configure_file(input : 'libratbag.doxygen.in',
|
||||
output : 'libratbag.doxygen',
|
||||
configuration : doc_config,
|
||||
install : false)
|
||||
|
||||
src_doxygen = [ doxyfile,
|
||||
files('../src/libratbag-enums.h') ]
|
||||
doxygen = custom_target('doxygen',
|
||||
input : src_doxygen,
|
||||
output : [ 'xml' ],
|
||||
command : [ cmd_doxygen, doxyfile ],
|
||||
install : false,
|
||||
build_by_default : true)
|
||||
|
||||
|
||||
# Sphinx really really wants a _static directory in its source tree. Let's
|
||||
# make it happy
|
||||
run_command('mkdir', '-p', join_paths(meson.build_root(), 'doc', '_static'))
|
||||
|
||||
xsl = join_paths(meson.source_root(), 'doc', 'doxygen-enums-to-rst.xsl')
|
||||
src_xsltproc = join_paths(meson.build_root(), 'xml', 'group__enums.xml')
|
||||
dst_xstlproc = join_paths(meson.build_root(), 'doc', 'enums.rst')
|
||||
rst_enum = custom_target('xsltproc',
|
||||
input : doxygen,
|
||||
output : 'enums.rst',
|
||||
command: [ cmd_xsltproc, '-o', dst_xstlproc, xsl, src_xsltproc],
|
||||
build_by_default : true)
|
||||
|
||||
# Effectively a noop copy. We *must* generate enums.rst so that will end up
|
||||
# in the build directory. sphinx doesn't allow for multiple source
|
||||
# directories, so any .rst and the conf.py must be copied over to the
|
||||
# build directory too
|
||||
src_rsts = ['index.rst', 'dbus.rst']
|
||||
dst_rsts = [rst_enum]
|
||||
foreach rst : src_rsts
|
||||
f = configure_file(input : rst,
|
||||
output : rst,
|
||||
configuration : doc_config,
|
||||
install : false)
|
||||
dst_rsts += f
|
||||
endforeach
|
||||
|
||||
sphinx_conf = configure_file(input : 'conf.py.in',
|
||||
output : 'conf.py',
|
||||
configuration : doc_config,
|
||||
install : false)
|
||||
|
||||
custom_target('sphinx',
|
||||
input : [ sphinx_conf, dst_rsts ],
|
||||
output : 'html',
|
||||
command : [ cmd_sphinx, '-b', 'html', '-q', '-n',
|
||||
join_paths(meson.build_root(), 'doc'),
|
||||
join_paths(meson.build_root(), 'doc', 'html') ],
|
||||
build_by_default : true,
|
||||
install : false)
|
||||
|
||||
endif
|
||||
@@ -1,237 +0,0 @@
|
||||
# Database for libratbag to select the correct driver to use for gaming mice.
|
||||
#
|
||||
# The lookup keys are composed in:
|
||||
# 70-libratbag-mouse.rules
|
||||
#
|
||||
# Match string format:
|
||||
# mouse:<subsystem>:v<vid>p<pid>:name:<name>:
|
||||
#
|
||||
# Supported subsystems: usb, bluetooth
|
||||
# vid/pid as 4-digit hex lowercase vendor/product
|
||||
#
|
||||
# if vid/pid is unavailable, use
|
||||
# mouse:*:name:<name>:
|
||||
# if name is unavailable, use
|
||||
# mouse:<subsystem>:v<vid>p<pid>:*
|
||||
#
|
||||
# For example, the following 5 matches all match the same mouse:
|
||||
# mouse:usb:v17efp6019:name:Lenovo Optical USB Mouse:
|
||||
# mouse:usb:*:name:Lenovo Optical USB Mouse:
|
||||
# mouse:usb:v17efp6019:*
|
||||
# mouse:*:name:Lenovo Optical USB Mouse:
|
||||
#
|
||||
# To add local entries, create a new file
|
||||
# /etc/udev/hwdb.d/71-libratbat-mouse-local.hwdb
|
||||
# and add your rules there. To load the new rules execute (as root):
|
||||
# udevadm hwdb --update
|
||||
# udevadm trigger /dev/input/eventXX
|
||||
# where /dev/input/eventXX is the mouse in question. If in
|
||||
# doubt, simply use /dev/input/event* to reload all input rules.
|
||||
#
|
||||
# If your changes are generally applicable, preferably send them as a pull
|
||||
# request to
|
||||
# https://github.com/libratbag/libratbag
|
||||
# or create a bug report on https://github.com/libratbag/libratbag/issues and
|
||||
# include your new rules, a description of the device, and the output of
|
||||
# udevadm info /dev/input/eventXX
|
||||
# (or /dev/input/event*).
|
||||
#
|
||||
# Allowed properties are:
|
||||
# RATBAG_DRIVER
|
||||
# RATBAG_SVG
|
||||
|
||||
# Sort by brand, driver
|
||||
|
||||
|
||||
##########################################
|
||||
# Etekcity
|
||||
##########################################
|
||||
|
||||
mouse:usb:v1ea7p4011:name:*:
|
||||
RATBAG_DRIVER=etekcity
|
||||
RATBAG_SVG=etekcity.svg
|
||||
|
||||
##########################################
|
||||
# Logitech
|
||||
##########################################
|
||||
|
||||
# M705
|
||||
mouse:usb:v046dp101b:name:*:
|
||||
RATBAG_DRIVER=hidpp10
|
||||
|
||||
# M570
|
||||
mouse:usb:v046dp1028:name:*:
|
||||
RATBAG_DRIVER=hidpp10
|
||||
|
||||
# G5
|
||||
mouse:usb:v046dpc041:name:*:
|
||||
RATBAG_DRIVER=hidpp10
|
||||
RATBAG_HIDPP10_DPI_LIST=400;800;1600;2000
|
||||
|
||||
# G5 2007
|
||||
# http://support.logitech.com/en_us/product/g5-laser-mouse-product/specs
|
||||
mouse:usb:v046dpc049:name:*:
|
||||
RATBAG_DRIVER=hidpp10
|
||||
RATBAG_HIDPP10_DPI_LIST=400;800;1600;2000
|
||||
RATBAG_HIDPP10_PROFILE_COUNT=1
|
||||
|
||||
# G7
|
||||
# http://support.logitech.com/en_us/product/g7-laser-cordless-mouse/specs
|
||||
mouse:usb:v046dpc51a:name:*:
|
||||
RATBAG_DRIVER=hidpp10
|
||||
RATBAG_HIDPP10_PROFILE_COUNT=1
|
||||
|
||||
# G9
|
||||
# http://support.logitech.com/en_us/product/g9-laser-mouse/specs
|
||||
mouse:usb:v046dpc048:name:*:
|
||||
RATBAG_DRIVER=hidpp10
|
||||
RATBAG_HIDPP10_DPI_LIST=0;200;400;600;800;1000;1200;1400;1600;1800;2000;2200;2400;2600;2800;3000;3200
|
||||
RATBAG_HIDPP10_PROFILE=G9
|
||||
RATBAG_HIDPP10_PROFILE_COUNT=5
|
||||
|
||||
# G9x [Original]
|
||||
# http://support.logitech.com/en_us/product/g9x-laser-mouse/specs
|
||||
mouse:usb:v046dpc066:name:*:
|
||||
RATBAG_DRIVER=hidpp10
|
||||
RATBAG_HIDPP10_DPI=0:5700@23.53
|
||||
RATBAG_HIDPP10_PROFILE=G500
|
||||
RATBAG_HIDPP10_PROFILE_COUNT=5
|
||||
|
||||
# G9x [Call of Duty MW3 Edition]
|
||||
# http://support.logitech.com/en_us/product/laser-mouse-g9x/specs
|
||||
mouse:usb:v046dpc249:name:*:
|
||||
RATBAG_DRIVER=hidpp10
|
||||
RATBAG_HIDPP10_DPI=0:5700@23.53
|
||||
RATBAG_HIDPP10_PROFILE=G500
|
||||
RATBAG_HIDPP10_PROFILE_COUNT=5
|
||||
|
||||
# G300
|
||||
mouse:usb:v046dpc246:name:*:
|
||||
RATBAG_DRIVER=logitech_g300
|
||||
RATBAG_SVG=logitech-g300.svg
|
||||
|
||||
# G403 over USB
|
||||
mouse:usb:v046dpc082:name:*:
|
||||
RATBAG_DRIVER=hidpp20
|
||||
RATBAG_SVG=logitech-g403.svg
|
||||
|
||||
# G500
|
||||
# http://support.logitech.com/en_us/product/gaming-mouse-g500/specs
|
||||
mouse:usb:v046dpc068:name:*:
|
||||
RATBAG_DRIVER=hidpp10
|
||||
RATBAG_SVG=logitech-g500.svg
|
||||
RATBAG_HIDPP10_DPI=0:5700@23.53
|
||||
RATBAG_HIDPP10_PROFILE=G500
|
||||
RATBAG_HIDPP10_PROFILE_COUNT=1
|
||||
|
||||
# G500s
|
||||
# http://support.logitech.com/en_us/product/g500s-laser-gaming-mouse/specs
|
||||
mouse:usb:v046dpc24e:name:*:
|
||||
RATBAG_DRIVER=hidpp10
|
||||
RATBAG_SVG=logitech-g500s.svg
|
||||
RATBAG_HIDPP10_DPI=0:8200@50
|
||||
RATBAG_HIDPP10_PROFILE=G500
|
||||
RATBAG_HIDPP10_PROFILE_COUNT=1
|
||||
|
||||
# G502 Proteus Core over USB
|
||||
mouse:usb:v046dpc07d:name:*:
|
||||
RATBAG_DRIVER=hidpp20
|
||||
RATBAG_SVG=logitech-g502.svg
|
||||
|
||||
# G502 Proteus Spectrum over USB
|
||||
mouse:usb:v046dpc332:name:*:
|
||||
RATBAG_DRIVER=hidpp20
|
||||
RATBAG_SVG=logitech-g502.svg
|
||||
|
||||
# G700 over USB
|
||||
# http://support.logitech.com/en_us/product/wireless-gaming-mouse-g700/specs
|
||||
mouse:usb:v046dpc06b:name:*:
|
||||
RATBAG_DRIVER=hidpp10
|
||||
RATBAG_SVG=logitech-g700.svg
|
||||
RATBAG_HIDPP10_DPI=0:5700@23.53
|
||||
RATBAG_HIDPP10_PROFILE=G700
|
||||
RATBAG_HIDPP10_PROFILE_COUNT=5
|
||||
|
||||
# G700 over wireless USB
|
||||
# http://support.logitech.com/en_us/product/wireless-gaming-mouse-g700/specs
|
||||
mouse:usb:v046dpc531:name:*:
|
||||
RATBAG_DRIVER=hidpp10
|
||||
RATBAG_HIDPP10_DPI=0:5700@23.53
|
||||
RATBAG_HIDPP10_PROFILE=G700
|
||||
RATBAG_HIDPP10_INDEX=1
|
||||
RATBAG_HIDPP10_PROFILE_COUNT=5
|
||||
|
||||
# G700s over USB
|
||||
# http://support.logitech.com/en_us/product/g700s-rechargable-wireless-gaming-mouse/specs
|
||||
mouse:usb:v046dpc07c:name:*:
|
||||
RATBAG_DRIVER=hidpp10
|
||||
RATBAG_SVG=logitech-g700.svg
|
||||
RATBAG_HIDPP10_DPI=0:8200@50
|
||||
RATBAG_HIDPP10_PROFILE=G700
|
||||
RATBAG_HIDPP10_PROFILE_COUNT=5
|
||||
|
||||
# G700s over wireless USB
|
||||
# http://support.logitech.com/en_us/product/g700s-rechargable-wireless-gaming-mouse/specs
|
||||
mouse:usb:v046dpc531:name:*:
|
||||
RATBAG_DRIVER=hidpp10
|
||||
RATBAG_SVG=logitech-g700.svg
|
||||
RATBAG_HIDPP10_DPI=0:8200@50
|
||||
RATBAG_HIDPP10_PROFILE=G700
|
||||
RATBAG_HIDPP10_INDEX=1
|
||||
RATBAG_HIDPP10_PROFILE_COUNT=5
|
||||
|
||||
# MX Master over unifying
|
||||
mouse:usb:v046dp4041:name:*:
|
||||
# MX Master over bluetooth
|
||||
mouse:bluetooth:v046dpb012:name:*:
|
||||
RATBAG_DRIVER=hidpp20
|
||||
RATBAG_SVG=logitech-mx_master.svg
|
||||
|
||||
# T650 over unifying
|
||||
mouse:usb:v046dp4101:name:*:
|
||||
RATBAG_DRIVER=hidpp20
|
||||
|
||||
# M325 over unifying
|
||||
mouse:usb:v046dp400a:name:*:
|
||||
RATBAG_DRIVER=hidpp20
|
||||
|
||||
# G303 over USB
|
||||
mouse:usb:v046dpc080:name:*:
|
||||
RATBAG_DRIVER=hidpp20
|
||||
RATBAG_SVG=logitech-g303.svg
|
||||
|
||||
# Wireless Touchpad (Unifying)
|
||||
mouse:usb:v046dp4011:name:*:
|
||||
RATBAG_DRIVER=hidpp20
|
||||
|
||||
# G602 over wireless USB
|
||||
mouse:usb:v046dpc537:name:*:
|
||||
RATBAG_HIDPP20_INDEX=1
|
||||
|
||||
# G900 over USB
|
||||
mouse:usb:v046dpc081:name:*:
|
||||
RATBAG_SVG=logitech-g900.svg
|
||||
|
||||
# G900, G403 over wireless USB
|
||||
mouse:usb:v046dpc539:name:*:
|
||||
RATBAG_DRIVER=hidpp20
|
||||
RATBAG_SVG=logitech-g900.svg
|
||||
RATBAG_HIDPP20_INDEX=1
|
||||
|
||||
|
||||
##########################################
|
||||
# Roccat
|
||||
##########################################
|
||||
|
||||
mouse:usb:v1e7dp2e22:name:*:
|
||||
RATBAG_DRIVER=roccat
|
||||
RATBAG_SVG=roccat-kone-xtd.svg
|
||||
|
||||
|
||||
##########################################
|
||||
# G.Skill
|
||||
##########################################
|
||||
|
||||
# MX-780
|
||||
mouse:usb:v28dap3101:name:*:
|
||||
RATBAG_DRIVER=gskill
|
||||
@@ -1,24 +0,0 @@
|
||||
# do not edit this file, it will be overwritten on update
|
||||
|
||||
ACTION=="remove", GOTO="mouse_end"
|
||||
KERNEL!="event*", GOTO="mouse_end"
|
||||
ENV{ID_INPUT}=="", GOTO="mouse_end"
|
||||
|
||||
# mouse:<subsystem>:v<vid>p<pid>:name:<name>:*
|
||||
KERNELS=="input*", ENV{ID_BUS}=="usb", \
|
||||
IMPORT{builtin}="hwdb 'mouse:$env{ID_BUS}:v$attr{id/vendor}p$attr{id/product}:name:$attr{name}:'", \
|
||||
GOTO="mouse_end"
|
||||
KERNELS=="input*", ENV{ID_BUS}=="bluetooth", \
|
||||
IMPORT{builtin}="hwdb 'mouse:$env{ID_BUS}:v$attr{id/vendor}p$attr{id/product}:name:$attr{name}:'", \
|
||||
GOTO="mouse_end"
|
||||
KERNELS=="input*", ENV{DEVPATH}=="/devices/virtual/misc/uhid/0003:*", \
|
||||
IMPORT{builtin}="hwdb 'mouse:usb:v$attr{id/vendor}p$attr{id/product}:name:$attr{name}:'", \
|
||||
GOTO="mouse_end"
|
||||
KERNELS=="input*", ENV{DEVPATH}=="/devices/virtual/misc/uhid/0005:*", \
|
||||
IMPORT{builtin}="hwdb 'mouse:bluetooth:v$attr{id/vendor}p$attr{id/product}:name:$attr{name}:'", \
|
||||
GOTO="mouse_end"
|
||||
DRIVERS=="psmouse", SUBSYSTEMS=="serio", \
|
||||
IMPORT{builtin}="hwdb 'mouse:ps2::name:$attr{device/name}:'", \
|
||||
GOTO="mouse_end"
|
||||
|
||||
LABEL="mouse_end"
|
||||
214
meson.build
@@ -1,7 +1,8 @@
|
||||
project('libratbag', 'c', 'cpp',
|
||||
version : '0.9.900',
|
||||
version : '0.9.901',
|
||||
license : 'MIT/Expat',
|
||||
default_options : [ 'c_std=gnu99', 'warning_level=2' ])
|
||||
default_options : [ 'c_std=gnu99', 'warning_level=2' ],
|
||||
meson_version : '>= 0.36.0')
|
||||
|
||||
libratbag_version = meson.project_version().split('.')
|
||||
|
||||
@@ -37,9 +38,11 @@ add_project_arguments(cppflags, language: 'cpp')
|
||||
# is generated at the end of this file
|
||||
config_h = configuration_data()
|
||||
config_h.set('_GNU_SOURCE', '1')
|
||||
config_h.set_quoted('FALLBACK_SVG_NAME', 'fallback.svg')
|
||||
libratbag_data_dir = join_paths(get_option('prefix'),
|
||||
get_option('datadir'),
|
||||
'libratbag')
|
||||
libratbag_data_dir_devel = join_paths(meson.source_root(), 'data')
|
||||
config_h.set_quoted('LIBRATBAG_DATA_DIR', libratbag_data_dir)
|
||||
|
||||
# dependencies
|
||||
@@ -48,6 +51,7 @@ dep_udev = dependency('libudev')
|
||||
dep_libevdev = dependency('libevdev')
|
||||
dep_libsystemd = dependency('libsystemd', version : '>=227')
|
||||
dep_systemd = dependency('systemd')
|
||||
dep_glib = dependency('glib-2.0')
|
||||
dep_lm = cc.find_library('m')
|
||||
|
||||
#### libutil.a ####
|
||||
@@ -121,6 +125,7 @@ pkgconfig.generate (
|
||||
|
||||
#### libratbag.so ####
|
||||
src_libratbag = [
|
||||
'src/libratbag-enums.h',
|
||||
'src/libratbag.h',
|
||||
'src/driver-etekcity.c',
|
||||
'src/driver-hidpp20.c',
|
||||
@@ -128,9 +133,12 @@ src_libratbag = [
|
||||
'src/driver-logitech-g300.c',
|
||||
'src/driver-roccat.c',
|
||||
'src/driver-gskill.c',
|
||||
'src/driver-steelseries.c',
|
||||
'src/driver-test.c',
|
||||
'src/libratbag.c',
|
||||
'src/libratbag.h',
|
||||
'src/libratbag-data.c',
|
||||
'src/libratbag-data.h',
|
||||
'src/libratbag-hidraw.c',
|
||||
'src/libratbag-hidraw.h',
|
||||
'src/libratbag-private.h',
|
||||
@@ -142,6 +150,7 @@ src_libratbag = [
|
||||
deps_libratbag = [
|
||||
dep_udev,
|
||||
dep_libevdev,
|
||||
dep_glib,
|
||||
dep_libutil,
|
||||
dep_libhidpp,
|
||||
]
|
||||
@@ -183,33 +192,6 @@ lib_libshared = static_library('shared',
|
||||
)
|
||||
dep_libshared = declare_dependency(link_with: lib_libshared)
|
||||
|
||||
#### ratbag-command ####
|
||||
src_ratbag_command = [ 'tools/ratbag-command.c' ]
|
||||
deps_ratbag_command = [
|
||||
dep_libshared,
|
||||
dep_libratbag,
|
||||
dep_libevdev
|
||||
]
|
||||
|
||||
executable('ratbag-command',
|
||||
src_ratbag_command,
|
||||
dependencies : deps_ratbag_command,
|
||||
include_directories : include_directories('src'),
|
||||
install : false,
|
||||
)
|
||||
|
||||
man_config = configuration_data()
|
||||
|
||||
man_config.set('version', meson.project_version())
|
||||
|
||||
man_ratbag_command = configure_file (
|
||||
input: 'tools/ratbag-command.man',
|
||||
output: 'ratbag-command.1',
|
||||
configuration: man_config,
|
||||
install : true,
|
||||
install_dir : join_paths(get_option('mandir'), 'man1')
|
||||
)
|
||||
|
||||
#### hidpp10-dump-page ####
|
||||
src_hidpp10_dump_page = [ 'tools/hidpp10-dump-page.c' ]
|
||||
executable('hidpp10-dump-page',
|
||||
@@ -228,6 +210,15 @@ executable('hidpp20-dump-page',
|
||||
install : false,
|
||||
)
|
||||
|
||||
#### hidpp20-reset ####
|
||||
src_hidpp20_reset = [ 'tools/hidpp20-reset.c' ]
|
||||
executable('hidpp20-reset',
|
||||
src_hidpp20_reset,
|
||||
dependencies : [ dep_libhidpp ],
|
||||
include_directories : include_directories('src'),
|
||||
install : false,
|
||||
)
|
||||
|
||||
#### lur-command ####
|
||||
src_lur_command = [ 'tools/lur-command.c' ]
|
||||
executable('lur-command',
|
||||
@@ -237,6 +228,10 @@ executable('lur-command',
|
||||
install : true,
|
||||
)
|
||||
|
||||
man_config = configuration_data()
|
||||
|
||||
man_config.set('version', meson.project_version())
|
||||
|
||||
man_lur_command = configure_file (
|
||||
input: 'tools/lur-command.man',
|
||||
output: 'lur-command.1',
|
||||
@@ -245,54 +240,80 @@ man_lur_command = configure_file (
|
||||
install_dir : join_paths(get_option('mandir'), 'man1')
|
||||
)
|
||||
|
||||
#### hwdb ####
|
||||
udev_dir = get_option('udev-dir')
|
||||
if udev_dir == ''
|
||||
udev_dir = '@0@/lib/udev'.format(get_option('prefix'))
|
||||
endif
|
||||
udev_rules_dir = '@0@/rules.d'.format(udev_dir)
|
||||
udev_hwdb_dir = '@0@/hwdb.d'.format(udev_dir)
|
||||
#### data files ####
|
||||
data_files = files(
|
||||
'data/devices/etekcity-fixme.device',
|
||||
'data/devices/gskill-MX-780.device',
|
||||
'data/devices/logitech-g300.device',
|
||||
'data/devices/logitech-g303.device',
|
||||
'data/devices/logitech-g403.device',
|
||||
'data/devices/logitech-g500.device',
|
||||
'data/devices/logitech-g500s.device',
|
||||
'data/devices/logitech-g502-Proteus-Core-over-USB.device',
|
||||
'data/devices/logitech-g502-Proteus-Spectrum-over-USB.device',
|
||||
'data/devices/logitech-g5-2007.device',
|
||||
'data/devices/logitech-g5.device',
|
||||
'data/devices/logitech-g602.device',
|
||||
'data/devices/logitech-g700.device',
|
||||
'data/devices/logitech-g700s.device',
|
||||
'data/devices/logitech-g700s-wireless.device',
|
||||
'data/devices/logitech-g700-wireless.device',
|
||||
'data/devices/logitech-g703.device',
|
||||
'data/devices/logitech-g7.device',
|
||||
'data/devices/logitech-g900.device',
|
||||
'data/devices/logitech-g900-wireless.device',
|
||||
'data/devices/logitech-g9.device',
|
||||
'data/devices/logitech-g9x-[Call-of-Duty-MW3-Edition].device',
|
||||
'data/devices/logitech-g9x-[Original].device',
|
||||
'data/devices/logitech-M325.device',
|
||||
'data/devices/logitech-M570.device',
|
||||
'data/devices/logitech-M705.device',
|
||||
'data/devices/logitech-MX-Master.device',
|
||||
'data/devices/logitech-T650.device',
|
||||
'data/devices/logitech-Wireless-Touchpad.device',
|
||||
'data/devices/roccat-kone-xtd.device',
|
||||
'data/devices/steelseries-kinzu-v2.device',
|
||||
'data/devices/steelseries-rival-310.device',
|
||||
)
|
||||
|
||||
install_data('hwdb/70-libratbag-mouse.rules',
|
||||
install_dir : udev_rules_dir)
|
||||
install_data('hwdb/70-libratbag-mouse.hwdb',
|
||||
install_dir : udev_hwdb_dir)
|
||||
install_data(data_files,
|
||||
install_dir : join_paths(get_option('datadir'), 'libratbag', 'devices'))
|
||||
|
||||
data_parse_test = find_program(join_paths(meson.source_root(), 'data/devices/data-parse-test.py'))
|
||||
test('data-parse-test', data_parse_test,
|
||||
args : [ '--svg-dir', join_paths(meson.source_root(), 'data/default'),
|
||||
'--svg-dir', join_paths(meson.source_root(), 'data/gnome') ] + data_files)
|
||||
|
||||
#### svg files ####
|
||||
default_svg_files = [
|
||||
'data/default/etekcity.svg',
|
||||
'data/default/logitech-g300.svg',
|
||||
'data/default/logitech-g303.svg',
|
||||
'data/default/logitech-g500s.svg',
|
||||
'data/default/logitech-g502.svg',
|
||||
'data/default/logitech-g700.svg',
|
||||
'data/default/logitech-g900.svg',
|
||||
'data/default/logitech-mx_master.svg',
|
||||
'data/default/roccat-kone-xtd.svg'
|
||||
]
|
||||
install_data(default_svg_files,
|
||||
install_dir : join_paths(get_option('datadir'), 'libratbag', 'default'))
|
||||
|
||||
gnome_svg_files = [
|
||||
gnome_svg_files = files(
|
||||
'data/gnome/fallback.svg',
|
||||
'data/gnome/logitech-g300.svg',
|
||||
'data/gnome/logitech-g303.svg',
|
||||
'data/gnome/logitech-g403.svg',
|
||||
'data/gnome/logitech-g500.svg',
|
||||
'data/gnome/logitech-g500s.svg',
|
||||
'data/gnome/logitech-g502.svg',
|
||||
'data/gnome/logitech-g700.svg',
|
||||
'data/gnome/logitech-g703.svg',
|
||||
'data/gnome/logitech-g9.svg',
|
||||
'data/gnome/logitech-g900.svg',
|
||||
'data/gnome/roccat-kone-xtd.svg',
|
||||
]
|
||||
'data/gnome/steelseries-kinzu-v2.svg',
|
||||
'data/gnome/steelseries-rival310.svg',
|
||||
)
|
||||
install_data(gnome_svg_files,
|
||||
install_dir : join_paths(get_option('datadir'), 'libratbag', 'gnome'))
|
||||
|
||||
test_svg_files = find_program('data/gnome/check-svg.py')
|
||||
test('check-svg', test_svg_files, args : gnome_svg_files)
|
||||
|
||||
#### tests ####
|
||||
enable_tests = get_option('enable-tests')
|
||||
if enable_tests
|
||||
dep_check = dependency('check', version: '>= 0.9.10')
|
||||
|
||||
config_h.set('BUILD_TESTS', '1')
|
||||
env_test = environment()
|
||||
env_test.set('RATBAG_TEST', '1')
|
||||
|
||||
test_context = executable('test-context',
|
||||
['test/test-context.c'],
|
||||
@@ -304,6 +325,11 @@ if enable_tests
|
||||
dependencies : [ dep_libratbag, dep_check ],
|
||||
include_directories : include_directories('src'),
|
||||
install : false)
|
||||
test_util = executable('test-util',
|
||||
['test/test-util.c'],
|
||||
dependencies : [ dep_libratbag, dep_check ],
|
||||
include_directories : include_directories('src'),
|
||||
install : false)
|
||||
test_iconv_helper = executable('test-iconv-helper',
|
||||
['test/test-iconv-helper.c'],
|
||||
dependencies : [ dep_libratbag,
|
||||
@@ -311,9 +337,10 @@ if enable_tests
|
||||
dep_libutil],
|
||||
include_directories : include_directories('src'),
|
||||
install : false)
|
||||
test('test-context', test_context, env : env_test)
|
||||
test('test-device', test_device, env : env_test)
|
||||
test('test-iconv-helper', test_iconv_helper, env : env_test)
|
||||
test('test-context', test_context)
|
||||
test('test-device', test_device)
|
||||
test('test-util', test_util)
|
||||
test('test-iconv-helper', test_iconv_helper)
|
||||
|
||||
valgrind = find_program('valgrind')
|
||||
valgrind_suppressions_file = join_paths(meson.source_root(), 'test', 'valgrind.suppressions')
|
||||
@@ -324,7 +351,6 @@ if enable_tests
|
||||
'--quiet',
|
||||
'--error-exitcode=3',
|
||||
'--suppressions=' + valgrind_suppressions_file ],
|
||||
env : env_test,
|
||||
timeout_multiplier: 5)
|
||||
|
||||
executable('test-build-cxx',
|
||||
@@ -352,11 +378,6 @@ if enable_tests
|
||||
install : false)
|
||||
endif
|
||||
|
||||
test_symbols_leak = find_program('test/symbols-leak-test')
|
||||
test('symbols-leak-test',
|
||||
test_symbols_leak,
|
||||
args : [ meson.current_source_dir() ])
|
||||
|
||||
#### ratbagd ####
|
||||
src_ratbagd = [
|
||||
'src/shared-macro.h',
|
||||
@@ -369,6 +390,7 @@ src_ratbagd = [
|
||||
'ratbagd/ratbagd-device.c',
|
||||
'ratbagd/ratbagd-profile.c',
|
||||
'ratbagd/ratbagd-resolution.c',
|
||||
'ratbagd/ratbagd-test.c',
|
||||
'src/libratbag-util.h',
|
||||
'src/libratbag-util.c',
|
||||
]
|
||||
@@ -395,7 +417,8 @@ executable('ratbagd.devel',
|
||||
dependencies : deps_ratbagd,
|
||||
include_directories : include_directories('src'),
|
||||
install : false,
|
||||
c_args : '-DRATBAG_DBUS_INTERFACE="ratbag_devel1_@0@"'.format(ratbagd_sha),
|
||||
c_args : ['-DRATBAG_DBUS_INTERFACE="ratbag_devel1_@0@"'.format(ratbagd_sha),
|
||||
'-DDISABLE_COREDUMP=1'],
|
||||
)
|
||||
|
||||
config_ratbagd_devel = configuration_data()
|
||||
@@ -462,19 +485,29 @@ custom_target('ratbagctl',
|
||||
'--version', meson.project_version()],
|
||||
install: true,
|
||||
install_dir: get_option('bindir'))
|
||||
install_man('tools/ratbagctl.1')
|
||||
|
||||
man_ratbagctl = configure_file (
|
||||
input: 'tools/ratbagctl.1',
|
||||
output: 'ratbagctl.1',
|
||||
configuration: man_config,
|
||||
install : true,
|
||||
install_dir : join_paths(get_option('mandir'), 'man1')
|
||||
)
|
||||
|
||||
config_ratbagctl_devel = configuration_data()
|
||||
config_ratbagctl_devel.set('ratbagd_sha', ratbagd_sha)
|
||||
config_ratbagctl_devel.set('MESON_BUILD_ROOT', meson.build_root())
|
||||
config_ratbagctl_devel.set('LIBRATBAG_DATA_DIR', libratbag_data_dir_devel)
|
||||
configure_file(input : 'tools/ratbagctl.devel.in',
|
||||
output : 'ratbagctl.devel',
|
||||
configuration : config_ratbagctl_devel)
|
||||
configure_file(input : 'tools/ratbagctl.test.in',
|
||||
output : 'ratbagctl.test',
|
||||
configuration : config_ratbagctl_devel)
|
||||
env_test = environment()
|
||||
env_test.set('LIBRATBAG_DATA_DIR', libratbag_data_dir_devel)
|
||||
ratbagctl_test = find_program(join_paths(meson.build_root(), 'ratbagctl.test'))
|
||||
test('ratbagctl-test', ratbagctl_test, args: ['-v'])
|
||||
test('ratbagctl-test', ratbagctl_test, args: ['-v'], env : env_test)
|
||||
|
||||
configure_file(input : 'tools/toolbox.py',
|
||||
output : 'toolbox.py',
|
||||
@@ -483,3 +516,46 @@ configure_file(input : 'tools/toolbox.py',
|
||||
#### output files ####
|
||||
configure_file(output: 'config.h', install: false, configuration: config_h)
|
||||
|
||||
subdir('doc')
|
||||
|
||||
#### swig generated ####
|
||||
swig = find_program('swig')
|
||||
swig_gen = generator(
|
||||
swig,
|
||||
output: ['@BASENAME@.c'],
|
||||
arguments: ['-python', '-py3', '-o', './@OUTPUT@',
|
||||
'-outdir', '.',
|
||||
'-I' + join_paths(meson.source_root(), 'src'),
|
||||
'-I' + join_paths(meson.source_root(), 'tools'),
|
||||
'@INPUT@'],
|
||||
)
|
||||
|
||||
wrapper_deps = [
|
||||
dependency('python3'),
|
||||
dep_libratbag,
|
||||
dep_libshared,
|
||||
]
|
||||
|
||||
i_source = join_paths(meson.source_root(), 'src', 'libratbag.i')
|
||||
c_source = swig_gen.process(i_source)
|
||||
shared_library(
|
||||
'libratbag',
|
||||
c_source,
|
||||
name_prefix: '_',
|
||||
c_args : ['-Wno-missing-prototypes', '-Wno-format-nonliteral'],
|
||||
extra_files: [ i_source ] + src_libratbag ,
|
||||
dependencies: deps_libratbag + wrapper_deps,
|
||||
include_directories : include_directories('src', 'tools'),
|
||||
install: false,
|
||||
)
|
||||
|
||||
|
||||
custom_target('ratbag-command',
|
||||
output : 'ratbag-command',
|
||||
input : ['tools/ratbagctl.in', 'tools/ratbagc.py'],
|
||||
build_by_default : true,
|
||||
command : [py3, join_paths(meson.source_root(), 'tools', 'merge_ratbagd.py'),
|
||||
'@INPUT@',
|
||||
'--output', '@OUTPUT@',
|
||||
'--version', meson.project_version()],
|
||||
install: false)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
option('udev-dir',
|
||||
type: 'string',
|
||||
default: '',
|
||||
value: '',
|
||||
description: 'udev base directory [default=$prefix/lib/udev]')
|
||||
|
||||
option('enable-tests',
|
||||
@@ -10,10 +10,15 @@ option('enable-tests',
|
||||
|
||||
option('systemd-unit-dir',
|
||||
type : 'string',
|
||||
default : '',
|
||||
value : '',
|
||||
description : 'systemd unit directory [default=$libdir/systemd/system]')
|
||||
|
||||
option('dbus-root-dir',
|
||||
type : 'string',
|
||||
default : '',
|
||||
value : '',
|
||||
description : 'dbus service directory [default=$datadir/dbus-1]')
|
||||
|
||||
option('documentation',
|
||||
type: 'boolean',
|
||||
value: false,
|
||||
description: 'Enable documentation build (default=no)')
|
||||
|
||||
@@ -39,6 +39,7 @@
|
||||
#include "libratbag-util.h"
|
||||
|
||||
struct ratbagd_button {
|
||||
struct ratbagd_device *device;
|
||||
struct ratbag_button *lib_button;
|
||||
unsigned int index;
|
||||
char *path;
|
||||
@@ -112,7 +113,7 @@ static int ratbagd_button_set_button(sd_bus *bus,
|
||||
NULL);
|
||||
}
|
||||
|
||||
return r;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ratbagd_button_get_special(sd_bus *bus,
|
||||
@@ -164,104 +165,7 @@ static int ratbagd_button_set_special(sd_bus *bus,
|
||||
NULL);
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static int ratbagd_button_get_key(sd_bus *bus,
|
||||
const char *path,
|
||||
const char *interface,
|
||||
const char *property,
|
||||
sd_bus_message *reply,
|
||||
void *userdata,
|
||||
sd_bus_error *error)
|
||||
{
|
||||
struct ratbagd_button *button = userdata;
|
||||
unsigned int key;
|
||||
unsigned int modifiers[10] = {0};
|
||||
size_t nmodifiers = ELEMENTSOF(modifiers);
|
||||
size_t i;
|
||||
int r;
|
||||
|
||||
/* Return an array with the first element the key, the rest
|
||||
are modifiers (or 0 if unset). If no key is set, the array is
|
||||
just [0] */
|
||||
|
||||
r = sd_bus_message_open_container(reply, 'a', "u");
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
key = ratbag_button_get_key(button->lib_button,
|
||||
modifiers,
|
||||
&nmodifiers);
|
||||
|
||||
r = sd_bus_message_append(reply, "u", key);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (key == 0)
|
||||
nmodifiers = 0;
|
||||
|
||||
for (i = 0; i < nmodifiers; i++) {
|
||||
r = sd_bus_message_append(reply, "u", modifiers[0]);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
return sd_bus_message_close_container(reply);
|
||||
}
|
||||
|
||||
static int ratbagd_button_set_key(sd_bus *bus,
|
||||
const char *path,
|
||||
const char *interface,
|
||||
const char *property,
|
||||
sd_bus_message *m,
|
||||
void *userdata,
|
||||
sd_bus_error *error)
|
||||
{
|
||||
struct ratbagd_button *button = userdata;
|
||||
unsigned int key;
|
||||
size_t nmodifiers = 10;
|
||||
unsigned int modifiers[nmodifiers];
|
||||
int r;
|
||||
|
||||
/* Expect an array with the first element the key, the rest
|
||||
are modifiers (or 0 if unset). */
|
||||
|
||||
r = sd_bus_message_enter_container(m, 'a', "u");
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_bus_message_read(m, "u", &key);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
nmodifiers = 0;
|
||||
while ((r = sd_bus_message_read_basic(m, 'u',
|
||||
&modifiers[nmodifiers++])) > 0)
|
||||
;
|
||||
|
||||
r = sd_bus_message_exit_container(m);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = ratbag_button_set_key(button->lib_button, key, modifiers, nmodifiers);
|
||||
|
||||
if (r == 0) {
|
||||
sd_bus *bus = sd_bus_message_get_bus(m);
|
||||
sd_bus_emit_properties_changed(bus,
|
||||
button->path,
|
||||
RATBAGD_NAME_ROOT ".Button",
|
||||
"KeyMapping",
|
||||
NULL);
|
||||
|
||||
sd_bus_emit_properties_changed(bus,
|
||||
button->path,
|
||||
RATBAGD_NAME_ROOT ".Button",
|
||||
"ActionType",
|
||||
NULL);
|
||||
}
|
||||
|
||||
return r;
|
||||
return 0;
|
||||
}
|
||||
|
||||
DEFINE_TRIVIAL_CLEANUP_FUNC(struct ratbag_button_macro *, ratbag_button_macro_unref);
|
||||
@@ -305,6 +209,8 @@ static int ratbagd_button_get_macro(sd_bus *bus,
|
||||
case RATBAG_MACRO_EVENT_WAIT:
|
||||
value = ratbag_button_macro_get_event_timeout(macro, idx);
|
||||
break;
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
|
||||
r = sd_bus_message_append(reply, "(uu)", type, value);
|
||||
@@ -336,8 +242,11 @@ static int ratbagd_button_set_macro(sd_bus *bus,
|
||||
macro = ratbag_button_macro_new("macro");
|
||||
while ((r = sd_bus_message_read(m, "(uu)", &type, &value)) > 0) {
|
||||
r = ratbag_button_macro_set_event(macro, idx++, type, value);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (r < 0) {
|
||||
r = ratbagd_device_resync(button->device, bus);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
}
|
||||
if (r < 0)
|
||||
return r;
|
||||
@@ -347,8 +256,11 @@ static int ratbagd_button_set_macro(sd_bus *bus,
|
||||
return r;
|
||||
|
||||
r = ratbag_button_set_macro(button->lib_button, macro);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (r < 0) {
|
||||
r = ratbagd_device_resync(button->device, bus);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
if (r == 0) {
|
||||
sd_bus *bus = sd_bus_message_get_bus(m);
|
||||
@@ -365,7 +277,7 @@ static int ratbagd_button_set_macro(sd_bus *bus,
|
||||
NULL);
|
||||
}
|
||||
|
||||
return r;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ratbagd_button_get_action_type(sd_bus *bus,
|
||||
@@ -380,6 +292,8 @@ static int ratbagd_button_get_action_type(sd_bus *bus,
|
||||
enum ratbag_button_action_type type;
|
||||
|
||||
type = ratbag_button_get_action_type(button->lib_button);
|
||||
if (type == RATBAG_BUTTON_ACTION_TYPE_KEY)
|
||||
type = RATBAG_BUTTON_ACTION_TYPE_UNKNOWN;
|
||||
|
||||
return sd_bus_message_append(reply, "u", type);
|
||||
}
|
||||
@@ -397,7 +311,6 @@ static int ratbagd_button_get_action_types(sd_bus *bus,
|
||||
enum ratbag_button_action_type types[] = {
|
||||
RATBAG_BUTTON_ACTION_TYPE_BUTTON,
|
||||
RATBAG_BUTTON_ACTION_TYPE_SPECIAL,
|
||||
RATBAG_BUTTON_ACTION_TYPE_KEY,
|
||||
RATBAG_BUTTON_ACTION_TYPE_MACRO
|
||||
};
|
||||
enum ratbag_button_action_type *t;
|
||||
@@ -431,8 +344,14 @@ static int ratbagd_button_disable(sd_bus_message *m,
|
||||
return r;
|
||||
|
||||
r = ratbag_button_disable(button->lib_button);
|
||||
if (r < 0) {
|
||||
sd_bus *bus = sd_bus_message_get_bus(m);
|
||||
r = ratbagd_device_resync(button->device, bus);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
return sd_bus_reply_method_return(m, "u", r);
|
||||
return sd_bus_reply_method_return(m, "u", 0);
|
||||
}
|
||||
|
||||
const sd_bus_vtable ratbagd_button_vtable[] = {
|
||||
@@ -447,10 +366,6 @@ const sd_bus_vtable ratbagd_button_vtable[] = {
|
||||
ratbagd_button_get_special,
|
||||
ratbagd_button_set_special,
|
||||
0, SD_BUS_VTABLE_UNPRIVILEGED | SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
|
||||
SD_BUS_WRITABLE_PROPERTY("KeyMapping", "au",
|
||||
ratbagd_button_get_key,
|
||||
ratbagd_button_set_key,
|
||||
0, SD_BUS_VTABLE_UNPRIVILEGED | SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
|
||||
SD_BUS_WRITABLE_PROPERTY("Macro", "a(uu)",
|
||||
ratbagd_button_get_macro,
|
||||
ratbagd_button_set_macro,
|
||||
@@ -476,6 +391,7 @@ int ratbagd_button_new(struct ratbagd_button **out,
|
||||
assert(lib_button);
|
||||
|
||||
button = zalloc(sizeof(*button));
|
||||
button->device = device;
|
||||
button->lib_button = lib_button;
|
||||
button->index = index;
|
||||
|
||||
@@ -483,7 +399,7 @@ int ratbagd_button_new(struct ratbagd_button **out,
|
||||
sprintf(button_buffer, "b%u", index);
|
||||
r = sd_bus_path_encode_many(&button->path,
|
||||
RATBAGD_OBJ_ROOT "/button/%/%/%",
|
||||
ratbagd_device_get_name(device),
|
||||
ratbagd_device_get_sysname(device),
|
||||
profile_buffer,
|
||||
button_buffer);
|
||||
if (r < 0)
|
||||
|
||||
@@ -43,7 +43,7 @@
|
||||
struct ratbagd_device {
|
||||
struct ratbagd *ctx;
|
||||
RBNode node;
|
||||
char *name;
|
||||
char *sysname;
|
||||
char *path;
|
||||
struct ratbag_device *lib_device;
|
||||
|
||||
@@ -125,8 +125,8 @@ static int ratbagd_device_get_device_name(sd_bus *bus,
|
||||
|
||||
name = ratbag_device_get_name(device->lib_device);
|
||||
if (!name) {
|
||||
log_error("Unable to fetch name for %s\n",
|
||||
ratbagd_device_get_name(device));
|
||||
log_error("%s: failed to fetch name\n",
|
||||
ratbagd_device_get_sysname(device));
|
||||
name = "";
|
||||
}
|
||||
|
||||
@@ -146,8 +146,8 @@ static int ratbagd_device_get_svg(sd_bus *bus,
|
||||
|
||||
svg = ratbag_device_get_svg_name(device->lib_device);
|
||||
if (!svg) {
|
||||
log_error("Unable to fetch SVG for %s\n",
|
||||
ratbagd_device_get_name(device));
|
||||
log_error("%s: failed to fetch SVG\n",
|
||||
ratbagd_device_get_sysname(device));
|
||||
svg = "";
|
||||
}
|
||||
|
||||
@@ -163,6 +163,11 @@ static int ratbagd_device_get_theme_svg(sd_bus_message *m,
|
||||
const char *theme;
|
||||
const char *svg;
|
||||
int r;
|
||||
const char *datadir;
|
||||
|
||||
datadir = getenv("LIBRATBAG_DATA_DIR");
|
||||
if (!datadir)
|
||||
datadir = LIBRATBAG_DATA_DIR;
|
||||
|
||||
r = sd_bus_message_read(m, "s", &theme);
|
||||
if (r < 0)
|
||||
@@ -171,14 +176,13 @@ static int ratbagd_device_get_theme_svg(sd_bus_message *m,
|
||||
|
||||
svg = ratbag_device_get_svg_name(device->lib_device);
|
||||
if (!svg) {
|
||||
log_error("Unable to fetch SVG for %s\n",
|
||||
ratbagd_device_get_name(device));
|
||||
goto out;
|
||||
log_error("%s: failed to fetch SVG, using fallback\n",
|
||||
ratbagd_device_get_sysname(device));
|
||||
svg = FALLBACK_SVG_NAME;
|
||||
}
|
||||
|
||||
sprintf(svg_path, "%s/%s/%s", LIBRATBAG_DATA_DIR, theme, svg);
|
||||
snprintf(svg_path, sizeof(svg_path), "%s/%s/%s", datadir, theme, svg);
|
||||
|
||||
out:
|
||||
return sd_bus_reply_method_return(m, "s", svg_path);
|
||||
}
|
||||
|
||||
@@ -222,8 +226,14 @@ static int ratbagd_device_commit(sd_bus_message *m,
|
||||
int r;
|
||||
|
||||
r = ratbag_device_commit(device->lib_device);
|
||||
if (r < 0) {
|
||||
sd_bus *bus = sd_bus_message_get_bus(m);
|
||||
r = ratbagd_device_resync(device, bus);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
return sd_bus_reply_method_return(m, "u", r);
|
||||
return sd_bus_reply_method_return(m, "u", 0);
|
||||
}
|
||||
|
||||
static int
|
||||
@@ -272,19 +282,20 @@ ratbagd_device_get_capabilities(sd_bus *bus,
|
||||
|
||||
const sd_bus_vtable ratbagd_device_vtable[] = {
|
||||
SD_BUS_VTABLE_START(0),
|
||||
SD_BUS_PROPERTY("Id", "s", NULL, offsetof(struct ratbagd_device, name), SD_BUS_VTABLE_PROPERTY_CONST),
|
||||
SD_BUS_PROPERTY("Id", "s", NULL, offsetof(struct ratbagd_device, sysname), SD_BUS_VTABLE_PROPERTY_CONST),
|
||||
SD_BUS_PROPERTY("Capabilities", "au", ratbagd_device_get_capabilities, 0, SD_BUS_VTABLE_PROPERTY_CONST),
|
||||
SD_BUS_PROPERTY("Name", "s", ratbagd_device_get_device_name, 0, SD_BUS_VTABLE_PROPERTY_CONST),
|
||||
SD_BUS_PROPERTY("Svg", "s", ratbagd_device_get_svg, 0, SD_BUS_VTABLE_PROPERTY_CONST),
|
||||
SD_BUS_PROPERTY("Profiles", "ao", ratbagd_device_get_profiles, 0, SD_BUS_VTABLE_PROPERTY_CONST),
|
||||
SD_BUS_METHOD("GetSvg", "s", "s", ratbagd_device_get_theme_svg, SD_BUS_VTABLE_UNPRIVILEGED),
|
||||
SD_BUS_METHOD("Commit", "", "u", ratbagd_device_commit, SD_BUS_VTABLE_UNPRIVILEGED),
|
||||
SD_BUS_SIGNAL("Resync", "", 0),
|
||||
SD_BUS_VTABLE_END,
|
||||
};
|
||||
|
||||
int ratbagd_device_new(struct ratbagd_device **out,
|
||||
struct ratbagd *ctx,
|
||||
const char *name,
|
||||
const char *sysname,
|
||||
struct ratbag_device *lib_device)
|
||||
{
|
||||
_cleanup_(ratbagd_device_freep) struct ratbagd_device *device = NULL;
|
||||
@@ -294,17 +305,17 @@ int ratbagd_device_new(struct ratbagd_device **out,
|
||||
|
||||
assert(out);
|
||||
assert(ctx);
|
||||
assert(name);
|
||||
assert(sysname);
|
||||
|
||||
device = zalloc(sizeof(*device));
|
||||
device->ctx = ctx;
|
||||
rbnode_init(&device->node);
|
||||
device->lib_device = ratbag_device_ref(lib_device);
|
||||
|
||||
device->name = strdup_safe(name);
|
||||
device->sysname = strdup_safe(sysname);
|
||||
|
||||
r = sd_bus_path_encode(RATBAGD_OBJ_ROOT "/device",
|
||||
device->name,
|
||||
device->sysname,
|
||||
&device->path);
|
||||
if (r < 0)
|
||||
return r;
|
||||
@@ -314,7 +325,7 @@ int ratbagd_device_new(struct ratbagd_device **out,
|
||||
device->profiles = zalloc(device->n_profiles * sizeof(*device->profiles));
|
||||
|
||||
log_verbose("%s: \"%s\", %d profiles\n",
|
||||
name,
|
||||
sysname,
|
||||
ratbag_device_get_name(lib_device),
|
||||
device->n_profiles);
|
||||
|
||||
@@ -329,8 +340,8 @@ int ratbagd_device_new(struct ratbagd_device **out,
|
||||
i);
|
||||
if (r < 0) {
|
||||
errno = -r;
|
||||
log_error("Cannot allocate profile for '%s': %m\n",
|
||||
device->name);
|
||||
log_error("%s: failed to allocate profile: %m\n",
|
||||
device->sysname);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -354,17 +365,17 @@ struct ratbagd_device *ratbagd_device_free(struct ratbagd_device *device)
|
||||
device->profiles = mfree(device->profiles);
|
||||
device->lib_device = ratbag_device_unref(device->lib_device);
|
||||
device->path = mfree(device->path);
|
||||
device->name = mfree(device->name);
|
||||
device->sysname = mfree(device->sysname);
|
||||
|
||||
assert(!device->lib_device); /* ratbag yields !NULL if still pinned */
|
||||
|
||||
return mfree(device);
|
||||
}
|
||||
|
||||
const char *ratbagd_device_get_name(struct ratbagd_device *device)
|
||||
const char *ratbagd_device_get_sysname(struct ratbagd_device *device)
|
||||
{
|
||||
assert(device);
|
||||
return device->name;
|
||||
return device->sysname;
|
||||
}
|
||||
|
||||
const char *ratbagd_device_get_path(struct ratbagd_device *device)
|
||||
@@ -385,6 +396,17 @@ unsigned int ratbagd_device_get_num_leds(struct ratbagd_device *device)
|
||||
return ratbag_device_get_num_leds(device->lib_device);
|
||||
}
|
||||
|
||||
int ratbagd_device_resync(struct ratbagd_device *device, sd_bus *bus)
|
||||
{
|
||||
assert(device);
|
||||
assert(bus);
|
||||
return sd_bus_emit_signal(bus,
|
||||
device->path,
|
||||
RATBAGD_NAME_ROOT ".Device",
|
||||
"Resync",
|
||||
NULL);
|
||||
}
|
||||
|
||||
bool ratbagd_device_linked(struct ratbagd_device *device)
|
||||
{
|
||||
return device && rbnode_linked(&device->node);
|
||||
@@ -407,7 +429,7 @@ void ratbagd_device_link(struct ratbagd_device *device)
|
||||
while (*node) {
|
||||
parent = *node;
|
||||
iter = ratbagd_device_from_node(parent);
|
||||
v = strcmp(device->name, iter->name);
|
||||
v = strcmp(device->sysname, iter->sysname);
|
||||
|
||||
/* if there's a duplicate, the caller screwed up */
|
||||
assert(v != 0);
|
||||
@@ -425,7 +447,7 @@ void ratbagd_device_link(struct ratbagd_device *device)
|
||||
/* register profile interfaces */
|
||||
r = sd_bus_path_encode_many(&prefix,
|
||||
RATBAGD_OBJ_ROOT "/profile/%",
|
||||
device->name);
|
||||
device->sysname);
|
||||
if (r >= 0) {
|
||||
r = sd_bus_add_fallback_vtable(device->ctx->bus,
|
||||
&device->profile_vtable_slot,
|
||||
@@ -443,8 +465,8 @@ void ratbagd_device_link(struct ratbagd_device *device)
|
||||
}
|
||||
if (r < 0) {
|
||||
errno = -r;
|
||||
log_error("Cannot register profile interfaces for '%s': %m\n",
|
||||
device->name);
|
||||
log_error("%s: failed to register profile interfaces: %m\n",
|
||||
device->sysname);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -453,24 +475,24 @@ void ratbagd_device_link(struct ratbagd_device *device)
|
||||
device,
|
||||
device->profiles[i]);
|
||||
if (r < 0) {
|
||||
log_error("Cannot register resolutions for '%s': %m\n",
|
||||
device->name);
|
||||
log_error("%s: failed to register resolutions: %m\n",
|
||||
device->sysname);
|
||||
}
|
||||
|
||||
r = ratbagd_profile_register_buttons(device->ctx->bus,
|
||||
device,
|
||||
device->profiles[i]);
|
||||
if (r < 0) {
|
||||
log_error("Cannot register buttons for '%s': %m\n",
|
||||
device->name);
|
||||
log_error("%s: failed to register buttons: %m\n",
|
||||
device->sysname);
|
||||
}
|
||||
|
||||
r = ratbagd_profile_register_leds(device->ctx->bus,
|
||||
device,
|
||||
device->profiles[i]);
|
||||
if (r < 0) {
|
||||
log_error("Cannot register leds for '%s': %m\n",
|
||||
device->name);
|
||||
log_error("%s: failed to register leds: %m\n",
|
||||
device->sysname);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -502,7 +524,7 @@ struct ratbagd_device *ratbagd_device_lookup(struct ratbagd *ctx,
|
||||
node = ctx->device_map.root;
|
||||
while (node) {
|
||||
device = ratbagd_device_from_node(node);
|
||||
v = strcmp(name, device->name);
|
||||
v = strcmp(name, device->sysname);
|
||||
if (!v)
|
||||
return device;
|
||||
else if (v < 0)
|
||||
|
||||
@@ -37,8 +37,35 @@ struct ratbagd_led {
|
||||
struct ratbag_led *lib_led;
|
||||
unsigned int index;
|
||||
char *path;
|
||||
enum ratbag_led_colordepth colordepth;
|
||||
};
|
||||
|
||||
static int ratbagd_led_get_modes(sd_bus *bus,
|
||||
const char *path,
|
||||
const char *interface,
|
||||
const char *property,
|
||||
sd_bus_message *reply,
|
||||
void *userdata,
|
||||
sd_bus_error *error)
|
||||
{
|
||||
struct ratbagd_led *led = userdata;
|
||||
enum ratbag_led_mode mode = 0;
|
||||
int r;
|
||||
|
||||
r = sd_bus_message_open_container(reply, 'a', "u");
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
|
||||
while (mode <= RATBAG_LED_BREATHING) {
|
||||
if (ratbag_led_has_mode(led->lib_led, mode))
|
||||
sd_bus_message_append(reply, "u", mode);
|
||||
mode++;
|
||||
}
|
||||
|
||||
return sd_bus_message_close_container(reply);
|
||||
}
|
||||
|
||||
static int ratbagd_led_get_mode(sd_bus *bus,
|
||||
const char *path,
|
||||
const char *interface,
|
||||
@@ -81,7 +108,7 @@ static int ratbagd_led_set_mode(sd_bus *bus,
|
||||
NULL);
|
||||
}
|
||||
|
||||
return r;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ratbagd_led_get_type(sd_bus *bus,
|
||||
@@ -131,8 +158,12 @@ static int ratbagd_led_set_color(sd_bus *bus,
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (c.red > 255 || c.green > 255 || c.blue > 255)
|
||||
return RATBAG_ERROR_VALUE;
|
||||
if (c.red > 255)
|
||||
c.red = 255;
|
||||
if (c.green > 255)
|
||||
c.green = 255;
|
||||
if (c.blue > 255)
|
||||
c.blue = 255;
|
||||
|
||||
r = ratbag_led_set_color(led->lib_led, c);
|
||||
|
||||
@@ -145,31 +176,31 @@ static int ratbagd_led_set_color(sd_bus *bus,
|
||||
NULL);
|
||||
}
|
||||
|
||||
return r;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ratbagd_led_get_effect_rate(sd_bus *bus,
|
||||
const char *path,
|
||||
const char *interface,
|
||||
const char *property,
|
||||
sd_bus_message *reply,
|
||||
void *userdata,
|
||||
sd_bus_error *error)
|
||||
static int ratbagd_led_get_effect_duration(sd_bus *bus,
|
||||
const char *path,
|
||||
const char *interface,
|
||||
const char *property,
|
||||
sd_bus_message *reply,
|
||||
void *userdata,
|
||||
sd_bus_error *error)
|
||||
{
|
||||
struct ratbagd_led *led = userdata;
|
||||
int rate;
|
||||
|
||||
rate = ratbag_led_get_effect_rate(led->lib_led);
|
||||
rate = ratbag_led_get_effect_duration(led->lib_led);
|
||||
return sd_bus_message_append(reply, "u", rate);
|
||||
}
|
||||
|
||||
static int ratbagd_led_set_effect_rate(sd_bus *bus,
|
||||
const char *path,
|
||||
const char *interface,
|
||||
const char *property,
|
||||
sd_bus_message *m,
|
||||
void *userdata,
|
||||
sd_bus_error *error)
|
||||
static int ratbagd_led_set_effect_duration(sd_bus *bus,
|
||||
const char *path,
|
||||
const char *interface,
|
||||
const char *property,
|
||||
sd_bus_message *m,
|
||||
void *userdata,
|
||||
sd_bus_error *error)
|
||||
{
|
||||
struct ratbagd_led *led = userdata;
|
||||
unsigned int rate;
|
||||
@@ -179,21 +210,21 @@ static int ratbagd_led_set_effect_rate(sd_bus *bus,
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (rate < 100 || rate > 20000)
|
||||
return 0;
|
||||
if (rate > 10000)
|
||||
rate = 10000;
|
||||
|
||||
r = ratbag_led_set_effect_rate(led->lib_led, rate);
|
||||
r = ratbag_led_set_effect_duration(led->lib_led, rate);
|
||||
|
||||
if (r == 0) {
|
||||
sd_bus *bus = sd_bus_message_get_bus(m);
|
||||
sd_bus_emit_properties_changed(bus,
|
||||
led->path,
|
||||
RATBAGD_NAME_ROOT ".Led",
|
||||
"EffectRate",
|
||||
"EffectDuration",
|
||||
NULL);
|
||||
}
|
||||
|
||||
return r;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ratbagd_led_get_brightness(sd_bus *bus,
|
||||
@@ -228,7 +259,7 @@ static int ratbagd_led_set_brightness(sd_bus *bus,
|
||||
return r;
|
||||
|
||||
if (brightness > 255)
|
||||
return 0;
|
||||
brightness = 255;
|
||||
|
||||
r = ratbag_led_set_brightness(led->lib_led, brightness);
|
||||
|
||||
@@ -241,12 +272,13 @@ static int ratbagd_led_set_brightness(sd_bus *bus,
|
||||
NULL);
|
||||
}
|
||||
|
||||
return r;
|
||||
return 0;
|
||||
}
|
||||
|
||||
const sd_bus_vtable ratbagd_led_vtable[] = {
|
||||
SD_BUS_VTABLE_START(0),
|
||||
SD_BUS_PROPERTY("Index", "u", NULL, offsetof(struct ratbagd_led, index), SD_BUS_VTABLE_PROPERTY_CONST),
|
||||
SD_BUS_PROPERTY("Modes", "au", ratbagd_led_get_modes, 0, SD_BUS_VTABLE_PROPERTY_CONST),
|
||||
SD_BUS_WRITABLE_PROPERTY("Mode", "u",
|
||||
ratbagd_led_get_mode,
|
||||
ratbagd_led_set_mode, 0,
|
||||
@@ -255,8 +287,9 @@ const sd_bus_vtable ratbagd_led_vtable[] = {
|
||||
SD_BUS_WRITABLE_PROPERTY("Color", "(uuu)",
|
||||
ratbagd_led_get_color, ratbagd_led_set_color, 0,
|
||||
SD_BUS_VTABLE_UNPRIVILEGED|SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
|
||||
SD_BUS_WRITABLE_PROPERTY("EffectRate", "u",
|
||||
ratbagd_led_get_effect_rate, ratbagd_led_set_effect_rate, 0,
|
||||
SD_BUS_PROPERTY("ColorDepth", "u", NULL, offsetof(struct ratbagd_led, colordepth), SD_BUS_VTABLE_PROPERTY_CONST),
|
||||
SD_BUS_WRITABLE_PROPERTY("EffectDuration", "u",
|
||||
ratbagd_led_get_effect_duration, ratbagd_led_set_effect_duration, 0,
|
||||
SD_BUS_VTABLE_UNPRIVILEGED|SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
|
||||
SD_BUS_WRITABLE_PROPERTY("Brightness", "u",
|
||||
ratbagd_led_get_brightness, ratbagd_led_set_brightness, 0,
|
||||
@@ -281,12 +314,13 @@ int ratbagd_led_new(struct ratbagd_led **out,
|
||||
led = zalloc(sizeof(*led));
|
||||
led->lib_led = lib_led;
|
||||
led->index = index;
|
||||
led->colordepth = ratbag_led_get_colordepth(lib_led);
|
||||
|
||||
sprintf(profile_buffer, "p%u", ratbagd_profile_get_index(profile));
|
||||
sprintf(led_buffer, "l%u", index);
|
||||
r = sd_bus_path_encode_many(&led->path,
|
||||
RATBAGD_OBJ_ROOT "/led/%/%/%",
|
||||
ratbagd_device_get_name(device),
|
||||
ratbagd_device_get_sysname(device),
|
||||
profile_buffer,
|
||||
led_buffer);
|
||||
if (r < 0)
|
||||
|
||||
@@ -268,17 +268,13 @@ static int ratbagd_profile_find_led(sd_bus *bus,
|
||||
static int ratbagd_profile_active_signal_cb(sd_bus *bus,
|
||||
struct ratbagd_profile *profile)
|
||||
{
|
||||
struct ratbag_profile *lib_profile = profile->lib_profile;
|
||||
|
||||
/* FIXME: we should cache is active and only send the signal for
|
||||
* those profiles where it changed */
|
||||
|
||||
(void) sd_bus_emit_signal(bus,
|
||||
profile->path,
|
||||
RATBAGD_NAME_ROOT ".Profile",
|
||||
"IsActive",
|
||||
"b",
|
||||
ratbag_profile_is_active(lib_profile));
|
||||
(void) sd_bus_emit_properties_changed(bus,
|
||||
profile->path,
|
||||
RATBAGD_NAME_ROOT ".Profile",
|
||||
"IsActive",
|
||||
NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -294,12 +290,19 @@ static int ratbagd_profile_set_active(sd_bus_message *m,
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = ratbag_profile_set_active(profile->lib_profile);
|
||||
if (r < 0) {
|
||||
sd_bus *bus = sd_bus_message_get_bus(m);
|
||||
r = ratbagd_device_resync(profile->device, bus);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
ratbagd_for_each_profile_signal(sd_bus_message_get_bus(m),
|
||||
profile->device,
|
||||
ratbagd_profile_active_signal_cb);
|
||||
|
||||
return sd_bus_reply_method_return(m, "u",
|
||||
ratbag_profile_set_active(profile->lib_profile));
|
||||
return sd_bus_reply_method_return(m, "u", 0);
|
||||
}
|
||||
|
||||
static int
|
||||
@@ -329,7 +332,7 @@ ratbagd_profile_set_enabled(sd_bus *bus,
|
||||
NULL);
|
||||
}
|
||||
|
||||
return r;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
@@ -347,13 +350,97 @@ ratbagd_profile_is_enabled(sd_bus *bus,
|
||||
return sd_bus_message_append(reply, "b", enabled);
|
||||
}
|
||||
|
||||
static int
|
||||
ratbagd_profile_set_name(sd_bus *bus,
|
||||
const char *path,
|
||||
const char *interface,
|
||||
const char *property,
|
||||
sd_bus_message *m,
|
||||
void *userdata,
|
||||
sd_bus_error *error)
|
||||
{
|
||||
struct ratbagd_profile *profile = userdata;
|
||||
char *name;
|
||||
int r;
|
||||
|
||||
r = sd_bus_message_read(m, "s", &name);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = ratbag_profile_set_name(profile->lib_profile, name);
|
||||
|
||||
if (r == 0) {
|
||||
sd_bus_emit_properties_changed(bus,
|
||||
profile->path,
|
||||
RATBAGD_NAME_ROOT ".Profile",
|
||||
"Name",
|
||||
NULL);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
ratbagd_profile_get_name(sd_bus *bus,
|
||||
const char *path,
|
||||
const char *interface,
|
||||
const char *property,
|
||||
sd_bus_message *reply,
|
||||
void *userdata,
|
||||
sd_bus_error *error)
|
||||
{
|
||||
struct ratbagd_profile *profile = userdata;
|
||||
const char *name = ratbag_profile_get_name(profile->lib_profile);
|
||||
|
||||
return sd_bus_message_append(reply, "s", name);
|
||||
}
|
||||
|
||||
static int
|
||||
ratbagd_profile_get_capabilities(sd_bus *bus,
|
||||
const char *path,
|
||||
const char *interface,
|
||||
const char *property,
|
||||
sd_bus_message *reply,
|
||||
void *userdata,
|
||||
sd_bus_error *error)
|
||||
{
|
||||
struct ratbagd_profile *profile = userdata;
|
||||
struct ratbag_profile *lib_profile = profile->lib_profile;
|
||||
enum ratbag_profile_capability cap;
|
||||
enum ratbag_profile_capability caps[] = {
|
||||
RATBAG_PROFILE_CAP_WRITABLE_NAME,
|
||||
};
|
||||
int r;
|
||||
size_t i;
|
||||
|
||||
r = sd_bus_message_open_container(reply, 'a', "u");
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
for (i = 0; i < ELEMENTSOF(caps); i++) {
|
||||
cap = caps[i];
|
||||
if (ratbag_profile_has_capability(lib_profile, cap)) {
|
||||
r = sd_bus_message_append(reply, "u", cap);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
return sd_bus_message_close_container(reply);
|
||||
}
|
||||
|
||||
const sd_bus_vtable ratbagd_profile_vtable[] = {
|
||||
SD_BUS_VTABLE_START(0),
|
||||
SD_BUS_WRITABLE_PROPERTY("Name", "s",
|
||||
ratbagd_profile_get_name,
|
||||
ratbagd_profile_set_name, 0,
|
||||
SD_BUS_VTABLE_UNPRIVILEGED|SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
|
||||
SD_BUS_WRITABLE_PROPERTY("Enabled", "b",
|
||||
ratbagd_profile_is_enabled,
|
||||
ratbagd_profile_set_enabled, 0,
|
||||
SD_BUS_VTABLE_UNPRIVILEGED|SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
|
||||
SD_BUS_PROPERTY("Index", "u", NULL, offsetof(struct ratbagd_profile, index), SD_BUS_VTABLE_PROPERTY_CONST),
|
||||
SD_BUS_PROPERTY("Capabilities", "au", ratbagd_profile_get_capabilities, 0, SD_BUS_VTABLE_PROPERTY_CONST),
|
||||
SD_BUS_PROPERTY("Resolutions", "ao", ratbagd_profile_get_resolutions, 0, 0),
|
||||
SD_BUS_PROPERTY("Buttons", "ao", ratbagd_profile_get_buttons, 0, 0),
|
||||
SD_BUS_PROPERTY("Leds", "ao", ratbagd_profile_get_leds, 0, 0),
|
||||
@@ -387,7 +474,7 @@ int ratbagd_profile_new(struct ratbagd_profile **out,
|
||||
sprintf(index_buffer, "p%u", index);
|
||||
r = sd_bus_path_encode_many(&profile->path,
|
||||
RATBAGD_OBJ_ROOT "/profile/%/%",
|
||||
ratbagd_device_get_name(device),
|
||||
ratbagd_device_get_sysname(device),
|
||||
index_buffer);
|
||||
if (r < 0)
|
||||
return r;
|
||||
@@ -413,8 +500,8 @@ int ratbagd_profile_new(struct ratbagd_profile **out,
|
||||
i);
|
||||
if (r < 0) {
|
||||
errno = -r;
|
||||
log_error("Cannot allocate resolution for '%s': %m\n",
|
||||
ratbagd_device_get_name(device));
|
||||
log_error("%s: failed to allocate resolution: %m\n",
|
||||
ratbagd_device_get_sysname(device));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -430,8 +517,8 @@ int ratbagd_profile_new(struct ratbagd_profile **out,
|
||||
i);
|
||||
if (r < 0) {
|
||||
errno = -r;
|
||||
log_error("Cannot allocate button for '%s': %m\n",
|
||||
ratbagd_device_get_name(device));
|
||||
log_error("%s: failed to allocate button: %m\n",
|
||||
ratbagd_device_get_sysname(device));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -447,8 +534,8 @@ int ratbagd_profile_new(struct ratbagd_profile **out,
|
||||
i);
|
||||
if (r < 0) {
|
||||
errno = -r;
|
||||
log_error("Cannot allocate led for '%s': %m\n",
|
||||
ratbagd_device_get_name(device));
|
||||
log_error("%s: failed to allocate led: %m\n",
|
||||
ratbagd_device_get_sysname(device));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -540,7 +627,7 @@ int ratbagd_profile_register_resolutions(struct sd_bus *bus,
|
||||
/* register resolution interfaces */
|
||||
r = sd_bus_path_encode_many(&prefix,
|
||||
RATBAGD_OBJ_ROOT "/resolution/%/%",
|
||||
ratbagd_device_get_name(device),
|
||||
ratbagd_device_get_sysname(device),
|
||||
index_buffer);
|
||||
|
||||
if (r >= 0) {
|
||||
@@ -560,8 +647,8 @@ int ratbagd_profile_register_resolutions(struct sd_bus *bus,
|
||||
}
|
||||
if (r < 0) {
|
||||
errno = -r;
|
||||
log_error("Cannot register resolutions for '%s': %m\n",
|
||||
ratbagd_device_get_name(device));
|
||||
log_error("%s: failed to register resolutions: %m\n",
|
||||
ratbagd_device_get_sysname(device));
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -606,7 +693,7 @@ int ratbagd_profile_register_buttons(struct sd_bus *bus,
|
||||
/* register button interfaces */
|
||||
r = sd_bus_path_encode_many(&prefix,
|
||||
RATBAGD_OBJ_ROOT "/button/%/%",
|
||||
ratbagd_device_get_name(device),
|
||||
ratbagd_device_get_sysname(device),
|
||||
index_buffer);
|
||||
|
||||
if (r >= 0) {
|
||||
@@ -626,8 +713,8 @@ int ratbagd_profile_register_buttons(struct sd_bus *bus,
|
||||
}
|
||||
if (r < 0) {
|
||||
errno = -r;
|
||||
log_error("Cannot register buttons for '%s': %m\n",
|
||||
ratbagd_device_get_name(device));
|
||||
log_error("%s: failed to register buttons: %m\n",
|
||||
ratbagd_device_get_sysname(device));
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -672,7 +759,7 @@ int ratbagd_profile_register_leds(struct sd_bus *bus,
|
||||
/* register led interfaces */
|
||||
r = sd_bus_path_encode_many(&prefix,
|
||||
RATBAGD_OBJ_ROOT "/led/%/%",
|
||||
ratbagd_device_get_name(device),
|
||||
ratbagd_device_get_sysname(device),
|
||||
index_buffer);
|
||||
|
||||
if (r >= 0) {
|
||||
@@ -692,8 +779,8 @@ int ratbagd_profile_register_leds(struct sd_bus *bus,
|
||||
}
|
||||
if (r < 0) {
|
||||
errno = -r;
|
||||
log_error("Cannot register leds for '%s': %m\n",
|
||||
ratbagd_device_get_name(device));
|
||||
log_error("%s: failed to register leds: %m\n",
|
||||
ratbagd_device_get_sysname(device));
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -38,62 +38,19 @@
|
||||
#include "libratbag-util.h"
|
||||
|
||||
struct ratbagd_resolution {
|
||||
struct ratbagd_device *device;
|
||||
struct ratbagd_profile *profile;
|
||||
struct ratbag_resolution *lib_resolution;
|
||||
unsigned int index;
|
||||
char *path;
|
||||
};
|
||||
|
||||
static int
|
||||
ratbagd_resolution_set_report_rate(sd_bus *bus,
|
||||
const char *path,
|
||||
const char *interface,
|
||||
const char *property,
|
||||
sd_bus_message *m,
|
||||
void *userdata,
|
||||
sd_bus_error *error)
|
||||
{
|
||||
struct ratbagd_resolution *resolution = userdata;
|
||||
unsigned int rate;
|
||||
int r;
|
||||
|
||||
r = sd_bus_message_read(m, "u", &rate);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
/* basic sanity check */
|
||||
if (rate > 5000 || rate % 100)
|
||||
return 0;
|
||||
|
||||
r = ratbag_resolution_set_report_rate(resolution->lib_resolution,
|
||||
rate);
|
||||
if (r == 0) {
|
||||
sd_bus *bus = sd_bus_message_get_bus(m);
|
||||
sd_bus_emit_properties_changed(bus,
|
||||
resolution->path,
|
||||
RATBAGD_NAME_ROOT ".Resolution",
|
||||
"ReportRate",
|
||||
NULL);
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static int ratbagd_resolution_active_signal_cb(sd_bus *bus,
|
||||
struct ratbagd_resolution *resolution)
|
||||
{
|
||||
struct ratbag_resolution *lib_resolution = resolution->lib_resolution;
|
||||
|
||||
/* FIXME: we should cache is_active and only send the signal for
|
||||
* those resolutions where it changed */
|
||||
|
||||
(void) sd_bus_emit_signal(bus,
|
||||
resolution->path,
|
||||
RATBAGD_NAME_ROOT ".Resolution",
|
||||
"IsActive",
|
||||
"b",
|
||||
ratbag_resolution_is_active(lib_resolution));
|
||||
|
||||
(void) sd_bus_emit_properties_changed(bus,
|
||||
resolution->path,
|
||||
RATBAGD_NAME_ROOT ".Resolution",
|
||||
@@ -111,31 +68,26 @@ static int ratbagd_resolution_set_active(sd_bus_message *m,
|
||||
int r;
|
||||
|
||||
r = ratbag_resolution_set_active(resolution->lib_resolution);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (r < 0) {
|
||||
sd_bus *bus = sd_bus_message_get_bus(m);
|
||||
r = ratbagd_device_resync(resolution->device, bus);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
ratbagd_for_each_resolution_signal(sd_bus_message_get_bus(m),
|
||||
resolution->profile,
|
||||
ratbagd_resolution_active_signal_cb);
|
||||
|
||||
return sd_bus_reply_method_return(m, "u", r);
|
||||
return sd_bus_reply_method_return(m, "u", 0);
|
||||
}
|
||||
|
||||
static int ratbagd_resolution_default_signal_cb(sd_bus *bus,
|
||||
struct ratbagd_resolution *resolution)
|
||||
{
|
||||
struct ratbag_resolution *lib_resolution = resolution->lib_resolution;
|
||||
|
||||
/* FIXME: we should cache is default and only send the signal for
|
||||
* those resolutions where it changed */
|
||||
|
||||
(void) sd_bus_emit_signal(bus,
|
||||
resolution->path,
|
||||
RATBAGD_NAME_ROOT ".Resolution",
|
||||
"IsDefault",
|
||||
"b",
|
||||
ratbag_resolution_is_default(lib_resolution));
|
||||
|
||||
(void) sd_bus_emit_properties_changed(bus,
|
||||
resolution->path,
|
||||
RATBAGD_NAME_ROOT ".Resolution",
|
||||
@@ -153,14 +105,18 @@ static int ratbagd_resolution_set_default(sd_bus_message *m,
|
||||
int r;
|
||||
|
||||
r = ratbag_resolution_set_default(resolution->lib_resolution);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (r < 0) {
|
||||
sd_bus *bus = sd_bus_message_get_bus(m);
|
||||
r = ratbagd_device_resync(resolution->device, bus);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
ratbagd_for_each_resolution_signal(sd_bus_message_get_bus(m),
|
||||
resolution->profile,
|
||||
ratbagd_resolution_default_signal_cb);
|
||||
|
||||
return sd_bus_reply_method_return(m, "u", r);
|
||||
return sd_bus_reply_method_return(m, "u", 0);
|
||||
}
|
||||
|
||||
static int
|
||||
@@ -174,7 +130,7 @@ ratbagd_resolution_get_capabilities(sd_bus *bus,
|
||||
{
|
||||
struct ratbagd_resolution *resolution = userdata;
|
||||
struct ratbag_resolution *lib_resolution = resolution->lib_resolution;
|
||||
enum ratbag_device_capability cap;
|
||||
enum ratbag_resolution_capability cap;
|
||||
int r;
|
||||
|
||||
r = sd_bus_message_open_container(reply, 'a', "u");
|
||||
@@ -234,6 +190,38 @@ ratbagd_resolution_is_default(sd_bus *bus,
|
||||
return sd_bus_message_append(reply, "b", is_default);
|
||||
}
|
||||
|
||||
static int
|
||||
ratbagd_resolution_get_resolutions(sd_bus *bus,
|
||||
const char *path,
|
||||
const char *interface,
|
||||
const char *property,
|
||||
sd_bus_message *reply,
|
||||
void *userdata,
|
||||
sd_bus_error *error)
|
||||
{
|
||||
struct ratbagd_resolution *resolution = userdata;
|
||||
struct ratbag_resolution *lib_resolution = resolution->lib_resolution;
|
||||
unsigned int dpis[300];
|
||||
unsigned int ndpis = ARRAY_LENGTH(dpis);
|
||||
int r;
|
||||
|
||||
r = sd_bus_message_open_container(reply, 'a', "u");
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
ndpis = ratbag_resolution_get_dpi_list(lib_resolution,
|
||||
dpis, ndpis);
|
||||
assert(ndpis <= ARRAY_LENGTH(dpis));
|
||||
|
||||
for (unsigned int i = 0; i < ndpis; i++) {
|
||||
r = sd_bus_message_append(reply, "u", dpis[i]);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
return sd_bus_message_close_container(reply);
|
||||
}
|
||||
|
||||
static int
|
||||
ratbagd_resolution_get_resolution(sd_bus *bus,
|
||||
const char *path,
|
||||
@@ -288,17 +276,17 @@ ratbagd_resolution_set_resolution(sd_bus *bus,
|
||||
NULL);
|
||||
}
|
||||
|
||||
return r;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
ratbagd_resolution_get_rate(sd_bus *bus,
|
||||
const char *path,
|
||||
const char *interface,
|
||||
const char *property,
|
||||
sd_bus_message *reply,
|
||||
void *userdata,
|
||||
sd_bus_error *error)
|
||||
ratbagd_resolution_get_report_rate(sd_bus *bus,
|
||||
const char *path,
|
||||
const char *interface,
|
||||
const char *property,
|
||||
sd_bus_message *reply,
|
||||
void *userdata,
|
||||
sd_bus_error *error)
|
||||
{
|
||||
struct ratbagd_resolution *resolution = userdata;
|
||||
struct ratbag_resolution *lib_resolution = resolution->lib_resolution;
|
||||
@@ -309,37 +297,73 @@ ratbagd_resolution_get_rate(sd_bus *bus,
|
||||
}
|
||||
|
||||
static int
|
||||
ratbagd_resolution_get_minimum(sd_bus *bus,
|
||||
const char *path,
|
||||
const char *interface,
|
||||
const char *property,
|
||||
sd_bus_message *reply,
|
||||
void *userdata,
|
||||
sd_bus_error *error)
|
||||
ratbagd_resolution_get_report_rates(sd_bus *bus,
|
||||
const char *path,
|
||||
const char *interface,
|
||||
const char *property,
|
||||
sd_bus_message *reply,
|
||||
void *userdata,
|
||||
sd_bus_error *error)
|
||||
{
|
||||
struct ratbagd_resolution *resolution = userdata;
|
||||
struct ratbag_resolution *lib_resolution = resolution->lib_resolution;
|
||||
int min;
|
||||
unsigned int rates[5];
|
||||
unsigned int nrates = ARRAY_LENGTH(rates);
|
||||
int r;
|
||||
|
||||
min = ratbag_resolution_get_dpi_minimum(lib_resolution);
|
||||
return sd_bus_message_append(reply, "u", min);
|
||||
r = sd_bus_message_open_container(reply, 'a', "u");
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
nrates = ratbag_resolution_get_report_rate_list(lib_resolution,
|
||||
rates, nrates);
|
||||
assert(nrates <= ARRAY_LENGTH(rates));
|
||||
|
||||
for (unsigned int i = 0; i < nrates; i++) {
|
||||
r = sd_bus_message_append(reply, "u", rates[i]);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
return sd_bus_message_close_container(reply);
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
ratbagd_resolution_get_maximum(sd_bus *bus,
|
||||
const char *path,
|
||||
const char *interface,
|
||||
const char *property,
|
||||
sd_bus_message *reply,
|
||||
void *userdata,
|
||||
sd_bus_error *error)
|
||||
ratbagd_resolution_set_report_rate(sd_bus *bus,
|
||||
const char *path,
|
||||
const char *interface,
|
||||
const char *property,
|
||||
sd_bus_message *m,
|
||||
void *userdata,
|
||||
sd_bus_error *error)
|
||||
{
|
||||
struct ratbagd_resolution *resolution = userdata;
|
||||
struct ratbag_resolution *lib_resolution = resolution->lib_resolution;
|
||||
int max;
|
||||
unsigned int rate;
|
||||
int r;
|
||||
|
||||
max = ratbag_resolution_get_dpi_maximum(lib_resolution);
|
||||
return sd_bus_message_append(reply, "u", max);
|
||||
r = sd_bus_message_read(m, "u", &rate);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
/* basic sanity check */
|
||||
if (rate > 5000)
|
||||
rate = 5000;
|
||||
else if (rate % 100)
|
||||
rate = rate - (rate % 100);
|
||||
|
||||
r = ratbag_resolution_set_report_rate(resolution->lib_resolution,
|
||||
rate);
|
||||
if (r == 0) {
|
||||
sd_bus *bus = sd_bus_message_get_bus(m);
|
||||
sd_bus_emit_properties_changed(bus,
|
||||
resolution->path,
|
||||
RATBAGD_NAME_ROOT ".Resolution",
|
||||
"ReportRate",
|
||||
NULL);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
const sd_bus_vtable ratbagd_resolution_vtable[] = {
|
||||
@@ -352,12 +376,12 @@ const sd_bus_vtable ratbagd_resolution_vtable[] = {
|
||||
ratbagd_resolution_get_resolution,
|
||||
ratbagd_resolution_set_resolution, 0,
|
||||
SD_BUS_VTABLE_UNPRIVILEGED|SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
|
||||
SD_BUS_PROPERTY("Resolutions", "au", ratbagd_resolution_get_resolutions, 0, SD_BUS_VTABLE_PROPERTY_CONST),
|
||||
SD_BUS_WRITABLE_PROPERTY("ReportRate", "u",
|
||||
ratbagd_resolution_get_rate,
|
||||
ratbagd_resolution_get_report_rate,
|
||||
ratbagd_resolution_set_report_rate, 0,
|
||||
SD_BUS_VTABLE_UNPRIVILEGED|SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
|
||||
SD_BUS_PROPERTY("Maximum", "u", ratbagd_resolution_get_maximum, 0, SD_BUS_VTABLE_PROPERTY_CONST),
|
||||
SD_BUS_PROPERTY("Minimum", "u", ratbagd_resolution_get_minimum, 0, SD_BUS_VTABLE_PROPERTY_CONST),
|
||||
SD_BUS_PROPERTY("ReportRates", "au", ratbagd_resolution_get_report_rates, 0, SD_BUS_VTABLE_PROPERTY_CONST),
|
||||
SD_BUS_METHOD("SetActive", "", "u", ratbagd_resolution_set_active, SD_BUS_VTABLE_UNPRIVILEGED),
|
||||
SD_BUS_METHOD("SetDefault", "", "u", ratbagd_resolution_set_default, SD_BUS_VTABLE_UNPRIVILEGED),
|
||||
SD_BUS_VTABLE_END,
|
||||
@@ -381,6 +405,7 @@ int ratbagd_resolution_new(struct ratbagd_resolution **out,
|
||||
if (!resolution)
|
||||
return -ENOMEM;
|
||||
|
||||
resolution->device = device;
|
||||
resolution->profile = profile;
|
||||
resolution->lib_resolution = lib_resolution;
|
||||
resolution->index = index;
|
||||
@@ -389,7 +414,7 @@ int ratbagd_resolution_new(struct ratbagd_resolution **out,
|
||||
sprintf(resolution_buffer, "r%u", index);
|
||||
r = sd_bus_path_encode_many(&resolution->path,
|
||||
RATBAGD_OBJ_ROOT "/resolution/%/%/%",
|
||||
ratbagd_device_get_name(device),
|
||||
ratbagd_device_get_sysname(device),
|
||||
profile_buffer,
|
||||
resolution_buffer);
|
||||
if (r < 0)
|
||||
|
||||
225
ratbagd/ratbagd-test.c
Normal file
@@ -0,0 +1,225 @@
|
||||
/*
|
||||
* Copyright © 2017 Red Hat, Inc.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the next
|
||||
* paragraph) shall be included in all copies or substantial portions of the
|
||||
* Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "ratbagd-test.h"
|
||||
|
||||
#ifdef RATBAG_DEVELOPER_EDITION
|
||||
|
||||
#include <linux/input.h>
|
||||
#include <systemd/sd-bus.h>
|
||||
#include <systemd/sd-event.h>
|
||||
|
||||
#include "libratbag-test.h"
|
||||
|
||||
/* A pre-setup sane device. Use for sanity testing by toggling the various
|
||||
* error conditions.
|
||||
*/
|
||||
static const struct ratbag_test_device ratbagd_test_device_descr = {
|
||||
.num_profiles = 4,
|
||||
.num_resolutions = 3,
|
||||
.num_buttons = 4,
|
||||
.num_leds = 3,
|
||||
.svg = "fallback.svg",
|
||||
.profiles = {
|
||||
{
|
||||
.buttons = {
|
||||
{ .button_type = RATBAG_BUTTON_TYPE_LEFT,
|
||||
.action_type = RATBAG_BUTTON_ACTION_TYPE_BUTTON,
|
||||
.button = 0 },
|
||||
{ .button_type = RATBAG_BUTTON_TYPE_MIDDLE,
|
||||
.action_type = RATBAG_BUTTON_ACTION_TYPE_KEY,
|
||||
.key = KEY_3 },
|
||||
{ .button_type = RATBAG_BUTTON_TYPE_RIGHT,
|
||||
.action_type = RATBAG_BUTTON_ACTION_TYPE_SPECIAL,
|
||||
.special = RATBAG_BUTTON_ACTION_SPECIAL_PROFILE_CYCLE_UP },
|
||||
{ .action_type = RATBAG_BUTTON_ACTION_TYPE_MACRO,
|
||||
.macro = {
|
||||
{ .type = RATBAG_MACRO_EVENT_KEY_PRESSED,
|
||||
.value = KEY_B },
|
||||
{ .type = RATBAG_MACRO_EVENT_KEY_RELEASED,
|
||||
.value = KEY_B },
|
||||
{ .type = RATBAG_MACRO_EVENT_WAIT,
|
||||
.value = 300 },
|
||||
},
|
||||
}
|
||||
},
|
||||
.resolutions = {
|
||||
{ .xres = 100, .yres = 200, .hz = 1000,
|
||||
.dpi_min = 50, .dpi_max = 5000,
|
||||
.report_rates = { 500, 1000 } },
|
||||
{ .xres = 200, .yres = 300, .hz = 1000, .active = true, .dflt = true },
|
||||
{ .xres = 300, .yres = 400, .hz = 1000 },
|
||||
},
|
||||
.active = true,
|
||||
.dflt = false,
|
||||
.leds = {
|
||||
{
|
||||
.mode = RATBAG_LED_OFF,
|
||||
.color = { .red = 255, .green = 0, .blue = 0 },
|
||||
.ms = 1000,
|
||||
.brightness = 20,
|
||||
.type = RATBAG_LED_TYPE_LOGO,
|
||||
},
|
||||
{
|
||||
.mode = RATBAG_LED_ON,
|
||||
.color = { .red = 255, .green = 0, .blue = 0 },
|
||||
.ms = 1000,
|
||||
.brightness = 20,
|
||||
.type = RATBAG_LED_TYPE_SIDE,
|
||||
},
|
||||
{
|
||||
.mode = RATBAG_LED_CYCLE,
|
||||
.color = { .red = 255, .green = 255, .blue = 0 },
|
||||
.ms = 333,
|
||||
.brightness = 40,
|
||||
.type = RATBAG_LED_TYPE_SIDE,
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
.buttons = {
|
||||
{ .action_type = RATBAG_BUTTON_ACTION_TYPE_KEY,
|
||||
.key = 4 },
|
||||
{ .action_type = RATBAG_BUTTON_ACTION_TYPE_KEY,
|
||||
.key = 5 },
|
||||
{ .action_type = RATBAG_BUTTON_ACTION_TYPE_KEY,
|
||||
.key = 6 },
|
||||
{ .action_type = RATBAG_BUTTON_ACTION_TYPE_KEY,
|
||||
.key = 7 },
|
||||
},
|
||||
.resolutions = {
|
||||
{ .xres = 1100, .yres = 1200, .hz = 2000, .caps = RATBAG_RESOLUTION_CAP_SEPARATE_XY_RESOLUTION },
|
||||
{ .xres = 1200, .yres = 1300, .hz = 2000, .dflt = true, .caps = RATBAG_RESOLUTION_CAP_SEPARATE_XY_RESOLUTION },
|
||||
{ .xres = 1300, .yres = 1400, .hz = 2000, .active = true, .caps = RATBAG_RESOLUTION_CAP_SEPARATE_XY_RESOLUTION },
|
||||
},
|
||||
.active = false,
|
||||
.dflt = true,
|
||||
.caps = { RATBAG_PROFILE_CAP_WRITABLE_NAME },
|
||||
},
|
||||
{
|
||||
.buttons = {
|
||||
{ .button_type = RATBAG_BUTTON_TYPE_LEFT,
|
||||
.action_type = RATBAG_BUTTON_ACTION_TYPE_SPECIAL,
|
||||
.special = RATBAG_BUTTON_ACTION_SPECIAL_PROFILE_CYCLE_UP },
|
||||
{ .action_type = RATBAG_BUTTON_ACTION_TYPE_MACRO,
|
||||
.macro = {
|
||||
{ .type = RATBAG_MACRO_EVENT_KEY_PRESSED,
|
||||
.value = KEY_A },
|
||||
{ .type = RATBAG_MACRO_EVENT_KEY_RELEASED,
|
||||
.value = KEY_A },
|
||||
{ .type = RATBAG_MACRO_EVENT_WAIT,
|
||||
.value = 150 },
|
||||
}
|
||||
},
|
||||
{ .action_type = RATBAG_BUTTON_ACTION_TYPE_BUTTON,
|
||||
.button = 2 },
|
||||
{ .action_type = RATBAG_BUTTON_ACTION_TYPE_BUTTON,
|
||||
.button = 3 },
|
||||
},
|
||||
.resolutions = {
|
||||
{ .xres = 2100, .yres = 2200, .hz = 3000, .active = true, .caps = RATBAG_RESOLUTION_CAP_SEPARATE_XY_RESOLUTION },
|
||||
{ .xres = 2200, .yres = 2300, .hz = 3000, .dflt = true, .caps = RATBAG_RESOLUTION_CAP_SEPARATE_XY_RESOLUTION },
|
||||
{ .xres = 2300, .yres = 2400, .hz = 3000, .caps = RATBAG_RESOLUTION_CAP_SEPARATE_XY_RESOLUTION },
|
||||
},
|
||||
.leds = {
|
||||
{
|
||||
.mode = RATBAG_LED_ON,
|
||||
.color = { .red = 255, .green = 0, .blue = 0 },
|
||||
.ms = 1000,
|
||||
.brightness = 20
|
||||
},
|
||||
{
|
||||
.mode = RATBAG_LED_CYCLE,
|
||||
.color = { .red = 255, .green = 255, .blue = 0 },
|
||||
.ms = 333,
|
||||
.brightness = 40
|
||||
}
|
||||
},
|
||||
.active = false,
|
||||
.dflt = false,
|
||||
},
|
||||
{
|
||||
.disabled = true,
|
||||
},
|
||||
},
|
||||
.destroyed = NULL,
|
||||
.destroyed_data = NULL,
|
||||
};
|
||||
|
||||
|
||||
int ratbagd_reset_test_device(sd_bus_message *m,
|
||||
void *userdata,
|
||||
sd_bus_error *error)
|
||||
{
|
||||
static struct ratbagd_device *ratbagd_test_device = NULL;
|
||||
struct ratbagd *ctx = userdata;
|
||||
struct ratbag_device *device;
|
||||
int r;
|
||||
|
||||
if (ratbagd_test_device) {
|
||||
ratbagd_device_unlink(ratbagd_test_device);
|
||||
ratbagd_device_free(ratbagd_test_device);
|
||||
|
||||
(void) sd_bus_emit_properties_changed(ctx->bus,
|
||||
RATBAGD_OBJ_ROOT,
|
||||
RATBAGD_NAME_ROOT ".Manager",
|
||||
"Devices",
|
||||
NULL);
|
||||
}
|
||||
|
||||
device = ratbag_device_new_test_device(ctx->lib_ctx, &ratbagd_test_device_descr);
|
||||
|
||||
r = ratbagd_device_new(&ratbagd_test_device, ctx, "test_device", device);
|
||||
|
||||
/* the ratbagd_device takes its own reference, drop ours */
|
||||
ratbag_device_unref(device);
|
||||
|
||||
if (r < 0) {
|
||||
log_error("Cannot track test device\n");
|
||||
return r;
|
||||
}
|
||||
|
||||
ratbagd_device_link(ratbagd_test_device);
|
||||
if (m) {
|
||||
sd_bus_reply_method_return(m, "u", r);
|
||||
(void) sd_bus_emit_properties_changed(ctx->bus,
|
||||
RATBAGD_OBJ_ROOT,
|
||||
RATBAGD_NAME_ROOT ".Manager",
|
||||
"Devices",
|
||||
NULL);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void ratbagd_init_test_device(struct ratbagd *ctx)
|
||||
{
|
||||
#ifdef RATBAG_DEVELOPER_EDITION
|
||||
setenv("RATBAG_TEST", "1", 0);
|
||||
|
||||
ratbagd_reset_test_device(NULL, ctx, NULL);
|
||||
#endif
|
||||
}
|
||||
|
||||
35
ratbagd/ratbagd-test.h
Normal file
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright © 2017 Red Hat, Inc.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the next
|
||||
* paragraph) shall be included in all copies or substantial portions of the
|
||||
* Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "libratbag-test.h"
|
||||
#include "ratbagd.h"
|
||||
|
||||
void ratbagd_init_test_device(struct ratbagd *ctx);
|
||||
|
||||
#ifdef RATBAG_DEVELOPER_EDITION
|
||||
int ratbagd_reset_test_device(sd_bus_message *m,
|
||||
void *userdata,
|
||||
sd_bus_error *error);
|
||||
#endif /* RATBAG_DEVELOPER_EDITION */
|
||||
@@ -33,13 +33,17 @@
|
||||
#include <libudev.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/resource.h>
|
||||
#include <systemd/sd-bus.h>
|
||||
#include <systemd/sd-event.h>
|
||||
#include "ratbagd.h"
|
||||
#include "shared-macro.h"
|
||||
#include "libratbag-util.h"
|
||||
|
||||
#include "ratbagd-test.h"
|
||||
|
||||
static bool verbose = false;
|
||||
static bool verbose_raw = false;
|
||||
|
||||
static const char *SVG_THEMES[] = {
|
||||
"default",
|
||||
@@ -184,195 +188,6 @@ static int ratbagd_get_themes(sd_bus *bus,
|
||||
return sd_bus_message_close_container(reply);
|
||||
}
|
||||
|
||||
#ifdef RATBAG_DEVELOPER_EDITION
|
||||
|
||||
#include "libratbag-test.h"
|
||||
|
||||
/* A pre-setup sane device. Use for sanity testing by toggling the various
|
||||
* error conditions.
|
||||
*/
|
||||
static const struct ratbag_test_device ratbagd_test_device_descr = {
|
||||
.num_profiles = 4,
|
||||
.num_resolutions = 3,
|
||||
.num_buttons = 4,
|
||||
.num_leds = 3,
|
||||
.svg = "logitech-g500.svg",
|
||||
.profiles = {
|
||||
{
|
||||
.buttons = {
|
||||
{ .button_type = RATBAG_BUTTON_TYPE_LEFT,
|
||||
.action_type = RATBAG_BUTTON_ACTION_TYPE_BUTTON,
|
||||
.button = 0 },
|
||||
{ .button_type = RATBAG_BUTTON_TYPE_MIDDLE,
|
||||
.action_type = RATBAG_BUTTON_ACTION_TYPE_KEY,
|
||||
.key = KEY_3 },
|
||||
{ .button_type = RATBAG_BUTTON_TYPE_RIGHT,
|
||||
.action_type = RATBAG_BUTTON_ACTION_TYPE_SPECIAL,
|
||||
.special = RATBAG_BUTTON_ACTION_SPECIAL_PROFILE_CYCLE_UP },
|
||||
{ .action_type = RATBAG_BUTTON_ACTION_TYPE_MACRO,
|
||||
.macro = {
|
||||
{ .type = RATBAG_MACRO_EVENT_KEY_PRESSED,
|
||||
.value = KEY_B },
|
||||
{ .type = RATBAG_MACRO_EVENT_KEY_RELEASED,
|
||||
.value = KEY_B },
|
||||
{ .type = RATBAG_MACRO_EVENT_WAIT,
|
||||
.value = 300 },
|
||||
},
|
||||
}
|
||||
},
|
||||
.resolutions = {
|
||||
{ .xres = 100, .yres = 200, .hz = 1000 },
|
||||
{ .xres = 200, .yres = 300, .hz = 1000, .active = true, .dflt = true },
|
||||
{ .xres = 300, .yres = 400, .hz = 1000 },
|
||||
},
|
||||
.active = true,
|
||||
.dflt = false,
|
||||
.leds = {
|
||||
{
|
||||
.mode = RATBAG_LED_OFF,
|
||||
.color = { .red = 255, .green = 0, .blue = 0 },
|
||||
.hz = 1,
|
||||
.brightness = 20
|
||||
},
|
||||
{
|
||||
.mode = RATBAG_LED_ON,
|
||||
.color = { .red = 255, .green = 0, .blue = 0 },
|
||||
.hz = 1,
|
||||
.brightness = 20
|
||||
},
|
||||
{
|
||||
.mode = RATBAG_LED_CYCLE,
|
||||
.color = { .red = 255, .green = 255, .blue = 0 },
|
||||
.hz = 3,
|
||||
.brightness = 40
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
.buttons = {
|
||||
{ .action_type = RATBAG_BUTTON_ACTION_TYPE_KEY,
|
||||
.key = 4 },
|
||||
{ .action_type = RATBAG_BUTTON_ACTION_TYPE_KEY,
|
||||
.key = 5 },
|
||||
{ .action_type = RATBAG_BUTTON_ACTION_TYPE_KEY,
|
||||
.key = 6 },
|
||||
{ .action_type = RATBAG_BUTTON_ACTION_TYPE_KEY,
|
||||
.key = 7 },
|
||||
},
|
||||
.resolutions = {
|
||||
{ .xres = 1100, .yres = 1200, .hz = 2000, .caps = RATBAG_RESOLUTION_CAP_SEPARATE_XY_RESOLUTION },
|
||||
{ .xres = 1200, .yres = 1300, .hz = 2000, .dflt = true, .caps = RATBAG_RESOLUTION_CAP_SEPARATE_XY_RESOLUTION },
|
||||
{ .xres = 1300, .yres = 1400, .hz = 2000, .active = true, .caps = RATBAG_RESOLUTION_CAP_SEPARATE_XY_RESOLUTION },
|
||||
},
|
||||
.active = false,
|
||||
.dflt = true,
|
||||
},
|
||||
{
|
||||
.buttons = {
|
||||
{ .button_type = RATBAG_BUTTON_TYPE_LEFT,
|
||||
.action_type = RATBAG_BUTTON_ACTION_TYPE_SPECIAL,
|
||||
.special = RATBAG_BUTTON_ACTION_SPECIAL_PROFILE_CYCLE_UP },
|
||||
{ .action_type = RATBAG_BUTTON_ACTION_TYPE_MACRO,
|
||||
.macro = {
|
||||
{ .type = RATBAG_MACRO_EVENT_KEY_PRESSED,
|
||||
.value = KEY_A },
|
||||
{ .type = RATBAG_MACRO_EVENT_KEY_RELEASED,
|
||||
.value = KEY_A },
|
||||
{ .type = RATBAG_MACRO_EVENT_WAIT,
|
||||
.value = 150 },
|
||||
}
|
||||
},
|
||||
{ .action_type = RATBAG_BUTTON_ACTION_TYPE_BUTTON,
|
||||
.button = 2 },
|
||||
{ .action_type = RATBAG_BUTTON_ACTION_TYPE_BUTTON,
|
||||
.button = 3 },
|
||||
},
|
||||
.resolutions = {
|
||||
{ .xres = 2100, .yres = 2200, .hz = 3000, .active = true, .caps = RATBAG_RESOLUTION_CAP_SEPARATE_XY_RESOLUTION },
|
||||
{ .xres = 2200, .yres = 2300, .hz = 3000, .dflt = true, .caps = RATBAG_RESOLUTION_CAP_SEPARATE_XY_RESOLUTION },
|
||||
{ .xres = 2300, .yres = 2400, .hz = 3000, .caps = RATBAG_RESOLUTION_CAP_SEPARATE_XY_RESOLUTION },
|
||||
},
|
||||
.leds = {
|
||||
{
|
||||
.mode = RATBAG_LED_ON,
|
||||
.color = { .red = 255, .green = 0, .blue = 0 },
|
||||
.hz = 1,
|
||||
.brightness = 20
|
||||
},
|
||||
{
|
||||
.mode = RATBAG_LED_CYCLE,
|
||||
.color = { .red = 255, .green = 255, .blue = 0 },
|
||||
.hz = 3,
|
||||
.brightness = 40
|
||||
}
|
||||
},
|
||||
.active = false,
|
||||
.dflt = false,
|
||||
},
|
||||
{
|
||||
.disabled = true,
|
||||
},
|
||||
},
|
||||
.destroyed = NULL,
|
||||
.destroyed_data = NULL,
|
||||
};
|
||||
|
||||
static int ratbagd_reset_test_device(sd_bus_message *m,
|
||||
void *userdata,
|
||||
sd_bus_error *error)
|
||||
{
|
||||
static struct ratbagd_device *ratbagd_test_device = NULL;
|
||||
struct ratbagd *ctx = userdata;
|
||||
struct ratbag_device *device;
|
||||
int r;
|
||||
|
||||
if (ratbagd_test_device) {
|
||||
ratbagd_device_unlink(ratbagd_test_device);
|
||||
ratbagd_device_free(ratbagd_test_device);
|
||||
|
||||
(void) sd_bus_emit_properties_changed(ctx->bus,
|
||||
RATBAGD_OBJ_ROOT,
|
||||
RATBAGD_NAME_ROOT ".Manager",
|
||||
"Devices",
|
||||
NULL);
|
||||
}
|
||||
|
||||
device = ratbag_device_new_test_device(ctx->lib_ctx, &ratbagd_test_device_descr);
|
||||
|
||||
r = ratbagd_device_new(&ratbagd_test_device, ctx, "test_device", device);
|
||||
|
||||
/* the ratbagd_device takes its own reference, drop ours */
|
||||
ratbag_device_unref(device);
|
||||
|
||||
if (r < 0) {
|
||||
log_error("Cannot track test device\n");
|
||||
return r;
|
||||
}
|
||||
|
||||
ratbagd_device_link(ratbagd_test_device);
|
||||
if (m) {
|
||||
sd_bus_reply_method_return(m, "u", r);
|
||||
(void) sd_bus_emit_properties_changed(ctx->bus,
|
||||
RATBAGD_OBJ_ROOT,
|
||||
RATBAGD_NAME_ROOT ".Manager",
|
||||
"Devices",
|
||||
NULL);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ratbagd_init_test_device(struct ratbagd *ctx)
|
||||
{
|
||||
setenv("RATBAG_TEST", "1", 0);
|
||||
|
||||
ratbagd_reset_test_device(NULL, ctx, NULL);
|
||||
}
|
||||
|
||||
#else /* RATBAG_DEVELOPER_EDITION */
|
||||
static inline void ratbagd_init_test_device(struct ratbagd *ctx) {}
|
||||
#endif /* RATBAG_DEVELOPER_EDITION */
|
||||
|
||||
static const sd_bus_vtable ratbagd_vtable[] = {
|
||||
SD_BUS_VTABLE_START(0),
|
||||
SD_BUS_PROPERTY("Devices", "ao", ratbagd_get_devices, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
|
||||
@@ -436,7 +251,7 @@ static void ratbagd_process_device(struct ratbagd *ctx,
|
||||
ratbag_device_unref(lib_device);
|
||||
|
||||
if (r < 0) {
|
||||
log_error("Cannot track device '%s'\n", name);
|
||||
log_error("%s: cannot track device\n", name);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -486,13 +301,15 @@ static const struct ratbag_interface ratbagd_lib_interface = {
|
||||
|
||||
static struct ratbagd *ratbagd_free(struct ratbagd *ctx)
|
||||
{
|
||||
struct ratbagd_device *device;
|
||||
struct ratbagd_device *device, *tmp;
|
||||
|
||||
if (!ctx)
|
||||
return NULL;
|
||||
|
||||
RATBAGD_DEVICE_FOREACH(device, ctx)
|
||||
RATBAGD_DEVICE_FOREACH_SAFE(device, tmp, ctx) {
|
||||
ratbagd_device_unlink(device);
|
||||
ratbagd_device_free(device);
|
||||
}
|
||||
|
||||
ctx->bus = sd_bus_flush_close_unref(ctx->bus);
|
||||
ctx->monitor_source = sd_event_source_unref(ctx->monitor_source);
|
||||
@@ -567,7 +384,10 @@ static int ratbagd_new(struct ratbagd **out)
|
||||
if (!ctx->lib_ctx)
|
||||
return -ENOMEM;
|
||||
|
||||
if (verbose)
|
||||
if (verbose_raw)
|
||||
ratbag_log_set_priority(ctx->lib_ctx,
|
||||
RATBAG_LOG_PRIORITY_RAW);
|
||||
else if (verbose)
|
||||
ratbag_log_set_priority(ctx->lib_ctx,
|
||||
RATBAG_LOG_PRIORITY_DEBUG);
|
||||
|
||||
@@ -706,11 +526,19 @@ int main(int argc, char *argv[])
|
||||
struct ratbagd *ctx = NULL;
|
||||
int r;
|
||||
|
||||
#if DISABLE_COREDUMP
|
||||
const struct rlimit corelimit = { 0, 0 };
|
||||
|
||||
setrlimit(RLIMIT_CORE, &corelimit);
|
||||
#endif
|
||||
|
||||
if (argc > 1) {
|
||||
if (streq(argv[1], "--verbose")) {
|
||||
if (streq(argv[1], "--verbose=raw")) {
|
||||
verbose_raw = true;
|
||||
} else if (streq(argv[1], "--verbose")) {
|
||||
verbose = true;
|
||||
} else {
|
||||
fprintf(stderr, "Usage: %s [--verbose]\n",
|
||||
fprintf(stderr, "Usage: %s [--verbose[=raw]]\n",
|
||||
program_invocation_short_name);
|
||||
r = -EINVAL;
|
||||
goto exit;
|
||||
|
||||
@@ -148,10 +148,11 @@ int ratbagd_device_new(struct ratbagd_device **out,
|
||||
const char *name,
|
||||
struct ratbag_device *lib_device);
|
||||
struct ratbagd_device *ratbagd_device_free(struct ratbagd_device *device);
|
||||
const char *ratbagd_device_get_name(struct ratbagd_device *device);
|
||||
const char *ratbagd_device_get_sysname(struct ratbagd_device *device);
|
||||
const char *ratbagd_device_get_path(struct ratbagd_device *device);
|
||||
unsigned int ratbagd_device_get_num_buttons(struct ratbagd_device *device);
|
||||
unsigned int ratbagd_device_get_num_leds(struct ratbagd_device *device);
|
||||
int ratbagd_device_resync(struct ratbagd_device *device, sd_bus *bus);
|
||||
|
||||
bool ratbagd_device_linked(struct ratbagd_device *device);
|
||||
void ratbagd_device_link(struct ratbagd_device *device);
|
||||
@@ -169,6 +170,12 @@ struct ratbagd_device *ratbagd_device_next(struct ratbagd_device *device);
|
||||
(_device); \
|
||||
(_device) = ratbagd_device_next(_device))
|
||||
|
||||
#define RATBAGD_DEVICE_FOREACH_SAFE(_device, _safe, _ctx) \
|
||||
for (_device = ratbagd_device_first(_ctx), \
|
||||
_safe = (_device) ? ratbagd_device_next(_device) : NULL; \
|
||||
(_device); \
|
||||
_device = (_safe), \
|
||||
_safe = (_safe) ? ratbagd_device_next(_safe) : NULL)
|
||||
/*
|
||||
* Context
|
||||
*/
|
||||
|
||||
@@ -324,78 +324,6 @@ etekcity_button_to_action(struct ratbag_profile *profile,
|
||||
return etekcity_raw_to_button_action(data);
|
||||
}
|
||||
|
||||
static void
|
||||
etekcity_read_profile(struct ratbag_profile *profile, unsigned int index)
|
||||
{
|
||||
struct ratbag_device *device = profile->device;
|
||||
struct etekcity_data *drv_data;
|
||||
struct ratbag_resolution *resolution;
|
||||
struct etekcity_settings_report *setting_report;
|
||||
uint8_t *buf;
|
||||
unsigned int report_rate;
|
||||
unsigned int i;
|
||||
int dpi_x, dpi_y, hz;
|
||||
int rc;
|
||||
|
||||
assert(index <= ETEKCITY_PROFILE_MAX);
|
||||
|
||||
drv_data = ratbag_get_drv_data(device);
|
||||
|
||||
setting_report = &drv_data->settings[index];
|
||||
buf = (uint8_t*)setting_report;
|
||||
etekcity_set_config_profile(device, index, ETEKCITY_CONFIG_SETTINGS);
|
||||
rc = ratbag_hidraw_raw_request(device, ETEKCITY_REPORT_ID_SETTINGS,
|
||||
buf, ETEKCITY_REPORT_SIZE_SETTINGS,
|
||||
HID_FEATURE_REPORT, HID_REQ_GET_REPORT);
|
||||
|
||||
if (rc < ETEKCITY_REPORT_SIZE_SETTINGS)
|
||||
return;
|
||||
|
||||
/* first retrieve the report rate, it is set per profile */
|
||||
switch (setting_report->report_rate) {
|
||||
case 0x00: report_rate = 125; break;
|
||||
case 0x01: report_rate = 250; break;
|
||||
case 0x02: report_rate = 500; break;
|
||||
case 0x03: report_rate = 1000; break;
|
||||
default:
|
||||
log_error(device->ratbag,
|
||||
"error while reading the report rate of the mouse (0x%02x)\n",
|
||||
buf[26]);
|
||||
report_rate = 0;
|
||||
}
|
||||
|
||||
for (i = 0; i < profile->resolution.num_modes; i++) {
|
||||
dpi_x = setting_report->xres[i] * 50;
|
||||
dpi_y = setting_report->yres[i] * 50;
|
||||
hz = report_rate;
|
||||
if (!(setting_report->dpi_mask & (1 << i))) {
|
||||
/* the profile is disabled, overwrite it */
|
||||
dpi_x = 0;
|
||||
dpi_y = 0;
|
||||
hz = 0;
|
||||
}
|
||||
resolution = ratbag_resolution_init(profile, i, dpi_x, dpi_y, hz);
|
||||
ratbag_resolution_set_cap(resolution,
|
||||
RATBAG_RESOLUTION_CAP_SEPARATE_XY_RESOLUTION);
|
||||
resolution->is_active = (i == setting_report->current_dpi);
|
||||
}
|
||||
|
||||
buf = drv_data->profiles[index];
|
||||
etekcity_set_config_profile(device, index, ETEKCITY_CONFIG_KEY_MAPPING);
|
||||
rc = ratbag_hidraw_raw_request(device, ETEKCITY_REPORT_ID_KEY_MAPPING,
|
||||
buf, ETEKCITY_REPORT_SIZE_PROFILE,
|
||||
HID_FEATURE_REPORT, HID_REQ_GET_REPORT);
|
||||
|
||||
msleep(10);
|
||||
|
||||
if (rc < ETEKCITY_REPORT_SIZE_PROFILE)
|
||||
return;
|
||||
|
||||
log_raw(device->ratbag, "profile: %d %s:%d\n",
|
||||
buf[2],
|
||||
__FILE__, __LINE__);
|
||||
}
|
||||
|
||||
static int
|
||||
etekcity_write_profile(struct ratbag_profile *profile)
|
||||
{
|
||||
@@ -440,7 +368,7 @@ etekcity_read_button(struct ratbag_button *button)
|
||||
|
||||
action = etekcity_button_to_action(button->profile, button->index);
|
||||
if (action)
|
||||
button->action = *action;
|
||||
ratbag_button_set_action(button, action);
|
||||
button->type = etekcity_raw_to_button_type(button->index);
|
||||
|
||||
ratbag_button_enable_action_type(button, RATBAG_BUTTON_ACTION_TYPE_BUTTON);
|
||||
@@ -490,6 +418,83 @@ etekcity_read_button(struct ratbag_button *button)
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
etekcity_read_profile(struct ratbag_profile *profile)
|
||||
{
|
||||
struct ratbag_device *device = profile->device;
|
||||
struct etekcity_data *drv_data;
|
||||
struct ratbag_resolution *resolution;
|
||||
struct ratbag_button *button;
|
||||
struct etekcity_settings_report *setting_report;
|
||||
uint8_t *buf;
|
||||
unsigned int report_rate;
|
||||
int dpi_x, dpi_y, hz;
|
||||
int rc;
|
||||
unsigned int report_rates[] = { 125, 250, 500, 1000 };
|
||||
|
||||
assert(profile->index <= ETEKCITY_PROFILE_MAX);
|
||||
|
||||
drv_data = ratbag_get_drv_data(device);
|
||||
|
||||
setting_report = &drv_data->settings[profile->index];
|
||||
buf = (uint8_t*)setting_report;
|
||||
etekcity_set_config_profile(device, profile->index, ETEKCITY_CONFIG_SETTINGS);
|
||||
rc = ratbag_hidraw_raw_request(device, ETEKCITY_REPORT_ID_SETTINGS,
|
||||
buf, ETEKCITY_REPORT_SIZE_SETTINGS,
|
||||
HID_FEATURE_REPORT, HID_REQ_GET_REPORT);
|
||||
|
||||
if (rc < ETEKCITY_REPORT_SIZE_SETTINGS)
|
||||
return;
|
||||
|
||||
/* first retrieve the report rate, it is set per profile */
|
||||
if (setting_report->report_rate < ARRAY_LENGTH(report_rates)) {
|
||||
report_rate = report_rates[setting_report->report_rate];
|
||||
} else {
|
||||
log_error(device->ratbag,
|
||||
"error while reading the report rate of the mouse (0x%02x)\n",
|
||||
buf[26]);
|
||||
report_rate = 0;
|
||||
}
|
||||
|
||||
ratbag_profile_for_each_resolution(profile, resolution) {
|
||||
dpi_x = setting_report->xres[resolution->index] * 50;
|
||||
dpi_y = setting_report->yres[resolution->index] * 50;
|
||||
hz = report_rate;
|
||||
if (!(setting_report->dpi_mask & (1 << resolution->index))) {
|
||||
/* the profile is disabled, overwrite it */
|
||||
dpi_x = 0;
|
||||
dpi_y = 0;
|
||||
hz = 0;
|
||||
}
|
||||
|
||||
ratbag_resolution_set_resolution(resolution, dpi_x, dpi_y, hz);
|
||||
ratbag_resolution_set_cap(resolution,
|
||||
RATBAG_RESOLUTION_CAP_SEPARATE_XY_RESOLUTION);
|
||||
resolution->is_active = (resolution->index == setting_report->current_dpi);
|
||||
|
||||
ratbag_resolution_set_report_rate_list(resolution, report_rates,
|
||||
ARRAY_LENGTH(report_rates));
|
||||
}
|
||||
|
||||
ratbag_profile_for_each_button(profile, button)
|
||||
etekcity_read_button(button);
|
||||
|
||||
buf = drv_data->profiles[profile->index];
|
||||
etekcity_set_config_profile(device, profile->index, ETEKCITY_CONFIG_KEY_MAPPING);
|
||||
rc = ratbag_hidraw_raw_request(device, ETEKCITY_REPORT_ID_KEY_MAPPING,
|
||||
buf, ETEKCITY_REPORT_SIZE_PROFILE,
|
||||
HID_FEATURE_REPORT, HID_REQ_GET_REPORT);
|
||||
|
||||
msleep(10);
|
||||
|
||||
if (rc < ETEKCITY_REPORT_SIZE_PROFILE)
|
||||
return;
|
||||
|
||||
log_raw(device->ratbag, "profile: %d %s:%d\n",
|
||||
buf[2],
|
||||
__FILE__, __LINE__);
|
||||
}
|
||||
|
||||
static int
|
||||
etekcity_write_macro(struct ratbag_button *button,
|
||||
const struct ratbag_button_action *action)
|
||||
@@ -594,7 +599,6 @@ etekcity_write_resolution_dpi(struct ratbag_resolution *resolution,
|
||||
struct ratbag_device *device = profile->device;
|
||||
struct etekcity_data *drv_data = ratbag_get_drv_data(device);
|
||||
struct etekcity_settings_report *settings_report;
|
||||
unsigned int index;
|
||||
uint8_t *buf;
|
||||
int rc;
|
||||
|
||||
@@ -605,13 +609,10 @@ etekcity_write_resolution_dpi(struct ratbag_resolution *resolution,
|
||||
|
||||
settings_report = &drv_data->settings[profile->index];
|
||||
|
||||
/* retrieve which resolution is asked to be changed */
|
||||
index = resolution - profile->resolution.modes;
|
||||
|
||||
settings_report->x_sensitivity = 0x0a;
|
||||
settings_report->y_sensitivity = 0x0a;
|
||||
settings_report->xres[index] = dpi_x / 50;
|
||||
settings_report->yres[index] = dpi_y / 50;
|
||||
settings_report->xres[resolution->index] = dpi_x / 50;
|
||||
settings_report->yres[resolution->index] = dpi_y / 50;
|
||||
|
||||
buf = (uint8_t*)settings_report;
|
||||
etekcity_set_config_profile(device, profile->index, ETEKCITY_CONFIG_SETTINGS);
|
||||
@@ -664,6 +665,9 @@ etekcity_probe(struct ratbag_device *device)
|
||||
ETEKCITY_BUTTON_MAX + 1,
|
||||
ETEKCITY_LED);
|
||||
|
||||
ratbag_device_for_each_profile(device, profile)
|
||||
etekcity_read_profile(profile);
|
||||
|
||||
ratbag_device_set_capability(device, RATBAG_DEVICE_CAP_BUTTON);
|
||||
ratbag_device_set_capability(device, RATBAG_DEVICE_CAP_BUTTON_MACROS);
|
||||
|
||||
@@ -709,10 +713,8 @@ struct ratbag_driver etekcity_driver = {
|
||||
.id = "etekcity",
|
||||
.probe = etekcity_probe,
|
||||
.remove = etekcity_remove,
|
||||
.read_profile = etekcity_read_profile,
|
||||
.write_profile = etekcity_write_profile,
|
||||
.set_active_profile = etekcity_set_current_profile,
|
||||
.read_button = etekcity_read_button,
|
||||
.write_button = etekcity_write_button,
|
||||
.write_resolution_dpi = etekcity_write_resolution_dpi,
|
||||
};
|
||||
|
||||
@@ -973,72 +973,11 @@ gskill_write_button_macro(struct ratbag_device *device,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
gskill_probe(struct ratbag_device *device)
|
||||
{
|
||||
struct gskill_data *drv_data = NULL;
|
||||
struct ratbag_profile *profile;
|
||||
unsigned int active_idx;
|
||||
int ret;
|
||||
|
||||
ret = ratbag_open_hidraw(device);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
drv_data = zalloc(sizeof(*drv_data));
|
||||
ratbag_set_drv_data(device, drv_data);
|
||||
|
||||
ret = gskill_get_firmware_version(device);
|
||||
if (ret < 0)
|
||||
goto err;
|
||||
|
||||
log_debug(device->ratbag,
|
||||
"Firmware version: %d\n", ret);
|
||||
|
||||
ret = gskill_get_profile_count(device);
|
||||
if (ret < 0)
|
||||
goto err;
|
||||
drv_data->profile_count = ret;
|
||||
|
||||
ratbag_device_init_profiles(device, GSKILL_PROFILE_MAX, GSKILL_NUM_DPI,
|
||||
GSKILL_BUTTON_MAX, GSKILL_NUM_LED);
|
||||
|
||||
ratbag_device_set_capability(device, RATBAG_DEVICE_CAP_QUERY_CONFIGURATION);
|
||||
ratbag_device_set_capability(device, RATBAG_DEVICE_CAP_BUTTON);
|
||||
ratbag_device_set_capability(device, RATBAG_DEVICE_CAP_BUTTON_KEY);
|
||||
ratbag_device_set_capability(device, RATBAG_DEVICE_CAP_BUTTON_MACROS);
|
||||
ratbag_device_set_capability(device, RATBAG_DEVICE_CAP_DISABLE_PROFILE);
|
||||
|
||||
ret = gskill_get_active_profile_idx(device);
|
||||
if (ret < 0)
|
||||
goto err;
|
||||
|
||||
active_idx = ret;
|
||||
list_for_each(profile, &device->profiles, link) {
|
||||
if (profile->index == active_idx) {
|
||||
profile->is_active = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err:
|
||||
if (drv_data) {
|
||||
ratbag_set_drv_data(device, NULL);
|
||||
free(drv_data);
|
||||
}
|
||||
|
||||
ratbag_close_hidraw(device);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void
|
||||
gskill_read_resolutions(struct ratbag_profile *profile,
|
||||
struct gskill_profile_report *report)
|
||||
{
|
||||
struct gskill_profile_data *pdata = profile_to_pdata(profile);
|
||||
struct ratbag_resolution *resolution;
|
||||
int dpi_x, dpi_y, hz, i;
|
||||
|
||||
log_debug(profile->device->ratbag,
|
||||
@@ -1048,16 +987,24 @@ gskill_read_resolutions(struct ratbag_profile *profile,
|
||||
hz = GSKILL_MAX_POLLING_RATE / (report->polling_rate + 1);
|
||||
|
||||
for (i = 0; i < report->dpi_num; i++) {
|
||||
_cleanup_resolution_ struct ratbag_resolution *resolution;
|
||||
unsigned int rates[] = { 500, 1000 }; /* let's assume that is true */
|
||||
|
||||
dpi_x = report->dpi_levels[i].x * GSKILL_DPI_UNIT;
|
||||
dpi_y = report->dpi_levels[i].y * GSKILL_DPI_UNIT;
|
||||
|
||||
resolution = ratbag_resolution_init(profile, i, dpi_x, dpi_y,
|
||||
hz);
|
||||
resolution = ratbag_profile_get_resolution(profile, i);
|
||||
ratbag_resolution_set_resolution(resolution, dpi_x, dpi_y, hz);
|
||||
resolution->is_active = (i == report->current_dpi_level);
|
||||
pdata->res_idx_to_dev_idx[i] = i;
|
||||
|
||||
ratbag_resolution_set_cap(resolution,
|
||||
RATBAG_RESOLUTION_CAP_SEPARATE_XY_RESOLUTION);
|
||||
|
||||
ratbag_resolution_set_dpi_list_from_range(resolution,
|
||||
GSKILL_MIN_DPI, GSKILL_MAX_DPI);
|
||||
ratbag_resolution_set_report_rate_list(resolution, rates,
|
||||
ARRAY_LENGTH(rates));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1083,7 +1030,7 @@ gskill_read_profile_name(struct ratbag_device *device,
|
||||
}
|
||||
|
||||
static void
|
||||
gskill_read_profile(struct ratbag_profile *profile, unsigned int index)
|
||||
gskill_read_profile(struct ratbag_profile *profile)
|
||||
{
|
||||
struct ratbag_device *device = profile->device;
|
||||
struct gskill_data *drv_data = ratbag_get_drv_data(device);
|
||||
@@ -1092,7 +1039,7 @@ gskill_read_profile(struct ratbag_profile *profile, unsigned int index)
|
||||
uint8_t checksum;
|
||||
int rc, retries;
|
||||
|
||||
if (index >= drv_data->profile_count) {
|
||||
if (profile->index >= drv_data->profile_count) {
|
||||
profile->is_enabled = false;
|
||||
return;
|
||||
}
|
||||
@@ -1106,7 +1053,7 @@ gskill_read_profile(struct ratbag_profile *profile, unsigned int index)
|
||||
* mouse we're doing something wrong.
|
||||
*/
|
||||
for (retries = 0; retries < 3; retries++) {
|
||||
rc = gskill_select_profile(device, index, false);
|
||||
rc = gskill_select_profile(device, profile->index, false);
|
||||
if (rc < 0)
|
||||
return;
|
||||
|
||||
@@ -1124,12 +1071,11 @@ gskill_read_profile(struct ratbag_profile *profile, unsigned int index)
|
||||
return;
|
||||
}
|
||||
|
||||
if (report->profile_num == index)
|
||||
if (report->profile_num == profile->index)
|
||||
break;
|
||||
|
||||
log_debug(device->ratbag,
|
||||
"Mouse send wrong profile %d instead of %d, retrying...\n",
|
||||
profile->index, index);
|
||||
"Mouse send wrong profile, retrying...\n");
|
||||
}
|
||||
|
||||
checksum = gskill_calculate_checksum((uint8_t*)report, sizeof(*report));
|
||||
@@ -1162,10 +1108,11 @@ gskill_update_resolutions(struct ratbag_profile *profile)
|
||||
* lost on exit
|
||||
*/
|
||||
for (i = 0; i < GSKILL_NUM_DPI; i++) {
|
||||
struct ratbag_resolution *res = &profile->resolution.modes[i];
|
||||
_cleanup_resolution_ struct ratbag_resolution *res;
|
||||
struct gskill_raw_dpi_level *level =
|
||||
&report->dpi_levels[report->dpi_num];
|
||||
|
||||
res = ratbag_profile_get_resolution(profile, i);
|
||||
if (!res->dpi_x || !res->dpi_y)
|
||||
continue;
|
||||
|
||||
@@ -1173,8 +1120,8 @@ gskill_update_resolutions(struct ratbag_profile *profile)
|
||||
level->y = res->dpi_y / GSKILL_DPI_UNIT;
|
||||
pdata->res_idx_to_dev_idx[i] = report->dpi_num;
|
||||
|
||||
log_debug(device->ratbag, "Profile %d res %ld mapped to %d\n",
|
||||
profile->index, res - profile->resolution.modes,
|
||||
log_debug(device->ratbag, "Profile %d res %d mapped to %d\n",
|
||||
profile->index, res->index,
|
||||
report->dpi_num);
|
||||
|
||||
report->dpi_num++;
|
||||
@@ -1429,6 +1376,73 @@ gskill_update_profile(struct ratbag_profile *profile)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
gskill_probe(struct ratbag_device *device)
|
||||
{
|
||||
struct gskill_data *drv_data = NULL;
|
||||
struct ratbag_profile *profile;
|
||||
unsigned int active_idx;
|
||||
int ret;
|
||||
|
||||
ret = ratbag_open_hidraw(device);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
drv_data = zalloc(sizeof(*drv_data));
|
||||
ratbag_set_drv_data(device, drv_data);
|
||||
|
||||
ret = gskill_get_firmware_version(device);
|
||||
if (ret < 0)
|
||||
goto err;
|
||||
|
||||
log_debug(device->ratbag,
|
||||
"Firmware version: %d\n", ret);
|
||||
|
||||
ret = gskill_get_profile_count(device);
|
||||
if (ret < 0)
|
||||
goto err;
|
||||
drv_data->profile_count = ret;
|
||||
|
||||
ratbag_device_init_profiles(device, GSKILL_PROFILE_MAX, GSKILL_NUM_DPI,
|
||||
GSKILL_BUTTON_MAX, GSKILL_NUM_LED);
|
||||
|
||||
ratbag_device_set_capability(device, RATBAG_DEVICE_CAP_QUERY_CONFIGURATION);
|
||||
ratbag_device_set_capability(device, RATBAG_DEVICE_CAP_BUTTON);
|
||||
ratbag_device_set_capability(device, RATBAG_DEVICE_CAP_BUTTON_KEY);
|
||||
ratbag_device_set_capability(device, RATBAG_DEVICE_CAP_BUTTON_MACROS);
|
||||
ratbag_device_set_capability(device, RATBAG_DEVICE_CAP_DISABLE_PROFILE);
|
||||
|
||||
ret = gskill_get_active_profile_idx(device);
|
||||
if (ret < 0)
|
||||
goto err;
|
||||
|
||||
active_idx = ret;
|
||||
ratbag_device_for_each_profile(device, profile) {
|
||||
struct ratbag_button *button;
|
||||
|
||||
gskill_read_profile(profile);
|
||||
|
||||
ratbag_profile_for_each_button(profile, button)
|
||||
gskill_read_button(button);
|
||||
|
||||
if (profile->index == active_idx) {
|
||||
profile->is_active = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err:
|
||||
if (drv_data) {
|
||||
ratbag_set_drv_data(device, NULL);
|
||||
free(drv_data);
|
||||
}
|
||||
|
||||
ratbag_close_hidraw(device);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
gskill_commit(struct ratbag_device *device)
|
||||
{
|
||||
@@ -1506,8 +1520,6 @@ struct ratbag_driver gskill_driver = {
|
||||
.id = "gskill",
|
||||
.probe = gskill_probe,
|
||||
.remove = gskill_remove,
|
||||
.read_profile = gskill_read_profile,
|
||||
.commit = gskill_commit,
|
||||
.set_active_profile = gskill_set_active_profile,
|
||||
.read_button = gskill_read_button,
|
||||
};
|
||||
|
||||
@@ -47,6 +47,7 @@
|
||||
|
||||
#include "libratbag-private.h"
|
||||
#include "libratbag-hidraw.h"
|
||||
#include "libratbag-data.h"
|
||||
|
||||
struct hidpp10drv_data {
|
||||
struct hidpp10_device *dev;
|
||||
@@ -336,6 +337,43 @@ hidpp10drv_write_button(struct hidpp10_profile *profile,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
hidpp10drv_read_led(struct ratbag_led *led)
|
||||
{
|
||||
struct ratbag_device *device = led->profile->device;
|
||||
struct hidpp10drv_data *drv_data = ratbag_get_drv_data(device);
|
||||
struct hidpp10_device *hidpp10 = drv_data->dev;
|
||||
struct hidpp10_profile profile;
|
||||
int ret;
|
||||
|
||||
ret = hidpp10_get_profile(hidpp10, led->profile->index, &profile);
|
||||
if (ret)
|
||||
return;
|
||||
|
||||
switch (hidpp10->profile_type) {
|
||||
case HIDPP10_PROFILE_G500:
|
||||
led->colordepth = RATBAG_LED_COLORDEPTH_RGB_888;
|
||||
break;
|
||||
default:
|
||||
led->colordepth = RATBAG_LED_COLORDEPTH_MONOCHROME;
|
||||
break;
|
||||
}
|
||||
|
||||
led->mode = RATBAG_LED_ON;
|
||||
led->color.red = profile.red;
|
||||
led->color.green = profile.green;
|
||||
led->color.blue = profile.blue;
|
||||
}
|
||||
|
||||
static void
|
||||
hidpp10drv_write_led(struct hidpp10_profile *profile,
|
||||
struct ratbag_led *led)
|
||||
{
|
||||
profile->red = led->color.red;
|
||||
profile->green = led->color.green;
|
||||
profile->blue = led->color.blue;
|
||||
}
|
||||
|
||||
static int
|
||||
hidpp10drv_set_current_profile(struct ratbag_device *device, unsigned int index)
|
||||
{
|
||||
@@ -346,21 +384,26 @@ hidpp10drv_set_current_profile(struct ratbag_device *device, unsigned int index)
|
||||
}
|
||||
|
||||
static void
|
||||
hidpp10drv_read_profile(struct ratbag_profile *profile, unsigned int index)
|
||||
hidpp10drv_read_profile(struct ratbag_profile *profile)
|
||||
{
|
||||
struct ratbag_device *device = profile->device;
|
||||
struct ratbag_button *button;
|
||||
struct ratbag_led *led;
|
||||
struct hidpp10drv_data *drv_data;
|
||||
struct hidpp10_device *hidpp10;
|
||||
struct hidpp10_profile p = {0};
|
||||
struct ratbag_resolution *res;
|
||||
int rc;
|
||||
unsigned int i;
|
||||
uint16_t xres, yres;
|
||||
uint8_t idx;
|
||||
|
||||
/* 0x64 USB_REFRESH_RATE has time between reports in ms. so let's
|
||||
* assume the 1000/500/250 rates exist on the devices */
|
||||
unsigned int rates[] = {250, 500, 1000};
|
||||
|
||||
drv_data = ratbag_get_drv_data(device);
|
||||
hidpp10 = drv_data->dev;
|
||||
rc = hidpp10_get_profile(hidpp10, index, &p);
|
||||
rc = hidpp10_get_profile(hidpp10, profile->index, &p);
|
||||
if (rc)
|
||||
return;
|
||||
|
||||
@@ -377,75 +420,55 @@ hidpp10drv_read_profile(struct ratbag_profile *profile, unsigned int index)
|
||||
ratbag_device_set_capability(device, RATBAG_DEVICE_CAP_RESOLUTION);
|
||||
ratbag_device_set_capability(device, RATBAG_DEVICE_CAP_SWITCHABLE_RESOLUTION);
|
||||
|
||||
for (i = 0; i < profile->resolution.num_modes; i++) {
|
||||
unsigned int min, max;
|
||||
ratbag_profile_for_each_resolution(profile, res) {
|
||||
unsigned int dpis[hidpp10->dpi_count];
|
||||
|
||||
res = ratbag_resolution_init(profile, i,
|
||||
p.dpi_modes[i].xres,
|
||||
p.dpi_modes[i].yres,
|
||||
p.refresh_rate);
|
||||
ratbag_resolution_set_resolution(res,
|
||||
p.dpi_modes[res->index].xres,
|
||||
p.dpi_modes[res->index].yres,
|
||||
p.refresh_rate);
|
||||
ratbag_resolution_set_cap(res,
|
||||
RATBAG_RESOLUTION_CAP_SEPARATE_XY_RESOLUTION);
|
||||
if (profile->is_active &&
|
||||
res->dpi_x == xres &&
|
||||
res->dpi_y == yres)
|
||||
res->is_active = true;
|
||||
if (i == p.default_dpi_mode) {
|
||||
if (res->index == p.default_dpi_mode) {
|
||||
res->is_default = true;
|
||||
if (!profile->is_active)
|
||||
res->is_active = true;
|
||||
}
|
||||
|
||||
min = hidpp10_dpi_table_get_min_dpi(hidpp10);
|
||||
max = hidpp10_dpi_table_get_max_dpi(hidpp10);
|
||||
ratbag_resolution_set_range(res, min, max);
|
||||
}
|
||||
}
|
||||
if (hidpp10->dpi_table_is_range) {
|
||||
unsigned int min, max;
|
||||
|
||||
static int
|
||||
hidpp10drv_write_profile(struct ratbag_profile *profile)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
min = hidpp10_dpi_table_get_min_dpi(hidpp10);
|
||||
max = hidpp10_dpi_table_get_max_dpi(hidpp10);
|
||||
/* FIXME: this relies on libratbag using the
|
||||
* same steps that we support */
|
||||
ratbag_resolution_set_dpi_list_from_range(res, min, max);
|
||||
} else {
|
||||
for (int i = 0; i < hidpp10->dpi_count; i++)
|
||||
dpis[i] = hidpp10->dpi_table[i].dpi;
|
||||
|
||||
static int
|
||||
hidpp10drv_write_resolution_dpi(struct hidpp10_profile *p,
|
||||
struct ratbag_resolution *resolution,
|
||||
int dpi_x, int dpi_y)
|
||||
{
|
||||
struct ratbag_profile *profile = resolution->profile;
|
||||
struct ratbag_device *device = profile->device;
|
||||
struct hidpp10drv_data *drv_data = ratbag_get_drv_data(device);
|
||||
struct hidpp10_device *hidpp10 = drv_data->dev;
|
||||
unsigned int index;
|
||||
uint16_t cur_dpi_x, cur_dpi_y;
|
||||
int rc;
|
||||
ratbag_resolution_set_dpi_list(res, dpis, hidpp10->dpi_count);
|
||||
}
|
||||
|
||||
/* store the current resolution */
|
||||
rc = hidpp10_get_current_resolution(hidpp10, &cur_dpi_x, &cur_dpi_y);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
if (resolution->is_active) {
|
||||
/* we need to switch to the new resolution */
|
||||
cur_dpi_x = dpi_x;
|
||||
cur_dpi_y = dpi_y;
|
||||
ratbag_resolution_set_report_rate_list(res, rates,
|
||||
ARRAY_LENGTH(rates));
|
||||
}
|
||||
|
||||
/* retrieve which resolution is asked to be changed */
|
||||
index = resolution - profile->resolution.modes;
|
||||
ratbag_profile_for_each_button(profile, button)
|
||||
hidpp10drv_read_button(button);
|
||||
|
||||
p->dpi_modes[index].xres = dpi_x;
|
||||
p->dpi_modes[index].yres = dpi_y;
|
||||
|
||||
/* restore the current setting */
|
||||
return hidpp10_set_current_resolution(hidpp10, cur_dpi_x, cur_dpi_y);
|
||||
ratbag_profile_for_each_led(profile, led)
|
||||
hidpp10drv_read_led(led);
|
||||
}
|
||||
|
||||
static int
|
||||
hidpp10drv_fill_from_profile(struct ratbag_device *device, struct hidpp10_device *dev)
|
||||
{
|
||||
int rc;
|
||||
int rc, num_leds;
|
||||
struct hidpp10_profile profile = {0};
|
||||
unsigned int i;
|
||||
|
||||
@@ -461,6 +484,11 @@ hidpp10drv_fill_from_profile(struct ratbag_device *device, struct hidpp10_device
|
||||
break;
|
||||
}
|
||||
|
||||
/* let the .device file override LED count from the profile */
|
||||
num_leds = ratbag_device_data_hidpp10_get_led_count(device->data);
|
||||
if (num_leds >= 0)
|
||||
profile.num_leds = num_leds;
|
||||
|
||||
ratbag_device_init_profiles(device,
|
||||
dev->profile_count,
|
||||
profile.num_dpi_modes,
|
||||
@@ -500,10 +528,11 @@ hidpp10drv_commit(struct ratbag_device *device)
|
||||
struct hidpp10_device *dev = drv_data->dev;
|
||||
struct ratbag_profile *profile;
|
||||
struct ratbag_button *button;
|
||||
struct ratbag_led *led;
|
||||
struct ratbag_resolution *resolution;
|
||||
struct ratbag_resolution *active_resolution = NULL;
|
||||
struct hidpp10_profile p;
|
||||
int rc;
|
||||
unsigned int i;
|
||||
|
||||
list_for_each(profile, &device->profiles, link) {
|
||||
if (!profile->dirty)
|
||||
@@ -515,15 +544,12 @@ hidpp10drv_commit(struct ratbag_device *device)
|
||||
|
||||
p.enabled = profile->is_enabled;
|
||||
|
||||
for (i = 0; i < profile->resolution.num_modes; i++) {
|
||||
resolution = &profile->resolution.modes[i];
|
||||
ratbag_profile_for_each_resolution(profile, resolution) {
|
||||
p.dpi_modes[resolution->index].xres = resolution->dpi_x;
|
||||
p.dpi_modes[resolution->index].yres = resolution->dpi_y;
|
||||
|
||||
rc = hidpp10drv_write_resolution_dpi(&p,
|
||||
resolution,
|
||||
resolution->dpi_x,
|
||||
resolution->dpi_y);
|
||||
if (rc)
|
||||
return RATBAG_ERROR_DEVICE;
|
||||
if (profile->is_active && resolution->is_active)
|
||||
active_resolution = resolution;
|
||||
}
|
||||
|
||||
list_for_each(button, &profile->buttons, link) {
|
||||
@@ -537,11 +563,25 @@ hidpp10drv_commit(struct ratbag_device *device)
|
||||
return RATBAG_ERROR_DEVICE;
|
||||
}
|
||||
|
||||
ratbag_profile_for_each_led(profile, led)
|
||||
hidpp10drv_write_led(&p, led);
|
||||
|
||||
if (dev->profile_type != HIDPP10_PROFILE_UNKNOWN) {
|
||||
rc = hidpp10_set_profile(dev, profile->index, &p);
|
||||
if (rc)
|
||||
return RATBAG_ERROR_DEVICE;
|
||||
}
|
||||
|
||||
/* Update the current resolution in case it changed */
|
||||
if (active_resolution) {
|
||||
rc = hidpp10_set_current_resolution(dev,
|
||||
active_resolution->dpi_x,
|
||||
active_resolution->dpi_y);
|
||||
if (rc)
|
||||
return RATBAG_ERROR_DEVICE;
|
||||
|
||||
active_resolution = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return RATBAG_SUCCESS;
|
||||
@@ -555,10 +595,10 @@ hidpp10drv_probe(struct ratbag_device *device)
|
||||
struct hidpp10_device *dev = NULL;
|
||||
struct hidpp_device base;
|
||||
enum hidpp10_profile_type type = HIDPP10_PROFILE_UNKNOWN;
|
||||
const char *prop;
|
||||
const char *typestr;
|
||||
int device_idx = HIDPP_WIRED_DEVICE_IDX;
|
||||
int nread = 0;
|
||||
unsigned int profile_count = 1;
|
||||
struct ratbag_profile *profile;
|
||||
|
||||
rc = ratbag_find_hidraw(device, hidpp10drv_test_hidraw);
|
||||
if (rc)
|
||||
@@ -568,38 +608,29 @@ hidpp10drv_probe(struct ratbag_device *device)
|
||||
hidpp_device_init(&base, device->hidraw.fd);
|
||||
hidpp_device_set_log_handler(&base, hidpp10_log, HIDPP_LOG_PRIORITY_RAW, device);
|
||||
|
||||
prop = ratbag_device_get_udev_property(device, "RATBAG_HIDPP10_PROFILE");
|
||||
if (prop) {
|
||||
if (strcasecmp("G500", prop) == 0)
|
||||
typestr = ratbag_device_data_hidpp10_get_profile_type(device->data);
|
||||
if (typestr) {
|
||||
if (strcasecmp("G500", typestr) == 0)
|
||||
type = HIDPP10_PROFILE_G500;
|
||||
else if (strcasecmp("G700", prop) == 0)
|
||||
else if (strcasecmp("G700", typestr) == 0)
|
||||
type = HIDPP10_PROFILE_G700;
|
||||
else if (strcasecmp("G9", prop) == 0)
|
||||
else if (strcasecmp("G9", typestr) == 0)
|
||||
type = HIDPP10_PROFILE_G9;
|
||||
|
||||
prop = ratbag_device_get_udev_property(device, "RATBAG_HIDPP10_PROFILE_COUNT");
|
||||
if (prop)
|
||||
profile_count = atoi(prop);
|
||||
profile_count = ratbag_device_data_hidpp10_get_profile_count(device->data);
|
||||
}
|
||||
|
||||
prop = ratbag_device_get_udev_property(device, "RATBAG_HIDPP10_INDEX");
|
||||
if (prop) {
|
||||
sscanf(prop, "%d%n", &device_idx, &nread);
|
||||
if (!nread || (prop[nread]) != '\0' || device_idx < 0) {
|
||||
log_error(device->ratbag,
|
||||
"Error parsing RATBAG_HIDPP10_INDEX: '%s' for %s\n",
|
||||
prop,
|
||||
device->name);
|
||||
device_idx = HIDPP_WIRED_DEVICE_IDX;
|
||||
}
|
||||
}
|
||||
device_idx = ratbag_device_data_hidpp10_get_index(device->data);
|
||||
if (device_idx == -1)
|
||||
device_idx = HIDPP_WIRED_DEVICE_IDX;
|
||||
|
||||
/* In the general case, we can treat all devices as wired devices
|
||||
* here. If we talk to the correct hidraw device the kernel adjusts
|
||||
* the device index for us, so even for unifying receiver devices
|
||||
* we can just use 0x00 as device index.
|
||||
*
|
||||
* If there is a special need like for G700(s), we can pass a
|
||||
* udev prop RATBAG_HIDPP10_INDEX.
|
||||
* If there is a special need like for G700(s), then add a DeviceIndex
|
||||
* entry to the .device file.
|
||||
*/
|
||||
dev = hidpp10_device_new(&base, device_idx, type, profile_count);
|
||||
|
||||
@@ -611,31 +642,31 @@ hidpp10drv_probe(struct ratbag_device *device)
|
||||
}
|
||||
|
||||
if (type != HIDPP10_PROFILE_UNKNOWN) {
|
||||
prop = ratbag_device_get_udev_property(device, "RATBAG_HIDPP10_DPI");
|
||||
if (prop) {
|
||||
rc = hidpp10_build_dpi_table_from_dpi_info(dev, prop);
|
||||
_cleanup_(dpi_list_freep) struct dpi_list *list = NULL;
|
||||
_cleanup_(freep) struct dpi_range *range = NULL;
|
||||
|
||||
range = ratbag_device_data_hidpp10_get_dpi_range(device->data);
|
||||
if (range) {
|
||||
rc = hidpp10_build_dpi_table_from_dpi_info(dev, range);
|
||||
if (rc)
|
||||
log_error(device->ratbag,
|
||||
"Error parsing RATBAG_HIDPP10_DPI: '%s' for %s\n",
|
||||
prop,
|
||||
"Error parsing DpiRange for %s\n",
|
||||
device->name);
|
||||
}
|
||||
|
||||
prop = ratbag_device_get_udev_property(device, "RATBAG_HIDPP10_DPI_LIST");
|
||||
if (prop) {
|
||||
rc = hidpp10_build_dpi_table_from_list(dev, prop);
|
||||
list = ratbag_device_data_hidpp10_get_dpi_list(device->data);
|
||||
if (list) {
|
||||
rc = hidpp10_build_dpi_table_from_list(dev, list);
|
||||
if (rc)
|
||||
log_error(device->ratbag,
|
||||
"Error parsing RATBAG_HIDPP10_DPI_LIST: '%s' for %s\n",
|
||||
prop,
|
||||
"Error parsing DpiList for %s\n",
|
||||
device->name);
|
||||
}
|
||||
|
||||
if (!dev->dpi_count)
|
||||
log_info(device->ratbag,
|
||||
"Device %s might have wrong dpi settings. "
|
||||
"Please add RATBAG_HIDPP10_DPI or RATBAG_HIDPP10_DPI_LIST "
|
||||
"to the udev properties.\n",
|
||||
"Please adjust the .device file.\n",
|
||||
device->name);
|
||||
}
|
||||
|
||||
@@ -648,14 +679,16 @@ hidpp10drv_probe(struct ratbag_device *device)
|
||||
|
||||
if (hidpp10drv_fill_from_profile(device, dev)) {
|
||||
/* Fall back to something that every mouse has */
|
||||
struct ratbag_profile *profile;
|
||||
_cleanup_profile_ struct ratbag_profile *profile;
|
||||
|
||||
ratbag_device_init_profiles(device, 1, 1, 3, 0);
|
||||
profile = ratbag_device_get_profile(device, 0);
|
||||
profile->is_active = true;
|
||||
ratbag_profile_unref(profile);
|
||||
}
|
||||
|
||||
ratbag_device_for_each_profile(device, profile)
|
||||
hidpp10drv_read_profile(profile);
|
||||
|
||||
return 0;
|
||||
err:
|
||||
free(drv_data);
|
||||
@@ -687,9 +720,6 @@ struct ratbag_driver hidpp10_driver = {
|
||||
.id = "hidpp10",
|
||||
.probe = hidpp10drv_probe,
|
||||
.remove = hidpp10drv_remove,
|
||||
.read_profile = hidpp10drv_read_profile,
|
||||
.write_profile = hidpp10drv_write_profile,
|
||||
.set_active_profile = hidpp10drv_set_current_profile,
|
||||
.read_button = hidpp10drv_read_button,
|
||||
.commit = hidpp10drv_commit,
|
||||
};
|
||||
|
||||
@@ -45,14 +45,17 @@
|
||||
|
||||
#include "libratbag-private.h"
|
||||
#include "libratbag-hidraw.h"
|
||||
#include "libratbag-data.h"
|
||||
|
||||
#define HIDPP_CAP_RESOLUTION_2200 (1 << 0)
|
||||
#define HIDPP_CAP_SWITCHABLE_RESOLUTION_2201 (1 << 1)
|
||||
#define HIDPP_CAP_BUTTON_KEY_1b04 (1 << 2)
|
||||
#define HIDPP_CAP_BATTERY_LEVEL_1000 (1 << 3)
|
||||
#define HIDPP_CAP_KBD_REPROGRAMMABLE_KEYS_1b00 (1 << 4)
|
||||
#define HIDPP_CAP_COLOR_LED_EFFECTS_8070 (1 << 5)
|
||||
#define HIDPP_CAP_COLOR_LED_EFFECTS_8070 (1 << 5)
|
||||
#define HIDPP_CAP_ONBOARD_PROFILES_8100 (1 << 6)
|
||||
#define HIDPP_CAP_LED_SW_CONTROL_1300 (1 << 7)
|
||||
#define HIDPP_CAP_ADJUSTIBLE_REPORT_RATE_8060 (1 << 8)
|
||||
|
||||
struct hidpp20drv_data {
|
||||
struct hidpp20_device *dev;
|
||||
@@ -62,7 +65,10 @@ struct hidpp20drv_data {
|
||||
unsigned num_controls;
|
||||
struct hidpp20_control_id *controls;
|
||||
struct hidpp20_profiles *profiles;
|
||||
struct hidpp20_color_led_zone_info *led_infos;
|
||||
union hidpp20_generic_led_zone_info led_infos;
|
||||
|
||||
unsigned int report_rates[4];
|
||||
unsigned int num_report_rates;
|
||||
|
||||
unsigned int num_profiles;
|
||||
unsigned int num_resolutions;
|
||||
@@ -96,7 +102,7 @@ hidpp20drv_read_button_1b04(struct ratbag_button *button)
|
||||
button->type = hidpp20_1b04_get_physical_mapping(control->task_id);
|
||||
action = hidpp20_1b04_get_logical_mapping(mapping);
|
||||
if (action)
|
||||
button->action = *action;
|
||||
ratbag_button_set_action(button, action);
|
||||
|
||||
ratbag_button_enable_action_type(button, RATBAG_BUTTON_ACTION_TYPE_BUTTON);
|
||||
ratbag_button_enable_action_type(button, RATBAG_BUTTON_ACTION_TYPE_KEY);
|
||||
@@ -245,18 +251,75 @@ hidpp20drv_read_button(struct ratbag_button *button)
|
||||
}
|
||||
|
||||
static void
|
||||
hidpp20drv_read_led(struct ratbag_led *led)
|
||||
hidpp20drv_read_led_1300(struct ratbag_led *led, struct hidpp20drv_data* data)
|
||||
{
|
||||
struct ratbag_device *device = led->profile->device;
|
||||
struct hidpp20drv_data *drv_data = ratbag_get_drv_data(device);
|
||||
struct hidpp20_profile *profile;
|
||||
struct hidpp20_color_led_zone_info *led_info;
|
||||
struct hidpp20_led *h_led;
|
||||
struct hidpp20_led_sw_ctrl_led_state state;
|
||||
struct hidpp20_led_sw_ctrl_led_info *info;
|
||||
int rc;
|
||||
|
||||
if (!(drv_data->capabilities & HIDPP_CAP_COLOR_LED_EFFECTS_8070))
|
||||
info = &data->led_infos.leds[led->index];
|
||||
|
||||
rc = hidpp20_led_sw_control_get_led_state(data->dev, led->index, &state);
|
||||
|
||||
if (rc != 0)
|
||||
return;
|
||||
|
||||
led_info = &drv_data->led_infos[led->index];
|
||||
led->colordepth = RATBAG_LED_COLORDEPTH_MONOCHROME;
|
||||
|
||||
switch (info->type)
|
||||
{
|
||||
case HIDPP20_LED_TYPE_LOGO:
|
||||
led->type = RATBAG_LED_TYPE_LOGO;
|
||||
break;
|
||||
case HIDPP20_LED_TYPE_BATTERY:
|
||||
led->type = RATBAG_LED_TYPE_BATTERY;
|
||||
break;
|
||||
case HIDPP20_LED_TYPE_DPI:
|
||||
led->type = RATBAG_LED_TYPE_DPI;
|
||||
break;
|
||||
case HIDPP20_LED_TYPE_PROFILE:
|
||||
case HIDPP20_LED_TYPE_COSMETIC:
|
||||
led->type = RATBAG_LED_TYPE_SIDE;
|
||||
break;
|
||||
}
|
||||
|
||||
switch (state.mode)
|
||||
{
|
||||
case HIDPP20_LED_MODE_OFF:
|
||||
led->mode = RATBAG_LED_OFF;
|
||||
break;
|
||||
case HIDPP20_LED_MODE_ON:
|
||||
led->mode = RATBAG_LED_ON;
|
||||
break;
|
||||
case HIDPP20_LED_MODE_BREATHING:
|
||||
led->mode = RATBAG_LED_BREATHING;
|
||||
led->ms = state.breathing.period;
|
||||
led->brightness = state.breathing.brightness;
|
||||
break;
|
||||
default:
|
||||
led->mode = RATBAG_LED_ON;
|
||||
}
|
||||
|
||||
if (info->caps & HIDPP20_LED_MODE_ON)
|
||||
ratbag_led_set_mode_capability(led, RATBAG_LED_ON);
|
||||
if (info->caps & HIDPP20_LED_MODE_OFF)
|
||||
ratbag_led_set_mode_capability(led, RATBAG_LED_OFF);
|
||||
if (info->caps & (HIDPP20_LED_MODE_BLINK | HIDPP20_LED_MODE_TRAVEL |
|
||||
HIDPP20_LED_MODE_RAMP_UP | HIDPP20_LED_MODE_RAMP_DOWN |
|
||||
HIDPP20_LED_MODE_HEARTBEAT | HIDPP20_LED_MODE_BREATHING))
|
||||
ratbag_led_set_mode_capability(led, RATBAG_LED_BREATHING);
|
||||
}
|
||||
|
||||
static void
|
||||
hidpp20drv_read_led_8070(struct ratbag_led *led, struct hidpp20drv_data* drv_data)
|
||||
{
|
||||
struct hidpp20_profile *profile;
|
||||
struct hidpp20_led *h_led;
|
||||
struct hidpp20_color_led_zone_info* led_info;
|
||||
struct hidpp20_color_led_info info;
|
||||
int rc;
|
||||
|
||||
led_info = &drv_data->led_infos.color_leds[led->index];
|
||||
profile = &drv_data->profiles->profiles[led->profile->index];
|
||||
h_led = &profile->leds[led->index];
|
||||
|
||||
@@ -274,21 +337,74 @@ hidpp20drv_read_led(struct ratbag_led *led)
|
||||
led->mode = RATBAG_LED_OFF;
|
||||
break;
|
||||
}
|
||||
led->type = hidpp20_8070_get_location_mapping(led_info->location);
|
||||
|
||||
/* pre-filled, only override if unknown */
|
||||
if (led->type == RATBAG_LED_TYPE_UNKNOWN)
|
||||
led->type = hidpp20_8070_get_location_mapping(led_info->location);
|
||||
led->color.red = h_led->color.red;
|
||||
led->color.green = h_led->color.green;
|
||||
led->color.blue = h_led->color.blue;
|
||||
led->hz = h_led->period; /* FIXME: should be ceil(1000.0 / h_led->period), but that would be very small */
|
||||
led->ms = h_led->period;
|
||||
led->brightness = h_led->brightness * 255 / 100;
|
||||
|
||||
rc = hidpp20_color_led_effects_get_info(drv_data->dev, &info);
|
||||
if (rc == 0 &&
|
||||
info.ext_caps & HIDPP20_COLOR_LED_INFO_EXT_CAP_MONOCHROME_ONLY)
|
||||
led->colordepth = RATBAG_LED_COLORDEPTH_MONOCHROME;
|
||||
else
|
||||
led->colordepth = RATBAG_LED_COLORDEPTH_RGB_888;
|
||||
|
||||
for (int i = 0; i < led_info->num_effects; i++) {
|
||||
struct hidpp20_color_led_zone_effect_info ei;
|
||||
rc = hidpp20_color_led_effect_get_zone_effect_info(drv_data->dev,
|
||||
led_info->index,
|
||||
i, &ei);
|
||||
if (rc < 0)
|
||||
break;
|
||||
|
||||
switch (ei.effect_id) {
|
||||
case HIDPP20_COLOR_LED_ZONE_EFFECT_DISABLED:
|
||||
ratbag_led_set_mode_capability(led, RATBAG_LED_OFF);
|
||||
break;
|
||||
case HIDPP20_COLOR_LED_ZONE_EFFECT_FIXED:
|
||||
ratbag_led_set_mode_capability(led, RATBAG_LED_ON);
|
||||
break;
|
||||
case HIDPP20_COLOR_LED_ZONE_EFFECT_CYCLING:
|
||||
ratbag_led_set_mode_capability(led, RATBAG_LED_CYCLE);
|
||||
break;
|
||||
case HIDPP20_COLOR_LED_ZONE_EFFECT_WAVE:
|
||||
case HIDPP20_COLOR_LED_ZONE_EFFECT_BREATHING:
|
||||
ratbag_led_set_mode_capability(led, RATBAG_LED_BREATHING);
|
||||
break;
|
||||
default:
|
||||
log_bug_libratbag(led->profile->device->ratbag,
|
||||
"%s: Unknown effect id %d\n",
|
||||
led->profile->device->name,
|
||||
ei.effect_id);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
hidpp20drv_read_led(struct ratbag_led *led)
|
||||
{
|
||||
struct ratbag_device *device = led->profile->device;
|
||||
struct hidpp20drv_data *drv_data = ratbag_get_drv_data(device);
|
||||
|
||||
if (drv_data->capabilities & HIDPP_CAP_COLOR_LED_EFFECTS_8070)
|
||||
hidpp20drv_read_led_8070(led, drv_data);
|
||||
else if (drv_data->capabilities & HIDPP_CAP_LED_SW_CONTROL_1300)
|
||||
hidpp20drv_read_led_1300(led, drv_data);
|
||||
}
|
||||
|
||||
static int
|
||||
hidpp20drv_write_button_1b04(struct ratbag_button *button,
|
||||
const struct ratbag_button_action *action)
|
||||
hidpp20drv_update_button_1b04(struct ratbag_button *button)
|
||||
{
|
||||
struct ratbag_device *device = button->profile->device;
|
||||
struct hidpp20drv_data *drv_data = ratbag_get_drv_data(device);
|
||||
struct hidpp20_control_id *control;
|
||||
struct ratbag_button_action *action = &button->action;
|
||||
uint16_t mapping;
|
||||
int rc;
|
||||
|
||||
@@ -318,12 +434,12 @@ hidpp20drv_write_button_1b04(struct ratbag_button *button,
|
||||
}
|
||||
|
||||
static int
|
||||
hidpp20drv_update_button_8100(struct ratbag_button *button,
|
||||
const struct ratbag_button_action *action)
|
||||
hidpp20drv_update_button_8100(struct ratbag_button *button)
|
||||
{
|
||||
struct ratbag_device *device = button->profile->device;
|
||||
struct hidpp20drv_data *drv_data = ratbag_get_drv_data(device);
|
||||
struct hidpp20_profile *profile;
|
||||
struct ratbag_button_action *action = &button->action;
|
||||
uint8_t code, type, subtype;
|
||||
|
||||
if (!(drv_data->capabilities & HIDPP_CAP_ONBOARD_PROFILES_8100))
|
||||
@@ -366,37 +482,80 @@ hidpp20drv_update_button_8100(struct ratbag_button *button,
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
return hidpp20_onboard_profiles_write(drv_data->dev, button->profile->index, drv_data->profiles);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
hidpp20drv_update_button(struct ratbag_button *button,
|
||||
const struct ratbag_button_action *action)
|
||||
hidpp20drv_update_button(struct ratbag_button *button)
|
||||
{
|
||||
struct ratbag_device *device = button->profile->device;
|
||||
struct hidpp20drv_data *drv_data = ratbag_get_drv_data(device);
|
||||
|
||||
if (drv_data->capabilities & HIDPP_CAP_ONBOARD_PROFILES_8100)
|
||||
return hidpp20drv_update_button_8100(button, action);
|
||||
return hidpp20drv_update_button_8100(button);
|
||||
|
||||
if (drv_data->capabilities & HIDPP_CAP_BUTTON_KEY_1b04)
|
||||
return hidpp20drv_write_button_1b04(button, action);
|
||||
return hidpp20drv_update_button_1b04(button);
|
||||
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
static int
|
||||
hidpp20drv_update_led(struct ratbag_led *led)
|
||||
hidpp20drv_update_led_1300(struct ratbag_led *led, struct hidpp20drv_data *data)
|
||||
{
|
||||
const uint16_t led_caps = data->led_infos.leds[led->index].caps;
|
||||
struct hidpp20_led_sw_ctrl_led_state h_led;
|
||||
int rc;
|
||||
|
||||
h_led.index = led->index;
|
||||
|
||||
switch(led->mode)
|
||||
{
|
||||
case RATBAG_LED_BREATHING:
|
||||
h_led.mode = HIDPP20_LED_MODE_BREATHING;
|
||||
h_led.breathing.brightness = led->brightness;
|
||||
h_led.breathing.period = led->ms;
|
||||
h_led.breathing.timeout = 300;
|
||||
break;
|
||||
case RATBAG_LED_OFF:
|
||||
h_led.mode = HIDPP20_LED_MODE_OFF;
|
||||
h_led.on.index = HIDPP20_LED_SW_CONTROL_LED_INDEX_ALL;
|
||||
break;
|
||||
case RATBAG_LED_ON:
|
||||
h_led.mode = HIDPP20_LED_MODE_ON;
|
||||
h_led.on.index = HIDPP20_LED_SW_CONTROL_LED_INDEX_ALL;
|
||||
break;
|
||||
case RATBAG_LED_CYCLE:
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
if (!(h_led.mode & led_caps)) {
|
||||
hidpp_log_error(&data->dev->base, "LED %d does not support effect %s(%04x), supports %04x\n",
|
||||
led->index, hidpp20_sw_led_control_get_mode_string(h_led.mode),
|
||||
h_led.mode, led_caps);
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
if (!hidpp20_led_sw_control_get_sw_ctrl(data->dev)) {
|
||||
rc = hidpp20_led_sw_control_set_sw_ctrl(data->dev, true);
|
||||
if (rc)
|
||||
return rc;
|
||||
}
|
||||
|
||||
rc = hidpp20_led_sw_control_set_led_state(data->dev, &h_led);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
return RATBAG_SUCCESS;
|
||||
}
|
||||
|
||||
static int
|
||||
hidpp20drv_update_led_8070(struct ratbag_led *led, struct ratbag_profile* profile,
|
||||
struct hidpp20drv_data *drv_data)
|
||||
{
|
||||
struct ratbag_profile *profile = led->profile;
|
||||
struct ratbag_device *device = profile->device;
|
||||
struct hidpp20drv_data *drv_data = ratbag_get_drv_data(device);
|
||||
struct hidpp20_profile *h_profile;
|
||||
struct hidpp20_led *h_led;
|
||||
|
||||
if (!(drv_data->capabilities & HIDPP_CAP_COLOR_LED_EFFECTS_8070))
|
||||
return -ENOTSUP;
|
||||
|
||||
h_profile = &drv_data->profiles->profiles[profile->index];
|
||||
|
||||
h_led = &(h_profile->leds[led->index]);
|
||||
@@ -421,12 +580,28 @@ hidpp20drv_update_led(struct ratbag_led *led)
|
||||
h_led->color.red = led->color.red;
|
||||
h_led->color.green = led->color.green;
|
||||
h_led->color.blue = led->color.blue;
|
||||
h_led->period = led->hz; /* FIXME: should be 1000 / led->hz, but that would be very small */
|
||||
h_led->period = led->ms;
|
||||
h_led->brightness = led->brightness * 100 / 255;
|
||||
|
||||
return RATBAG_SUCCESS;
|
||||
}
|
||||
|
||||
static int
|
||||
hidpp20drv_update_led(struct ratbag_led *led)
|
||||
{
|
||||
struct ratbag_profile *profile = led->profile;
|
||||
struct ratbag_device *device = profile->device;
|
||||
struct hidpp20drv_data *drv_data = ratbag_get_drv_data(device);
|
||||
|
||||
if (drv_data->capabilities & HIDPP_CAP_COLOR_LED_EFFECTS_8070)
|
||||
return hidpp20drv_update_led_8070(led, profile, drv_data);
|
||||
|
||||
if (drv_data->capabilities & HIDPP_CAP_LED_SW_CONTROL_1300)
|
||||
return hidpp20drv_update_led_1300(led, drv_data);
|
||||
|
||||
return RATBAG_ERROR_CAPABILITY;
|
||||
}
|
||||
|
||||
static int
|
||||
hidpp20drv_current_profile(struct ratbag_device *device)
|
||||
{
|
||||
@@ -458,7 +633,8 @@ hidpp20drv_set_current_profile(struct ratbag_device *device, unsigned int index)
|
||||
|
||||
h_profile = &drv_data->profiles->profiles[index];
|
||||
if (!h_profile->enabled) {
|
||||
rc = hidpp20_onboard_profiles_write(drv_data->dev, index, drv_data->profiles);
|
||||
h_profile->enabled = 1;
|
||||
rc = hidpp20_onboard_profiles_commit(drv_data->dev, drv_data->profiles);
|
||||
if (rc)
|
||||
return rc;
|
||||
}
|
||||
@@ -493,7 +669,43 @@ hidpp20drv_read_resolution_dpi_2201(struct ratbag_device *device)
|
||||
drv_data->sensors[0].dpi_max);
|
||||
|
||||
drv_data->num_sensors = rc;
|
||||
drv_data->num_resolutions = drv_data->num_sensors;
|
||||
|
||||
/* if 0x8100 has already been enumerated we already have the supported
|
||||
* number of resolutions and shouldn't overwrite it
|
||||
*/
|
||||
if (!(drv_data->capabilities & HIDPP_CAP_ONBOARD_PROFILES_8100))
|
||||
drv_data->num_resolutions = drv_data->num_sensors;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
hidpp20drv_read_report_rate_8060(struct ratbag_device *device)
|
||||
{
|
||||
struct hidpp20drv_data *drv_data = ratbag_get_drv_data(device);
|
||||
struct ratbag *ratbag = device->ratbag;
|
||||
uint8_t bitflags_ms;
|
||||
int nrates = 0;
|
||||
int rc;
|
||||
|
||||
rc = hidpp20_adjustable_report_rate_get_report_rate_list(drv_data->dev,
|
||||
&bitflags_ms);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
/* We only care about 'standard' rates */
|
||||
if (bitflags_ms & 0x80)
|
||||
drv_data->report_rates[nrates++] = 125;
|
||||
if (bitflags_ms & 0x8)
|
||||
drv_data->report_rates[nrates++] = 250;
|
||||
if (bitflags_ms & 0x2)
|
||||
drv_data->report_rates[nrates++] = 500;
|
||||
if (bitflags_ms & 0x1)
|
||||
drv_data->report_rates[nrates++] = 1000;
|
||||
|
||||
drv_data->num_report_rates = nrates;
|
||||
|
||||
log_debug(ratbag, "device has %d report rates\n", nrates);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -504,9 +716,7 @@ hidpp20drv_read_resolution_dpi(struct ratbag_profile *profile)
|
||||
struct ratbag_device *device = profile->device;
|
||||
struct ratbag *ratbag = device->ratbag;
|
||||
struct hidpp20drv_data *drv_data = ratbag_get_drv_data(device);
|
||||
struct ratbag_resolution *res;
|
||||
int rc;
|
||||
unsigned int i;
|
||||
|
||||
if (drv_data->capabilities & HIDPP_CAP_RESOLUTION_2200) {
|
||||
uint16_t resolution;
|
||||
@@ -524,11 +734,13 @@ hidpp20drv_read_resolution_dpi(struct ratbag_profile *profile)
|
||||
}
|
||||
|
||||
if (drv_data->capabilities & HIDPP_CAP_SWITCHABLE_RESOLUTION_2201) {
|
||||
struct ratbag_resolution *res;
|
||||
|
||||
rc = hidpp20drv_read_resolution_dpi_2201(device);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
for (i = 0; i < profile->resolution.num_modes; i++) {
|
||||
ratbag_profile_for_each_resolution(profile, res) {
|
||||
struct hidpp20_sensor *sensor;
|
||||
|
||||
/* We only look at the first sensor. Multiple
|
||||
@@ -536,9 +748,10 @@ hidpp20drv_read_resolution_dpi(struct ratbag_profile *profile)
|
||||
sensor = &drv_data->sensors[0];
|
||||
|
||||
/* FIXME: retrieve the refresh rate */
|
||||
res = ratbag_resolution_init(profile, i, sensor->dpi, sensor->dpi, 0);
|
||||
ratbag_resolution_set_range(res, sensor->dpi_min, sensor->dpi_max);
|
||||
|
||||
ratbag_resolution_set_resolution(res, sensor->dpi, sensor->dpi, 0);
|
||||
ratbag_resolution_set_dpi_list_from_range(res,
|
||||
sensor->dpi_min,
|
||||
sensor->dpi_max);
|
||||
/* FIXME: we mark all resolutions as active because
|
||||
* they are from different sensors */
|
||||
res->is_active = true;
|
||||
@@ -547,6 +760,19 @@ hidpp20drv_read_resolution_dpi(struct ratbag_profile *profile)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (drv_data->capabilities & HIDPP_CAP_ADJUSTIBLE_REPORT_RATE_8060) {
|
||||
struct ratbag_resolution *res;
|
||||
|
||||
rc = hidpp20drv_read_report_rate_8060(device);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
ratbag_profile_for_each_resolution(profile, res)
|
||||
ratbag_resolution_set_report_rate_list(res,
|
||||
drv_data->report_rates,
|
||||
drv_data->num_report_rates);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -558,14 +784,10 @@ hidpp20drv_update_resolution_dpi_8100(struct ratbag_resolution *resolution,
|
||||
struct ratbag_device *device = profile->device;
|
||||
struct hidpp20drv_data *drv_data = ratbag_get_drv_data(device);
|
||||
struct hidpp20_profile *h_profile;
|
||||
unsigned int index;
|
||||
int dpi = dpi_x; /* dpi_x == dpi_y if we don't have the individual resolution cap */
|
||||
|
||||
/* retrieve which resolution is asked to be changed */
|
||||
index = resolution - profile->resolution.modes;
|
||||
|
||||
h_profile = &drv_data->profiles->profiles[profile->index];
|
||||
h_profile->dpi[index] = dpi;
|
||||
h_profile->dpi[resolution->index] = dpi;
|
||||
|
||||
return RATBAG_SUCCESS;
|
||||
}
|
||||
@@ -669,11 +891,11 @@ hidpp20drv_read_color_leds(struct ratbag_device *device)
|
||||
if (!(drv_data->capabilities & HIDPP_CAP_COLOR_LED_EFFECTS_8070))
|
||||
return 0;
|
||||
|
||||
free(drv_data->led_infos);
|
||||
drv_data->led_infos = NULL;
|
||||
free(drv_data->led_infos.color_leds);
|
||||
drv_data->led_infos.color_leds = NULL;
|
||||
drv_data->num_leds = 0;
|
||||
|
||||
rc = hidpp20_color_led_effects_get_zone_infos(drv_data->dev, &drv_data->led_infos);
|
||||
rc = hidpp20_color_led_effects_get_zone_infos(drv_data->dev, &drv_data->led_infos.color_leds);
|
||||
|
||||
if (rc > 0) {
|
||||
drv_data->num_leds = rc;
|
||||
@@ -684,37 +906,39 @@ hidpp20drv_read_color_leds(struct ratbag_device *device)
|
||||
}
|
||||
|
||||
static int
|
||||
hidpp20drv_read_onboard_profile(struct ratbag_device *device, unsigned index)
|
||||
hidpp20drv_read_leds(struct ratbag_device *device)
|
||||
{
|
||||
struct hidpp20drv_data *drv_data = ratbag_get_drv_data(device);
|
||||
int rc;
|
||||
|
||||
if (!(drv_data->capabilities & HIDPP_CAP_ONBOARD_PROFILES_8100))
|
||||
if (!(drv_data->capabilities & HIDPP_CAP_LED_SW_CONTROL_1300))
|
||||
return 0;
|
||||
|
||||
rc = hidpp20_onboard_profiles_read(drv_data->dev, index, drv_data->profiles);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
free(drv_data->led_infos.leds);
|
||||
drv_data->led_infos.leds = NULL;
|
||||
|
||||
return 0;
|
||||
rc = hidpp20_led_sw_control_read_leds(drv_data->dev, &drv_data->led_infos.leds);
|
||||
if (rc > 0) {
|
||||
drv_data->num_leds = rc;
|
||||
rc = 0;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void
|
||||
hidpp20drv_read_profile_8100(struct ratbag_profile *profile, unsigned int index)
|
||||
hidpp20drv_read_profile_8100(struct ratbag_profile *profile)
|
||||
{
|
||||
struct ratbag_device *device = profile->device;
|
||||
struct hidpp20drv_data *drv_data = ratbag_get_drv_data(device);
|
||||
struct ratbag_resolution *res;
|
||||
struct hidpp20_profile *p;
|
||||
unsigned int i;
|
||||
int dpi_index = 0xff;
|
||||
|
||||
profile->is_enabled = drv_data->profiles->profiles[index].enabled;
|
||||
|
||||
hidpp20drv_read_onboard_profile(device, profile->index);
|
||||
profile->is_enabled = drv_data->profiles->profiles[profile->index].enabled;
|
||||
|
||||
profile->is_active = false;
|
||||
if ((int)index == hidpp20drv_current_profile(device))
|
||||
if ((int)profile->index == hidpp20drv_current_profile(device))
|
||||
profile->is_active = true;
|
||||
|
||||
if (profile->is_active)
|
||||
@@ -723,46 +947,60 @@ hidpp20drv_read_profile_8100(struct ratbag_profile *profile, unsigned int index)
|
||||
if (dpi_index < 0)
|
||||
dpi_index = 0xff;
|
||||
|
||||
p = &drv_data->profiles->profiles[index];
|
||||
p = &drv_data->profiles->profiles[profile->index];
|
||||
|
||||
for (i = 0; i < profile->resolution.num_modes; i++) {
|
||||
ratbag_profile_for_each_resolution(profile, res) {
|
||||
struct hidpp20_sensor *sensor;
|
||||
|
||||
/* We only look at the first sensor. Multiple
|
||||
* sensors is too niche to care about right now */
|
||||
sensor = &drv_data->sensors[0];
|
||||
|
||||
res = ratbag_resolution_init(profile, i,
|
||||
p->dpi[i],
|
||||
p->dpi[i],
|
||||
p->report_rate);
|
||||
ratbag_resolution_set_resolution(res,
|
||||
p->dpi[res->index],
|
||||
p->dpi[res->index],
|
||||
p->report_rate);
|
||||
|
||||
if (profile->is_active &&
|
||||
i == (unsigned int)dpi_index)
|
||||
res->index == (unsigned int)dpi_index)
|
||||
res->is_active = true;
|
||||
if (i == p->default_dpi) {
|
||||
if (res->index == p->default_dpi) {
|
||||
res->is_default = true;
|
||||
if (!profile->is_active || dpi_index < 0 || dpi_index > 4)
|
||||
res->is_active = true;
|
||||
}
|
||||
|
||||
ratbag_resolution_set_range(res, sensor->dpi_min, sensor->dpi_max);
|
||||
ratbag_resolution_set_dpi_list_from_range(res,
|
||||
sensor->dpi_min,
|
||||
sensor->dpi_max);
|
||||
ratbag_resolution_set_report_rate_list(res,
|
||||
drv_data->report_rates,
|
||||
drv_data->num_report_rates);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
hidpp20drv_read_profile(struct ratbag_profile *profile, unsigned int index)
|
||||
hidpp20drv_read_profile(struct ratbag_profile *profile)
|
||||
{
|
||||
struct ratbag_device *device = profile->device;
|
||||
struct hidpp20drv_data *drv_data = ratbag_get_drv_data(device);
|
||||
struct ratbag_led *led;
|
||||
struct ratbag_button *button;
|
||||
|
||||
if (drv_data->capabilities & HIDPP_CAP_ONBOARD_PROFILES_8100)
|
||||
return hidpp20drv_read_profile_8100(profile, index);
|
||||
if (drv_data->capabilities & HIDPP_CAP_ONBOARD_PROFILES_8100) {
|
||||
hidpp20drv_read_profile_8100(profile);
|
||||
} else {
|
||||
hidpp20drv_read_resolution_dpi(profile);
|
||||
hidpp20drv_read_special_key_mouse(device);
|
||||
|
||||
hidpp20drv_read_resolution_dpi(profile);
|
||||
hidpp20drv_read_special_key_mouse(device);
|
||||
profile->is_active = (profile->index == 0);
|
||||
}
|
||||
|
||||
profile->is_active = (index == 0);
|
||||
ratbag_profile_for_each_led(profile, led)
|
||||
hidpp20drv_read_led(led);
|
||||
|
||||
ratbag_profile_for_each_button(profile, button)
|
||||
hidpp20drv_read_button(button);
|
||||
}
|
||||
|
||||
static int
|
||||
@@ -841,6 +1079,14 @@ hidpp20drv_init_feature(struct ratbag_device *device, uint16_t feature)
|
||||
}
|
||||
case HIDPP_PAGE_ADJUSTABLE_REPORT_RATE: {
|
||||
log_debug(ratbag, "device has adjustable report rate\n");
|
||||
|
||||
/* we read the profile once to get the correct number of
|
||||
* supported report rates. */
|
||||
rc = hidpp20drv_read_report_rate_8060(device);
|
||||
if (rc < 0)
|
||||
return 0; /* this is not a hard failure */
|
||||
|
||||
drv_data->capabilities |= HIDPP_CAP_ADJUSTIBLE_REPORT_RATE_8060;
|
||||
break;
|
||||
}
|
||||
case HIDPP_PAGE_COLOR_LED_EFFECTS: {
|
||||
@@ -856,6 +1102,19 @@ hidpp20drv_init_feature(struct ratbag_device *device, uint16_t feature)
|
||||
device->num_leds = drv_data->num_leds;
|
||||
break;
|
||||
}
|
||||
case HIDPP_PAGE_LED_SW_CONTROL: {
|
||||
log_debug(ratbag, "device has non-rgb leds\n");
|
||||
drv_data->capabilities |= HIDPP_CAP_LED_SW_CONTROL_1300;
|
||||
|
||||
if (drv_data->capabilities & HIDPP_PAGE_COLOR_LED_EFFECTS)
|
||||
return 0;
|
||||
|
||||
if (hidpp20drv_read_leds(device))
|
||||
return 0;
|
||||
|
||||
ratbag_device_set_capability(device, RATBAG_DEVICE_CAP_LED);
|
||||
break;
|
||||
}
|
||||
case HIDPP_PAGE_ONBOARD_PROFILES: {
|
||||
log_debug(ratbag, "device has onboard profiles\n");
|
||||
drv_data->capabilities |= HIDPP_CAP_ONBOARD_PROFILES_8100;
|
||||
@@ -866,10 +1125,16 @@ hidpp20drv_init_feature(struct ratbag_device *device, uint16_t feature)
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
rc = hidpp20_onboard_profiles_initialize(drv_data->dev, drv_data->profiles);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
drv_data->num_profiles = drv_data->profiles->num_profiles;
|
||||
drv_data->num_resolutions = drv_data->profiles->num_modes;
|
||||
drv_data->num_buttons = drv_data->profiles->num_buttons;
|
||||
drv_data->num_leds = drv_data->profiles->num_leds;
|
||||
/* We ignore the profile's num_leds and require
|
||||
* HIDPP_PAGE_COLOR_LED_EFFECTS to succeed instead
|
||||
*/
|
||||
|
||||
break;
|
||||
}
|
||||
@@ -892,7 +1157,7 @@ hidpp20drv_commit(struct ratbag_device *device)
|
||||
struct ratbag_led *led;
|
||||
struct ratbag_resolution *resolution;
|
||||
int rc;
|
||||
unsigned int i, dpi_index = 0;
|
||||
unsigned int dpi_index = 0;
|
||||
|
||||
list_for_each(profile, &device->profiles, link) {
|
||||
if (!profile->dirty)
|
||||
@@ -900,10 +1165,9 @@ hidpp20drv_commit(struct ratbag_device *device)
|
||||
|
||||
drv_data->profiles->profiles[profile->index].enabled = profile->is_enabled;
|
||||
|
||||
for (i = 0; i < profile->resolution.num_modes; i++) {
|
||||
resolution = &profile->resolution.modes[i];
|
||||
ratbag_profile_for_each_resolution(profile, resolution) {
|
||||
if (resolution->is_active)
|
||||
dpi_index = i;
|
||||
dpi_index = resolution->index;
|
||||
|
||||
rc = hidpp20drv_update_resolution_dpi(resolution,
|
||||
resolution->dpi_x,
|
||||
@@ -913,12 +1177,10 @@ hidpp20drv_commit(struct ratbag_device *device)
|
||||
}
|
||||
|
||||
list_for_each(button, &profile->buttons, link) {
|
||||
struct ratbag_button_action action = button->action;
|
||||
|
||||
if (!button->dirty)
|
||||
continue;
|
||||
|
||||
rc = hidpp20drv_update_button(button, &action);
|
||||
rc = hidpp20drv_update_button(button);
|
||||
if (rc)
|
||||
return RATBAG_ERROR_DEVICE;
|
||||
}
|
||||
@@ -932,10 +1194,15 @@ hidpp20drv_commit(struct ratbag_device *device)
|
||||
return RATBAG_ERROR_DEVICE;
|
||||
}
|
||||
|
||||
if (drv_data->capabilities & HIDPP_CAP_ONBOARD_PROFILES_8100) {
|
||||
hidpp20_onboard_profiles_write(drv_data->dev,
|
||||
profile->index,
|
||||
drv_data->profiles);
|
||||
}
|
||||
|
||||
if (drv_data->capabilities & HIDPP_CAP_ONBOARD_PROFILES_8100) {
|
||||
rc = hidpp20_onboard_profiles_commit(drv_data->dev,
|
||||
drv_data->profiles);
|
||||
if (rc)
|
||||
return RATBAG_ERROR_DEVICE;
|
||||
|
||||
list_for_each(profile, &device->profiles, link) {
|
||||
if (profile->is_active)
|
||||
hidpp20_onboard_profiles_set_current_dpi_index(drv_data->dev,
|
||||
dpi_index);
|
||||
@@ -1000,6 +1267,7 @@ hidpp20drv_remove(struct ratbag_device *device)
|
||||
|
||||
if (drv_data->profiles)
|
||||
hidpp20_onboard_profiles_destroy(drv_data->profiles);
|
||||
free(drv_data->led_infos.color_leds);
|
||||
free(drv_data->controls);
|
||||
free(drv_data->sensors);
|
||||
if (drv_data->dev)
|
||||
@@ -1007,6 +1275,22 @@ hidpp20drv_remove(struct ratbag_device *device)
|
||||
free(drv_data);
|
||||
}
|
||||
|
||||
static void
|
||||
hidpp20drv_init_device(struct ratbag_device *device,
|
||||
struct hidpp20drv_data *drv_data)
|
||||
{
|
||||
struct ratbag_profile *profile;
|
||||
|
||||
ratbag_device_init_profiles(device,
|
||||
drv_data->num_profiles,
|
||||
drv_data->num_resolutions,
|
||||
drv_data->num_buttons,
|
||||
drv_data->num_leds);
|
||||
|
||||
ratbag_device_for_each_profile(device, profile)
|
||||
hidpp20drv_read_profile(profile);
|
||||
}
|
||||
|
||||
static int
|
||||
hidpp20drv_probe(struct ratbag_device *device)
|
||||
{
|
||||
@@ -1014,9 +1298,7 @@ hidpp20drv_probe(struct ratbag_device *device)
|
||||
struct hidpp20drv_data *drv_data;
|
||||
struct hidpp_device base;
|
||||
struct hidpp20_device *dev;
|
||||
const char *prop;
|
||||
int device_idx = HIDPP_RECEIVER_IDX;
|
||||
int nread = 0;
|
||||
|
||||
rc = ratbag_find_hidraw(device, hidpp20drv_test_hidraw);
|
||||
if (rc)
|
||||
@@ -1027,25 +1309,17 @@ hidpp20drv_probe(struct ratbag_device *device)
|
||||
hidpp_device_init(&base, device->hidraw.fd);
|
||||
hidpp_device_set_log_handler(&base, hidpp20_log, HIDPP_LOG_PRIORITY_RAW, device);
|
||||
|
||||
prop = ratbag_device_get_udev_property(device, "RATBAG_HIDPP20_INDEX");
|
||||
if (prop) {
|
||||
sscanf(prop, "%d%n", &device_idx, &nread);
|
||||
if (!nread || (prop[nread]) != '\0' || device_idx < 0) {
|
||||
log_error(device->ratbag,
|
||||
"Error parsing RATBAG_HIDPP20_INDEX: '%s' for %s\n",
|
||||
prop,
|
||||
device->name);
|
||||
device_idx = HIDPP_RECEIVER_IDX;
|
||||
}
|
||||
}
|
||||
device_idx = ratbag_device_data_hidpp20_get_index(device->data);
|
||||
if (device_idx == -1)
|
||||
device_idx = HIDPP_RECEIVER_IDX;
|
||||
|
||||
/* In the general case, we can treat all devices as wired devices
|
||||
* here. If we talk to the correct hidraw device the kernel adjusts
|
||||
* the device index for us, so even for unifying receiver devices
|
||||
* we can just use 0xff as device index.
|
||||
*
|
||||
* If there is a special need like for G900, we can pass a
|
||||
* udev prop RATBAG_HIDPP20_INDEX.
|
||||
* If there is a special need like for G900, we can add this in the
|
||||
* device data file.
|
||||
*/
|
||||
dev = hidpp20_device_new(&base, device_idx);
|
||||
if (!dev) {
|
||||
@@ -1067,11 +1341,7 @@ hidpp20drv_probe(struct ratbag_device *device)
|
||||
if (rc)
|
||||
goto err;
|
||||
|
||||
ratbag_device_init_profiles(device,
|
||||
drv_data->num_profiles,
|
||||
drv_data->num_resolutions,
|
||||
drv_data->num_buttons,
|
||||
drv_data->num_leds);
|
||||
hidpp20drv_init_device(device, drv_data);
|
||||
|
||||
return rc;
|
||||
err:
|
||||
@@ -1085,8 +1355,5 @@ struct ratbag_driver hidpp20_driver = {
|
||||
.probe = hidpp20drv_probe,
|
||||
.remove = hidpp20drv_remove,
|
||||
.commit = hidpp20drv_commit,
|
||||
.read_profile = hidpp20drv_read_profile,
|
||||
.set_active_profile = hidpp20drv_set_current_profile,
|
||||
.read_button = hidpp20drv_read_button,
|
||||
.read_led = hidpp20drv_read_led,
|
||||
};
|
||||
|
||||
@@ -36,16 +36,18 @@
|
||||
#define LOGITECH_G300_PROFILE_MAX 2
|
||||
#define LOGITECH_G300_BUTTON_MAX 8
|
||||
#define LOGITECH_G300_NUM_DPI 4
|
||||
#define LOGITECH_G300_NUM_LED 0
|
||||
#define LOGITECH_G300_NUM_LED 1
|
||||
#define LOGITECH_G300_DPI_MIN 250
|
||||
#define LOGITECH_G300_DPI_MAX 2500
|
||||
|
||||
#define LOGITECH_G300_REPORT_ID_SET_ACTIVE_PROFILE 0xF0
|
||||
#define LOGITECH_G300_REPORT_ID_GET_ACTIVE_PROFILE 0xF1
|
||||
#define LOGITECH_G300_REPORT_ID_SET_ACTIVE_RESOLUTION 0xF0
|
||||
#define LOGITECH_G300_REPORT_ID_GET_ACTIVE 0xF0
|
||||
#define LOGITECH_G300_REPORT_ID_SET_ACTIVE 0xF0
|
||||
#define LOGITECH_G300_REPORT_ID_GET_ACTIVE_LED 0xF1
|
||||
#define LOGITECH_G300_REPORT_ID_PROFILE_0 0xF3
|
||||
#define LOGITECH_G300_REPORT_ID_PROFILE_1 0xF4
|
||||
#define LOGITECH_G300_REPORT_ID_PROFILE_2 0xF5
|
||||
|
||||
#define LOGITECH_G300_REPORT_SIZE_ACTIVE_PROFILE 2
|
||||
#define LOGITECH_G300_REPORT_SIZE_ACTIVE 4
|
||||
#define LOGITECH_G300_REPORT_SIZE_PROFILE 35
|
||||
|
||||
struct logitech_g300_resolution {
|
||||
@@ -61,10 +63,13 @@ struct logitech_g300_button {
|
||||
|
||||
struct logitech_g300_profile_report {
|
||||
uint8_t id; /* F3, F4, F5 */
|
||||
uint8_t led; /* 00=off, 01=red, 02=green, 03=yellow, 04=blue, 05=pink, 06=turquoise, 07=white */
|
||||
uint8_t led_red :1;
|
||||
uint8_t led_green :1;
|
||||
uint8_t led_blue :1;
|
||||
uint8_t unknown1 :5;
|
||||
uint8_t frequency; /* 00=1000, 01=125, 02=250, 03=500 */
|
||||
struct logitech_g300_resolution dpi_levels[LOGITECH_G300_NUM_DPI];
|
||||
uint8_t unknown; /* dpi index for shift, but something else too */
|
||||
uint8_t unknown2; /* dpi index for shift, but something else too */
|
||||
struct logitech_g300_button buttons[LOGITECH_G300_BUTTON_MAX + 1];
|
||||
} __attribute__((packed));
|
||||
|
||||
@@ -197,14 +202,24 @@ logitech_g300_frequency_to_raw(unsigned int frequency)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
logitech_g300_current_profile(struct ratbag_device *device)
|
||||
{
|
||||
struct logitech_g300_data *drv_data = device->drv_data;
|
||||
uint8_t buf[LOGITECH_G300_REPORT_SIZE_ACTIVE_PROFILE];
|
||||
int i, ret;
|
||||
struct logitech_g300_F0_report {
|
||||
uint8_t id;
|
||||
uint8_t unknown1 :1;
|
||||
uint8_t resolution :3;
|
||||
uint8_t profile :4;
|
||||
uint8_t unknown2;
|
||||
uint8_t unknown3;
|
||||
} __attribute__((packed));
|
||||
|
||||
ret = ratbag_hidraw_raw_request(device, LOGITECH_G300_REPORT_ID_GET_ACTIVE_PROFILE, buf,
|
||||
|
||||
static int
|
||||
logitech_g300_get_active_profile_and_resolution(struct ratbag_device *device)
|
||||
{
|
||||
struct ratbag_profile *profile;
|
||||
struct logitech_g300_F0_report buf;
|
||||
int ret;
|
||||
|
||||
ret = ratbag_hidraw_raw_request(device, 0xF0, (uint8_t*)&buf,
|
||||
sizeof(buf), HID_FEATURE_REPORT, HID_REQ_GET_REPORT);
|
||||
|
||||
if (ret < 0)
|
||||
@@ -213,22 +228,26 @@ logitech_g300_current_profile(struct ratbag_device *device)
|
||||
if (ret != sizeof(buf))
|
||||
return -EIO;
|
||||
|
||||
/* The current profile is identifed by its LED color code. */
|
||||
for (i = 0; i <= LOGITECH_G300_PROFILE_MAX; i++) {
|
||||
struct logitech_g300_profile_report report;
|
||||
list_for_each(profile, &device->profiles, link) {
|
||||
struct ratbag_resolution *resolution;
|
||||
|
||||
report = drv_data->profile_data[i].report;
|
||||
if (report.led == buf[1])
|
||||
return i;
|
||||
if (profile->index != buf.profile)
|
||||
continue;
|
||||
|
||||
profile->is_active = true;
|
||||
ratbag_profile_for_each_resolution(profile, resolution) {
|
||||
resolution->is_active = resolution->index == buf.resolution;
|
||||
}
|
||||
}
|
||||
|
||||
return -EPROTO;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
logitech_g300_set_current_profile(struct ratbag_device *device, unsigned int index)
|
||||
logitech_g300_set_active_profile(struct ratbag_device *device, unsigned int index)
|
||||
{
|
||||
uint8_t buf[] = {LOGITECH_G300_REPORT_ID_SET_ACTIVE_PROFILE, 0x80 + index, 0x00, 0x00};
|
||||
struct ratbag_profile *profile;
|
||||
uint8_t buf[] = {LOGITECH_G300_REPORT_ID_SET_ACTIVE, 0x80 | (index << 4), 0x00, 0x00};
|
||||
int ret;
|
||||
|
||||
if (index > LOGITECH_G300_PROFILE_MAX)
|
||||
@@ -237,14 +256,28 @@ logitech_g300_set_current_profile(struct ratbag_device *device, unsigned int ind
|
||||
ret = ratbag_hidraw_raw_request(device, buf[0], buf, sizeof(buf),
|
||||
HID_FEATURE_REPORT, HID_REQ_SET_REPORT);
|
||||
|
||||
return ret == sizeof(buf) ? 0 : ret;
|
||||
if (ret != sizeof(buf))
|
||||
return ret;
|
||||
|
||||
/* Update the active resolution. After profile change the default is used. */
|
||||
list_for_each(profile, &device->profiles, link) {
|
||||
struct ratbag_resolution *resolution;
|
||||
|
||||
if (profile->index != index)
|
||||
continue;
|
||||
|
||||
ratbag_profile_for_each_resolution(profile, resolution) {
|
||||
resolution->is_active = resolution->is_default;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if 0
|
||||
static int
|
||||
logitech_g300_set_current_resolution(struct ratbag_device *device, unsigned int index)
|
||||
{
|
||||
uint8_t buf[] = {LOGITECH_G300_REPORT_ID_SET_ACTIVE_PROFILE, 0x40 + index*2, 0x00, 0x00};
|
||||
uint8_t buf[] = {LOGITECH_G300_REPORT_ID_SET_ACTIVE, 0x40 | (index << 1), 0x00, 0x00};
|
||||
int ret;
|
||||
|
||||
if (index >= LOGITECH_G300_NUM_DPI)
|
||||
@@ -255,56 +288,6 @@ logitech_g300_set_current_resolution(struct ratbag_device *device, unsigned int
|
||||
|
||||
return ret == sizeof(buf) ? 0 : ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
static void
|
||||
logitech_g300_read_profile(struct ratbag_profile *profile, unsigned int index)
|
||||
{
|
||||
struct ratbag_device *device = profile->device;
|
||||
struct logitech_g300_data *drv_data = device->drv_data;
|
||||
struct logitech_g300_profile_data *pdata;
|
||||
struct logitech_g300_profile_report *report;
|
||||
struct ratbag_resolution *resolution;
|
||||
unsigned int i, hz;
|
||||
uint8_t report_id;
|
||||
int rc;
|
||||
|
||||
assert(index <= LOGITECH_G300_PROFILE_MAX);
|
||||
|
||||
pdata = &drv_data->profile_data[index];
|
||||
report = &pdata->report;
|
||||
|
||||
switch (index) {
|
||||
case 0: report_id = LOGITECH_G300_REPORT_ID_PROFILE_0; break;
|
||||
case 1: report_id = LOGITECH_G300_REPORT_ID_PROFILE_1; break;
|
||||
case 2: report_id = LOGITECH_G300_REPORT_ID_PROFILE_2; break;
|
||||
}
|
||||
|
||||
rc = ratbag_hidraw_raw_request(device, report_id,
|
||||
(uint8_t*)report,
|
||||
sizeof(*report),
|
||||
HID_FEATURE_REPORT,
|
||||
HID_REQ_GET_REPORT);
|
||||
|
||||
if (rc < (signed)sizeof(*report)) {
|
||||
log_error(device->ratbag,
|
||||
"Error while requesting profile: %d\n", rc);
|
||||
return;
|
||||
}
|
||||
|
||||
hz = logitech_g300_raw_to_frequency(report->frequency);
|
||||
|
||||
for (i = 0; i < profile->resolution.num_modes; i++) {
|
||||
struct logitech_g300_resolution *res =
|
||||
&report->dpi_levels[i];
|
||||
|
||||
resolution = &profile->resolution.modes[i];
|
||||
resolution->dpi_x = res->dpi * 250;
|
||||
resolution->dpi_y = res->dpi * 250;
|
||||
resolution->hz = hz;
|
||||
resolution->is_default = res->is_default;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
logitech_g300_read_button(struct ratbag_button *button)
|
||||
@@ -329,7 +312,7 @@ logitech_g300_read_button(struct ratbag_button *button)
|
||||
|
||||
action = logitech_g300_raw_to_button_action(button_report->code);
|
||||
if (action) {
|
||||
button->action = *action;
|
||||
ratbag_button_set_action(button, action);
|
||||
}
|
||||
else if (button_report->code == 0x00 && (button_report->modifier > 0x00 || button_report->key > 0x00))
|
||||
{
|
||||
@@ -341,19 +324,102 @@ logitech_g300_read_button(struct ratbag_button *button)
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
logitech_g300_read_led(struct ratbag_led *led)
|
||||
{
|
||||
struct ratbag_profile *profile = led->profile;
|
||||
struct ratbag_device *device = profile->device;
|
||||
struct logitech_g300_data *drv_data = device->drv_data;
|
||||
struct logitech_g300_profile_data *pdata;
|
||||
struct logitech_g300_profile_report *profile_report;
|
||||
|
||||
pdata = &drv_data->profile_data[profile->index];
|
||||
profile_report = &pdata->report;
|
||||
|
||||
led->type = RATBAG_LED_TYPE_SIDE;
|
||||
led->mode = RATBAG_LED_ON;
|
||||
led->colordepth = RATBAG_LED_COLORDEPTH_RGB_111;
|
||||
led->color.red = profile_report->led_red * 255;
|
||||
led->color.green = profile_report->led_green * 255;
|
||||
led->color.blue = profile_report->led_blue * 255;
|
||||
}
|
||||
|
||||
static void
|
||||
logitech_g300_read_profile(struct ratbag_profile *profile)
|
||||
{
|
||||
struct ratbag_device *device = profile->device;
|
||||
struct logitech_g300_data *drv_data = device->drv_data;
|
||||
struct logitech_g300_profile_data *pdata;
|
||||
struct logitech_g300_profile_report *report;
|
||||
struct ratbag_resolution *resolution;
|
||||
unsigned int hz;
|
||||
uint8_t report_id;
|
||||
int rc;
|
||||
struct ratbag_button *button;
|
||||
struct ratbag_led *led;
|
||||
|
||||
assert(profile->index <= LOGITECH_G300_PROFILE_MAX);
|
||||
|
||||
pdata = &drv_data->profile_data[profile->index];
|
||||
report = &pdata->report;
|
||||
|
||||
switch (profile->index) {
|
||||
case 0: report_id = LOGITECH_G300_REPORT_ID_PROFILE_0; break;
|
||||
case 1: report_id = LOGITECH_G300_REPORT_ID_PROFILE_1; break;
|
||||
case 2: report_id = LOGITECH_G300_REPORT_ID_PROFILE_2; break;
|
||||
}
|
||||
|
||||
rc = ratbag_hidraw_raw_request(device, report_id,
|
||||
(uint8_t*)report,
|
||||
sizeof(*report),
|
||||
HID_FEATURE_REPORT,
|
||||
HID_REQ_GET_REPORT);
|
||||
|
||||
if (rc < (int)sizeof(*report)) {
|
||||
log_error(device->ratbag,
|
||||
"Error while requesting profile: %d\n", rc);
|
||||
return;
|
||||
}
|
||||
|
||||
hz = logitech_g300_raw_to_frequency(report->frequency);
|
||||
|
||||
ratbag_profile_for_each_resolution(profile, resolution) {
|
||||
struct logitech_g300_resolution *res =
|
||||
&report->dpi_levels[resolution->index];
|
||||
unsigned int dpis[10] = { 250, 500, 750, 1000, 1250, 1500, 1750,
|
||||
2000, 2250, 2500 };
|
||||
|
||||
resolution->dpi_x = res->dpi * 250;
|
||||
resolution->dpi_y = res->dpi * 250;
|
||||
resolution->hz = hz;
|
||||
resolution->is_default = res->is_default;
|
||||
resolution->is_active = res->is_default;
|
||||
|
||||
ratbag_resolution_set_dpi_list(resolution, dpis,
|
||||
ARRAY_LENGTH(dpis));
|
||||
ratbag_resolution_set_report_rate_list(resolution, &hz, 1);
|
||||
}
|
||||
|
||||
ratbag_profile_for_each_button(profile, button)
|
||||
logitech_g300_read_button(button);
|
||||
|
||||
ratbag_profile_for_each_led(profile, led)
|
||||
logitech_g300_read_led(led);
|
||||
}
|
||||
|
||||
static int
|
||||
logitech_g300_test_hidraw(struct ratbag_device *device)
|
||||
{
|
||||
return ratbag_hidraw_has_report(device, LOGITECH_G300_REPORT_ID_GET_ACTIVE_PROFILE);
|
||||
return ratbag_hidraw_has_report(device, LOGITECH_G300_REPORT_ID_GET_ACTIVE);
|
||||
}
|
||||
|
||||
static int
|
||||
logitech_g300_probe(struct ratbag_device *device)
|
||||
{
|
||||
int rc;
|
||||
struct ratbag_profile *profile;
|
||||
struct logitech_g300_data *drv_data = NULL;
|
||||
int active_idx;
|
||||
struct ratbag_profile *profile;
|
||||
|
||||
rc = ratbag_find_hidraw(device, logitech_g300_test_hidraw);
|
||||
if (rc)
|
||||
@@ -369,6 +435,9 @@ logitech_g300_probe(struct ratbag_device *device)
|
||||
LOGITECH_G300_BUTTON_MAX + 1,
|
||||
LOGITECH_G300_NUM_LED);
|
||||
|
||||
ratbag_device_for_each_profile(device, profile)
|
||||
logitech_g300_read_profile(profile);
|
||||
|
||||
ratbag_device_set_capability(device, RATBAG_DEVICE_CAP_RESOLUTION);
|
||||
ratbag_device_set_capability(device, RATBAG_DEVICE_CAP_SWITCHABLE_RESOLUTION);
|
||||
ratbag_device_set_capability(device, RATBAG_DEVICE_CAP_PROFILE);
|
||||
@@ -376,7 +445,7 @@ logitech_g300_probe(struct ratbag_device *device)
|
||||
ratbag_device_set_capability(device, RATBAG_DEVICE_CAP_BUTTON);
|
||||
ratbag_device_set_capability(device, RATBAG_DEVICE_CAP_BUTTON_KEY);
|
||||
|
||||
active_idx = logitech_g300_current_profile(device);
|
||||
active_idx = logitech_g300_get_active_profile_and_resolution(device);
|
||||
|
||||
if (active_idx < 0) {
|
||||
log_error(device->ratbag,
|
||||
@@ -387,17 +456,10 @@ logitech_g300_probe(struct ratbag_device *device)
|
||||
goto err;
|
||||
}
|
||||
|
||||
list_for_each(profile, &device->profiles, link) {
|
||||
if (profile->index == (unsigned int)active_idx) {
|
||||
profile->is_active = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
log_raw(device->ratbag,
|
||||
"'%s' is in profile %d\n",
|
||||
ratbag_device_get_name(device),
|
||||
profile->index);
|
||||
active_idx);
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -414,24 +476,33 @@ logitech_g300_write_profile(struct ratbag_profile *profile)
|
||||
struct logitech_g300_data *drv_data = device->drv_data;
|
||||
struct logitech_g300_profile_data *pdata;
|
||||
struct logitech_g300_profile_report *report;
|
||||
struct ratbag_resolution *resolution;
|
||||
struct ratbag_button *button;
|
||||
struct ratbag_led *led;
|
||||
|
||||
uint8_t *buf;
|
||||
unsigned int hz, i;
|
||||
unsigned int hz;
|
||||
int rc;
|
||||
|
||||
pdata = &drv_data->profile_data[profile->index];
|
||||
report = &pdata->report;
|
||||
|
||||
/* The same hz is used for all resolutions */
|
||||
hz = profile->resolution.modes[0].hz;
|
||||
report->frequency = logitech_g300_frequency_to_raw(hz);
|
||||
|
||||
for (i = 0; i < profile->resolution.num_modes; i++) {
|
||||
struct ratbag_resolution *resolution = &profile->resolution.modes[i];
|
||||
struct logitech_g300_resolution *res = &report->dpi_levels[i];
|
||||
ratbag_profile_for_each_resolution(profile, resolution) {
|
||||
struct logitech_g300_resolution *res =
|
||||
&report->dpi_levels[resolution->index];
|
||||
|
||||
res->dpi = resolution->dpi_x / 250;
|
||||
res->is_default = resolution->is_default;
|
||||
|
||||
if (profile->is_active && resolution->is_active)
|
||||
logitech_g300_set_current_resolution(device,
|
||||
resolution->index);
|
||||
|
||||
/* The same hz is used for all resolutions */
|
||||
if (resolution->index == 0) {
|
||||
hz = resolution->hz;
|
||||
report->frequency = logitech_g300_frequency_to_raw(hz);
|
||||
}
|
||||
}
|
||||
|
||||
list_for_each(button, &profile->buttons, link) {
|
||||
@@ -452,6 +523,17 @@ logitech_g300_write_profile(struct ratbag_profile *profile)
|
||||
}
|
||||
}
|
||||
|
||||
list_for_each(led, &profile->leds, link) {
|
||||
if (!led->dirty)
|
||||
continue;
|
||||
|
||||
/* Clamp the 8 bit colors to 1 bit */
|
||||
report->led_red = led->color.red > 127;
|
||||
report->led_green = led->color.green > 127;
|
||||
report->led_blue = led->color.blue > 127;
|
||||
}
|
||||
|
||||
|
||||
buf = (uint8_t*)report;
|
||||
|
||||
rc = ratbag_hidraw_raw_request(device, report->id,
|
||||
@@ -460,7 +542,13 @@ logitech_g300_write_profile(struct ratbag_profile *profile)
|
||||
HID_FEATURE_REPORT,
|
||||
HID_REQ_SET_REPORT);
|
||||
|
||||
return rc;
|
||||
if (rc < (int)sizeof(*report)) {
|
||||
log_error(device->ratbag,
|
||||
"Error while writing profile: %d\n", rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
@@ -496,8 +584,6 @@ struct ratbag_driver logitech_g300_driver = {
|
||||
.id = "logitech_g300",
|
||||
.probe = logitech_g300_probe,
|
||||
.remove = logitech_g300_remove,
|
||||
.read_profile = logitech_g300_read_profile,
|
||||
.commit = logitech_g300_commit,
|
||||
.set_active_profile = logitech_g300_set_current_profile,
|
||||
.read_button = logitech_g300_read_button,
|
||||
.set_active_profile = logitech_g300_set_active_profile,
|
||||
};
|
||||
|
||||
@@ -391,83 +391,6 @@ roccat_button_to_action(struct ratbag_profile *profile,
|
||||
return roccat_raw_to_button_action(data);
|
||||
}
|
||||
|
||||
static void
|
||||
roccat_read_profile(struct ratbag_profile *profile, unsigned int index)
|
||||
{
|
||||
struct ratbag_device *device = profile->device;
|
||||
struct roccat_data *drv_data;
|
||||
struct ratbag_resolution *resolution;
|
||||
struct roccat_settings_report *setting_report;
|
||||
uint8_t *buf;
|
||||
unsigned int report_rate;
|
||||
unsigned int i;
|
||||
int dpi_x, dpi_y, hz;
|
||||
int rc;
|
||||
|
||||
assert(index <= ROCCAT_PROFILE_MAX);
|
||||
|
||||
drv_data = ratbag_get_drv_data(device);
|
||||
|
||||
setting_report = &drv_data->settings[index];
|
||||
buf = (uint8_t*)setting_report;
|
||||
roccat_set_config_profile(device, index, ROCCAT_CONFIG_SETTINGS);
|
||||
rc = ratbag_hidraw_raw_request(device, ROCCAT_REPORT_ID_SETTINGS,
|
||||
buf, ROCCAT_REPORT_SIZE_SETTINGS,
|
||||
HID_FEATURE_REPORT, HID_REQ_GET_REPORT);
|
||||
|
||||
if (rc < ROCCAT_REPORT_SIZE_SETTINGS)
|
||||
return;
|
||||
|
||||
/* first retrieve the report rate, it is set per profile */
|
||||
switch (setting_report->report_rate) {
|
||||
case 0x00: report_rate = 125; break;
|
||||
case 0x01: report_rate = 250; break;
|
||||
case 0x02: report_rate = 500; break;
|
||||
case 0x03: report_rate = 1000; break;
|
||||
default:
|
||||
log_error(device->ratbag,
|
||||
"error while reading the report rate of the mouse (0x%02x)\n",
|
||||
buf[26]);
|
||||
report_rate = 0;
|
||||
}
|
||||
|
||||
for (i = 0; i < profile->resolution.num_modes; i++) {
|
||||
dpi_x = setting_report->xres[i] * 50;
|
||||
dpi_y = setting_report->yres[i] * 50;
|
||||
hz = report_rate;
|
||||
if (!(setting_report->dpi_mask & (1 << i))) {
|
||||
/* the profile is disabled, overwrite it */
|
||||
dpi_x = 0;
|
||||
dpi_y = 0;
|
||||
hz = 0;
|
||||
}
|
||||
resolution = ratbag_resolution_init(profile, i, dpi_x, dpi_y, hz);
|
||||
ratbag_resolution_set_cap(resolution,
|
||||
RATBAG_RESOLUTION_CAP_SEPARATE_XY_RESOLUTION);
|
||||
resolution->is_active = (i == setting_report->current_dpi);
|
||||
}
|
||||
|
||||
buf = drv_data->profiles[index];
|
||||
roccat_set_config_profile(device, index, ROCCAT_CONFIG_KEY_MAPPING);
|
||||
rc = ratbag_hidraw_raw_request(device, ROCCAT_REPORT_ID_KEY_MAPPING,
|
||||
buf, ROCCAT_REPORT_SIZE_PROFILE,
|
||||
HID_FEATURE_REPORT, HID_REQ_GET_REPORT);
|
||||
|
||||
msleep(10);
|
||||
|
||||
if (rc < ROCCAT_REPORT_SIZE_PROFILE)
|
||||
return;
|
||||
|
||||
if (!roccat_crc_is_valid(device, buf, ROCCAT_REPORT_SIZE_PROFILE))
|
||||
log_error(device->ratbag,
|
||||
"Error while reading profile %d, continuing...\n",
|
||||
profile->index);
|
||||
|
||||
log_raw(device->ratbag, "profile: %d %s:%d\n",
|
||||
buf[2],
|
||||
__FILE__, __LINE__);
|
||||
}
|
||||
|
||||
static int
|
||||
roccat_write_profile(struct ratbag_profile *profile)
|
||||
{
|
||||
@@ -521,7 +444,7 @@ roccat_read_button(struct ratbag_button *button)
|
||||
drv_data = ratbag_get_drv_data(device);
|
||||
action = roccat_button_to_action(button->profile, button->index);
|
||||
if (action)
|
||||
button->action = *action;
|
||||
ratbag_button_set_action(button, action);
|
||||
button->type = roccat_raw_to_button_type(button->index);
|
||||
// if (action == NULL)
|
||||
// log_error(device->ratbag, "button: %d -> %d %s:%d\n",
|
||||
@@ -733,7 +656,6 @@ roccat_write_resolution_dpi(struct ratbag_resolution *resolution,
|
||||
struct ratbag_device *device = profile->device;
|
||||
struct roccat_data *drv_data = ratbag_get_drv_data(device);
|
||||
struct roccat_settings_report *settings_report;
|
||||
unsigned int index;
|
||||
uint8_t *buf;
|
||||
int rc;
|
||||
|
||||
@@ -744,11 +666,8 @@ roccat_write_resolution_dpi(struct ratbag_resolution *resolution,
|
||||
|
||||
settings_report = &drv_data->settings[profile->index];
|
||||
|
||||
/* retrieve which resolution is asked to be changed */
|
||||
index = resolution - profile->resolution.modes;
|
||||
|
||||
settings_report->xres[index] = dpi_x / 50;
|
||||
settings_report->yres[index] = dpi_y / 50;
|
||||
settings_report->xres[resolution->index] = dpi_x / 50;
|
||||
settings_report->yres[resolution->index] = dpi_y / 50;
|
||||
|
||||
buf = (uint8_t*)settings_report;
|
||||
|
||||
@@ -773,6 +692,88 @@ roccat_write_resolution_dpi(struct ratbag_resolution *resolution,
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void
|
||||
roccat_read_profile(struct ratbag_profile *profile)
|
||||
{
|
||||
struct ratbag_device *device = profile->device;
|
||||
struct roccat_data *drv_data;
|
||||
struct ratbag_resolution *resolution;
|
||||
struct ratbag_button *button;
|
||||
struct roccat_settings_report *setting_report;
|
||||
uint8_t *buf;
|
||||
unsigned int report_rate;
|
||||
int dpi_x, dpi_y, hz;
|
||||
int rc;
|
||||
unsigned int report_rates[] = { 125, 250, 500, 1000 };
|
||||
|
||||
assert(profile->index <= ROCCAT_PROFILE_MAX);
|
||||
|
||||
drv_data = ratbag_get_drv_data(device);
|
||||
|
||||
setting_report = &drv_data->settings[profile->index];
|
||||
buf = (uint8_t*)setting_report;
|
||||
roccat_set_config_profile(device, profile->index, ROCCAT_CONFIG_SETTINGS);
|
||||
rc = ratbag_hidraw_raw_request(device, ROCCAT_REPORT_ID_SETTINGS,
|
||||
buf, ROCCAT_REPORT_SIZE_SETTINGS,
|
||||
HID_FEATURE_REPORT, HID_REQ_GET_REPORT);
|
||||
|
||||
if (rc < ROCCAT_REPORT_SIZE_SETTINGS)
|
||||
return;
|
||||
|
||||
/* first retrieve the report rate, it is set per profile */
|
||||
if (setting_report->report_rate < ARRAY_LENGTH(report_rates)) {
|
||||
report_rate = report_rates[setting_report->report_rate];
|
||||
} else {
|
||||
log_error(device->ratbag,
|
||||
"error while reading the report rate of the mouse (0x%02x)\n",
|
||||
buf[26]);
|
||||
report_rate = 0;
|
||||
}
|
||||
|
||||
ratbag_profile_for_each_resolution(profile, resolution) {
|
||||
dpi_x = setting_report->xres[resolution->index] * 50;
|
||||
dpi_y = setting_report->yres[resolution->index] * 50;
|
||||
hz = report_rate;
|
||||
if (!(setting_report->dpi_mask & (1 << resolution->index))) {
|
||||
/* the profile is disabled, overwrite it */
|
||||
dpi_x = 0;
|
||||
dpi_y = 0;
|
||||
hz = 0;
|
||||
}
|
||||
|
||||
ratbag_resolution_set_resolution(resolution, dpi_x, dpi_y, hz);
|
||||
ratbag_resolution_set_cap(resolution,
|
||||
RATBAG_RESOLUTION_CAP_SEPARATE_XY_RESOLUTION);
|
||||
resolution->is_active = (resolution->index == setting_report->current_dpi);
|
||||
|
||||
ratbag_resolution_set_report_rate_list(resolution, report_rates,
|
||||
ARRAY_LENGTH(report_rates));
|
||||
}
|
||||
|
||||
ratbag_profile_for_each_button(profile, button)
|
||||
roccat_read_button(button);
|
||||
|
||||
buf = drv_data->profiles[profile->index];
|
||||
roccat_set_config_profile(device, profile->index, ROCCAT_CONFIG_KEY_MAPPING);
|
||||
rc = ratbag_hidraw_raw_request(device, ROCCAT_REPORT_ID_KEY_MAPPING,
|
||||
buf, ROCCAT_REPORT_SIZE_PROFILE,
|
||||
HID_FEATURE_REPORT, HID_REQ_GET_REPORT);
|
||||
|
||||
msleep(10);
|
||||
|
||||
if (rc < ROCCAT_REPORT_SIZE_PROFILE)
|
||||
return;
|
||||
|
||||
if (!roccat_crc_is_valid(device, buf, ROCCAT_REPORT_SIZE_PROFILE))
|
||||
log_error(device->ratbag,
|
||||
"Error while reading profile %d, continuing...\n",
|
||||
profile->index);
|
||||
|
||||
log_raw(device->ratbag, "profile: %d %s:%d\n",
|
||||
buf[2],
|
||||
__FILE__, __LINE__);
|
||||
}
|
||||
|
||||
static int
|
||||
roccat_probe(struct ratbag_device *device)
|
||||
{
|
||||
@@ -800,6 +801,9 @@ roccat_probe(struct ratbag_device *device)
|
||||
ROCCAT_BUTTON_MAX + 1,
|
||||
ROCCAT_LED_MAX);
|
||||
|
||||
ratbag_device_for_each_profile(device, profile)
|
||||
roccat_read_profile(profile);
|
||||
|
||||
ratbag_device_set_capability(device, RATBAG_DEVICE_CAP_BUTTON);
|
||||
ratbag_device_set_capability(device, RATBAG_DEVICE_CAP_BUTTON_MACROS);
|
||||
|
||||
@@ -845,10 +849,8 @@ struct ratbag_driver roccat_driver = {
|
||||
.id = "roccat",
|
||||
.probe = roccat_probe,
|
||||
.remove = roccat_remove,
|
||||
.read_profile = roccat_read_profile,
|
||||
.write_profile = roccat_write_profile,
|
||||
.set_active_profile = roccat_set_current_profile,
|
||||
.read_button = roccat_read_button,
|
||||
.write_button = roccat_write_button,
|
||||
.write_resolution_dpi = roccat_write_resolution_dpi,
|
||||
};
|
||||
|
||||
533
src/driver-steelseries.c
Normal file
@@ -0,0 +1,533 @@
|
||||
/*
|
||||
* Copyright © 2017 Thomas Hindoe Paaboel Andersen.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the next
|
||||
* paragraph) shall be included in all copies or substantial portions of the
|
||||
* Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <libevdev/libevdev.h>
|
||||
#include <linux/input.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "libratbag-private.h"
|
||||
#include "libratbag-hidraw.h"
|
||||
#include "libratbag-data.h"
|
||||
#include "hidpp-generic.h"
|
||||
|
||||
#define STEELSERIES_NUM_PROFILES 1
|
||||
#define STEELSERIES_NUM_DPI 2
|
||||
|
||||
/* not sure these two are used for */
|
||||
#define STEELSERIES_REPORT_ID_1 0x01
|
||||
#define STEELSERIES_REPORT_ID_2 0x02
|
||||
|
||||
#define STEELSERIES_REPORT_SIZE_SHORT 32
|
||||
#define STEELSERIES_REPORT_SIZE 64
|
||||
#define STEELSERIES_REPORT_LONG_SIZE 262
|
||||
|
||||
#define STEELSERIES_ID_DPI_SHORT 0x03
|
||||
#define STEELSERIES_ID_REPORT_RATE_SHORT 0x04
|
||||
#define STEELSERIES_ID_SAVE_SHORT 0x09
|
||||
|
||||
#define STEELSERIES_ID_BUTTONS 0x31
|
||||
#define STEELSERIES_ID_DPI 0x53
|
||||
#define STEELSERIES_ID_REPORT_RATE 0x54
|
||||
#define STEELSERIES_ID_LED 0x5b
|
||||
#define STEELSERIES_ID_SAVE 0x59
|
||||
|
||||
#define STEELSERIES_BUTTON_OFF 0x00
|
||||
#define STEELSERIES_BUTTON_RES_CYCLE 0x30
|
||||
#define STEELSERIES_BUTTON_WHEEL_UP 0x31
|
||||
#define STEELSERIES_BUTTON_WHEEL_DOWN 0x32
|
||||
#define STEELSERIES_BUTTON_KBD 0x51
|
||||
#define STEELSERIES_BUTTON_CONSUMER 0x61
|
||||
|
||||
static const enum ratbag_button_type button_types[6] =
|
||||
{
|
||||
RATBAG_BUTTON_TYPE_LEFT,
|
||||
RATBAG_BUTTON_TYPE_RIGHT,
|
||||
RATBAG_BUTTON_TYPE_MIDDLE,
|
||||
RATBAG_BUTTON_TYPE_THUMB,
|
||||
RATBAG_BUTTON_TYPE_THUMB2,
|
||||
RATBAG_BUTTON_TYPE_RESOLUTION_CYCLE_UP,
|
||||
};
|
||||
|
||||
static const struct ratbag_button_action button_actions[6] =
|
||||
{
|
||||
BUTTON_ACTION_BUTTON(1),
|
||||
BUTTON_ACTION_BUTTON(2),
|
||||
BUTTON_ACTION_BUTTON(3),
|
||||
BUTTON_ACTION_BUTTON(4),
|
||||
BUTTON_ACTION_BUTTON(5),
|
||||
BUTTON_ACTION_SPECIAL(RATBAG_BUTTON_ACTION_SPECIAL_RESOLUTION_CYCLE_UP),
|
||||
};
|
||||
|
||||
static int
|
||||
steelseries_test_hidraw(struct ratbag_device *device)
|
||||
{
|
||||
int device_version = ratbag_device_data_steelseries_get_device_version(device->data);
|
||||
|
||||
if (device_version > 1)
|
||||
return ratbag_hidraw_has_report(device, STEELSERIES_REPORT_ID_1);
|
||||
else
|
||||
return true;
|
||||
}
|
||||
|
||||
static int
|
||||
steelseries_probe(struct ratbag_device *device)
|
||||
{
|
||||
struct ratbag_profile *profile = NULL;
|
||||
struct ratbag_resolution *resolution;
|
||||
struct ratbag_button *button;
|
||||
struct ratbag_led *led;
|
||||
int rc, button_count, led_count, device_version;
|
||||
_cleanup_(dpi_list_freep) struct dpi_list *dpilist = NULL;
|
||||
_cleanup_(freep) struct dpi_range *dpirange = NULL;
|
||||
|
||||
unsigned int report_rates[] = { 125, 250, 500, 1000 };
|
||||
|
||||
rc = ratbag_find_hidraw(device, steelseries_test_hidraw);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
device_version = ratbag_device_data_steelseries_get_device_version(device->data);
|
||||
button_count = ratbag_device_data_steelseries_get_button_count(device->data);
|
||||
led_count = ratbag_device_data_steelseries_get_led_count(device->data);
|
||||
dpirange = ratbag_device_data_steelseries_get_dpi_range(device->data);
|
||||
dpilist = ratbag_device_data_steelseries_get_dpi_list(device->data);
|
||||
|
||||
ratbag_device_init_profiles(device,
|
||||
STEELSERIES_NUM_PROFILES,
|
||||
STEELSERIES_NUM_DPI,
|
||||
button_count,
|
||||
led_count);
|
||||
|
||||
/* only later models allow setting buttons on the device */
|
||||
if (device_version > 1) {
|
||||
/* set these caps manually as they are not assumed with only 1 profile */
|
||||
ratbag_device_set_capability(device, RATBAG_DEVICE_CAP_BUTTON);
|
||||
ratbag_device_set_capability(device, RATBAG_DEVICE_CAP_BUTTON_KEY);
|
||||
}
|
||||
|
||||
ratbag_device_unset_capability(device, RATBAG_DEVICE_CAP_QUERY_CONFIGURATION);
|
||||
|
||||
/* The device does not support reading the current settings. Fall back
|
||||
to some sensible defaults */
|
||||
ratbag_device_for_each_profile(device, profile) {
|
||||
profile->is_active = true;
|
||||
|
||||
ratbag_profile_for_each_resolution(profile, resolution) {
|
||||
if (resolution->index == 0) {
|
||||
resolution->is_active = true;
|
||||
resolution->is_default = true;
|
||||
}
|
||||
|
||||
if (dpirange)
|
||||
ratbag_resolution_set_dpi_list_from_range(resolution,
|
||||
dpirange->min,
|
||||
dpirange->max);
|
||||
if (dpilist)
|
||||
ratbag_resolution_set_dpi_list(resolution,
|
||||
(unsigned int *)dpilist->entries,
|
||||
dpilist->nentries);
|
||||
|
||||
resolution->dpi_x = resolution->dpis[resolution->index];
|
||||
resolution->dpi_y = resolution->dpis[resolution->index];
|
||||
|
||||
ratbag_resolution_set_report_rate_list(resolution, report_rates,
|
||||
ARRAY_LENGTH(report_rates));
|
||||
resolution->hz = 1000;
|
||||
}
|
||||
|
||||
ratbag_profile_for_each_button(profile, button) {
|
||||
ratbag_button_enable_action_type(button, RATBAG_BUTTON_ACTION_TYPE_BUTTON);
|
||||
ratbag_button_enable_action_type(button, RATBAG_BUTTON_ACTION_TYPE_SPECIAL);
|
||||
ratbag_button_enable_action_type(button, RATBAG_BUTTON_ACTION_TYPE_KEY);
|
||||
|
||||
button->type = button_types[button->index];
|
||||
ratbag_button_set_action(button, &button_actions[button->index]);
|
||||
}
|
||||
|
||||
ratbag_profile_for_each_led(profile, led) {
|
||||
led->type = led->index == 0 ? RATBAG_LED_TYPE_LOGO : RATBAG_LED_TYPE_WHEEL;
|
||||
led->mode = RATBAG_LED_ON;
|
||||
led->colordepth = RATBAG_LED_COLORDEPTH_RGB_888;
|
||||
led->color.red = 0;
|
||||
led->color.green = 0;
|
||||
led->color.blue = 255;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
steelseries_write_dpi(struct ratbag_resolution *resolution)
|
||||
{
|
||||
struct ratbag_device *device = resolution->profile->device;
|
||||
int device_version = ratbag_device_data_steelseries_get_device_version(device->data);
|
||||
struct dpi_list *dpilist = NULL;
|
||||
struct dpi_range *dpirange = NULL;
|
||||
int ret;
|
||||
size_t buf_len;
|
||||
uint8_t buf[STEELSERIES_REPORT_SIZE] = {0};
|
||||
|
||||
dpirange = ratbag_device_data_steelseries_get_dpi_range(device->data);
|
||||
dpilist = ratbag_device_data_steelseries_get_dpi_list(device->data);
|
||||
|
||||
if (device_version == 1) {
|
||||
int i = 0;
|
||||
|
||||
/* when using lists the entries are enumerated in reverse */
|
||||
if (dpilist) {
|
||||
for (i = 0; i < (int)resolution->ndpis; i++) {
|
||||
if (resolution->dpis[i] == resolution->dpi_x)
|
||||
break;
|
||||
}
|
||||
i = resolution->ndpis - i;
|
||||
} else {
|
||||
i = resolution->dpi_x / dpirange->step - 1;
|
||||
}
|
||||
|
||||
buf_len = STEELSERIES_REPORT_SIZE_SHORT;
|
||||
buf[0] = STEELSERIES_ID_DPI_SHORT;
|
||||
buf[1] = resolution->index + 1;
|
||||
buf[2] = i;
|
||||
} else {
|
||||
buf_len = STEELSERIES_REPORT_SIZE;
|
||||
buf[0] = STEELSERIES_ID_DPI;
|
||||
buf[2] = resolution->index + 1;
|
||||
buf[3] = resolution->dpi_x / dpirange->step - 1;
|
||||
buf[6] = 0x42; /* not sure if needed */
|
||||
}
|
||||
|
||||
ret = ratbag_hidraw_output_report(device, buf, buf_len);
|
||||
if ((size_t)ret != buf_len)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
steelseries_write_report_rate(struct ratbag_resolution *resolution)
|
||||
{
|
||||
struct ratbag_device *device = resolution->profile->device;
|
||||
int device_version = ratbag_device_data_steelseries_get_device_version(device->data);
|
||||
int ret;
|
||||
size_t buf_len;
|
||||
uint8_t buf[STEELSERIES_REPORT_SIZE] = {0};
|
||||
|
||||
if (device_version == 1) {
|
||||
buf_len = STEELSERIES_REPORT_SIZE_SHORT;
|
||||
buf[0] = STEELSERIES_ID_REPORT_RATE_SHORT;
|
||||
buf[2] = 1000 / resolution->hz;
|
||||
} else {
|
||||
buf_len = STEELSERIES_REPORT_SIZE;
|
||||
buf[0] = STEELSERIES_ID_REPORT_RATE;
|
||||
buf[2] = 1000 / resolution->hz;
|
||||
}
|
||||
|
||||
ret = ratbag_hidraw_output_report(device, buf, buf_len);
|
||||
if ((size_t)ret != buf_len)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
steelseries_write_buttons(struct ratbag_profile *profile)
|
||||
{
|
||||
struct ratbag_device *device = profile->device;
|
||||
int device_version = ratbag_device_data_steelseries_get_device_version(device->data);
|
||||
uint8_t buf[STEELSERIES_REPORT_LONG_SIZE] = {0};
|
||||
struct ratbag_button *button;
|
||||
int ret;
|
||||
|
||||
if (device_version < 2)
|
||||
return 0;
|
||||
|
||||
buf[0] = STEELSERIES_ID_BUTTONS;
|
||||
|
||||
ratbag_profile_for_each_button(profile, button) {
|
||||
struct ratbag_button_action *action = &button->action;
|
||||
uint16_t code;
|
||||
int idx;
|
||||
|
||||
/* Each button takes up 5 bytes starting from index 2 */
|
||||
idx = 2 + button->index * 5;
|
||||
|
||||
switch (action->type) {
|
||||
case RATBAG_BUTTON_ACTION_TYPE_BUTTON:
|
||||
buf[idx] = action->action.button;
|
||||
break;
|
||||
|
||||
case RATBAG_BUTTON_ACTION_TYPE_KEY:
|
||||
code = ratbag_hidraw_get_keyboard_usage_from_keycode(
|
||||
device, action->action.key.key);
|
||||
if (code) {
|
||||
buf[idx] = STEELSERIES_BUTTON_KBD;
|
||||
buf[idx + 1] = code;
|
||||
} else {
|
||||
code = ratbag_hidraw_get_consumer_usage_from_keycode(
|
||||
device, action->action.key.key);
|
||||
buf[idx] = STEELSERIES_BUTTON_CONSUMER;
|
||||
buf[idx + 1] = code;
|
||||
}
|
||||
break;
|
||||
|
||||
case RATBAG_BUTTON_ACTION_TYPE_SPECIAL:
|
||||
switch (action->action.special) {
|
||||
case RATBAG_BUTTON_ACTION_SPECIAL_RESOLUTION_CYCLE_UP:
|
||||
buf[idx] = STEELSERIES_BUTTON_RES_CYCLE;
|
||||
break;
|
||||
case RATBAG_BUTTON_ACTION_SPECIAL_WHEEL_UP:
|
||||
buf[idx] = STEELSERIES_BUTTON_WHEEL_UP;
|
||||
break;
|
||||
case RATBAG_BUTTON_ACTION_SPECIAL_WHEEL_DOWN:
|
||||
buf[idx] = STEELSERIES_BUTTON_WHEEL_DOWN;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case RATBAG_BUTTON_ACTION_TYPE_NONE:
|
||||
default:
|
||||
buf[idx] = STEELSERIES_BUTTON_OFF;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ret = ratbag_hidraw_output_report(device, buf, sizeof(buf));
|
||||
if (ret != sizeof(buf))
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
steelseries_write_led(struct ratbag_led *led)
|
||||
{
|
||||
struct ratbag_device *device = led->profile->device;
|
||||
uint8_t buf[STEELSERIES_REPORT_SIZE] = {0};
|
||||
uint16_t duration, min_duration;
|
||||
int ret;
|
||||
|
||||
buf[0] = STEELSERIES_ID_LED;
|
||||
buf[2] = led->index;
|
||||
|
||||
/* not sure if these two are needed */
|
||||
buf[15] = 0x01;
|
||||
buf[17] = 0x01;
|
||||
|
||||
switch(led->mode) {
|
||||
case RATBAG_LED_OFF:
|
||||
buf[19] = 0x01;
|
||||
buf[27] = 0x01;
|
||||
buf[28] = buf[31] = 0x00;
|
||||
buf[29] = buf[32] = 0x00;
|
||||
buf[30] = buf[33] = 0x00;
|
||||
/* not sure why the duration is set for the steady color or why
|
||||
it is different for the two LEDs */
|
||||
duration = led->index == 0 ? 10000 : 5000; /* 0x1027 or 0x8813 */
|
||||
break;
|
||||
case RATBAG_LED_ON:
|
||||
buf[19] = 0x01;
|
||||
buf[27] = 0x01;
|
||||
buf[28] = buf[31] = led->color.red;
|
||||
buf[29] = buf[32] = led->color.green;
|
||||
buf[30] = buf[33] = led->color.blue;
|
||||
|
||||
/* not sure why the duration is set for the steady color or why
|
||||
it is different for the two LEDs */
|
||||
duration = led->index == 0 ? 10000 : 5000; /* 0x1027 or 0x8813 */
|
||||
break;
|
||||
case RATBAG_LED_CYCLE:
|
||||
buf[27] = 0x04; /* number of steps in cycle */
|
||||
|
||||
/* start color */
|
||||
buf[28] = buf[31] = 0xFF;
|
||||
buf[29] = buf[32] = 0x00;
|
||||
buf[30] = buf[33] = 0x00;
|
||||
|
||||
/* Cycle to green */
|
||||
buf[35] = 0x00;
|
||||
buf[36] = 0xFF;
|
||||
buf[37] = 0x00;
|
||||
buf[38] = 0x54; /* normalized time share of animation */
|
||||
|
||||
/* Cycle to blue */
|
||||
buf[39] = 0x00;
|
||||
buf[40] = 0x00;
|
||||
buf[41] = 0xFF;
|
||||
buf[42] = 0x54; /* normalized time share of animation */
|
||||
|
||||
/* Cycle to red */
|
||||
buf[43] = 0xFF;
|
||||
buf[44] = 0x00;
|
||||
buf[45] = 0x00;
|
||||
buf[46] = 0x56; /* normalized time share of animation */
|
||||
|
||||
duration = led->ms;
|
||||
break;
|
||||
case RATBAG_LED_BREATHING:
|
||||
buf[27] = 0x03; /* number of steps in cycle */
|
||||
|
||||
/* start color */
|
||||
buf[28] = buf[31] = led->color.red;
|
||||
buf[29] = buf[32] = led->color.green;
|
||||
buf[30] = buf[33] = led->color.blue;
|
||||
|
||||
/* Cycle to black */
|
||||
buf[35] = 0x00;
|
||||
buf[36] = 0x00;
|
||||
buf[37] = 0x00;
|
||||
buf[38] = 0x7F; /* normalized time share of animation */
|
||||
|
||||
/* Cycle to selected color */
|
||||
buf[39] = led->color.red;
|
||||
buf[40] = led->color.green;
|
||||
buf[41] = led->color.blue;
|
||||
buf[42] = 0x7F; /* normalized time share of animation */
|
||||
|
||||
duration = led->ms;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* this seems to be the minimum allowed */
|
||||
min_duration = buf[27] * 330;
|
||||
if (duration < min_duration)
|
||||
duration = min_duration;
|
||||
|
||||
hidpp_set_unaligned_le_u16(&buf[3], duration);
|
||||
|
||||
ret = ratbag_hidraw_output_report(device, buf, sizeof(buf));
|
||||
if (ret != sizeof(buf))
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
steelseries_write_save(struct ratbag_device *device)
|
||||
{
|
||||
int device_version = ratbag_device_data_steelseries_get_device_version(device->data);
|
||||
int ret;
|
||||
size_t buf_len;
|
||||
uint8_t buf[STEELSERIES_REPORT_SIZE] = {0};
|
||||
|
||||
if (device_version == 1) {
|
||||
buf_len = STEELSERIES_REPORT_SIZE_SHORT;
|
||||
buf[0] = STEELSERIES_ID_SAVE_SHORT;
|
||||
} else {
|
||||
buf_len = STEELSERIES_REPORT_SIZE;
|
||||
buf[0] = STEELSERIES_ID_SAVE;
|
||||
}
|
||||
|
||||
ret = ratbag_hidraw_output_report(device, buf, buf_len);
|
||||
if ((size_t)ret != buf_len)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
steelseries_write_profile(struct ratbag_profile *profile)
|
||||
{
|
||||
struct ratbag_resolution *resolution;
|
||||
struct ratbag_led *led;
|
||||
int rc;
|
||||
|
||||
ratbag_profile_for_each_resolution(profile, resolution) {
|
||||
rc = steelseries_write_dpi(resolution);
|
||||
if (rc != 0)
|
||||
return rc;
|
||||
|
||||
/* The same hz is used for all resolutions. Only write once. */
|
||||
if (resolution->index > 0)
|
||||
continue;
|
||||
|
||||
rc = steelseries_write_report_rate(resolution);
|
||||
if (rc != 0)
|
||||
return rc;
|
||||
}
|
||||
|
||||
rc = steelseries_write_buttons(profile);
|
||||
if (rc != 0)
|
||||
return rc;
|
||||
|
||||
ratbag_profile_for_each_led(profile, led) {
|
||||
if (!led->dirty)
|
||||
continue;
|
||||
|
||||
rc = steelseries_write_led(led);
|
||||
if (rc != 0)
|
||||
return rc;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
steelseries_commit(struct ratbag_device *device)
|
||||
{
|
||||
struct ratbag_profile *profile;
|
||||
int rc = 0;
|
||||
|
||||
list_for_each(profile, &device->profiles, link) {
|
||||
if (!profile->dirty)
|
||||
continue;
|
||||
|
||||
log_debug(device->ratbag,
|
||||
"Profile %d changed, rewriting\n", profile->index);
|
||||
|
||||
rc = steelseries_write_profile(profile);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
/* persist the current settings on the device */
|
||||
|
||||
rc = steelseries_write_save(device);
|
||||
if (rc)
|
||||
return rc;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
steelseries_remove(struct ratbag_device *device)
|
||||
{
|
||||
ratbag_close_hidraw(device);
|
||||
}
|
||||
|
||||
struct ratbag_driver steelseries_driver = {
|
||||
.name = "SteelSeries",
|
||||
.id = "steelseries",
|
||||
.probe = steelseries_probe,
|
||||
.remove = steelseries_remove,
|
||||
.commit = steelseries_commit,
|
||||
};
|
||||
@@ -29,49 +29,6 @@
|
||||
#include "libratbag-private.h"
|
||||
#include "libratbag-test.h"
|
||||
|
||||
static void
|
||||
test_read_profile(struct ratbag_profile *profile, unsigned int index)
|
||||
{
|
||||
struct ratbag_test_device *d = ratbag_get_drv_data(profile->device);
|
||||
struct ratbag_test_profile *p;
|
||||
struct ratbag_test_resolution *r;
|
||||
struct ratbag_resolution *res;
|
||||
unsigned int i;
|
||||
bool active_set = false;
|
||||
bool default_set = false;
|
||||
|
||||
assert(index < d->num_profiles);
|
||||
|
||||
p = &d->profiles[index];
|
||||
for (i = 0; i < d->num_resolutions; i++) {
|
||||
r = &p->resolutions[i];
|
||||
res = ratbag_resolution_init(profile, i, r->xres, r->yres, r->hz);
|
||||
res->is_active = r->active;
|
||||
if (r->active)
|
||||
active_set = true;
|
||||
res->is_default = r->dflt;
|
||||
if (r->dflt)
|
||||
default_set = true;
|
||||
ratbag_resolution_set_cap(res, r->caps);
|
||||
res->hz = r->hz;
|
||||
assert(res);
|
||||
}
|
||||
|
||||
/* special case triggered by the test suite when num_resolutions is 0 */
|
||||
if (d->num_resolutions) {
|
||||
res = ratbag_profile_get_resolution(profile, 0);
|
||||
assert(res);
|
||||
if (!active_set)
|
||||
res->is_active = true;
|
||||
if (!default_set)
|
||||
res->is_default = true;
|
||||
ratbag_resolution_unref(res);
|
||||
}
|
||||
|
||||
profile->is_active = p->active;
|
||||
profile->is_enabled = !p->disabled;
|
||||
}
|
||||
|
||||
static int
|
||||
test_write_profile(struct ratbag_profile *profile)
|
||||
{
|
||||
@@ -149,6 +106,11 @@ test_read_led(struct ratbag_led *led)
|
||||
struct ratbag_test_profile *p = &d->profiles[led->profile->index];
|
||||
struct ratbag_test_led t_led = p->leds[led->index];
|
||||
|
||||
ratbag_led_set_mode_capability(led, RATBAG_LED_ON);
|
||||
ratbag_led_set_mode_capability(led, RATBAG_LED_CYCLE);
|
||||
ratbag_led_set_mode_capability(led, RATBAG_LED_BREATHING);
|
||||
ratbag_led_set_mode_capability(led, RATBAG_LED_OFF);
|
||||
|
||||
switch (t_led.mode) {
|
||||
case RATBAG_LED_ON:
|
||||
led->mode = RATBAG_LED_ON;
|
||||
@@ -165,8 +127,13 @@ test_read_led(struct ratbag_led *led)
|
||||
led->color.red = t_led.color.red;
|
||||
led->color.green = t_led.color.green;
|
||||
led->color.blue = t_led.color.blue;
|
||||
led->hz = t_led.hz;
|
||||
led->ms = t_led.ms;
|
||||
led->brightness = t_led.brightness;
|
||||
|
||||
/* The led type has to be the same anyway so make writing test
|
||||
* devices easier by always getting the first profile's LED type.
|
||||
*/
|
||||
led->type = d->profiles[0].leds[led->index].type;
|
||||
}
|
||||
|
||||
static int
|
||||
@@ -181,7 +148,7 @@ test_write_button(struct ratbag_button *button,
|
||||
static int
|
||||
test_write_led(struct ratbag_led *led,
|
||||
enum ratbag_led_mode mode,
|
||||
struct ratbag_color color, unsigned int hz,
|
||||
struct ratbag_color color, unsigned int ms,
|
||||
unsigned int brightness)
|
||||
{
|
||||
/* check if the device is still valid */
|
||||
@@ -202,10 +169,91 @@ test_fake_probe(struct ratbag_device *device)
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
static void
|
||||
test_read_profile(struct ratbag_profile *profile)
|
||||
{
|
||||
struct ratbag_test_device *d = ratbag_get_drv_data(profile->device);
|
||||
struct ratbag_test_profile *p;
|
||||
struct ratbag_test_profile *p0;
|
||||
struct ratbag_test_resolution *r;
|
||||
struct ratbag_test_resolution *r0;
|
||||
struct ratbag_button *button;
|
||||
struct ratbag_led *led;
|
||||
unsigned int i;
|
||||
bool active_set = false;
|
||||
bool default_set = false;
|
||||
|
||||
assert(profile->index < d->num_profiles);
|
||||
|
||||
p = &d->profiles[profile->index];
|
||||
p0 = &d->profiles[0];
|
||||
r0 = &p0->resolutions[0];
|
||||
|
||||
for (i = 0; i < d->num_resolutions; i++) {
|
||||
_cleanup_resolution_ struct ratbag_resolution *res;
|
||||
size_t nrates = 0;
|
||||
|
||||
r = &p->resolutions[i];
|
||||
|
||||
res = ratbag_profile_get_resolution(profile, i);
|
||||
assert(res);
|
||||
ratbag_resolution_set_resolution(res, r->xres, r->yres, r->hz);
|
||||
if (r0->dpi_min != 0 && r0->dpi_max != 0)
|
||||
ratbag_resolution_set_dpi_list_from_range(res,
|
||||
r0->dpi_min,
|
||||
r0->dpi_max);
|
||||
|
||||
for (size_t r = 0; r < ARRAY_LENGTH(r0->report_rates); r++) {
|
||||
if (r0->report_rates[r] > 0)
|
||||
nrates++;
|
||||
}
|
||||
|
||||
if (nrates > 0)
|
||||
ratbag_resolution_set_report_rate_list(res,
|
||||
r0->report_rates,
|
||||
nrates);
|
||||
|
||||
res->is_active = r->active;
|
||||
if (r->active)
|
||||
active_set = true;
|
||||
res->is_default = r->dflt;
|
||||
if (r->dflt)
|
||||
default_set = true;
|
||||
ratbag_resolution_set_cap(res, r->caps);
|
||||
res->hz = r->hz;
|
||||
}
|
||||
|
||||
/* special case triggered by the test suite when num_resolutions is 0 */
|
||||
if (d->num_resolutions) {
|
||||
_cleanup_resolution_ struct ratbag_resolution *res;
|
||||
|
||||
res = ratbag_profile_get_resolution(profile, 0);
|
||||
assert(res);
|
||||
if (!active_set)
|
||||
res->is_active = true;
|
||||
if (!default_set)
|
||||
res->is_default = true;
|
||||
}
|
||||
|
||||
ratbag_profile_for_each_button(profile, button)
|
||||
test_read_button(button);
|
||||
|
||||
ratbag_profile_for_each_led(profile, led)
|
||||
test_read_led(led);
|
||||
|
||||
profile->is_active = p->active;
|
||||
profile->is_enabled = !p->disabled;
|
||||
|
||||
for (i = 0; i < ARRAY_LENGTH(p->caps) && p->caps[i]; i++) {
|
||||
ratbag_profile_set_cap(profile, p->caps[i]);
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
test_probe(struct ratbag_device *device, const void *data)
|
||||
{
|
||||
struct ratbag_test_device *test_device;
|
||||
struct ratbag_profile *profile;
|
||||
|
||||
test_device = zalloc(sizeof(*test_device));
|
||||
memcpy(test_device, data, sizeof(*test_device));
|
||||
@@ -216,11 +264,15 @@ test_probe(struct ratbag_device *device, const void *data)
|
||||
test_device->num_resolutions,
|
||||
test_device->num_buttons,
|
||||
test_device->num_leds);
|
||||
|
||||
if (test_device->num_profiles > 1) {
|
||||
ratbag_device_set_capability(device, RATBAG_DEVICE_CAP_BUTTON_MACROS);
|
||||
ratbag_device_set_capability(device, RATBAG_DEVICE_CAP_DISABLE_PROFILE);
|
||||
}
|
||||
|
||||
ratbag_device_for_each_profile(device, profile)
|
||||
test_read_profile(profile);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -244,11 +296,8 @@ struct ratbag_driver test_driver = {
|
||||
.test_probe = test_probe,
|
||||
.remove = test_remove,
|
||||
.get_svg_name = test_get_svg_name,
|
||||
.read_profile = test_read_profile,
|
||||
.write_profile = test_write_profile,
|
||||
.set_active_profile = test_set_active_profile,
|
||||
.read_button = test_read_button,
|
||||
.read_led = test_read_led,
|
||||
.write_button = test_write_button,
|
||||
.write_resolution_dpi = NULL,
|
||||
.write_led = test_write_led,
|
||||
|
||||
111
src/hidpp10.c
@@ -114,57 +114,23 @@ hidpp10_dpi_table_get_min_dpi(struct hidpp10_device *dev)
|
||||
|
||||
int
|
||||
hidpp10_build_dpi_table_from_list(struct hidpp10_device *dev,
|
||||
const char *str_list)
|
||||
const struct dpi_list *list)
|
||||
{
|
||||
unsigned int i, count, index;
|
||||
int nread, dpi = 0;
|
||||
char c;
|
||||
/*
|
||||
* str_list is in the form:
|
||||
* "0;200;400;600;800;1000;1200"
|
||||
*/
|
||||
size_t i;
|
||||
|
||||
/* first, count how many elements do we have in the table */
|
||||
count = 1;
|
||||
i = 0;
|
||||
while (str_list[i] != 0) {
|
||||
c = str_list[i++];
|
||||
if (c == ';')
|
||||
count++;
|
||||
}
|
||||
|
||||
index = 0;
|
||||
|
||||
/* check that the max raw value fits in a uint8_t */
|
||||
if (count + 0x80 - 1> 0xff)
|
||||
return -EINVAL;
|
||||
|
||||
dev->dpi_count = count;
|
||||
dev->dpi_table = zalloc(count * sizeof(*dev->dpi_table));
|
||||
|
||||
while (*str_list != 0 && index < count) {
|
||||
if (*str_list == ';') {
|
||||
str_list++;
|
||||
continue;
|
||||
}
|
||||
|
||||
nread = 0;
|
||||
sscanf(str_list, "%d%n", &dpi, &nread);
|
||||
if (!nread || dpi < 0)
|
||||
goto err;
|
||||
|
||||
dev->dpi_table[index].raw_value = index + 0x80;
|
||||
dev->dpi_table[index].dpi = dpi;
|
||||
|
||||
str_list += nread;
|
||||
index++;
|
||||
}
|
||||
|
||||
if (index != count)
|
||||
if (list->nentries + 0x80 - 1> 0xff)
|
||||
goto err;
|
||||
|
||||
return 0;
|
||||
dev->dpi_count = list->nentries;
|
||||
dev->dpi_table = zalloc(list->nentries * sizeof(*dev->dpi_table));
|
||||
dev->dpi_table_is_range = false;
|
||||
|
||||
for (i = 0; i < list->nentries; i++) {
|
||||
dev->dpi_table[i].raw_value = i + 0x80;
|
||||
dev->dpi_table[i].dpi = list->entries[i];
|
||||
}
|
||||
|
||||
return 0;
|
||||
err:
|
||||
dev->dpi_count = 0;
|
||||
free(dev->dpi_table);
|
||||
@@ -174,30 +140,22 @@ err:
|
||||
|
||||
int
|
||||
hidpp10_build_dpi_table_from_dpi_info(struct hidpp10_device *dev,
|
||||
const char *str_dpi)
|
||||
const struct dpi_range *range)
|
||||
{
|
||||
float min, max, step;
|
||||
unsigned raw_max, i;
|
||||
int rc;
|
||||
/*
|
||||
* str_list is in the form:
|
||||
* "MIN:MAX@STEP"
|
||||
*/
|
||||
|
||||
rc = sscanf(str_dpi, "%f:%f@%f", &min, &max, &step);
|
||||
if (rc != 3)
|
||||
return -EINVAL;
|
||||
|
||||
raw_max = (max - min) / step;
|
||||
raw_max = (range->max - range->min) / range->step;
|
||||
if (raw_max > 0xff)
|
||||
return -EINVAL;
|
||||
|
||||
dev->dpi_count = raw_max + 1;
|
||||
dev->dpi_table = zalloc((raw_max + 1) * sizeof(*dev->dpi_table));
|
||||
dev->dpi_table_is_range = true;
|
||||
|
||||
for (i = 1; i <= raw_max; i++) {
|
||||
dev->dpi_table[i].raw_value = i;
|
||||
dev->dpi_table[i].dpi = round((min + step * i) / 25.0f) * 25;
|
||||
dev->dpi_table[i].dpi = round((range->min + range->step * i) / 25.0f) * 25;
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -1186,8 +1144,7 @@ hidpp10_onboard_profiles_read_macro(struct hidpp10_device *device,
|
||||
return index;
|
||||
|
||||
out_err:
|
||||
if (macro)
|
||||
free(macro);
|
||||
free(macro);
|
||||
|
||||
return rc;
|
||||
}
|
||||
@@ -1495,8 +1452,12 @@ hidpp10_read_profile(struct hidpp10_device *dev, uint8_t number)
|
||||
long_clear_bit(&pages, 0);
|
||||
long_clear_bit(&pages, 1);
|
||||
|
||||
for (i = 0; i < dev->profile_count; i++)
|
||||
long_clear_bit(&pages, dev->profiles[i].page);
|
||||
for (i = 0; i < dev->profile_count; i++) {
|
||||
uint8_t page = dev->profiles[i].page;
|
||||
|
||||
assert(page < sizeof(pages) * 8);
|
||||
long_clear_bit(&pages, page);
|
||||
}
|
||||
|
||||
page = ffsl(pages) - 1;
|
||||
profile->page = page;
|
||||
@@ -1556,6 +1517,9 @@ hidpp10_read_profile(struct hidpp10_device *dev, uint8_t number)
|
||||
hidpp10_fill_buttons(dev, profile, buttons, PROFILE_NUM_BUTTONS);
|
||||
break;
|
||||
case HIDPP10_PROFILE_G9:
|
||||
profile->red = p9->red;
|
||||
profile->green = p9->green;
|
||||
profile->blue = p9->blue;
|
||||
profile->default_dpi_mode = p9->default_dpi_mode;
|
||||
profile->refresh_rate = p9->usb_refresh_rate ? 1000/p9->usb_refresh_rate : 0;
|
||||
|
||||
@@ -2150,12 +2114,24 @@ hidpp10_set_current_resolution(struct hidpp10_device *dev,
|
||||
uint16_t yres)
|
||||
{
|
||||
unsigned idx = dev->index;
|
||||
union hidpp10_message resolution = CMD_CURRENT_RESOLUTION(REPORT_ID_LONG, idx, SET_LONG_REGISTER_REQ);
|
||||
union hidpp10_message resolution = CMD_CURRENT_RESOLUTION(REPORT_ID_SHORT, idx, SET_REGISTER_REQ);
|
||||
union hidpp10_message resolution_long = CMD_CURRENT_RESOLUTION(REPORT_ID_LONG, idx, SET_LONG_REGISTER_REQ);
|
||||
int res;
|
||||
|
||||
hidpp_set_unaligned_le_u16(&resolution.data[4], hidpp10_get_dpi_mapping(dev, xres));
|
||||
hidpp_set_unaligned_le_u16(&resolution.data[6], hidpp10_get_dpi_mapping(dev, yres));
|
||||
switch (dev->profile_type) {
|
||||
case HIDPP10_PROFILE_G9:
|
||||
resolution.data[4] = hidpp10_get_dpi_mapping(dev, xres);
|
||||
res = hidpp10_request_command(dev, &resolution);
|
||||
break;
|
||||
default:
|
||||
hidpp_set_unaligned_le_u16(&resolution_long.data[4], hidpp10_get_dpi_mapping(dev, xres));
|
||||
hidpp_set_unaligned_le_u16(&resolution_long.data[6], hidpp10_get_dpi_mapping(dev, yres));
|
||||
|
||||
return hidpp10_request_command(dev, &resolution);
|
||||
res = hidpp10_request_command(dev, &resolution_long);
|
||||
break;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
@@ -2767,8 +2743,7 @@ hidpp10_device_destroy(struct hidpp10_device *dev)
|
||||
union hidpp10_macro_data **macro;
|
||||
unsigned i;
|
||||
|
||||
if (dev->dpi_table)
|
||||
free(dev->dpi_table);
|
||||
free(dev->dpi_table);
|
||||
for (i = 0; i < dev->profile_count; i++) {
|
||||
ARRAY_FOR_EACH(dev->profiles[i].macros, macro) {
|
||||
if (*macro) {
|
||||
|
||||
@@ -33,6 +33,9 @@
|
||||
|
||||
#include "hidpp-generic.h"
|
||||
|
||||
struct dpi_list;
|
||||
struct dpi_range;
|
||||
|
||||
/* FIXME: that's what my G500s supports, but only pages 3-5 are valid.
|
||||
* 0 is zeroed, 1 and 2 are garbage, all above 6 is garbage */
|
||||
#define HIDPP10_NUM_PROFILES 5
|
||||
@@ -57,6 +60,8 @@ struct hidpp10_dpi_mapping {
|
||||
struct hidpp10_device {
|
||||
struct hidpp_device base;
|
||||
unsigned index;
|
||||
|
||||
bool dpi_table_is_range;
|
||||
uint8_t dpi_count;
|
||||
struct hidpp10_dpi_mapping *dpi_table;
|
||||
enum hidpp10_profile_type profile_type;
|
||||
@@ -88,7 +93,7 @@ hidpp10_device_destroy(struct hidpp10_device *dev);
|
||||
*/
|
||||
int
|
||||
hidpp10_build_dpi_table_from_list(struct hidpp10_device *dev,
|
||||
const char *str_list);
|
||||
const struct dpi_list *list);
|
||||
|
||||
/**
|
||||
* Builds the table of dpi for the device from the given dpi description.
|
||||
@@ -103,7 +108,7 @@ hidpp10_build_dpi_table_from_list(struct hidpp10_device *dev,
|
||||
*/
|
||||
int
|
||||
hidpp10_build_dpi_table_from_dpi_info(struct hidpp10_device *dev,
|
||||
const char *str_dpi);
|
||||
const struct dpi_range *range);
|
||||
|
||||
/**
|
||||
* Returns the lowest dpi stored in the dpi mapping table generated by
|
||||
|
||||
1239
src/hidpp20.c
263
src/hidpp20.h
@@ -31,6 +31,7 @@
|
||||
#include <stdint.h>
|
||||
|
||||
#include "hidpp-generic.h"
|
||||
#include "libratbag-util.h"
|
||||
|
||||
struct _hidpp20_message {
|
||||
uint8_t report_id;
|
||||
@@ -125,6 +126,130 @@ int hidpp20_batterylevel_get_battery_level(struct hidpp20_device *device,
|
||||
uint16_t *level,
|
||||
uint16_t *next_level);
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* 0x1300: LED software control */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
#define HIDPP_PAGE_LED_SW_CONTROL 0x1300
|
||||
|
||||
enum hidpp20_led_sw_ctrl_led_type {
|
||||
HIDPP20_LED_TYPE_BATTERY = 0x01,
|
||||
HIDPP20_LED_TYPE_DPI,
|
||||
HIDPP20_LED_TYPE_PROFILE,
|
||||
HIDPP20_LED_TYPE_LOGO,
|
||||
HIDPP20_LED_TYPE_COSMETIC
|
||||
};
|
||||
|
||||
enum hidpp20_led_sw_ctrl_led_mode {
|
||||
HIDPP20_LED_MODE_OFF = 0x01,
|
||||
HIDPP20_LED_MODE_ON = 0x02,
|
||||
HIDPP20_LED_MODE_BLINK = 0x04,
|
||||
HIDPP20_LED_MODE_TRAVEL = 0x08,
|
||||
HIDPP20_LED_MODE_RAMP_UP = 0x10,
|
||||
HIDPP20_LED_MODE_RAMP_DOWN = 0x20,
|
||||
HIDPP20_LED_MODE_HEARTBEAT = 0x40,
|
||||
HIDPP20_LED_MODE_BREATHING = 0x80
|
||||
};
|
||||
|
||||
#define HIDPP20_LED_SW_CONTROL_LED_INDEX_ALL 0xff
|
||||
|
||||
struct hidpp20_led_sw_ctrl_led_info {
|
||||
uint8_t index;
|
||||
uint8_t type;
|
||||
uint8_t physical_count;
|
||||
uint16_t caps;
|
||||
uint8_t nvconfig_caps;
|
||||
} __attribute__((packed));
|
||||
_Static_assert(sizeof(struct hidpp20_led_sw_ctrl_led_info) == 6, "Invalid size");
|
||||
|
||||
struct hidpp20_led_sw_ctrl_led_state {
|
||||
uint8_t index;
|
||||
uint16_t mode;
|
||||
union {
|
||||
struct {
|
||||
uint16_t brightness;
|
||||
uint16_t period;
|
||||
uint16_t timeout;
|
||||
} breathing;
|
||||
struct {
|
||||
uint16_t unused;
|
||||
uint16_t delay;
|
||||
} traveling;
|
||||
struct {
|
||||
uint16_t index;
|
||||
uint16_t on_time;
|
||||
uint16_t off_time;
|
||||
} blink;
|
||||
struct {
|
||||
/* Logical information to display on the LED
|
||||
* Meaning and value range depend on the LED
|
||||
*/
|
||||
uint16_t index;
|
||||
} on;
|
||||
};
|
||||
} __attribute__((packed));
|
||||
_Static_assert(sizeof(struct hidpp20_led_sw_ctrl_led_state) == 9, "Invalid size");
|
||||
|
||||
int hidpp20_led_sw_control_read_leds(struct hidpp20_device* device,
|
||||
struct hidpp20_led_sw_ctrl_led_info** info_list);
|
||||
|
||||
const char*
|
||||
hidpp20_sw_led_control_get_mode_string(const enum hidpp20_led_sw_ctrl_led_mode mode);
|
||||
|
||||
int hidpp20_led_sw_control_read_leds(struct hidpp20_device* device,
|
||||
struct hidpp20_led_sw_ctrl_led_info** info_list);
|
||||
|
||||
/**
|
||||
* Retrieves the number of non-RGB logical leds from the mouse
|
||||
* @return the led count or a negative errno
|
||||
*/
|
||||
int hidpp20_led_sw_control_get_led_count(struct hidpp20_device* device);
|
||||
|
||||
/**
|
||||
* Retrieves the info for a given logical led
|
||||
* @return 0 or a negative errno in case of error
|
||||
*/
|
||||
int hidpp20_led_sw_control_get_led_info(struct hidpp20_device* device,
|
||||
uint8_t led_idx,
|
||||
struct hidpp20_led_sw_ctrl_led_info* info);
|
||||
|
||||
/**
|
||||
* Reads all LEDs on the device for their current state
|
||||
* @return 0 on success or a negative errno
|
||||
*/
|
||||
int hidpp20_led_sw_control_read_leds(struct hidpp20_device* device,
|
||||
struct hidpp20_led_sw_ctrl_led_info** info_list);
|
||||
|
||||
/**
|
||||
* Get the current sw control value
|
||||
* @return 0 if the leds are sofware-controlled 1 if they are firmware controlled
|
||||
*/
|
||||
bool hidpp20_led_sw_control_get_sw_ctrl(struct hidpp20_device* device);
|
||||
|
||||
/**
|
||||
* Sets who controls the LEDs
|
||||
* ctrl = 0, the software controls the LEDs
|
||||
* ctrl = 1, the firmware controls the LEDs
|
||||
* @return 0 on success or a negative errno
|
||||
*/
|
||||
int hidpp20_led_sw_control_set_sw_ctrl(struct hidpp20_device* device, bool ctrl);
|
||||
|
||||
/**
|
||||
* Gets the state of a LED
|
||||
* @return 0 on success or a negative errno
|
||||
*/
|
||||
int hidpp20_led_sw_control_get_led_state(struct hidpp20_device* device,
|
||||
uint8_t led_idx,
|
||||
struct hidpp20_led_sw_ctrl_led_state* state);
|
||||
|
||||
/**
|
||||
* Sets the state of a LED
|
||||
* The LED index should be passed in the state structure
|
||||
* @return 0 on success or a negative errno
|
||||
*/
|
||||
int hidpp20_led_sw_control_set_led_state(struct hidpp20_device* device,
|
||||
const struct hidpp20_led_sw_ctrl_led_state* state);
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* 0x1b00: KBD reprogrammable keys and mouse buttons */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
@@ -251,15 +376,33 @@ int hidpp20_adjustable_dpi_set_sensor_dpi(struct hidpp20_device *device,
|
||||
|
||||
#define HIDPP_PAGE_ADJUSTABLE_REPORT_RATE 0x8060
|
||||
|
||||
/**
|
||||
* set the bitmap_ms to the supported report rates. Bits enabled reflect a
|
||||
* supported report rate, where bit 0 equals 1ms, bit 1 2ms, bit 2 3ms, etc.
|
||||
*/
|
||||
int hidpp20_adjustable_report_rate_get_report_rate_list(struct hidpp20_device *device,
|
||||
uint8_t *bitflags_ms);
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* 0x8070v4 - Color LED effects */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
#define HIDPP_PAGE_COLOR_LED_EFFECTS 0x8070
|
||||
|
||||
enum hidpp20_color_led_info_ext_caps {
|
||||
HIDPP20_COLOR_LED_INFO_EXT_CAP_HAS_ZONE_EFFECT = 0x01,
|
||||
HIDPP20_COLOR_LED_INFO_EXT_CAP_NO_GET_EFFECT_SETTINGS = 0x02,
|
||||
HIDPP20_COLOR_LED_INFO_EXT_CAP_HAS_SET_LED_BIN_INFO = 0x04,
|
||||
HIDPP20_COLOR_LED_INFO_EXT_CAP_MONOCHROME_ONLY = 0x08,
|
||||
};
|
||||
|
||||
struct hidpp20_color_led_info;
|
||||
|
||||
int
|
||||
hidpp20_color_led_effects_get_info(struct hidpp20_device *device,
|
||||
struct hidpp20_color_led_info *info);
|
||||
|
||||
|
||||
struct hidpp20_color_led_zone_info;
|
||||
|
||||
int
|
||||
@@ -270,6 +413,14 @@ int
|
||||
hidpp20_color_led_effects_get_zone_infos(struct hidpp20_device *device,
|
||||
struct hidpp20_color_led_zone_info **infos_list);
|
||||
|
||||
struct hidpp20_color_led_zone_effect_info;
|
||||
|
||||
int
|
||||
hidpp20_color_led_effect_get_zone_effect_info(struct hidpp20_device *device,
|
||||
uint8_t zone_index,
|
||||
uint8_t zone_effect_index,
|
||||
struct hidpp20_color_led_zone_effect_info *info);
|
||||
|
||||
enum hidpp20_color_led_location {
|
||||
HIDPP20_COLOR_LED_LOCATION_UNDEFINED = 0,
|
||||
HIDPP20_COLOR_LED_LOCATION_PRIMARY,
|
||||
@@ -292,6 +443,19 @@ enum hidpp20_color_led_persistency {
|
||||
HIDPP20_COLOR_LED_PERSISTENCY_ON_OFF,
|
||||
};
|
||||
|
||||
enum hidpp20_color_led_zone_effect {
|
||||
HIDPP20_COLOR_LED_ZONE_EFFECT_DISABLED = 0,
|
||||
HIDPP20_COLOR_LED_ZONE_EFFECT_FIXED = 1,
|
||||
HIDPP20_COLOR_LED_ZONE_EFFECT_CYCLING = 3,
|
||||
HIDPP20_COLOR_LED_ZONE_EFFECT_WAVE = 4,
|
||||
HIDPP20_COLOR_LED_ZONE_EFFECT_STARLIGHT = 5,
|
||||
HIDPP20_COLOR_LED_ZONE_EFFECT_LIGHT_ON_PRESS = 6,
|
||||
HIDPP20_COLOR_LED_ZONE_EFFECT_AUDIO_VISUALIZER = 7,
|
||||
HIDPP20_COLOR_LED_ZONE_EFFECT_BOOT_UP = 8,
|
||||
HIDPP20_COLOR_LED_ZONE_EFFECT_DEMO_MODE = 8,
|
||||
HIDPP20_COLOR_LED_ZONE_EFFECT_BREATHING = 10,
|
||||
};
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* 0x8100 - Onboard Profiles */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
@@ -361,6 +525,14 @@ struct hidpp20_color_led_info {
|
||||
} __attribute__((packed));
|
||||
_Static_assert(sizeof(struct hidpp20_color_led_info) == 5, "Invalid size");
|
||||
|
||||
struct hidpp20_non_color_led_zone_info {
|
||||
uint8_t index;
|
||||
uint8_t type;
|
||||
uint16_t capabilities;
|
||||
uint8_t nv_config;
|
||||
} __attribute__((packed));
|
||||
_Static_assert(sizeof(struct hidpp20_non_color_led_zone_info) == 5, "Invalid size");
|
||||
|
||||
struct hidpp20_color_led_zone_info {
|
||||
uint8_t index;
|
||||
uint16_t location;
|
||||
@@ -369,6 +541,20 @@ struct hidpp20_color_led_zone_info {
|
||||
} __attribute__((packed));
|
||||
_Static_assert(sizeof(struct hidpp20_color_led_zone_info) == 5, "Invalid size");
|
||||
|
||||
union hidpp20_generic_led_zone_info {
|
||||
struct hidpp20_led_sw_ctrl_led_info* leds;
|
||||
struct hidpp20_color_led_zone_info* color_leds;
|
||||
};
|
||||
|
||||
struct hidpp20_color_led_zone_effect_info {
|
||||
uint8_t zone_index;
|
||||
uint8_t zone_effect_index;
|
||||
uint16_t effect_id;
|
||||
uint16_t effect_caps;
|
||||
uint16_t effect_period;
|
||||
} __attribute__((packed));
|
||||
_Static_assert(sizeof(struct hidpp20_color_led_zone_effect_info) == 8, "Invalid size");
|
||||
|
||||
struct hidpp20_color {
|
||||
uint8_t red;
|
||||
uint8_t green;
|
||||
@@ -466,7 +652,7 @@ union hidpp20_macro_data {
|
||||
_Static_assert(sizeof(union hidpp20_macro_data) == 3, "Invalid size");
|
||||
|
||||
struct hidpp20_profile {
|
||||
uint8_t index;
|
||||
uint16_t address;
|
||||
uint8_t enabled;
|
||||
char name[16 * 3];
|
||||
unsigned report_rate;
|
||||
@@ -479,6 +665,21 @@ struct hidpp20_profile {
|
||||
struct hidpp20_led leds[HIDPP20_LED_COUNT];
|
||||
};
|
||||
|
||||
struct hidpp20_onboard_profiles_info {
|
||||
uint8_t memory_model_id;
|
||||
uint8_t profile_format_id;
|
||||
uint8_t macro_format_id;
|
||||
uint8_t profile_count;
|
||||
uint8_t profile_count_oob;
|
||||
uint8_t button_count;
|
||||
uint8_t sector_count;
|
||||
uint16_t sector_size;
|
||||
uint8_t mechanical_layout;
|
||||
uint8_t various_info;
|
||||
uint8_t reserved[5];
|
||||
} __attribute__((packed));
|
||||
_Static_assert(sizeof(struct hidpp20_onboard_profiles_info) == 16, "Invalid size");
|
||||
|
||||
struct hidpp20_profiles {
|
||||
uint8_t num_profiles;
|
||||
uint8_t num_rom_profiles;
|
||||
@@ -489,9 +690,20 @@ struct hidpp20_profiles {
|
||||
uint8_t has_dpi_shift;
|
||||
uint8_t corded;
|
||||
uint8_t wireless;
|
||||
struct hidpp20_profile profiles[0];
|
||||
uint8_t sector_count;
|
||||
uint16_t sector_size;
|
||||
struct hidpp20_profile *profiles;
|
||||
};
|
||||
|
||||
/**
|
||||
* fetches the profiles description as reported by the mouse.
|
||||
*
|
||||
* returns 0 or a negative error.
|
||||
*/
|
||||
int
|
||||
hidpp20_onboard_profiles_get_profiles_desc(struct hidpp20_device *device,
|
||||
struct hidpp20_onboard_profiles_info *info);
|
||||
|
||||
/**
|
||||
* allocates a list of profiles that has to be destroyed by the caller.
|
||||
* The caller must use hidpp20_onboard_profiles_destroy() to free the memory.
|
||||
@@ -507,6 +719,14 @@ int hidpp20_onboard_profiles_allocate(struct hidpp20_device *device,
|
||||
void
|
||||
hidpp20_onboard_profiles_destroy(struct hidpp20_profiles *profiles_list);
|
||||
|
||||
/**
|
||||
* initialize a struct hidpp20_profiles previous allocated with
|
||||
* hidpp20_onboard_profiles_allocate().
|
||||
*/
|
||||
int
|
||||
hidpp20_onboard_profiles_initialize(struct hidpp20_device *device,
|
||||
struct hidpp20_profiles *profiles);
|
||||
|
||||
/**
|
||||
* return the current profile index or a negative error.
|
||||
*/
|
||||
@@ -539,18 +759,11 @@ hidpp20_onboard_profiles_set_current_dpi_index(struct hidpp20_device *device,
|
||||
uint8_t index);
|
||||
|
||||
/**
|
||||
* parse a given profile from the mouse and fill in the right profile in
|
||||
* profiles_list.
|
||||
*
|
||||
* return 0 or a negative error.
|
||||
* Write the internal state of the device onto the FLASH.
|
||||
*/
|
||||
int hidpp20_onboard_profiles_read(struct hidpp20_device *device,
|
||||
unsigned int index,
|
||||
struct hidpp20_profiles *profiles_list);
|
||||
|
||||
int hidpp20_onboard_profiles_write(struct hidpp20_device *device,
|
||||
unsigned int index,
|
||||
struct hidpp20_profiles *profiles_list);
|
||||
int
|
||||
hidpp20_onboard_profiles_commit(struct hidpp20_device *device,
|
||||
struct hidpp20_profiles *profiles_list);
|
||||
|
||||
enum ratbag_button_action_special
|
||||
hidpp20_onboard_profiles_get_special(uint8_t code);
|
||||
@@ -559,16 +772,26 @@ uint8_t
|
||||
hidpp20_onboard_profiles_get_code_from_special(enum ratbag_button_action_special special);
|
||||
|
||||
int
|
||||
hidpp20_onboard_profiles_read_memory(struct hidpp20_device *device,
|
||||
uint8_t read_rom,
|
||||
uint8_t page,
|
||||
uint16_t section,
|
||||
uint8_t result[16]);
|
||||
hidpp20_onboard_profiles_read_sector(struct hidpp20_device *device,
|
||||
uint16_t sector,
|
||||
uint16_t sector_size,
|
||||
uint8_t *data);
|
||||
|
||||
int
|
||||
hidpp20_onboard_profiles_write_sector(struct hidpp20_device *device,
|
||||
uint16_t sector,
|
||||
uint16_t sector_size,
|
||||
uint8_t *data,
|
||||
bool write_crc);
|
||||
|
||||
static inline uint8_t *
|
||||
hidpp20_onboard_profiles_allocate_sector(struct hidpp20_profiles *profiles)
|
||||
{
|
||||
return zalloc(profiles->sector_size);
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* 0x8110 - Mouse Button Spy */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
#define HIDPP_PAGE_MOUSE_BUTTON_SPY 0x8110
|
||||
|
||||
|
||||
|
||||
@@ -23,6 +23,8 @@
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
586
src/libratbag-data.c
Normal file
@@ -0,0 +1,586 @@
|
||||
/*
|
||||
* Copyright © 2017 Red Hat, Inc.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the next
|
||||
* paragraph) shall be included in all copies or substantial portions of the
|
||||
* Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <linux/input.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <glib.h>
|
||||
|
||||
#include "libratbag.h"
|
||||
#include "libratbag-private.h"
|
||||
#include "libratbag-data.h"
|
||||
|
||||
#define GROUP_DEVICE "Device"
|
||||
|
||||
DEFINE_TRIVIAL_CLEANUP_FUNC(GKeyFile *, g_key_file_free);
|
||||
DEFINE_TRIVIAL_CLEANUP_FUNC(GError *, g_error_free);
|
||||
DEFINE_TRIVIAL_CLEANUP_FUNC(char **, g_strfreev);
|
||||
|
||||
enum driver {
|
||||
NONE = 0,
|
||||
HIDPP10,
|
||||
HIDPP20,
|
||||
ROCCAT,
|
||||
ETEKCITY,
|
||||
GSKILL,
|
||||
LOGITECH_G300,
|
||||
STEELSERIES,
|
||||
};
|
||||
|
||||
struct data_hidpp20 {
|
||||
int index;
|
||||
};
|
||||
|
||||
struct data_hidpp10 {
|
||||
int index;
|
||||
int profile_count;
|
||||
char *profile_type;
|
||||
|
||||
struct dpi_list *dpi_list;
|
||||
struct dpi_range *dpi_range;
|
||||
int led_count;
|
||||
};
|
||||
|
||||
struct data_steelseries {
|
||||
int device_version;
|
||||
int button_count;
|
||||
int led_count;
|
||||
struct dpi_list *dpi_list;
|
||||
struct dpi_range *dpi_range;
|
||||
};
|
||||
|
||||
struct ratbag_device_data {
|
||||
int refcount;
|
||||
char *name;
|
||||
char *driver;
|
||||
char *svg;
|
||||
|
||||
enum driver drivertype;
|
||||
|
||||
union {
|
||||
struct data_hidpp20 hidpp20;
|
||||
struct data_hidpp10 hidpp10;
|
||||
struct data_steelseries steelseries;
|
||||
};
|
||||
|
||||
enum ratbag_led_type led_types[20];
|
||||
size_t nled_types;
|
||||
};
|
||||
|
||||
static void
|
||||
init_data_hidpp10(struct ratbag *ratbag,
|
||||
GKeyFile *keyfile,
|
||||
struct ratbag_device_data *data)
|
||||
{
|
||||
const char *group = "Driver/hidpp10";
|
||||
char *profile_type;
|
||||
GError *error = NULL;
|
||||
_cleanup_(freep) char *str = NULL;
|
||||
int num;
|
||||
|
||||
data->hidpp10.index = -1;
|
||||
data->hidpp10.profile_count = -1;
|
||||
data->hidpp10.profile_type = NULL;
|
||||
data->hidpp10.led_count = -1;
|
||||
|
||||
num = g_key_file_get_integer(keyfile, group, "DeviceIndex", &error);
|
||||
if (num != 0 || !error)
|
||||
data->hidpp10.index = num;
|
||||
if (error)
|
||||
g_error_free(error);
|
||||
|
||||
error = NULL;
|
||||
num = g_key_file_get_integer(keyfile, group, "Profiles", &error);
|
||||
if (num > 0 || !error)
|
||||
data->hidpp10.profile_count = num;
|
||||
if (error)
|
||||
g_error_free(error);
|
||||
|
||||
error = NULL;
|
||||
num = g_key_file_get_integer(keyfile, group, "Leds", &error);
|
||||
if (num > 0 || !error)
|
||||
data->hidpp10.led_count = num;
|
||||
if (error)
|
||||
g_error_free(error);
|
||||
|
||||
profile_type = g_key_file_get_string(keyfile, group, "ProfileType", NULL);
|
||||
if (profile_type)
|
||||
data->hidpp10.profile_type = profile_type;
|
||||
|
||||
str = g_key_file_get_string(keyfile, group, "DpiRange", NULL);
|
||||
if (str) {
|
||||
data->hidpp10.dpi_range = dpi_range_from_string(str);
|
||||
} else {
|
||||
str = g_key_file_get_string(keyfile, group, "DpiList", NULL);
|
||||
if (str)
|
||||
data->hidpp10.dpi_list = dpi_list_from_string(str);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
init_data_hidpp20(struct ratbag *ratbag,
|
||||
GKeyFile *keyfile,
|
||||
struct ratbag_device_data *data)
|
||||
{
|
||||
const char *group = "Driver/hidpp20";
|
||||
GError *error = NULL;
|
||||
int num;
|
||||
|
||||
data->hidpp20.index = -1;
|
||||
|
||||
num = g_key_file_get_integer(keyfile, group, "DeviceIndex", &error);
|
||||
if (num != 0 || !error)
|
||||
data->hidpp20.index = num;
|
||||
if (error)
|
||||
g_error_free(error);
|
||||
}
|
||||
|
||||
static void
|
||||
init_data_steelseries(struct ratbag *ratbag,
|
||||
GKeyFile *keyfile,
|
||||
struct ratbag_device_data *data)
|
||||
{
|
||||
const char *group = "Driver/steelseries";
|
||||
GError *error = NULL;
|
||||
_cleanup_(freep) char *str = NULL;
|
||||
int num;
|
||||
|
||||
data->steelseries.device_version = -1;
|
||||
data->steelseries.button_count = -1;
|
||||
data->steelseries.led_count = -1;
|
||||
data->steelseries.dpi_list = NULL;
|
||||
data->steelseries.dpi_range = NULL;
|
||||
|
||||
num = g_key_file_get_integer(keyfile, group, "Buttons", &error);
|
||||
if (num != 0 || !error)
|
||||
data->steelseries.button_count = num;
|
||||
if (error)
|
||||
g_error_free(error);
|
||||
|
||||
error = NULL;
|
||||
num = g_key_file_get_integer(keyfile, group, "Leds", &error);
|
||||
if (num > 0 || !error)
|
||||
data->steelseries.led_count = num;
|
||||
if (error)
|
||||
g_error_free(error);
|
||||
|
||||
error = NULL;
|
||||
num = g_key_file_get_integer(keyfile, group, "DeviceVersion", &error);
|
||||
if (num > 0 || !error)
|
||||
data->steelseries.device_version = num;
|
||||
if (error)
|
||||
g_error_free(error);
|
||||
|
||||
str = g_key_file_get_string(keyfile, group, "DpiRange", NULL);
|
||||
if (str) {
|
||||
data->steelseries.dpi_range = dpi_range_from_string(str);
|
||||
} else {
|
||||
str = g_key_file_get_string(keyfile, group, "DpiList", NULL);
|
||||
if (str)
|
||||
data->steelseries.dpi_list = dpi_list_from_string(str);
|
||||
}
|
||||
}
|
||||
|
||||
static const struct driver_map {
|
||||
enum driver map;
|
||||
const char *driver;
|
||||
void (*init)(struct ratbag *ratbag,
|
||||
GKeyFile *keyfile,
|
||||
struct ratbag_device_data *data);
|
||||
} driver_map[] = {
|
||||
{ HIDPP10, "hidpp10", init_data_hidpp10 },
|
||||
{ HIDPP20, "hidpp20", init_data_hidpp20 },
|
||||
{ ROCCAT, "roccat", NULL },
|
||||
{ ETEKCITY, "etekcity", NULL},
|
||||
{ GSKILL, "gskill", NULL },
|
||||
{ LOGITECH_G300, "logitech_g300", NULL},
|
||||
{ STEELSERIES, "steelseries", init_data_steelseries },
|
||||
};
|
||||
|
||||
const char *
|
||||
ratbag_device_data_get_driver(const struct ratbag_device_data *data)
|
||||
{
|
||||
return data->driver;
|
||||
}
|
||||
|
||||
const char *
|
||||
ratbag_device_data_get_name(const struct ratbag_device_data *data)
|
||||
{
|
||||
return data->name;
|
||||
}
|
||||
|
||||
const char *
|
||||
ratbag_device_data_get_svg(const struct ratbag_device_data *data)
|
||||
{
|
||||
return data->svg;
|
||||
}
|
||||
|
||||
enum ratbag_led_type
|
||||
ratbag_device_data_get_led_type(const struct ratbag_device_data *data,
|
||||
unsigned int index)
|
||||
{
|
||||
assert(index < ARRAY_LENGTH(data->led_types));
|
||||
|
||||
return data->led_types[index];
|
||||
}
|
||||
|
||||
struct ratbag_device_data *
|
||||
ratbag_device_data_ref(struct ratbag_device_data *data)
|
||||
{
|
||||
data->refcount++;
|
||||
return data;
|
||||
}
|
||||
|
||||
static void
|
||||
ratbag_device_data_destroy(struct ratbag_device_data *data)
|
||||
{
|
||||
switch (data->drivertype) {
|
||||
case HIDPP10:
|
||||
free(data->hidpp10.profile_type);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
free(data->name);
|
||||
free(data->driver);
|
||||
free(data->svg);
|
||||
free(data);
|
||||
}
|
||||
|
||||
struct ratbag_device_data *
|
||||
ratbag_device_data_unref(struct ratbag_device_data *data)
|
||||
{
|
||||
if (data == NULL)
|
||||
return NULL;
|
||||
|
||||
assert(data->refcount > 0);
|
||||
data->refcount--;
|
||||
|
||||
if (data->refcount == 0)
|
||||
ratbag_device_data_destroy(data);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
DEFINE_TRIVIAL_CLEANUP_FUNC(struct ratbag_device_data *, ratbag_device_data_unref);
|
||||
|
||||
static int
|
||||
parse_ledtypes(char **strv, enum ratbag_led_type *types, size_t ntypes)
|
||||
{
|
||||
unsigned int i;
|
||||
int count = 0;
|
||||
|
||||
for (i = 0; i < ntypes; i++)
|
||||
types[i] = RATBAG_LED_TYPE_UNKNOWN;
|
||||
|
||||
if (!strv)
|
||||
return count;
|
||||
|
||||
i = 0;
|
||||
while(strv[i]) {
|
||||
const char *s = strv[i];
|
||||
|
||||
if (streq(s, "logo"))
|
||||
types[i] = RATBAG_LED_TYPE_LOGO;
|
||||
else if (streq(s, "side"))
|
||||
types[i] = RATBAG_LED_TYPE_SIDE;
|
||||
else if (streq(s, "dpi"))
|
||||
types[i] = RATBAG_LED_TYPE_SIDE;
|
||||
else if (streq(s, "battery"))
|
||||
types[i] = RATBAG_LED_TYPE_SIDE;
|
||||
else if (streq(s, "wheel"))
|
||||
types[i] = RATBAG_LED_TYPE_WHEEL;
|
||||
else
|
||||
return -1;
|
||||
|
||||
count++;
|
||||
i++;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static bool
|
||||
match(const struct input_id *id, char **strv)
|
||||
{
|
||||
const char *bus;
|
||||
char str[64];
|
||||
int i = 0;
|
||||
|
||||
switch (id->bustype) {
|
||||
case BUS_USB: bus = "usb"; break;
|
||||
case BUS_BLUETOOTH: bus = "bluetooth"; break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
snprintf(str, sizeof(str), "%s:%04x:%04x", bus, id->vendor, id->product);
|
||||
|
||||
while (strv[i]) {
|
||||
if (streq(strv[i], str))
|
||||
return true;
|
||||
i++;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool
|
||||
file_data_matches(struct ratbag *ratbag,
|
||||
const char *path, const struct input_id *id,
|
||||
struct ratbag_device_data **data_out)
|
||||
{
|
||||
_cleanup_(g_key_file_freep) GKeyFile *keyfile = NULL;
|
||||
_cleanup_(g_error_freep) GError *error = NULL;
|
||||
_cleanup_(g_strfreevp) char **match_strv = NULL;
|
||||
_cleanup_(g_strfreevp) char **ledtypes_strv = NULL;
|
||||
_cleanup_(ratbag_device_data_unrefp) struct ratbag_device_data *data = NULL;
|
||||
int rc;
|
||||
|
||||
keyfile = g_key_file_new();
|
||||
rc = g_key_file_load_from_file(keyfile, path, G_KEY_FILE_NONE, &error);
|
||||
if (!rc) {
|
||||
log_error(ratbag, "Failed to parse keyfile %s: %s\n", path, error->message);
|
||||
return false;
|
||||
}
|
||||
|
||||
match_strv = g_key_file_get_string_list(keyfile, GROUP_DEVICE, "DeviceMatch", NULL, NULL);
|
||||
if (!match_strv) {
|
||||
log_error(ratbag, "Missing DeviceMatch in %s\n", basename(path));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!match(id, match_strv))
|
||||
return false;
|
||||
|
||||
data = zalloc(sizeof(*data));
|
||||
data->refcount = 1;
|
||||
data->name = g_key_file_get_string(keyfile, GROUP_DEVICE, "Name", NULL);
|
||||
if (!data->name) {
|
||||
return false;
|
||||
}
|
||||
|
||||
data->driver = g_key_file_get_string(keyfile, GROUP_DEVICE, "Driver", NULL);
|
||||
if (!data->driver) {
|
||||
log_error(ratbag, "Missing Driver in %s\n", basename(path));
|
||||
return false;
|
||||
} else {
|
||||
const struct driver_map *map;
|
||||
|
||||
data->drivertype = NONE;
|
||||
ARRAY_FOR_EACH(driver_map, map) {
|
||||
if (streq(map->driver, data->driver)) {
|
||||
data->drivertype = map->map;
|
||||
if (map->init)
|
||||
map->init(ratbag, keyfile, data);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (data->drivertype == NONE) {
|
||||
log_error(ratbag, "Unknown driver %s in %s\n",
|
||||
data->driver, basename(path));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
data->svg = g_key_file_get_string(keyfile, GROUP_DEVICE, "Svg", NULL);
|
||||
|
||||
ledtypes_strv = g_key_file_get_string_list(keyfile, GROUP_DEVICE, "LedTypes", NULL, NULL);
|
||||
if (parse_ledtypes(ledtypes_strv, data->led_types, ARRAY_LENGTH(data->led_types)) < 0) {
|
||||
log_error(ratbag, "Invalid LedTypes string in '%s'\n", basename(path));
|
||||
return false;
|
||||
}
|
||||
|
||||
*data_out = data;
|
||||
data = NULL;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static int
|
||||
filter_device_files(const struct dirent *entry)
|
||||
{
|
||||
const char *SUFFIX = ".device";
|
||||
const char *name = entry->d_name;
|
||||
int len, slen;
|
||||
|
||||
if (!name || name[0] == '.')
|
||||
return 0;
|
||||
|
||||
len = strlen(name);
|
||||
slen = strlen(SUFFIX);
|
||||
if (len <= slen)
|
||||
return 0;
|
||||
|
||||
return streq(&name[len - slen], SUFFIX);
|
||||
}
|
||||
|
||||
struct ratbag_device_data *
|
||||
ratbag_device_data_new_for_id(struct ratbag *ratbag, const struct input_id *id)
|
||||
{
|
||||
struct ratbag_device_data *data = NULL;
|
||||
struct dirent **files;
|
||||
int n, nfiles;
|
||||
const char *datadir;
|
||||
char devicedir[PATH_MAX] = {0};
|
||||
|
||||
datadir = getenv("LIBRATBAG_DATA_DIR");
|
||||
if (!datadir)
|
||||
datadir = LIBRATBAG_DATA_DIR;
|
||||
|
||||
snprintf(devicedir, sizeof(devicedir), "%s/devices", datadir);
|
||||
|
||||
n = scandir(devicedir, &files, filter_device_files, alphasort);
|
||||
if (n <= 0) {
|
||||
log_error(ratbag, "Unable to locate device files in %s: %s\n",
|
||||
devicedir, n == 0 ? "No files found" : strerror(errno));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
nfiles = n;
|
||||
while(n--) {
|
||||
_cleanup_(freep) char *file = NULL;
|
||||
int rc;
|
||||
|
||||
rc = xasprintf(&file, "%s/%s", devicedir, files[n]->d_name);
|
||||
if (rc == -1)
|
||||
goto out;
|
||||
if (file_data_matches(ratbag, file, id, &data))
|
||||
goto out;
|
||||
}
|
||||
|
||||
out:
|
||||
while(nfiles--)
|
||||
free(files[nfiles]);
|
||||
free(files);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
|
||||
/* HID++ 1.0 */
|
||||
|
||||
int
|
||||
ratbag_device_data_hidpp10_get_index(const struct ratbag_device_data *data)
|
||||
{
|
||||
assert(data->drivertype == HIDPP10);
|
||||
|
||||
return data->hidpp10.index;
|
||||
}
|
||||
|
||||
int
|
||||
ratbag_device_data_hidpp10_get_profile_count(const struct ratbag_device_data *data)
|
||||
{
|
||||
assert(data->drivertype == HIDPP10);
|
||||
|
||||
return data->hidpp10.profile_count;
|
||||
}
|
||||
|
||||
const char *
|
||||
ratbag_device_data_hidpp10_get_profile_type(const struct ratbag_device_data *data)
|
||||
{
|
||||
assert(data->drivertype == HIDPP10);
|
||||
|
||||
return data->hidpp10.profile_type;
|
||||
}
|
||||
|
||||
struct dpi_list *
|
||||
ratbag_device_data_hidpp10_get_dpi_list(const struct ratbag_device_data *data)
|
||||
{
|
||||
assert(data->drivertype == HIDPP10);
|
||||
|
||||
return data->hidpp10.dpi_list;
|
||||
}
|
||||
|
||||
struct dpi_range *
|
||||
ratbag_device_data_hidpp10_get_dpi_range(const struct ratbag_device_data *data)
|
||||
{
|
||||
assert(data->drivertype == HIDPP10);
|
||||
|
||||
return data->hidpp10.dpi_range;
|
||||
}
|
||||
|
||||
int
|
||||
ratbag_device_data_hidpp10_get_led_count(const struct ratbag_device_data *data)
|
||||
{
|
||||
assert(data->drivertype == HIDPP10);
|
||||
|
||||
return data->hidpp10.led_count;
|
||||
}
|
||||
|
||||
/* HID++ 2.0 */
|
||||
|
||||
int
|
||||
ratbag_device_data_hidpp20_get_index(const struct ratbag_device_data *data)
|
||||
{
|
||||
assert(data->drivertype == HIDPP20);
|
||||
|
||||
return data->hidpp20.index;
|
||||
}
|
||||
|
||||
/* SteelSeries */
|
||||
|
||||
int
|
||||
ratbag_device_data_steelseries_get_device_version(const struct ratbag_device_data *data)
|
||||
{
|
||||
assert(data->drivertype == STEELSERIES);
|
||||
|
||||
return data->steelseries.device_version;
|
||||
}
|
||||
|
||||
int
|
||||
ratbag_device_data_steelseries_get_button_count(const struct ratbag_device_data *data)
|
||||
{
|
||||
assert(data->drivertype == STEELSERIES);
|
||||
|
||||
return data->steelseries.button_count;
|
||||
}
|
||||
|
||||
int
|
||||
ratbag_device_data_steelseries_get_led_count(const struct ratbag_device_data *data)
|
||||
{
|
||||
assert(data->drivertype == STEELSERIES);
|
||||
|
||||
return data->steelseries.led_count;
|
||||
}
|
||||
|
||||
struct dpi_list *
|
||||
ratbag_device_data_steelseries_get_dpi_list(const struct ratbag_device_data *data)
|
||||
{
|
||||
assert(data->drivertype == STEELSERIES);
|
||||
|
||||
return data->steelseries.dpi_list;
|
||||
}
|
||||
|
||||
struct dpi_range *
|
||||
ratbag_device_data_steelseries_get_dpi_range(const struct ratbag_device_data *data)
|
||||
{
|
||||
assert(data->drivertype == STEELSERIES);
|
||||
|
||||
return data->steelseries.dpi_range;
|
||||
}
|
||||
|
||||
110
src/libratbag-data.h
Normal file
@@ -0,0 +1,110 @@
|
||||
/*
|
||||
* Copyright © 2017 Red Hat, Inc.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the next
|
||||
* paragraph) shall be included in all copies or substantial portions of the
|
||||
* Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
struct ratbag_device_data;
|
||||
|
||||
struct ratbag_device_data *
|
||||
ratbag_device_data_new_for_id(struct ratbag *ratbag, const struct input_id *id);
|
||||
|
||||
|
||||
struct ratbag_device_data *
|
||||
ratbag_device_data_unref(struct ratbag_device_data *data);
|
||||
|
||||
struct ratbag_device_data *
|
||||
ratbag_device_data_ref(struct ratbag_device_data *data);
|
||||
|
||||
|
||||
const char *
|
||||
ratbag_device_data_get_driver(const struct ratbag_device_data *data);
|
||||
const char *
|
||||
ratbag_device_data_get_name(const struct ratbag_device_data *data);
|
||||
const char *
|
||||
ratbag_device_data_get_svg(const struct ratbag_device_data *data);
|
||||
enum ratbag_led_type
|
||||
ratbag_device_data_get_led_type(const struct ratbag_device_data *data,
|
||||
unsigned int index);
|
||||
|
||||
/* HID++ 1.0 */
|
||||
/**
|
||||
* @return The device index or -1 if not set
|
||||
*/
|
||||
int
|
||||
ratbag_device_data_hidpp10_get_index(const struct ratbag_device_data *data);
|
||||
|
||||
const char *
|
||||
ratbag_device_data_hidpp10_get_profile_type(const struct ratbag_device_data *data);
|
||||
|
||||
/**
|
||||
* @return The profile count index or -1 if not set
|
||||
*/
|
||||
int
|
||||
ratbag_device_data_hidpp10_get_profile_count(const struct ratbag_device_data *data);
|
||||
|
||||
struct dpi_list *
|
||||
ratbag_device_data_hidpp10_get_dpi_list(const struct ratbag_device_data *data);
|
||||
|
||||
struct dpi_range *
|
||||
ratbag_device_data_hidpp10_get_dpi_range(const struct ratbag_device_data *data);
|
||||
|
||||
/**
|
||||
* @return The led count index or -1 if not set
|
||||
*/
|
||||
int
|
||||
ratbag_device_data_hidpp10_get_led_count(const struct ratbag_device_data *data);
|
||||
|
||||
/* HID++ 2.0 */
|
||||
|
||||
/**
|
||||
* @return The device index or -1 if not set
|
||||
*/
|
||||
int
|
||||
ratbag_device_data_hidpp20_get_index(const struct ratbag_device_data *data);
|
||||
|
||||
/* SteelSeries */
|
||||
|
||||
/**
|
||||
* @return The device version or -1 if not set
|
||||
*/
|
||||
int
|
||||
ratbag_device_data_steelseries_get_device_version(const struct ratbag_device_data *data);
|
||||
|
||||
/**
|
||||
* @return The button count or -1 if not set
|
||||
*/
|
||||
int
|
||||
ratbag_device_data_steelseries_get_button_count(const struct ratbag_device_data *data);
|
||||
|
||||
/**
|
||||
* @return The led count or -1 if not set
|
||||
*/
|
||||
int
|
||||
ratbag_device_data_steelseries_get_led_count(const struct ratbag_device_data *data);
|
||||
|
||||
struct dpi_list *
|
||||
ratbag_device_data_steelseries_get_dpi_list(const struct ratbag_device_data *data);
|
||||
|
||||
struct dpi_range *
|
||||
ratbag_device_data_steelseries_get_dpi_range(const struct ratbag_device_data *data);
|
||||
|
||||
390
src/libratbag-enums.h
Normal file
@@ -0,0 +1,390 @@
|
||||
/*
|
||||
* Copyright © 2017 Red Hat, Inc.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the next
|
||||
* paragraph) shall be included in all copies or substantial portions of the
|
||||
* Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
/**
|
||||
* This file contains enum values that are used in the DBus API and thus
|
||||
* considered ABI.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @defgroup enums Enumerations used in the DBus API
|
||||
*/
|
||||
|
||||
/**
|
||||
* @ingroup enums
|
||||
*
|
||||
* Error codes used by libratbag.
|
||||
*/
|
||||
enum ratbag_error_code {
|
||||
RATBAG_SUCCESS = 0,
|
||||
|
||||
/**
|
||||
* An error occured on the device. Either the device is not a
|
||||
* libratbag device or communication with the device failed.
|
||||
*/
|
||||
RATBAG_ERROR_DEVICE = -1000,
|
||||
|
||||
/**
|
||||
* Insufficient capabilities. This error occurs when a requested change is
|
||||
* beyond the device's capabilities.
|
||||
*/
|
||||
RATBAG_ERROR_CAPABILITY = -1001,
|
||||
|
||||
/**
|
||||
* Invalid value or value range. The provided value or value range
|
||||
* is outside of the legal or supported range.
|
||||
*/
|
||||
RATBAG_ERROR_VALUE = -1002,
|
||||
|
||||
/**
|
||||
* A low-level system error has occured, e.g. a failure to access
|
||||
* files that should be there. This error is usually unrecoverable
|
||||
* and libratbag will print a log message with details about the
|
||||
* error.
|
||||
*/
|
||||
RATBAG_ERROR_SYSTEM = -1003,
|
||||
|
||||
/**
|
||||
* Implementation bug, either in libratbag or in the caller. This
|
||||
* error is usually unrecoverable and libratbag will print a log
|
||||
* message with details about the
|
||||
* error.
|
||||
*/
|
||||
RATBAG_ERROR_IMPLEMENTATION = -1004,
|
||||
};
|
||||
|
||||
/**
|
||||
* @ingroup enums
|
||||
*/
|
||||
enum ratbag_device_capability {
|
||||
RATBAG_DEVICE_CAP_NONE = 0,
|
||||
|
||||
/**
|
||||
* The device has the capability to query the current hardware
|
||||
* configuration. If this capability is missing, libratbag cannot
|
||||
* query the device for its current configuration and the
|
||||
* configured resolutions and button mappings are unknown.
|
||||
* libratbag will still provide information about the structure of
|
||||
* the device such as the number of buttons and resolutions.
|
||||
* Clients that encounter a device without this resolution are
|
||||
* encouraged to upload a configuration stored on-disk to the
|
||||
* device to reset the device to a known state.
|
||||
*
|
||||
* Any changes uploaded to the device will be cached in libratbag,
|
||||
* once a client has sent a full configuration to the device
|
||||
* libratbag can be used to query the device as normal.
|
||||
*/
|
||||
RATBAG_DEVICE_CAP_QUERY_CONFIGURATION,
|
||||
|
||||
/**
|
||||
* The device provides read and/or write access to one or more
|
||||
* resolutions.
|
||||
*/
|
||||
RATBAG_DEVICE_CAP_RESOLUTION = 100,
|
||||
|
||||
/**
|
||||
* The device can change resolution, either software-controlled or
|
||||
* by a hardware button.
|
||||
*
|
||||
* FIXME: what about devices that only have hw buttons? can we
|
||||
* query that, even if we can't switch it ourselves? Maybe better to
|
||||
* have a separate cap for that then.
|
||||
*/
|
||||
RATBAG_DEVICE_CAP_SWITCHABLE_RESOLUTION,
|
||||
|
||||
/**
|
||||
* The device provides read and/or write access to one or more
|
||||
* profiles.
|
||||
*/
|
||||
RATBAG_DEVICE_CAP_PROFILE = 200,
|
||||
|
||||
/**
|
||||
* The device can switch between hardware profiles.
|
||||
* A device with this capability can store multiple profiles in the
|
||||
* hardware and provides the ability to switch between the profiles,
|
||||
* possibly with a button.
|
||||
* Devices without this capability will only have a single profile.
|
||||
*/
|
||||
RATBAG_DEVICE_CAP_SWITCHABLE_PROFILE,
|
||||
|
||||
/**
|
||||
* The device has the capability to disable and enable profiles. While
|
||||
* profiles are not immediately deleted after being disabled, it is not
|
||||
* guaranteed that the device will remember any disabled profiles the
|
||||
* next time ratbag runs. Furthermore, the order of profiles may get
|
||||
* changed the next time ratbag runs if profiles are disabled.
|
||||
*/
|
||||
RATBAG_DEVICE_CAP_DISABLE_PROFILE,
|
||||
|
||||
/**
|
||||
* The device can have one profile assigned as a default profile.
|
||||
* A default profile is the profile that is selected when the device
|
||||
* is plugged in. Devices without this capability may select the
|
||||
* last-used profile or a specific profile (usually the first).
|
||||
*/
|
||||
RATBAG_DEVICE_CAP_DEFAULT_PROFILE,
|
||||
|
||||
/**
|
||||
* The device provides read and/or write access to one or more
|
||||
* buttons.
|
||||
*/
|
||||
RATBAG_DEVICE_CAP_BUTTON = 300,
|
||||
|
||||
/**
|
||||
* The device supports assigning button numbers, key events or key +
|
||||
* modifier combinations.
|
||||
*/
|
||||
RATBAG_DEVICE_CAP_BUTTON_KEY,
|
||||
|
||||
/**
|
||||
* The device supports user-defined key or button sequences.
|
||||
*/
|
||||
RATBAG_DEVICE_CAP_BUTTON_MACROS,
|
||||
|
||||
/**
|
||||
* The device supports assigning LED colors and effects
|
||||
*/
|
||||
RATBAG_DEVICE_CAP_LED = 400,
|
||||
};
|
||||
|
||||
/**
|
||||
* @ingroup enums
|
||||
*/
|
||||
enum ratbag_profile_capability {
|
||||
RATBAG_PROFILE_CAP_NONE = 0,
|
||||
|
||||
/**
|
||||
* The device has the capability to write a name to a profile
|
||||
* and store it in its flash.
|
||||
*
|
||||
* Any changes uploaded to the device will be cached in libratbag
|
||||
* and will be committed to it after a commit only.
|
||||
*/
|
||||
RATBAG_PROFILE_CAP_WRITABLE_NAME = 100,
|
||||
};
|
||||
|
||||
/**
|
||||
* @ingroup enums
|
||||
*/
|
||||
enum ratbag_resolution_capability {
|
||||
/**
|
||||
* The report rate can be set per resolution mode. If this property
|
||||
* is not available, all resolutions within the same profile have
|
||||
* the same report rate and changing one changes the others.
|
||||
*/
|
||||
RATBAG_RESOLUTION_CAP_INDIVIDUAL_REPORT_RATE = 1,
|
||||
|
||||
/**
|
||||
* The resolution can be set for x and y separately.
|
||||
*/
|
||||
RATBAG_RESOLUTION_CAP_SEPARATE_XY_RESOLUTION,
|
||||
};
|
||||
|
||||
/**
|
||||
* @ingroup enums
|
||||
*
|
||||
* Button types describing the physical button.
|
||||
*/
|
||||
enum ratbag_button_type {
|
||||
RATBAG_BUTTON_TYPE_UNKNOWN = 0,
|
||||
|
||||
/* mouse buttons */
|
||||
RATBAG_BUTTON_TYPE_LEFT,
|
||||
RATBAG_BUTTON_TYPE_MIDDLE,
|
||||
RATBAG_BUTTON_TYPE_RIGHT,
|
||||
RATBAG_BUTTON_TYPE_THUMB,
|
||||
RATBAG_BUTTON_TYPE_THUMB2,
|
||||
RATBAG_BUTTON_TYPE_THUMB3,
|
||||
RATBAG_BUTTON_TYPE_THUMB4,
|
||||
RATBAG_BUTTON_TYPE_WHEEL_LEFT,
|
||||
RATBAG_BUTTON_TYPE_WHEEL_RIGHT,
|
||||
RATBAG_BUTTON_TYPE_WHEEL_CLICK,
|
||||
RATBAG_BUTTON_TYPE_WHEEL_UP,
|
||||
RATBAG_BUTTON_TYPE_WHEEL_DOWN,
|
||||
/**
|
||||
* A button to toggle the wheel from free-spinning to click-based.
|
||||
*/
|
||||
RATBAG_BUTTON_TYPE_WHEEL_RATCHET_MODE_SHIFT,
|
||||
RATBAG_BUTTON_TYPE_EXTRA,
|
||||
RATBAG_BUTTON_TYPE_SIDE,
|
||||
RATBAG_BUTTON_TYPE_PINKIE,
|
||||
RATBAG_BUTTON_TYPE_PINKIE2,
|
||||
|
||||
/* DPI switch */
|
||||
RATBAG_BUTTON_TYPE_RESOLUTION_CYCLE_UP,
|
||||
RATBAG_BUTTON_TYPE_RESOLUTION_UP,
|
||||
RATBAG_BUTTON_TYPE_RESOLUTION_DOWN,
|
||||
|
||||
/* Profile */
|
||||
RATBAG_BUTTON_TYPE_PROFILE_CYCLE_UP,
|
||||
RATBAG_BUTTON_TYPE_PROFILE_UP,
|
||||
RATBAG_BUTTON_TYPE_PROFILE_DOWN,
|
||||
};
|
||||
|
||||
/**
|
||||
* @ingroup enums
|
||||
*
|
||||
* The type assigned to a button.
|
||||
*/
|
||||
enum ratbag_button_action_type {
|
||||
/**
|
||||
* Button is disabled
|
||||
*/
|
||||
RATBAG_BUTTON_ACTION_TYPE_NONE = 0,
|
||||
/**
|
||||
* Button sends numeric button events
|
||||
*/
|
||||
RATBAG_BUTTON_ACTION_TYPE_BUTTON,
|
||||
/**
|
||||
* Button triggers a mouse-specific special function. This includes
|
||||
* resolution changes and profile changes.
|
||||
*/
|
||||
RATBAG_BUTTON_ACTION_TYPE_SPECIAL,
|
||||
/**
|
||||
* Button sends a key or key + modifier combination
|
||||
*/
|
||||
RATBAG_BUTTON_ACTION_TYPE_KEY,
|
||||
/**
|
||||
* Button sends a user-defined key or button sequence
|
||||
*/
|
||||
RATBAG_BUTTON_ACTION_TYPE_MACRO,
|
||||
/**
|
||||
* Button action is unknown
|
||||
*/
|
||||
RATBAG_BUTTON_ACTION_TYPE_UNKNOWN = 1000,
|
||||
};
|
||||
|
||||
/**
|
||||
* @ingroup enums
|
||||
*/
|
||||
enum ratbag_button_action_special {
|
||||
/**
|
||||
* This button is not set up for a special action
|
||||
*/
|
||||
RATBAG_BUTTON_ACTION_SPECIAL_INVALID = -1,
|
||||
RATBAG_BUTTON_ACTION_SPECIAL_UNKNOWN = (1 << 30),
|
||||
|
||||
RATBAG_BUTTON_ACTION_SPECIAL_DOUBLECLICK,
|
||||
|
||||
/* Wheel mappings */
|
||||
RATBAG_BUTTON_ACTION_SPECIAL_WHEEL_LEFT,
|
||||
RATBAG_BUTTON_ACTION_SPECIAL_WHEEL_RIGHT,
|
||||
RATBAG_BUTTON_ACTION_SPECIAL_WHEEL_UP,
|
||||
RATBAG_BUTTON_ACTION_SPECIAL_WHEEL_DOWN,
|
||||
RATBAG_BUTTON_ACTION_SPECIAL_RATCHET_MODE_SWITCH,
|
||||
|
||||
/* DPI switch */
|
||||
RATBAG_BUTTON_ACTION_SPECIAL_RESOLUTION_CYCLE_UP,
|
||||
RATBAG_BUTTON_ACTION_SPECIAL_RESOLUTION_CYCLE_DOWN,
|
||||
RATBAG_BUTTON_ACTION_SPECIAL_RESOLUTION_UP,
|
||||
RATBAG_BUTTON_ACTION_SPECIAL_RESOLUTION_DOWN,
|
||||
RATBAG_BUTTON_ACTION_SPECIAL_RESOLUTION_ALTERNATE,
|
||||
RATBAG_BUTTON_ACTION_SPECIAL_RESOLUTION_DEFAULT,
|
||||
|
||||
/* Profile */
|
||||
RATBAG_BUTTON_ACTION_SPECIAL_PROFILE_CYCLE_UP,
|
||||
RATBAG_BUTTON_ACTION_SPECIAL_PROFILE_CYCLE_DOWN,
|
||||
RATBAG_BUTTON_ACTION_SPECIAL_PROFILE_UP,
|
||||
RATBAG_BUTTON_ACTION_SPECIAL_PROFILE_DOWN,
|
||||
|
||||
/* second mode for buttons */
|
||||
RATBAG_BUTTON_ACTION_SPECIAL_SECOND_MODE,
|
||||
|
||||
/* battery level */
|
||||
RATBAG_BUTTON_ACTION_SPECIAL_BATTERY_LEVEL,
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* @ingroup enums
|
||||
*
|
||||
* Each LED mode has different properties, e.g. the brightness and rate are only
|
||||
* available in modes @ref RATBAG_LED_CYCLE and @ref RATBAG_LED_BREATHING modes
|
||||
*/
|
||||
enum ratbag_led_mode {
|
||||
/**
|
||||
* led is now off
|
||||
*/
|
||||
RATBAG_LED_OFF = 0,
|
||||
|
||||
/**
|
||||
* led is on with static color
|
||||
*/
|
||||
RATBAG_LED_ON,
|
||||
|
||||
/**
|
||||
* led is cycling between all colors
|
||||
*/
|
||||
RATBAG_LED_CYCLE,
|
||||
|
||||
/**
|
||||
* led is pulsating with static color
|
||||
*/
|
||||
RATBAG_LED_BREATHING,
|
||||
};
|
||||
/**
|
||||
* @ingroup enums
|
||||
*
|
||||
* LED types, usually based on their physical location
|
||||
*/
|
||||
enum ratbag_led_type {
|
||||
RATBAG_LED_TYPE_LOGO = 1,
|
||||
RATBAG_LED_TYPE_SIDE,
|
||||
RATBAG_LED_TYPE_BATTERY,
|
||||
RATBAG_LED_TYPE_DPI,
|
||||
RATBAG_LED_TYPE_WHEEL,
|
||||
};
|
||||
|
||||
/**
|
||||
* @ingroup enums
|
||||
*/
|
||||
enum ratbag_led_colordepth {
|
||||
/**
|
||||
* The device only supports a single color.
|
||||
* All color components should be set to 255.
|
||||
*/
|
||||
RATBAG_LED_COLORDEPTH_MONOCHROME = 400,
|
||||
/**
|
||||
* The device supports RBG color with 8 bits per color.
|
||||
*/
|
||||
RATBAG_LED_COLORDEPTH_RGB_888,
|
||||
/**
|
||||
* The device supports RBG colors with 1 bit per color.
|
||||
*/
|
||||
RATBAG_LED_COLORDEPTH_RGB_111,
|
||||
};
|
||||
|
||||
/**
|
||||
* @ingroup enums
|
||||
*
|
||||
* Macro event types describing the event.
|
||||
*/
|
||||
enum ratbag_macro_event_type {
|
||||
RATBAG_MACRO_EVENT_INVALID = -1,
|
||||
RATBAG_MACRO_EVENT_NONE = 0,
|
||||
RATBAG_MACRO_EVENT_KEY_PRESSED,
|
||||
RATBAG_MACRO_EVENT_KEY_RELEASED,
|
||||
RATBAG_MACRO_EVENT_WAIT,
|
||||
};
|
||||
@@ -21,6 +21,8 @@
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <poll.h>
|
||||
|
||||
@@ -32,6 +32,36 @@
|
||||
#include "libratbag-util.h"
|
||||
#include "libratbag-hidraw.h"
|
||||
|
||||
#define RATBAG_LED_TYPE_UNKNOWN 0
|
||||
|
||||
void
|
||||
log_msg_va(struct ratbag *ratbag,
|
||||
enum ratbag_log_priority priority,
|
||||
const char *format,
|
||||
va_list args)
|
||||
LIBRATBAG_ATTRIBUTE_PRINTF(3, 0);
|
||||
void log_msg(struct ratbag *ratbag,
|
||||
enum ratbag_log_priority priority,
|
||||
const char *format, ...)
|
||||
LIBRATBAG_ATTRIBUTE_PRINTF(3, 4);
|
||||
void
|
||||
log_buffer(struct ratbag *ratbag,
|
||||
enum ratbag_log_priority priority,
|
||||
const char *header,
|
||||
uint8_t *buf, size_t len);
|
||||
|
||||
#define log_raw(li_, ...) log_msg((li_), RATBAG_LOG_PRIORITY_RAW, __VA_ARGS__)
|
||||
#define log_debug(li_, ...) log_msg((li_), RATBAG_LOG_PRIORITY_DEBUG, __VA_ARGS__)
|
||||
#define log_info(li_, ...) log_msg((li_), RATBAG_LOG_PRIORITY_INFO, __VA_ARGS__)
|
||||
#define log_error(li_, ...) log_msg((li_), RATBAG_LOG_PRIORITY_ERROR, __VA_ARGS__)
|
||||
#define log_bug_kernel(li_, ...) log_msg((li_), RATBAG_LOG_PRIORITY_ERROR, "kernel bug: " __VA_ARGS__)
|
||||
#define log_bug_libratbag(li_, ...) log_msg((li_), RATBAG_LOG_PRIORITY_ERROR, "libratbag bug: " __VA_ARGS__)
|
||||
#define log_bug_client(li_, ...) log_msg((li_), RATBAG_LOG_PRIORITY_ERROR, "client bug: " __VA_ARGS__)
|
||||
#define log_buf_raw(li_, h_, buf_, len_) log_buffer(li_, RATBAG_LOG_PRIORITY_RAW, h_, buf_, len_)
|
||||
#define log_buf_debug(li_, h_, buf_, len_) log_buffer(li_, RATBAG_LOG_PRIORITY_DEBUG, h_, buf_, len_)
|
||||
#define log_buf_info(li_, h_, buf_, len_) log_buffer(li_, RATBAG_LOG_PRIORITY_INFO, h_, buf_, len_)
|
||||
#define log_buf_error(li_, h_, buf_, len_) log_buffer(li_, RATBAG_LOG_PRIORITY_ERROR, h_, buf_, len_)
|
||||
|
||||
static inline void
|
||||
cleanup_device(struct ratbag_device **d)
|
||||
{
|
||||
@@ -50,9 +80,23 @@ cleanup_resolution(struct ratbag_resolution **r)
|
||||
ratbag_resolution_unref(*r);
|
||||
}
|
||||
|
||||
static inline void
|
||||
cleanup_button(struct ratbag_button **b)
|
||||
{
|
||||
ratbag_button_unref(*b);
|
||||
}
|
||||
|
||||
static inline void
|
||||
cleanup_led(struct ratbag_led **l)
|
||||
{
|
||||
ratbag_led_unref(*l);
|
||||
}
|
||||
|
||||
#define _cleanup_device_ _cleanup_(cleanup_device)
|
||||
#define _cleanup_profile_ _cleanup_(cleanup_profile)
|
||||
#define _cleanup_resolution_ _cleanup_(cleanup_resolution)
|
||||
#define _cleanup_button_ _cleanup_(cleanup_button)
|
||||
#define _cleanup_led_ _cleanup_(cleanup_led)
|
||||
|
||||
#define BUS_ANY 0xffff
|
||||
#define VENDOR_ANY 0xffff
|
||||
@@ -90,6 +134,7 @@ struct ratbag_device {
|
||||
struct input_id ids;
|
||||
struct ratbag_driver *driver;
|
||||
struct ratbag *ratbag;
|
||||
struct ratbag_device_data *data;
|
||||
unsigned long capabilities[NLONGS(MAX_CAP)];
|
||||
|
||||
unsigned num_profiles;
|
||||
@@ -120,6 +165,10 @@ struct ratbag_driver {
|
||||
*
|
||||
* Return -ENODEV to ignore the device and let other drivers
|
||||
* probe the device. Any other error code will stop the probing.
|
||||
*
|
||||
* If a matching driver is found it should initialize itself
|
||||
* and synchronize all profiles with the current state on the device
|
||||
* in this callback.
|
||||
*/
|
||||
int (*probe)(struct ratbag_device *device);
|
||||
|
||||
@@ -145,27 +194,16 @@ struct ratbag_driver {
|
||||
int (*commit)(struct ratbag_device *device);
|
||||
|
||||
/**
|
||||
* Callback called when the device doesn't have the udev property
|
||||
* RATBAG_SVG.
|
||||
* Callback called when the device doesn't have a .device file with
|
||||
* an SVG name set.
|
||||
*
|
||||
* The returned value must not be free by the caller, the driver
|
||||
* has to free it during .remove().
|
||||
*/
|
||||
const char *(*get_svg_name)(const struct ratbag_device *device);
|
||||
|
||||
/**
|
||||
* Callback called when a read profile is requested by the
|
||||
* caller of the library.
|
||||
*
|
||||
* The driver should probe here the device for the requested
|
||||
* profile and populate the related information.
|
||||
* There is no need to populate the various struct ratbag_button
|
||||
* as they are allocated when the user needs it.
|
||||
*/
|
||||
void (*read_profile)(struct ratbag_profile *profile, unsigned int index);
|
||||
|
||||
/*
|
||||
* FIXME: This function is deprecated and should not be removed. Once
|
||||
* FIXME: This function is deprecated and should be removed. Once
|
||||
* we've updated all the device drivers to stop using it we'll remove
|
||||
* it. Look at commit() instead.
|
||||
*/
|
||||
@@ -179,21 +217,8 @@ struct ratbag_driver {
|
||||
*/
|
||||
int (*set_active_profile)(struct ratbag_device *device, unsigned int index);
|
||||
|
||||
/**
|
||||
* For the given button, fill in the struct ratbag_button
|
||||
* with the available information.
|
||||
*
|
||||
* For devices with profiles, profile will not be NULL. For
|
||||
* device without, profile will be set to NULL.
|
||||
*
|
||||
* For devices with profile, there should not be the need to
|
||||
* actually read the profile from the device. The caller
|
||||
* should make sure that the profile is up to date.
|
||||
*/
|
||||
void (*read_button)(struct ratbag_button *button);
|
||||
|
||||
/*
|
||||
* FIXME: This function is deprecated and should not be removed. Once
|
||||
* FIXME: This function is deprecated and should be removed. Once
|
||||
* we've updated all the device drivers to stop using it we'll remove
|
||||
* it. Look at commit() instead.
|
||||
*/
|
||||
@@ -201,26 +226,20 @@ struct ratbag_driver {
|
||||
const struct ratbag_button_action *action);
|
||||
|
||||
/*
|
||||
* FIXME: This function is deprecated and should not be removed. Once
|
||||
* FIXME: This function is deprecated and should be removed. Once
|
||||
* we've updated all the device drivers to stop using it we'll remove
|
||||
* it. Look at commit() instead.
|
||||
*/
|
||||
int (*write_resolution_dpi)(struct ratbag_resolution *resolution,
|
||||
int dpi_x, int dpi_y);
|
||||
|
||||
/**
|
||||
* For the given led, fill in the struct ratbag_led
|
||||
* with the available information.
|
||||
*/
|
||||
void (*read_led)(struct ratbag_led *led);
|
||||
|
||||
/*
|
||||
* FIXME: This function is deprecated and should be removed. Once
|
||||
* we've updated all the device drivers to stop using it we'll remove
|
||||
* it. Look at commit() instead.
|
||||
*/
|
||||
int (*write_led)(struct ratbag_led *led, enum ratbag_led_mode mode,
|
||||
struct ratbag_color color, unsigned int hz,
|
||||
struct ratbag_color color, unsigned int ms,
|
||||
unsigned int brightness);
|
||||
|
||||
/* private */
|
||||
@@ -233,11 +252,19 @@ struct ratbag_resolution {
|
||||
struct ratbag_profile *profile;
|
||||
int refcount;
|
||||
void *userdata;
|
||||
unsigned int dpi_max; /**< max resolution in dpi */
|
||||
unsigned int dpi_min; /**< min resolution in dpi */
|
||||
struct list link;
|
||||
unsigned index;
|
||||
|
||||
unsigned int dpis[300];
|
||||
size_t ndpis;
|
||||
|
||||
unsigned int dpi_x; /**< x resolution in dpi */
|
||||
unsigned int dpi_y; /**< y resolution in dpi */
|
||||
unsigned int hz; /**< report rate in Hz */
|
||||
|
||||
unsigned int rates[5];
|
||||
size_t nrates;
|
||||
|
||||
bool is_active;
|
||||
bool is_default;
|
||||
uint32_t capabilities;
|
||||
@@ -251,8 +278,10 @@ struct ratbag_led {
|
||||
unsigned index;
|
||||
enum ratbag_led_type type;
|
||||
enum ratbag_led_mode mode;
|
||||
uint32_t modes; /**< supported modes */
|
||||
struct ratbag_color color;
|
||||
unsigned int hz; /**< rate of action in hz */
|
||||
enum ratbag_led_colordepth colordepth;
|
||||
unsigned int ms; /**< duration of action in ms */
|
||||
unsigned int brightness; /**< brightness of the LED */
|
||||
bool dirty;
|
||||
};
|
||||
@@ -260,6 +289,7 @@ struct ratbag_led {
|
||||
struct ratbag_profile {
|
||||
int refcount;
|
||||
void *userdata;
|
||||
char *name;
|
||||
|
||||
struct list link;
|
||||
unsigned index;
|
||||
@@ -267,17 +297,29 @@ struct ratbag_profile {
|
||||
struct list buttons;
|
||||
void *drv_data;
|
||||
void *user_data;
|
||||
struct {
|
||||
struct ratbag_resolution *modes;
|
||||
unsigned int num_modes;
|
||||
} resolution;
|
||||
struct list resolutions;
|
||||
struct list leds;
|
||||
|
||||
unsigned int num_resolutions;
|
||||
|
||||
bool is_active; /**< profile is the currently active one */
|
||||
bool is_enabled;
|
||||
bool dirty; /**< profile changed since last commit */
|
||||
unsigned long capabilities[NLONGS(MAX_CAP)];
|
||||
};
|
||||
|
||||
#define ratbag_device_for_each_profile(device_, profile_) \
|
||||
list_for_each(profile_, &(device_)->profiles, link)
|
||||
|
||||
#define ratbag_profile_for_each_button(profile_, button_) \
|
||||
list_for_each(button_, &(profile_)->buttons, link) \
|
||||
|
||||
#define ratbag_profile_for_each_led(profile_, led_) \
|
||||
list_for_each(led_, &(profile_)->leds, link)
|
||||
|
||||
#define ratbag_profile_for_each_resolution(profile_, resolution_) \
|
||||
list_for_each(resolution_, &(profile_)->resolutions, link)
|
||||
|
||||
#define BUTTON_ACTION_NONE \
|
||||
{ .type = RATBAG_BUTTON_ACTION_TYPE_NONE }
|
||||
#define BUTTON_ACTION_BUTTON(num_) \
|
||||
@@ -338,6 +380,10 @@ struct ratbag_button {
|
||||
bool dirty; /* changed since last commit to device */
|
||||
};
|
||||
|
||||
void
|
||||
ratbag_button_set_action(struct ratbag_button *button,
|
||||
const struct ratbag_button_action *action);
|
||||
|
||||
static inline void
|
||||
ratbag_button_enable_action_type(struct ratbag_button *button,
|
||||
enum ratbag_button_action_type type)
|
||||
@@ -384,6 +430,10 @@ void
|
||||
ratbag_device_set_capability(struct ratbag_device *device,
|
||||
enum ratbag_device_capability cap);
|
||||
|
||||
void
|
||||
ratbag_device_unset_capability(struct ratbag_device *device,
|
||||
enum ratbag_device_capability cap);
|
||||
|
||||
static inline void
|
||||
ratbag_profile_set_drv_data(struct ratbag_profile *profile, void *drv_data)
|
||||
{
|
||||
@@ -396,6 +446,15 @@ ratbag_profile_get_drv_data(struct ratbag_profile *profile)
|
||||
return profile->drv_data;
|
||||
}
|
||||
|
||||
static inline void
|
||||
ratbag_profile_set_cap(struct ratbag_profile *profile,
|
||||
enum ratbag_profile_capability cap)
|
||||
{
|
||||
assert(cap <= MAX_CAP);
|
||||
|
||||
long_set_bit(profile->capabilities, cap);
|
||||
}
|
||||
|
||||
static inline int
|
||||
ratbag_button_action_match(const struct ratbag_button_action *action,
|
||||
const struct ratbag_button_action *match)
|
||||
@@ -419,30 +478,82 @@ ratbag_button_action_match(const struct ratbag_button_action *action,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline struct ratbag_resolution *
|
||||
ratbag_resolution_init(struct ratbag_profile *profile, int index,
|
||||
int dpi_x, int dpi_y, int hz)
|
||||
static inline void
|
||||
ratbag_resolution_set_resolution(struct ratbag_resolution *res,
|
||||
int dpi_x, int dpi_y, int hz)
|
||||
{
|
||||
struct ratbag_resolution *res = &profile->resolution.modes[index];
|
||||
|
||||
res->profile = profile;
|
||||
res->dpi_x = dpi_x;
|
||||
res->dpi_y = dpi_y;
|
||||
res->hz = hz;
|
||||
res->is_active = false;
|
||||
res->is_default = false;
|
||||
res->capabilities = 0;
|
||||
res->dpi_min = 0;
|
||||
res->dpi_max = 0;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static inline void
|
||||
ratbag_resolution_set_range(struct ratbag_resolution *res, int min, int max)
|
||||
ratbag_resolution_set_dpi_list_from_range(struct ratbag_resolution *res,
|
||||
unsigned int min, unsigned int max)
|
||||
{
|
||||
res->dpi_min = min;
|
||||
res->dpi_max = max;
|
||||
unsigned int stepsize = 50;
|
||||
unsigned int dpi = min;
|
||||
bool maxed_out = false;
|
||||
|
||||
res->ndpis = 0;
|
||||
|
||||
while (res->ndpis < ARRAY_LENGTH(res->dpis)) {
|
||||
if (dpi > (unsigned)max) {
|
||||
maxed_out = true;
|
||||
break;
|
||||
}
|
||||
|
||||
res->dpis[res->ndpis] = dpi;
|
||||
res->ndpis++;
|
||||
|
||||
if (dpi < 1000)
|
||||
stepsize = 50;
|
||||
else if (dpi < 2600)
|
||||
stepsize = 100;
|
||||
else if (dpi < 5000)
|
||||
stepsize = 200;
|
||||
else
|
||||
stepsize = 500;
|
||||
|
||||
dpi += stepsize;
|
||||
}
|
||||
|
||||
if (!maxed_out)
|
||||
log_bug_libratbag(res->profile->device->ratbag,
|
||||
"%s: resolution range exceeds available space.\n",
|
||||
res->profile->device->name);
|
||||
}
|
||||
|
||||
static inline void
|
||||
ratbag_resolution_set_dpi_list(struct ratbag_resolution *res,
|
||||
unsigned int *dpis,
|
||||
size_t ndpis)
|
||||
{
|
||||
assert(ndpis <= ARRAY_LENGTH(res->dpis));
|
||||
_Static_assert(sizeof(*dpis) == sizeof(*res->dpis), "Mismatching size");
|
||||
|
||||
for (size_t i = 0; i < ndpis; i++) {
|
||||
res->dpis[i] = dpis[i];
|
||||
if (i > 0)
|
||||
assert(dpis[i] > dpis[i - 1]);
|
||||
}
|
||||
res->ndpis = ndpis;
|
||||
}
|
||||
|
||||
static inline void
|
||||
ratbag_resolution_set_report_rate_list(struct ratbag_resolution *res,
|
||||
unsigned int *rates,
|
||||
size_t nrates)
|
||||
{
|
||||
assert(nrates <= ARRAY_LENGTH(res->rates));
|
||||
_Static_assert(sizeof(*rates) == sizeof(*res->rates), "Mismatching size");
|
||||
|
||||
for (size_t i = 0; i < nrates; i++) {
|
||||
res->rates[i] = rates[i];
|
||||
if (i > 0)
|
||||
assert(rates[i] > rates[i - 1]);
|
||||
}
|
||||
res->nrates = nrates;
|
||||
}
|
||||
|
||||
static inline void
|
||||
@@ -454,33 +565,15 @@ ratbag_resolution_set_cap(struct ratbag_resolution *res,
|
||||
res->capabilities = (1 << cap);
|
||||
}
|
||||
|
||||
void
|
||||
log_msg_va(struct ratbag *ratbag,
|
||||
enum ratbag_log_priority priority,
|
||||
const char *format,
|
||||
va_list args)
|
||||
LIBRATBAG_ATTRIBUTE_PRINTF(3, 0);
|
||||
void log_msg(struct ratbag *ratbag,
|
||||
enum ratbag_log_priority priority,
|
||||
const char *format, ...)
|
||||
LIBRATBAG_ATTRIBUTE_PRINTF(3, 4);
|
||||
void
|
||||
log_buffer(struct ratbag *ratbag,
|
||||
enum ratbag_log_priority priority,
|
||||
const char *header,
|
||||
uint8_t *buf, size_t len);
|
||||
static inline void
|
||||
ratbag_led_set_mode_capability(struct ratbag_led *led,
|
||||
enum ratbag_led_mode mode)
|
||||
{
|
||||
assert(mode <= RATBAG_LED_BREATHING);
|
||||
assert(mode < sizeof(led->modes) * 8);
|
||||
|
||||
#define log_raw(li_, ...) log_msg((li_), RATBAG_LOG_PRIORITY_RAW, __VA_ARGS__)
|
||||
#define log_debug(li_, ...) log_msg((li_), RATBAG_LOG_PRIORITY_DEBUG, __VA_ARGS__)
|
||||
#define log_info(li_, ...) log_msg((li_), RATBAG_LOG_PRIORITY_INFO, __VA_ARGS__)
|
||||
#define log_error(li_, ...) log_msg((li_), RATBAG_LOG_PRIORITY_ERROR, __VA_ARGS__)
|
||||
#define log_bug_kernel(li_, ...) log_msg((li_), RATBAG_LOG_PRIORITY_ERROR, "kernel bug: " __VA_ARGS__)
|
||||
#define log_bug_libratbag(li_, ...) log_msg((li_), RATBAG_LOG_PRIORITY_ERROR, "libratbag bug: " __VA_ARGS__)
|
||||
#define log_bug_client(li_, ...) log_msg((li_), RATBAG_LOG_PRIORITY_ERROR, "client bug: " __VA_ARGS__)
|
||||
#define log_buf_raw(li_, h_, buf_, len_) log_buffer(li_, RATBAG_LOG_PRIORITY_RAW, h_, buf_, len_)
|
||||
#define log_buf_debug(li_, h_, buf_, len_) log_buffer(li_, RATBAG_LOG_PRIORITY_DEBUG, h_, buf_, len_)
|
||||
#define log_buf_info(li_, h_, buf_, len_) log_buffer(li_, RATBAG_LOG_PRIORITY_INFO, h_, buf_, len_)
|
||||
#define log_buf_error(li_, h_, buf_, len_) log_buffer(li_, RATBAG_LOG_PRIORITY_ERROR, h_, buf_, len_)
|
||||
led->modes |= (1 << mode);
|
||||
}
|
||||
|
||||
/* list of all supported drivers */
|
||||
struct ratbag_driver etekcity_driver;
|
||||
@@ -489,6 +582,7 @@ struct ratbag_driver hidpp10_driver;
|
||||
struct ratbag_driver logitech_g300_driver;
|
||||
struct ratbag_driver roccat_driver;
|
||||
struct ratbag_driver gskill_driver;
|
||||
struct ratbag_driver steelseries_driver;
|
||||
|
||||
struct ratbag_device*
|
||||
ratbag_device_new(struct ratbag *ratbag, struct udev_device *udev_device,
|
||||
|
||||
@@ -24,6 +24,8 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "libratbag.h"
|
||||
|
||||
#define RATBAG_TEST_MAX_PROFILES 12
|
||||
@@ -53,6 +55,9 @@ struct ratbag_test_resolution {
|
||||
bool active;
|
||||
bool dflt;
|
||||
uint32_t caps;
|
||||
|
||||
int dpi_min, dpi_max;
|
||||
unsigned int report_rates[5];
|
||||
};
|
||||
|
||||
struct ratbag_test_color {
|
||||
@@ -65,7 +70,7 @@ struct ratbag_test_led {
|
||||
enum ratbag_led_type type;
|
||||
enum ratbag_led_mode mode;
|
||||
struct ratbag_test_color color;
|
||||
unsigned int hz;
|
||||
unsigned int ms;
|
||||
unsigned int brightness;
|
||||
};
|
||||
|
||||
@@ -76,6 +81,7 @@ struct ratbag_test_profile {
|
||||
bool active;
|
||||
bool dflt;
|
||||
bool disabled;
|
||||
uint32_t caps[10];
|
||||
};
|
||||
|
||||
struct ratbag_test_device {
|
||||
|
||||
@@ -23,6 +23,8 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
@@ -116,6 +118,24 @@ snprintf_safe(char *buf, size_t n, const char *fmt, ...)
|
||||
#define sprintf_safe(buf, fmt, ...) \
|
||||
snprintf_safe(buf, ARRAY_LENGTH(buf), fmt, __VA_ARGS__)
|
||||
|
||||
__attribute__((format(printf, 1, 2)))
|
||||
static inline void *
|
||||
asprintf_safe(const char *fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
int rc;
|
||||
char *result;
|
||||
|
||||
va_start(args, fmt);
|
||||
rc = vasprintf(&result, fmt, args);
|
||||
va_end(args);
|
||||
|
||||
if (rc < 0)
|
||||
abort();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static inline void
|
||||
msleep(unsigned int ms)
|
||||
{
|
||||
@@ -169,3 +189,120 @@ ratbag_utf8_to_enc(char *buf, size_t buf_len, const char *to_enc,
|
||||
ssize_t
|
||||
ratbag_utf8_from_enc(char *in_buf, size_t in_len, const char *from_enc,
|
||||
char **out);
|
||||
|
||||
__attribute__((format(printf, 2, 3)))
|
||||
static inline int
|
||||
xasprintf(char **strp, const char *fmt, ...)
|
||||
{
|
||||
int rc = 0;
|
||||
va_list args;
|
||||
|
||||
va_start(args, fmt);
|
||||
rc = vasprintf(strp, fmt, args);
|
||||
va_end(args);
|
||||
if ((rc == -1) && strp)
|
||||
*strp = NULL;
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
struct dpi_range {
|
||||
unsigned int min;
|
||||
unsigned int max;
|
||||
float step;
|
||||
};
|
||||
|
||||
/* Parse a string in the form min:max@step to a dpi_range */
|
||||
static inline struct dpi_range *
|
||||
dpi_range_from_string(const char *str)
|
||||
{
|
||||
float min, max, step;
|
||||
int rc;
|
||||
struct dpi_range *range;
|
||||
|
||||
rc = sscanf(str, "%f:%f@%f", &min, &max, &step);
|
||||
if (rc != 3 || min < 0 || max <= min || step < 20)
|
||||
return NULL;
|
||||
|
||||
range = zalloc(sizeof(*range));
|
||||
range->min = min;
|
||||
range->max = max;
|
||||
range->step = step;
|
||||
|
||||
return range;
|
||||
}
|
||||
|
||||
struct dpi_list {
|
||||
int *entries;
|
||||
size_t nentries;
|
||||
};
|
||||
|
||||
static inline void
|
||||
dpi_list_free(struct dpi_list *list)
|
||||
{
|
||||
free(list->entries);
|
||||
free(list);
|
||||
}
|
||||
|
||||
DEFINE_TRIVIAL_CLEANUP_FUNC(struct dpi_list *, dpi_list_free);
|
||||
|
||||
/* Parse a string in the form "100;200;400"to a dpi_list */
|
||||
static inline struct dpi_list *
|
||||
dpi_list_from_string(const char *str)
|
||||
{
|
||||
struct dpi_list *list;
|
||||
unsigned int i, count, index;
|
||||
int nread, dpi = 0;
|
||||
char c;
|
||||
void *tmp;
|
||||
|
||||
if (!str || str[0] == '\0')
|
||||
return NULL;
|
||||
printf("%s: ", str);
|
||||
|
||||
/* first, count how many elements do we have in the table */
|
||||
count = 1;
|
||||
i = 0;
|
||||
while (str[i] != 0) {
|
||||
c = str[i++];
|
||||
if (c == ';')
|
||||
count++;
|
||||
}
|
||||
|
||||
list = zalloc(sizeof *list);
|
||||
list->nentries = count;
|
||||
list->entries = zalloc(count * sizeof(list->entries[0]));
|
||||
|
||||
index = 0;
|
||||
|
||||
while (*str != 0 && index < count) {
|
||||
if (*str == ';') {
|
||||
str++;
|
||||
continue;
|
||||
}
|
||||
|
||||
nread = 0;
|
||||
sscanf(str, "%d%n", &dpi, &nread);
|
||||
if (!nread || dpi < 0)
|
||||
goto err;
|
||||
|
||||
list->entries[index] = dpi;
|
||||
str += nread;
|
||||
index++;
|
||||
}
|
||||
|
||||
if (index == 0)
|
||||
goto err;
|
||||
|
||||
/* Drop empty entries for trailing semicolons */
|
||||
list->nentries = index;
|
||||
tmp = realloc(list->entries, index * sizeof(list->entries[0]));
|
||||
if (tmp)
|
||||
list->entries = tmp;
|
||||
|
||||
return list;
|
||||
|
||||
err:
|
||||
dpi_list_free(list);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
332
src/libratbag.c
@@ -37,6 +37,7 @@
|
||||
#include "usb-ids.h"
|
||||
#include "libratbag-private.h"
|
||||
#include "libratbag-util.h"
|
||||
#include "libratbag-data.h"
|
||||
|
||||
static enum ratbag_error_code
|
||||
error_code(enum ratbag_error_code code)
|
||||
@@ -61,6 +62,8 @@ static void
|
||||
ratbag_button_destroy(struct ratbag_button *button);
|
||||
static void
|
||||
ratbag_led_destroy(struct ratbag_led *led);
|
||||
static void
|
||||
ratbag_resolution_destroy(struct ratbag_resolution *resolution);
|
||||
|
||||
static void
|
||||
ratbag_default_log_func(struct ratbag *ratbag,
|
||||
@@ -180,6 +183,7 @@ ratbag_device_new(struct ratbag *ratbag, struct udev_device *udev_device,
|
||||
device->refcount = 1;
|
||||
device->udev_device = udev_device_ref(udev_device);
|
||||
device->ids = *id;
|
||||
device->data = ratbag_device_data_new_for_id(ratbag, id);
|
||||
list_init(&device->profiles);
|
||||
|
||||
list_insert(&ratbag->devices, &device->link);
|
||||
@@ -217,6 +221,7 @@ ratbag_device_destroy(struct ratbag_device *device)
|
||||
list_remove(&device->link);
|
||||
|
||||
ratbag_unref(device->ratbag);
|
||||
ratbag_device_data_unref(device->data);
|
||||
free(device->name);
|
||||
free(device);
|
||||
}
|
||||
@@ -225,11 +230,10 @@ static inline bool
|
||||
ratbag_sanity_check_device(struct ratbag_device *device)
|
||||
{
|
||||
struct ratbag *ratbag = device->ratbag;
|
||||
_cleanup_profile_ struct ratbag_profile *profile = NULL;
|
||||
struct ratbag_profile *profile = NULL;
|
||||
bool has_active = false;
|
||||
unsigned int nres, nprofiles;
|
||||
unsigned int nres;
|
||||
bool rc = false;
|
||||
unsigned int i;
|
||||
|
||||
/* arbitrary number: max 16 profiles, does any mouse have more? but
|
||||
* since we have num_profiles unsigned, it also checks for
|
||||
@@ -242,11 +246,8 @@ ratbag_sanity_check_device(struct ratbag_device *device)
|
||||
goto out;
|
||||
}
|
||||
|
||||
nprofiles = ratbag_device_get_num_profiles(device);
|
||||
for (i = 0; i < nprofiles; i++) {
|
||||
profile = ratbag_device_get_profile(device, i);
|
||||
if (!profile)
|
||||
goto out;
|
||||
ratbag_device_for_each_profile(device, profile) {
|
||||
struct ratbag_resolution *resolution;
|
||||
|
||||
/* Allow max 1 active profile */
|
||||
if (profile->is_active) {
|
||||
@@ -268,8 +269,29 @@ ratbag_sanity_check_device(struct ratbag_device *device)
|
||||
goto out;
|
||||
}
|
||||
|
||||
ratbag_profile_unref(profile);
|
||||
profile = NULL;
|
||||
ratbag_profile_for_each_resolution(profile, resolution) {
|
||||
unsigned int vals[300];
|
||||
unsigned int nvals = ARRAY_LENGTH(vals);
|
||||
|
||||
if (!ratbag_device_has_capability(device, RATBAG_DEVICE_CAP_RESOLUTION))
|
||||
break;
|
||||
|
||||
nvals = ratbag_resolution_get_dpi_list(resolution, vals, nvals);
|
||||
if (nvals == 0) {
|
||||
log_bug_libratbag(ratbag,
|
||||
"%s: invalid dpi list\n",
|
||||
device->name);
|
||||
goto out;
|
||||
}
|
||||
|
||||
nvals = ratbag_resolution_get_report_rate_list(resolution, vals, nvals);
|
||||
if (nvals == 0) {
|
||||
log_bug_libratbag(ratbag,
|
||||
"%s: invalid report rate list\n",
|
||||
device->name);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Require 1 active profile */
|
||||
@@ -280,6 +302,29 @@ ratbag_sanity_check_device(struct ratbag_device *device)
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Require LED to be the same type in each profile */
|
||||
ratbag_device_for_each_profile(device, profile) {
|
||||
_cleanup_profile_ struct ratbag_profile *p0 = ratbag_device_get_profile(device, 0);
|
||||
struct ratbag_led *led;
|
||||
|
||||
|
||||
ratbag_profile_for_each_led(profile, led) {
|
||||
_cleanup_led_ struct ratbag_led *p0_led = ratbag_profile_get_led(p0, led->index);
|
||||
|
||||
assert(led->type != RATBAG_LED_TYPE_UNKNOWN);
|
||||
|
||||
if (p0_led->type != led->type) {
|
||||
log_bug_libratbag(ratbag,
|
||||
"%s: mismatching LED types (profile %d led %d)\n",
|
||||
device->name,
|
||||
profile->index,
|
||||
led->type);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
rc = true;
|
||||
|
||||
out:
|
||||
@@ -358,7 +403,7 @@ ratbag_assign_driver(struct ratbag_device *device,
|
||||
const char *driver_name;
|
||||
|
||||
if (!test_device) {
|
||||
driver_name = udev_prop_value(device->udev_device, "RATBAG_DRIVER");
|
||||
driver_name = ratbag_device_data_get_driver(device->data);
|
||||
} else {
|
||||
driver_name = "test_driver";
|
||||
}
|
||||
@@ -433,7 +478,7 @@ ratbag_device_new_from_udev_device(struct ratbag *ratbag,
|
||||
goto out_err;
|
||||
|
||||
device = ratbag_device_new(ratbag, udev_device, name, &id);
|
||||
if (!device)
|
||||
if (!device || !device->data)
|
||||
goto out_err;
|
||||
|
||||
if (!ratbag_assign_driver(device, &device->ids, NULL))
|
||||
@@ -483,22 +528,16 @@ ratbag_device_get_name(const struct ratbag_device* device)
|
||||
LIBRATBAG_EXPORT const char *
|
||||
ratbag_device_get_svg_name(const struct ratbag_device* device)
|
||||
{
|
||||
const char *name;
|
||||
const char *name = NULL;
|
||||
|
||||
name = udev_prop_value(device->udev_device, "RATBAG_SVG");
|
||||
if (device->data)
|
||||
name = ratbag_device_data_get_svg(device->data);
|
||||
if (!name && device->driver->get_svg_name)
|
||||
name = device->driver->get_svg_name(device);
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
const char *
|
||||
ratbag_device_get_udev_property(const struct ratbag_device* device,
|
||||
const char *name)
|
||||
{
|
||||
return udev_prop_value(device->udev_device, name);
|
||||
}
|
||||
|
||||
void
|
||||
ratbag_register_driver(struct ratbag *ratbag, struct ratbag_driver *driver)
|
||||
{
|
||||
@@ -546,6 +585,7 @@ ratbag_create_context(const struct ratbag_interface *interface,
|
||||
ratbag_register_driver(ratbag, &logitech_g300_driver);
|
||||
ratbag_register_driver(ratbag, &roccat_driver);
|
||||
ratbag_register_driver(ratbag, &gskill_driver);
|
||||
ratbag_register_driver(ratbag, &steelseries_driver);
|
||||
|
||||
return ratbag;
|
||||
}
|
||||
@@ -576,19 +616,16 @@ ratbag_unref(struct ratbag *ratbag)
|
||||
static struct ratbag_button *
|
||||
ratbag_create_button(struct ratbag_profile *profile, unsigned int index)
|
||||
{
|
||||
struct ratbag_device *device = profile->device;
|
||||
struct ratbag_button *button;
|
||||
|
||||
button = zalloc(sizeof(*button));
|
||||
button->refcount = 0;
|
||||
button->profile = profile;
|
||||
button->index = index;
|
||||
button->type = RATBAG_BUTTON_TYPE_UNKNOWN;
|
||||
|
||||
list_insert(&profile->buttons, &button->link);
|
||||
|
||||
if (device->driver->read_button)
|
||||
device->driver->read_button(button);
|
||||
|
||||
return button;
|
||||
}
|
||||
|
||||
@@ -602,41 +639,42 @@ ratbag_create_led(struct ratbag_profile *profile, unsigned int index)
|
||||
led->refcount = 0;
|
||||
led->profile = profile;
|
||||
led->index = index;
|
||||
led->colordepth = RATBAG_LED_COLORDEPTH_RGB_888;
|
||||
led->type = RATBAG_LED_TYPE_UNKNOWN;
|
||||
if (device->data)
|
||||
led->type = ratbag_device_data_get_led_type(device->data, led->index);
|
||||
|
||||
list_insert(&profile->leds, &led->link);
|
||||
|
||||
if (device->driver->read_led)
|
||||
device->driver->read_led(led);
|
||||
|
||||
return led;
|
||||
}
|
||||
|
||||
static int
|
||||
ratbag_profile_init_buttons(struct ratbag_profile *profile, unsigned int count)
|
||||
LIBRATBAG_EXPORT int
|
||||
ratbag_profile_has_capability(const struct ratbag_profile *profile,
|
||||
enum ratbag_profile_capability cap)
|
||||
{
|
||||
unsigned int i;
|
||||
if (cap == RATBAG_PROFILE_CAP_NONE || cap >= MAX_CAP)
|
||||
abort();
|
||||
|
||||
for (i = 0; i < count; i++)
|
||||
ratbag_create_button(profile, i);
|
||||
|
||||
profile->device->num_buttons = count;
|
||||
|
||||
return 0;
|
||||
return long_bit_is_set(profile->capabilities, cap);
|
||||
}
|
||||
|
||||
static int
|
||||
ratbag_profile_init_leds(struct ratbag_profile *profile, unsigned int count)
|
||||
static inline void
|
||||
ratbag_create_resolution(struct ratbag_profile *profile, int index)
|
||||
{
|
||||
unsigned int i;
|
||||
struct ratbag_resolution *res;
|
||||
|
||||
for (i = 0; i < count; i++)
|
||||
ratbag_create_led(profile, i);
|
||||
res = zalloc(sizeof(*res));
|
||||
res->refcount = 0;
|
||||
res->profile = profile;
|
||||
res->index = index;
|
||||
|
||||
profile->device->num_leds = count;
|
||||
list_insert(&profile->resolutions, &res->link);
|
||||
|
||||
return 0;
|
||||
profile->num_resolutions++;
|
||||
}
|
||||
|
||||
|
||||
static struct ratbag_profile *
|
||||
ratbag_create_profile(struct ratbag_device *device,
|
||||
unsigned int index,
|
||||
@@ -651,24 +689,26 @@ ratbag_create_profile(struct ratbag_device *device,
|
||||
profile->refcount = 0;
|
||||
profile->device = device;
|
||||
profile->index = index;
|
||||
if (num_resolutions)
|
||||
profile->resolution.modes = zalloc(num_resolutions *
|
||||
sizeof(*profile->resolution.modes));
|
||||
profile->resolution.num_modes = num_resolutions;
|
||||
profile->num_resolutions = 0;
|
||||
profile->is_enabled = true;
|
||||
profile->name = asprintf_safe("Profile %d", index + 1);
|
||||
|
||||
list_insert(&device->profiles, &profile->link);
|
||||
list_init(&profile->buttons);
|
||||
list_init(&profile->leds);
|
||||
list_init(&profile->resolutions);
|
||||
|
||||
profile->device->num_buttons = num_buttons;
|
||||
profile->device->num_leds = num_leds;
|
||||
|
||||
for (i = 0; i < num_resolutions; i++)
|
||||
ratbag_resolution_init(profile, i, 0, 0, 0);
|
||||
ratbag_create_resolution(profile, i);
|
||||
|
||||
assert(device->driver->read_profile);
|
||||
device->driver->read_profile(profile, index);
|
||||
for (i = 0; i < num_buttons; i++)
|
||||
ratbag_create_button(profile, i);
|
||||
|
||||
ratbag_profile_init_buttons(profile, num_buttons);
|
||||
ratbag_profile_init_leds(profile, num_leds);
|
||||
for (i = 0; i < num_leds; i++)
|
||||
ratbag_create_led(profile, i);
|
||||
|
||||
return profile;
|
||||
}
|
||||
@@ -703,7 +743,7 @@ ratbag_device_init_profiles(struct ratbag_device *device,
|
||||
ratbag_device_set_capability(device, RATBAG_DEVICE_CAP_SWITCHABLE_RESOLUTION);
|
||||
}
|
||||
|
||||
if (num_leds > 1)
|
||||
if (num_leds > 0)
|
||||
ratbag_device_set_capability(device, RATBAG_DEVICE_CAP_LED);
|
||||
|
||||
return 0;
|
||||
@@ -724,6 +764,7 @@ ratbag_profile_destroy(struct ratbag_profile *profile)
|
||||
{
|
||||
struct ratbag_button *button, *b_next;
|
||||
struct ratbag_led *led, *l_next;
|
||||
struct ratbag_resolution *res, *r_next;
|
||||
|
||||
/* if we get to the point where the profile is destroyed, buttons,
|
||||
* resolutions , etc. are at a refcount of 0, so we can destroy
|
||||
@@ -734,7 +775,10 @@ ratbag_profile_destroy(struct ratbag_profile *profile)
|
||||
list_for_each_safe(led, l_next, &profile->leds, link)
|
||||
ratbag_led_destroy(led);
|
||||
|
||||
free(profile->resolution.modes);
|
||||
list_for_each_safe(res, r_next, &profile->resolutions, link)
|
||||
ratbag_resolution_destroy(res);
|
||||
|
||||
free(profile->name);
|
||||
|
||||
list_remove(&profile->link);
|
||||
free(profile);
|
||||
@@ -838,6 +882,16 @@ ratbag_device_set_capability(struct ratbag_device *device,
|
||||
long_set_bit(device->capabilities, cap);
|
||||
}
|
||||
|
||||
void
|
||||
ratbag_device_unset_capability(struct ratbag_device *device,
|
||||
enum ratbag_device_capability cap)
|
||||
{
|
||||
if (cap == RATBAG_DEVICE_CAP_NONE || cap >= MAX_CAP)
|
||||
abort();
|
||||
|
||||
long_clear_bit(device->capabilities, cap);
|
||||
}
|
||||
|
||||
LIBRATBAG_EXPORT int
|
||||
ratbag_device_has_capability(const struct ratbag_device *device,
|
||||
enum ratbag_device_capability cap)
|
||||
@@ -851,7 +905,7 @@ ratbag_device_has_capability(const struct ratbag_device *device,
|
||||
static inline enum ratbag_error_code
|
||||
write_led_helper(struct ratbag_device *device, struct ratbag_led *led)
|
||||
{
|
||||
return device->driver->write_led(led, led->mode, led->color, led->hz, led->brightness);
|
||||
return device->driver->write_led(led, led->mode, led->color, led->ms, led->brightness);
|
||||
}
|
||||
|
||||
/* FIXME: This is a temporary fix for all of the drivers that have yet to be
|
||||
@@ -866,7 +920,6 @@ ratbag_old_write_profile(struct ratbag_device *device)
|
||||
struct ratbag_led *led;
|
||||
struct ratbag_resolution *resolution;
|
||||
int rc;
|
||||
unsigned int i;
|
||||
|
||||
assert(device->driver->write_profile);
|
||||
|
||||
@@ -879,9 +932,7 @@ ratbag_old_write_profile(struct ratbag_device *device)
|
||||
return RATBAG_ERROR_DEVICE;
|
||||
|
||||
if (device->driver->write_resolution_dpi) {
|
||||
for (i = 0; i < profile->resolution.num_modes; i++) {
|
||||
resolution = &profile->resolution.modes[i];
|
||||
|
||||
ratbag_profile_for_each_resolution(profile, resolution) {
|
||||
rc = device->driver->write_resolution_dpi(
|
||||
resolution, resolution->dpi_x,
|
||||
resolution->dpi_y);
|
||||
@@ -972,12 +1023,13 @@ ratbag_profile_set_active(struct ratbag_profile *profile)
|
||||
LIBRATBAG_EXPORT unsigned int
|
||||
ratbag_profile_get_num_resolutions(struct ratbag_profile *profile)
|
||||
{
|
||||
return profile->resolution.num_modes;
|
||||
return profile->num_resolutions;
|
||||
}
|
||||
|
||||
LIBRATBAG_EXPORT struct ratbag_resolution *
|
||||
ratbag_profile_get_resolution(struct ratbag_profile *profile, unsigned int idx)
|
||||
{
|
||||
struct ratbag_device *device = profile->device;
|
||||
struct ratbag_resolution *res;
|
||||
unsigned max = ratbag_profile_get_num_resolutions(profile);
|
||||
|
||||
@@ -987,9 +1039,15 @@ ratbag_profile_get_resolution(struct ratbag_profile *profile, unsigned int idx)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
res = &profile->resolution.modes[idx];
|
||||
ratbag_profile_for_each_resolution(profile, res) {
|
||||
if (res->index == idx)
|
||||
return ratbag_resolution_ref(res);
|
||||
}
|
||||
|
||||
return ratbag_resolution_ref(res);
|
||||
log_bug_libratbag(device->ratbag, "Resolution %d, profile %d not found\n",
|
||||
idx, profile->index);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
LIBRATBAG_EXPORT struct ratbag_resolution *
|
||||
@@ -1080,12 +1138,11 @@ ratbag_resolution_set_report_rate(struct ratbag_resolution *resolution,
|
||||
}
|
||||
} else {
|
||||
struct ratbag_profile *profile = resolution->profile;
|
||||
unsigned int i;
|
||||
struct ratbag_resolution *res;
|
||||
|
||||
/* No indvidual report rate per resolution. Loop through all of
|
||||
* them and update. */
|
||||
for (i = 0; i < profile->resolution.num_modes; i++) {
|
||||
struct ratbag_resolution *res = &profile->resolution.modes[i];
|
||||
ratbag_profile_for_each_resolution(profile, res) {
|
||||
if (res->hz != hz) {
|
||||
res->hz = hz;
|
||||
profile->dirty = true;
|
||||
@@ -1102,16 +1159,22 @@ ratbag_resolution_get_dpi(struct ratbag_resolution *resolution)
|
||||
return resolution->dpi_x;
|
||||
}
|
||||
|
||||
LIBRATBAG_EXPORT int
|
||||
ratbag_resolution_get_dpi_maximum(struct ratbag_resolution *resolution)
|
||||
LIBRATBAG_EXPORT size_t
|
||||
ratbag_resolution_get_dpi_list(struct ratbag_resolution *resolution,
|
||||
unsigned int *resolutions,
|
||||
size_t nres)
|
||||
{
|
||||
return resolution->dpi_max;
|
||||
}
|
||||
_Static_assert(sizeof(*resolutions) == sizeof(*resolution->dpis), "type mismatch");
|
||||
|
||||
LIBRATBAG_EXPORT int
|
||||
ratbag_resolution_get_dpi_minimum(struct ratbag_resolution *resolution)
|
||||
{
|
||||
return resolution->dpi_min;
|
||||
assert(nres > 0);
|
||||
|
||||
if (resolution->ndpis == 0)
|
||||
return 0;
|
||||
|
||||
memcpy(resolutions, resolution->dpis,
|
||||
sizeof(unsigned int) * min(nres, resolution->ndpis));
|
||||
|
||||
return resolution->ndpis;
|
||||
}
|
||||
|
||||
LIBRATBAG_EXPORT int
|
||||
@@ -1132,6 +1195,24 @@ ratbag_resolution_get_report_rate(struct ratbag_resolution *resolution)
|
||||
return resolution->hz;
|
||||
}
|
||||
|
||||
LIBRATBAG_EXPORT size_t
|
||||
ratbag_resolution_get_report_rate_list(struct ratbag_resolution *resolution,
|
||||
unsigned int *rates,
|
||||
size_t nrates)
|
||||
{
|
||||
_Static_assert(sizeof(*rates) == sizeof(*resolution->rates), "type mismatch");
|
||||
|
||||
assert(nrates > 0);
|
||||
|
||||
if (resolution->nrates == 0)
|
||||
return 0;
|
||||
|
||||
memcpy(rates, resolution->rates,
|
||||
sizeof(unsigned int) * min(nrates, resolution->nrates));
|
||||
|
||||
return resolution->nrates;
|
||||
}
|
||||
|
||||
LIBRATBAG_EXPORT int
|
||||
ratbag_resolution_is_active(const struct ratbag_resolution *resolution)
|
||||
{
|
||||
@@ -1142,10 +1223,10 @@ LIBRATBAG_EXPORT enum ratbag_error_code
|
||||
ratbag_resolution_set_active(struct ratbag_resolution *resolution)
|
||||
{
|
||||
struct ratbag_profile *profile = resolution->profile;
|
||||
unsigned int i;
|
||||
struct ratbag_resolution *res;
|
||||
|
||||
for (i = 0; i < profile->resolution.num_modes; i++)
|
||||
profile->resolution.modes[i].is_active = false;
|
||||
ratbag_profile_for_each_resolution(profile, res)
|
||||
res->is_active = false;
|
||||
|
||||
resolution->is_active = true;
|
||||
profile->dirty = true;
|
||||
@@ -1163,12 +1244,10 @@ LIBRATBAG_EXPORT enum ratbag_error_code
|
||||
ratbag_resolution_set_default(struct ratbag_resolution *resolution)
|
||||
{
|
||||
struct ratbag_profile *profile = resolution->profile;
|
||||
unsigned int i;
|
||||
struct ratbag_resolution *other;
|
||||
|
||||
/* Unset the default on the other resolutions */
|
||||
for (i = 0; i < profile->resolution.num_modes; i++) {
|
||||
struct ratbag_resolution *other = &profile->resolution.modes[i];
|
||||
|
||||
ratbag_profile_for_each_resolution(profile, other) {
|
||||
if (other == resolution || !other->is_default)
|
||||
continue;
|
||||
|
||||
@@ -1245,6 +1324,17 @@ ratbag_button_get_button(struct ratbag_button *button)
|
||||
return button->action.action.button;
|
||||
}
|
||||
|
||||
void
|
||||
ratbag_button_set_action(struct ratbag_button *button,
|
||||
const struct ratbag_button_action *action)
|
||||
{
|
||||
struct ratbag_macro *macro = button->action.macro;
|
||||
|
||||
button->action = *action;
|
||||
if (action->type != RATBAG_BUTTON_ACTION_TYPE_MACRO)
|
||||
button->action.macro = macro;
|
||||
}
|
||||
|
||||
LIBRATBAG_EXPORT enum ratbag_error_code
|
||||
ratbag_button_set_button(struct ratbag_button *button, unsigned int btn)
|
||||
{
|
||||
@@ -1257,7 +1347,7 @@ ratbag_button_set_button(struct ratbag_button *button, unsigned int btn)
|
||||
action.type = RATBAG_BUTTON_ACTION_TYPE_BUTTON;
|
||||
action.action.button = btn;
|
||||
|
||||
button->action = action;
|
||||
ratbag_button_set_action(button, &action);
|
||||
button->dirty = true;
|
||||
button->profile->dirty = true;
|
||||
|
||||
@@ -1288,7 +1378,7 @@ ratbag_button_set_special(struct ratbag_button *button,
|
||||
action.type = RATBAG_BUTTON_ACTION_TYPE_SPECIAL;
|
||||
action.action.special = act;
|
||||
|
||||
button->action = action;
|
||||
ratbag_button_set_action(button, &action);
|
||||
button->dirty = true;
|
||||
button->profile->dirty = true;
|
||||
|
||||
@@ -1327,7 +1417,7 @@ ratbag_button_set_key(struct ratbag_button *button,
|
||||
action.type = RATBAG_BUTTON_ACTION_TYPE_KEY;
|
||||
action.action.key.key = key;
|
||||
|
||||
button->action = action;
|
||||
ratbag_button_set_action(button, &action);
|
||||
button->dirty = true;
|
||||
button->profile->dirty = true;
|
||||
|
||||
@@ -1345,7 +1435,7 @@ ratbag_button_disable(struct ratbag_button *button)
|
||||
|
||||
action.type = RATBAG_BUTTON_ACTION_TYPE_NONE;
|
||||
|
||||
button->action = action;
|
||||
ratbag_button_set_action(button, &action);
|
||||
button->dirty = true;
|
||||
button->profile->dirty = true;
|
||||
|
||||
@@ -1377,8 +1467,8 @@ ratbag_button_destroy(struct ratbag_button *button)
|
||||
{
|
||||
list_remove(&button->link);
|
||||
if (button->action.macro) {
|
||||
if (button->action.macro->name)
|
||||
free(button->action.macro->name);
|
||||
free(button->action.macro->name);
|
||||
free(button->action.macro->group);
|
||||
free(button->action.macro);
|
||||
}
|
||||
free(button);
|
||||
@@ -1391,6 +1481,13 @@ ratbag_led_destroy(struct ratbag_led *led)
|
||||
free(led);
|
||||
}
|
||||
|
||||
static void
|
||||
ratbag_resolution_destroy(struct ratbag_resolution *res)
|
||||
{
|
||||
list_remove(&res->link);
|
||||
free(res);
|
||||
}
|
||||
|
||||
LIBRATBAG_EXPORT struct ratbag_button *
|
||||
ratbag_button_unref(struct ratbag_button *button)
|
||||
{
|
||||
@@ -1431,6 +1528,18 @@ ratbag_led_get_type(struct ratbag_led *led)
|
||||
return led->type;
|
||||
}
|
||||
|
||||
LIBRATBAG_EXPORT int
|
||||
ratbag_led_has_mode(struct ratbag_led *led,
|
||||
enum ratbag_led_mode mode)
|
||||
{
|
||||
assert(mode <= RATBAG_LED_BREATHING);
|
||||
|
||||
if (mode == RATBAG_LED_OFF)
|
||||
return 1;
|
||||
|
||||
return (led->modes & (1 << mode));
|
||||
}
|
||||
|
||||
LIBRATBAG_EXPORT struct ratbag_color
|
||||
ratbag_led_get_color(struct ratbag_led *led)
|
||||
{
|
||||
@@ -1438,9 +1547,9 @@ ratbag_led_get_color(struct ratbag_led *led)
|
||||
}
|
||||
|
||||
LIBRATBAG_EXPORT int
|
||||
ratbag_led_get_effect_rate(struct ratbag_led *led)
|
||||
ratbag_led_get_effect_duration(struct ratbag_led *led)
|
||||
{
|
||||
return led->hz;
|
||||
return led->ms;
|
||||
}
|
||||
|
||||
LIBRATBAG_EXPORT unsigned int
|
||||
@@ -1476,14 +1585,24 @@ ratbag_led_set_color(struct ratbag_led *led, struct ratbag_color color)
|
||||
return RATBAG_SUCCESS;
|
||||
}
|
||||
|
||||
LIBRATBAG_EXPORT enum ratbag_error_code
|
||||
ratbag_led_set_effect_rate(struct ratbag_led *led, unsigned int hz)
|
||||
LIBRATBAG_EXPORT enum ratbag_led_colordepth
|
||||
ratbag_led_get_colordepth(struct ratbag_led *led)
|
||||
{
|
||||
if (!ratbag_device_has_capability(led->profile->device,
|
||||
RATBAG_DEVICE_CAP_LED))
|
||||
return RATBAG_ERROR_CAPABILITY;
|
||||
|
||||
led->hz = hz;
|
||||
return led->colordepth;
|
||||
}
|
||||
|
||||
LIBRATBAG_EXPORT enum ratbag_error_code
|
||||
ratbag_led_set_effect_duration(struct ratbag_led *led, unsigned int ms)
|
||||
{
|
||||
if (!ratbag_device_has_capability(led->profile->device,
|
||||
RATBAG_DEVICE_CAP_LED))
|
||||
return RATBAG_ERROR_CAPABILITY;
|
||||
|
||||
led->ms = ms;
|
||||
led->dirty = true;
|
||||
led->profile->dirty = true;
|
||||
return RATBAG_SUCCESS;
|
||||
@@ -1525,6 +1644,31 @@ ratbag_profile_get_led(struct ratbag_profile *profile,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
LIBRATBAG_EXPORT const char *
|
||||
ratbag_profile_get_name(struct ratbag_profile *profile)
|
||||
{
|
||||
return profile->name;
|
||||
}
|
||||
|
||||
LIBRATBAG_EXPORT int
|
||||
ratbag_profile_set_name(struct ratbag_profile *profile,
|
||||
const char *name)
|
||||
{
|
||||
char *name_copy;
|
||||
|
||||
if (!ratbag_profile_has_capability(profile,
|
||||
RATBAG_PROFILE_CAP_WRITABLE_NAME))
|
||||
return RATBAG_ERROR_CAPABILITY;
|
||||
|
||||
name_copy = strdup_safe(name);
|
||||
if (profile->name)
|
||||
free(profile->name);
|
||||
|
||||
profile->name = name_copy;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
LIBRATBAG_EXPORT void
|
||||
ratbag_set_user_data(struct ratbag *ratbag, void *userdata)
|
||||
{
|
||||
@@ -1608,8 +1752,8 @@ ratbag_button_copy_macro(struct ratbag_button *button,
|
||||
if (!button->action.macro)
|
||||
button->action.macro = zalloc(sizeof(struct ratbag_macro));
|
||||
else {
|
||||
if (button->action.macro->name)
|
||||
free(button->action.macro->name);
|
||||
free(button->action.macro->name);
|
||||
free(button->action.macro->group);
|
||||
memset(button->action.macro, 0, sizeof(struct ratbag_macro));
|
||||
}
|
||||
|
||||
|
||||
470
src/libratbag.h
@@ -23,15 +23,13 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdbool.h>
|
||||
#include <libudev.h>
|
||||
|
||||
#include "libratbag-enums.h"
|
||||
|
||||
#define LIBRATBAG_ATTRIBUTE_PRINTF(_format, _args) \
|
||||
__attribute__ ((format (printf, _format, _args)))
|
||||
#define LIBRATBAG_ATTRIBUTE_DEPRECATED __attribute__ ((deprecated))
|
||||
@@ -160,49 +158,6 @@ struct ratbag_led;
|
||||
*/
|
||||
struct ratbag_button_macro;
|
||||
|
||||
/**
|
||||
* @ingroup base
|
||||
*
|
||||
* Error codes used by libratbag.
|
||||
*/
|
||||
enum ratbag_error_code {
|
||||
RATBAG_SUCCESS = 0,
|
||||
|
||||
/**
|
||||
* An error occured on the device. Either the device is not a
|
||||
* libratbag device or communication with the device failed.
|
||||
*/
|
||||
RATBAG_ERROR_DEVICE = -1000,
|
||||
|
||||
/**
|
||||
* Insufficient capabilities. This error occurs when a requested change is
|
||||
* beyond the device's capabilities.
|
||||
*/
|
||||
RATBAG_ERROR_CAPABILITY = -1001,
|
||||
|
||||
/**
|
||||
* Invalid value or value range. The provided value or value range
|
||||
* is outside of the legal or supported range.
|
||||
*/
|
||||
RATBAG_ERROR_VALUE = -1002,
|
||||
|
||||
/**
|
||||
* A low-level system error has occured, e.g. a failure to access
|
||||
* files that should be there. This error is usually unrecoverable
|
||||
* and libratbag will print a log message with details about the
|
||||
* error.
|
||||
*/
|
||||
RATBAG_ERROR_SYSTEM = -1003,
|
||||
|
||||
/**
|
||||
* Implementation bug, either in libratbag or in the caller. This
|
||||
* error is usually unrecoverable and libratbag will print a log
|
||||
* message with details about the
|
||||
* error.
|
||||
*/
|
||||
RATBAG_ERROR_IMPLEMENTATION = -1004,
|
||||
};
|
||||
|
||||
/**
|
||||
* @ingroup base
|
||||
*
|
||||
@@ -485,99 +440,6 @@ ratbag_device_get_name(const struct ratbag_device* device);
|
||||
const char *
|
||||
ratbag_device_get_svg_name(const struct ratbag_device* device);
|
||||
|
||||
/**
|
||||
* @ingroup device
|
||||
*/
|
||||
enum ratbag_device_capability {
|
||||
RATBAG_DEVICE_CAP_NONE = 0,
|
||||
/**
|
||||
* The device has the capability to query the current hardware
|
||||
* configuration. If this capability is missing, libratbag cannot
|
||||
* query the device for its current configuration and the
|
||||
* configured resolutions and button mappings are unknown.
|
||||
* libratbag will still provide information about the structure of
|
||||
* the device such as the number of buttons and resolutions.
|
||||
* Clients that encounter a device without this resolution are
|
||||
* encouraged to upload a configuration stored on-disk to the
|
||||
* device to reset the device to a known state.
|
||||
*
|
||||
* Any changes uploaded to the device will be cached in libratbag,
|
||||
* once a client has sent a full configuration to the device
|
||||
* libratbag can be used to query the device as normal.
|
||||
*/
|
||||
RATBAG_DEVICE_CAP_QUERY_CONFIGURATION,
|
||||
|
||||
/**
|
||||
* The device provides read and/or write access to one or more
|
||||
* resolutions.
|
||||
*/
|
||||
RATBAG_DEVICE_CAP_RESOLUTION = 100,
|
||||
|
||||
/**
|
||||
* The device can change resolution, either software-controlled or
|
||||
* by a hardware button.
|
||||
*
|
||||
* FIXME: what about devices that only have hw buttons? can we
|
||||
* query that, even if we can't switch it ourselves? Maybe better to
|
||||
* have a separate cap for that then.
|
||||
*/
|
||||
RATBAG_DEVICE_CAP_SWITCHABLE_RESOLUTION,
|
||||
|
||||
/**
|
||||
* The device provides read and/or write access to one or more
|
||||
* profiles.
|
||||
*/
|
||||
RATBAG_DEVICE_CAP_PROFILE = 200,
|
||||
|
||||
/**
|
||||
* The device can switch between hardware profiles.
|
||||
* A device with this capability can store multiple profiles in the
|
||||
* hardware and provides the ability to switch between the profiles,
|
||||
* possibly with a button.
|
||||
* Devices without this capability will only have a single profile.
|
||||
*/
|
||||
RATBAG_DEVICE_CAP_SWITCHABLE_PROFILE,
|
||||
|
||||
/**
|
||||
* The device has the capability to disable and enable profiles. While
|
||||
* profiles are not immediately deleted after being disabled, it is not
|
||||
* guaranteed that the device will remember any disabled profiles the
|
||||
* next time ratbag runs. Furthermore, the order of profiles may get
|
||||
* changed the next time ratbag runs if profiles are disabled.
|
||||
*/
|
||||
RATBAG_DEVICE_CAP_DISABLE_PROFILE,
|
||||
|
||||
/**
|
||||
* The device can have one profile assigned as a default profile.
|
||||
* A default profile is the profile that is selected when the device
|
||||
* is plugged in. Devices without this capability may select the
|
||||
* last-used profile or a specific profile (usually the first).
|
||||
*/
|
||||
RATBAG_DEVICE_CAP_DEFAULT_PROFILE,
|
||||
|
||||
/**
|
||||
* The device provides read and/or write access to one or more
|
||||
* buttons.
|
||||
*/
|
||||
RATBAG_DEVICE_CAP_BUTTON = 300,
|
||||
|
||||
/**
|
||||
* The device supports assigning button numbers, key events or key +
|
||||
* modifier combinations.
|
||||
*/
|
||||
RATBAG_DEVICE_CAP_BUTTON_KEY,
|
||||
|
||||
/**
|
||||
* The device supports user-defined key or button sequences.
|
||||
*/
|
||||
RATBAG_DEVICE_CAP_BUTTON_MACROS,
|
||||
|
||||
/**
|
||||
* The device supports assigning LED colors and effects
|
||||
*/
|
||||
RATBAG_DEVICE_CAP_LED = 400,
|
||||
};
|
||||
|
||||
/**
|
||||
* @ingroup device
|
||||
*
|
||||
@@ -671,6 +533,42 @@ ratbag_profile_ref(struct ratbag_profile *profile);
|
||||
struct ratbag_profile *
|
||||
ratbag_profile_unref(struct ratbag_profile *profile);
|
||||
|
||||
/**
|
||||
* @ingroup profile
|
||||
*
|
||||
* Check if a profile has a specific capability.
|
||||
*
|
||||
* @return non-zero if the capability is available, zero otherwise.
|
||||
*/
|
||||
int
|
||||
ratbag_profile_has_capability(const struct ratbag_profile *profile,
|
||||
enum ratbag_profile_capability cap);
|
||||
|
||||
/**
|
||||
* @ingroup profile
|
||||
*
|
||||
* Return the ratbag profile name.
|
||||
*
|
||||
* @param profile A previously initialized ratbag profile
|
||||
* @return the profile name
|
||||
*/
|
||||
const char *
|
||||
ratbag_profile_get_name(struct ratbag_profile *profile);
|
||||
|
||||
/**
|
||||
* @ingroup profile
|
||||
*
|
||||
* Set the name of a ratbag profile.
|
||||
*
|
||||
* @param profile A previously initialized ratbag profile
|
||||
* @param name the profile name
|
||||
*
|
||||
* @return 0 on success or an error code otherwise
|
||||
*/
|
||||
int
|
||||
ratbag_profile_set_name(struct ratbag_profile *profile,
|
||||
const char *name);
|
||||
|
||||
/**
|
||||
* @ingroup profile
|
||||
*
|
||||
@@ -866,20 +764,6 @@ ratbag_resolution_set_user_data(struct ratbag_resolution *resolution, void *user
|
||||
void*
|
||||
ratbag_resolution_get_user_data(const struct ratbag_resolution *resolution);
|
||||
|
||||
enum ratbag_resolution_capability {
|
||||
/**
|
||||
* The report rate can be set per resolution mode. If this property
|
||||
* is not available, all resolutions within the same profile have
|
||||
* the same report rate and changing one changes the others.
|
||||
*/
|
||||
RATBAG_RESOLUTION_CAP_INDIVIDUAL_REPORT_RATE = 1,
|
||||
|
||||
/**
|
||||
* The resolution can be set for x and y separately.
|
||||
*/
|
||||
RATBAG_RESOLUTION_CAP_SEPARATE_XY_RESOLUTION,
|
||||
};
|
||||
|
||||
/**
|
||||
* @ingroup resolution
|
||||
*
|
||||
@@ -959,28 +843,26 @@ ratbag_resolution_get_dpi(struct ratbag_resolution *resolution);
|
||||
/**
|
||||
* @ingroup resolution
|
||||
*
|
||||
* Get the maximum allowed resolution in DPI for the resolution mode.
|
||||
* Get the number of resolutions in DPI available for this resolution.
|
||||
* The list of DPI values is sorted in ascending order but may be filtered
|
||||
* by libratbag and does not necessarily reflect all resolutions supported
|
||||
* by the physical device.
|
||||
*
|
||||
* @param resolution A previously initialized ratbag resolution
|
||||
* This function writes at most nres values but returns the number of
|
||||
* DPI values available on this resolution. In other words, if it returns a
|
||||
* number larger than nres, call it again with an array the size of the
|
||||
* return value.
|
||||
*
|
||||
* @return The maximum resolution in dpi
|
||||
* @retval 0 The maximum resolution is unknown to libratbag
|
||||
* @param[out] resolutions Set to the supported DPI values in ascending order
|
||||
* @param[in] nres The number of elements in resolutions
|
||||
*
|
||||
* @return The number of valid items in resolutions. If the returned value
|
||||
* is larger than nres, the list was truncated.
|
||||
*/
|
||||
int
|
||||
ratbag_resolution_get_dpi_maximum(struct ratbag_resolution *resolution);
|
||||
|
||||
/**
|
||||
* @ingroup resolution
|
||||
*
|
||||
* Get the minimum allowed resolution in DPI for the resolution mode.
|
||||
*
|
||||
* @param resolution A previously initialized ratbag resolution
|
||||
*
|
||||
* @return The minimum resolution in dpi
|
||||
* @retval 0 The minimum resolution is unknown to libratbag
|
||||
*/
|
||||
int
|
||||
ratbag_resolution_get_dpi_minimum(struct ratbag_resolution *resolution);
|
||||
size_t
|
||||
ratbag_resolution_get_dpi_list(struct ratbag_resolution *resolution,
|
||||
unsigned int *resolutions,
|
||||
size_t nres);
|
||||
|
||||
/**
|
||||
* @ingroup resolution
|
||||
@@ -1054,6 +936,29 @@ ratbag_resolution_set_report_rate(struct ratbag_resolution *resolution,
|
||||
int
|
||||
ratbag_resolution_get_report_rate(struct ratbag_resolution *resolution);
|
||||
|
||||
/**
|
||||
* @ingroup resolution
|
||||
*
|
||||
* Get the number of report rates in Hz available for this resolution.
|
||||
* The list of report rates is sorted in ascending order but may be filtered
|
||||
* by libratbag and does not necessarily reflect all report rates supported by
|
||||
* the physical device.
|
||||
*
|
||||
* This function writes at most nrates values but returns the number of
|
||||
* report rates available on this resolution. In other words, if it returns a
|
||||
* number larger than nrates, call it again with an array the size of the
|
||||
* return value.
|
||||
*
|
||||
* @param[out] rates Set to the supported report rates in ascending order
|
||||
* @param[in] nrates The number of elements in resolutions
|
||||
*
|
||||
* @return The number of valid items in rates. If the returned value
|
||||
* is larger than nrates, the list was truncated.
|
||||
*/
|
||||
size_t
|
||||
ratbag_resolution_get_report_rate_list(struct ratbag_resolution *resolution,
|
||||
unsigned int *rates,
|
||||
size_t nrates);
|
||||
/**
|
||||
* @ingroup resolution
|
||||
*
|
||||
@@ -1168,47 +1073,6 @@ ratbag_button_set_user_data(struct ratbag_button *button, void *userdata);
|
||||
void*
|
||||
ratbag_button_get_user_data(const struct ratbag_button *button);
|
||||
|
||||
/**
|
||||
* @ingroup button
|
||||
*
|
||||
* Button types describing the physical button.
|
||||
*/
|
||||
enum ratbag_button_type {
|
||||
RATBAG_BUTTON_TYPE_UNKNOWN = 0,
|
||||
|
||||
/* mouse buttons */
|
||||
RATBAG_BUTTON_TYPE_LEFT,
|
||||
RATBAG_BUTTON_TYPE_MIDDLE,
|
||||
RATBAG_BUTTON_TYPE_RIGHT,
|
||||
RATBAG_BUTTON_TYPE_THUMB,
|
||||
RATBAG_BUTTON_TYPE_THUMB2,
|
||||
RATBAG_BUTTON_TYPE_THUMB3,
|
||||
RATBAG_BUTTON_TYPE_THUMB4,
|
||||
RATBAG_BUTTON_TYPE_WHEEL_LEFT,
|
||||
RATBAG_BUTTON_TYPE_WHEEL_RIGHT,
|
||||
RATBAG_BUTTON_TYPE_WHEEL_CLICK,
|
||||
RATBAG_BUTTON_TYPE_WHEEL_UP,
|
||||
RATBAG_BUTTON_TYPE_WHEEL_DOWN,
|
||||
/**
|
||||
* A button to toggle the wheel from free-spinning to click-based.
|
||||
*/
|
||||
RATBAG_BUTTON_TYPE_WHEEL_RATCHET_MODE_SHIFT,
|
||||
RATBAG_BUTTON_TYPE_EXTRA,
|
||||
RATBAG_BUTTON_TYPE_SIDE,
|
||||
RATBAG_BUTTON_TYPE_PINKIE,
|
||||
RATBAG_BUTTON_TYPE_PINKIE2,
|
||||
|
||||
/* DPI switch */
|
||||
RATBAG_BUTTON_TYPE_RESOLUTION_CYCLE_UP,
|
||||
RATBAG_BUTTON_TYPE_RESOLUTION_UP,
|
||||
RATBAG_BUTTON_TYPE_RESOLUTION_DOWN,
|
||||
|
||||
/* Profile */
|
||||
RATBAG_BUTTON_TYPE_PROFILE_CYCLE_UP,
|
||||
RATBAG_BUTTON_TYPE_PROFILE_UP,
|
||||
RATBAG_BUTTON_TYPE_PROFILE_DOWN,
|
||||
};
|
||||
|
||||
/**
|
||||
* @ingroup button
|
||||
*
|
||||
@@ -1228,39 +1092,6 @@ enum ratbag_button_type {
|
||||
enum ratbag_button_type
|
||||
ratbag_button_get_type(struct ratbag_button *button);
|
||||
|
||||
/**
|
||||
* @ingroup button
|
||||
*
|
||||
* The type assigned to a button.
|
||||
*/
|
||||
enum ratbag_button_action_type {
|
||||
/**
|
||||
* Button is disabled
|
||||
*/
|
||||
RATBAG_BUTTON_ACTION_TYPE_NONE = 0,
|
||||
/**
|
||||
* Button sends numeric button events
|
||||
*/
|
||||
RATBAG_BUTTON_ACTION_TYPE_BUTTON,
|
||||
/**
|
||||
* Button triggers a mouse-specific special function. This includes
|
||||
* resolution changes and profile changes.
|
||||
*/
|
||||
RATBAG_BUTTON_ACTION_TYPE_SPECIAL,
|
||||
/**
|
||||
* Button sends a key or key + modifier combination
|
||||
*/
|
||||
RATBAG_BUTTON_ACTION_TYPE_KEY,
|
||||
/**
|
||||
* Button sends a user-defined key or button sequence
|
||||
*/
|
||||
RATBAG_BUTTON_ACTION_TYPE_MACRO,
|
||||
/**
|
||||
* Button action is unknown
|
||||
*/
|
||||
RATBAG_BUTTON_ACTION_TYPE_UNKNOWN = 1000,
|
||||
};
|
||||
|
||||
/**
|
||||
* @ingroup button
|
||||
*
|
||||
@@ -1290,47 +1121,6 @@ int
|
||||
ratbag_button_has_action_type(struct ratbag_button *button,
|
||||
enum ratbag_button_action_type action_type);
|
||||
|
||||
/**
|
||||
* @ingroup button
|
||||
*/
|
||||
enum ratbag_button_action_special {
|
||||
/**
|
||||
* This button is not set up for a special action
|
||||
*/
|
||||
RATBAG_BUTTON_ACTION_SPECIAL_INVALID = -1,
|
||||
RATBAG_BUTTON_ACTION_SPECIAL_UNKNOWN = (1 << 30),
|
||||
|
||||
RATBAG_BUTTON_ACTION_SPECIAL_DOUBLECLICK,
|
||||
|
||||
/* Wheel mappings */
|
||||
RATBAG_BUTTON_ACTION_SPECIAL_WHEEL_LEFT,
|
||||
RATBAG_BUTTON_ACTION_SPECIAL_WHEEL_RIGHT,
|
||||
RATBAG_BUTTON_ACTION_SPECIAL_WHEEL_UP,
|
||||
RATBAG_BUTTON_ACTION_SPECIAL_WHEEL_DOWN,
|
||||
RATBAG_BUTTON_ACTION_SPECIAL_RATCHET_MODE_SWITCH,
|
||||
|
||||
/* DPI switch */
|
||||
RATBAG_BUTTON_ACTION_SPECIAL_RESOLUTION_CYCLE_UP,
|
||||
RATBAG_BUTTON_ACTION_SPECIAL_RESOLUTION_CYCLE_DOWN,
|
||||
RATBAG_BUTTON_ACTION_SPECIAL_RESOLUTION_UP,
|
||||
RATBAG_BUTTON_ACTION_SPECIAL_RESOLUTION_DOWN,
|
||||
RATBAG_BUTTON_ACTION_SPECIAL_RESOLUTION_ALTERNATE,
|
||||
RATBAG_BUTTON_ACTION_SPECIAL_RESOLUTION_DEFAULT,
|
||||
|
||||
/* Profile */
|
||||
RATBAG_BUTTON_ACTION_SPECIAL_PROFILE_CYCLE_UP,
|
||||
RATBAG_BUTTON_ACTION_SPECIAL_PROFILE_CYCLE_DOWN,
|
||||
RATBAG_BUTTON_ACTION_SPECIAL_PROFILE_UP,
|
||||
RATBAG_BUTTON_ACTION_SPECIAL_PROFILE_DOWN,
|
||||
|
||||
/* second mode for buttons */
|
||||
RATBAG_BUTTON_ACTION_SPECIAL_SECOND_MODE,
|
||||
|
||||
/* battery level */
|
||||
RATBAG_BUTTON_ACTION_SPECIAL_BATTERY_LEVEL,
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* @ingroup button
|
||||
*
|
||||
@@ -1385,34 +1175,6 @@ ratbag_button_set_button(struct ratbag_button *button,
|
||||
enum ratbag_button_action_special
|
||||
ratbag_button_get_special(struct ratbag_button *button);
|
||||
|
||||
/**
|
||||
* @ingroup led
|
||||
*
|
||||
* RATBAG_LED_OFF - led is now off,
|
||||
* RATBAG_LED_ON - led is on with static color,
|
||||
* RATBAG_LED_CYCLE - led is cycling between all colors.
|
||||
* RATBAG_LED_BREATHING - led is pulsating with static color
|
||||
*
|
||||
* Each LED mode has different properties, e.g. the brightness and rate are only
|
||||
* available in modes @ref RATBAG_LED_CYCLE and @ref RATBAG_LED_BREATHING modes
|
||||
*/
|
||||
enum ratbag_led_mode {
|
||||
RATBAG_LED_OFF = 0,
|
||||
RATBAG_LED_ON,
|
||||
RATBAG_LED_CYCLE,
|
||||
RATBAG_LED_BREATHING,
|
||||
};
|
||||
/**
|
||||
* @ingroup led
|
||||
*
|
||||
* LED types, usually based on their physical location
|
||||
*/
|
||||
enum ratbag_led_type {
|
||||
RATBAG_LED_TYPE_UNKNOWN = -1,
|
||||
RATBAG_LED_TYPE_LOGO = 0,
|
||||
RATBAG_LED_TYPE_SIDE
|
||||
};
|
||||
|
||||
/**
|
||||
* @ingroup led
|
||||
*
|
||||
@@ -1443,13 +1205,30 @@ ratbag_profile_get_led(struct ratbag_profile *profile, unsigned int index);
|
||||
*/
|
||||
enum ratbag_led_type
|
||||
ratbag_led_get_type(struct ratbag_led *led);
|
||||
|
||||
/**
|
||||
* @ingroup led
|
||||
*
|
||||
* This function returns true if the given mode is supported by the LED, or
|
||||
* false otherwise.
|
||||
*
|
||||
* @param led A previously initialized ratbag LED
|
||||
* @param mode The LED mode @ref ratbag_led_mode to check for
|
||||
* @return True if supported, false otherwise
|
||||
*
|
||||
* @see ratbag_led_set_mode
|
||||
*/
|
||||
int
|
||||
ratbag_led_has_mode(struct ratbag_led *led,
|
||||
enum ratbag_led_mode mode);
|
||||
|
||||
/**
|
||||
* @ingroup led
|
||||
*
|
||||
* This function returns the mode for ratbag_led.
|
||||
*
|
||||
* @param led A previously initialized ratbag LED
|
||||
* @return The LED mod @ref ratbag_led_mode
|
||||
* @return The LED mode @ref ratbag_led_mode
|
||||
*
|
||||
* @see ratbag_led_set_mode
|
||||
*/
|
||||
@@ -1460,6 +1239,11 @@ ratbag_led_get_mode(struct ratbag_led *led);
|
||||
*
|
||||
* This function returns the led color.
|
||||
*
|
||||
* If any color scaling applies because of the device's color depth
|
||||
* this is not reflected in the returned value. In other words,
|
||||
* the returned value always matches the most recent value provided
|
||||
* to ratbag_led_set_color().
|
||||
*
|
||||
* @param led A previously initialized ratbag LED
|
||||
* @return The LED color in @ref ratbag_led_mode
|
||||
*
|
||||
@@ -1467,18 +1251,32 @@ ratbag_led_get_mode(struct ratbag_led *led);
|
||||
*/
|
||||
struct ratbag_color
|
||||
ratbag_led_get_color(struct ratbag_led *led);
|
||||
|
||||
/**
|
||||
* @ingroup led
|
||||
*
|
||||
* This function returns the LED effect rate.
|
||||
* This function returns the color depth of this LED.
|
||||
*
|
||||
* @param led A previously initialized ratbag LED
|
||||
* @return The LED rate in Hz, can be 100 - 20000
|
||||
* @return The bit depth of this LED
|
||||
*
|
||||
* @see ratbag_led_set_effect_rate
|
||||
* @see ratbag_led_set_color
|
||||
*/
|
||||
enum ratbag_led_colordepth
|
||||
ratbag_led_get_colordepth(struct ratbag_led *led);
|
||||
|
||||
/**
|
||||
* @ingroup led
|
||||
*
|
||||
* This function returns the LED effect duration.
|
||||
*
|
||||
* @param led A previously initialized ratbag LED
|
||||
* @return The LED duration in ms, can be 0 - 10000
|
||||
*
|
||||
* @see ratbag_led_set_effect_duration
|
||||
*/
|
||||
int
|
||||
ratbag_led_get_effect_rate(struct ratbag_led *led);
|
||||
ratbag_led_get_effect_duration(struct ratbag_led *led);
|
||||
/**
|
||||
* @ingroup led
|
||||
*
|
||||
@@ -1512,6 +1310,12 @@ ratbag_led_set_mode(struct ratbag_led *led, enum ratbag_led_mode mode);
|
||||
* If the LED's mode is @ref RATBAG_LED_ON or @ref RATBAG_LED_BREATHING
|
||||
* then this function sets the LED color, otherwise it has no effect.
|
||||
*
|
||||
* The color provided has to be within the allowed color range (see @ref
|
||||
* ratbag_color). libratbag silently scales and/or clamps this range into
|
||||
* the device's color depth. It is the caller's responsibility to set the
|
||||
* colors in a non-ambiguous way for the device's bit depth. See @ref
|
||||
* ratbag_led_colordepth for more details.
|
||||
*
|
||||
* @param led A previously initialized ratbag LED
|
||||
* @param color A LED color.
|
||||
* @return 0 on success or an error code otherwise.
|
||||
@@ -1525,16 +1329,16 @@ ratbag_led_set_color(struct ratbag_led *led, struct ratbag_color color);
|
||||
* @ingroup led
|
||||
*
|
||||
* If the LED's mode is @ref RATBAG_LED_CYCLE or @ref RATBAG_LED_BREATHING
|
||||
* then this function sets the LED rate in Hz
|
||||
* then this function sets the LED duration in ms
|
||||
*
|
||||
* @param led A previously initialized ratbag LED
|
||||
* @param rate Effect rate in hz, 100 - 20000
|
||||
* @param rate Effect duration in ms, 0 - 10000
|
||||
* @return 0 on success or an error code otherwise.
|
||||
*
|
||||
* @see ratbag_led_get_effect_rate
|
||||
* @see ratbag_led_get_effect_duration
|
||||
*/
|
||||
enum ratbag_error_code
|
||||
ratbag_led_set_effect_rate(struct ratbag_led *led, unsigned int rate);
|
||||
ratbag_led_set_effect_duration(struct ratbag_led *led, unsigned int rate);
|
||||
|
||||
/**
|
||||
* @ingroup led
|
||||
@@ -1624,19 +1428,6 @@ ratbag_button_set_key(struct ratbag_button *button,
|
||||
enum ratbag_error_code
|
||||
ratbag_button_disable(struct ratbag_button *button);
|
||||
|
||||
/**
|
||||
* @ingroup button
|
||||
*
|
||||
* Macro event types describing the event.
|
||||
*/
|
||||
enum ratbag_macro_event_type {
|
||||
RATBAG_MACRO_EVENT_INVALID = -1,
|
||||
RATBAG_MACRO_EVENT_NONE = 0,
|
||||
RATBAG_MACRO_EVENT_KEY_PRESSED,
|
||||
RATBAG_MACRO_EVENT_KEY_RELEASED,
|
||||
RATBAG_MACRO_EVENT_WAIT,
|
||||
};
|
||||
|
||||
/**
|
||||
* @ingroup button
|
||||
*
|
||||
@@ -1859,6 +1650,3 @@ ratbag_led_ref(struct ratbag_led *led);
|
||||
struct ratbag_led *
|
||||
ratbag_led_unref(struct ratbag_led *led);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
58
src/libratbag.i
Normal file
@@ -0,0 +1,58 @@
|
||||
/* wrapping libratbag functions from libratbag.h using SWIG. */
|
||||
|
||||
%module libratbag
|
||||
%{
|
||||
/* the resulting C file should be built as a python extension */
|
||||
#define SWIG_FILE_WITH_INIT
|
||||
/* Includes the header in the wrapper code */
|
||||
#include <libratbag.h>
|
||||
#include <shared.h>
|
||||
%}
|
||||
#define __attribute__(x)
|
||||
|
||||
/* custom typemap for handling ratbag_resolution_get_dpi_list */
|
||||
%typemap(in) (unsigned int *resolutions, size_t nres) {
|
||||
unsigned int i;
|
||||
if (!PyList_Check($input)) {
|
||||
PyErr_SetString(PyExc_ValueError, "Expecting a list");
|
||||
return NULL;
|
||||
}
|
||||
$2 = PyList_Size($input);
|
||||
$1 = (unsigned int *) malloc(($2 + 1) * sizeof(unsigned int));
|
||||
for (i = 0; i < $2; i++) {
|
||||
PyObject *s = PyList_GetItem($input, i);
|
||||
if (!PyInt_Check(s)) {
|
||||
free($1);
|
||||
PyErr_SetString(PyExc_ValueError, "List items must be integers");
|
||||
return NULL;
|
||||
}
|
||||
$1[i] = PyInt_AsLong(s);
|
||||
}
|
||||
$1[i] = 0;
|
||||
}
|
||||
|
||||
%typemap(argout) (unsigned int *resolutions, size_t nres) {
|
||||
unsigned int i;
|
||||
for (i = 0; i < $2; i++) {
|
||||
PyList_SetItem($input, i, PyInt_FromLong($1[i]));
|
||||
}
|
||||
}
|
||||
|
||||
%typemap(freearg) (unsigned int *resolutions, size_t nres) {
|
||||
if ($1)
|
||||
free($1);
|
||||
}
|
||||
/* END OF custom typemap for handling ratbag_resolution_get_dpi_list */
|
||||
|
||||
|
||||
/* custom typemap for handling ratbag_resolution_get_report_rate_list */
|
||||
/* We re-use the ratbag_resolution_get_dpi_list typemap */
|
||||
%typemap(in) (unsigned int *rates, size_t nrates) = (unsigned int *resolutions, size_t nres);
|
||||
%typemap(argout) (unsigned int *rates, size_t nrates) = (unsigned int *resolutions, size_t nres);
|
||||
%typemap(freearg) (unsigned int *rates, size_t nrates) = (unsigned int *resolutions, size_t nres);
|
||||
/* END OF custom typemap for handling ratbag_resolution_get_report_rate_list */
|
||||
|
||||
/* Parse the header file to generate wrappers */
|
||||
%include "libratbag.h"
|
||||
%include "libratbag-enums.h"
|
||||
%include "shared.h"
|
||||
@@ -1,95 +0,0 @@
|
||||
/* in alphabetical order! */
|
||||
|
||||
LIBRATBAG_0.5.0 {
|
||||
global:
|
||||
ratbag_create_context;
|
||||
ratbag_button_disable;
|
||||
ratbag_button_get_action_type;
|
||||
ratbag_button_get_type;
|
||||
ratbag_button_get_button;
|
||||
ratbag_button_get_key;
|
||||
ratbag_button_get_macro;
|
||||
ratbag_button_get_special;
|
||||
ratbag_button_get_user_data;
|
||||
ratbag_button_has_action_type;
|
||||
ratbag_button_macro_get_event_key;
|
||||
ratbag_button_macro_get_event_timeout;
|
||||
ratbag_button_macro_get_event_type;
|
||||
ratbag_button_macro_get_name;
|
||||
ratbag_button_macro_get_num_events;
|
||||
ratbag_button_macro_new;
|
||||
ratbag_button_macro_ref;
|
||||
ratbag_button_macro_set_event;
|
||||
ratbag_button_macro_unref;
|
||||
ratbag_button_ref;
|
||||
ratbag_button_set_button;
|
||||
ratbag_button_set_key;
|
||||
ratbag_button_set_macro;
|
||||
ratbag_button_set_special;
|
||||
ratbag_button_set_user_data;
|
||||
ratbag_button_unref;
|
||||
ratbag_device_commit;
|
||||
ratbag_device_get_name;
|
||||
ratbag_device_get_num_buttons;
|
||||
ratbag_device_get_num_profiles;
|
||||
ratbag_device_get_profile;
|
||||
ratbag_device_get_svg_name;
|
||||
ratbag_device_get_user_data;
|
||||
ratbag_device_has_capability;
|
||||
ratbag_device_new_from_udev_device;
|
||||
ratbag_device_new_test_device;
|
||||
ratbag_device_ref;
|
||||
ratbag_device_set_user_data;
|
||||
ratbag_device_unref;
|
||||
ratbag_get_user_data;
|
||||
ratbag_log_get_priority;
|
||||
ratbag_log_set_handler;
|
||||
ratbag_log_set_priority;
|
||||
ratbag_profile_get_led;
|
||||
ratbag_led_get_mode;
|
||||
ratbag_led_get_type;
|
||||
ratbag_led_get_color;
|
||||
ratbag_led_get_effect_rate;
|
||||
ratbag_led_get_brightness;
|
||||
ratbag_led_ref;
|
||||
ratbag_led_set_mode;
|
||||
ratbag_led_set_color;
|
||||
ratbag_led_set_effect_rate;
|
||||
ratbag_led_set_brightness;
|
||||
ratbag_led_unref;
|
||||
ratbag_device_get_num_leds;
|
||||
ratbag_profile_get_button;
|
||||
ratbag_profile_get_num_resolutions;
|
||||
ratbag_profile_get_resolution;
|
||||
ratbag_profile_get_user_data;
|
||||
ratbag_profile_is_active;
|
||||
ratbag_profile_is_enabled;
|
||||
ratbag_profile_ref;
|
||||
ratbag_profile_set_user_data;
|
||||
ratbag_profile_set_active;
|
||||
ratbag_profile_set_enabled;
|
||||
ratbag_profile_unref;
|
||||
ratbag_resolution_get_dpi;
|
||||
ratbag_resolution_get_dpi_maximum;
|
||||
ratbag_resolution_get_dpi_minimum;
|
||||
ratbag_resolution_get_dpi_x;
|
||||
ratbag_resolution_get_dpi_y;
|
||||
ratbag_resolution_get_report_rate;
|
||||
ratbag_resolution_get_user_data;
|
||||
ratbag_resolution_has_capability;
|
||||
ratbag_resolution_is_active;
|
||||
ratbag_resolution_is_default;
|
||||
ratbag_resolution_ref;
|
||||
ratbag_resolution_set_active;
|
||||
ratbag_resolution_set_default;
|
||||
ratbag_resolution_set_dpi;
|
||||
ratbag_resolution_set_dpi_xy;
|
||||
ratbag_resolution_set_report_rate;
|
||||
ratbag_resolution_set_user_data;
|
||||
ratbag_resolution_unref;
|
||||
ratbag_ref;
|
||||
ratbag_set_user_data;
|
||||
ratbag_unref;
|
||||
local:
|
||||
*;
|
||||
};
|
||||
@@ -1,22 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
### simple check for exported symbols
|
||||
|
||||
TOP_SRCDIR="$1"
|
||||
|
||||
if [ -z "$TOP_SRCDIR" ]; then
|
||||
echo "usage: $0 path/to/top_srcdir"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# make bash exit if any command will exit with non-0 return value
|
||||
set -e
|
||||
|
||||
# make sure the paths are alright
|
||||
diff -a -u \
|
||||
<(cat "$TOP_SRCDIR"/src/libratbag.sym | \
|
||||
grep '^\s\+ratbag_.*' | \
|
||||
sed -e 's/^\s\+\(.*\);/\1/' | sort) \
|
||||
<(cat "$TOP_SRCDIR"/src/*.c | \
|
||||
grep LIBRATBAG_EXPORT -A 1 | grep '^ratbag_.*' | \
|
||||
sed -e 's/(.*//' | sort)
|
||||
@@ -165,6 +165,8 @@ int main(void)
|
||||
bool using_valgrind;
|
||||
const struct rlimit corelimit = { 0, 0 };
|
||||
|
||||
setenv("RATBAG_TEST", "1", 0);
|
||||
|
||||
setrlimit(RLIMIT_CORE, &corelimit);
|
||||
|
||||
/* when running under valgrind we're using nofork mode, so a
|
||||
|
||||
@@ -34,6 +34,7 @@
|
||||
#include <sys/resource.h>
|
||||
|
||||
#include "libratbag.h"
|
||||
#include "libratbag-util.h"
|
||||
#include "libratbag-test.h"
|
||||
|
||||
static void
|
||||
@@ -58,10 +59,16 @@ const struct ratbag_test_device sane_device = {
|
||||
.profiles = {
|
||||
{
|
||||
.resolutions = {
|
||||
{ .xres = 100, .yres = 200, .hz = 1000 },
|
||||
{ .xres = 100, .yres = 200, .hz = 1000,
|
||||
.dpi_min = 100, .dpi_max = 5000,
|
||||
.report_rates = { 500, 1000 } },
|
||||
{ .xres = 200, .yres = 300, .hz = 1000 },
|
||||
{ .xres = 300, .yres = 400, .hz = 1000 },
|
||||
},
|
||||
.leds = {
|
||||
{ .type = RATBAG_LED_TYPE_SIDE, },
|
||||
{ .type = RATBAG_LED_TYPE_LOGO, },
|
||||
},
|
||||
.active = true,
|
||||
.dflt = false,
|
||||
},
|
||||
@@ -84,14 +91,14 @@ const struct ratbag_test_device sane_device = {
|
||||
{
|
||||
.mode = RATBAG_LED_ON,
|
||||
.color = { .red = 255, .green = 0, .blue = 0 },
|
||||
.hz = 1,
|
||||
.brightness = 20
|
||||
.ms = 1000,
|
||||
.brightness = 20,
|
||||
},
|
||||
{
|
||||
.mode = RATBAG_LED_CYCLE,
|
||||
.color = { .red = 255, .green = 255, .blue = 0 },
|
||||
.hz = 3,
|
||||
.brightness = 40
|
||||
.ms = 333,
|
||||
.brightness = 40,
|
||||
}
|
||||
},
|
||||
.active = false,
|
||||
@@ -349,7 +356,9 @@ START_TEST(device_resolutions)
|
||||
.profiles = {
|
||||
{
|
||||
.resolutions = {
|
||||
{ .xres = 100, .yres = 200, .hz = 1000 },
|
||||
{ .xres = 100, .yres = 200, .hz = 1000,
|
||||
.dpi_min = 50, .dpi_max = 5000,
|
||||
.report_rates = { 500, 1000 } },
|
||||
{ .xres = 200, .yres = 300, .hz = 1000, .active = true },
|
||||
{ .xres = 300, .yres = 400, .hz = 1000 },
|
||||
},
|
||||
@@ -384,6 +393,9 @@ START_TEST(device_resolutions)
|
||||
ck_assert_int_eq(nresolutions, 3);
|
||||
|
||||
for (j = 0; j < nresolutions; j++) {
|
||||
unsigned int dpis[200];
|
||||
int ndpis = ARRAY_LENGTH(dpis);
|
||||
|
||||
res = ratbag_profile_get_resolution(p, j);
|
||||
|
||||
xres = ratbag_resolution_get_dpi_x(res);
|
||||
@@ -391,11 +403,18 @@ START_TEST(device_resolutions)
|
||||
rate = ratbag_resolution_get_report_rate(res);
|
||||
is_active = ratbag_resolution_is_active(res);
|
||||
|
||||
ndpis = ratbag_resolution_get_dpi_list(res, dpis, ndpis);
|
||||
ck_assert_int_lt(ndpis, ARRAY_LENGTH(dpis));
|
||||
ck_assert_int_gt(ndpis, 20);
|
||||
|
||||
ck_assert_int_eq(xres, i * 1000 + (j + 1) * 100);
|
||||
ck_assert_int_eq(yres, i * 1000 + (j + 1) * 100 + 100);
|
||||
ck_assert_int_eq(xres, ratbag_resolution_get_dpi(res));
|
||||
ck_assert_int_eq(is_active, (j == 1));
|
||||
|
||||
ck_assert_int_eq(dpis[0], 50);
|
||||
ck_assert_int_eq(dpis[ndpis - 1], 5000);
|
||||
|
||||
ck_assert_int_eq(rate, (i + 1) * 1000);
|
||||
|
||||
ratbag_resolution_unref(res);
|
||||
@@ -774,18 +793,18 @@ assert_led_equals(struct ratbag_led *l, struct ratbag_test_led e_l)
|
||||
{
|
||||
enum ratbag_led_mode mode;
|
||||
struct ratbag_color color;
|
||||
int brightness, hz;
|
||||
int brightness, ms;
|
||||
|
||||
ck_assert(l != NULL);
|
||||
mode = ratbag_led_get_mode(l);
|
||||
color = ratbag_led_get_color(l);
|
||||
hz = ratbag_led_get_effect_rate(l);
|
||||
ms = ratbag_led_get_effect_duration(l);
|
||||
brightness = ratbag_led_get_brightness(l);
|
||||
ck_assert_int_eq(mode, e_l.mode);
|
||||
ck_assert_int_eq(color.red, e_l.color.red);
|
||||
ck_assert_int_eq(color.green, e_l.color.green);
|
||||
ck_assert_int_eq(color.blue, e_l.color.blue);
|
||||
ck_assert_int_eq(hz, e_l.hz);
|
||||
ck_assert_int_eq(ms, e_l.ms);
|
||||
ck_assert_int_eq(brightness, e_l.brightness);
|
||||
}
|
||||
|
||||
@@ -811,10 +830,10 @@ START_TEST(device_leds)
|
||||
p = ratbag_device_get_profile(d, 2);
|
||||
ck_assert(p != NULL);
|
||||
|
||||
led_logo = ratbag_profile_get_led(p, RATBAG_LED_TYPE_LOGO);
|
||||
assert_led_equals(led_logo, td.profiles[2].leds[RATBAG_LED_TYPE_LOGO]);
|
||||
led_side = ratbag_profile_get_led(p, RATBAG_LED_TYPE_SIDE);
|
||||
assert_led_equals(led_side, td.profiles[2].leds[RATBAG_LED_TYPE_SIDE]);
|
||||
led_logo = ratbag_profile_get_led(p, 0);
|
||||
assert_led_equals(led_logo, td.profiles[2].leds[0]);
|
||||
led_side = ratbag_profile_get_led(p, 1);
|
||||
assert_led_equals(led_side, td.profiles[2].leds[1]);
|
||||
|
||||
ratbag_led_unref(led_logo);
|
||||
ratbag_led_unref(led_side);
|
||||
@@ -853,14 +872,14 @@ START_TEST(device_leds_set)
|
||||
p = ratbag_device_get_profile(d, 0);
|
||||
ck_assert(p != NULL);
|
||||
|
||||
l = ratbag_profile_get_led(p, RATBAG_LED_TYPE_LOGO);
|
||||
l = ratbag_profile_get_led(p, 0);
|
||||
|
||||
ratbag_led_set_mode(l, RATBAG_LED_BREATHING);
|
||||
ratbag_led_set_color(l, c);
|
||||
ratbag_led_set_effect_rate(l, 11);
|
||||
ratbag_led_set_effect_duration(l, 90);
|
||||
ratbag_led_set_brightness(l, 22);
|
||||
|
||||
l = ratbag_profile_get_led(p, RATBAG_LED_TYPE_LOGO);
|
||||
l = ratbag_profile_get_led(p, 0);
|
||||
struct ratbag_test_led e_l = {
|
||||
.mode = RATBAG_LED_BREATHING,
|
||||
.color = {
|
||||
@@ -868,7 +887,7 @@ START_TEST(device_leds_set)
|
||||
.green = c.green,
|
||||
.blue = c.blue
|
||||
},
|
||||
.hz = 11,
|
||||
.ms = 90,
|
||||
.brightness = 22
|
||||
};
|
||||
assert_led_equals(l, e_l);
|
||||
@@ -935,6 +954,8 @@ int main(void)
|
||||
SRunner *sr;
|
||||
const struct rlimit corelimit = { 0, 0 };
|
||||
|
||||
setenv("RATBAG_TEST", "1", 0);
|
||||
|
||||
setrlimit(RLIMIT_CORE, &corelimit);
|
||||
|
||||
s = test_context_suite();
|
||||
|
||||
@@ -169,6 +169,8 @@ int main(void)
|
||||
SRunner *sr;
|
||||
const struct rlimit corelimit = { 0, 0 };
|
||||
|
||||
setenv("RATBAG_TEST", "1", 0);
|
||||
|
||||
setrlimit(RLIMIT_CORE, &corelimit);
|
||||
|
||||
s = test_context_suite();
|
||||
|
||||
159
test/test-util.c
Normal file
@@ -0,0 +1,159 @@
|
||||
/*
|
||||
* Copyright © 2017 Red Hat, Inc.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the next
|
||||
* paragraph) shall be included in all copies or substantial portions of the
|
||||
* Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include <check.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <signal.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/resource.h>
|
||||
|
||||
#include "libratbag-util.h"
|
||||
|
||||
START_TEST(dpi_range_parser)
|
||||
{
|
||||
struct testcase {
|
||||
const char *str;
|
||||
bool success;
|
||||
struct dpi_range result;
|
||||
} tests[] = {
|
||||
{ "", false, { 0, 0, 0 }},
|
||||
{ "1", false, { 0, 0, 0 }},
|
||||
{ "a", false, { 0, 0, 0 }},
|
||||
{ "1:1", false, { 0, 0, 0 }},
|
||||
{ "2:1", false, { 0, 0, 0 }},
|
||||
{ "2:1@0", false, { 0, 0, 0 }},
|
||||
{ "10:100@0", false, { 0, 0, 0 }},
|
||||
{ "100:10@50", false, { 0, 0, 0 }},
|
||||
{ "100:10@", false, { 0, 0, 0 }},
|
||||
{ ":10@50", false, { 0, 0, 0 }},
|
||||
|
||||
{ "10:100@50", true, { 10, 100, 50 }},
|
||||
{ "100:12000@20", true, { 100, 12000, 20 }},
|
||||
{ "50:12000@250", true, { 50, 12000, 250 }},
|
||||
};
|
||||
struct testcase *t;
|
||||
|
||||
ARRAY_FOR_EACH(tests, t) {
|
||||
struct dpi_range *range;
|
||||
|
||||
range = dpi_range_from_string(t->str);
|
||||
if (!t->success) {
|
||||
ck_assert(range == NULL);
|
||||
continue;
|
||||
}
|
||||
|
||||
ck_assert(range != NULL);
|
||||
ck_assert_int_eq(t->result.min, range->min);
|
||||
ck_assert_int_eq(t->result.max, range->max);
|
||||
ck_assert_int_eq(t->result.step, range->step);
|
||||
|
||||
free(range);
|
||||
}
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(dpi_list_parser)
|
||||
{
|
||||
struct testcase {
|
||||
const char *str;
|
||||
int nentries;
|
||||
int entries[64];
|
||||
} tests[] = {
|
||||
{ "", -1, {0}},
|
||||
{ "a", -1, {0}},
|
||||
{ "a;b", -1, {0}},
|
||||
{ "1;a;b", -1, {0}},
|
||||
{ "100;200;b", -1, {0}},
|
||||
{ "10.2;200", -1, {0}},
|
||||
{ "0xab;100", -1, {0}},
|
||||
|
||||
{ "100", 1, { 100 }},
|
||||
{ "100;200", 2, { 100, 200 }},
|
||||
{ "100;200;", 2, { 100, 200 }},
|
||||
{ "100;300;;;;", 2, { 100, 300 }},
|
||||
{ "0;300;", 2, { 0, 300 }},
|
||||
{ "0;300;400;", 3, { 0, 300, 400 }},
|
||||
{ "0;300;400;500;100;23;", 6, { 0, 300, 400, 500, 100, 23 }},
|
||||
};
|
||||
struct testcase *t;
|
||||
|
||||
ARRAY_FOR_EACH(tests, t) {
|
||||
struct dpi_list *list;
|
||||
|
||||
list = dpi_list_from_string(t->str);
|
||||
if (t->nentries == -1) {
|
||||
ck_assert(list == NULL);
|
||||
continue;
|
||||
}
|
||||
|
||||
ck_assert(list != NULL);
|
||||
ck_assert_int_eq(t->nentries, list->nentries);
|
||||
ck_assert_int_eq(memcmp(t->entries, list->entries,
|
||||
t->nentries * sizeof(int)), 0);
|
||||
|
||||
dpi_list_free(list);
|
||||
}
|
||||
}
|
||||
END_TEST
|
||||
|
||||
static Suite *
|
||||
test_context_suite(void)
|
||||
{
|
||||
TCase *tc;
|
||||
Suite *s;
|
||||
|
||||
s = suite_create("device");
|
||||
tc = tcase_create("util");
|
||||
tcase_add_test(tc, dpi_range_parser);
|
||||
tcase_add_test(tc, dpi_list_parser);
|
||||
|
||||
suite_add_tcase(s, tc);
|
||||
return s;
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
int nfailed;
|
||||
Suite *s;
|
||||
SRunner *sr;
|
||||
const struct rlimit corelimit = { 0, 0 };
|
||||
|
||||
setenv("RATBAG_TEST", "1", 0);
|
||||
|
||||
setrlimit(RLIMIT_CORE, &corelimit);
|
||||
|
||||
s = test_context_suite();
|
||||
sr = srunner_create(s);
|
||||
|
||||
srunner_run_all(sr, CK_ENV);
|
||||
nfailed = srunner_ntests_failed(sr);
|
||||
srunner_free(sr);
|
||||
|
||||
return (nfailed == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
|
||||
}
|
||||
@@ -7,3 +7,15 @@
|
||||
...
|
||||
fun:main
|
||||
}
|
||||
{
|
||||
Python::PyObject_Malloc
|
||||
Memcheck:Leak
|
||||
fun:malloc
|
||||
obj:/*lib*/libpython3*
|
||||
}
|
||||
{
|
||||
Python::PyObject_Malloc
|
||||
Memcheck:Leak
|
||||
fun:realloc
|
||||
obj:/*lib*/libpython3*
|
||||
}
|
||||
|
||||
@@ -30,32 +30,36 @@
|
||||
#include <libratbag-util.h>
|
||||
|
||||
static inline int
|
||||
dump_page(struct hidpp20_device *dev, uint8_t rom, size_t page, size_t offset)
|
||||
dump_page(struct hidpp20_device *dev, uint16_t sector_size, uint8_t rom, size_t page, size_t offset)
|
||||
{
|
||||
int rc = 0;
|
||||
uint8_t bytes[16];
|
||||
uint16_t sector = (rom << 8) | page;
|
||||
uint8_t *data = zalloc(sector_size);
|
||||
|
||||
rc = hidpp20_onboard_profiles_read_sector(dev, sector, sector_size, data);
|
||||
if (rc != 0)
|
||||
goto out;
|
||||
|
||||
while (offset < 256) {
|
||||
hidpp_log_info(&dev->base, "%s: page 0x%02zx off 0x%02zx: ", rom ? "ROM " : "FLASH", page, offset);
|
||||
rc = hidpp20_onboard_profiles_read_memory(dev, rom, page, offset, bytes);
|
||||
if (rc != 0)
|
||||
break;
|
||||
|
||||
hidpp_log_buffer(&dev->base, HIDPP_LOG_PRIORITY_INFO, " ", bytes, ARRAY_LENGTH(bytes));
|
||||
hidpp_log_buffer(&dev->base, HIDPP_LOG_PRIORITY_INFO, " ", data + offset, 16);
|
||||
offset += 16;
|
||||
}
|
||||
|
||||
out:
|
||||
free(data);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static inline int
|
||||
dump_all_pages(struct hidpp20_device *dev, uint8_t rom)
|
||||
dump_all_pages(struct hidpp20_device *dev, uint16_t sector_size, uint8_t rom)
|
||||
{
|
||||
uint8_t page;
|
||||
int rc = 0;
|
||||
|
||||
for (page = 0; page < 31; page++) {
|
||||
rc = dump_page(dev, rom, page, 0);
|
||||
rc = dump_page(dev, sector_size, rom, page, 0);
|
||||
if (rc != 0)
|
||||
break;
|
||||
}
|
||||
@@ -72,15 +76,15 @@ dump_all_pages(struct hidpp20_device *dev, uint8_t rom)
|
||||
}
|
||||
|
||||
static inline int
|
||||
dump_everything(struct hidpp20_device *dev)
|
||||
dump_everything(struct hidpp20_device *dev, uint16_t sector_size)
|
||||
{
|
||||
int rc;
|
||||
|
||||
rc = dump_all_pages(dev, 0);
|
||||
rc = dump_all_pages(dev, sector_size, 0);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
return dump_all_pages(dev, 1);
|
||||
return dump_all_pages(dev, sector_size, 1);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -97,6 +101,7 @@ main(int argc, char **argv)
|
||||
size_t page = 0, offset = 0;
|
||||
struct hidpp20_device *dev = NULL;
|
||||
struct hidpp_device base;
|
||||
struct hidpp20_onboard_profiles_info info = { 0 };
|
||||
int rc;
|
||||
|
||||
if (argc < 2 || argc > 4) {
|
||||
@@ -114,13 +119,15 @@ main(int argc, char **argv)
|
||||
if (!dev)
|
||||
error(1, 0, "Failed to open %s as a HID++ 2.0 device", path);
|
||||
|
||||
hidpp20_onboard_profiles_get_profiles_desc(dev, &info);
|
||||
|
||||
if (argc == 2)
|
||||
rc = dump_everything(dev);
|
||||
rc = dump_everything(dev, info.sector_size);
|
||||
else {
|
||||
page = atoi(argv[1]);
|
||||
if (argc > 3)
|
||||
offset = atoi(argv[2]);
|
||||
rc = dump_page(dev, 0, page, offset);
|
||||
rc = dump_page(dev, info.sector_size, 0, page, offset);
|
||||
}
|
||||
|
||||
hidpp20_device_destroy(dev);
|
||||
|
||||
110
tools/hidpp20-reset.c
Normal file
@@ -0,0 +1,110 @@
|
||||
/*
|
||||
* Copyright © 2017 Red Hat, Inc.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the next
|
||||
* paragraph) shall be included in all copies or substantial portions of the
|
||||
* Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include <errno.h>
|
||||
#include <error.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#include <hidpp20.h>
|
||||
#include <libratbag-util.h>
|
||||
|
||||
static inline int
|
||||
reset_sector(struct hidpp20_device *dev, uint16_t sector_size, uint16_t sector)
|
||||
{
|
||||
int rc = 0;
|
||||
_cleanup_free_ uint8_t *data = NULL;
|
||||
|
||||
data = zalloc(sector_size);
|
||||
|
||||
/* this returns error 4: hardware error and is expected */
|
||||
rc = hidpp20_onboard_profiles_write_sector(dev, sector, sector_size, data, false);
|
||||
if (rc == 4)
|
||||
rc = 0;
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int
|
||||
reset_all_sectors(struct hidpp20_device *dev, uint16_t sector_size)
|
||||
{
|
||||
uint8_t sector;
|
||||
int rc = 0;
|
||||
|
||||
for (sector = 1; sector < 31; sector++) {
|
||||
rc = reset_sector(dev, sector_size, sector);
|
||||
if (rc != 0)
|
||||
break;
|
||||
}
|
||||
|
||||
if (!rc)
|
||||
rc = reset_sector(dev, sector_size, 0);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void
|
||||
usage(void)
|
||||
{
|
||||
printf("Usage: %s [sector] /dev/hidraw0\n", program_invocation_short_name);
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
_cleanup_close_ int fd = -1;
|
||||
const char *path;
|
||||
size_t sector = 0;
|
||||
struct hidpp20_device *dev = NULL;
|
||||
struct hidpp_device base;
|
||||
struct hidpp20_onboard_profiles_info info = { 0 };
|
||||
int rc;
|
||||
|
||||
if (argc < 2 || argc > 3) {
|
||||
usage();
|
||||
return 1;
|
||||
}
|
||||
|
||||
path = argv[argc - 1];
|
||||
fd = open(path, O_RDWR);
|
||||
if (fd < 0)
|
||||
error(1, errno, "Failed to open path %s", path);
|
||||
|
||||
hidpp_device_init(&base, fd);
|
||||
dev = hidpp20_device_new(&base, 0xff);
|
||||
if (!dev)
|
||||
error(1, 0, "Failed to open %s as a HID++ 2.0 device", path);
|
||||
|
||||
hidpp20_onboard_profiles_get_profiles_desc(dev, &info);
|
||||
|
||||
if (argc == 2)
|
||||
rc = reset_all_sectors(dev, info.sector_size);
|
||||
else {
|
||||
sector = atoi(argv[1]);
|
||||
rc = reset_sector(dev, info.sector_size, sector);
|
||||
}
|
||||
|
||||
hidpp20_device_destroy(dev);
|
||||
|
||||
return rc;
|
||||
}
|
||||
@@ -55,7 +55,7 @@ def main(argv):
|
||||
if ns.output:
|
||||
ns.output_file = open(ns.output, 'w')
|
||||
st = os.stat(ns.output)
|
||||
os.chmod(ns.output, st.st_mode | stat.S_IEXEC)
|
||||
os.chmod(ns.output, st.st_mode | stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH)
|
||||
sys.stdout = ns.output_file
|
||||
print_ratbagctl(ns.ratbagctl, ns.ratbagd, ns.version)
|
||||
try:
|
||||
|
||||