1
0
forked from drath/libratbag

Compare commits

..

106 Commits
v0.2 ... v0.5

Author SHA1 Message Date
Benjamin Tissoires
821e2798b9 configure.ac: libratbag 0.5
Signed-off-by: Benjamin Tissoires <benjamin.tissoires@gmail.com>
2016-09-16 11:45:31 +02:00
Benjamin Tissoires
3a0dc8f8a5 hwdb: add svg file for the new G502
Signed-off-by: Benjamin Tissoires <benjamin.tissoires@gmail.com>
2016-08-31 11:38:00 +02:00
bentiss
f75152f074 Merge pull request #95 from cvuchener/g502rgb
Added G502 support and small fix
2016-08-31 11:37:08 +02:00
Clément Vuchener
f72c96914b hidpp20: fix reading has_dpi_shift
The comparison was always false because of missing bit shift.

Signed-off-by: Clément Vuchener <clement.vuchener@gmail.com>
2016-08-30 16:50:18 +02:00
Clément Vuchener
23036eec08 hwdb: Add new version for the G502
The new version is called "G502 Proteus Spectrum", so the older version comment is changed to "G502 Proteus Core" (its complete name) to avoid confusion.

Signed-off-by: Clément Vuchener <clement.vuchener@gmail.com>
2016-08-30 16:42:41 +02:00
bentiss
045a46aa9d Merge pull request #94 from whot/master
hidpp10: fix fetching of serial number
2016-07-27 11:00:44 +02:00
Peter Hutterer
01876023bb hidpp10: fix fetching of serial number
Was off by one, the message content only includes one byte of extra information
before the serial number. And add a BE 32-bit helper while we're at it.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2016-07-14 10:17:49 +10:00
Peter Hutterer
e2ae29efdc configure.ac: place udev files into $prefix/udev
$libdir is /usr/lib64 on some distros

Fixes #93

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2016-07-01 20:19:29 +10:00
Peter Hutterer
f67389c017 lur: fix the index parsing for disconnect
argv[3] is the /dev/hidraw path

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2016-06-23 16:13:57 +10:00
Peter Hutterer
20a57b76a8 Merge pull request #91 from bentiss/g602-fixes
G602 fixes
2016-05-18 15:53:59 +10:00
Benjamin Tissoires
d54d77c395 hidpp20drv: ignore errors of PAGE_ADJUSTABLE_DPI
The G602 seems to fail here, but it is safe to continue.

Signed-off-by: Benjamin Tissoires <benjamin.tissoires@gmail.com>
2016-05-17 17:19:55 +02:00
Benjamin Tissoires
a8897ca8ca tools: hidpp20-dump: prevent segfault when called on non HID++ device
Signed-off-by: Benjamin Tissoires <benjamin.tissoires@gmail.com>
2016-05-17 17:19:55 +02:00
bentiss
4e62a3bdd9 Merge pull request #90 from ntzrmtthihu777/master
Added hwdb entry for G602 (046d:c537)
2016-05-15 09:15:21 +02:00
Marty Plummer
d8a60eca94 Added hwdb entry for G602 (046d:c537)
Signed-off-by: Marty Plummer <ntzrmtthihu777@gmail.com>
2016-05-14 15:09:17 -05:00
Benjamin Tissoires
9aa2120c7d hidpp20: prevent segfault if hidpp20_adjustable_dpi_get_dpi() fails
Signed-off-by: Benjamin Tissoires <benjamin.tissoires@gmail.com>
2016-05-14 09:43:35 +02:00
Peter Hutterer
f7e3f51b54 Merge pull request #89 from bentiss/g900
G900
2016-05-12 12:39:37 +10:00
Benjamin Tissoires
aef7b3e9bb hidpp20drv: add support for the G900 over wireless
We need the same setting that we have on the hidpp10 side.

Signed-off-by: Benjamin Tissoires <benjamin.tissoires@gmail.com>
2016-05-11 14:01:15 +02:00
Benjamin Tissoires
21d0219809 hidpp20: add new special action in G900
Signed-off-by: Benjamin Tissoires <benjamin.tissoires@gmail.com>
2016-05-11 14:01:15 +02:00
Peter Hutterer
3cf59af3e9 Merge pull request #85 from bentiss/g900
G900
2016-05-11 09:07:34 +10:00
Benjamin Tissoires
28438e638b hidpp20-drv: actually retrieve the current resolution value
The onboard profile do not store the current value but the default.
To retrieve the current value, we need to access the switchable resolution
feature.

Signed-off-by: Benjamin Tissoires <benjamin.tissoires@gmail.com>
2016-05-10 11:35:17 +02:00
Benjamin Tissoires
c1bf3be48e hidpp20: read/write the whole dictionary, not just the first 16 bytes
The G900 advertises 5 profiles, which do not fit in only 16 bytes.
We need to read at least 32 bytes, so be it.

Signed-off-by: Benjamin Tissoires <benjamin.tissoires@gmail.com>
2016-05-10 11:13:34 +02:00
Benjamin Tissoires
27293a22df hidpp20: enable G900 profile type
The profile is retro-compatible with the rest, so we can access it
in the same way.

Signed-off-by: Benjamin Tissoires <benjamin.tissoires@gmail.com>
2016-05-09 20:09:24 +02:00
Benjamin Tissoires
fc07672983 hidpp20: prevent invalid ROM access
The device can report how much rom it has through profile_count_oob.
Make sure we have something in ROM before accessing it.

Signed-off-by: Benjamin Tissoires <benjamin.tissoires@gmail.com>
2016-05-09 20:08:18 +02:00
Benjamin Tissoires
c14a0ca2a1 hidpp20-drv: prevent an empty profile to try to read a null macro
If the macro has not been retrieved, it's more likely that the button
is not bound to anything.

Signed-off-by: Benjamin Tissoires <benjamin.tissoires@gmail.com>
2016-05-09 19:52:56 +02:00
Benjamin Tissoires
64037febdc hidpp20: fix return path for hidpp20_onboard_profiles_read
A negative error means a communication error, while a positive one means
a HID++ one. Make sure we abort early enough.

Signed-off-by: Benjamin Tissoires <benjamin.tissoires@gmail.com>
2016-05-09 19:51:46 +02:00
bentiss
fd10ebbc87 Merge pull request #83 from whot/ignore-keyboard-devices
Ignore devices that don't have ID_INPUT_MOUSE set
2016-05-09 10:37:11 +02:00
Peter Hutterer
91eefb9a3f Ignore devices that don't have ID_INPUT_MOUSE set
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2016-05-05 12:57:11 +10:00
Benjamin Tissoires
1da0180e0f hidraw: do not return success if match failed
rc is set to 0 by ratbag_open_hidraw_node(), and if matched failed, we
close the hidraw node and end the loop.

Signed-off-by: Benjamin Tissoires <benjamin.tissoires@gmail.com>
2016-04-29 12:10:41 +02:00
bentiss
22abddc9d4 Merge pull request #82 from whot/wip/logitech-auto-detect
Wip/logitech auto detect
2016-04-29 12:04:59 +02:00
Peter Hutterer
e912f56c26 driver-hidpp20: don't log an error if we can't init a hidpp20 device
Once we start probing devices for multiple drivers we shouldn't just print
error messages for every failed driver. In the hidpp20 case an error would be
printed for any hidpp10 logitech device.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2016-04-29 10:14:11 +10:00
Peter Hutterer
a715679f1f Add a fallback for Logitech's HID++ devices
If a device is not specifically assigned a driver, try hidpp20 and then
hidpp10 hoping that one of them will work.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2016-04-29 10:02:42 +10:00
Peter Hutterer
55673442f1 Split the driver search + testing into a helper function
Prep work for being able to probe multiple drivers on a device. The function
that tests the actual driver simply takes a const char * with the driver name,
so in the future we can loop through multiple driver names easily.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2016-04-29 10:01:24 +10:00
Peter Hutterer
b6294d4f93 Add a new header for PID/VIDs that we need to care about
Beats having the same #define in multiple places

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2016-04-29 09:56:22 +10:00
Peter Hutterer
40112e6061 driver-hidpp20: re-use the destroy function for cleanup during init
No need for two separate cleanup blocks, they're doing the same thing anyway.
Just make the function more robust to uninitalized fields and we're good to
go.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2016-04-29 09:55:58 +10:00
Peter Hutterer
0785bf138d hidpp20: fail for hidpp10 devices
hidpp10 devices have their own driver, let's not initialize them here and just
fail. If a hidpp10 device is assigned the hidpp20 driver this is a bug.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2016-04-29 09:50:20 +10:00
Peter Hutterer
e18e25d685 hwdb: Add Logitech Wireless Touchpad
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2016-04-21 14:13:46 +10:00
Peter Hutterer
85fdea19c2 Link to the github-pages generated documentation
To update the documentation, do the following:

  	# delete current documentation
	pushd doc/html
	rm -rf $PWD/*
	# clone into current directory, checkout gh-pages
	git clone git@github.com:libratbag/libratbag .
	git checkout -b gh-pages
	# delete master branch so we don't accidentally push that one
	git branch -d master
	# return to main, generate docs
	popd
	make
	# commit updated docs, push
	pushd doc/html
	git commit -asm "Updated documentation"
	git push origin gh-pages
	popd

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2016-03-17 15:21:06 +10:00
bentiss
792b6c28df Merge pull request #79 from whot/master
Fix a couple of error messages
2016-03-16 10:17:06 +01:00
Peter Hutterer
5c68164d48 etekcity/roccat: fix error message when we can't talk to the mouse
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2016-03-16 10:00:09 +10:00
Peter Hutterer
b1d99a744b Standardize the error on device open failures
No reason for the drivers to have their own printf each, just return the
negative errno and let the common code print it.

This now also means that we only return -ENODEV on something that's not really
an error, for anything else we print the strerror.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2016-03-16 10:00:09 +10:00
Peter Hutterer
9f544cbe1c Revert "Fix error message on ENODEV"
We now get an error message for all devices that have duplicate event nodes
because we use -ENODEV for 'device not found', 'device is a duplicates' and
'device doesn't have the hidraw report'.

The original commit was triggered by a misunderstanding of the error message,
will be fixed in a follow-up.

This reverts commit 855a6bd831.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2016-03-16 10:00:09 +10:00
bentiss
ad06d29140 Merge pull request #77 from whot/master
configure.ac: udev basedir should be relative to prefix
2016-03-15 08:34:54 +01:00
Peter Hutterer
c12cb66824 configure.ac: udev basedir should be relative to prefix
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2016-03-15 09:48:52 +10:00
Peter Hutterer
c476cd0654 Merge pull request #76 from r3pek/master
Fix supported resolutions from G700s
2016-03-15 07:38:56 +10:00
Carlos Silva
98315343b0 Fix supported resolutions from G700s
I was under the impression that G700 and G700s had the same sensor.
Comparing the specs on the Logitech website, i found myself wrong.
2016-03-14 20:56:00 +00:00
bentiss
eb6787181d Merge pull request #75 from r3pek/master
Add Logitech G700s
2016-03-14 20:48:26 +01:00
Carlos Silva
f7d9ca63e2 Add Logitech G700s 2016-03-14 19:14:16 +00:00
Benjamin Tissoires
b563467164 configure.ac: libratbag 0.4
Soname bump for liblur and libratbag as their ABI has been broken in
this release.

Signed-off-by: Benjamin Tissoires <benjamin.tissoires@gmail.com>
2016-03-14 19:55:43 +01:00
Benjamin Tissoires
86e9a7abcd lur: bump the version of the library
commit b3237fd0 ("lur: change new_from_hidraw to return an errno") broke
the API, so we need to bump the version too.

Signed-off-by: Benjamin Tissoires <benjamin.tissoires@gmail.com>
2016-03-14 19:54:39 +01:00
Benjamin Tissoires
030eaa7c1c Add G502 svg data
Signed-off-by: Benjamin Tissoires <benjamin.tissoires@gmail.com>
2016-03-14 17:19:52 +01:00
Benjamin Tissoires
ae129fe911 Add G700 svg data
Most of the SVG work was made by Peter. Cheers!

Signed-off-by: Benjamin Tissoires <benjamin.tissoires@gmail.com>
2016-03-14 16:20:56 +01:00
Benjamin Tissoires
6190f0c7bf Make sure we do not put random values in the .macro field of buttons
Otherwise, as soon as we set an action for a button, we get a nice
invalid free on cleanup.

Signed-off-by: Benjamin Tissoires <benjamin.tissoires@gmail.com>
2016-03-14 16:20:56 +01:00
Benjamin Tissoires
717505daef Test: add a set_button test
Which currently fails.

Signed-off-by: Benjamin Tissoires <benjamin.tissoires@gmail.com>
2016-03-14 16:20:56 +01:00
Benjamin Tissoires
8ede0b734f Test: make sure the macros ref/unref are tested
Signed-off-by: Benjamin Tissoires <benjamin.tissoires@gmail.com>
2016-03-14 16:20:53 +01:00
Benjamin Tissoires
090851fce1 Test: add some generic tests for the buttons
Currently only ref/unref

Signed-off-by: Benjamin Tissoires <benjamin.tissoires@gmail.com>
2016-03-14 16:20:50 +01:00
bentiss
164232bbbc Merge pull request #74 from whot/wip/macro-rewrite
Rewrite the macro API, which contains PR #72 (Some more cleanup) and PR #73 (Use error enums)
2016-03-14 11:07:28 +01:00
Peter Hutterer
4054616190 Revamp the button macro code
The previous API was inconsistent and different to the rest of libratbag's
API. Replace with one where a macro is a separate struct, can be initialized
and then written to the device with a set_macro() call. The device copies the
contents, the macro is otherwise unmodified and can be re-used by the client
if need be.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2016-03-14 14:22:22 +10:00
Peter Hutterer
578142964d Change ratbag_find_driver to ratbag_assign_driver()
We don't do anything with the return value anyway and we do assign the driver
in this function. Rename it and return a boolean only.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2016-03-14 14:20:50 +10:00
Peter Hutterer
37bd43511b Switch to using an emum for error codes
Whenever we do something that may fail, return an enum of possible errors.

This also changes the API for ratbag_device_new_from_udev_device() to return
an error code now too instead of just NULL on failure.

Error numbers start at -1000 to avoid overlap with errnos, error_code() should
be used internally to avoid returning an errno.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2016-03-14 14:20:47 +10:00
Peter Hutterer
b53981c439 Add a few client error messages
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2016-03-14 11:54:46 +10:00
Peter Hutterer
bf8442a250 Use __cleanup__ to free the device name
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2016-03-14 11:54:46 +10:00
Peter Hutterer
198523fe8f Simplify validity checks with assert
Let the caller check that what they're passing in is correct, we don't have to
respond with sensible error codes here.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2016-03-14 11:54:46 +10:00
bentiss
7f7507a0dd Merge pull request #70 from whot/master
miscellaneous cleanups
2016-03-12 09:58:54 +01:00
bentiss
a08c8ebc60 Merge pull request #71 from cvuchener/fix-g500s-button-mapping
data: Fix G500s button labels and arrows

Fixes bug #69
2016-03-11 11:17:52 +01:00
Clément Vuchener
aa76cb5005 data: Fix G500s button labels and arrows
Changed button labels with their proper numbers and rotated arrows for wheel tilt buttons.
2016-03-11 11:07:01 +01:00
Peter Hutterer
be008cd86c Switch ratbag_get_num_resolutions() to return an unsigned
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2016-03-11 16:22:19 +10:00
Peter Hutterer
6f9aa5aa24 Coding style fixes
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2016-03-11 16:22:19 +10:00
Peter Hutterer
bfe6d446ad Comment typo fixes
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2016-03-11 16:22:15 +10:00
Peter Hutterer
855a6bd831 Fix error message on ENODEV
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2016-03-11 16:16:42 +10:00
Peter Hutterer
f5ff267c54 Improve a few error messages
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2016-03-11 16:16:39 +10:00
Peter Hutterer
014c4105f4 Remove superfluous check for a NULL udev device
If the udev device is NULL, we should fail a lot earlier

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2016-03-11 16:16:37 +10:00
Peter Hutterer
52fea6f3ce Remove superfluous check for strdup() ENOMEM
If that happens, strdup_safe() will abort.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2016-03-11 16:16:35 +10:00
bentiss
43ab3c961e Merge pull request #68 from whot/wip/query-capability
Add a QUERY_CONFIGURATION capability
2016-03-10 14:31:39 +01:00
Peter Hutterer
f7523f000e Add a QUERY_CONFIGURATION capability
Designates a device that can be queried for the current configuration. Some
devices lack this ability so we rely on the caller to upload a known
configuration to the device before we can really proceed.

Set by default, devices without that capability should be the exception, not
the norm.

This patch just adds the capability, actual handling for this needs to be
added when we add the first device without this capability.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2016-03-10 16:53:55 +10:00
bentiss
765ee6c08c Merge pull request #67 from phomes/g9-read-dpi
hidpp10: Fix getting current resolution on G9
2016-03-04 09:02:55 +01:00
Thomas Hindoe Paaboel Andersen
577a7c52fc hidpp10: Fix getting current resolution on G9
On the G9 the response to a 0x63 is a short report. The G9 does
not have individual resolutions for X and Y and thus only needs
to report a single value.

The set version of 0x63 should probably also be updated. However,
while my testing of such a change worked better than with long
reports there are still strange side effects of setting resolution,
like turning off all the LED's. LGS also seems to do a full profile
read/write instead of using 0x63 when changing the resolution.
2016-03-04 00:19:10 +01:00
Benjamin Tissoires
85acab4642 hidpp20: fix correct number of resolutions in the profile
There are only 5 resolutions per profile.

Signed-off-by: Benjamin Tissoires <benjamin.tissoires@gmail.com>
2016-03-02 10:54:13 +01:00
Benjamin Tissoires
0b5ccfeaed hidpp20: re-enable G303
The G303 shares the same profile than the G402/G502. The only difference
is an extension at the end of the profile, but they are compatible.

Signed-off-by: Benjamin Tissoires <benjamin.tissoires@gmail.com>
2016-03-02 10:50:19 +01:00
Benjamin Tissoires
f108ffa9ff hidpp20: remove internal project name
Signed-off-by: Benjamin Tissoires <benjamin.tissoires@gmail.com>
2016-03-02 10:49:07 +01:00
Peter Hutterer
f233b6bf77 data: add a README on how do do the data files
And update all devices to match the the requirements

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2016-03-02 09:09:17 +01:00
Peter Hutterer
c95d8e05ca lur: Add a note that we're not doing OOM
Mostly inherited from our zalloc() implementation. But really,
if you have no memory left, should you be trying to talk to receivers?

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2016-03-02 09:08:58 +01:00
Peter Hutterer
b3237fd001 lur: change new_from_hidraw to return an errno
Makes debugging slightly more useful than just returning NULL.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2016-03-02 09:08:13 +01:00
Benjamin Tissoires
7704c102e4 lur: add lur_device_get/set_userdata
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
BT: move the functions in LIBLUR_0.4.0
Signed-off-by: Benjamin Tissoires <benjamin.tissoires@gmail.com>
2016-03-02 09:08:05 +01:00
Peter Hutterer
55cb7447f9 lur: capitalize use of Logitech Unifying Receiver
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2016-03-02 14:40:41 +10:00
bentiss
77eaa70f77 Merge pull request #63 from phomes/G9-set-profile
hidpp10: write profile for G9
2016-03-01 23:45:30 +01:00
Thomas Hindoe Paaboel Andersen
70d864af09 hidpp10: write profile for G9 2016-03-01 23:37:54 +01:00
bentiss
15968c8e39 Merge pull request #62 from phomes/g9-features
hidpp10: Add button mappings for G9
2016-03-01 23:12:00 +01:00
bentiss
0558bd4101 Merge pull request #61 from phomes/cleanup
Follow up for #56
2016-03-01 23:10:56 +01:00
Thomas Hindoe Paaboel Andersen
3962ec7745 hidpp10: Add button mappings for G9
There are 10 buttons defined in the profile but only 9 physical
buttons. LGS also only allows to configure 9 of them. Button 5
is the "dead" button in the list.
2016-03-01 22:11:47 +01:00
Thomas Hindoe Paaboel Andersen
2164a3b549 libratbag: remove unused variable 2016-03-01 21:20:23 +01:00
Thomas Hindoe Paaboel Andersen
f0417a9535 hidpp10: Add definition for buttons on the G9 2016-03-01 21:20:18 +01:00
Thomas Hindoe Paaboel Andersen
9d9c42cc6a hidpp10: rename structs wrt _sym vs. _dual
Follow up for review in #56
2016-03-01 21:20:13 +01:00
Benjamin Tissoires
efd15a33fb configure.ac: libratbag 0.3
Soname bump for liblur and libratbag as they were not properly versioned.

Signed-off-by: Benjamin Tissoires <benjamin.tissoires@gmail.com>
2016-03-01 17:04:39 +01:00
Benjamin Tissoires
b804e117c1 hidpp20drv: fix segfault when a device is not powered on
We were returning 0 and libratbag tried to access the profiles afterward.

Signed-off-by: Benjamin Tissoires <benjamin.tissoires@gmail.com>
2016-03-01 16:59:32 +01:00
Benjamin Tissoires
b54d28ec1a tools: add a man for ratbag-command
Just duplicated the help.

Signed-off-by: Benjamin Tissoires <benjamin.tissoires@gmail.com>
2016-03-01 16:46:31 +01:00
Benjamin Tissoires
388dae76bc libratbag.sym: bump symbols version
0.1.0 never existed, the first release was 0.2 :)

Signed-off-by: Benjamin Tissoires <benjamin.tissoires@gmail.com>
2016-03-01 15:35:33 +01:00
Benjamin Tissoires
19f87790bb Add liblur versioning and pkg-config
Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
2016-03-01 15:34:46 +01:00
Benjamin Tissoires
9aa8938eb8 hidpp20: profiles: make sure the mouse is in the profiles mode, not HID
Signed-off-by: Benjamin Tissoires <benjamin.tissoires@gmail.com>
2016-03-01 15:05:50 +01:00
Benjamin Tissoires
25094daaed hidpp20: profiles: make sure device is compatible with our implementation
Get_Profile_Info gives valuable information to know if we are compatible
with a given device. Use it and bail out if we are not able to support
the device.

Signed-off-by: Benjamin Tissoires <benjamin.tissoires@gmail.com>
2016-03-01 14:57:19 +01:00
Benjamin Tissoires
39069623f2 hidpp20drv: bail out if the features are not working as expected
Signed-off-by: Benjamin Tissoires <benjamin.tissoires@gmail.com>
2016-03-01 14:36:03 +01:00
Benjamin Tissoires
d5c74682f1 Add missing carriage return when the driver does not match
Signed-off-by: Benjamin Tissoires <benjamin.tissoires@gmail.com>
2016-03-01 14:32:42 +01:00
Benjamin Tissoires
6cba2abd8e hidpp20: reorder profile initialization
Spec says the profile count is stored in byte 3 of
CMD_ONBOARD_PROFILES_GET_PROFILES_DESCR, so use this to allocate the proper
number of profiles.

Signed-off-by: Benjamin Tissoires <benjamin.tissoires@gmail.com>
2016-03-01 14:15:15 +01:00
Peter Hutterer
f58b91a9b2 When setting a button action, update our internal state on success
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
2016-02-29 09:58:18 +10:00
Peter Hutterer
de08323609 Fix return for ratbag_button_get_special when we don't have a special action
Do what the doc says.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2016-02-24 10:51:28 +10:00
Peter Hutterer
5fcdfab2a6 Fix a doxygen ref
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2016-02-24 10:51:07 +10:00
Benjamin Tissoires
e07839bcee tools: remove no-install flag for lur-command
The resulting RPM complains about RPATH.

Signed-off-by: Benjamin Tissoires <benjamin.tissoires@gmail.com>
2016-02-18 14:25:18 +01:00
41 changed files with 4233 additions and 1841 deletions

View File

@@ -7,6 +7,13 @@ libratbag is a configuration library for gaming mice. It provides a generic
way to access the various features exposed by these mice and abstracts away
hardware-specific and kernel-specific quirks.
Documentation
-------------
API documentation is available here:
http://libratbag.github.io/libratbag/
Architecture
------------

View File

@@ -1,7 +1,7 @@
AC_PREREQ([2.64])
m4_define([libratbag_major_version], [0])
m4_define([libratbag_minor_version], [2])
m4_define([libratbag_minor_version], [5])
m4_define([libratbag_micro_version], [0])
m4_define([libratbag_version],
[libratbag_major_version.libratbag_minor_version.libratbag_micro_version])
@@ -22,16 +22,18 @@ AC_CONFIG_MACRO_DIR([m4])
AM_INIT_AUTOMAKE([1.11 foreign no-dist-gzip dist-xz])
# Before making a release, the LIBRATBAG_LT_VERSION string should be
# modified.
# The string is of the form C:R:A.
# Before making a release, the LIBRATBAG_LT_VERSION and LIBLUR_LT_VERSION
# strings should be modified.
# The strings are of the form C:R:A.
# a) If binary compatibility has been broken (eg removed or changed interfaces)
# change to C+1:0:0.
# b) If interfaces have been changed or added, but binary compatibility has
# been preserved, change to C+1:0:A+1
# c) If the interface is the same as the previous version, change to C:R+1:A
LIBRATBAG_LT_VERSION=1:0:0
LIBRATBAG_LT_VERSION=3:1:0
LIBLUR_LT_VERSION=3:1:0
AC_SUBST(LIBRATBAG_LT_VERSION)
AC_SUBST(LIBLUR_LT_VERSION)
AM_SILENT_RULES([yes])
AC_USE_SYSTEM_EXTENSIONS
@@ -60,7 +62,7 @@ AC_ARG_WITH(udev-base-dir, AS_HELP_STRING([--with-udev-base-dir=DIR], [where ude
if test -n "$with_udev_base_dir" ; then
UDEV_BASE_DIR="$with_udev_base_dir"
else
UDEV_BASE_DIR="/usr/lib/udev"
UDEV_BASE_DIR="$prefix/lib/udev"
fi
AC_SUBST(UDEV_BASE_DIR)
@@ -145,6 +147,7 @@ AC_CONFIG_FILES([Makefile
src/Makefile
src/libratbag.pc
src/libratbag-version.h
src/liblur.pc
test/Makefile
tools/Makefile])
AC_CONFIG_FILES([test/symbols-leak-test],

26
data/README.md Normal file
View File

@@ -0,0 +1,26 @@
libratbag data files
====================
These SVG files should approximate the device to make it immediately
recognizable. Detail work not required, the graphic is an illustration only.
Requirements
------------
- Canvas size: 750x750 pixels
- Two layers in the final SVG: a lower layer named "Device" with the device
itself, "Leaders" with the buttons and leader-lines
- The device should be approximately centered on the canvas and occupy a
meaningful portion of the canvas without making it look cramped
- Button labels must be in 12pt Sans, starting with Button0
- Wheel buttons may be labeled separately if required (look at the Etekcity
for an example)
Technique
---------
The simplest approach is to find a photo of the device and import it into
inkscape. Put it on the lowest layer, create a new layer "Device" above it
and start tracing the outlines and edges of the device. Fill in the shapes
and your device should resemble the underlying photo. Delete the photo
layer, add leaders and button labels and you're done.

View File

@@ -10,12 +10,12 @@
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="414.6424mm"
height="285.98199mm"
viewBox="0 0 1469.2054 1013.322"
width="750"
height="750"
viewBox="0 0 750.00005 750"
id="svg2"
version="1.1"
inkscape:version="0.91 r13725"
inkscape:version="0.48.4 r9939"
sodipodi:docname="etekcity.svg">
<defs
id="defs4">
@@ -46,19 +46,9 @@
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient4449"
id="linearGradient4562"
id="linearGradient3237"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(1.698701,0,0,1.698701,340.78058,475.26804)"
x1="31.968746"
y1="18.546629"
x2="31.968746"
y2="29.577879" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient4449"
id="linearGradient4215"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(1.698701,0,0,1.698701,111.54723,131.64433)"
gradientTransform="matrix(1.344964,0,0,1.344964,-138.13637,564.60502)"
x1="31.968746"
y1="18.546629"
x2="31.968746"
@@ -66,13 +56,43 @@
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient4336"
id="linearGradient4219"
id="linearGradient3889"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.79176032,0,0,0.79176032,-529.7793,277.79557)"
x1="97.085503"
y1="74.08123"
x2="95.471596"
y2="200.83122"
gradientTransform="translate(0,85.407996)" />
y2="200.83122" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient4449"
id="linearGradient3891"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(1.344964,0,0,1.344964,-441.46063,314.40367)"
x1="31.968746"
y1="18.546629"
x2="31.968746"
y2="29.577879" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient4336"
id="linearGradient3921"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.79176032,0,0,0.79176032,-529.7793,277.79557)"
x1="97.085503"
y1="74.08123"
x2="95.471596"
y2="200.83122" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient4449"
id="linearGradient3923"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(1.344964,0,0,1.344964,-441.46063,314.40367)"
x1="31.968746"
y1="18.546629"
x2="31.968746"
y2="29.577879" />
</defs>
<sodipodi:namedview
id="base"
@@ -81,11 +101,11 @@
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="0.67909341"
inkscape:cx="650.93837"
inkscape:cy="527.80453"
inkscape:zoom="0.96038311"
inkscape:cx="377.27056"
inkscape:cy="338.13614"
inkscape:document-units="px"
inkscape:current-layer="layer6"
inkscape:current-layer="layer4"
showgrid="false"
showguides="true"
inkscape:guide-bbox="true"
@@ -94,9 +114,9 @@
fit-margin-right="50"
fit-margin-bottom="50"
inkscape:window-width="1920"
inkscape:window-height="1016"
inkscape:window-x="0"
inkscape:window-y="27"
inkscape:window-height="1099"
inkscape:window-x="1920"
inkscape:window-y="28"
inkscape:window-maximized="1" />
<metadata
id="metadata7">
@@ -111,443 +131,352 @@
</rdf:RDF>
</metadata>
<g
inkscape:label="Mouse"
inkscape:groupmode="layer"
id="layer1"
transform="translate(522.78594,97.359194)"
id="layer5"
inkscape:label="Device"
transform="translate(647.36582,-57.672087)"
style="display:inline">
<g
id="g4271"
style="fill:#000000;fill-opacity:1;stroke:none"
transform="translate(0,85.407996)">
id="g3893"
transform="translate(121.82639,-21.866275)">
<g
transform="matrix(0.79176032,0,0,0.79176032,-628.41671,192.05523)"
style="fill:#000000;fill-opacity:1;stroke:none;display:inline"
id="g4271">
<path
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none"
d="m 421.23361,409.14757 c 4.4349,4.09496 9.16721,10.86185 32.57742,27.27412 4.08118,24.47294 2.40765,48.35999 1.01015,67.42768 -1.3975,19.06769 -9.52288,85.7367 -30.55711,85.7367 l -41.92133,-6.18719 8.9651,-171.72593 32.38801,-150.26019 27.05315,-2.27284 -2.70689,27.21098 -26.19294,53.47495 z"
id="path4249"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cczcccccccc" />
<use
style="fill:#000000;fill-opacity:1;stroke:none"
x="0"
y="0"
xlink:href="#path4249"
id="use4266"
transform="matrix(-1,0,0,1,580.95786,0)"
width="1469.2054"
height="1013.322" />
</g>
<path
sodipodi:nodetypes="cczcccccccc"
sodipodi:nodetypes="cccccc"
inkscape:connector-curvature="0"
id="path4249"
d="m 421.23361,409.14757 c 4.4349,4.09496 9.16721,10.86185 32.57742,27.27412 4.08118,24.47294 2.40765,48.35999 1.01015,67.42768 -1.3975,19.06769 -9.52288,85.7367 -30.55711,85.7367 l -41.92133,-6.18719 8.9651,-171.72593 32.38801,-150.26019 27.05315,-2.27284 -2.70689,27.21098 -26.19294,53.47495 z"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
id="path4251"
d="m -268.43146,403.53037 c -1.07689,19.01234 -1.64984,38.40264 -3.69907,56.68573 -2.36798,4.75208 -4.96718,7.8857 -7.59809,10.79728 l -13.59657,0 5.59859,-67.18309 z"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;display:inline" />
<path
inkscape:connector-curvature="0"
id="path4253"
d="m -281.12826,473.7127 -0.29993,6.19844 7.09822,5.79854 -2.19945,30.1924 -8.99773,9.59758 -0.29993,28.99271 -2.3994,3.59909 -14.59632,0 0,-84.47873 z"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;display:inline" />
<use
height="100%"
width="100%"
transform="matrix(-1,0,0,1,580.95786,0)"
id="use4266"
xlink:href="#path4249"
height="1013.322"
width="1469.2054"
transform="matrix(-1,0,0,1,-698.21665,-85.740335)"
id="use4275"
xlink:href="#path4251"
y="0"
x="0"
style="fill:#000000;fill-opacity:1;stroke:none" />
style="display:inline" />
<ellipse
sodipodi:ry="36.875"
sodipodi:rx="57.5"
sodipodi:cy="231.07376"
sodipodi:cx="290.47894"
d="m 347.97894,231.07376 c 0,20.3655 -25.74362,36.875 -57.5,36.875 -31.75637,0 -57.5,-16.5095 -57.5,-36.875 0,-20.3655 25.74363,-36.875 57.5,-36.875 31.75638,0 57.5,16.5095 57.5,36.875 z"
ry="36.875"
rx="57.5"
cy="231.07376"
cx="290.47894"
id="path4243"
style="fill:#000000;fill-opacity:1;stroke:#ff0000;stroke-width:1.26300848;stroke-opacity:1;display:inline"
transform="matrix(0.79176032,0,0,0.79176032,-628.41671,124.43258)" />
<use
height="1013.322"
width="1469.2054"
transform="matrix(-1,0,0,1,-698.21665,-85.740335)"
id="use4277"
xlink:href="#path4253"
y="0"
x="0"
style="display:inline" />
<path
sodipodi:nodetypes="cccccscccccccccccccccccscccccc"
inkscape:connector-curvature="0"
id="path3441"
d="m -401.08313,328.79009 0.26444,-40.70143 c -39.18883,7.37119 -44.1411,4.0242 -51.69484,0.84743 -19.57977,14.34842 -45.06471,30.13362 -73.61979,38.63234 -2.47282,19.58198 -2.71663,46.75085 -2.09075,66.56663 19.0204,10.56139 17.6053,33.92046 19.25741,48.34377 1.65211,14.4233 7.20626,94.24576 7.20626,94.24576 l -2.59797,21.72393 23.30745,43.04888 c -0.16213,7.00604 -0.46719,14.87323 -3.03251,37.40758 -7.15647,2.04323 -13.81042,1.56652 -20.02442,-1.10259 0.0912,10.91499 -0.68305,21.82736 0.56908,32.68021 11.24444,13.4205 16.39645,27.09393 56.20571,56.18715 l 6.498,11.63207 c 13.0739,7.46592 23.16933,11.65186 42.40866,14.95221 19.23933,-3.30035 29.33476,-7.48629 42.40866,-14.95221 l 6.498,-11.63207 c 39.80926,-29.09322 44.96127,-42.76665 56.2057,-56.18715 1.25213,-10.85285 0.47635,-21.76522 0.56754,-32.68021 -6.214,2.66911 -12.86641,3.14582 -20.02288,1.10259 -2.56532,-22.53435 -2.87037,-30.40154 -3.0325,-37.40758 l 23.3059,-43.04888 -2.59642,-21.72393 c 0,0 5.55415,-79.82246 7.20625,-94.24576 1.65211,-14.42331 0.23546,-37.78238 19.25586,-48.34377 0.62589,-19.81578 0.38362,-46.98465 -2.08919,-66.56663 -28.55509,-8.49872 -54.04157,-24.28392 -73.62134,-38.63234 -7.55373,3.17677 -12.50447,6.52376 -51.69329,-0.84743 l 0.26444,40.70143 z"
style="fill:#282828;fill-opacity:1;fill-rule:evenodd;stroke:#ff0000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;display:inline" />
<path
inkscape:connector-curvature="0"
id="path4289"
d="m -398.45459,328.52925 0,117.85034"
style="fill:none;stroke:#ff0000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;display:inline" />
<path
sodipodi:nodetypes="cccccccccc"
inkscape:connector-curvature="0"
id="path4247"
d="m -390.51793,495.35976 13.14911,20.077 24.31724,0 -19.22802,-64.1898 -26.14665,-13.56354 -26.14819,13.56354 -19.22802,64.1898 24.31879,0 13.14909,-20.077 z"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#ff0000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;display:inline" />
<rect
ry="3.2500002"
rx="3.2500002"
y="334.18024"
x="-410.93967"
height="59.523411"
width="25.025282"
id="rect4245"
style="fill:#000000;fill-opacity:1;stroke:#ff0000;stroke-width:1;stroke-opacity:1;display:inline" />
<path
inkscape:connector-curvature="0"
id="path4311"
d="m -408.76059,297.49061 c -14.10207,2.39851 -28.95919,4.88556 -42.94836,0.51186 -20.52977,14.9081 -42.9383,27.51676 -67.08004,35.5287 -1.79569,18.70085 -2.21232,37.56904 -1.4629,56.27529 14.36611,10.46486 18.14376,29.44442 18.67596,46.17572 1.42879,19.10333 3.31403,38.21183 4.78767,57.33922 l 94.06329,0.0603 0,-99.67829 -5.64129,0 c -1.42556,0 -2.57322,-1.14766 -2.57322,-2.57323 l 0,-54.37631 c 0,-1.42556 1.14766,-2.57322 2.57322,-2.57322 l 2.21136,0 c -2.89117,-5.43908 -2.75569,-17.98166 -2.75569,-23.06002 0,-6.57742 0.14421,-9.08623 0.15,-13.63002 z"
style="fill:url(#linearGradient3921);fill-opacity:1;fill-rule:evenodd;stroke:none;display:inline" />
<use
height="1013.322"
width="1469.2054"
transform="matrix(-1,0,0,1,-796.64968,2.010815e-6)"
id="use4348"
xlink:href="#path4311"
y="0"
x="0"
style="display:inline" />
<circle
sodipodi:ry="13.13577"
sodipodi:rx="13.13577"
sodipodi:cy="194.21156"
sodipodi:cx="165.89903"
d="m 179.0348,194.21156 c 0,7.25469 -5.88108,13.13577 -13.13577,13.13577 -7.25468,0 -13.13577,-5.88108 -13.13577,-13.13577 0,-7.25468 5.88109,-13.13577 13.13577,-13.13577 7.25469,0 13.13577,5.88109 13.13577,13.13577 z"
r="13.13577"
cy="194.21156"
cx="165.89903"
id="path4352"
style="fill:#898989;fill-opacity:1;stroke:none;display:inline"
transform="matrix(0.79176032,0,0,0.79176032,-529.7793,210.17291)" />
<path
inkscape:connector-curvature="0"
id="path4357"
d="m -420.59834,454.5406 c -5.60675,18.71514 -11.21351,37.43027 -16.82027,56.1454 5.1217,0 10.2434,0 15.3651,0 4.38485,-6.69216 8.76766,-13.38566 13.15375,-20.077 6.98254,0 13.96508,0 20.94762,0 4.38609,6.69134 8.76889,13.38484 13.15374,20.077 5.12118,0 10.24237,0 15.36355,0 -5.60676,-18.71565 -11.21352,-37.43129 -16.82027,-56.14694 -7.39028,-3.83406 -14.78056,-7.66812 -22.17083,-11.50218 -7.39079,3.83457 -14.78159,7.66915 -22.17239,11.50372 z"
style="fill:#898989;fill-opacity:1;fill-rule:evenodd;stroke:none;display:inline" />
<path
inkscape:connector-curvature="0"
id="use4396"
d="m -521.43644,406.56488 c -1.77374,0.0227 -3.15566,0.4222 -3.55518,1.76754 l 0.11752,2.1727 c 1.24058,16.62081 0.75876,33.65011 3.93561,49.99997 1.98359,2.87617 3.63732,8.09685 7.96709,7.20935 1.8046,-0.22471 4.69928,1.07511 6.16243,-0.0881 -0.0876,-1.12531 -0.18047,-2.37689 -0.26598,-3.46086 -1.38363,-12.51596 -2.3414,-25.11574 -3.33096,-37.70913 -0.77697,-6.57243 -2.15369,-13.39954 -5.30263,-19.41823 -1.9185,-0.16721 -4.00601,-0.49523 -5.7279,-0.4732 z"
style="fill:#898989;fill-opacity:1;fill-rule:evenodd;stroke:none;display:inline" />
<path
inkscape:connector-curvature="0"
id="use4398"
d="m -506.09917,476.83515 c -1.97837,0.009 -3.95674,0.0188 -5.93511,0.0279 0.85216,4.85149 -4.04309,7.59388 -6.85213,10.37484 -0.6345,6.02214 1.09923,12.03757 0.98197,18.13626 0.3064,4.54843 -0.35793,10.2138 4.18921,12.95425 3.89072,2.9778 6.76537,7.60716 5.65521,12.64652 0.43285,7.84497 -0.8119,15.99277 0.9062,23.38167 1.01515,0.57035 2.08809,0.77358 3.18869,0.80413 l 2.20518,-18.43626 c 0,0 -2.26899,-32.57611 -4.33922,-59.88925 z"
style="fill:#898989;fill-opacity:1;fill-rule:evenodd;stroke:none;display:inline" />
<path
inkscape:connector-curvature="0"
id="path4404"
d="m -271.77677,406.75044 c -3.09643,0.0485 -6.19285,0.0969 -9.28928,0.14537 -3.15953,5.97283 -4.55856,12.75131 -5.34747,19.29452 l -3.45931,41.48855 c 3.94759,0.0294 9.07538,1.78551 11.24547,-2.81911 5.80456,-6.57393 3.74439,-15.87475 4.98871,-23.78837 0.76732,-11.43639 1.23856,-22.86533 1.86188,-34.32096 z"
style="fill:#898989;fill-opacity:1;fill-rule:evenodd;stroke:none;display:inline" />
<path
inkscape:connector-curvature="0"
id="path4406"
d="m -288.21508,476.67123 c -0.84134,0.006 -1.68687,0.0599 -2.53457,0.11907 -2.07117,27.32261 -4.3423,59.9341 -4.3423,59.9341 l 2.20826,18.47337 c 1.29581,-0.023 2.52331,-0.3133 3.58612,-1.2263 1.08603,-9.86486 -0.19804,-20.31797 0.95414,-30.09153 3.59307,-4.65204 10.46727,-8.17451 9.15627,-15.08365 0.31411,-7.28513 1.50719,-14.93066 1.3129,-22.00692 -3.27092,-2.21915 -7.90201,-5.21182 -6.84904,-9.77793 -1.14795,-0.27038 -2.31544,-0.34912 -3.49178,-0.34021 z"
style="fill:#898989;fill-opacity:1;fill-rule:evenodd;stroke:none;display:inline" />
<path
inkscape:connector-curvature="0"
id="path4441"
d="m -398.42702,334.8881 -2.54284,4.40528 -2.54281,4.40266 2.90008,0 0,9.31229 2.18557,-1.2609 2.18556,1.2609 0,-9.31229 2.90008,0 -2.54283,-4.40266 -2.54281,-4.40528 z"
style="fill:url(#linearGradient3923);fill-opacity:1;stroke:none;display:inline" />
<use
height="1013.322"
width="1469.2054"
transform="matrix(1,0,0,-1,-9.1690072e-7,727.78645)"
id="use4460"
xlink:href="#path4441"
y="0"
x="0"
style="display:inline" />
</g>
<path
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 454.66443,352.50287 c -1.36013,24.01275 -2.08377,48.50286 -4.67196,71.59456 -2.99078,6.00192 -6.27359,9.95971 -9.59645,13.63706 l -17.17259,0 7.07107,-84.85281 z"
id="path4251"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cccccc" />
<path
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 438.62826,441.14375 -0.37881,7.82869 8.9651,7.3236 -2.77792,38.13326 -11.36421,12.12183 -0.37881,36.61803 -3.03046,4.54569 -18.43528,0 0,-106.69736 z"
id="path4253"
inkscape:connector-curvature="0" />
<use
x="0"
y="0"
xlink:href="#path4251"
id="use4275"
transform="matrix(-1,0,0,1,580.95786,4.8707099e-7)"
width="100%"
height="100%" />
<ellipse
style="fill:#000000;fill-opacity:1;stroke:#ff0000;stroke-opacity:1"
id="path4243"
cx="290.47894"
cy="231.07376"
rx="57.5"
ry="36.875" />
<use
x="0"
y="0"
xlink:href="#path4253"
id="use4277"
transform="matrix(-1,0,0,1,580.95786,4.8707099e-7)"
width="100%"
height="100%" />
<path
style="fill:#282828;fill-opacity:1;fill-rule:evenodd;stroke:#ff0000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 287.12424,258.10527 0.33399,-51.40625 c -49.49582,9.30987 -55.75059,5.0826 -65.29102,1.07031 -24.72942,18.12217 -56.91711,38.05902 -92.98242,48.79297 -3.12319,24.73221 -3.43113,59.04672 -2.64063,84.07422 24.02292,13.33912 22.23564,42.84183 24.32227,61.05859 2.08662,18.21675 9.10156,119.0332 9.10156,119.0332 l -3.28125,27.4375 29.4375,54.3711 c -0.20477,8.84869 -0.59006,18.78502 -3.83008,47.24609 -9.03868,2.58062 -17.44268,1.97853 -25.29101,-1.39258 0.11517,13.78573 -0.8627,27.56815 0.71875,41.27539 14.20182,16.9502 20.70885,34.21986 70.98828,70.96485 l 8.20703,14.6914 c 16.51245,9.42952 29.26306,14.71639 53.5625,18.88477 24.29944,-4.16838 37.05005,-9.45525 53.5625,-18.88477 l 8.20703,-14.6914 c 50.27943,-36.74499 56.78646,-54.01465 70.98828,-70.96485 1.58145,-13.70724 0.60163,-27.48966 0.7168,-41.27539 -7.84833,3.37111 -16.25038,3.9732 -25.28906,1.39258 -3.24002,-28.46107 -3.62531,-38.3974 -3.83008,-47.24609 l 29.43555,-54.3711 -3.2793,-27.4375 c 0,0 7.01494,-100.81645 9.10156,-119.0332 2.08663,-18.21676 0.29739,-47.71947 24.32031,-61.05859 0.7905,-25.0275 0.48452,-59.34201 -2.63867,-84.07422 -36.06531,-10.73395 -68.25495,-30.6708 -92.98437,-48.79297 -9.54043,4.01229 -15.79325,8.23956 -65.28907,-1.07031 l 0.33399,51.40625 z"
id="path3441"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cccccscccccccccccccccccscccccc" />
<path
style="fill:none;fill-rule:evenodd;stroke:#ff0000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 290.44411,257.77582 0,148.84598"
id="path4289"
inkscape:connector-curvature="0" />
<path
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#ff0000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 300.46818,468.48417 16.60743,25.35742 30.71289,0 -24.28516,-81.07226 -33.02344,-17.13086 -33.02539,17.13086 -24.28515,81.07226 30.71484,0 16.60742,-25.35742 z"
id="path4247"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cccccccccc" />
<rect
style="fill:#000000;fill-opacity:1;stroke:#ff0000;stroke-opacity:1"
id="rect4245"
width="31.607143"
height="75.178574"
x="274.67535"
y="264.91306"
rx="3.25"
ry="3.25" />
</g>
<g
inkscape:groupmode="layer"
id="layer3"
inkscape:label="Actions"
style="display:inline"
transform="translate(647.36582,205.64997)">
<path
style="fill:url(#linearGradient4219);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 152.84766,110.283 c -17.81104,3.02933 -36.57571,6.1705 -54.244144,0.64648 -25.929275,18.82906 -54.231433,34.7539 -84.722657,44.87305 -2.267978,23.61933 -2.794179,47.45001 -1.847656,71.07617 18.144518,13.21721 22.915716,37.18855 23.587891,58.32032 1.804576,24.12767 4.185653,48.26187 6.046875,72.41992 l 118.802731,0.0762 0,-125.89453 -7.125,0 c -1.8005,0 -3.25,-1.4495 -3.25,-3.25 l 0,-68.67774 c 0,-1.8005 1.4495,-3.25 3.25,-3.25 l 2.79297,0 c -3.65158,-6.86961 -3.48047,-22.71099 -3.48047,-29.125 0,-8.30734 0.18214,-11.47599 0.18946,-17.21484 z"
id="path4311"
inkscape:connector-curvature="0" />
<use
x="0"
y="0"
xlink:href="#path4311"
id="use4348"
transform="matrix(-1,0,0,1,332.05619,4.8707099e-7)"
width="100%"
height="100%" />
<circle
style="fill:#898989;fill-opacity:1;stroke:none;stroke-opacity:1"
id="path4352"
cx="165.89903"
cy="194.21156"
r="13.13577" />
<path
style="fill:#898989;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 137.89648,308.63847 c -7.08138,23.63737 -14.16276,47.27474 -21.24414,70.91211 6.46875,0 12.9375,0 19.40625,0 5.5381,-8.45225 11.07362,-16.9062 16.61329,-25.35742 8.81901,0 17.63802,0 26.45703,0 5.53967,8.45122 11.07518,16.90517 16.61328,25.35742 6.4681,0 12.9362,0 19.40429,0 -7.08138,-23.63802 -14.16276,-47.27604 -21.24414,-70.91406 -9.33398,-4.84245 -18.66797,-9.6849 -28.00195,-14.52735 -9.33463,4.8431 -18.66927,9.6862 -28.00391,14.5293 z"
id="path4357"
inkscape:connector-curvature="0" />
<path
style="fill:#898989;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 10.537109,248.04472 c -2.2402592,0.0287 -3.9856276,0.53324 -4.490234,2.23242 l 0.1484375,2.74414 c 1.566854,20.99222 0.9583123,42.50038 4.9707035,63.15039 2.505291,3.63263 4.593974,10.22639 10.0625,9.10547 2.27923,-0.28382 5.935234,1.35787 7.783203,-0.11133 -0.110687,-1.42127 -0.227935,-3.00203 -0.335938,-4.37109 -1.747534,-15.80777 -2.957208,-31.72139 -4.207031,-47.62695 -0.981314,-8.30104 -2.720121,-16.92373 -6.697266,-24.52539 -2.423075,-0.21119 -5.059619,-0.62548 -7.234375,-0.59766 z"
id="use4396"
inkscape:connector-curvature="0" />
<path
style="fill:#898989;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 29.908203,336.79667 c -2.498699,0.0115 -4.997394,0.0237 -7.496094,0.0352 1.076291,6.12748 -5.106457,9.59114 -8.654297,13.10351 -0.801383,7.60601 1.388334,15.20355 1.240235,22.90625 0.386982,5.74471 -0.452066,12.90012 5.291015,16.36133 4.914007,3.76099 8.544715,9.60791 7.142579,15.97266 0.546689,9.90826 -1.025444,20.199 1.144531,29.53125 1.282147,0.72035 2.637282,0.97704 4.027344,1.01562 l 2.785156,-23.28515 c 0,0 -2.865754,-41.1439 -5.480469,-75.64063 z"
id="use4398"
inkscape:connector-curvature="0" />
<path
style="fill:#898989;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 325.85938,248.27909 c -3.91081,0.0612 -7.82162,0.12234 -11.73243,0.1836 -3.99052,7.54373 -5.75751,16.10502 -6.7539,24.36914 l -4.36914,52.40039 c 4.98584,0.0372 11.46228,2.25512 14.20312,-3.56055 7.33121,-8.30294 4.7292,-20.04995 6.30078,-30.04492 0.96913,-14.44425 1.56431,-28.8791 2.35157,-43.34766 z"
id="path4404"
inkscape:connector-curvature="0" />
<path
style="fill:#898989;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 305.09766,336.58964 c -1.06262,0.008 -2.13053,0.0756 -3.20118,0.15039 -2.61591,34.50868 -5.48437,75.69727 -5.48437,75.69727 l 2.78906,23.33203 c 1.63662,-0.029 3.18696,-0.39571 4.5293,-1.54883 1.37166,-12.4594 -0.25013,-25.66177 1.20508,-38.00586 4.53808,-5.87556 13.22025,-10.32447 11.56445,-19.05078 0.39672,-9.20118 1.90359,-18.85755 1.6582,-27.79492 -4.1312,-2.80281 -9.9803,-6.58258 -8.65039,-12.34961 -1.44987,-0.34149 -2.92443,-0.44095 -4.41015,-0.42969 z"
id="path4406"
inkscape:connector-curvature="0" />
<path
style="fill:url(#linearGradient4215);fill-opacity:1;stroke:none;stroke-opacity:1"
d="m 165.89904,157.51634 -3.21162,5.56391 -3.21159,5.56059 3.66282,0 0,11.76151 2.76039,-1.59253 2.76039,1.59253 0,-11.76151 3.66282,0 -3.21161,-5.56059 -3.2116,-5.56391 z"
id="path4441"
inkscape:connector-curvature="0" />
<use
x="0"
y="0"
xlink:href="#path4441"
id="use4460"
transform="matrix(1,0,0,-1,-4.295044e-6,388.30011)"
width="100%"
height="100%" />
</g>
<g
inkscape:groupmode="layer"
id="layer4"
inkscape:label="Leaders"
transform="translate(647.36582,205.64997)"
transform="translate(647.36582,-57.672087)"
style="display:inline">
<path
inkscape:connector-curvature="0"
id="path4556"
d="m 395.13239,501.14005 -3.21162,5.56391 -3.21159,5.56059 3.66282,0 0,11.76151 2.76039,-1.59253 2.76039,1.59253 0,-11.76151 3.66282,0 -3.21161,-5.56059 -3.2116,-5.56391 z"
style="display:inline;fill:url(#linearGradient4562);fill-opacity:1;stroke:none;stroke-opacity:1" />
<use
style="display:inline"
height="100%"
width="100%"
transform="matrix(1.0000001,0,0,-1.0000001,229.23333,737.5807)"
id="use4558"
xlink:href="#path4441"
y="0"
x="0" />
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;display:inline"
d="M -346.88483,324.11711 -381.86206,206.36042"
id="path4211"
inkscape:connector-curvature="0" />
<path
style="display:inline;fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 164.75586,327.92021 115.08162,-115.08161 95.36037,0"
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;display:inline"
d="M -204.64408,314.78985 -143.68094,209.1986"
id="path4215"
inkscape:connector-curvature="0" />
<path
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;display:inline"
d="m -480.19795,353.09245 84.92794,58.46775"
id="path4227"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
<path
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;display:inline"
d="m -481.9468,416.63443 92.50633,61.96547"
id="path4229"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
<path
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;display:inline"
d="m -277.50576,447.94085 91.11706,-91.11705 75.50256,0"
id="path4546"
inkscape:connector-curvature="0"
sodipodi:nodetypes="ccc" />
<path
style="display:inline;fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="M 77.129499,171.52978 32.952959,22.802079"
id="path4211"
inkscape:connector-curvature="0" />
<path
style="display:inline;fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 165.48259,195.09061 32.39613,0 0,-238.553341"
id="path4213"
inkscape:connector-curvature="0" />
<path
style="display:inline;fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="M 256.78078,159.74937 333.77774,26.386719"
id="path4215"
inkscape:connector-curvature="0" />
<path
style="display:inline;fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 375.15404,291.50573 -61.68003,0"
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;display:inline"
d="m -110.92083,419.10931 -48.8358,0"
id="path4221"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
<path
style="display:inline;fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 375.28322,364.38474 -64.17738,0"
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;display:inline"
d="m -110.81855,476.81202 -50.8131,0"
id="path4225"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
<path
style="display:inline;fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="M -175.41308,446.16063 16.018609,281.97114"
id="path4227"
inkscape:connector-curvature="0" />
<path
style="display:inline;fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="M -177.6219,526.41468 23.381369,366.64285"
id="path4229"
inkscape:connector-curvature="0" />
</g>
<g
inkscape:groupmode="layer"
id="layer5"
inkscape:label="Controls"
transform="translate(647.36582,205.64997)"
style="display:inline">
inkscape:connector-curvature="0"
id="path4556"
d="m -95.10276,585.08945 -2.54284,4.40528 -2.54281,4.40265 2.90008,0 0,9.3123 2.18557,-1.2609 2.18556,1.2609 0,-9.3123 2.90008,0 -2.54283,-4.40265 -2.54281,-4.40528 z"
style="fill:url(#linearGradient3237);fill-opacity:1;stroke:none;display:inline" />
<use
style="display:inline"
height="1013.322"
width="1469.2054"
transform="matrix(1.0000001,0,0,-1.0000001,303.3243,982.46676)"
id="use4558"
xlink:href="#path4441"
y="0"
x="0" />
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:40.00000381px;line-height:125%;font-family:Sans;-inkscape-font-specification:'Sans, Normal';text-align:end;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:end;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="27.097548"
y="16.66757"
style="font-size:31.67041588px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:end;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:end;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Sans;-inkscape-font-specification:'Sans, Normal'"
x="-368.79688"
y="175.47208"
id="text4473"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
x="27.097548"
y="16.66757"
id="tspan4217">Button0</tspan></text>
x="-368.79688"
y="175.47208"
id="tspan4217"
style="font-size:32.00000381px">Button0</tspan></text>
<text
sodipodi:linespacing="125%"
id="text4477"
y="21.853914"
x="336.33337"
style="font-style:normal;font-weight:normal;font-size:40px;line-height:125%;font-family:Sans;letter-spacing:0px;word-spacing:0px;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
y="205.6097"
x="-141.6575"
style="font-size:31.67041206px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Sans"
xml:space="preserve"><tspan
y="21.853914"
x="336.33337"
y="205.6097"
x="-141.6575"
id="tspan4479"
sodipodi:role="line">Button1</tspan></text>
sodipodi:role="line"
style="font-size:32.00000381px">Button1</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:40.00000381px;line-height:125%;font-family:Sans;-inkscape-font-specification:'Sans, Normal';text-align:center;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="196.44098"
y="-51.004951"
style="font-size:32.00000381px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Sans;-inkscape-font-specification:'Sans, Normal'"
x="-252.41873"
y="147.92294"
id="text4481"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
id="tspan4483"
x="196.44098"
y="-51.004951">Button2</tspan></text>
x="-252.41873"
y="147.92294">Button2</tspan></text>
<text
sodipodi:linespacing="125%"
id="text4485"
y="446.01364"
x="-176.11456"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:40.00000381px;line-height:125%;font-family:Sans;-inkscape-font-specification:'Sans, Normal';text-align:end;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:end;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
y="361.82675"
x="-492.72778"
style="font-size:31.67041588px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:end;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:end;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Sans;-inkscape-font-specification:'Sans, Normal'"
xml:space="preserve"><tspan
y="446.01364"
x="-176.11456"
y="361.82675"
x="-492.72778"
id="tspan4487"
sodipodi:role="line">Button3</tspan></text>
sodipodi:role="line"
style="font-size:32.00000381px">Button3</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:40.00000381px;line-height:125%;font-family:Sans;-inkscape-font-specification:'Sans, Normal';text-align:end;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:end;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="-177.07159"
y="526.30017"
style="font-size:31.67041588px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:end;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:end;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Sans;-inkscape-font-specification:'Sans, Normal'"
x="-492.44421"
y="414.9819"
id="text4489"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
id="tspan4491"
x="-177.07159"
y="526.30017">Button4</tspan></text>
x="-492.44421"
y="414.9819"
style="font-size:32.00000381px">Button4</tspan></text>
<text
sodipodi:linespacing="125%"
id="text4493"
y="212.67909"
x="375.72412"
style="font-style:normal;font-weight:normal;font-size:40px;line-height:125%;font-family:Sans;letter-spacing:0px;word-spacing:0px;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
y="356.69751"
x="-110.46946"
style="font-size:31.67041206px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Sans"
xml:space="preserve"><tspan
y="212.67909"
x="375.72412"
y="356.69751"
x="-110.46946"
id="tspan4495"
sodipodi:role="line">Button5</tspan></text>
sodipodi:role="line"
style="font-size:32.00000381px">Button5</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:40px;line-height:125%;font-family:Sans;letter-spacing:0px;word-spacing:0px;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="375.72412"
y="288.81161"
style="font-size:31.67041206px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Sans"
x="-110.46946"
y="416.97623"
id="text4497"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
id="tspan4499"
x="375.72412"
y="288.81161">Button6</tspan></text>
x="-110.46946"
y="416.97623"
style="font-size:32.00000381px">Button6</tspan></text>
<text
sodipodi:linespacing="125%"
id="text4501"
y="364.41678"
x="375.72412"
style="font-style:normal;font-weight:normal;font-size:40px;line-height:125%;font-family:Sans;letter-spacing:0px;word-spacing:0px;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
y="476.83734"
x="-110.46946"
style="font-size:31.67041206px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Sans"
xml:space="preserve"><tspan
y="364.41678"
x="375.72412"
y="476.83734"
x="-110.46946"
id="tspan4503"
sodipodi:role="line">Button7</tspan></text>
sodipodi:role="line"
style="font-size:32.00000381px">Button7</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:40px;line-height:125%;font-family:Sans;letter-spacing:0px;word-spacing:0px;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="417.32373"
y="526.42987"
style="font-size:31.67041206px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Sans"
x="-77.532547"
y="605.11292"
id="text4505"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
id="tspan4507"
x="417.32373"
y="526.42987">Button8</tspan></text>
x="-77.532547"
y="605.11292"
style="font-size:32.00000381px">Button8</tspan></text>
<text
sodipodi:linespacing="125%"
id="text4509"
y="583.15552"
x="417.32373"
style="font-style:normal;font-weight:normal;font-size:40px;line-height:125%;font-family:Sans;letter-spacing:0px;word-spacing:0px;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
y="650.02606"
x="-77.532547"
style="font-size:31.67041206px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Sans"
xml:space="preserve"><tspan
y="583.15552"
x="417.32373"
y="650.02606"
x="-77.532547"
id="tspan4511"
sodipodi:role="line">Button9</tspan></text>
<g
id="g4602"
transform="translate(-140.12576,-153.50496)">
<text
sodipodi:linespacing="125%"
id="text4572"
y="109.05057"
x="-431.3205"
style="font-style:normal;font-weight:normal;font-size:40px;line-height:125%;font-family:Sans;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
xml:space="preserve"><tspan
id="tspan4576"
y="109.05057"
x="-431.3205"
sodipodi:role="line">Resolution0</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:40px;line-height:125%;font-family:Sans;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="-431.3205"
y="182.02396"
id="text4580"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
x="-431.3205"
y="182.02396"
id="tspan4582">Resolution1</tspan></text>
<text
sodipodi:linespacing="125%"
id="text4584"
y="254.99734"
x="-431.3205"
style="font-style:normal;font-weight:normal;font-size:40px;line-height:125%;font-family:Sans;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
xml:space="preserve"><tspan
id="tspan4586"
y="254.99734"
x="-431.3205"
sodipodi:role="line">Resolution2</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:40px;line-height:125%;font-family:Sans;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="-431.3205"
y="327.97079"
id="text4588"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
x="-431.3205"
y="327.97079"
id="tspan4590">Resolution3</tspan></text>
<text
sodipodi:linespacing="125%"
id="text4592"
y="400.94421"
x="-431.3205"
style="font-style:normal;font-weight:normal;font-size:40px;line-height:125%;font-family:Sans;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
xml:space="preserve"><tspan
id="tspan4594"
y="400.94421"
x="-431.3205"
sodipodi:role="line">Resolution4</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:40px;line-height:125%;font-family:Sans;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="-431.3205"
y="473.91763"
id="text4596"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
x="-431.3205"
y="473.91763"
id="tspan4598">Resolution5</tspan></text>
</g>
<rect
style="fill:none;fill-opacity:1;stroke:#000000;stroke-opacity:1"
id="rect4600"
width="323.85489"
height="479.4184"
x="-615.48309"
y="-116.64217"
rx="10.321068"
ry="10.321068" />
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:40px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="-591.40881"
y="625.81189"
id="text4211"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
id="tspan4213"
x="-591.40881"
y="625.81189">Current Profile</tspan></text>
</g>
<g
inkscape:groupmode="layer"
id="layer6"
inkscape:label="Title">
<text
transform="translate(647.36582,205.64997)"
xml:space="preserve"
style="display:inline;font-style:normal;font-weight:normal;font-size:40px;line-height:125%;font-family:Sans;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="-271.95749"
y="-131.81583"
id="text4223"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
id="tspan4225"
x="-271.95749"
y="-131.81583"
style="font-size:70.00000763px">Etekcity Scroll Alpha</tspan></text>
style="font-size:32.00000381px">Button9</tspan></text>
<path
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;display:inline"
d="m -276.93036,342.77164 25.64997,0 0,-188.87707"
id="path4213"
inkscape:connector-curvature="0" />
</g>
</svg>

Before

Width:  |  Height:  |  Size: 27 KiB

After

Width:  |  Height:  |  Size: 23 KiB

File diff suppressed because it is too large Load Diff

Before

Width:  |  Height:  |  Size: 64 KiB

After

Width:  |  Height:  |  Size: 62 KiB

778
data/logitech-g502.svg Normal file
View File

@@ -0,0 +1,778 @@
<?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:xlink="http://www.w3.org/1999/xlink"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="750"
height="750"
viewBox="0 0 750.00004 749.99998"
id="svg2"
version="1.1"
inkscape:version="0.91 r13725"
sodipodi:docname="logitech-g502.svg">
<defs
id="defs4">
<linearGradient
inkscape:collect="always"
id="linearGradient4372">
<stop
style="stop-color:#3d444c;stop-opacity:1"
offset="0"
id="stop4374" />
<stop
style="stop-color:#8f9aaa;stop-opacity:1"
offset="1"
id="stop4376" />
</linearGradient>
<linearGradient
inkscape:collect="always"
id="linearGradient4327">
<stop
style="stop-color:#000000;stop-opacity:1;"
offset="0"
id="stop4329" />
<stop
style="stop-color:#969696;stop-opacity:1"
offset="1"
id="stop4331" />
</linearGradient>
<linearGradient
inkscape:collect="always"
id="linearGradient4319">
<stop
style="stop-color:#000000;stop-opacity:1;"
offset="0"
id="stop4321" />
<stop
style="stop-color:#969696;stop-opacity:1"
offset="1"
id="stop4323" />
</linearGradient>
<linearGradient
id="linearGradient4219">
<stop
style="stop-color:#c3c3c3;stop-opacity:1;"
offset="0"
id="stop4221" />
<stop
style="stop-color:#000000;stop-opacity:0;"
offset="1"
id="stop4223" />
</linearGradient>
<linearGradient
id="linearGradient4197">
<stop
style="stop-color:#ffffff;stop-opacity:1;"
offset="0"
id="stop4199" />
<stop
id="stop4205"
offset="0.23127364"
style="stop-color:#242424;stop-opacity:1;" />
<stop
style="stop-color:#242424;stop-opacity:1;"
offset="0.7880435"
id="stop4207" />
<stop
style="stop-color:#ffffff;stop-opacity:1;"
offset="1"
id="stop4201" />
</linearGradient>
<linearGradient
id="linearGradient4178">
<stop
id="stop4180"
offset="0"
style="stop-color:#000000;stop-opacity:1;" />
<stop
style="stop-color:#3b3b3b;stop-opacity:1;"
offset="0.46853611"
id="stop4182" />
<stop
style="stop-color:#777777;stop-opacity:1;"
offset="0.84132797"
id="stop4184" />
<stop
id="stop4186"
offset="1"
style="stop-color:#000000;stop-opacity:1;" />
</linearGradient>
<linearGradient
id="linearGradient4168">
<stop
id="stop4170"
offset="0"
style="stop-color:#000000;stop-opacity:1;" />
<stop
style="stop-color:#3b3b3b;stop-opacity:1;"
offset="0.646918"
id="stop4172" />
<stop
style="stop-color:#777777;stop-opacity:1;"
offset="0.76408035"
id="stop4174" />
<stop
id="stop4176"
offset="1"
style="stop-color:#000000;stop-opacity:1;" />
</linearGradient>
<linearGradient
id="linearGradient4150">
<stop
id="stop4152"
offset="0"
style="stop-color:#000000;stop-opacity:1;" />
<stop
style="stop-color:#3b3b3b;stop-opacity:1;"
offset="0.54100561"
id="stop4154" />
<stop
style="stop-color:#777777;stop-opacity:1;"
offset="0.84132797"
id="stop4156" />
<stop
id="stop4158"
offset="1"
style="stop-color:#000000;stop-opacity:1;" />
</linearGradient>
<linearGradient
id="linearGradient4140">
<stop
id="stop4142"
offset="0"
style="stop-color:#000000;stop-opacity:1;" />
<stop
style="stop-color:#3b3b3b;stop-opacity:1;"
offset="0.5890528"
id="stop4144" />
<stop
style="stop-color:#777777;stop-opacity:1;"
offset="0.69403088"
id="stop4146" />
<stop
id="stop4148"
offset="1"
style="stop-color:#000000;stop-opacity:1;" />
</linearGradient>
<linearGradient
id="linearGradient4047">
<stop
style="stop-color:#000000;stop-opacity:1;"
offset="0"
id="stop4049" />
<stop
id="stop4055"
offset="0.5"
style="stop-color:#000000;stop-opacity:0.49803922;" />
<stop
style="stop-color:#000000;stop-opacity:0;"
offset="1"
id="stop4051" />
</linearGradient>
<linearGradient
id="linearGradient4039">
<stop
style="stop-color:#636363;stop-opacity:1;"
offset="0"
id="stop4041" />
<stop
id="stop4063"
offset="0.19902708"
style="stop-color:#595959;stop-opacity:1;" />
<stop
id="stop4061"
offset="0.39056408"
style="stop-color:#4f4f4f;stop-opacity:1;" />
<stop
style="stop-color:#a3a3a3;stop-opacity:1;"
offset="1"
id="stop4043" />
</linearGradient>
<linearGradient
id="linearGradient4449">
<stop
style="stop-color:#000000;stop-opacity:1;"
offset="0"
id="stop4451" />
<stop
id="stop4059"
offset="0.24691147"
style="stop-color:#3b3b3b;stop-opacity:1;" />
<stop
id="stop4057"
offset="0.84132797"
style="stop-color:#777777;stop-opacity:1;" />
<stop
style="stop-color:#000000;stop-opacity:1;"
offset="1"
id="stop4453" />
</linearGradient>
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient4449"
id="linearGradient4562"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0,-1.698701,1.698701,0,-120.19569,737.44997)"
x1="31.968746"
y1="18.546629"
x2="31.968746"
y2="29.577879" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient4449"
id="linearGradient4623"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0,-1.6987012,-1.6987012,0,-45.565631,793.48827)"
x1="31.968746"
y1="18.546629"
x2="31.968746"
y2="29.577879" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient4319"
id="linearGradient4325"
x1="-258.85849"
y1="636.73883"
x2="-210.58292"
y2="669.61383"
gradientUnits="userSpaceOnUse" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient4327"
id="linearGradient4333"
x1="-258.85849"
y1="636.73883"
x2="-210.58292"
y2="669.61383"
gradientUnits="userSpaceOnUse" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient4372"
id="linearGradient4378"
x1="476.00003"
y1="513.00006"
x2="559.50006"
y2="463.50003"
gradientUnits="userSpaceOnUse" />
</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="359.25033"
inkscape:cy="331.87231"
inkscape:document-units="px"
inkscape:current-layer="layer4"
showgrid="false"
showguides="false"
inkscape:guide-bbox="true"
fit-margin-top="50"
fit-margin-left="50"
fit-margin-right="50"
fit-margin-bottom="50"
inkscape:window-width="2048"
inkscape:window-height="1088"
inkscape:window-x="2560"
inkscape:window-y="27"
inkscape:window-maximized="1" />
<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></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Device"
inkscape:groupmode="layer"
id="layer1"
transform="translate(522.78594,-165.96284)"
style="display:inline"
sodipodi:insensitive="true">
<g
id="g4390"
transform="translate(46.66905,-6.3639614)">
<path
sodipodi:nodetypes="zccccccscsscssssssssz"
inkscape:connector-curvature="0"
id="path4435"
d="m -226.16095,683.58782 c -6.01535,-13.02364 -13,-16.5 -13,-16.5 l -11.25,-3.375 -116.45795,-88.57547 11.4905,-82.02437 7.62132,1.97703 6.89061,-13.15685 c -18.38478,2.65165 -27.23986,-1.01777 -28.47729,-2.60876 -1.23744,-1.59099 0.17677,-3.18198 0.17677,-3.18198 0,0 7.43505,-10.39747 47.55294,-23.33452 117.72759,-37.96429 194.75285,-32.63933 310.328127,14.65494 101.699787,41.61632 127.995243,117.50993 130.641353,159.47011 0,0 -2.38649,0.17677 -5.74524,5.03813 -3.35876,4.86136 6.0104,17.05896 3.53553,28.72622 -2.47487,11.66726 -28.637827,53.29817 -45.166448,48.70198 -16.528622,-4.5962 -39.067651,-6.98268 -55.154331,-3.00521 -16.08667977,3.97748 -95.017477,43.75224 -100.144001,46.66905 -5.126525,2.91682 -19.26866,10.42983 -25.36746,10.87177 -6.09879,0.44194 -18.29639,-4.06586 -45.25483,-14.05375 -26.95845,-9.98788 -54.09367,-22.98097 -61.25313,-32.88046 -7.15946,-9.8995 -4.95112,-20.38922 -10.96647,-33.41286 z"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
<path
inkscape:connector-curvature="0"
id="path4362"
transform="translate(-522.78594,165.96281)"
d="m 564.2793,394.82812 c -3.92575,-0.10626 -7.28936,3.75042 -13.08985,11.8711 -8.83883,12.37437 -39.24401,61.16451 -77.07422,75.30664 -37.83021,14.14214 -97.93406,2.12147 -130.10742,-1.41406 -32.07532,-3.52476 -80.61133,-16.61719 -80.61133,-16.61719 l -30.16601,4.00391 39.14453,29.77148 11.25,3.375 c 0,0 6.98465,3.47636 13,16.5 6.01535,13.02364 3.80734,23.51261 10.9668,33.41211 7.15946,9.89949 34.2935,22.89298 61.25195,32.88086 26.95844,9.98789 39.15707,14.49663 45.25586,14.05469 6.0988,-0.44194 20.24066,-7.95623 25.36719,-10.87305 5.12652,-2.91681 84.05785,-42.69049 100.14453,-46.66797 16.08668,-3.97747 38.62567,-1.59229 55.15429,3.00391 16.52863,4.59619 42.69115,-37.03392 45.16602,-48.70117 0.81145,-3.82542 0.34164,-7.70307 -0.52734,-11.36524 -4.70923,-11.20032 -11.76875,-25.18057 -21.7461,-38.13281 -23.82425,-30.92783 -38.18467,-40.65753 -46.3164,-47.02149 -2.79529,-2.18761 -5.00616,-3.33105 -7.0625,-3.38672 z"
style="fill:url(#linearGradient4378);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
<g
id="g4356">
<path
inkscape:connector-curvature="0"
style="fill:#2e2d2b;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 130.91406,379.34375 c -0.46995,0.14042 -0.93877,0.27563 -1.41015,0.42187 0,10e-6 -1.6703,5.53928 -1.51758,6.25196 l 51.97265,21.91992 23.86524,-17.50195 2.72461,-3.55664 c -0.22885,-0.14243 -0.45999,-0.27609 -0.68945,-0.41602 -27.39877,-3.31358 -52.27682,-5.25289 -75.04493,-6.2793 l 0.0996,-0.83984 z"
transform="translate(-522.78594,165.96281)"
id="path4417" />
<path
inkscape:connector-curvature="0"
style="fill:#13130f;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 128.01367,386.0293 4.48633,9.0957 66,39.375 -18.53906,-26.56445 -0.002,0.002 -51.94531,-21.9082 z"
transform="translate(-522.78594,165.96281)"
id="path4422" />
<path
inkscape:connector-curvature="0"
style="fill:#7c7a79;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 203.82422,390.61328 c 0,0 -0.57509,0.25215 -0.60156,0.26367 l -23.26172,17.0586 18.38281,26.33984 -1.14844,-4.50586 0.79492,-17.32422 5.83399,-21.83203 z"
transform="translate(-522.78594,165.96281)"
id="path4427" />
</g>
<path
inkscape:connector-curvature="0"
id="path4216"
transform="translate(-522.78594,165.96281)"
d="M 411.19922,269.32812 C 389.02158,276.55183 382.23256,283.7763 371.75,291 l 25.375,6.25 c 18.2282,-19.41084 23.88453,-20.47312 31.20117,-23.95898 -5.76229,-1.45746 -11.46778,-2.78139 -17.12695,-3.9629 z"
style="fill:#3d4144;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
<path
inkscape:connector-curvature="0"
id="path4220"
d="m -170.91095,464.08782 -8.5,16.125 35.75,3.25 1.625,-16.25 z"
style="fill:#3c4247;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
<path
sodipodi:nodetypes="cssccccc"
inkscape:connector-curvature="0"
id="path4226"
transform="translate(-522.78594,165.96281)"
d="m 411.17969,269.33398 c -24.50302,-5.11518 -48.18402,-7.65405 -72.22657,-7.57031 -42.56105,0.14824 -86.27544,8.47266 -137.78124,25.08203 -40.11789,12.93705 -47.55274,23.33399 -47.55274,23.33399 0,0 -0.48629,0.56241 -0.63476,1.3457 l 0.10351,0.0684 c 65.05383,-30.40559 116.42376,-36.77027 218.33008,-20.63869 11.09267,-7.17661 17.60011,-14.39959 39.76172,-21.62112 z"
style="fill:#363c41;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
<path
inkscape:connector-curvature="0"
id="path4263"
transform="translate(-522.78594,165.96281)"
d="m 296.87305,518.20312 c 5.68645,12.75421 3.66653,23.08278 10.71875,32.83399 7.15946,9.89949 34.2935,22.89298 61.25195,32.88086 26.95844,9.98789 39.15707,14.49663 45.25586,14.05469 5.82656,-0.42222 18.90685,-7.25764 24.54101,-10.41407 -0.55038,-0.0177 -1.10725,-0.03 -1.64062,-0.0586 -7,-0.375 -17.75,-3.625 -26.375,-6.5 -8.625,-2.875 -67.14947,-20.67049 -76.375,-33.125 -7.10507,-9.59187 -5.33684,-16.54135 -8.83008,-19.27148 -2.49111,-1.94692 -8.34261,-3.73063 -12.5039,-5.15625 -3.08671,-1.05747 -11.18273,-3.67568 -16.04297,-5.24415 z"
style="fill:#10f5fa;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
<g
id="g4348">
<path
inkscape:connector-curvature="0"
style="fill:#a6a09b;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 244.0293,281.64062 c -11.87933,0.21005 -21.28719,4.70945 -25.45899,14.41407 l -7.76367,15.2207 c 4.63005,-8.00151 13.38623,-11.7657 24.20703,-11.95703 13.84985,-0.24489 31.05521,5.35529 47.24414,15.31641 4.24517,-2.44738 6.87171,-7.03619 7.65625,-8.34375 0.83684,-1.39473 3.09281,-4.54246 4.70703,-7.20118 -17.13681,-11.29215 -35.78244,-17.71107 -50.59179,-17.44922 z m -33.22266,29.63477 c -0.45292,0.78273 -0.88022,1.59229 -1.25195,2.45703 l 1.25195,-2.45703 z"
transform="translate(-522.78594,165.96281)"
id="path4228" />
<path
style="fill:#0c0d08;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 210.77539,311.25976 -1.12305,2.28126 c -0.45554,2.37144 2.75076,4.2831 5.21875,3.9746 2.82843,-0.35354 20.06602,-2.56346 32.97071,-2.74023 12.9047,-0.17678 22.09591,1.76761 29.34375,1.41406 1.88682,-0.092 3.57816,-0.69332 5.07226,-1.55468 -16.18893,-9.96112 -33.39429,-15.5613 -47.24414,-15.31641 -10.8208,0.19133 -19.60823,3.93989 -24.23828,11.9414 z"
id="path4247"
inkscape:connector-curvature="0"
sodipodi:nodetypes="ccssscsc"
transform="translate(-522.78594,165.96281)" />
</g>
<path
sodipodi:nodetypes="ccccc"
inkscape:connector-curvature="0"
id="path4258"
d="m -179.35432,480.17165 -2.95971,5.51668 39.24443,5.56847 -0.88388,-7.86656 z"
style="fill:#111419;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
<path
sodipodi:nodetypes="ccccc"
inkscape:connector-curvature="0"
id="path4260"
d="m -143.07496,491.2041 -1.00352,-7.90761 2.03293,-16.10721 1.45082,6.56663 z"
style="fill:#282d32;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
<g
id="g4352">
<path
style="fill:#2f333a;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m -313.91094,553.83781 -2.375,3.5 -3.875,14.125 93.375,-1.625 c -21.95804,-4.72268 -46.10785,-9.6343 -87.125,-16 z"
id="path4262"
inkscape:connector-curvature="0"
sodipodi:nodetypes="ccccc" />
<path
sodipodi:nodetypes="cccccc"
style="fill:#585958;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m -320.16094,571.44718 -3.125,23.01563 3.25,7.125 99.5,-15.375 -6.29687,-16.40625 z"
id="path4264"
inkscape:connector-curvature="0" />
</g>
<g
id="g4335">
<path
style="fill:url(#linearGradient4333);fill-opacity:1;fill-rule:evenodd;stroke:url(#linearGradient4325);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m -295.16094,608.46281 6.625,27.125 27.125,5.875 c 0,0 38.75,14.5 45.75,29.125 l 5.5,0.875 2.375,-4.625 c 0,0 -13.875,-23.75 -49.625,-33.375 l -1,-1.25 2.25,-11.25 z"
id="path4288"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cccccccccc" />
<path
style="fill:#1f2021;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="M 235.18359,469.82617 272.125,497.75 l 35,6.875 C 300.125,490 261.375,475.5 261.375,475.5 Z"
transform="translate(-522.78594,165.96281)"
id="path4290"
inkscape:connector-curvature="0"
sodipodi:nodetypes="ccccc" />
</g>
<g
id="g4297">
<path
style="fill:#5e5d5c;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m -271.28594,618.46281 4,7 85.38128,13.44194 9.61872,-8.44194 z"
id="path4266"
inkscape:connector-curvature="0"
sodipodi:nodetypes="ccccc" />
<path
style="fill:#242422;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m -181.07659,638.77695 c 0,0 22.18548,12.55115 -5.48008,8.04334 -27.66555,-4.5078 -67.97064,-12.55114 -67.97064,-12.55114 l -12.72792,-8.75045 z"
id="path4268"
inkscape:connector-curvature="0" />
<path
style="fill:#5e6570;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m -172.41453,630.38006 -9.45755,8.3085 9.28077,8.3969 9.54594,-5.3033 z"
id="path4270"
inkscape:connector-curvature="0"
sodipodi:nodetypes="ccccc" />
<path
style="fill:#181719;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m -271.48416,618.56636 2.19822,-8.60355 103.25,9.875 6,18.125 -2.625,3.875 -9.60983,-10.91789 z"
id="path4280"
inkscape:connector-curvature="0"
sodipodi:nodetypes="ccccccc" />
</g>
<g
id="g4305">
<path
style="fill:#676763;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m -164.98991,632.50138 6.18718,9.72272 75.041708,8.22011 8.131734,-6.54073 1.155328,-4.55469 4.153795,-8.23574 -93.255535,-9.12988 z"
id="path4272"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cccccccc" />
<path
style="fill:#2f343b;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m -70.32599,631.08717 5.48008,5.39169 -5.74524,12.90469 -5.204655,-5.54257 c 0.08832,-4.98178 3.353501,-8.62593 5.469815,-12.75381 z"
id="path4274"
inkscape:connector-curvature="0"
sodipodi:nodetypes="ccccc" />
<path
style="fill:#202328;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m -83.58424,650.17905 3.8007,4.06586 -77.87014,-6.89429 -1.15104,-5.14215 z"
id="path4276"
inkscape:connector-curvature="0"
sodipodi:nodetypes="ccccc" />
<path
sodipodi:nodetypes="ccccc"
inkscape:connector-curvature="0"
id="path4278"
d="m -70.59115,649.38355 -9.1397,4.91406 -3.894905,-4.1034 7.819685,-6.37912 z"
style="fill:#97a6b5;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
</g>
<path
sodipodi:nodetypes="ccccc"
inkscape:connector-curvature="0"
id="path4292"
d="m -153.03036,495.18342 44.96255,6.76837 1.76776,125.51145 -32.51219,-3.18198 z"
style="fill:#676769;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
<path
style="fill:#181719;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m -164.98991,632.50138 89.360622,11.4021 1.155328,-4.55469 4.153795,-8.23574 -93.255535,-9.12988 z"
id="path4303"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cccccc" />
<g
id="g4282">
<path
style="fill:#9b9994;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m -283.96063,605.18939 1.59099,4.06586 144.42656,16.26346 -6.01041,-45.07806 z"
id="path4244"
inkscape:connector-curvature="0" />
<path
inkscape:connector-curvature="0"
style="fill:#2cbfff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 312.64258,435.04297 -5.01172,0.64453 8.00195,8.8418 5.88281,0.41015 -8.87304,-9.89648 z"
transform="translate(-522.78594,165.96281)"
id="path4246" />
<path
inkscape:connector-curvature="0"
style="fill:#2cbfff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 331.68945,432.58984 -4.78515,0.61524 11.86718,12.93945 6.72461,0.4707 -13.80664,-14.02539 z"
transform="translate(-522.78594,165.96281)"
id="path4248" />
<path
inkscape:connector-curvature="0"
style="fill:#2cbfff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 351.97266,429.97852 -6.13282,0.78906 16.58594,17.0293 7.58399,0.52929 -18.03711,-18.34765 z"
transform="translate(-522.78594,165.96281)"
id="path4250" />
</g>
<g
id="g4339">
<path
style="fill:#4c5053;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m -386.31433,498.06271 -5.65686,48.08326 c 45.99186,2.07336 100.55399,7.85718 167.23075,21.21321 l 1.06066,3.0052 c 23.24045,-1.15617 46.44002,-2.32824 77.95852,-0.26516 l 3.35876,3.62392 -10.6066,-78.48885 c -119.63944,-15.8417 -179.55343,-5.16228 -233.34523,2.82842 z"
id="path3608"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cccccccc" />
<path
inkscape:connector-curvature="0"
style="fill:#413d44;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 344.67578,403.00977 c -16.50546,-0.0586 -30.99426,0.6673 -45.49414,1.38867 l 6.64258,15.02929 74.77539,-10.96093 -0.94727,-1.53907 -2.58789,-2.79101 c -11.81943,-0.77366 -22.46808,-1.09174 -32.38867,-1.12695 z"
transform="translate(-522.78594,165.96281)"
id="path4412" />
<path
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m -296.22345,497.71282 4.375,6.6875 6.875,-6.8125 z"
id="path4242"
inkscape:connector-curvature="0" />
</g>
<g
style="stroke:none"
id="g4344">
<path
style="fill:#6d747e;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 428.32422,273.29297 c -7.29616,3.47575 -12.94858,4.55152 -31.06055,23.8125 0.0479,0.0864 0.0803,0.17102 0.13086,0.25781 6.62912,19.7106 10.60547,165.375 10.60547,165.375 0,0 41.19295,7.2655 67.125,1.38672 22.33947,-5.06434 38.625,-29.625 51.125,-42.625 12.5,-13 24.89365,-35.29164 33.5,-37.875 6.89763,-2.07046 15.8234,4.4109 29.125,12.375 33.4418,20.02269 42.89394,39.55603 52.79297,65.09375 0.30214,-0.10531 0.47265,-0.12305 0.47265,-0.12305 C 639.49453,419.01054 613.19977,343.11632 511.5,301.5 481.65769,289.2883 454.39027,279.88532 428.32422,273.29297 Z"
transform="translate(-522.78594,165.96281)"
id="path4234"
inkscape:connector-curvature="0"
sodipodi:nodetypes="ccccssssccsc" />
<ellipse
style="opacity:1;fill:#2cbfff;fill-opacity:1;stroke:none;stroke-width:1.5;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="path4261"
cx="-58.535938"
cy="561.08783"
rx="32.25"
ry="29.875" />
</g>
<path
inkscape:connector-curvature="0"
id="path4218"
d="m -205.53595,454.96282 -11.375,19 21.5,-0.875 10.875,-18.875 z"
style="fill:#202124;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
<path
sodipodi:nodetypes="ccccc"
inkscape:connector-curvature="0"
id="path4254"
d="m -222.88428,483.39024 6.01577,-9.47808 21.47301,-0.86336 1.23744,11.49049 z"
style="fill:#121518;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
<path
sodipodi:nodetypes="ccccc"
inkscape:connector-curvature="0"
id="path4256"
d="m -195.50442,473.05324 10.88157,-18.79455 2.39721,10.39322 -12.00029,19.91863 z"
style="fill:#1a1e22;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
</g>
</g>
<g
inkscape:groupmode="layer"
id="layer4"
inkscape:label="Leaders"
transform="translate(647.36582,-57.672066)"
style="display:inline">
<path
inkscape:connector-curvature="0"
id="path4556"
d="m -94.323676,683.09816 5.56391,3.21163 5.56059,3.21159 0,-3.66282 11.76151,0 -1.59253,-2.7604 1.59253,-2.76039 -11.76151,0 0,-3.66282 -5.56059,3.21162 -5.56391,3.21159 z"
style="display:inline;fill:url(#linearGradient4562);fill-opacity:1;stroke:none" />
<path
inkscape:connector-curvature="0"
id="use4558"
d="m -71.437651,739.13645 -5.56391,3.21162 -5.56059,3.21159 0,-3.66282 -11.76152,0 1.59254,-2.76039 -1.59254,-2.76039 11.76152,0 0,-3.66282 5.56059,3.21161 5.56391,3.2116 z"
style="fill:url(#linearGradient4623);fill-opacity:1;stroke:none" />
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:40.00000381px;line-height:125%;font-family:Sans;-inkscape-font-specification:'Sans, Normal';text-align:end;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:end;display:inline;fill:#000000;fill-opacity:1;stroke:none"
x="-507.44232"
y="412.75952"
id="text4489"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
id="tspan4491"
x="-507.44232"
y="412.75952"
style="font-size:32px">Button0</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:40px;line-height:125%;font-family:Sans;letter-spacing:0px;word-spacing:0px;display:inline;fill:#000000;fill-opacity:1;stroke:none"
x="-60.689339"
y="696.94501"
id="text4505"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
id="tspan4507"
x="-60.689339"
y="696.94501"
style="font-size:32px">Button10</tspan></text>
<text
sodipodi:linespacing="125%"
id="text4509"
y="753.67065"
x="-60.689339"
style="font-style:normal;font-weight:normal;font-size:40px;line-height:125%;font-family:Sans;letter-spacing:0px;word-spacing:0px;display:inline;fill:#000000;fill-opacity:1;stroke:none"
xml:space="preserve"><tspan
y="753.67065"
x="-60.689339"
id="tspan4511"
sodipodi:role="line"
style="font-size:32px">Button9</tspan></text>
<text
sodipodi:linespacing="125%"
id="text4440"
y="467.91382"
x="-507.44232"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:40.00000381px;line-height:125%;font-family:Sans;-inkscape-font-specification:'Sans, Normal';text-align:end;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:end;display:inline;fill:#000000;fill-opacity:1;stroke:none"
xml:space="preserve"><tspan
style="font-size:32px"
y="467.91382"
x="-507.44232"
id="tspan4442"
sodipodi:role="line">Button7</tspan></text>
<path
inkscape:connector-curvature="0"
id="path4448"
d="m -501.44135,408.77695 79.19595,0"
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
sodipodi:nodetypes="cc" />
<path
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m -290.72353,319.68149 38.18376,-118.08684"
id="path4450"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
<text
sodipodi:linespacing="125%"
id="text4452"
y="209.51634"
x="-419.71732"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:40.00000381px;line-height:125%;font-family:Sans;-inkscape-font-specification:'Sans, Normal';text-align:center;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;display:inline;fill:#000000;fill-opacity:1;stroke:none"
xml:space="preserve"><tspan
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:32px;font-family:Sans;-inkscape-font-specification:Sans"
y="209.51634"
x="-419.71732"
id="tspan4454"
sodipodi:role="line">Button2</tspan></text>
<path
inkscape:connector-curvature="0"
id="path4456"
d="M -355.77735,340.18759 -422.9525,219.97943"
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
sodipodi:nodetypes="cc" />
<path
inkscape:connector-curvature="0"
id="path4466"
d="m -302.74434,651.31459 94.0452,-113.8442"
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
sodipodi:nodetypes="cc" />
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:40.00000381px;line-height:125%;font-family:Sans;-inkscape-font-specification:'Sans, Normal';text-align:end;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:end;display:inline;fill:#000000;fill-opacity:1;stroke:none"
x="-507.44232"
y="516.70416"
id="text4468"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
id="tspan4470"
x="-507.44232"
y="516.70416"
style="font-size:32px">Button6</tspan></text>
<text
sodipodi:linespacing="125%"
id="text4472"
y="566.90875"
x="-455.11642"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:40.00000381px;line-height:125%;font-family:Sans;-inkscape-font-specification:'Sans, Normal';text-align:end;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:end;display:inline;fill:#000000;fill-opacity:1;stroke:none"
xml:space="preserve"><tspan
style="font-size:32px"
y="566.90875"
x="-455.11642"
id="tspan4474"
sodipodi:role="line">Button4</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:40.00000381px;line-height:125%;font-family:Sans;-inkscape-font-specification:'Sans, Normal';text-align:end;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:end;display:inline;fill:#000000;fill-opacity:1;stroke:none"
x="-456.53064"
y="616.40625"
id="text4476"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
id="tspan4478"
x="-456.53064"
y="616.40625"
style="font-size:32px">Button5</tspan></text>
<text
sodipodi:linespacing="125%"
id="text4480"
y="662.36816"
x="-310.86664"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:40.00000381px;line-height:125%;font-family:Sans;-inkscape-font-specification:'Sans, Normal';text-align:end;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:end;display:inline;fill:#000000;fill-opacity:1;stroke:none"
xml:space="preserve"><tspan
style="font-size:32px"
y="662.36816"
x="-310.86664"
id="tspan4482"
sodipodi:role="line">Button3</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:40.00000381px;line-height:125%;font-family:Sans;-inkscape-font-specification:'Sans, Normal';text-align:left;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;display:inline;fill:#000000;fill-opacity:1;stroke:none"
x="-252.13301"
y="200.32396"
id="text4484"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
id="tspan4486"
x="-252.13301"
y="200.32396"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:32px;font-family:Sans;-inkscape-font-specification:Sans">Button1</tspan></text>
<text
sodipodi:linespacing="125%"
id="text4488"
y="247.93217"
x="-103.82285"
style="font-style:normal;font-weight:normal;font-size:40px;line-height:125%;font-family:Sans;letter-spacing:0px;word-spacing:0px;display:inline;fill:#000000;fill-opacity:1;stroke:none"
xml:space="preserve"><tspan
style="font-size:32px"
y="247.93217"
x="-103.82285"
id="tspan4490"
sodipodi:role="line">Button8</tspan></text>
<path
sodipodi:nodetypes="cc"
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m -502.14846,464.63839 60.10407,-12.72792"
id="path4492"
inkscape:connector-curvature="0" />
<path
inkscape:connector-curvature="0"
id="path4494"
d="m -496.4916,512.72165 126.57211,-43.84061"
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
sodipodi:nodetypes="cc" />
<path
sodipodi:nodetypes="cc"
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m -445.57991,562.92624 140.71425,-43.84062"
id="path4496"
inkscape:connector-curvature="0" />
<path
inkscape:connector-curvature="0"
id="path4498"
d="m -439.21595,608.88818 100.40916,-61.51829"
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
sodipodi:nodetypes="cc" />
<path
sodipodi:nodetypes="cc"
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="M -232.03365,357.15816 -108.28996,250.38503"
id="path4500"
inkscape:connector-curvature="0" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 38 KiB

708
data/logitech-g700.svg Normal file

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 36 KiB

View File

@@ -10,12 +10,12 @@
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="414.6424mm"
height="285.98199mm"
viewBox="0 0 1469.2054 1013.322"
width="750"
height="750"
viewBox="0 0 750.00004 749.99998"
id="svg2"
version="1.1"
inkscape:version="0.91 r13725"
inkscape:version="0.48.4 r9939"
sodipodi:docname="logitech-mx_master.svg">
<defs
id="defs4">
@@ -46,22 +46,22 @@
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient5128"
id="linearGradient5134"
id="linearGradient3078"
gradientUnits="userSpaceOnUse"
spreadMethod="reflect"
x1="230.63638"
y1="432.30179"
x2="238.061"
y2="447.85815"
gradientUnits="userSpaceOnUse"
spreadMethod="reflect" />
y2="447.85815" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient5204"
id="linearGradient5210"
id="linearGradient3080"
gradientUnits="userSpaceOnUse"
x1="196.63423"
y1="468.17209"
x2="170.13423"
y2="402.67206"
gradientUnits="userSpaceOnUse" />
y2="402.67206" />
</defs>
<sodipodi:namedview
id="base"
@@ -70,11 +70,11 @@
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="0.70710678"
inkscape:cx="672.09896"
inkscape:cy="504.57351"
inkscape:zoom="1"
inkscape:cx="417.6511"
inkscape:cy="345.62267"
inkscape:document-units="px"
inkscape:current-layer="layer2"
inkscape:current-layer="layer4"
showgrid="false"
showguides="true"
inkscape:guide-bbox="true"
@@ -83,9 +83,9 @@
fit-margin-right="50"
fit-margin-bottom="50"
inkscape:window-width="1920"
inkscape:window-height="1016"
inkscape:window-x="0"
inkscape:window-y="27"
inkscape:window-height="1099"
inkscape:window-x="1920"
inkscape:window-y="28"
inkscape:window-maximized="1" />
<metadata
id="metadata7">
@@ -100,290 +100,253 @@
</rdf:RDF>
</metadata>
<g
inkscape:label="Mouse"
inkscape:label="Device"
inkscape:groupmode="layer"
id="layer1"
transform="translate(522.78594,97.359194)"
style="display:inline"
sodipodi:insensitive="true">
<path
style="fill:#433737;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 921.14258,351.92188 c -10.71472,0.3561 17.48242,40.65039 17.48242,40.65039 l -0.99805,38.58007 c -0.0632,-0.10181 -0.1163,-0.2052 -0.18164,-0.30664 -0.41273,0.4635 -0.8827,0.9276 -1.47656,1.39063 C 883.92622,472.81347 836.5,478.32226 756.5,516.32227 c -80,37.99997 -316.69239,159.29807 -343.5,147.5 -0.19217,-0.0846 -0.3462,-0.18445 -0.50195,-0.28321 -0.14711,0.0864 -0.35538,0.19871 -0.49805,0.28321 -0.0138,-0.0118 -0.0272,-0.0234 -0.041,-0.0352 l -0.0273,0.0156 c 20.65212,21.99316 41.34778,28.42752 134.68945,6.01954 l 67.87891,0 c 0,0 31.685,6.41255 73,41.25 56.21397,47.40048 70.15272,37.94645 213.83008,7.3789 120.72766,-25.68496 98.22343,-76.56575 107.07816,-168.1289 5.6329,-58.24749 15.6725,-114.94915 -35.90824,-161 -31.61176,-28.22275 -46.12465,-37.57431 -51.35742,-37.40039 z"
transform="translate(-522.78594,-97.359255)"
id="path5084"
inkscape:connector-curvature="0" />
<path
style="fill:#3d3d3d;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 766.6582,304.5 c -179.15881,0.002 -367.84961,155.86523 -367.84961,155.86523 -21.93235,32.98189 -41.23548,69.54864 -57.98242,109.60157 7.5036,28.04106 30.67382,59.21512 71.17383,93.85547 59.9519,-35.50497 512.63903,-236.02476 512.5,-244 95.7156,51.99999 -269.006,189 -269,189 -12.27104,5.04673 -14.55606,11.0677 -7.5,18 l 2.06445,1.76953 0.002,0 11.89062,10.1875 c -0.62249,0.15805 -1.26128,0.30706 -1.87305,0.48242 -47.26127,13.54738 -84.55325,23.64795 -114.41015,30.79101 L 615,669.82227 l 63.40625,-16.95508 38.59961,33.06445 c 38.18376,34.64823 37.84255,32.06806 141.42187,14.14258 C 964.16532,681.77523 962.3307,680.80807 974.39258,545.2168 984.45817,432.06647 1011.3318,377.81074 858.42773,320.35742 828.82733,309.23515 797.88772,304.49969 766.6582,304.5 Z"
transform="translate(-522.78594,-97.359255)"
id="path5077"
inkscape:connector-curvature="0"
sodipodi:nodetypes="scccccccccsccccssss" />
<path
style="fill:#826c5e;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 924.5,419.82227 c 0.13868,7.95534 -450.25292,207.4789 -512.00586,243.71484 0.15695,0.0995 0.31224,0.19994 0.50586,0.28516 26.80761,11.79809 263.5,-109.50001 343.5,-147.5 80,-38.00001 127.42622,-43.50878 179.46875,-84.08594 0.5964,-0.46501 1.06842,-0.93101 1.48242,-1.39649 -2.56726,-3.98332 -6.80221,-7.67699 -12.95117,-11.01757 z"
transform="translate(-522.78594,-97.359255)"
id="path5079"
inkscape:connector-curvature="0" />
<path
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 633.2832,328.9668 c -128.50884,43.87332 -234.47461,131.39843 -234.47461,131.39843 -21.86064,32.87406 -41.10756,69.31169 -57.8164,109.21094 l 0.008,-0.004 61.25,-46.25 c -0.31467,-30.27892 8.67871,-33.61166 108.5,-91 105.67745,-60.75512 109.87649,-54.6167 115.74609,-80.49805 1.83541,-8.09301 4.52898,-16.4514 6.78711,-22.85742 z"
transform="translate(-522.78594,-97.359255)"
id="path5101"
inkscape:connector-curvature="0" />
<path
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 640.70703,428.57422 c -3.04651,0.0756 -6.31444,0.73835 -9.96875,2.0918 -19.09188,7.07104 -141.89935,74.20682 -175.71484,98.99414 -48.59449,35.62053 -48.4375,14.14257 -48.4375,14.14257 l -4.24219,-20.85937 c 0,0 -0.0901,0.0489 -0.0937,0.0508 9.1e-4,0.11168 -10e-4,0.2157 0,0.32813 l -61.25,46.25 -0.008,0.004 c -0.0548,0.13093 -0.11124,0.25961 -0.16602,0.39063 7.5036,28.04104 30.67382,59.21512 71.17383,93.85547 0.14966,-0.0886 0.33959,-0.19447 0.49414,-0.28516 0.0169,-0.01 0.0397,-0.0213 0.0566,-0.0312 1.02546,-0.60112 2.16407,-1.25057 3.39844,-1.93945 0.2066,-0.11531 0.43415,-0.23971 0.64648,-0.35743 1.08032,-0.59888 2.2254,-1.22479 3.45118,-1.88476 0.32998,-0.17769 0.67334,-0.36095 1.01367,-0.54297 1.22538,-0.65535 2.51457,-1.33647 3.87109,-2.04687 0.32591,-0.17069 0.65104,-0.34183 0.98438,-0.51563 0.98003,-0.51099 2.03888,-1.05627 3.08203,-1.59375 1.50441,-0.77516 3.19823,-1.63034 4.83007,-2.45898 2.6812,-1.36148 5.48308,-2.77245 8.49219,-4.27149 1.45002,-0.72234 2.95192,-1.46789 4.47461,-2.2207 3.14575,-1.55527 6.43566,-3.16851 9.87696,-4.84766 1.7505,-0.85415 3.50304,-1.70917 5.32617,-2.59375 3.69907,-1.79476 7.57491,-3.665 11.55664,-5.57812 1.62203,-0.77935 3.19102,-1.53607 4.85742,-2.33399 4.85137,-2.32297 9.91021,-4.73306 15.11328,-7.20312 1.05862,-0.50256 2.06054,-0.98002 3.13281,-1.48828 6.27234,-2.97314 12.74159,-6.02841 19.44532,-9.18164 0.19493,-0.0917 0.37504,-0.1777 0.57031,-0.26954 0.88374,-0.4156 1.84183,-0.86083 2.73242,-1.27929 8.89106,-4.17765 18.33343,-8.58591 27.83008,-13.01563 9.48674,-4.42512 19.20352,-8.94432 29.15625,-13.5625 5.63004,-2.6124 11.17539,-5.18811 16.91992,-7.84765 11.03955,-5.11098 22.24511,-10.28776 33.57227,-15.51563 4.59686,-2.12162 9.06381,-4.18813 13.6875,-6.32031 31.79772,-14.66333 64.04275,-29.4992 94.89648,-43.72656 0.64347,-0.29672 1.23671,-0.57103 1.87891,-0.86719 -0.0661,-2.523 -0.5325,-5.27289 -1.4043,-8.3125 -2.95973,-10.3194 -36.14133,-35.93502 -56.06055,-50.55859 C 663.08118,438.83704 654.18972,428.94451 642,428.57812 c -0.42664,-0.0128 -0.85775,-0.0147 -1.29297,-0.004 z"
transform="translate(-522.78594,-97.359255)"
id="path5107"
inkscape:connector-curvature="0" />
<rect
style="fill:#000000;fill-opacity:1;stroke:#ffffff;stroke-width:1.00065422;stroke-opacity:1"
id="rect5118"
width="42.955582"
height="22.140448"
x="-63.730179"
y="299.94894"
rx="3.3438475"
ry="3.162921"
transform="matrix(0.89707316,-0.44188205,0.39545007,0.91848747,0,0)" />
<path
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 275.08906,417.33778 4.375,22.875 80.75,-60.625 z"
id="path5120"
inkscape:connector-curvature="0" />
<path
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 281.58906,443.33778 91.75,-68.625 c 10.87423,-8.13345 34.03844,-10.26653 -9.25,21.375 -37.38734,27.32814 -82.5,47.25 -82.5,47.25 z"
id="path5122"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cssc" />
<path
style="fill:url(#linearGradient5134);fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.00000012;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 197.58906,448.96278 c 6.125,13 10.625,29.125 10.625,29.125 0,0 57.34269,-25.16319 68.25,-30.75 -0.13843,-9.48681 -3.52264,-22.72856 -8.375,-27.875 -27.125,3.75 -70.5,29.5 -70.5,29.5 z"
id="path5124"
inkscape:connector-curvature="0"
sodipodi:nodetypes="ccccc" />
<path
style="fill:#797979;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 3.47828,341.26173 c 0,0 6.886406,9.46214 7.95495,30.22881 -9.7125082,0.38797 -22.45064,-1.59098 -48.96714,10.78339 -26.5165,12.37437 -35.70889,37.29989 -35.70889,37.29989 l -6.84404,-0.46967 -8.1731,-22.75242 c 0,0 5.196794,-22.7334 30.485095,-40.41753 C -32.486544,338.25007 3.47828,341.26173 3.47828,341.26173 Z"
id="path5138"
inkscape:connector-curvature="0"
sodipodi:nodetypes="ccsccczc" />
<path
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 527.89648,441.94336 c -11.21543,-6.8e-4 -35.91089,1.15173 -54.02148,10.37891 -20.66776,10.53002 -34.76604,36.66892 -38.41016,44.00195 l 7.17383,19.9707 c 2.6388,-7.65898 11.92913,-28.82418 37.36133,-42.34765 27.46537,-14.60461 48.83613,-10.8705 53.86328,-9.67383 -1.11415,-11.22385 -3.86953,-18.48609 -5.74414,-22.32617 -0.0929,-1.7e-4 -0.12786,-0.004 -0.22266,-0.004 z"
transform="translate(-522.78594,-97.359255)"
id="path5140"
inkscape:connector-curvature="0" />
<path
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 485.25195,479.63281 c -26.5165,12.37437 -35.70886,37.34486 -35.70886,37.34486 9.75656,-6.29912 84.5483,-48.37571 84.5483,-48.37571 -6.04962,0.7682 -22.32294,-1.34352 -48.83944,11.03085 z"
transform="translate(-522.78594,-97.359255)"
id="path5145"
inkscape:connector-curvature="0"
sodipodi:nodetypes="sccs" />
</g>
<g
inkscape:groupmode="layer"
id="layer3"
inkscape:label="Actions"
style="display:inline"
transform="translate(647.36582,205.64997)"
sodipodi:insensitive="true">
<path
style="display:inline;fill:#868686;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m -6.1035156,230.91992 c -19.3024674,3.60682 -35.0488854,16.31894 -52.6556354,24.21599 -51.094769,27.0536 -101.437299,55.94388 -149.051399,88.65901 -9.95415,5.51243 -22.54214,11.99271 -33.83984,6.61914 -6.38959,-3.90926 -7.96324,-11.94005 -8.66992,-18.82617 -15.28799,12.40039 -32.51253,23.07504 -46.6875,36.30469 11.43671,32.54466 37.53518,57.07166 61.90234,80.5625 1.79409,1.58773 4.14015,-3.28155 6.15485,-2.80815 C -144.1825,402.09598 -56.798635,363.92186 29.448769,323.50255 46.66114,315.61589 63.86767,307.71041 80.912109,299.46484 75.326356,287.31278 62.865961,280.7519 53.502952,271.87742 35.5688,257.98999 18.22755,242.94827 -1.484375,231.63672 c -1.4916064,-0.46547 -3.0527704,-0.75113 -4.6191406,-0.7168 z"
id="path5151"
inkscape:connector-curvature="0" />
<path
style="display:inline;fill:#868686;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m -28.414062,137.02148 c -76.907488,29.50803 -148.819988,71.80459 -213.308758,122.89206 -13.55128,17.43946 -23.11685,37.54603 -33.88323,56.82187 -3.7754,7.32186 -7.34192,14.58222 -10.84707,22.04584 11.21464,-8.37958 22.86793,-16.47415 33.20898,-25.8125 -0.25698,-17.631 11.68533,-33.06792 26.42383,-41.59375 31.52229,-22.08766 66.11652,-39.23093 99.04413,-59.05073 30.395219,-17.37588 61.961588,-32.92482 91.295711,-52.0313 6.692064,-6.28955 7.910236,-15.49613 9.814453,-23.93359 l -0.935164,0.35421 -0.812882,0.30789 z"
id="path5162"
inkscape:connector-curvature="0" />
<path
style="display:inline;fill:#868686;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 152.77364,310.2307 c 1.1582,6.05599 2.3164,12.11198 3.4746,18.16797 21.37631,-16.04948 42.75261,-32.09896 64.12891,-48.14843 -22.5345,9.99349 -45.06901,19.98697 -67.60351,29.98046 z"
id="path5173"
inkscape:connector-curvature="0" />
<path
style="display:inline;fill:#868686;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 261.2834,263.28539 c -12.21657,2.16029 -20.42211,12.86093 -30.56476,19.12846 -18.40968,13.8199 -38.36778,28.59535 -55.81414,41.82076 29.28272,-15.22709 58.48771,-31.62916 82.88671,-54.0625 1.70896,-1.96865 4.73868,-4.48833 4.69532,-6.85547 -0.39767,-0.0641 -0.80252,-0.0596 -1.20313,-0.0312 z"
id="path5187"
inkscape:connector-curvature="0" />
<path
style="display:inline;fill:url(#linearGradient5210);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 42.546875,449.04102 c 19.339052,15.73498 36.723013,34.10436 57.603515,47.67578 20.60808,9.36671 43.55773,2.08926 64.83959,-0.49809 35.57938,-6.15258 71.49952,-11.18454 106.39931,-20.59787 15.04923,-4.60526 29.72058,-14.93837 34.46618,-30.81811 9.43121,-25.52623 9.54274,-53.05503 12.87313,-79.81517 -0.62149,-4.24546 3.55982,-14.72991 -0.52003,-14.51534 -91.88723,32.85626 -183.77446,65.71253 -275.661695,98.5688 z"
id="path5192"
inkscape:connector-curvature="0" />
<path
style="display:inline;fill:#868686;fill-opacity:1;stroke:none;stroke-width:1.00065422;stroke-opacity:1"
d="m -27.103516,182.32422 c -10.397754,4.71799 -21.409505,9.91406 -30.929687,15.4375 2.508683,3.97971 3.88786,8.5168 5.707031,12.72266 10.007293,-5.84796 21.032198,-9.89858 31.039063,-15.81641 -1.598593,-4.02995 -3.118058,-9.77197 -5.816407,-12.34375 z"
id="rect5212"
inkscape:connector-curvature="0" />
transform="translate(522.78594,-165.96284)"
style="display:inline">
<g
id="g3058"
transform="matrix(0.70142923,0,0,0.70142923,-172.43767,286.8878)">
<path
inkscape:connector-curvature="0"
id="path5084"
transform="translate(-522.78594,-97.359255)"
d="m 921.14258,351.92188 c -10.71472,0.3561 17.48242,40.65039 17.48242,40.65039 l -0.99805,38.58007 c -0.0632,-0.10181 -0.1163,-0.2052 -0.18164,-0.30664 -0.41273,0.4635 -0.8827,0.9276 -1.47656,1.39063 C 883.92622,472.81347 836.5,478.32226 756.5,516.32227 c -80,37.99997 -316.69239,159.29807 -343.5,147.5 -0.19217,-0.0846 -0.3462,-0.18445 -0.50195,-0.28321 -0.14711,0.0864 -0.35538,0.19871 -0.49805,0.28321 -0.0138,-0.0118 -0.0272,-0.0234 -0.041,-0.0352 l -0.0273,0.0156 c 20.65212,21.99316 41.34778,28.42752 134.68945,6.01954 l 67.87891,0 c 0,0 31.685,6.41255 73,41.25 56.21397,47.40048 70.15272,37.94645 213.83008,7.3789 120.72766,-25.68496 98.22343,-76.56575 107.07816,-168.1289 5.6329,-58.24749 15.6725,-114.94915 -35.90824,-161 -31.61176,-28.22275 -46.12465,-37.57431 -51.35742,-37.40039 z"
style="fill:#433737;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.42566061px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
<path
sodipodi:nodetypes="scccccccccsccccssss"
inkscape:connector-curvature="0"
id="path5077"
transform="translate(-522.78594,-97.359255)"
d="m 766.6582,304.5 c -179.15881,0.002 -367.84961,155.86523 -367.84961,155.86523 -21.93235,32.98189 -41.23548,69.54864 -57.98242,109.60157 7.5036,28.04106 30.67382,59.21512 71.17383,93.85547 59.9519,-35.50497 512.63903,-236.02476 512.5,-244 95.7156,51.99999 -269.006,189 -269,189 -12.27104,5.04673 -14.55606,11.0677 -7.5,18 l 2.06445,1.76953 0.002,0 11.89062,10.1875 c -0.62249,0.15805 -1.26128,0.30706 -1.87305,0.48242 -47.26127,13.54738 -84.55325,23.64795 -114.41015,30.79101 L 615,669.82227 l 63.40625,-16.95508 38.59961,33.06445 c 38.18376,34.64823 37.84255,32.06806 141.42187,14.14258 C 964.16532,681.77523 962.3307,680.80807 974.39258,545.2168 984.45817,432.06647 1011.3318,377.81074 858.42773,320.35742 828.82733,309.23515 797.88772,304.49969 766.6582,304.5 z"
style="fill:#3d3d3d;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.42566061px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
<path
inkscape:connector-curvature="0"
id="path5079"
transform="translate(-522.78594,-97.359255)"
d="m 924.5,419.82227 c 0.13868,7.95534 -450.25292,207.4789 -512.00586,243.71484 0.15695,0.0995 0.31224,0.19994 0.50586,0.28516 26.80761,11.79809 263.5,-109.50001 343.5,-147.5 80,-38.00001 127.42622,-43.50878 179.46875,-84.08594 0.5964,-0.46501 1.06842,-0.93101 1.48242,-1.39649 -2.56726,-3.98332 -6.80221,-7.67699 -12.95117,-11.01757 z"
style="fill:#826c5e;fill-opacity:1;fill-rule:evenodd;stroke:none" />
<path
inkscape:connector-curvature="0"
id="path5101"
transform="translate(-522.78594,-97.359255)"
d="m 633.2832,328.9668 c -128.50884,43.87332 -234.47461,131.39843 -234.47461,131.39843 -21.86064,32.87406 -41.10756,69.31169 -57.8164,109.21094 l 0.008,-0.004 61.25,-46.25 c -0.31467,-30.27892 8.67871,-33.61166 108.5,-91 105.67745,-60.75512 109.87649,-54.6167 115.74609,-80.49805 1.83541,-8.09301 4.52898,-16.4514 6.78711,-22.85742 z"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:1.42566061px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
<path
inkscape:connector-curvature="0"
id="path5107"
transform="translate(-522.78594,-97.359255)"
d="m 640.70703,428.57422 c -3.04651,0.0756 -6.31444,0.73835 -9.96875,2.0918 -19.09188,7.07104 -141.89935,74.20682 -175.71484,98.99414 -48.59449,35.62053 -48.4375,14.14257 -48.4375,14.14257 l -4.24219,-20.85937 c 0,0 -0.0901,0.0489 -0.0937,0.0508 9.1e-4,0.11168 -10e-4,0.2157 0,0.32813 l -61.25,46.25 -0.008,0.004 c -0.0548,0.13093 -0.11124,0.25961 -0.16602,0.39063 7.5036,28.04104 30.67382,59.21512 71.17383,93.85547 0.14966,-0.0886 0.33959,-0.19447 0.49414,-0.28516 0.0169,-0.01 0.0397,-0.0213 0.0566,-0.0312 1.02546,-0.60112 2.16407,-1.25057 3.39844,-1.93945 0.2066,-0.11531 0.43415,-0.23971 0.64648,-0.35743 1.08032,-0.59888 2.2254,-1.22479 3.45118,-1.88476 0.32998,-0.17769 0.67334,-0.36095 1.01367,-0.54297 1.22538,-0.65535 2.51457,-1.33647 3.87109,-2.04687 0.32591,-0.17069 0.65104,-0.34183 0.98438,-0.51563 0.98003,-0.51099 2.03888,-1.05627 3.08203,-1.59375 1.50441,-0.77516 3.19823,-1.63034 4.83007,-2.45898 2.6812,-1.36148 5.48308,-2.77245 8.49219,-4.27149 1.45002,-0.72234 2.95192,-1.46789 4.47461,-2.2207 3.14575,-1.55527 6.43566,-3.16851 9.87696,-4.84766 1.7505,-0.85415 3.50304,-1.70917 5.32617,-2.59375 3.69907,-1.79476 7.57491,-3.665 11.55664,-5.57812 1.62203,-0.77935 3.19102,-1.53607 4.85742,-2.33399 4.85137,-2.32297 9.91021,-4.73306 15.11328,-7.20312 1.05862,-0.50256 2.06054,-0.98002 3.13281,-1.48828 6.27234,-2.97314 12.74159,-6.02841 19.44532,-9.18164 0.19493,-0.0917 0.37504,-0.1777 0.57031,-0.26954 0.88374,-0.4156 1.84183,-0.86083 2.73242,-1.27929 8.89106,-4.17765 18.33343,-8.58591 27.83008,-13.01563 9.48674,-4.42512 19.20352,-8.94432 29.15625,-13.5625 5.63004,-2.6124 11.17539,-5.18811 16.91992,-7.84765 11.03955,-5.11098 22.24511,-10.28776 33.57227,-15.51563 4.59686,-2.12162 9.06381,-4.18813 13.6875,-6.32031 31.79772,-14.66333 64.04275,-29.4992 94.89648,-43.72656 0.64347,-0.29672 1.23671,-0.57103 1.87891,-0.86719 -0.0661,-2.523 -0.5325,-5.27289 -1.4043,-8.3125 -2.95973,-10.3194 -36.14133,-35.93502 -56.06055,-50.55859 C 663.08118,438.83704 654.18972,428.94451 642,428.57812 c -0.42664,-0.0128 -0.85775,-0.0147 -1.29297,-0.004 z"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:1.42566061px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
<rect
transform="matrix(0.89707316,-0.44188205,0.39545007,0.91848747,0,0)"
ry="4.5092516"
rx="4.7671914"
y="299.94894"
x="-63.730179"
height="22.140448"
width="42.955582"
id="rect5118"
style="fill:#000000;fill-opacity:1;stroke:#ffffff;stroke-width:1.4265933;stroke-opacity:1" />
<path
inkscape:connector-curvature="0"
id="path5120"
d="m 275.08906,417.33778 4.375,22.875 80.75,-60.625 z"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:1.42566061px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
<path
sodipodi:nodetypes="cssc"
inkscape:connector-curvature="0"
id="path5122"
d="m 281.58906,443.33778 91.75,-68.625 c 10.87423,-8.13345 34.03844,-10.26653 -9.25,21.375 -37.38734,27.32814 -82.5,47.25 -82.5,47.25 z"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:1.42566061px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
<path
sodipodi:nodetypes="ccccc"
inkscape:connector-curvature="0"
id="path5124"
d="m 197.58906,448.96278 c 6.125,13 10.625,29.125 10.625,29.125 0,0 57.34269,-25.16319 68.25,-30.75 -0.13843,-9.48681 -3.52264,-22.72856 -8.375,-27.875 -27.125,3.75 -70.5,29.5 -70.5,29.5 z"
style="fill:url(#linearGradient3078);fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.42566073;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" />
<path
sodipodi:nodetypes="ccsccczc"
inkscape:connector-curvature="0"
id="path5138"
d="m 3.47828,341.26173 c 0,0 6.886406,9.46214 7.95495,30.22881 -9.7125082,0.38797 -22.45064,-1.59098 -48.96714,10.78339 -26.5165,12.37437 -35.70889,37.29989 -35.70889,37.29989 l -6.84404,-0.46967 -8.1731,-22.75242 c 0,0 5.196794,-22.7334 30.485095,-40.41753 C -32.486544,338.25007 3.47828,341.26173 3.47828,341.26173 z"
style="fill:#797979;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.42566061px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
<path
inkscape:connector-curvature="0"
id="path5140"
transform="translate(-522.78594,-97.359255)"
d="m 527.89648,441.94336 c -11.21543,-6.8e-4 -35.91089,1.15173 -54.02148,10.37891 -20.66776,10.53002 -34.76604,36.66892 -38.41016,44.00195 l 7.17383,19.9707 c 2.6388,-7.65898 11.92913,-28.82418 37.36133,-42.34765 27.46537,-14.60461 48.83613,-10.8705 53.86328,-9.67383 -1.11415,-11.22385 -3.86953,-18.48609 -5.74414,-22.32617 -0.0929,-1.7e-4 -0.12786,-0.004 -0.22266,-0.004 z"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none" />
<path
sodipodi:nodetypes="sccs"
inkscape:connector-curvature="0"
id="path5145"
transform="translate(-522.78594,-97.359255)"
d="m 485.25195,479.63281 c -26.5165,12.37437 -35.70886,37.34486 -35.70886,37.34486 9.75656,-6.29912 84.5483,-48.37571 84.5483,-48.37571 -6.04962,0.7682 -22.32294,-1.34352 -48.83944,11.03085 z"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none" />
<path
inkscape:connector-curvature="0"
id="path5151"
d="m -6.1035156,230.91992 c -19.3024674,3.60682 -35.0488854,16.31894 -52.6556354,24.21599 -51.094769,27.0536 -101.437299,55.94388 -149.051399,88.65901 -9.95415,5.51243 -22.54214,11.99271 -33.83984,6.61914 -6.38959,-3.90926 -7.96324,-11.94005 -8.66992,-18.82617 -15.28799,12.40039 -32.51253,23.07504 -46.6875,36.30469 11.43671,32.54466 37.53518,57.07166 61.90234,80.5625 1.79409,1.58773 4.14015,-3.28155 6.15485,-2.80815 C -144.1825,402.09598 -56.798635,363.92186 29.448769,323.50255 46.66114,315.61589 63.86767,307.71041 80.912109,299.46484 75.326356,287.31278 62.865961,280.7519 53.502952,271.87742 35.5688,257.98999 18.22755,242.94827 -1.484375,231.63672 c -1.4916064,-0.46547 -3.0527704,-0.75113 -4.6191406,-0.7168 z"
style="fill:#868686;fill-opacity:1;fill-rule:evenodd;stroke:none;display:inline"
transform="translate(124.57988,108.29077)" />
<path
inkscape:connector-curvature="0"
id="path5162"
d="m -28.414062,137.02148 c -76.907488,29.50803 -148.819988,71.80459 -213.308758,122.89206 -13.55128,17.43946 -23.11685,37.54603 -33.88323,56.82187 -3.7754,7.32186 -7.34192,14.58222 -10.84707,22.04584 11.21464,-8.37958 22.86793,-16.47415 33.20898,-25.8125 -0.25698,-17.631 11.68533,-33.06792 26.42383,-41.59375 31.52229,-22.08766 66.11652,-39.23093 99.04413,-59.05073 30.395219,-17.37588 61.961588,-32.92482 91.295711,-52.0313 6.692064,-6.28955 7.910236,-15.49613 9.814453,-23.93359 l -0.935164,0.35421 -0.812882,0.30789 z"
style="fill:#868686;fill-opacity:1;fill-rule:evenodd;stroke:none;display:inline"
transform="translate(124.57988,108.29077)" />
<path
inkscape:connector-curvature="0"
id="path5173"
d="m 152.77364,310.2307 c 1.1582,6.05599 2.3164,12.11198 3.4746,18.16797 21.37631,-16.04948 42.75261,-32.09896 64.12891,-48.14843 -22.5345,9.99349 -45.06901,19.98697 -67.60351,29.98046 z"
style="fill:#868686;fill-opacity:1;fill-rule:evenodd;stroke:none;display:inline"
transform="translate(124.57988,108.29077)" />
<path
inkscape:connector-curvature="0"
id="path5187"
d="m 261.2834,263.28539 c -12.21657,2.16029 -20.42211,12.86093 -30.56476,19.12846 -18.40968,13.8199 -38.36778,28.59535 -55.81414,41.82076 29.28272,-15.22709 58.48771,-31.62916 82.88671,-54.0625 1.70896,-1.96865 4.73868,-4.48833 4.69532,-6.85547 -0.39767,-0.0641 -0.80252,-0.0596 -1.20313,-0.0312 z"
style="fill:#868686;fill-opacity:1;fill-rule:evenodd;stroke:none;display:inline"
transform="translate(124.57988,108.29077)" />
<path
inkscape:connector-curvature="0"
id="path5192"
d="m 42.546875,449.04102 c 19.339052,15.73498 36.723013,34.10436 57.603515,47.67578 20.60808,9.36671 43.55773,2.08926 64.83959,-0.49809 35.57938,-6.15258 71.49952,-11.18454 106.39931,-20.59787 15.04923,-4.60526 29.72058,-14.93837 34.46618,-30.81811 9.43121,-25.52623 9.54274,-53.05503 12.87313,-79.81517 -0.62149,-4.24546 3.55982,-14.72991 -0.52003,-14.51534 -91.88723,32.85626 -183.77446,65.71253 -275.661695,98.5688 z"
style="fill:url(#linearGradient3080);fill-opacity:1;fill-rule:evenodd;stroke:none;display:inline"
transform="translate(124.57988,108.29077)" />
<path
inkscape:connector-curvature="0"
id="rect5212"
d="m -27.103516,182.32422 c -10.397754,4.71799 -21.409505,9.91406 -30.929687,15.4375 2.508683,3.97971 3.88786,8.5168 5.707031,12.72266 10.007293,-5.84796 21.032198,-9.89858 31.039063,-15.81641 -1.598593,-4.02995 -3.118058,-9.77197 -5.816407,-12.34375 z"
style="fill:#868686;fill-opacity:1;stroke:none;display:inline"
transform="translate(124.57988,108.29077)" />
</g>
</g>
<g
inkscape:groupmode="layer"
id="layer4"
inkscape:label="Leaders"
transform="translate(647.36582,205.64997)"
style="display:inline">
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m -345.36582,473.672 139,-91"
id="path5269"
inkscape:connector-curvature="0" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m -367.36582,346.672 192,-87"
id="path5271"
inkscape:connector-curvature="0" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m -336.36582,223.672 152,5"
id="path5273"
inkscape:connector-curvature="0" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 22.63418,39.672 -60,152"
id="path5275"
inkscape:connector-curvature="0" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 296.63418,105.672 -132,205"
id="path5277"
inkscape:connector-curvature="0" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 431.63418,222.672 -187,54"
id="path5279"
inkscape:connector-curvature="0" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 398.63418,512.672 -163,-63"
id="path5281"
inkscape:connector-curvature="0" />
</g>
<g
inkscape:groupmode="layer"
id="layer5"
inkscape:label="Controls"
transform="translate(647.36582,205.64997)"
transform="translate(647.36582,-57.672066)"
style="display:inline">
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:40.00000381px;line-height:125%;font-family:Sans;-inkscape-font-specification:'Sans, Normal';text-align:end;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:end;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="-352.13092"
y="486.22949"
style="font-size:40.00000381px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:end;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:end;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Sans;-inkscape-font-specification:'Sans, Normal'"
x="-502.6427"
y="633.16559"
id="text4473"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
id="tspan4475"
x="-352.13092"
y="486.22949">Button0</tspan></text>
x="-502.6427"
y="633.16559"
style="font-size:32px">Button0</tspan></text>
<text
sodipodi:linespacing="125%"
id="text4477"
y="225.95509"
x="-348.13092"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:40.00000381px;line-height:125%;font-family:Sans;-inkscape-font-specification:'Sans, Normal';text-align:end;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:end;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
y="337.89117"
x="-491.6427"
style="font-size:40.00000381px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:end;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:end;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Sans;-inkscape-font-specification:'Sans, Normal'"
xml:space="preserve"><tspan
y="225.95509"
x="-348.13092"
y="337.89117"
x="-491.6427"
id="tspan4479"
sodipodi:role="line">Button1</tspan></text>
sodipodi:role="line"
style="font-size:32px">Button1</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:40.00000381px;line-height:125%;font-family:Sans;-inkscape-font-specification:'Sans, Normal';text-align:end;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:end;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="-376.13092"
y="351.68076"
style="font-size:40.00000381px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:end;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:end;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Sans;-inkscape-font-specification:'Sans, Normal'"
x="-484.6427"
y="453.61685"
id="text4481"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
id="tspan4483"
x="-376.13092"
y="351.68076">Button2</tspan></text>
x="-484.6427"
y="453.61685"
style="font-size:32px">Button2</tspan></text>
<text
sodipodi:linespacing="125%"
id="text4485"
y="218.54855"
x="442.71985"
style="font-style:normal;font-weight:normal;font-size:40px;line-height:125%;font-family:Sans;letter-spacing:0px;word-spacing:0px;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
y="235.48463"
x="-59.791931"
style="font-size:40px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Sans"
xml:space="preserve"><tspan
y="218.54855"
x="442.71985"
y="235.48463"
x="-59.791931"
id="tspan4487"
sodipodi:role="line">Button3</tspan></text>
sodipodi:role="line"
style="font-size:32px">Button3</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:40px;line-height:125%;font-family:Sans;letter-spacing:0px;word-spacing:0px;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="296.71985"
y="96.274208"
style="font-size:40px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Sans"
x="-265.79193"
y="177.2103"
id="text4489"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
id="tspan4491"
x="296.71985"
y="96.274208">Button4</tspan></text>
x="-265.79193"
y="177.2103"
style="font-size:32px">Button4</tspan></text>
<text
sodipodi:linespacing="125%"
id="text4493"
y="524.99994"
x="402.71985"
style="font-style:normal;font-weight:normal;font-size:40px;line-height:125%;font-family:Sans;letter-spacing:0px;word-spacing:0px;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
y="713.93604"
x="-229.79195"
style="font-size:40px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Sans"
xml:space="preserve"><tspan
y="524.99994"
x="402.71985"
y="713.93604"
x="-229.79195"
id="tspan4495"
sodipodi:role="line">Button5</tspan></text>
sodipodi:role="line"
style="font-size:32px">Button5</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:40px;line-height:125%;font-family:Sans;letter-spacing:0px;word-spacing:0px;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="-29.28018"
y="29.72551"
style="font-size:40px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Sans"
x="-499.79196"
y="209.66159"
id="text4497"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
id="tspan4499"
x="-29.28018"
y="29.72551">Button6</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:40px;line-height:125%;font-family:Sans;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="-425.66364"
y="83.6576"
id="text4572"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
x="-425.66364"
y="83.6576"
id="tspan4576">Resolution0</tspan></text>
<rect
style="fill:none;fill-opacity:1;stroke:#000000;stroke-opacity:1"
id="rect4600"
width="323.85489"
height="120.2081"
x="-469.70047"
y="11.469827"
rx="10.321068"
ry="10.321068" />
</g>
<g
inkscape:groupmode="layer"
id="layer2"
inkscape:label="Title">
<text
transform="translate(647.36582,205.64997)"
xml:space="preserve"
style="display:inline;font-style:normal;font-weight:normal;font-size:40px;line-height:125%;font-family:Sans;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="-261.24213"
y="-97.912132"
id="text4223"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
id="tspan4225"
x="-261.24213"
y="-97.912132"
style="font-size:70.00000763px">Logitech MX Master</tspan></text>
x="-499.79196"
y="209.66159"
style="font-size:32px">Button6</tspan></text>
<path
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m -484.36582,336.67204 121,88"
id="path3082"
inkscape:connector-curvature="0" />
<path
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m -480.36582,448.67204 148,-7"
id="path3084"
inkscape:connector-curvature="0" />
<path
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m -492.36582,626.67204 130,-108"
id="path3086"
inkscape:connector-curvature="0" />
<path
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m -375.36582,214.67204 133,180"
id="path3088"
inkscape:connector-curvature="0" />
<path
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m -167.36582,192.67204 81,275"
id="path3092"
inkscape:connector-curvature="0" />
<path
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 34.63418,254.67204 -67,189"
id="path3094"
inkscape:connector-curvature="0" />
<path
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m -152.36582,675.67204 85,-87"
id="path3096"
inkscape:connector-curvature="0" />
</g>
</svg>

Before

Width:  |  Height:  |  Size: 23 KiB

After

Width:  |  Height:  |  Size: 21 KiB

View File

@@ -9,12 +9,12 @@
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="414.6424mm"
height="285.98199mm"
viewBox="0 0 1469.2054 1013.322"
width="750"
height="750"
viewBox="0 0 750.00004 749.99998"
id="svg2"
version="1.1"
inkscape:version="0.91 r13725"
inkscape:version="0.48.4 r9939"
sodipodi:docname="roccat-kone-xtd.svg">
<defs
id="defs4" />
@@ -26,10 +26,10 @@
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="1.3581868"
inkscape:cx="554.68333"
inkscape:cy="461.59649"
inkscape:cx="337.88759"
inkscape:cy="511.56243"
inkscape:document-units="px"
inkscape:current-layer="layer5"
inkscape:current-layer="layer4"
showgrid="false"
showguides="true"
inkscape:guide-bbox="true"
@@ -37,10 +37,10 @@
fit-margin-left="50"
fit-margin-right="50"
fit-margin-bottom="50"
inkscape:window-width="2560"
inkscape:window-height="1571"
inkscape:window-x="0"
inkscape:window-y="55"
inkscape:window-width="1920"
inkscape:window-height="1099"
inkscape:window-x="1920"
inkscape:window-y="28"
inkscape:window-maximized="1" />
<metadata
id="metadata7">
@@ -55,307 +55,173 @@
</rdf:RDF>
</metadata>
<g
inkscape:label="Mouse"
inkscape:label="Device"
inkscape:groupmode="layer"
id="layer1"
transform="translate(522.78594,97.359194)"
transform="translate(522.78594,-165.96284)"
style="display:inline">
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:20.31594276;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m -6.8766439,519.77381 c -32.5046101,10.85914 -64.2932331,9.07935 -55.9542041,-23.77308 18.883288,-74.39257 -57.845532,2.41084 -29.233145,-133.3763"
id="path4770"
inkscape:connector-curvature="0"
sodipodi:nodetypes="csc" />
<path
style="fill:#293843;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m -33.934887,422.04568 10.14038,-25.10953 C 52.122953,323.19727 160.74504,269.07207 269.83981,256.48052 c 114.24665,-13.18617 232.89306,-1.04277 284.3675,72.85307 67.68352,97.16539 16.07476,170.11753 -8.69176,195.56454 -20.05502,20.60604 -39.26023,38.76732 -57.46217,50.70193 -38.08063,24.96863 -99.02413,29.12078 -118.30443,27.5239 -56.28478,-4.66179 -227.65266,41.307 -235.6432,46.83891 L 32.219046,607.9527 C 4.8894737,559.61921 -21.751345,509.50644 -33.934887,422.04568 Z"
id="path3661"
inkscape:connector-curvature="0"
sodipodi:nodetypes="ccsssssccc" />
<path
inkscape:connector-curvature="0"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 520.63342,372.91486 c -22.02158,0.11026 -45.15654,9.22867 -63.99943,19.07328 -68.64532,35.8642 -269.2094,153.12888 -338.02986,180.28255 l -87.122352,34.37512 c 0.245863,0.43536 0.49112,0.87206 0.737105,1.30711 l 39.216027,16.16965 c 44.83999,-15.41316 98.86516,-40.41176 154.72423,-67.21674 90.48008,-43.41854 177.45369,-92.45774 236.96271,-121.89569 60.39622,-29.87684 105.87888,-24.18751 112.83284,44.85426 6.15884,-13.91293 10.75607,-30.17964 11.63778,-48.45529 -13.44827,-44.58801 -39.32739,-58.63259 -66.95905,-58.49425 z"
id="path4463" />
<path
style="fill:#00ff3a;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 460.17444,405.06363 c -25.33816,12.5814 -164.20311,89.16529 -247.36725,132.94909 -31.24494,16.55348 -62.91668,32.44366 -95.5461,46.08015 l 3.13236,9.65662 c 54.85379,-22.99389 108.07344,-49.78006 161.39646,-76.09146 64.31558,-32.64428 127.12882,-68.2385 192.32459,-99.13545 18.32983,-7.64259 38.30614,-12.8303 58.27155,-10.58417 14.47996,1.85097 28.06901,9.59531 37.24885,20.96153 6.66994,-53.74538 -76.10417,-40.33748 -109.46046,-23.83631 z"
id="path4468"
inkscape:connector-curvature="0"
sodipodi:nodetypes="ccccccccc" />
<path
style="fill:#202427;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 270.88842,559.80819 26.12051,4.09732 62.14289,-30.90074 c 11.97455,-20.17142 5.93562,-23.53024 5.29239,-31.92505 l -91.50713,47.4608 c -3.16993,2.58552 -6.42443,5.13123 -2.04866,11.26767 z"
id="path4545"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cccccc" />
<path
style="fill:#202427;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 392.10122,486.05615 c 1.23298,4.69552 4.04803,7.598 -1.19506,19.63307 l -9.73117,17.58438 80.75159,-31.4129 c 5.77716,-10.78358 11.4074,-21.61616 11.4384,-34.31516 -2.7867,-11.40006 -8.20083,-9.22506 -13.65779,-6.82888 z"
id="path4547"
inkscape:connector-curvature="0"
sodipodi:nodetypes="ccccccc" />
<path
style="fill:#202427;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="M 20.837165,461.33753 26.414193,480.9345 62.94875,466.25238 55.307676,431.63187 Z"
id="path4549"
inkscape:connector-curvature="0"
sodipodi:nodetypes="ccccc" />
<path
style="fill:#202427;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 178.69842,365.35554 12.29201,31.24217 56.50906,-25.09617 -12.46274,-27.48628 z"
id="path4551"
inkscape:connector-curvature="0" />
<path
style="fill:#202427;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 261.4987,335.64987 11.95056,26.63267 49.85089,-20.31594 12.80416,-3.41445 -6.82888,-14.16994 -12.97489,-3.41445 z"
id="path4553"
inkscape:connector-curvature="0" />
<path
style="font-style:normal;font-weight:normal;font-size:medium;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;writing-mode:tb-rl;fill:#838d96;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
inkscape:connector-curvature="0"
id="path4560"
d="m 204.43745,364.0435 2.09895,5.60714 5.81901,-2.56255 0.64062,1.71134 -5.81901,2.56254 2.09895,5.60714 -1.75511,0.77292 -2.09894,-5.60715 -5.81902,2.56255 -0.64059,-1.71135 5.81898,-2.56254 -2.09892,-5.60714 1.75508,-0.7729 z" />
<path
d="m 305.42303,329.94388 4.03768,8.95391 -2.72436,1.22853 -4.03769,-8.95391 2.72437,-1.22853 z"
id="path4567"
inkscape:connector-curvature="0"
style="font-style:normal;font-weight:normal;font-size:medium;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;fill:#838d96;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
<path
style="font-style:normal;font-weight:normal;font-size:medium;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;fill:#838d96;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
inkscape:connector-curvature="0"
id="path4569"
d="m 46.989112,448.7916 2.557622,11.39542 -2.682847,1.56354 -2.557622,-11.39545 2.682847,-1.56351 z" />
<path
d="m 42.643233,451.50777 2.557622,11.39545 -2.682847,1.56351 -2.557622,-11.39545 2.682847,-1.56351 z"
id="path4577"
inkscape:connector-curvature="0"
style="font-style:normal;font-weight:normal;font-size:medium;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;fill:#838d96;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
<path
style="font-style:normal;font-weight:normal;font-size:medium;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;fill:#838d96;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
inkscape:connector-curvature="0"
id="path4579"
d="m 38.478433,454.34466 2.557622,11.39543 -2.682847,1.56354 -2.557622,-11.39545 2.682847,-1.56352 z" />
<path
style="fill:#838d96;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 119.43841,465.4441 5.37199,3.74229 1.87114,-8.26926 z"
id="path4581"
inkscape:connector-curvature="0" />
<path
style="fill:#838d96;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 99.218,376.23286 -2.29366,6.51884 6.33774,-3.25942 z"
id="path4583"
inkscape:connector-curvature="0" />
<path
inkscape:connector-curvature="0"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 370.13999,299.12951 c -0.43414,-0.004 -0.88599,0.004 -1.35658,0.0243 -114.61991,18.29248 -262.7613,57.8235 -362.6396132,162.97056 l -0.2413441,18.34924 -23.0804397,18.75305 c 0.295394,0.96107 0.592605,1.91666 0.892085,2.8672 L 6.8682998,485.78508 11.938416,498.5815 c 3.022522,1.91455 4.542353,4.99753 13.03731,2.65575 0,0 35.049508,-13.87527 66.878294,-31.62836 25.86269,-14.4254 169.13513,-92.29377 297.45122,-135.68783 3.53168,-1.85807 6.92052,-3.82383 2.89753,-11.3479 l -11.34789,-17.38339 c -1.68431,-3.27833 -4.20267,-6.0005 -10.71489,-6.06024 z m 0.85055,7.18994 c 0.76127,-0.0183 1.49621,0.14715 2.1413,0.68389 2.28062,2.60105 3.95393,5.73706 5.90572,8.6044 2.36789,3.85426 5.13602,7.51375 7.31692,11.43239 -2.00889,0.76437 -4.02217,1.5172 -6.0383,2.2622 -74.38121,26.47497 -146.51346,58.91354 -216.93155,94.53357 -23.7859,11.80119 -47.13201,24.45131 -70.49007,37.07193 -21.87976,12.03816 -44.368571,22.99172 -67.494965,32.39674 -2.178032,0.79387 -4.91012,2.49014 -7.139522,0.97798 -2.462342,-3.62775 -3.065109,-8.18739 -5.10326,-12.05744 -0.191754,-5.72806 0.125694,-11.45575 0.125574,-17.18406 19.24401,-19.99827 40.662677,-37.85032 63.501803,-53.60899 56.88977,-39.14613 121.81546,-65.28367 188.25625,-83.14833 34.45174,-9.02055 69.30996,-16.66573 104.56505,-21.77335 0.46215,-0.10291 0.9283,-0.17995 1.38505,-0.19093 z"
id="path4585" />
<path
style="fill:#202427;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 69.56866,436.43193 c 2.34022,-18.39325 11.0874,-31.41629 35.56456,-46.25604 24.47717,-14.83973 51.02774,-12.17822 62.53237,-11.10613 4.19739,0.39116 6.14741,2.1271 9.65751,8.20888 l 9.65751,18.10785 c -9.72905,-3.24303 -45.31306,0.55135 -63.36379,8.82104 -23.93977,10.96767 -32.63451,13.417 -49.78556,44.90031 z"
id="path4590"
inkscape:connector-curvature="0"
sodipodi:nodetypes="czsccscc" />
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:19.26995659px;line-height:125%;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;fill:#838d96;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="541.47949"
y="544.12469"
id="text4751"
sodipodi:linespacing="125%"
transform="matrix(0.81792144,-0.30782972,0,1.2226113,0,0)"><tspan
sodipodi:role="line"
id="tspan4753"
<g
id="g3136"
transform="matrix(0.68876596,0,0,0.68876596,-231.95789,223.11559)">
<path
sodipodi:nodetypes="csc"
inkscape:connector-curvature="0"
id="path4770"
d="m -6.8766439,519.77381 c -32.5046101,10.85914 -64.2932331,9.07935 -55.9542041,-23.77308 18.883288,-74.39257 -57.845532,2.41084 -29.233145,-133.3763"
style="fill:none;stroke:#000000;stroke-width:29.49614906;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" />
<path
sodipodi:nodetypes="ccsssssccc"
inkscape:connector-curvature="0"
id="path3661"
d="m -33.934887,422.04568 10.14038,-25.10953 C 52.122953,323.19727 160.74504,269.07207 269.83981,256.48052 c 114.24665,-13.18617 232.89306,-1.04277 284.3675,72.85307 67.68352,97.16539 16.07476,170.11753 -8.69176,195.56454 -20.05502,20.60604 -39.26023,38.76732 -57.46217,50.70193 -38.08063,24.96863 -99.02413,29.12078 -118.30443,27.5239 -56.28478,-4.66179 -227.65266,41.307 -235.6432,46.83891 L 32.219046,607.9527 C 4.8894737,559.61921 -21.751345,509.50644 -33.934887,422.04568 z"
style="fill:#293843;fill-opacity:1;fill-rule:evenodd;stroke:none" />
<path
id="path4463"
d="m 520.63342,372.91486 c -22.02158,0.11026 -45.15654,9.22867 -63.99943,19.07328 -68.64532,35.8642 -269.2094,153.12888 -338.02986,180.28255 l -87.122352,34.37512 c 0.245863,0.43536 0.49112,0.87206 0.737105,1.30711 l 39.216027,16.16965 c 44.83999,-15.41316 98.86516,-40.41176 154.72423,-67.21674 90.48008,-43.41854 177.45369,-92.45774 236.96271,-121.89569 60.39622,-29.87684 105.87888,-24.18751 112.83284,44.85426 6.15884,-13.91293 10.75607,-30.17964 11.63778,-48.45529 -13.44827,-44.58801 -39.32739,-58.63259 -66.95905,-58.49425 z"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none"
inkscape:connector-curvature="0" />
<path
sodipodi:nodetypes="ccccccccc"
inkscape:connector-curvature="0"
id="path4468"
d="m 460.17444,405.06363 c -25.33816,12.5814 -164.20311,89.16529 -247.36725,132.94909 -31.24494,16.55348 -62.91668,32.44366 -95.5461,46.08015 l 3.13236,9.65662 c 54.85379,-22.99389 108.07344,-49.78006 161.39646,-76.09146 64.31558,-32.64428 127.12882,-68.2385 192.32459,-99.13545 18.32983,-7.64259 38.30614,-12.8303 58.27155,-10.58417 14.47996,1.85097 28.06901,9.59531 37.24885,20.96153 6.66994,-53.74538 -76.10417,-40.33748 -109.46046,-23.83631 z"
style="fill:#00ff3a;fill-opacity:1;fill-rule:evenodd;stroke:none" />
<path
sodipodi:nodetypes="cccccc"
inkscape:connector-curvature="0"
id="path4545"
d="m 270.88842,559.80819 26.12051,4.09732 62.14289,-30.90074 c 11.97455,-20.17142 5.93562,-23.53024 5.29239,-31.92505 l -91.50713,47.4608 c -3.16993,2.58552 -6.42443,5.13123 -2.04866,11.26767 z"
style="fill:#202427;fill-opacity:1;fill-rule:evenodd;stroke:none" />
<path
sodipodi:nodetypes="ccccccc"
inkscape:connector-curvature="0"
id="path4547"
d="m 392.10122,486.05615 c 1.23298,4.69552 4.04803,7.598 -1.19506,19.63307 l -9.73117,17.58438 80.75159,-31.4129 c 5.77716,-10.78358 11.4074,-21.61616 11.4384,-34.31516 -2.7867,-11.40006 -8.20083,-9.22506 -13.65779,-6.82888 z"
style="fill:#202427;fill-opacity:1;fill-rule:evenodd;stroke:none" />
<path
sodipodi:nodetypes="ccccc"
inkscape:connector-curvature="0"
id="path4549"
d="M 20.837165,461.33753 26.414193,480.9345 62.94875,466.25238 55.307676,431.63187 z"
style="fill:#202427;fill-opacity:1;fill-rule:evenodd;stroke:none" />
<path
inkscape:connector-curvature="0"
id="path4551"
d="m 178.69842,365.35554 12.29201,31.24217 56.50906,-25.09617 -12.46274,-27.48628 z"
style="fill:#202427;fill-opacity:1;fill-rule:evenodd;stroke:none" />
<path
inkscape:connector-curvature="0"
id="path4553"
d="m 261.4987,335.64987 11.95056,26.63267 49.85089,-20.31594 12.80416,-3.41445 -6.82888,-14.16994 -12.97489,-3.41445 z"
style="fill:#202427;fill-opacity:1;fill-rule:evenodd;stroke:none" />
<path
d="m 204.43745,364.0435 2.09895,5.60714 5.81901,-2.56255 0.64062,1.71134 -5.81901,2.56254 2.09895,5.60714 -1.75511,0.77292 -2.09894,-5.60715 -5.81902,2.56255 -0.64059,-1.71135 5.81898,-2.56254 -2.09892,-5.60714 1.75508,-0.7729 z"
id="path4560"
inkscape:connector-curvature="0"
style="font-size:medium;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:tb-rl;fill:#838d96;fill-opacity:1;stroke:none;font-family:sans-serif" />
<path
style="font-size:medium;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;fill:#838d96;fill-opacity:1;stroke:none;font-family:sans-serif"
inkscape:connector-curvature="0"
id="path4567"
d="m 305.42303,329.94388 4.03768,8.95391 -2.72436,1.22853 -4.03769,-8.95391 2.72437,-1.22853 z" />
<path
d="m 46.989112,448.7916 2.557622,11.39542 -2.682847,1.56354 -2.557622,-11.39545 2.682847,-1.56351 z"
id="path4569"
inkscape:connector-curvature="0"
style="font-size:medium;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;fill:#838d96;fill-opacity:1;stroke:none;font-family:sans-serif" />
<path
style="font-size:medium;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;fill:#838d96;fill-opacity:1;stroke:none;font-family:sans-serif"
inkscape:connector-curvature="0"
id="path4577"
d="m 42.643233,451.50777 2.557622,11.39545 -2.682847,1.56351 -2.557622,-11.39545 2.682847,-1.56351 z" />
<path
d="m 38.478433,454.34466 2.557622,11.39543 -2.682847,1.56354 -2.557622,-11.39545 2.682847,-1.56352 z"
id="path4579"
inkscape:connector-curvature="0"
style="font-size:medium;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;fill:#838d96;fill-opacity:1;stroke:none;font-family:sans-serif" />
<path
inkscape:connector-curvature="0"
id="path4581"
d="m 119.43841,465.4441 5.37199,3.74229 1.87114,-8.26926 z"
style="fill:#838d96;fill-opacity:1;fill-rule:evenodd;stroke:none" />
<path
inkscape:connector-curvature="0"
id="path4583"
d="m 99.218,376.23286 -2.29366,6.51884 6.33774,-3.25942 z"
style="fill:#838d96;fill-opacity:1;fill-rule:evenodd;stroke:none" />
<path
id="path4585"
d="m 370.13999,299.12951 c -0.43414,-0.004 -0.88599,0.004 -1.35658,0.0243 -114.61991,18.29248 -262.7613,57.8235 -362.6396132,162.97056 l -0.2413441,18.34924 -23.0804397,18.75305 c 0.295394,0.96107 0.592605,1.91666 0.892085,2.8672 L 6.8682998,485.78508 11.938416,498.5815 c 3.022522,1.91455 4.542353,4.99753 13.03731,2.65575 0,0 35.049508,-13.87527 66.878294,-31.62836 25.86269,-14.4254 169.13513,-92.29377 297.45122,-135.68783 3.53168,-1.85807 6.92052,-3.82383 2.89753,-11.3479 l -11.34789,-17.38339 c -1.68431,-3.27833 -4.20267,-6.0005 -10.71489,-6.06024 z m 0.85055,7.18994 c 0.76127,-0.0183 1.49621,0.14715 2.1413,0.68389 2.28062,2.60105 3.95393,5.73706 5.90572,8.6044 2.36789,3.85426 5.13602,7.51375 7.31692,11.43239 -2.00889,0.76437 -4.02217,1.5172 -6.0383,2.2622 -74.38121,26.47497 -146.51346,58.91354 -216.93155,94.53357 -23.7859,11.80119 -47.13201,24.45131 -70.49007,37.07193 -21.87976,12.03816 -44.368571,22.99172 -67.494965,32.39674 -2.178032,0.79387 -4.91012,2.49014 -7.139522,0.97798 -2.462342,-3.62775 -3.065109,-8.18739 -5.10326,-12.05744 -0.191754,-5.72806 0.125694,-11.45575 0.125574,-17.18406 19.24401,-19.99827 40.662677,-37.85032 63.501803,-53.60899 56.88977,-39.14613 121.81546,-65.28367 188.25625,-83.14833 34.45174,-9.02055 69.30996,-16.66573 104.56505,-21.77335 0.46215,-0.10291 0.9283,-0.17995 1.38505,-0.19093 z"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none"
inkscape:connector-curvature="0" />
<path
sodipodi:nodetypes="czsccscc"
inkscape:connector-curvature="0"
id="path4590"
d="m 69.56866,436.43193 c 2.34022,-18.39325 11.0874,-31.41629 35.56456,-46.25604 24.47717,-14.83973 51.02774,-12.17822 62.53237,-11.10613 4.19739,0.39116 6.14741,2.1271 9.65751,8.20888 l 9.65751,18.10785 c -9.72905,-3.24303 -45.31306,0.55135 -63.36379,8.82104 -23.93977,10.96767 -32.63451,13.417 -49.78556,44.90031 z"
style="fill:#202427;fill-opacity:1;fill-rule:evenodd;stroke:none" />
<text
transform="matrix(0.81792144,-0.30782972,0,1.2226113,0,0)"
sodipodi:linespacing="125%"
id="text4751"
y="544.12469"
x="541.47949"
y="544.12469">&gt;</tspan></text>
<path
style="fill:#838d96;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 300.25264,556.5858 10.24335,-10.8622 0.29876,2.6035 -4.75887,5.05767 6.35939,-0.96032 0.72556,2.19804 z"
id="path4759"
inkscape:connector-curvature="0" />
<path
inkscape:connector-curvature="0"
style="fill:#151d23;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 175.51398,404.23374 c -14.95857,0.0867 -38.3591,3.7713 -51.89715,9.97357 -23.8618,10.93194 -32.57995,13.40905 -49.62048,44.60172 l 112.98222,-53.41898 -0.0122,-0.008 c -2.4337,-0.80767 -6.47543,-1.17722 -11.45245,-1.14838 z"
id="path4761" />
</g>
<g
inkscape:groupmode="layer"
id="layer3"
inkscape:label="Actions"
style="display:inline"
transform="translate(647.36582,205.64997)">
<ellipse
style="display:inline;fill:#898989;fill-opacity:1;stroke:none;stroke-opacity:1"
id="path4352"
cx="-12.758862"
cy="294.12094"
rx="11.98534"
ry="11.985341" />
style="font-size:19.26995659px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;fill:#838d96;fill-opacity:1;stroke:none;font-family:sans-serif;-inkscape-font-specification:sans-serif Bold"
xml:space="preserve"><tspan
y="544.12469"
x="541.47949"
id="tspan4753"
sodipodi:role="line">&gt;</tspan></text>
<path
inkscape:connector-curvature="0"
id="path4759"
d="m 300.25264,556.5858 10.24335,-10.8622 0.29876,2.6035 -4.75887,5.05767 6.35939,-0.96032 0.72556,2.19804 z"
style="fill:#838d96;fill-opacity:1;fill-rule:evenodd;stroke:none" />
<path
id="path4761"
d="m 175.51398,404.23374 c -14.95857,0.0867 -38.3591,3.7713 -51.89715,9.97357 -23.8618,10.93194 -32.57995,13.40905 -49.62048,44.60172 l 112.98222,-53.41898 -0.0122,-0.008 c -2.4337,-0.80767 -6.47543,-1.17722 -11.45245,-1.14838 z"
style="fill:#151d23;fill-opacity:1;fill-rule:evenodd;stroke:none"
inkscape:connector-curvature="0" />
<ellipse
sodipodi:ry="11.985341"
sodipodi:rx="11.98534"
sodipodi:cy="294.12094"
sodipodi:cx="-12.758862"
d="m -0.77352142,294.12094 c 0,6.61932 -5.36601958,11.98534 -11.98534058,11.98534 -6.61932,0 -11.98534,-5.36602 -11.98534,-11.98534 0,-6.61932 5.36602,-11.98534 11.98534,-11.98534 6.619321,0 11.98534058,5.36602 11.98534058,11.98534 z"
ry="11.985341"
rx="11.98534"
cy="294.12094"
cx="-12.758862"
id="path4352"
style="fill:#898989;fill-opacity:1;stroke:none;display:inline"
transform="translate(124.57988,108.29077)" />
</g>
</g>
<g
inkscape:groupmode="layer"
id="layer4"
inkscape:label="Leaders"
transform="translate(647.36582,205.64997)"
style="display:inline">
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="M -216.45721,492.54598 -83.92758,424.07234"
id="path4368"
inkscape:connector-curvature="0" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="M -148.71984,592.67948 0.00785948,357.80752"
id="path4370"
inkscape:connector-curvature="0" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="M -231.919,376.21442 -92.76289,355.5987"
id="path4372"
inkscape:connector-curvature="0" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m -237.07293,234.84948 113.38646,72.89129"
id="path4374"
inkscape:connector-curvature="0" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="M -177.52663,109.77463 -12.600865,294.57984"
id="path4376"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m -30.915721,22.80206 6.62648,247.38865"
id="path4378"
inkscape:connector-curvature="0" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="M 107.50411,-32.41862 96.45998,252.52009"
id="path4380"
inkscape:connector-curvature="0" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="M 258.44064,52.98937 162.7248,230.43182"
id="path4382"
inkscape:connector-curvature="0" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="M 130.32866,662.62568 199.53858,430.69882"
id="path4384"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="M 192.9121,662.62567 295.9907,385.786"
id="path4386"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
</g>
<g
inkscape:groupmode="layer"
id="layer5"
inkscape:label="Controls"
transform="translate(647.36582,205.64997)"
transform="translate(647.36582,-57.672066)"
style="display:inline">
<g
id="g4200"
transform="translate(1110.0988,277.2489)">
<text
sodipodi:linespacing="125%"
id="text4572"
y="-44.454391"
x="-571.44623"
style="font-style:normal;font-weight:normal;font-size:40px;line-height:125%;font-family:Sans;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
xml:space="preserve"><tspan
id="tspan4576"
y="-44.454391"
x="-571.44623"
sodipodi:role="line">Resolution0</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:40px;line-height:125%;font-family:Sans;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="-571.44623"
y="28.518997"
id="text4580"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
x="-571.44623"
y="28.518997"
id="tspan4582">Resolution1</tspan></text>
<text
sodipodi:linespacing="125%"
id="text4584"
y="101.49239"
x="-571.44623"
style="font-style:normal;font-weight:normal;font-size:40px;line-height:125%;font-family:Sans;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
xml:space="preserve"><tspan
id="tspan4586"
y="101.49239"
x="-571.44623"
sodipodi:role="line">Resolution2</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:40px;line-height:125%;font-family:Sans;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="-571.44623"
y="174.46584"
id="text4588"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
x="-571.44623"
y="174.46584"
id="tspan4590">Resolution3</tspan></text>
<text
sodipodi:linespacing="125%"
id="text4592"
y="247.43925"
x="-571.44623"
style="font-style:normal;font-weight:normal;font-size:40px;line-height:125%;font-family:Sans;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
xml:space="preserve"><tspan
id="tspan4594"
y="247.43925"
x="-571.44623"
sodipodi:role="line">Resolution4</tspan></text>
</g>
<rect
style="fill:none;fill-opacity:1;stroke:#000000;stroke-opacity:1"
id="rect4600"
width="323.85489"
height="410.20847"
x="494.82077"
y="158.72498"
rx="10.321068"
ry="10.321068" />
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:40px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="-629.95673"
y="789.13135"
id="text4211"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
id="tspan4213"
x="-629.95673"
y="789.13135">Current Profile</tspan></text>
<g
style="display:inline"
id="g4230"
transform="translate(-73.440271,-63.319721)">
transform="translate(-312.22243,78.703789)">
<text
sodipodi:linespacing="125%"
id="text4473"
y="547.70569"
x="-157.20392"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:40.00000381px;line-height:125%;font-family:Sans;-inkscape-font-specification:'Sans, Normal';text-align:end;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:end;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
style="font-size:40.00000381px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:end;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:end;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Sans;-inkscape-font-specification:'Sans, Normal'"
xml:space="preserve"><tspan
id="tspan4217"
y="547.70569"
x="-157.20392"
sodipodi:role="line">Button0</tspan></text>
sodipodi:role="line"
style="font-size:32px">Button0</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:40.00000381px;line-height:125%;font-family:Sans;-inkscape-font-specification:'Sans, Normal';text-align:end;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:end;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
style="font-size:40.00000381px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:end;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:end;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Sans;-inkscape-font-specification:'Sans, Normal'"
x="-157.20392"
y="591.14594"
id="text4212"
@@ -363,14 +229,16 @@
sodipodi:role="line"
x="-157.20392"
y="591.14594"
id="tspan4214">Button12</tspan></text>
id="tspan4214"
style="font-size:32px">Button12</tspan></text>
</g>
<g
style="display:inline"
id="g4224"
transform="translate(112.10123,30.187304)">
transform="translate(-177.72019,47.152301)">
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:40.00000381px;line-height:125%;font-family:Sans;-inkscape-font-specification:'Sans, Normal';text-align:end;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:end;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
style="font-size:40.00000381px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:end;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:end;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Sans;-inkscape-font-specification:'Sans, Normal'"
x="6.9855804"
y="647.10291"
id="text4216"
@@ -378,51 +246,69 @@
sodipodi:role="line"
x="6.9855804"
y="647.10291"
id="tspan4218">Button3</tspan></text>
id="tspan4218"
style="font-size:32px">Button3</tspan></text>
<text
sodipodi:linespacing="125%"
id="text4220"
y="690.54315"
x="6.9855804"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:40.00000381px;line-height:125%;font-family:Sans;-inkscape-font-specification:'Sans, Normal';text-align:end;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:end;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
style="font-size:40.00000381px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:end;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:end;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Sans;-inkscape-font-specification:'Sans, Normal'"
xml:space="preserve"><tspan
id="tspan4222"
y="690.54315"
x="6.9855781"
sodipodi:role="line">Button15</tspan></text>
x="6.9855804"
sodipodi:role="line"
style="font-size:32px">Button15</tspan></text>
</g>
<g
style="display:inline"
id="g4250"
transform="translate(14.912823,34.604968)">
transform="translate(-353.6901,52.306237)">
<text
sodipodi:linespacing="125%"
id="text4238"
y="642.68524"
x="195.12758"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:40.00000381px;line-height:125%;font-family:Sans;-inkscape-font-specification:'Sans, Normal';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
y="645.63037"
x="270.96399"
style="font-size:40.00000381px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Sans;-inkscape-font-specification:'Sans, Normal'"
xml:space="preserve"><tspan
id="tspan4240"
y="642.68524"
x="195.12758"
sodipodi:role="line">Button4</tspan></text>
y="645.63037"
x="270.96399"
sodipodi:role="line"
style="font-size:32px">Button4</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:40.00000381px;line-height:125%;font-family:Sans;-inkscape-font-specification:'Sans, Normal';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="195.12758"
y="686.12549"
style="font-size:40.00000381px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Sans;-inkscape-font-specification:'Sans, Normal'"
x="270.96399"
y="689.07062"
id="text4242"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
x="195.12758"
y="686.12549"
id="tspan4244">Button16</tspan></text>
x="270.96399"
y="689.07062"
id="tspan4244"
style="font-size:32px">Button16</tspan></text>
<path
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 426.30366,602.00857 72.8913,-163.45321"
id="path3163"
inkscape:connector-curvature="0"
transform="translate(-293.67572,5.365799)" />
<path
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="M 629.51576,602.74485 586.81177,393.64254"
id="path3165"
inkscape:connector-curvature="0"
transform="translate(-293.67572,5.365799)" />
</g>
<g
style="display:inline"
id="g4256"
transform="translate(86.33157,-599.32852)">
transform="translate(-311.42639,-501.45091)">
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:40.00000381px;line-height:125%;font-family:Sans;-inkscape-font-specification:'Sans, Normal';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
style="font-size:40.00000381px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Sans;-inkscape-font-specification:'Sans, Normal'"
x="195.12758"
y="642.68524"
id="text4258"
@@ -430,36 +316,40 @@
sodipodi:role="line"
x="195.12758"
y="642.68524"
id="tspan4260">Button10</tspan></text>
id="tspan4260"
style="font-size:32.00000171px">Button10</tspan></text>
<text
sodipodi:linespacing="125%"
id="text4262"
y="686.12549"
x="195.12758"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:40.00000381px;line-height:125%;font-family:Sans;-inkscape-font-specification:'Sans, Normal';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
style="font-size:40.00000381px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Sans;-inkscape-font-specification:'Sans, Normal'"
xml:space="preserve"><tspan
id="tspan4264"
y="686.12549"
x="195.12758"
sodipodi:role="line">Button22</tspan></text>
sodipodi:role="line"
style="font-size:32.00000171px">Button22</tspan></text>
</g>
<g
transform="translate(-76.385377,-689.15417)"
style="display:inline"
transform="translate(-539.74217,-541.2965)"
id="g4266">
<text
sodipodi:linespacing="125%"
id="text4268"
y="642.68524"
x="195.12758"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:40.00000381px;line-height:125%;font-family:Sans;-inkscape-font-specification:'Sans, Normal';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
style="font-size:40.00000381px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Sans;-inkscape-font-specification:'Sans, Normal'"
xml:space="preserve"><tspan
id="tspan4270"
y="642.68524"
x="195.12758"
sodipodi:role="line">Button9</tspan></text>
sodipodi:role="line"
style="font-size:32px">Button9</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:40.00000381px;line-height:125%;font-family:Sans;-inkscape-font-specification:'Sans, Normal';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
style="font-size:40.00000381px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Sans;-inkscape-font-specification:'Sans, Normal'"
x="195.12758"
y="686.12549"
id="text4272"
@@ -467,14 +357,16 @@
sodipodi:role="line"
x="195.12758"
y="686.12549"
id="tspan4274">Button21</tspan></text>
id="tspan4274"
style="font-size:32px">Button21</tspan></text>
</g>
<g
transform="translate(0.18730648,35.341239)"
style="display:inline"
transform="translate(-209.20512,184.48383)"
id="g4276">
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:40.00000381px;line-height:125%;font-family:Sans;-inkscape-font-specification:'Sans, Normal';text-align:end;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:end;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
style="font-size:40.00000381px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:end;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:end;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Sans;-inkscape-font-specification:'Sans, Normal'"
x="-157.20392"
y="547.70569"
id="text4278"
@@ -482,36 +374,40 @@
sodipodi:role="line"
x="-157.20392"
y="547.70569"
id="tspan4280">Button5</tspan></text>
id="tspan4280"
style="font-size:32px">Button5</tspan></text>
<text
sodipodi:linespacing="125%"
id="text4282"
y="591.14594"
x="-157.20392"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:40.00000381px;line-height:125%;font-family:Sans;-inkscape-font-specification:'Sans, Normal';text-align:end;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:end;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
style="font-size:40.00000381px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:end;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:end;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Sans;-inkscape-font-specification:'Sans, Normal'"
xml:space="preserve"><tspan
id="tspan4284"
y="591.14594"
x="-157.20392"
sodipodi:role="line">Button17</tspan></text>
sodipodi:role="line"
style="font-size:32px">Button17</tspan></text>
</g>
<g
style="display:inline"
id="g4286"
transform="translate(-73.440271,-166.39834)">
transform="translate(-330.93429,-54.814789)">
<text
sodipodi:linespacing="125%"
id="text4288"
y="547.70569"
x="-157.20392"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:40.00000381px;line-height:125%;font-family:Sans;-inkscape-font-specification:'Sans, Normal';text-align:end;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:end;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
style="font-size:40.00000381px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:end;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:end;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Sans;-inkscape-font-specification:'Sans, Normal'"
xml:space="preserve"><tspan
id="tspan4290"
y="547.70569"
x="-157.20392"
sodipodi:role="line">Button11</tspan></text>
sodipodi:role="line"
style="font-size:32px">Button11</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:40.00000381px;line-height:125%;font-family:Sans;-inkscape-font-specification:'Sans, Normal';text-align:end;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:end;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
style="font-size:40.00000381px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:end;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:end;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Sans;-inkscape-font-specification:'Sans, Normal'"
x="-157.20392"
y="591.14594"
id="text4292"
@@ -519,14 +415,16 @@
sodipodi:role="line"
x="-157.20392"
y="591.14594"
id="tspan4294">Button23</tspan></text>
id="tspan4294"
style="font-size:32px">Button23</tspan></text>
</g>
<g
transform="translate(-86.693235,-300.40054)"
style="display:inline"
transform="translate(-333.46977,-188.98667)"
id="g4338">
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:40.00000381px;line-height:125%;font-family:Sans;-inkscape-font-specification:'Sans, Normal';text-align:end;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:end;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
style="font-size:40.00000381px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:end;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:end;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Sans;-inkscape-font-specification:'Sans, Normal'"
x="-157.20392"
y="547.70569"
id="text4340"
@@ -534,36 +432,40 @@
sodipodi:role="line"
x="-157.20392"
y="547.70569"
id="tspan4342">Button1</tspan></text>
id="tspan4342"
style="font-size:32px">Button1</tspan></text>
<text
sodipodi:linespacing="125%"
id="text4344"
y="591.14594"
x="-157.20392"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:40.00000381px;line-height:125%;font-family:Sans;-inkscape-font-specification:'Sans, Normal';text-align:end;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:end;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
style="font-size:40.00000381px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:end;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:end;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Sans;-inkscape-font-specification:'Sans, Normal'"
xml:space="preserve"><tspan
id="tspan4346"
y="591.14594"
x="-157.20392"
sodipodi:role="line">Button13</tspan></text>
sodipodi:role="line"
style="font-size:32px">Button13</tspan></text>
</g>
<g
style="display:inline"
id="g4348"
transform="translate(-31.472552,-438.82039)">
transform="translate(-264.96175,-314.68951)">
<text
sodipodi:linespacing="125%"
id="text4350"
y="547.70569"
x="-157.20392"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:40.00000381px;line-height:125%;font-family:Sans;-inkscape-font-specification:'Sans, Normal';text-align:end;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:end;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
style="font-size:40.00000381px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:end;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:end;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Sans;-inkscape-font-specification:'Sans, Normal'"
xml:space="preserve"><tspan
id="tspan4352"
y="547.70569"
x="-157.20392"
sodipodi:role="line">Button2</tspan></text>
sodipodi:role="line"
style="font-size:32px">Button2</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:40.00000381px;line-height:125%;font-family:Sans;-inkscape-font-specification:'Sans, Normal';text-align:end;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:end;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
style="font-size:40.00000381px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:end;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:end;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Sans;-inkscape-font-specification:'Sans, Normal'"
x="-157.20392"
y="591.14594"
id="text4354"
@@ -571,14 +473,16 @@
sodipodi:role="line"
x="-157.20392"
y="591.14594"
id="tspan4356">Button14</tspan></text>
id="tspan4356"
style="font-size:32px">Button14</tspan></text>
</g>
<g
transform="translate(115.04633,-541.16273)"
style="display:inline"
transform="translate(-220.77251,-418.68304)"
id="g4358">
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:40.00000381px;line-height:125%;font-family:Sans;-inkscape-font-specification:'Sans, Normal';text-align:end;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:end;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
style="font-size:40.00000381px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:end;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:end;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Sans;-inkscape-font-specification:'Sans, Normal'"
x="-157.20392"
y="547.70569"
id="text4360"
@@ -586,36 +490,68 @@
sodipodi:role="line"
x="-157.20392"
y="547.70569"
id="tspan4362">Button6</tspan></text>
id="tspan4362"
style="font-size:32px">Button6</tspan></text>
<text
sodipodi:linespacing="125%"
id="text4364"
y="591.14594"
x="-157.20392"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:40.00000381px;line-height:125%;font-family:Sans;-inkscape-font-specification:'Sans, Normal';text-align:end;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:end;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
style="font-size:40.00000381px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:end;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:end;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Sans;-inkscape-font-specification:'Sans, Normal'"
xml:space="preserve"><tspan
id="tspan4366"
y="591.14594"
x="-157.20392"
sodipodi:role="line">Button18</tspan></text>
sodipodi:role="line"
style="font-size:32px">Button18</tspan></text>
</g>
</g>
<g
inkscape:groupmode="layer"
id="layer6"
inkscape:label="Title"
sodipodi:insensitive="true">
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:40px;line-height:125%;font-family:Sans;letter-spacing:0px;word-spacing:0px;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="733.21844"
y="73.834145"
id="text4223"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
id="tspan4225"
x="733.21844"
y="73.834145"
style="font-size:70.00000763px;text-align:center;text-anchor:middle">Roccat Kone XTD</tspan></text>
<path
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="M 250.33375,638.82236 373.2918,377.44447"
id="path3167"
inkscape:connector-curvature="0"
transform="translate(-647.36582,57.672036)" />
<path
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="M 187.75032,550.46927 313.65347,442.97301"
id="path3171"
inkscape:connector-curvature="0"
transform="translate(-647.36582,57.672036)" />
<path
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="M 170.0797,442.23674 318.07112,378.91702"
id="path3173"
inkscape:connector-curvature="0"
transform="translate(-647.36582,57.672036)" />
<path
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="M 590.49315,144.78134 502.14006,287.61883"
id="path3175"
inkscape:connector-curvature="0"
transform="translate(-647.36582,57.672036)" />
<path
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="M 403.47911,102.07734 437.34779,309.7071"
id="path3177"
inkscape:connector-curvature="0"
transform="translate(-647.36582,57.672036)" />
<path
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 257.69651,135.20975 98.66095,183.33266"
id="path3179"
inkscape:connector-curvature="0"
transform="translate(-647.36582,57.672036)" />
<path
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="M 207.62976,229.45305 365.19277,333.26793"
id="path3181"
inkscape:connector-curvature="0"
transform="translate(-647.36582,57.672036)" />
<path
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 162.71694,318.54241 133.26591,29.45103"
id="path3183"
inkscape:connector-curvature="0"
transform="translate(-647.36582,57.672036)" />
</g>
</svg>

Before

Width:  |  Height:  |  Size: 35 KiB

After

Width:  |  Height:  |  Size: 29 KiB

View File

@@ -108,13 +108,20 @@ mouse:usb:v046dpc24e:name:*:
RATBAG_HIDPP10_DPI=0:8200@50
RATBAG_HIDPP10_PROFILE=G500
# G502 over USB
# 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
mouse:usb:v046dpc06b:name:*:
RATBAG_DRIVER=hidpp10
RATBAG_SVG=logitech-g700.svg
RATBAG_HIDPP10_DPI=0:5700@23.53
RATBAG_HIDPP10_PROFILE=G700
@@ -125,6 +132,21 @@ mouse:usb:v046dpc531:name:*:
RATBAG_HIDPP10_PROFILE=G700
RATBAG_HIDPP10_INDEX=1
# G700s over USB
mouse:usb:v046dpc07c:name:*:
RATBAG_DRIVER=hidpp10
RATBAG_SVG=logitech-g700.svg
RATBAG_HIDPP10_DPI=0:8200@50
RATBAG_HIDPP10_PROFILE=G700
# G700s over wireless USB
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
# MX Master over unifying
mouse:usb:v046dp4041:name:*:
# MX Master over bluetooth
@@ -144,6 +166,20 @@ mouse:usb:v046dp400a:name:*:
mouse:usb:v046dpc080:name:*:
RATBAG_DRIVER=hidpp20
# Wireless Touchpad (Unifying)
mouse:usb:v046dp4011:name:*:
RATBAG_DRIVER=hidpp20
# G602 over wireless USB
mouse:usb:v046dpc537:name:*:
RATBAG_HIDPP20_INDEX=1
# G900 over wireless USB
mouse:usb:v046dpc539:name:*:
RATBAG_DRIVER=hidpp20
RATBAG_HIDPP20_INDEX=1
##########################################
# Roccat
##########################################

View File

@@ -19,7 +19,8 @@ libratbag_la_SOURCES = \
libratbag-hidraw.h \
libratbag-private.h \
libratbag-test.c \
libratbag-test.h
libratbag-test.h \
usb-ids.h
libratbag_la_LIBADD = \
libhidpp.la \
@@ -44,15 +45,19 @@ liblur_la_LIBADD = \
liblur_la_CFLAGS = \
-I$(top_srcdir)/include \
$(GCC_CFLAGS)
liblur_la_LDFLAGS = -shared
EXTRA_liblur_la_DEPENDENCIES = $(srcdir)/liblur.sym
liblur_la_LDFLAGS = -version-info $(LIBLUR_LT_VERSION) -shared \
-Wl,--version-script=$(srcdir)/liblur.sym
pkgconfigdir = $(libdir)/pkgconfig
pkgconfig_DATA = libratbag.pc
pkgconfig_DATA = libratbag.pc \
liblur.pc
AM_CFLAGS = $(GCC_CFLAGS)
DISTCLEANFILES = libratbag-version.h
EXTRA_DIST = libratbag-version.h.in libratbag.sym
EXTRA_DIST = libratbag-version.h.in libratbag.sym liblur.sym
# The hidpp libraries are static libraries only for in-tree tools. No API
# stability is guaranteed here.
@@ -62,7 +67,8 @@ libhidpp_la_SOURCES = \
hidpp10.h \
hidpp10.c \
hidpp20.h \
hidpp20.c
hidpp20.c \
usb-ids.h
libhidpp_la_LDFLAGS = -lm
libutil_la_SOURCES = \
libratbag-util.c \

View File

@@ -430,6 +430,7 @@ etekcity_read_button(struct ratbag_button *button)
{
const struct ratbag_button_action *action;
struct ratbag_device *device;
struct ratbag_button_macro *m;
struct etekcity_macro *macro;
struct etekcity_data *drv_data;
uint8_t *buf;
@@ -464,7 +465,7 @@ etekcity_read_button(struct ratbag_button *button)
button->index, button->profile->index,
rc < 0 ? strerror(-rc) : "not read enough", rc);
} else {
ratbag_button_set_macro(button, macro->name);
m = ratbag_button_macro_new(macro->name);
log_raw(device->ratbag,
"macro on button %d of profile %d is named '%s', and contains %d events:\n",
button->index, button->profile->index,
@@ -472,7 +473,7 @@ etekcity_read_button(struct ratbag_button *button)
for (j = 0; j < macro->length; j++) {
unsigned int keycode = ratbag_hidraw_get_keycode_from_keyboard_usage(device,
macro->keys[j].keycode);
ratbag_button_set_macro_event(button,
ratbag_button_macro_set_event(m,
j,
macro->keys[j].flag & 0x80 ? RATBAG_MACRO_EVENT_KEY_RELEASED : RATBAG_MACRO_EVENT_KEY_PRESSED,
keycode);
@@ -481,6 +482,8 @@ etekcity_read_button(struct ratbag_button *button)
libevdev_event_code_get_name(EV_KEY, keycode),
macro->keys[j].flag & 0x80 ? "released" : "pressed");
}
ratbag_button_copy_macro(button, m);
ratbag_button_macro_unref(m);
}
msleep(10);
}
@@ -633,13 +636,8 @@ etekcity_probe(struct ratbag_device *device)
int active_idx;
rc = ratbag_open_hidraw(device);
if (rc) {
log_error(device->ratbag,
"Can't open corresponding hidraw node: '%s' (%d)\n",
strerror(-rc),
rc);
return -ENODEV;
}
if (rc)
return rc;
if (!ratbag_hidraw_has_report(device, ETEKCITY_REPORT_ID_KEY_MAPPING)) {
ratbag_close_hidraw(device);
@@ -667,8 +665,8 @@ etekcity_probe(struct ratbag_device *device)
if (active_idx < 0) {
log_error(device->ratbag,
"Can't talk to the mouse: '%s' (%d)\n",
strerror(-rc),
rc);
strerror(-active_idx),
active_idx);
rc = -ENODEV;
goto err;
}

View File

@@ -35,8 +35,6 @@
#include "config.h"
#define USB_VENDOR_ID_LOGITECH 0x046d
#include <linux/types.h>
#include <errno.h>
#include <stdbool.h>
@@ -45,6 +43,7 @@
#include <unistd.h>
#include "hidpp10.h"
#include "usb-ids.h"
#include "libratbag-private.h"
#include "libratbag-hidraw.h"
@@ -76,6 +75,7 @@ hidpp10drv_read_macro(struct ratbag_button *button,
union hidpp10_button *binding)
{
struct ratbag_device *device = button->profile->device;
struct ratbag_button_macro *m;
const char *name;
union hidpp10_macro_data *macro;
unsigned int i, keycode;
@@ -84,13 +84,13 @@ hidpp10drv_read_macro(struct ratbag_button *button,
macro = profile->macros[binding->macro.address];
name = binding->macro.address > 1 ? (const char *)profile->macro_names[binding->macro.address - 2] : "";
ratbag_button_set_macro(button, name);
i = 0;
m = ratbag_button_macro_new(name);
while (macro && macro->any.type != HIDPP10_MACRO_END && i < MAX_MACRO_EVENTS) {
switch (macro->any.type) {
case HIDPP10_MACRO_DELAY:
ratbag_button_set_macro_event(button,
ratbag_button_macro_set_event(m,
i++,
RATBAG_MACRO_EVENT_WAIT,
macro->delay.time);
@@ -99,11 +99,11 @@ hidpp10drv_read_macro(struct ratbag_button *button,
case HIDPP10_MACRO_KEY_PRESS:
keycode = ratbag_hidraw_get_keycode_from_keyboard_usage(device, macro->key.key);
if (!delay)
ratbag_button_set_macro_event(button,
ratbag_button_macro_set_event(m,
i++,
RATBAG_MACRO_EVENT_WAIT,
1);
ratbag_button_set_macro_event(button,
ratbag_button_macro_set_event(m,
i++,
RATBAG_MACRO_EVENT_KEY_PRESSED,
keycode);
@@ -112,11 +112,11 @@ hidpp10drv_read_macro(struct ratbag_button *button,
case HIDPP10_MACRO_KEY_RELEASE:
keycode = ratbag_hidraw_get_keycode_from_keyboard_usage(device, macro->key.key);
if (!delay)
ratbag_button_set_macro_event(button,
ratbag_button_macro_set_event(m,
i++,
RATBAG_MACRO_EVENT_WAIT,
1);
ratbag_button_set_macro_event(button,
ratbag_button_macro_set_event(m,
i++,
RATBAG_MACRO_EVENT_KEY_RELEASED,
keycode);
@@ -125,11 +125,11 @@ hidpp10drv_read_macro(struct ratbag_button *button,
case HIDPP10_MACRO_MOD_PRESS:
keycode = hidpp10drv_read_macro_modifier(device, macro);
if (!delay)
ratbag_button_set_macro_event(button,
ratbag_button_macro_set_event(m,
i++,
RATBAG_MACRO_EVENT_WAIT,
1);
ratbag_button_set_macro_event(button,
ratbag_button_macro_set_event(m,
i++,
RATBAG_MACRO_EVENT_KEY_PRESSED,
keycode);
@@ -138,11 +138,11 @@ hidpp10drv_read_macro(struct ratbag_button *button,
case HIDPP10_MACRO_MOD_RELEASE:
keycode = hidpp10drv_read_macro_modifier(device, macro);
if (!delay)
ratbag_button_set_macro_event(button,
ratbag_button_macro_set_event(m,
i++,
RATBAG_MACRO_EVENT_WAIT,
1);
ratbag_button_set_macro_event(button,
ratbag_button_macro_set_event(m,
i++,
RATBAG_MACRO_EVENT_KEY_RELEASED,
keycode);
@@ -151,6 +151,9 @@ hidpp10drv_read_macro(struct ratbag_button *button,
}
macro++;
}
ratbag_button_copy_macro(button, m);
ratbag_button_macro_unref(m);
}
static void
@@ -248,6 +251,27 @@ hidpp10drv_read_button(struct ratbag_button *button)
}
hidpp10drv_map_button(device, hidpp10, button);
break;
case HIDPP10_PROFILE_G9:
switch (button->index) {
case 0: type = RATBAG_BUTTON_TYPE_LEFT; break;
case 1: type = RATBAG_BUTTON_TYPE_RIGHT; break;
case 2: type = RATBAG_BUTTON_TYPE_MIDDLE; break;
case 3: type = RATBAG_BUTTON_TYPE_THUMB; break;
case 4: type = RATBAG_BUTTON_TYPE_THUMB2; break;
case 5: type = RATBAG_BUTTON_TYPE_UNKNOWN; break;
case 6: type = RATBAG_BUTTON_TYPE_WHEEL_LEFT; break;
case 7: type = RATBAG_BUTTON_TYPE_WHEEL_RIGHT; break;
case 8: type = RATBAG_BUTTON_TYPE_RESOLUTION_UP; break;
case 9: type = RATBAG_BUTTON_TYPE_RESOLUTION_DOWN; break;
case 10:
case 11:
case 12: /* these don't actually exist on the device */
type = RATBAG_BUTTON_TYPE_UNKNOWN; break;
default:
break;
}
hidpp10drv_map_button(device, hidpp10, button);
break;
default:
switch (button->index) {
case 0: type = RATBAG_BUTTON_TYPE_LEFT; break;
@@ -479,16 +503,8 @@ hidpp10drv_probe(struct ratbag_device *device)
int nread = 0;
rc = ratbag_find_hidraw(device, hidpp10drv_test_hidraw);
if (rc == -ENODEV) {
return rc;
} else if (rc) {
log_error(device->ratbag,
"Can't open corresponding hidraw node: '%s' (%d)\n",
strerror(-rc),
rc);
rc = -ENODEV;
if (rc)
goto err;
}
drv_data = zalloc(sizeof(*drv_data));
hidpp_device_init(&base, device->hidraw.fd);

View File

@@ -117,38 +117,43 @@ hidpp20drv_read_macro_key_8100(struct ratbag_device *device, union hidpp20_macro
return ratbag_hidraw_get_keycode_from_keyboard_usage(device, macro->key.key);
}
static void
static int
hidpp20drv_read_macro_8100(struct ratbag_button *button,
struct hidpp20_profile *profile,
union hidpp20_button_binding *binding)
{
struct ratbag_device *device = button->profile->device;
struct ratbag_button_macro *m;
union hidpp20_macro_data *macro;
unsigned int i, keycode;
bool delay = true;
macro = profile->macros[binding->macro.page];
ratbag_button_set_macro(button, "macro");
if (!macro)
return -EINVAL;
i = 0;
m = ratbag_button_macro_new("macro");
while (macro && macro->any.type != HIDPP20_MACRO_END && i < MAX_MACRO_EVENTS) {
switch (macro->any.type) {
case HIDPP20_MACRO_DELAY:
ratbag_button_set_macro_event(button,
i++,
RATBAG_MACRO_EVENT_WAIT,
macro->delay.time);
ratbag_button_macro_set_event(m,
i++,
RATBAG_MACRO_EVENT_WAIT,
macro->delay.time);
delay = true;
break;
case HIDPP20_MACRO_KEY_PRESS:
keycode = hidpp20drv_read_macro_key_8100(device, macro);
if (!delay)
ratbag_button_set_macro_event(button,
ratbag_button_macro_set_event(m,
i++,
RATBAG_MACRO_EVENT_WAIT,
1);
ratbag_button_set_macro_event(button,
ratbag_button_macro_set_event(m,
i++,
RATBAG_MACRO_EVENT_KEY_PRESSED,
keycode);
@@ -157,11 +162,11 @@ hidpp20drv_read_macro_8100(struct ratbag_button *button,
case HIDPP20_MACRO_KEY_RELEASE:
keycode = hidpp20drv_read_macro_key_8100(device, macro);
if (!delay)
ratbag_button_set_macro_event(button,
ratbag_button_macro_set_event(m,
i++,
RATBAG_MACRO_EVENT_WAIT,
1);
ratbag_button_set_macro_event(button,
ratbag_button_macro_set_event(m,
i++,
RATBAG_MACRO_EVENT_KEY_RELEASED,
keycode);
@@ -170,6 +175,11 @@ hidpp20drv_read_macro_8100(struct ratbag_button *button,
}
macro++;
}
ratbag_button_copy_macro(button, m);
ratbag_button_macro_unref(m);
return 0;
}
static void
@@ -178,6 +188,7 @@ hidpp20drv_read_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;
int rc;
if (!(drv_data->capabilities & HIDPP_CAP_ONBOARD_PROFILES_8100))
return;
@@ -208,7 +219,9 @@ hidpp20drv_read_button_8100(struct ratbag_button *button)
button->action.action.special = hidpp20_onboard_profiles_get_special(profile->buttons[button->index].special.special);
break;
case HIDPP20_BUTTON_MACRO:
hidpp20drv_read_macro_8100(button, profile, &profile->buttons[button->index]);
rc = hidpp20drv_read_macro_8100(button, profile, &profile->buttons[button->index]);
if (rc)
button->action.type = RATBAG_BUTTON_ACTION_TYPE_NONE;
break;
default:
button->action.type = RATBAG_BUTTON_ACTION_TYPE_UNKNOWN;
@@ -579,7 +592,7 @@ hidpp20drv_read_profile_8100(struct ratbag_profile *profile, unsigned int index)
struct hidpp20drv_data *drv_data = ratbag_get_drv_data(device);
struct ratbag_resolution *res;
struct hidpp20_profile *p;
unsigned i, dpi;
unsigned i, dpi = 0;
hidpp20drv_read_onboard_profile(device, profile->index);
@@ -587,6 +600,10 @@ hidpp20drv_read_profile_8100(struct ratbag_profile *profile, unsigned int index)
if ((int)index == hidpp20drv_current_profile(device))
profile->is_active = true;
/* retrieve the resolution through 220X as the profile doesn't has it */
if (profile->is_active)
hidpp20drv_read_resolution_dpi(profile);
dpi = ratbag_resolution_get_dpi(profile->resolution.modes);
p = &drv_data->profiles->profiles[index];
@@ -651,13 +668,13 @@ hidpp20drv_init_feature(struct ratbag_device *device, uint16_t feature)
}
case HIDPP_PAGE_ADJUSTABLE_DPI: {
log_debug(ratbag, "device has adjustable dpi\n");
ratbag_device_set_capability(device, RATBAG_DEVICE_CAP_SWITCHABLE_RESOLUTION);
drv_data->capabilities |= HIDPP_CAP_SWITCHABLE_RESOLUTION_2201;
/* we read the profile once to get the correct number of
* supported resolutions. */
rc = hidpp20drv_read_resolution_dpi_2201(device);
if (rc < 0)
return rc;
return 0; /* this is not a hard failure */
ratbag_device_set_capability(device, RATBAG_DEVICE_CAP_SWITCHABLE_RESOLUTION);
drv_data->capabilities |= HIDPP_CAP_SWITCHABLE_RESOLUTION_2201;
break;
}
case HIDPP_PAGE_SPECIAL_KEYS_BUTTONS: {
@@ -734,6 +751,7 @@ hidpp20drv_20_probe(struct ratbag_device *device)
struct hidpp20_device *dev = drv_data->dev;
struct hidpp20_feature *feature_list = dev->feature_list;
unsigned int i;
int rc;
log_raw(device->ratbag,
"'%s' has %d features\n",
@@ -744,7 +762,9 @@ hidpp20drv_20_probe(struct ratbag_device *device)
log_raw(device->ratbag, "Init feature %s (0x%04x) \n",
hidpp20_feature_get_name(feature_list[i].feature),
feature_list[i].feature);
hidpp20drv_init_feature(device, feature_list[i].feature);
rc = hidpp20drv_init_feature(device, feature_list[i].feature);
if (rc < 0)
return rc;
}
return 0;
@@ -765,6 +785,26 @@ hidpp20_log(void *userdata, enum hidpp_log_priority priority, const char *format
log_msg_va(device->ratbag, priority, format, args);
}
static void
hidpp20drv_remove(struct ratbag_device *device)
{
struct hidpp20drv_data *drv_data = ratbag_get_drv_data(device);
struct hidpp20_device *dev = drv_data->dev;
if (!device)
return;
ratbag_close_hidraw(device);
if (drv_data->profiles)
hidpp20_onboard_profiles_destroy(dev, drv_data->profiles);
free(drv_data->controls);
free(drv_data->sensors);
if (drv_data->dev)
hidpp20_device_destroy(drv_data->dev);
free(drv_data);
}
static int
hidpp20drv_probe(struct ratbag_device *device)
{
@@ -772,28 +812,42 @@ 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 == -ENODEV) {
if (rc)
return rc;
} else if (rc) {
log_error(device->ratbag,
"Can't open corresponding hidraw node: '%s' (%d)\n",
strerror(-rc),
rc);
return -ENODEV;
}
drv_data = zalloc(sizeof(*drv_data));
ratbag_set_drv_data(device, drv_data);
hidpp_device_init(&base, device->hidraw.fd);
hidpp_device_set_log_handler(&base, hidpp20_log, HIDPP_LOG_PRIORITY_RAW, device);
dev = hidpp20_device_new(&base, HIDPP_RECEIVER_IDX);
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;
}
}
/* 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.
*/
dev = hidpp20_device_new(&base, device_idx);
if (!dev) {
log_error(device->ratbag,
"Failed to get HID++2.0 device for %s\n",
device->name);
rc = -ENODEV;
goto err;
}
@@ -806,11 +860,9 @@ hidpp20drv_probe(struct ratbag_device *device)
drv_data->num_resolutions = 1;
drv_data->num_buttons = 8;
if (dev->proto_major >= 2) {
rc = hidpp20drv_20_probe(device);
if (rc)
goto err;
}
rc = hidpp20drv_20_probe(device);
if (rc)
goto err;
ratbag_device_init_profiles(device,
drv_data->num_profiles,
@@ -819,27 +871,10 @@ hidpp20drv_probe(struct ratbag_device *device)
return rc;
err:
free(drv_data);
ratbag_set_drv_data(device, NULL);
hidpp20drv_remove(device);
return rc;
}
static void
hidpp20drv_remove(struct ratbag_device *device)
{
struct hidpp20drv_data *drv_data = ratbag_get_drv_data(device);
struct hidpp20_device *dev = drv_data->dev;
ratbag_close_hidraw(device);
if (drv_data->profiles)
hidpp20_onboard_profiles_destroy(dev, drv_data->profiles);
free(drv_data->controls);
free(drv_data->sensors);
hidpp20_device_destroy(drv_data->dev);
free(drv_data);
}
struct ratbag_driver hidpp20_driver = {
.name = "Logitech HID++2.0",
.id = "hidpp20",

View File

@@ -532,6 +532,7 @@ roccat_read_button(struct ratbag_button *button)
ratbag_button_enable_action_type(button, RATBAG_BUTTON_ACTION_TYPE_MACRO);
if (action && action->type == RATBAG_BUTTON_ACTION_TYPE_MACRO) {
struct ratbag_button_macro *m = NULL;
roccat_set_config_profile(device,
button->profile->index,
@@ -566,7 +567,7 @@ roccat_read_button(struct ratbag_button *button)
goto out_macro;
}
ratbag_button_set_macro(button, macro->name);
m = ratbag_button_macro_new(macro->name);
log_raw(device->ratbag,
"macro on button %d of profile %d is named '%s', and contains %d events:\n",
button->index, button->profile->index,
@@ -574,7 +575,7 @@ roccat_read_button(struct ratbag_button *button)
for (j = 0; j < macro->length; j++) {
unsigned int keycode = ratbag_hidraw_get_keycode_from_keyboard_usage(device,
macro->keys[j].keycode);
ratbag_button_set_macro_event(button,
ratbag_button_macro_set_event(m,
j * 2,
macro->keys[j].flag & 0x01 ? RATBAG_MACRO_EVENT_KEY_PRESSED : RATBAG_MACRO_EVENT_KEY_RELEASED,
keycode);
@@ -582,7 +583,7 @@ roccat_read_button(struct ratbag_button *button)
time = macro->keys[j].time;
else
time = macro->keys[j].flag & 0x01 ? 10 : 50;
ratbag_button_set_macro_event(button,
ratbag_button_macro_set_event(m,
j * 2 + 1,
RATBAG_MACRO_EVENT_WAIT,
time);
@@ -592,9 +593,11 @@ roccat_read_button(struct ratbag_button *button)
libevdev_event_code_get_name(EV_KEY, keycode),
macro->keys[j].flag & 0x80 ? "released" : "pressed");
}
ratbag_button_copy_macro(button, m);
}
out_macro:
msleep(10);
ratbag_button_macro_unref(m);
}
}
@@ -777,13 +780,8 @@ roccat_probe(struct ratbag_device *device)
int active_idx;
rc = ratbag_open_hidraw(device);
if (rc) {
log_error(device->ratbag,
"Can't open corresponding hidraw node: '%s' (%d)\n",
strerror(-rc),
rc);
return -ENODEV;
}
if (rc)
return rc;
if (!ratbag_hidraw_has_report(device, ROCCAT_REPORT_ID_KEY_MAPPING)) {
ratbag_close_hidraw(device);
@@ -805,8 +803,8 @@ roccat_probe(struct ratbag_device *device)
if (active_idx < 0) {
log_error(device->ratbag,
"Can't talk to the mouse: '%s' (%d)\n",
strerror(-rc),
rc);
strerror(-active_idx),
active_idx);
rc = -ENODEV;
goto err;
}

View File

@@ -24,6 +24,7 @@
#include "config.h"
#include <errno.h>
#include <libevdev/libevdev.h>
#include "libratbag-private.h"
#include "libratbag-test.h"
@@ -73,6 +74,63 @@ test_set_active_profile(struct ratbag_device *device, unsigned int index)
return 0;
}
static void
test_read_button(struct ratbag_button *button)
{
struct ratbag_device *device = button->profile->device;
struct ratbag_test_device *d = ratbag_get_drv_data(device);
struct ratbag_test_profile *p = &d->profiles[button->profile->index];
struct ratbag_button_macro *m;
const char data[] = "TEST";
const char *c;
switch (p->buttons[button->index].type) {
case RATBAG_BUTTON_ACTION_TYPE_BUTTON:
button->action.type = RATBAG_BUTTON_ACTION_TYPE_BUTTON;
button->action.action.button = p->buttons[button->index].button;
break;
case RATBAG_BUTTON_ACTION_TYPE_KEY:
button->action.type = RATBAG_BUTTON_ACTION_TYPE_KEY;
button->action.action.key.key = p->buttons[button->index].key;
break;
case RATBAG_BUTTON_ACTION_TYPE_MACRO:
button->action.type = RATBAG_BUTTON_ACTION_TYPE_MACRO;
m = ratbag_button_macro_new("test macro");
ARRAY_FOR_EACH(data, c) {
char str[6];
snprintf_safe(str, 6, "KEY_%c", *c);
ratbag_button_macro_set_event(m,
0,
RATBAG_MACRO_EVENT_KEY_PRESSED,
libevdev_event_code_from_name(EV_KEY, str));
ratbag_button_macro_set_event(m,
0,
RATBAG_MACRO_EVENT_KEY_RELEASED,
libevdev_event_code_from_name(EV_KEY, str));
}
ratbag_button_copy_macro(button, m);
ratbag_button_macro_unref(m);
break;
default:
button->action.type = RATBAG_BUTTON_ACTION_TYPE_UNKNOWN;
}
ratbag_button_enable_action_type(button, RATBAG_BUTTON_ACTION_TYPE_BUTTON);
ratbag_button_enable_action_type(button, RATBAG_BUTTON_ACTION_TYPE_KEY);
ratbag_button_enable_action_type(button, RATBAG_BUTTON_ACTION_TYPE_SPECIAL);
ratbag_button_enable_action_type(button, RATBAG_BUTTON_ACTION_TYPE_MACRO);
}
static int
test_write_button(struct ratbag_button *button,
const struct ratbag_button_action *action)
{
/* check if the device is still valid */
assert(ratbag_get_drv_data(button->profile->device) != NULL);
return 0;
}
static int
test_fake_probe(struct ratbag_device *device)
{
@@ -116,7 +174,7 @@ struct ratbag_driver test_driver = {
.read_profile = test_read_profile,
.write_profile = test_write_profile,
.set_active_profile = test_set_active_profile,
.read_button = NULL,
.write_button = NULL,
.read_button = test_read_button,
.write_button = test_write_button,
.write_resolution_dpi = NULL,
};

View File

@@ -200,4 +200,10 @@ hidpp_cpu_to_le_u16(uint16_t data)
return result;
}
static inline uint32_t
hidpp_get_unaligned_be_u32(uint8_t *buf)
{
return (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3];
}
#endif /* HIDPP_GENERIC_H */

View File

@@ -520,16 +520,16 @@ hidpp10_get_battery_mileage(struct hidpp10_device *dev,
} \
}
struct _hidpp10_dpi_mode_8_sym {
struct _hidpp10_dpi_mode_8 {
uint8_t res;
uint8_t led1:4;
uint8_t led2:4;
uint8_t led3:4;
uint8_t led4:4;
} __attribute__((packed));
_Static_assert(sizeof(struct _hidpp10_dpi_mode_8_sym) == 3, "Invalid size");
_Static_assert(sizeof(struct _hidpp10_dpi_mode_8) == 3, "Invalid size");
struct _hidpp10_dpi_mode_8 {
struct _hidpp10_dpi_mode_8_dual {
uint8_t xres;
uint8_t yres;
uint8_t led1:4;
@@ -537,7 +537,7 @@ struct _hidpp10_dpi_mode_8 {
uint8_t led3:4;
uint8_t led4:4;
} __attribute__((packed));
_Static_assert(sizeof(struct _hidpp10_dpi_mode_8) == 4, "Invalid size");
_Static_assert(sizeof(struct _hidpp10_dpi_mode_8_dual) == 4, "Invalid size");
struct _hidpp10_dpi_mode_16 {
uint16_t xres;
@@ -616,7 +616,7 @@ static const uint8_t _hidpp10_profile_700_unknown1[3] = { 0x80, 0x01, 0x10 };
static const uint8_t _hidpp10_profile_700_unknown2[10] = { 0x01, 0x2c, 0x02, 0x58, 0x64, 0xff, 0xbc, 0x00, 0x09, 0x31 };
struct _hidpp10_profile_700 {
struct _hidpp10_dpi_mode_8 dpi_modes[PROFILE_NUM_DPI_MODES];
struct _hidpp10_dpi_mode_8_dual dpi_modes[PROFILE_NUM_DPI_MODES];
uint8_t default_dpi_mode;
uint8_t unknown1[3];
uint8_t usb_refresh_rate;
@@ -631,11 +631,11 @@ struct _hidpp10_profile_9 {
uint8_t green;
uint8_t blue;
uint8_t unknown1;
struct _hidpp10_dpi_mode_8_sym dpi_modes[PROFILE_NUM_DPI_MODES];
struct _hidpp10_dpi_mode_8 dpi_modes[PROFILE_NUM_DPI_MODES];
uint8_t default_dpi_mode;
uint8_t unknown2[2];
uint8_t usb_refresh_rate;
union _hidpp10_button_binding buttons[10];
union _hidpp10_button_binding buttons[PROFILE_NUM_BUTTONS_G9];
uint8_t unknown3[3];
union _hidpp10_profile_metadata metadata;
} __attribute__((packed));
@@ -858,28 +858,6 @@ hidpp10_set_current_profile(struct hidpp10_device *dev, int16_t current_profile)
PROFILE_TYPE_INDEX);
}
static void
hidpp10_fill_dpi_modes_8_sym(struct hidpp10_device *dev,
struct hidpp10_profile *profile,
struct _hidpp10_dpi_mode_8_sym *dpi_list,
unsigned int count)
{
unsigned int i;
profile->num_dpi_modes = count;
for (i = 0; i < count; i++) {
struct _hidpp10_dpi_mode_8_sym *dpi = &dpi_list[i];
profile->dpi_modes[i].xres = hidpp10_get_dpi_value(dev, dpi->res);
profile->dpi_modes[i].yres = hidpp10_get_dpi_value(dev, dpi->res);
profile->dpi_modes[i].led[0] = dpi->led1 == 0x2;
profile->dpi_modes[i].led[1] = dpi->led2 == 0x2;
profile->dpi_modes[i].led[2] = dpi->led3 == 0x2;
profile->dpi_modes[i].led[3] = dpi->led4 == 0x2;
}
}
static void
hidpp10_fill_dpi_modes_8(struct hidpp10_device *dev,
struct hidpp10_profile *profile,
@@ -892,8 +870,8 @@ hidpp10_fill_dpi_modes_8(struct hidpp10_device *dev,
for (i = 0; i < count; i++) {
struct _hidpp10_dpi_mode_8 *dpi = &dpi_list[i];
profile->dpi_modes[i].xres = hidpp10_get_dpi_value(dev, dpi->xres);
profile->dpi_modes[i].yres = hidpp10_get_dpi_value(dev, dpi->yres);
profile->dpi_modes[i].xres = hidpp10_get_dpi_value(dev, dpi->res);
profile->dpi_modes[i].yres = hidpp10_get_dpi_value(dev, dpi->res);
profile->dpi_modes[i].led[0] = dpi->led1 == 0x2;
profile->dpi_modes[i].led[1] = dpi->led2 == 0x2;
@@ -913,6 +891,48 @@ hidpp10_write_dpi_modes_8(struct hidpp10_device *dev,
for (i = 0; i < count; i++) {
struct _hidpp10_dpi_mode_8 *dpi = &dpi_list[i];
dpi->res = hidpp10_get_dpi_mapping(dev, profile->dpi_modes[i].xres);
dpi->led1 = profile->dpi_modes[i].led[0] ? 0x02 : 0x01;
dpi->led2 = profile->dpi_modes[i].led[1] ? 0x02 : 0x01;
dpi->led3 = profile->dpi_modes[i].led[2] ? 0x02 : 0x01;
dpi->led4 = profile->dpi_modes[i].led[3] ? 0x02 : 0x01;
}
}
static void
hidpp10_fill_dpi_modes_8_dual(struct hidpp10_device *dev,
struct hidpp10_profile *profile,
struct _hidpp10_dpi_mode_8_dual *dpi_list,
unsigned int count)
{
unsigned int i;
profile->num_dpi_modes = count;
for (i = 0; i < count; i++) {
struct _hidpp10_dpi_mode_8_dual *dpi = &dpi_list[i];
profile->dpi_modes[i].xres = hidpp10_get_dpi_value(dev, dpi->xres);
profile->dpi_modes[i].yres = hidpp10_get_dpi_value(dev, dpi->yres);
profile->dpi_modes[i].led[0] = dpi->led1 == 0x2;
profile->dpi_modes[i].led[1] = dpi->led2 == 0x2;
profile->dpi_modes[i].led[2] = dpi->led3 == 0x2;
profile->dpi_modes[i].led[3] = dpi->led4 == 0x2;
}
}
static void
hidpp10_write_dpi_modes_8_dual(struct hidpp10_device *dev,
struct hidpp10_profile *profile,
struct _hidpp10_dpi_mode_8_dual *dpi_list,
unsigned int count)
{
unsigned int i;
for (i = 0; i < count; i++) {
struct _hidpp10_dpi_mode_8_dual *dpi = &dpi_list[i];
dpi->xres = hidpp10_get_dpi_mapping(dev, profile->dpi_modes[i].xres);
dpi->yres = hidpp10_get_dpi_mapping(dev, profile->dpi_modes[i].yres);
@@ -1437,6 +1457,7 @@ hidpp10_get_profile(struct hidpp10_device *dev, int8_t number, struct hidpp10_pr
break;
default:
hidpp_log_error(&dev->base, "This should never happen, complain to your maintainer.\n");
return -EINVAL;
}
profile = &dev->profiles[number];
@@ -1474,7 +1495,7 @@ hidpp10_get_profile(struct hidpp10_device *dev, int8_t number, struct hidpp10_pr
profile->default_dpi_mode = p700->default_dpi_mode;
profile->refresh_rate = p700->usb_refresh_rate ? 1000/p700->usb_refresh_rate : 0;
hidpp10_fill_dpi_modes_8(dev, profile, p700->dpi_modes, PROFILE_NUM_DPI_MODES);
hidpp10_fill_dpi_modes_8_dual(dev, profile, p700->dpi_modes, PROFILE_NUM_DPI_MODES);
hidpp10_profile_parse_names(dev, profile, number, &p700->metadata);
hidpp10_fill_buttons(dev, profile, buttons, PROFILE_NUM_BUTTONS);
break;
@@ -1482,9 +1503,9 @@ hidpp10_get_profile(struct hidpp10_device *dev, int8_t number, struct hidpp10_pr
profile->default_dpi_mode = p9->default_dpi_mode;
profile->refresh_rate = p9->usb_refresh_rate ? 1000/p9->usb_refresh_rate : 0;
hidpp10_fill_dpi_modes_8_sym(dev, profile, p9->dpi_modes, PROFILE_NUM_DPI_MODES);
hidpp10_fill_dpi_modes_8(dev, profile, p9->dpi_modes, PROFILE_NUM_DPI_MODES);
hidpp10_profile_parse_names(dev, profile, number, &p9->metadata);
hidpp10_fill_buttons(dev, profile, buttons, 10);
hidpp10_fill_buttons(dev, profile, buttons, PROFILE_NUM_BUTTONS_G9);
break;
default:
hidpp_log_error(&dev->base, "This should never happen, complain to your maintainer.\n");
@@ -1605,6 +1626,7 @@ hidpp10_set_profile(struct hidpp10_device *dev, int8_t number, struct hidpp10_pr
union _hidpp10_profile_data *data = (union _hidpp10_profile_data *)page_data;
struct _hidpp10_profile_500 *p500 = &data->profile_500;
struct _hidpp10_profile_700 *p700 = &data->profile_700;
struct _hidpp10_profile_9 *p9 = &data->profile_9;
int res;
struct hidpp10_directory directory[16]; /* completely random profile count */
union _hidpp10_button_binding *buttons;
@@ -1636,6 +1658,9 @@ hidpp10_set_profile(struct hidpp10_device *dev, int8_t number, struct hidpp10_pr
case HIDPP10_PROFILE_G700:
buttons = p700->buttons;
break;
case HIDPP10_PROFILE_G9:
buttons = p9->buttons;
break;
default:
hidpp_log_error(&dev->base, "This should never happen, complain to your maintainer.\n");
}
@@ -1645,6 +1670,7 @@ hidpp10_set_profile(struct hidpp10_device *dev, int8_t number, struct hidpp10_pr
* values when we are not sure. */
switch (dev->profile_type) {
case HIDPP10_PROFILE_G500:
case HIDPP10_PROFILE_G9:
/* we do not know the actual values of the remaining field right now
* so pre-fill with the current data */
res = hidpp10_read_page(dev, directory[number].page, page_data);
@@ -1676,10 +1702,21 @@ hidpp10_set_profile(struct hidpp10_device *dev, int8_t number, struct hidpp10_pr
p700->default_dpi_mode = profile->default_dpi_mode;
p700->usb_refresh_rate = 1000 / profile->refresh_rate;
hidpp10_write_dpi_modes_8(dev, profile, p700->dpi_modes, PROFILE_NUM_DPI_MODES);
hidpp10_write_dpi_modes_8_dual(dev, profile, p700->dpi_modes, PROFILE_NUM_DPI_MODES);
hidpp10_write_buttons(dev, profile, buttons, PROFILE_NUM_BUTTONS);
hidpp10_profile_set_names(dev, profile, number, &p700->metadata);
break;
case HIDPP10_PROFILE_G9:
p9->red = profile->red;
p9->green = profile->green;
p9->blue = profile->blue;
p9->default_dpi_mode = profile->default_dpi_mode;
p9->usb_refresh_rate = 1000 / profile->refresh_rate;
hidpp10_write_dpi_modes_8(dev, profile, p9->dpi_modes, PROFILE_NUM_DPI_MODES);
hidpp10_write_buttons(dev, profile, buttons, PROFILE_NUM_BUTTONS);
hidpp10_profile_set_names(dev, profile, number, &p9->metadata);
break;
default:
hidpp_log_error(&dev->base, "This should never happen, complain to your maintainer.\n");
}
@@ -2002,18 +2039,28 @@ hidpp10_get_current_resolution(struct hidpp10_device *dev,
uint16_t *yres)
{
unsigned idx = dev->index;
union hidpp10_message resolution = CMD_CURRENT_RESOLUTION(REPORT_ID_SHORT, idx, GET_LONG_REGISTER_REQ);
union hidpp10_message resolution = CMD_CURRENT_RESOLUTION(REPORT_ID_SHORT, idx, GET_REGISTER_REQ);
union hidpp10_message resolution_long = CMD_CURRENT_RESOLUTION(REPORT_ID_SHORT, idx, GET_LONG_REGISTER_REQ);
int res;
hidpp_log_raw(&dev->base, "Fetching current resolution\n");
res = hidpp10_request_command(dev, &resolution);
if (res)
return res;
/* resolution is in 50dpi multiples */
*xres = hidpp10_get_dpi_value(dev, hidpp_get_unaligned_le_u16(&resolution.data[4]));
*yres = hidpp10_get_dpi_value(dev, hidpp_get_unaligned_le_u16(&resolution.data[6]));
switch (dev->profile_type) {
case HIDPP10_PROFILE_G9:
res = hidpp10_request_command(dev, &resolution);
if (res)
return res;
/* resolution is in 50dpi multiples */
*xres = *yres = hidpp10_get_dpi_value(dev, hidpp_get_unaligned_le_u16(&resolution.data[4]));
break;
default:
res = hidpp10_request_command(dev, &resolution_long);
if (res)
return res;
/* resolution is in 50dpi multiples */
*xres = hidpp10_get_dpi_value(dev, hidpp_get_unaligned_le_u16(&resolution_long.data[4]));
*yres = hidpp10_get_dpi_value(dev, hidpp_get_unaligned_le_u16(&resolution_long.data[6]));
}
return 0;
}
@@ -2508,8 +2555,7 @@ hidpp10_get_extended_pairing_information(struct hidpp10_device *dev,
if (res)
return -1;
*serial = hidpp_get_unaligned_be_u16(&info.msg.string[2]) << 16;
*serial |= hidpp_get_unaligned_be_u16(&info.msg.string[4]);
*serial = hidpp_get_unaligned_be_u32(&info.msg.string[1]);
return 0;
}

View File

@@ -365,6 +365,7 @@ hidpp10_get_battery_mileage(struct hidpp10_device *dev,
/* 0x0F: Profile queries */
/* -------------------------------------------------------------------------- */
#define PROFILE_NUM_BUTTONS 13
#define PROFILE_NUM_BUTTONS_G9 10
#define PROFILE_NUM_DPI_MODES 5
#define PROFILE_BUTTON_TYPE_BUTTON 0x81
#define PROFILE_BUTTON_TYPE_KEYS 0x82

View File

@@ -863,8 +863,9 @@ int hidpp20_adjustable_dpi_get_sensors(struct hidpp20_device *device,
*sensors_list = s_list;
return num_sensors;
err:
num_sensors = 0;
free(s_list);
return rc;
return rc > 0 ? -EPROTO : rc;
}
int hidpp20_adjustable_dpi_set_sensor_dpi(struct hidpp20_device *device,
@@ -907,6 +908,8 @@ int hidpp20_adjustable_dpi_set_sensor_dpi(struct hidpp20_device *device,
/* -------------------------------------------------------------------------- */
#define CMD_ONBOARD_PROFILES_GET_PROFILES_DESCR 0x00
#define CMD_ONBOARD_PROFILES_SET_ONBOARD_MODE 0x10
#define CMD_ONBOARD_PROFILES_GET_ONBOARD_MODE 0x20
#define CMD_ONBOARD_PROFILES_SET_CURRENT_PROFILE 0x30
#define CMD_ONBOARD_PROFILES_GET_CURRENT_PROFILE 0x40
#define CMD_ONBOARD_PROFILES_MEMORY_READ 0x50
@@ -920,6 +923,31 @@ int hidpp20_adjustable_dpi_set_sensor_dpi(struct hidpp20_device *device,
#define HIDPP20_PROFILE_SIZE HIDPP20_PAGE_SIZE
#define HIDPP20_BUTTON_HID 0x80
#define HIDPP20_MODE_NO_CHANGE 0x00
#define HIDPP20_ONBOARD_MODE 0x01
#define HIDPP20_HOST_MODE 0x02
#define HIDPP20_ONBOARD_PROFILES_MEMORY_TYPE_G402 0x01
#define HIDPP20_ONBOARD_PROFILES_PROFILE_TYPE_G402 0x01
#define HIDPP20_ONBOARD_PROFILES_PROFILE_TYPE_G303 0x02
#define HIDPP20_ONBOARD_PROFILES_PROFILE_TYPE_G900 0x03
#define HIDPP20_ONBOARD_PROFILES_MACRO_TYPE_G402 0x01
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");
int
hidpp20_onboard_profiles_read_memory(struct hidpp20_device *device,
uint8_t read_rom,
@@ -1076,6 +1104,58 @@ hidpp20_onboard_profiles_write_page(struct hidpp20_device *device,
return hidpp20_onboard_profiles_write_data(device, page, 0x00, data, HIDPP20_PAGE_SIZE);
}
static int
hidpp20_onboard_profiles_get_onboard_mode(struct hidpp20_device *device)
{
uint8_t feature_index;
int rc;
union hidpp20_message msg = {
.msg.report_id = REPORT_ID_SHORT,
.msg.device_idx = device->index,
.msg.address = CMD_ONBOARD_PROFILES_GET_ONBOARD_MODE,
};
feature_index = hidpp_root_get_feature_idx(device,
HIDPP_PAGE_ONBOARD_PROFILES);
if (feature_index == 0)
return -ENOTSUP;
msg.msg.sub_id = feature_index;
rc = hidpp20_request_command(device, &msg);
if (rc)
return rc;
return msg.msg.parameters[0];
}
static int
hidpp20_onboard_profiles_set_onboard_mode(struct hidpp20_device *device,
uint8_t onboard_mode)
{
uint8_t feature_index;
int rc;
union hidpp20_message msg = {
.msg.report_id = REPORT_ID_SHORT,
.msg.device_idx = device->index,
.msg.address = CMD_ONBOARD_PROFILES_SET_ONBOARD_MODE,
.msg.parameters[1] = onboard_mode,
};
feature_index = hidpp_root_get_feature_idx(device,
HIDPP_PAGE_ONBOARD_PROFILES);
if (feature_index == 0)
return -ENOTSUP;
msg.msg.sub_id = feature_index;
rc = hidpp20_request_command(device, &msg);
if (rc)
return rc;
return 0;
}
int
hidpp20_onboard_profiles_get_current_profile(struct hidpp20_device *device)
{
@@ -1130,16 +1210,18 @@ hidpp20_onboard_profiles_set_current_profile(struct hidpp20_device *device,
static int
hidpp20_onboard_profiles_initialize(struct hidpp20_device *device,
unsigned profile_count,
struct hidpp20_profiles *profiles_list)
struct hidpp20_profiles **profiles_list)
{
uint8_t feature_index;
int rc;
struct hidpp20_profiles *profiles;
union hidpp20_message msg = {
.msg.report_id = REPORT_ID_SHORT,
.msg.device_idx = device->index,
.msg.address = CMD_ONBOARD_PROFILES_GET_PROFILES_DESCR,
};
struct hidpp20_onboard_profiles_info *info;
int onboard_mode;
feature_index = hidpp_root_get_feature_idx(device,
HIDPP_PAGE_ONBOARD_PROFILES);
@@ -1152,10 +1234,77 @@ hidpp20_onboard_profiles_initialize(struct hidpp20_device *device,
if (rc)
return rc;
profiles_list->num_buttons = msg.msg.parameters[5] <= 16 ? msg.msg.parameters[5] : 16;
profiles_list->num_profiles = profile_count;
/* FIXME: actually retrieve the correct values */
profiles_list->num_modes = 5;
info = (struct hidpp20_onboard_profiles_info *)msg.msg.parameters;
if (info->memory_model_id != HIDPP20_ONBOARD_PROFILES_MEMORY_TYPE_G402) {
hidpp_log_error(&device->base,
"Memory layout not supported: 0x%02x.\n",
info->memory_model_id);
return -ENOTSUP;
}
if ((info->profile_format_id != HIDPP20_ONBOARD_PROFILES_PROFILE_TYPE_G402) &&
(info->profile_format_id != HIDPP20_ONBOARD_PROFILES_PROFILE_TYPE_G303) &&
(info->profile_format_id != HIDPP20_ONBOARD_PROFILES_PROFILE_TYPE_G900)) {
hidpp_log_error(&device->base,
"Profile layout not supported: 0x%02x.\n",
info->profile_format_id);
return -ENOTSUP;
}
if (info->macro_format_id != HIDPP20_ONBOARD_PROFILES_MACRO_TYPE_G402) {
hidpp_log_error(&device->base,
"Macro format not supported: 0x%02x.\n",
info->macro_format_id);
return -ENOTSUP;
}
info->sector_size = hidpp_be_u16_to_cpu(info->sector_size);
if (info->sector_size != HIDPP20_PAGE_SIZE) {
hidpp_log_error(&device->base,
"Unsupported sector size: %d.\n",
info->sector_size);
return -ENOTSUP;
}
rc = hidpp20_onboard_profiles_get_onboard_mode(device);
if (rc < 0)
return rc;
onboard_mode = rc;
if (onboard_mode != HIDPP20_ONBOARD_MODE) {
hidpp_log_raw(&device->base,
"not on the correct mode: %d.\n",
onboard_mode);
rc = hidpp20_onboard_profiles_set_onboard_mode(device,
HIDPP20_ONBOARD_MODE);
if (rc < 0)
return rc;
}
profiles = zalloc(sizeof(struct hidpp20_profiles) +
info->profile_count * sizeof(struct hidpp20_profile));
profiles->num_profiles = info->profile_count;
profiles->num_rom_profiles = info->profile_count_oob;
profiles->num_buttons = msg.msg.parameters[5] <= 16 ? msg.msg.parameters[5] : 16;
profiles->num_modes = HIDPP20_DPI_COUNT;
profiles->has_g_shift = (info->mechanical_layout & 0x03) == 2;
profiles->has_dpi_shift = ((info->mechanical_layout & 0x0c) >> 2) == 2;
switch(info->various_info & 0x07) {
case 1:
profiles->corded = 1;
break;
case 2:
profiles->wireless = 1;
break;
case 4:
profiles->corded = 1;
profiles->wireless = 1;
break;
}
*profiles_list = profiles;
return 0;
}
@@ -1320,44 +1469,64 @@ hidpp20_onboard_profiles_parse_macro(struct hidpp20_device *device,
return 0;
}
static unsigned int
hidpp20_onboard_profiles_compute_dict_size(struct hidpp20_device *device,
struct hidpp20_profiles *profiles)
{
unsigned p, num_offset;
num_offset = 0;
p = profiles->num_profiles;
while (p) {
p >>= 2;
num_offset += 16;
}
return num_offset;
}
int
hidpp20_onboard_profiles_allocate(struct hidpp20_device *device,
struct hidpp20_profiles **profiles_list)
{
unsigned i;
unsigned i, offset, num_offset;
int rc;
uint8_t data[16] = {0};
struct hidpp20_profiles *profiles;
unsigned profile_count = 0;
uint8_t data[HIDPP20_PAGE_SIZE] = {0};
struct hidpp20_profiles *profiles = NULL;
rc = hidpp20_onboard_profiles_read_memory(device,
0x00,
0x00,
0x00,
data);
rc = hidpp20_onboard_profiles_initialize(device,
&profiles);
if (rc < 0)
return rc;
profiles = zalloc(sizeof(struct hidpp20_profiles));
assert(profiles);
for (i = 0; i < 3; i++) {
uint8_t *d = data + 4 * i;
num_offset = hidpp20_onboard_profiles_compute_dict_size(device,
profiles);
for (offset = 0; offset < num_offset; offset += 16) {
rc = hidpp20_onboard_profiles_read_memory(device,
0x00,
0x00,
offset,
data + offset);
if (rc < 0)
return rc;
}
for (i = 0; i < profiles->num_profiles; i++) {
uint8_t *d = data + offset + 4 * i;
if (d[0] == 0xFF && d[1] == 0xFF)
break;
profile_count++;
profiles->profiles[i].index = d[1];
profiles->profiles[i].enabled = d[2];
}
hidpp20_onboard_profiles_initialize(device,
profile_count,
profiles);
*profiles_list = profiles;
return profile_count;
return profiles->num_profiles;
}
void
@@ -1386,7 +1555,8 @@ hidpp20_onboard_profiles_destroy(struct hidpp20_device *device,
static int
hidpp20_onboard_profiles_find_and_read_profile(struct hidpp20_device *device,
unsigned int index,
uint8_t *data)
uint8_t *data,
unsigned int num_rom_profiles)
{
int rc;
unsigned i;
@@ -1419,13 +1589,19 @@ hidpp20_onboard_profiles_find_and_read_profile(struct hidpp20_device *device,
}
/* something went wrong, the mouse is using the factory profile in ROM */
if (num_rom_profiles == 0)
return -EINVAL;
if (index >= num_rom_profiles)
index = num_rom_profiles - 1;
for (i = 0; i < HIDPP20_PROFILE_SIZE / 0x10; i++) {
rc = hidpp20_onboard_profiles_read_memory(device,
1,
index + 1,
i * 0x10,
data + i * 0x10);
if (rc < 0)
if (rc != 0)
return rc;
}
@@ -1446,7 +1622,7 @@ hidpp20_onboard_profiles_enable_profile(struct hidpp20_device *device,
profiles_list->profiles[index].index = index + 1;
profiles_list->profiles[index].enabled = 0x01;
for (i = 0; i < 3; i++) {
for (i = 0; i < profiles_list->num_profiles; i++) {
data[buffer_index++] = 0x00;
data[buffer_index++] = i + 1;
data[buffer_index++] = profiles_list->profiles[i].enabled;
@@ -1461,7 +1637,11 @@ hidpp20_onboard_profiles_enable_profile(struct hidpp20_device *device,
memset(data + buffer_index, 0xff, sizeof(data) - buffer_index);
hidpp_log_buf_error(&device->base, "dictionary: ", data, 16);
hidpp_log_buf_debug(&device->base,
"dictionary: ",
data,
hidpp20_onboard_profiles_compute_dict_size(device,
profiles_list));
return hidpp20_onboard_profiles_write_page(device, 0x00, data);
}
@@ -1472,16 +1652,24 @@ union hidpp20_internal_profile {
uint8_t report_rate;
uint8_t default_dpi;
uint8_t switched_dpi;
uint16_t dpi[7];
uint8_t zero;
uint8_t padding[14];
uint16_t dpi[5];
struct {
uint8_t red;
uint8_t green;
uint8_t blue;
} profile_color;
uint8_t power_mode;
uint8_t angle_snapping;
uint8_t reserved[14];
union hidpp20_button_binding buttons[16];
union hidpp20_button_binding alternate_buttons[16];
union {
char txt[16 * 3];
uint8_t raw[16 * 3];
} name;
uint8_t padding1[46];
uint8_t logo_effect[11]; /* G303 only */
uint8_t side_effects[11]; /* G303 only */
uint8_t free[24];
uint16_t crc;
} __attribute__((packed)) profile;
};
@@ -1606,8 +1794,11 @@ int hidpp20_onboard_profiles_read(struct hidpp20_device *device,
if (index >= profiles_list->num_profiles)
return -EINVAL;
rc = hidpp20_onboard_profiles_find_and_read_profile(device, index, data);
if (rc < 0)
rc = hidpp20_onboard_profiles_find_and_read_profile(device,
index,
data,
profiles_list->num_rom_profiles);
if (rc != 0)
return rc;
profile->report_rate = 1000 / max(1, pdata.profile.report_rate);
@@ -1648,7 +1839,10 @@ int hidpp20_onboard_profiles_write(struct hidpp20_device *device,
if (index >= profiles_list->num_profiles)
return -EINVAL;
rc = hidpp20_onboard_profiles_find_and_read_profile(device, index, data);
rc = hidpp20_onboard_profiles_find_and_read_profile(device,
index,
data,
profiles_list->num_rom_profiles);
if (rc < 0)
return rc;
@@ -1691,8 +1885,9 @@ static const enum ratbag_button_action_special hidpp20_profiles_specials[] = {
[0x09] = RATBAG_BUTTON_ACTION_SPECIAL_INVALID,
[0x0a] = RATBAG_BUTTON_ACTION_SPECIAL_PROFILE_CYCLE_UP,
[0x0b] = RATBAG_BUTTON_ACTION_SPECIAL_SECOND_MODE,
[0x0c] = RATBAG_BUTTON_ACTION_SPECIAL_BATTERY_LEVEL,
[0x0c ... 0xff] = RATBAG_BUTTON_ACTION_SPECIAL_INVALID,
[0x0d ... 0xff] = RATBAG_BUTTON_ACTION_SPECIAL_INVALID,
};
enum ratbag_button_action_special
@@ -1738,6 +1933,9 @@ hidpp20_device_new(const struct hidpp_device *base, unsigned int idx)
goto err;
}
if (dev->proto_major < 2)
goto err;
rc = hidpp20_feature_set_get(dev);
if (rc < 0)
goto err;

View File

@@ -275,6 +275,8 @@ int hidpp20_adjustable_dpi_set_sensor_dpi(struct hidpp20_device *device,
#define HIDPP20_MODIFIER_KEY_CTRL 0x01
#define HIDPP20_MODIFIER_KEY_SHIFT 0x02
#define HIDPP20_DPI_COUNT 5
union hidpp20_button_binding {
struct {
uint8_t type;
@@ -353,16 +355,21 @@ struct hidpp20_profile {
unsigned report_rate;
unsigned default_dpi;
unsigned switched_dpi;
uint16_t dpi[5];
uint16_t dpi[HIDPP20_DPI_COUNT];
union hidpp20_button_binding buttons[32];
union hidpp20_macro_data *macros[32];
};
struct hidpp20_profiles {
uint8_t num_profiles;
uint8_t num_rom_profiles;
uint8_t num_buttons;
uint8_t num_modes;
struct hidpp20_profile profiles[5];
uint8_t has_g_shift;
uint8_t has_dpi_shift;
uint8_t corded;
uint8_t wireless;
struct hidpp20_profile profiles[0];
};
/**

View File

@@ -24,18 +24,19 @@
*/
#include <assert.h>
#include <errno.h>
#include <stdbool.h>
#include <stdlib.h>
#include <sys/ioctl.h>
#include <linux/hidraw.h>
#include "usb-ids.h"
#include "hidpp10.h"
#include "libratbag-util.h"
#include "liblur.h"
#define _EXPORT_ __attribute__ ((visibility("default")))
#define MAX_DEVICES 6
#define VENDOR_ID_LOGITECH 0x046d
struct lur_receiver {
int refcount;
@@ -50,6 +51,7 @@ struct lur_receiver {
struct lur_device {
struct lur_receiver *receiver;
int refcount;
void *userdata;
char *name;
uint16_t vid, pid;
@@ -111,7 +113,7 @@ lur_device_disconnect(struct lur_device *dev)
_EXPORT_ int
lur_is_receiver(uint16_t vid, uint16_t pid)
{
return (vid == VENDOR_ID_LOGITECH && (pid == 0xc52b || pid == 0xc532));
return (vid == USB_VENDOR_ID_LOGITECH && (pid == 0xc52b || pid == 0xc532));
}
static bool
@@ -140,13 +142,13 @@ hidpp10_init(int fd)
HIDPP10_PROFILE_UNKNOWN);
}
_EXPORT_ struct lur_receiver*
lur_receiver_new_from_hidraw(int fd, void *userdata)
_EXPORT_ int
lur_receiver_new_from_hidraw(int fd, void *userdata, struct lur_receiver **out)
{
struct lur_receiver *receiver;
if (!hidraw_is_receiver(fd))
return NULL;
return -EINVAL;
receiver = zalloc(sizeof(*receiver));
receiver->refcount = 1;
@@ -158,11 +160,12 @@ lur_receiver_new_from_hidraw(int fd, void *userdata)
if (!receiver->hidppdev)
goto error;
return receiver;
*out = receiver;
return 0;
error:
free(receiver);
return NULL;
return -errno;
}
@@ -229,7 +232,7 @@ lur_receiver_enumerate(struct lur_receiver *lur,
lur_receiver_ref(lur);
dev->refcount = 1;
dev->name = strdup_safe(name);
dev->vid = VENDOR_ID_LOGITECH;
dev->vid = USB_VENDOR_ID_LOGITECH;
dev->pid = wpid;
dev->type = type;
dev->serial = serial;
@@ -347,3 +350,15 @@ lur_device_unref(struct lur_device *dev)
return NULL;
}
_EXPORT_ void
lur_device_set_user_data(struct lur_device *dev, void *userdata)
{
dev->userdata = userdata;
}
_EXPORT_ void*
lur_device_get_user_data(const struct lur_device *dev)
{
return dev->userdata;
}

View File

@@ -85,8 +85,8 @@ int
lur_device_disconnect(struct lur_device *dev);
/**
* Returns non-zero if a device with the given vid/pid is a logitech
* unifying receiver device.
* Returns non-zero if a device with the given vid/pid is a Logitech
* Unifying Receiver device.
*
* @param vid The vendor ID
* @param pid The product ID
@@ -107,11 +107,16 @@ lur_is_receiver(uint16_t vid, uint16_t pid);
*
* @param fd An O_RDWR file descriptor pointing to a /dev/hidraw node
* @param userdata Caller-specific data
* @param lur Set to the lur object on success, otherwise unmodified
*
* @return A lur object, or NULL on error.
* @return 0 on success or a negative errno on error
* @retval -EINVAL The fd does not point to a lur receiver
*
* @note liblur does not have OOM handling. If an allocation fails, liblur
* will simply abort()
*/
struct lur_receiver*
lur_receiver_new_from_hidraw(int fd, void *userdata);
int
lur_receiver_new_from_hidraw(int fd, void *userdata, struct lur_receiver **lur);
/**
* Enumerate devices currently paired with the given receiver.
@@ -239,6 +244,27 @@ lur_device_ref(struct lur_device *dev);
struct lur_device *
lur_device_unref(struct lur_device *dev);
/**
* Set caller-specific data associated with this object. liblur does
* not manage, look at, or modify this data. The caller must ensure the
* data is valid.
*
* @param dev A valid device object
* @param userdata Caller-specific data
*/
void
lur_device_set_user_data(struct lur_device *dev, void *userdata);
/**
* Get the caller-specific data associated with this object, if any.
*
* @param dev A valid device object
* @return The caller-specific data previously assigned in
* lur_device_set_user_data().
*/
void*
lur_device_get_user_data(const struct lur_device *dev);
#ifdef __cplusplus
}
#endif

13
src/liblur.pc.in Normal file
View File

@@ -0,0 +1,13 @@
prefix=@prefix@
exec_prefix=@exec_prefix@
datarootdir=@datarootdir@
pkgdatadir=@datadir@/@PACKAGE@
libdir=@libdir@
includedir=@includedir@
Name: Liblur
Description: Logitech Unifying Receiver configuration library
Version: @LIBRATBAG_VERSION@
Cflags: -I${includedir}
Libs: -L${libdir} -llur
Libs.private: -lm -lrt

28
src/liblur.sym Normal file
View File

@@ -0,0 +1,28 @@
/* in alphabetical order! */
LIBLUR_0.4.0 {
global:
lur_device_disconnect;
lur_device_get_name;
lur_device_get_product_id;
lur_device_get_serial;
lur_device_get_type;
lur_device_get_user_data;
lur_device_get_vendor_id;
lur_device_ref;
lur_device_set_user_data;
lur_device_unref;
lur_is_receiver;
lur_receiver_close;
lur_receiver_enumerate;
lur_receiver_get_fd;
lur_receiver_get_user_data;
lur_receiver_new_from_hidraw;
lur_receiver_open;
lur_receiver_ref;
lur_receiver_set_user_data;
lur_receiver_unref;
local:
*;
};

View File

@@ -1417,14 +1417,12 @@ ratbag_find_hidraw_node(struct ratbag_device *device,
goto skip;
matched = match(device);
if (matched == 1) {
rc = 0;
rc = matched ? 0 : -ENODEV;
if (matched == 1)
goto out;
}
skip:
ratbag_close_hidraw(device);
rc = -ENODEV;
}
out:

View File

@@ -250,6 +250,11 @@ struct ratbag_macro {
struct ratbag_macro_event events[MAX_MACRO_EVENTS];
};
struct ratbag_button_macro {
int refcount;
struct ratbag_macro macro;
};
struct ratbag_button_action {
enum ratbag_button_action_type type;
union ratbag_btn_action {
@@ -424,13 +429,17 @@ const char *
ratbag_device_get_udev_property(const struct ratbag_device* device,
const char *name);
struct ratbag_driver *
ratbag_find_driver(struct ratbag_device *device,
const struct input_id *dev_id,
struct ratbag_test_device *test_device);
bool
ratbag_assign_driver(struct ratbag_device *device,
const struct input_id *dev_id,
struct ratbag_test_device *test_device);
void
ratbag_register_driver(struct ratbag *ratbag, struct ratbag_driver *driver);
void
ratbag_button_copy_macro(struct ratbag_button *button,
const struct ratbag_button_macro *macro);
#endif /* LIBRATBAG_PRIVATE_H */

View File

@@ -71,7 +71,7 @@ ratbag_device_new_test_device(struct ratbag *ratbag,
device = ratbag_device_new(ratbag, NULL, "Test device", &id);
if (!ratbag_find_driver(device, &device->ids, test_device)) {
if (!ratbag_assign_driver(device, &device->ids, test_device)) {
ratbag_device_destroy(device);
return NULL;
}

View File

@@ -32,6 +32,12 @@
#define RATBAG_TEST_MAX_RESOLUTIONS 8
struct ratbag_test_button {
enum ratbag_button_action_type type;
union {
int button;
int key;
enum ratbag_button_action_special special;
};
};
struct ratbag_test_resolution {

View File

@@ -34,9 +34,27 @@
#include <unistd.h>
#include <limits.h>
#include "usb-ids.h"
#include "libratbag-private.h"
#include "libratbag-util.h"
static enum ratbag_error_code
error_code(enum ratbag_error_code code)
{
switch(code) {
case RATBAG_SUCCESS:
case RATBAG_ERROR_DEVICE:
case RATBAG_ERROR_CAPABILITY:
case RATBAG_ERROR_VALUE:
case RATBAG_ERROR_SYSTEM:
case RATBAG_ERROR_IMPLEMENTATION:
break;
default:
assert(!"Invalid error code. This is a library bug.");
}
return code;
}
static void
ratbag_profile_destroy(struct ratbag_profile *profile);
static void
@@ -156,22 +174,21 @@ ratbag_device_new(struct ratbag *ratbag, struct udev_device *udev_device,
device = zalloc(sizeof(*device));
device->name = strdup_safe(name);
if (!name) {
free(device);
return NULL;
}
device->ratbag = ratbag_ref(ratbag);
device->refcount = 1;
if (udev_device)
device->udev_device = udev_device_ref(udev_device);
device->udev_device = udev_device_ref(udev_device);
device->ids = *id;
list_init(&device->profiles);
list_insert(&ratbag->devices, &device->link);
/* We assume that most devices have this capability, so let's set it
* by default. The few devices that miss this capability should
* unset it instead.
*/
ratbag_device_set_capability(device,
RATBAG_DEVICE_CAP_QUERY_CONFIGURATION);
return device;
}
@@ -207,7 +224,6 @@ ratbag_sanity_check_device(struct ratbag_device *device)
{
struct ratbag *ratbag = device->ratbag;
_cleanup_profile_ struct ratbag_profile *profile = NULL;
_cleanup_resolution_ struct ratbag_resolution *res = NULL;
bool has_active = false;
unsigned int nres, nprofiles;
bool rc = false;
@@ -218,7 +234,7 @@ ratbag_sanity_check_device(struct ratbag_device *device)
* accidental negative */
if (device->num_profiles == 0 || device->num_profiles > 16) {
log_bug_libratbag(ratbag,
"%s: invalid number of profiles %d\n",
"%s: invalid number of profiles (%d)\n",
device->name,
device->num_profiles);
goto out;
@@ -244,8 +260,9 @@ ratbag_sanity_check_device(struct ratbag_device *device)
nres = ratbag_profile_get_num_resolutions(profile);
if (nres == 0 || nres > 16) {
log_bug_libratbag(ratbag,
"%s: minimum 1 resolution required\n",
device->name);
"%s: invalid number of resolutions (%d)\n",
device->name,
nres);
goto out;
}
@@ -256,7 +273,7 @@ ratbag_sanity_check_device(struct ratbag_device *device)
/* Require 1 active profile */
if (!has_active) {
log_bug_libratbag(ratbag,
"%s: no active profile found\n",
"%s: no profile set as active profile\n",
device->name);
goto out;
}
@@ -267,23 +284,15 @@ out:
return rc;
}
struct ratbag_driver *
ratbag_find_driver(struct ratbag_device *device,
static inline bool
ratbag_test_driver(struct ratbag_device *device,
const struct input_id *dev_id,
const char *driver_name,
struct ratbag_test_device *test_device)
{
struct ratbag *ratbag = device->ratbag;
struct ratbag_driver *driver;
int rc;
const char *driver_name;
if (!test_device) {
driver_name = udev_prop_value(device->udev_device, "RATBAG_DRIVER");
if (!driver_name)
return NULL;
} else {
driver_name = "test_driver";
}
list_for_each(driver, &ratbag->drivers, link) {
if (streq(driver->id, driver_name)) {
@@ -293,9 +302,9 @@ ratbag_find_driver(struct ratbag_device *device,
}
if (!device->driver) {
log_error(ratbag, "%s: driver specified in hwdb not found: %s\n",
log_error(ratbag, "%s: driver '%s' does not exist\n",
device->name, driver_name);
return NULL;
goto error;
}
if (test_device)
@@ -304,21 +313,62 @@ ratbag_find_driver(struct ratbag_device *device,
rc = device->driver->probe(device);
if (rc == 0) {
if (!ratbag_sanity_check_device(device)) {
return NULL;
goto error;
} else {
log_debug(ratbag, "driver match found: %s\n", driver->name);
return device->driver;
log_debug(ratbag,
"driver match found: %s\n",
device->driver->name);
return true;
}
}
if (rc != -ENODEV)
log_error(ratbag, "%s: error opening hidraw node (%s)\n",
device->name, strerror(-rc));
error:
device->driver = NULL;
if (rc != -ENODEV) {
log_error(ratbag, "%s: no hidraw device found", device->name);
return NULL;
return false;
}
static inline bool
ratbag_driver_fallback_logitech(struct ratbag_device *device,
const struct input_id *dev_id)
{
int rc;
if (dev_id->vendor != USB_VENDOR_ID_LOGITECH)
return false;
rc = ratbag_test_driver(device, dev_id, "hidpp20", NULL);
if (!rc)
rc = ratbag_test_driver(device, dev_id, "hidpp10", NULL);
return rc;
}
bool
ratbag_assign_driver(struct ratbag_device *device,
const struct input_id *dev_id,
struct ratbag_test_device *test_device)
{
bool rc;
const char *driver_name;
if (!test_device) {
driver_name = udev_prop_value(device->udev_device, "RATBAG_DRIVER");
} else {
driver_name = "test_driver";
}
return NULL;
if (driver_name) {
rc = ratbag_test_driver(device, dev_id, driver_name, test_device);
} else {
rc = ratbag_driver_fallback_logitech(device, dev_id);
}
return rc;
}
static inline char*
@@ -330,7 +380,7 @@ get_device_name(struct udev_device *device)
if (!prop)
return NULL;
/* udev name is inclosed by " */
/* udev name is enclosed by " */
return strndup(&prop[1], strlen(prop) - 2);
}
@@ -354,52 +404,47 @@ get_product_id(struct udev_device *device, struct input_id *id)
return 0;
}
LIBRATBAG_EXPORT struct ratbag_device*
LIBRATBAG_EXPORT enum ratbag_error_code
ratbag_device_new_from_udev_device(struct ratbag *ratbag,
struct udev_device *udev_device)
struct udev_device *udev_device,
struct ratbag_device **device_out)
{
struct ratbag_device *device = NULL;
struct ratbag_driver *driver;
char *name = NULL;
enum ratbag_error_code error = RATBAG_ERROR_DEVICE;
_cleanup_free_ char *name = NULL;
struct input_id id;
if (!ratbag) {
fprintf(stderr, "ratbag is NULL\n");
return NULL;
}
assert(ratbag != NULL);
assert(udev_device != NULL);
assert(device_out != NULL);
if (!udev_device) {
log_bug_client(ratbag, "udev device is NULL.\n");
return NULL;
}
if (udev_prop_value(udev_device, "ID_INPUT_MOUSE") == NULL)
goto out_err;
if (get_product_id(udev_device, &id) != 0)
goto out_err;
name = get_device_name(udev_device);
if (!name) {
errno = ENOMEM;
if (!name)
goto out_err;
}
device = ratbag_device_new(ratbag, udev_device, name, &id);
free(name);
if (!device)
goto out_err;
driver = ratbag_find_driver(device, &device->ids, NULL);
if (!driver) {
errno = ENOTSUP;
if (!ratbag_assign_driver(device, &device->ids, NULL))
goto out_err;
}
return device;
error = RATBAG_SUCCESS;
out_err:
ratbag_device_destroy(device);
return NULL;
if (error != RATBAG_SUCCESS)
ratbag_device_destroy(device);
else
*device_out = device;
return error_code(error);
}
LIBRATBAG_EXPORT struct ratbag_device *
@@ -461,14 +506,13 @@ ratbag_register_driver(struct ratbag *ratbag, struct ratbag_driver *driver)
LIBRATBAG_EXPORT struct ratbag *
ratbag_create_context(const struct ratbag_interface *interface,
void *userdata)
void *userdata)
{
struct ratbag *ratbag;
if (interface == NULL ||
interface->open_restricted == NULL ||
interface->close_restricted == NULL)
return NULL;
assert(interface != NULL);
assert(interface->open_restricted != NULL);
assert(interface->close_restricted != NULL);
ratbag = zalloc(sizeof(*ratbag));
ratbag->refcount = 1;
@@ -654,8 +698,10 @@ ratbag_device_get_profile(struct ratbag_device *device, unsigned int index)
{
struct ratbag_profile *profile;
if (index >= ratbag_device_get_num_profiles(device))
if (index >= ratbag_device_get_num_profiles(device)) {
log_bug_client(device->ratbag, "Requested invalid profile %d\n", index);
return NULL;
}
list_for_each(profile, &device->profiles, link) {
if (profile->index == index)
@@ -702,34 +748,34 @@ ratbag_device_has_capability(const struct ratbag_device *device,
return !!(device->capabilities & (1UL << cap));
}
LIBRATBAG_EXPORT int
LIBRATBAG_EXPORT enum ratbag_error_code
ratbag_profile_set_active(struct ratbag_profile *profile)
{
struct ratbag_device *device = profile->device;
struct ratbag_profile *p;
int rc;
if (!ratbag_device_has_capability(device, RATBAG_DEVICE_CAP_SWITCHABLE_PROFILE))
return RATBAG_ERROR_CAPABILITY;
assert(device->driver->write_profile);
rc = device->driver->write_profile(profile);
if (rc)
return rc;
if (ratbag_device_has_capability(device, RATBAG_DEVICE_CAP_SWITCHABLE_PROFILE)) {
assert(device->driver->set_active_profile);
rc = device->driver->set_active_profile(device, profile->index);
}
return RATBAG_ERROR_DEVICE;
assert(device->driver->set_active_profile);
rc = device->driver->set_active_profile(device, profile->index);
if (rc)
return rc;
return RATBAG_ERROR_DEVICE;
list_for_each(p, &device->profiles, link) {
list_for_each(p, &device->profiles, link)
p->is_active = false;
}
profile->is_active = true;
return rc;
return RATBAG_SUCCESS;
}
LIBRATBAG_EXPORT int
LIBRATBAG_EXPORT unsigned int
ratbag_profile_get_num_resolutions(struct ratbag_profile *profile)
{
return profile->resolution.num_modes;
@@ -739,10 +785,13 @@ LIBRATBAG_EXPORT struct ratbag_resolution *
ratbag_profile_get_resolution(struct ratbag_profile *profile, unsigned int idx)
{
struct ratbag_resolution *res;
int max = ratbag_profile_get_num_resolutions(profile);
unsigned max = ratbag_profile_get_num_resolutions(profile);
if (max < 0 || idx >= (unsigned int)max)
if (idx >= max) {
log_bug_client(profile->device->ratbag,
"Requested invalid resolution %d\n", idx);
return NULL;
}
res = &profile->resolution.modes[idx];
@@ -788,42 +837,48 @@ ratbag_resolution_has_capability(struct ratbag_resolution *resolution,
return !!(resolution->capabilities & (1 << cap));
}
LIBRATBAG_EXPORT int
LIBRATBAG_EXPORT enum ratbag_error_code
ratbag_resolution_set_dpi(struct ratbag_resolution *resolution,
unsigned int dpi)
{
struct ratbag_profile *profile = resolution->profile;
int rc;
resolution->dpi_x = dpi;
resolution->dpi_y = dpi;
assert(profile->device->driver->write_resolution_dpi);
return profile->device->driver->write_resolution_dpi(resolution, dpi, dpi);
rc = profile->device->driver->write_resolution_dpi(resolution, dpi, dpi);
return rc == 0 ? RATBAG_SUCCESS : RATBAG_ERROR_DEVICE;
}
LIBRATBAG_EXPORT int
LIBRATBAG_EXPORT enum ratbag_error_code
ratbag_resolution_set_dpi_xy(struct ratbag_resolution *resolution,
unsigned int x, unsigned int y)
{
struct ratbag_profile *profile = resolution->profile;
int rc;
if (!ratbag_resolution_has_capability(resolution,
RATBAG_RESOLUTION_CAP_SEPARATE_XY_RESOLUTION))
return -1;
return RATBAG_ERROR_CAPABILITY;
if ((x == 0 && y != 0) || (x != 0 && y == 0))
return -1;
return RATBAG_ERROR_VALUE;
assert(profile->device->driver->write_resolution_dpi);
return profile->device->driver->write_resolution_dpi(resolution, x, y);
rc = profile->device->driver->write_resolution_dpi(resolution, x, y);
return rc == 0 ? RATBAG_SUCCESS : RATBAG_ERROR_DEVICE;
}
LIBRATBAG_EXPORT int
LIBRATBAG_EXPORT enum ratbag_error_code
ratbag_resolution_set_report_rate(struct ratbag_resolution *resolution,
unsigned int hz)
{
resolution->hz = hz;
/* FIXME: call into the driver */
return 0;
return RATBAG_ERROR_IMPLEMENTATION;
}
LIBRATBAG_EXPORT int
@@ -856,12 +911,12 @@ ratbag_resolution_is_active(const struct ratbag_resolution *resolution)
return resolution->is_active;
}
LIBRATBAG_EXPORT int
LIBRATBAG_EXPORT enum ratbag_error_code
ratbag_resolution_set_active(struct ratbag_resolution *resolution)
{
resolution->is_active = true;
/* FIXME: call into the driver */
return 0;
return RATBAG_ERROR_IMPLEMENTATION;
}
@@ -871,12 +926,12 @@ ratbag_resolution_is_default(const struct ratbag_resolution *resolution)
return resolution->is_default;
}
LIBRATBAG_EXPORT int
LIBRATBAG_EXPORT enum ratbag_error_code
ratbag_resolution_set_default(struct ratbag_resolution *resolution)
{
resolution->is_default = true;
/* FIXME: call into the driver */
return 0;
return RATBAG_ERROR_IMPLEMENTATION;
}
LIBRATBAG_EXPORT struct ratbag_button*
@@ -886,8 +941,10 @@ ratbag_profile_get_button(struct ratbag_profile *profile,
struct ratbag_device *device = profile->device;
struct ratbag_button *button;
if (index >= ratbag_device_get_num_buttons(device))
if (index >= ratbag_device_get_num_buttons(device)) {
log_bug_client(device->ratbag, "Requested invalid button %d\n", index);
return NULL;
}
list_for_each(button, &profile->buttons, link) {
if (button->index == index)
@@ -938,50 +995,56 @@ ratbag_button_get_button(struct ratbag_button *button)
return button->action.action.button;
}
LIBRATBAG_EXPORT int
LIBRATBAG_EXPORT enum ratbag_error_code
ratbag_button_set_button(struct ratbag_button *button, unsigned int btn)
{
struct ratbag_button_action action;
struct ratbag_button_action action = {0};
int rc;
if (!button->profile->device->driver->write_button)
return -ENOTSUP;
return RATBAG_ERROR_CAPABILITY;
action.type = RATBAG_BUTTON_ACTION_TYPE_BUTTON;
action.action.button = btn;
rc = button->profile->device->driver->write_button(button, &action);
return rc;
if (rc == 0)
button->action = action;
return rc == 0 ? RATBAG_SUCCESS : RATBAG_ERROR_DEVICE;
}
LIBRATBAG_EXPORT enum ratbag_button_action_special
ratbag_button_get_special(struct ratbag_button *button)
{
if (button->action.type != RATBAG_BUTTON_ACTION_TYPE_SPECIAL)
return 0;
return RATBAG_BUTTON_ACTION_SPECIAL_INVALID;
return button->action.action.special;
}
LIBRATBAG_EXPORT int
LIBRATBAG_EXPORT enum ratbag_error_code
ratbag_button_set_special(struct ratbag_button *button,
enum ratbag_button_action_special act)
{
struct ratbag_button_action action;
struct ratbag_button_action action = {0};
int rc;
/* FIXME: range checks */
if (!button->profile->device->driver->write_button)
return -1;
return RATBAG_ERROR_CAPABILITY;
action.type = RATBAG_BUTTON_ACTION_TYPE_SPECIAL;
action.action.special = act;
rc = button->profile->device->driver->write_button(button, &action);
return rc;
if (rc == 0)
button->action = action;
return rc == 0 ? RATBAG_SUCCESS : RATBAG_ERROR_DEVICE;
}
LIBRATBAG_EXPORT unsigned int
@@ -997,19 +1060,19 @@ ratbag_button_get_key(struct ratbag_button *button,
return button->action.action.key.key;
}
LIBRATBAG_EXPORT int
LIBRATBAG_EXPORT enum ratbag_error_code
ratbag_button_set_key(struct ratbag_button *button,
unsigned int key,
unsigned int *modifiers,
size_t sz)
{
struct ratbag_button_action action;
struct ratbag_button_action action = {0};
int rc;
/* FIXME: range checks */
if (!button->profile->device->driver->write_button)
return -1;
return RATBAG_ERROR_CAPABILITY;
/* FIXME: modifiers */
@@ -1017,22 +1080,28 @@ ratbag_button_set_key(struct ratbag_button *button,
action.action.key.key = key;
rc = button->profile->device->driver->write_button(button, &action);
return rc;
if (rc == 0)
button->action = action;
return rc == 0 ? RATBAG_SUCCESS : RATBAG_ERROR_DEVICE;
}
LIBRATBAG_EXPORT int
LIBRATBAG_EXPORT enum ratbag_error_code
ratbag_button_disable(struct ratbag_button *button)
{
struct ratbag_button_action action;
int rc;
if (!button->profile->device->driver->write_button)
return -1;
return RATBAG_ERROR_CAPABILITY;
action.type = RATBAG_BUTTON_ACTION_TYPE_NONE;
rc = button->profile->device->driver->write_button(button, &action);
return rc;
if (rc == 0)
button->action = action;
return rc == 0 ? RATBAG_SUCCESS : RATBAG_ERROR_DEVICE;
}
LIBRATBAG_EXPORT struct ratbag_button *
@@ -1131,8 +1200,25 @@ ratbag_resolution_get_user_data(const struct ratbag_resolution *ratbag_resolutio
return ratbag_resolution->userdata;
}
LIBRATBAG_EXPORT int
ratbag_button_set_macro(struct ratbag_button *button, const char *name)
LIBRATBAG_EXPORT struct ratbag_button_macro *
ratbag_button_get_macro(struct ratbag_button *button)
{
struct ratbag_button_macro *macro;
if (button->action.type != RATBAG_BUTTON_ACTION_TYPE_MACRO)
return NULL;
macro = ratbag_button_macro_new(button->action.macro->name);
memcpy(macro->macro.events,
button->action.macro->events,
sizeof(macro->macro.events));
return macro;
}
void
ratbag_button_copy_macro(struct ratbag_button *button,
const struct ratbag_button_macro *macro)
{
if (!button->action.macro)
button->action.macro = zalloc(sizeof(struct ratbag_macro));
@@ -1143,24 +1229,36 @@ ratbag_button_set_macro(struct ratbag_button *button, const char *name)
}
button->action.type = RATBAG_BUTTON_ACTION_TYPE_MACRO;
button->action.macro->name = strdup_safe(name);
return 0;
memcpy(button->action.macro->events,
macro->macro.events,
sizeof(macro->macro.events));
button->action.macro->name = strdup_safe(macro->macro.name);
button->action.macro->group = strdup_safe(macro->macro.group);
}
LIBRATBAG_EXPORT int
ratbag_button_set_macro_event(struct ratbag_button *button,
LIBRATBAG_EXPORT enum ratbag_error_code
ratbag_button_set_macro(struct ratbag_button *button,
const struct ratbag_button_macro *macro)
{
int rc;
ratbag_button_copy_macro(button, macro);
rc = button->profile->device->driver->write_button(button, &button->action);
return rc == 0 ? RATBAG_SUCCESS : RATBAG_ERROR_DEVICE;
}
LIBRATBAG_EXPORT enum ratbag_error_code
ratbag_button_macro_set_event(struct ratbag_button_macro *m,
unsigned int index,
enum ratbag_macro_event_type type,
unsigned int data)
{
struct ratbag_macro *macro;
struct ratbag_macro *macro = &m->macro;
if (button->action.type != RATBAG_BUTTON_ACTION_TYPE_MACRO ||
index >= MAX_MACRO_EVENTS)
return -EINVAL;
macro = button->action.macro;
if (index >= MAX_MACRO_EVENTS)
return RATBAG_ERROR_VALUE;
switch (type) {
case RATBAG_MACRO_EVENT_KEY_PRESSED:
@@ -1176,39 +1274,28 @@ ratbag_button_set_macro_event(struct ratbag_button *button,
macro->events[index].type = type;
break;
default:
return -EINVAL;
return RATBAG_ERROR_VALUE;
}
return 0;
}
LIBRATBAG_EXPORT int
ratbag_button_write_macro(struct ratbag_button *button)
{
return button->profile->device->driver->write_button(button, &button->action);
}
LIBRATBAG_EXPORT enum ratbag_macro_event_type
ratbag_button_get_macro_event_type(struct ratbag_button *button, unsigned int index)
ratbag_button_macro_get_event_type(struct ratbag_button_macro *macro, unsigned int index)
{
if (button->action.type != RATBAG_BUTTON_ACTION_TYPE_MACRO ||
index >= MAX_MACRO_EVENTS)
if (index >= MAX_MACRO_EVENTS)
return RATBAG_MACRO_EVENT_INVALID;
return button->action.macro->events[index].type;
return macro->macro.events[index].type;
}
LIBRATBAG_EXPORT int
ratbag_button_get_macro_event_key(struct ratbag_button *button, unsigned int index)
ratbag_button_macro_get_event_key(struct ratbag_button_macro *m, unsigned int index)
{
struct ratbag_macro *macro;
struct ratbag_macro *macro = &m->macro;
if (button->action.type != RATBAG_BUTTON_ACTION_TYPE_MACRO ||
index >= MAX_MACRO_EVENTS)
return -EINVAL;
macro = button->action.macro;
if (index >= MAX_MACRO_EVENTS)
return 0;
if (macro->events[index].type != RATBAG_MACRO_EVENT_KEY_PRESSED &&
macro->events[index].type != RATBAG_MACRO_EVENT_KEY_RELEASED)
@@ -1218,27 +1305,72 @@ ratbag_button_get_macro_event_key(struct ratbag_button *button, unsigned int ind
}
LIBRATBAG_EXPORT int
ratbag_button_get_macro_event_timeout(struct ratbag_button *button, unsigned int index)
ratbag_button_macro_get_event_timeout(struct ratbag_button_macro *m,
unsigned int index)
{
struct ratbag_macro *macro;
struct ratbag_macro *macro = &m->macro;
if (button->action.type != RATBAG_BUTTON_ACTION_TYPE_MACRO ||
index >= MAX_MACRO_EVENTS)
return -EINVAL;
macro = button->action.macro;
if (index >= MAX_MACRO_EVENTS)
return 0;
if (macro->events[index].type != RATBAG_MACRO_EVENT_WAIT)
return -EINVAL;
return 0;
return macro->events[index].event.timeout;
}
LIBRATBAG_EXPORT const char *
ratbag_button_get_macro_name(struct ratbag_button *button)
LIBRATBAG_EXPORT unsigned int
ratbag_button_macro_get_num_events(struct ratbag_button_macro *macro)
{
if (button->action.type != RATBAG_BUTTON_ACTION_TYPE_MACRO)
return MAX_MACRO_EVENTS;
}
LIBRATBAG_EXPORT const char *
ratbag_button_macro_get_name(struct ratbag_button_macro *macro)
{
return macro->macro.name;
}
static void
ratbag_button_macro_destroy(struct ratbag_button_macro *macro)
{
assert(macro->refcount == 0);
free(macro->macro.name);
free(macro->macro.group);
free(macro);
}
LIBRATBAG_EXPORT struct ratbag_button_macro *
ratbag_button_macro_ref(struct ratbag_button_macro *macro)
{
assert(macro->refcount < INT_MAX);
macro->refcount++;
return macro;
}
LIBRATBAG_EXPORT struct ratbag_button_macro *
ratbag_button_macro_unref(struct ratbag_button_macro *macro)
{
if (macro == NULL)
return NULL;
return button->action.macro->name;
assert(macro->refcount > 0);
macro->refcount--;
if (macro->refcount == 0)
ratbag_button_macro_destroy(macro);
return NULL;
}
LIBRATBAG_EXPORT struct ratbag_button_macro *
ratbag_button_macro_new(const char *name)
{
struct ratbag_button_macro *macro;
macro = zalloc(sizeof *macro);
macro->refcount = 1;
macro->macro.name = strdup_safe(name);
return macro;
}

View File

@@ -125,6 +125,59 @@ struct ratbag_button;
*/
struct ratbag_resolution;
/**
* @ingroup button
* @struct ratbag_macro
*
* Represents a macro that can be assigned to a button.
*
* This struct is refcounted, use ratbag_button_macro_ref() and
* ratbag_button_macro_unref().
*/
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 requestd 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
@@ -325,12 +378,18 @@ ratbag_unref(struct ratbag *ratbag);
* The device is refcounted with an initial value of at least 1.
* Use ratbag_device_unref() to release the device.
*
* @return A new device based on the udev device, or NULL in case of
* failure.
* @param ratbag A previously initialized ratbag context
* @param udev_device The udev device that points at the device
* @param device Set to a new device based on the udev device.
*
* @return 0 on success or the error.
* @retval RATBAG_ERROR_DEVICE The given device does not exist or is not
* supported by libratbag.
*/
struct ratbag_device*
enum ratbag_error_code
ratbag_device_new_from_udev_device(struct ratbag *ratbag,
struct udev_device *device);
struct udev_device *udev_device,
struct ratbag_device **device);
/**
* @ingroup device
@@ -443,6 +502,23 @@ enum ratbag_device_capability {
* last-used profile or a specific profile (usually the first).
*/
RATBAG_DEVICE_CAP_DEFAULT_PROFILE,
/**
* 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,
};
/**
@@ -583,9 +659,9 @@ ratbag_profile_is_active(struct ratbag_profile *profile);
*
* @param profile The profile to make the active profile.
*
* @return 0 on success or nonzero otherwise.
* @return 0 on success or an error code otherwise
*/
int
enum ratbag_error_code
ratbag_profile_set_active(struct ratbag_profile *profile);
/**
@@ -603,7 +679,7 @@ ratbag_profile_set_active(struct ratbag_profile *profile);
*
* @return The number of profiles available.
*/
int
unsigned int
ratbag_profile_get_num_resolutions(struct ratbag_profile *profile);
/**
@@ -723,9 +799,9 @@ ratbag_resolution_has_capability(struct ratbag_resolution *resolution,
* @param resolution A previously initialized ratbag resolution
* @param dpi Set to the resolution in dpi, 0 to disable
*
* @return zero on success, non-zero otherwise
* @return zero on success or an error code on failure
*/
int
enum ratbag_error_code
ratbag_resolution_set_dpi(struct ratbag_resolution *resolution,
unsigned int dpi);
@@ -749,9 +825,9 @@ ratbag_resolution_set_dpi(struct ratbag_resolution *resolution,
* @param x The x resolution in dpi
* @param y The y resolution in dpi
*
* @return zero on success, non-zero otherwise
* @return zero on success or an error code on failure
*/
int
enum ratbag_error_code
ratbag_resolution_set_dpi_xy(struct ratbag_resolution *resolution,
unsigned int x, unsigned int y);
@@ -819,9 +895,9 @@ ratbag_resolution_get_dpi_y(struct ratbag_resolution *resolution);
* @param resolution A previously initialized ratbag resolution
* @param hz Set to the report rate in Hz, may be 0
*
* @return zero on success, non-zero otherwise
* @return zero on success or an error code on failure
*/
int
enum ratbag_error_code
ratbag_resolution_set_report_rate(struct ratbag_resolution *resolution,
unsigned int hz);
@@ -839,7 +915,7 @@ ratbag_resolution_set_report_rate(struct ratbag_resolution *resolution,
*
* @param resolution A previously initialized ratbag resolution
*
* @return zero on success, non-zero otherwise
* @return The report rate for this resolution in Hz
*/
int
ratbag_resolution_get_report_rate(struct ratbag_resolution *resolution);
@@ -855,9 +931,9 @@ ratbag_resolution_get_report_rate(struct ratbag_resolution *resolution);
*
* @param resolution A previously initialized ratbag resolution
*
* @return zero on success, non-zero otherwise
* @return zero on success or an error code on failure
*/
int
enum ratbag_error_code
ratbag_resolution_set_active(struct ratbag_resolution *resolution);
/**
@@ -889,9 +965,9 @@ ratbag_resolution_is_active(const struct ratbag_resolution *resolution);
*
* @param resolution A previously initialized ratbag resolution
*
* @return zero on success, non-zero otherwise
* @return zero on success or an error code on failure
*/
int
enum ratbag_error_code
ratbag_resolution_set_default(struct ratbag_resolution *resolution);
/**
@@ -927,7 +1003,7 @@ ratbag_resolution_is_default(const struct ratbag_resolution *resolution);
*
* @return A button context, or NULL if the button does not exist.
*
* @see ratbag_get_num_buttons
* @see ratbag_device_get_num_buttons
*/
struct ratbag_button*
ratbag_profile_get_button(struct ratbag_profile *profile, unsigned int index);
@@ -1148,12 +1224,12 @@ ratbag_button_get_button(struct ratbag_button *button);
*
* @param button A previously initialized ratbag button
* @param btn The logical button number to assign to this button.
* @return 0 on success or nonzero otherwise. On success, the button's
* @return 0 on success or an error code otherwise. On success, the button's
* action is set to @ref RATBAG_BUTTON_ACTION_TYPE_BUTTON.
*
* @see ratbag_button_get_button
*/
int
enum ratbag_error_code
ratbag_button_set_button(struct ratbag_button *button,
unsigned int btn);
@@ -1180,12 +1256,12 @@ ratbag_button_get_special(struct ratbag_button *button);
*
* @param button A previously initialized ratbag button
* @param action The special action to assign to this button.
* @return 0 on success or nonzero otherwise. On success, the button's
* @return 0 on success or an error code otherwise. On success, the button's
* action is set to @ref RATBAG_BUTTON_ACTION_TYPE_SPECIAL.
*
* @see ratbag_button_get_button
*/
int
enum ratbag_error_code
ratbag_button_set_special(struct ratbag_button *button,
enum ratbag_button_action_special action);
@@ -1226,10 +1302,10 @@ ratbag_button_get_key(struct ratbag_button *button,
* @param sz The size of the modifiers array. sz may be 0 if no modifiers
* are required.
*
* @return 0 on success or nonzero otherwise. On success, the button's
* @return 0 on success or an error code otherwise. On success, the button's
* action is set to @ref RATBAG_BUTTON_ACTION_TYPE_KEY.
*/
int
enum ratbag_error_code
ratbag_button_set_key(struct ratbag_button *button,
unsigned int key,
unsigned int *modifiers,
@@ -1240,10 +1316,10 @@ ratbag_button_set_key(struct ratbag_button *button,
*
* @param button A previously initialized ratbag button
*
* @return 0 on success or nonzero otherwise. On success, the button's
* @return 0 on success or an error code otherwise. On success, the button's
* action is set to @ref RATBAG_BUTTON_ACTION_TYPE_NONE.
*/
int
enum ratbag_error_code
ratbag_button_disable(struct ratbag_button *button);
/**
@@ -1262,101 +1338,175 @@ enum ratbag_macro_event_type {
/**
* @ingroup button
*
* If a button's action is @ref RATBAG_BUTTON_ACTION_TYPE_MACRO,
* this function returns the macro name.
* @param macro A previously initialized ratbag button macro
*
* If the button's action type is not @ref RATBAG_BUTTON_ACTION_TYPE_MACRO,
* this function returns NULL.
*
* @param button A previously initialized ratbag button
*
* @return The name of the macro associated to the button.
* @return The name of the macro
*/
const char *
ratbag_button_get_macro_name(struct ratbag_button *button);
ratbag_button_macro_get_name(struct ratbag_button_macro *macro);
/**
* @ingroup button
*
* If a button's action is @ref RATBAG_BUTTON_ACTION_TYPE_MACRO,
* this function returns the macro event type configured for the event at the
* @param macro A previously initialized ratbag button macro
*
* @return The maximum number of events that can be assigned to this macro
*/
unsigned int
ratbag_button_macro_get_num_events(struct ratbag_button_macro *macro);
/**
* @ingroup button
*
* Returns the macro event type configured for the event at the
* given index.
*
* If the button's action type is not @ref RATBAG_BUTTON_ACTION_TYPE_MACRO,
* this function returns @ref RATBAG_MACRO_EVENT_INVALID.
* The behavior of this function for an index equal to or greater than the
* return value of ratbag_button_macro_get_num_events() is undefined.
*
* @param button A previously initialized ratbag button
* @param macro A previously initialized ratbag button macro
* @param index An index of the event within the macro we are interested in.
*
* @return The type of the event at the given index
*/
enum ratbag_macro_event_type
ratbag_button_get_macro_event_type(struct ratbag_button *button, unsigned int index);
ratbag_button_macro_get_event_type(struct ratbag_button_macro *macro,
unsigned int index);
/**
* @ingroup button
*
* If a button's action is @ref RATBAG_BUTTON_ACTION_TYPE_MACRO, and if the
* event stored at the given index is @ref RATBAG_MACRO_EVENT_KEY_PRESSED or
* @ref RATBAG_MACRO_EVENT_KEY_RELEASED, this function returns the key code
* configured for the event at the given index.
* If the event stored at the given index is @ref
* RATBAG_MACRO_EVENT_KEY_PRESSED or @ref RATBAG_MACRO_EVENT_KEY_RELEASED,
* this function returns the key code configured for the event at the given
* index.
*
* If the button's action type is not @ref RATBAG_BUTTON_ACTION_TYPE_MACRO,
* or if the event stored at the given index is not
* @ref RATBAG_MACRO_EVENT_KEY_PRESSED or @ref RATBAG_MACRO_EVENT_KEY_RELEASED,
* this function returns -EINVAL.
* The behavior of this function for an index equal to or greater than the
* return value of ratbag_button_macro_get_num_events() is undefined.
*
* @param button A previously initialized ratbag button
* @param macro A previously initialized ratbag button macro
* @param index An index of the event within the macro we are interested in.
*
* @return The key of the event at the given index
*/
int
ratbag_button_get_macro_event_key(struct ratbag_button *button, unsigned int index);
ratbag_button_macro_get_event_key(struct ratbag_button_macro*macro,
unsigned int index);
/**
* @ingroup button
*
* If a button's action is @ref RATBAG_BUTTON_ACTION_TYPE_MACRO, and if the
* event stored at the given index is @ref RATBAG_MACRO_EVENT_WAIT, this
* function returns the timeout configured for the event at the given index.
* If the event stored at the given index is @ref RATBAG_MACRO_EVENT_WAIT,
* this function returns the timeout configured for the event at the given
* index.
*
* If the button's action type is not @ref RATBAG_BUTTON_ACTION_TYPE_MACRO,
* or if the event stored at the given index is not
* @ref RATBAG_MACRO_EVENT_WAIT, this function returns -EINVAL.
* The behavior of this function for an index equal to or greater than the
* return value of ratbag_button_macro_get_num_events() is undefined.
*
* @param button A previously initialized ratbag button
* @param macro A previously initialized ratbag button macro
* @param index An index of the event within the macro we are interested in.
*
* @return The tiemout of the event at the given index
* @return The timeout of the event at the given index
*/
int
ratbag_button_get_macro_event_timeout(struct ratbag_button *button, unsigned int index);
ratbag_button_macro_get_event_timeout(struct ratbag_button_macro *macro,
unsigned int index);
/**
* @ingroup button
*
* Sets the button's action to @ref RATBAG_BUTTON_ACTION_TYPE_MACRO and
* allocates the required memory to store the macro.
* assigns the given macro to this button.
*
* libratbag does not use the macro struct passed in, it extracts the
* required information from the struct. Changes to the macro after a call
* to ratbag_button_set_macro() are not reflected in the device until a
* subsequent call to ratbag_button_set_macro().
*
* @param button A previously intialized ratbag button
* @param macro A fully initialized macro
*
* @return 0 on success or nonzero otherwise
*/
int
ratbag_button_set_macro(struct ratbag_button *button, const char *name);
enum ratbag_error_code
ratbag_button_set_macro(struct ratbag_button *button,
const struct ratbag_button_macro *macro);
int
ratbag_button_write_macro(struct ratbag_button *button);
/**
* @ingroup button
*
* Initialize a new button macro.
*
* The macro is refcounted with an initial value of at least 1.
* Use ratbag_button_macro_unref() to release the macro.
*
* Note that some devices have limited storage for the macro names.
* libratbag silently shortens macro names to the longest string the device
* is capable of storing.
*
* @param name The name to assign to this macro.
*
* @return An "empty" button macro
*/
struct ratbag_button_macro *
ratbag_button_macro_new(const char *name);
/**
* @ingroup button
*
* If a button's action is @ref RATBAG_BUTTON_ACTION_TYPE_MACRO,
* this function returns the current button macro. The macro is a copy of
* the one used on the device, changes to the macro are not reflected on the
* device until a subsequent call to ratbag_button_set_macro().
*
* If a button's action is not @ref RATBAG_BUTTON_ACTION_TYPE_MACRO,
* this function returns NULL.
*
* @param button A previously initialized ratbag button
*/
struct ratbag_button_macro *
ratbag_button_get_macro(struct ratbag_button *button);
/**
* @ingroup button
*
* Sets the macro's event at the given index to the given type with the
* key code or timeout given.
*
* The behavior of this function for an index equal to or greater than the
* return value of ratbag_button_macro_get_num_events() is undefined.
*/
int
ratbag_button_set_macro_event(struct ratbag_button *button,
enum ratbag_error_code
ratbag_button_macro_set_event(struct ratbag_button_macro *macro,
unsigned int index,
enum ratbag_macro_event_type type,
unsigned int data);
/**
* @ingroup button
*
* Add a reference to the macro. A macro is destroyed whenever the
* reference count reaches 0. See @ref ratbag_button_macro_unref.
*
* @param macro A previously initialized valid ratbag button macro
* @return The passed ratbag macro
*/
struct ratbag_button_macro *
ratbag_button_macro_ref(struct ratbag_button_macro *macro);
/**
* @ingroup button
*
* Dereference the ratbag button macro. When the internal refcount reaches
* zero, all resources associated with this object are released. The object
* must be considered invalid once unref is called.
*
* @param macro A previously initialized ratbag button macro
* @return Always NULL
*/
struct ratbag_button_macro *
ratbag_button_macro_unref(struct ratbag_button_macro *macro);
/**
* @ingroup button
*

View File

@@ -1,6 +1,6 @@
/* in alphabetical order! */
LIBRATBAG_0.1.0 {
LIBRATBAG_0.3.0 {
global:
ratbag_create_context;
ratbag_button_disable;
@@ -8,22 +8,26 @@ global:
ratbag_button_get_type;
ratbag_button_get_button;
ratbag_button_get_key;
ratbag_button_get_macro_event_type;
ratbag_button_get_macro_event_key;
ratbag_button_get_macro_event_timeout;
ratbag_button_get_macro_name;
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_macro_event;
ratbag_button_set_special;
ratbag_button_set_user_data;
ratbag_button_unref;
ratbag_button_write_macro;
ratbag_device_get_name;
ratbag_device_get_num_buttons;
ratbag_device_get_num_profiles;

29
src/usb-ids.h Normal file
View File

@@ -0,0 +1,29 @@
/*
* Copyright © 2016 Red Hat, Inc.
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
* the above copyright notice appear in all copies and that both that copyright
* notice and this permission notice appear in supporting documentation, and
* that the name of the copyright holders not be used in advertising or
* publicity pertaining to distribution of the software without specific,
* written prior permission. The copyright holders make no representations
* about the suitability of this software for any purpose. It is provided "as
* is" without express or implied warranty.
*
* THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
* EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
* DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
* OF THIS SOFTWARE.
*/
#ifndef USB_IDS_H
#define USB_IDS_H
#define USB_VENDOR_ID_LOGITECH 0x046d
#endif

View File

@@ -26,12 +26,16 @@
#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 "libratbag.h"
#define _unused_ __attribute__ ((unused))
static int
open_restricted(const char *path, int flags, void *user_data)
{
@@ -65,23 +69,40 @@ END_TEST
START_TEST(context_init_bad_iface)
{
struct ratbag *lr;
struct ratbag *lr _unused_;
struct ratbag_interface iface = {
.open_restricted = NULL,
.close_restricted = NULL,
};
lr = ratbag_create_context(&iface, NULL);
ck_assert(lr == NULL);
/* abort */
}
END_TEST
iface.open_restricted = open_restricted;
lr = ratbag_create_context(&iface, NULL);
ck_assert(lr == NULL);
START_TEST(context_init_bad_iface_open)
{
struct ratbag *lr _unused_;
struct ratbag_interface iface = {
.open_restricted = open_restricted,
.close_restricted = NULL,
};
iface.open_restricted = NULL;
iface.close_restricted = close_restricted;
lr = ratbag_create_context(&iface, NULL);
ck_assert(lr == NULL);
/* abort */
}
END_TEST
START_TEST(context_init_bad_iface_close)
{
struct ratbag *lr _unused_;
struct ratbag_interface iface = {
.open_restricted = NULL,
.close_restricted = close_restricted,
};
lr = ratbag_create_context(&iface, NULL);
/* abort */
}
END_TEST
@@ -115,15 +136,19 @@ START_TEST(context_ref)
END_TEST
static Suite *
test_context_suite(void)
test_context_suite(bool using_valgrind)
{
TCase *tc;
Suite *s;
s = suite_create("context");
tc = tcase_create("init");
tcase_add_test(tc, context_init_NULL);
tcase_add_test(tc, context_init_bad_iface);
if (!using_valgrind) {
tcase_add_test_raise_signal(tc, context_init_NULL, SIGABRT);
tcase_add_test_raise_signal(tc, context_init_bad_iface, SIGABRT);
tcase_add_test_raise_signal(tc, context_init_bad_iface_open, SIGABRT);
tcase_add_test_raise_signal(tc, context_init_bad_iface_close, SIGABRT);
}
tcase_add_test(tc, context_init);
tcase_add_test(tc, context_ref);
suite_add_tcase(s, tc);
@@ -136,9 +161,14 @@ int main(void)
int nfailed;
Suite *s;
SRunner *sr;
bool using_valgrind;
s = test_context_suite();
sr = srunner_create(s);
/* when running under valgrind we're using nofork mode, so a
* signal raised by a test will fail in valgrind */
using_valgrind = !!getenv("USING_VALGRIND");
s = test_context_suite(using_valgrind);
sr = srunner_create(s);
srunner_run_all(sr, CK_ENV);
nfailed = srunner_ntests_failed(sr);

View File

@@ -649,6 +649,108 @@ START_TEST(device_and_profile_and_resolution_freed_before_button)
}
END_TEST
START_TEST(device_buttons)
{
struct ratbag *r;
struct ratbag_device *d;
struct ratbag_profile *p;
struct ratbag_button *b;
struct ratbag_button_macro *m;
int nprofiles, nbuttons;
int i, j;
int device_freed_count = 0;
struct ratbag_test_device td = sane_device;
td.num_buttons = 10;
td.profiles[0].buttons[8].type = RATBAG_BUTTON_ACTION_TYPE_MACRO;
td.destroyed_data = &device_freed_count;
r = ratbag_create_context(&abort_iface, NULL);
d = ratbag_device_new_test_device(r, &td);
nprofiles = ratbag_device_get_num_profiles(d);
ck_assert_int_eq(nprofiles, 3);
nbuttons = ratbag_device_get_num_buttons(d);
ck_assert_int_eq(nbuttons, 10);
for (i = 0; i < nprofiles; i++) {
p = ratbag_device_get_profile(d, i);
ck_assert(p != NULL);
for (j = 0; j < nbuttons; j++) {
b = ratbag_profile_get_button(p, j);
ck_assert(b != NULL);
if (ratbag_button_get_action_type(b) ==
RATBAG_BUTTON_ACTION_TYPE_MACRO) {
m = ratbag_button_get_macro(b);
ck_assert(m != NULL);
ratbag_button_macro_unref(m);
}
ratbag_button_unref(b);
}
ratbag_profile_unref(p);
}
ratbag_device_unref(d);
ratbag_unref(r);
ck_assert_int_eq(device_freed_count, 1);
}
END_TEST
START_TEST(device_buttons_ref_unref)
{
struct ratbag *r;
struct ratbag_device *d;
struct ratbag_profile *p;
struct ratbag_button *b;
struct ratbag_test_device td = sane_device;
td.num_buttons = 10;
r = ratbag_create_context(&abort_iface, NULL);
d = ratbag_device_new_test_device(r, &td);
p = ratbag_device_get_profile(d, 1);
b = ratbag_profile_get_button(p, 0);
ratbag_unref(r);
ratbag_device_unref(d);
ratbag_profile_unref(p);
ref_unref_test(ratbag_button, b);
ratbag_button_unref(b);
}
END_TEST
START_TEST(device_buttons_set)
{
struct ratbag *r;
struct ratbag_device *d;
struct ratbag_profile *p;
struct ratbag_button *b;
struct ratbag_test_device td = sane_device;
td.num_buttons = 10;
r = ratbag_create_context(&abort_iface, NULL);
d = ratbag_device_new_test_device(r, &td);
p = ratbag_device_get_profile(d, 1);
b = ratbag_profile_get_button(p, 0);
ratbag_button_set_button(b, 3);
ratbag_button_unref(b);
ratbag_profile_unref(p);
ratbag_device_unref(d);
ratbag_unref(r);
}
END_TEST
static Suite *
test_context_suite(void)
{
@@ -681,6 +783,12 @@ test_context_suite(void)
tcase_add_test(tc, device_resolutions_num_0);
suite_add_tcase(s, tc);
tc = tcase_create("buttons");
tcase_add_test(tc, device_buttons);
tcase_add_test(tc, device_buttons_ref_unref);
tcase_add_test(tc, device_buttons_set);
suite_add_tcase(s, tc);
return s;
}

View File

@@ -15,6 +15,7 @@ libshared_la_LIBADD = $(LIBUDEV_CFLAGS) $(LIBEVDEV_LIBS)
ratbag_command_SOURCES = ratbag-command.c
ratbag_command_LDADD = ../src/libratbag.la libshared.la $(LIBUDEV_LIBS) $(LIBEVDEV_LIBS)
ratbag_command_CFLAGS = $(LIBUDEV_CFLAGS) $(LIBEVDEV_CFLAGS)
dist_man1_MANS = ratbag-command.man
hidpp10_dump_page_SOURCES = hidpp10-dump-page.c
hidpp10_dump_page_LDADD = ../src/libhidpp.la
@@ -28,5 +29,4 @@ hidpp20_dump_page_CFLAGS = -I$(top_srcdir)/src
lur_command_SOURCeS = lur-command.c
lur_command_LDADD = ../src/liblur.la
lur_command_LDFLAGS = -no-install
lur_command_CFLAGS = -I$(top_srcdir)/src

View File

@@ -111,6 +111,8 @@ main(int argc, char **argv)
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);
if (argc == 2)
rc = dump_everything(dev);

View File

@@ -41,8 +41,9 @@ enum options {
static struct lur_receiver *
open_receiver(const char *path)
{
struct lur_receiver *receiver;
struct lur_receiver *receiver = NULL;
int fd = -1;
int rc;
fd = open(path, O_RDWR);
if (fd < 0) {
@@ -50,8 +51,8 @@ open_receiver(const char *path)
return NULL;
}
receiver = lur_receiver_new_from_hidraw(fd, NULL);
if (!receiver)
rc = lur_receiver_new_from_hidraw(fd, NULL, &receiver);
if (rc != 0)
close(fd);
return receiver;
@@ -242,7 +243,7 @@ main(int argc, char **argv)
return EXIT_FAILURE;
}
index = atoi(argv[3]);
index = atoi(argv[2]);
disconnect_device(receiver, index);
} else {
usage();

View File

@@ -556,6 +556,7 @@ ratbag_cmd_change_button(const struct ratbag_cmd *cmd,
struct ratbag_device *device;
struct ratbag_button *button = NULL;
struct ratbag_profile *profile = NULL;
struct ratbag_button_macro *m = NULL;
int button_index;
enum ratbag_button_action_type action_type;
int rc = ERR_DEVICE;
@@ -630,17 +631,18 @@ ratbag_cmd_change_button(const struct ratbag_cmd *cmd,
rc = ratbag_button_set_special(button, special);
break;
case RATBAG_BUTTON_ACTION_TYPE_MACRO:
rc = ratbag_button_set_macro(button, macro.name);
m = ratbag_button_macro_new(macro.name);
for (i = 0; i < ARRAY_LENGTH(macro.events); i++) {
if (macro.events[i].type == RATBAG_MACRO_EVENT_NONE)
break;
ratbag_button_set_macro_event(button,
ratbag_button_macro_set_event(m,
i,
macro.events[i].type,
macro.events[i].data);
}
rc = ratbag_button_write_macro(button);
rc = ratbag_button_set_macro(button, m);
ratbag_button_macro_unref(m);
break;
default:
error("well, that shouldn't have happened\n");
@@ -1265,6 +1267,7 @@ ratbag_cmd_button_set_macro(const struct ratbag_cmd *cmd,
{
struct ratbag_device *device;
struct ratbag_button *button;
struct ratbag_button_macro *m;
struct macro macro = {0};
int rc;
int i;
@@ -1289,17 +1292,18 @@ ratbag_cmd_button_set_macro(const struct ratbag_cmd *cmd,
return ERR_UNSUPPORTED;
button = options->button;
rc = ratbag_button_set_macro(button, macro.name);
m = ratbag_button_macro_new(macro.name);
for (i = 0; i < ARRAY_LENGTH(macro.events); i++) {
if (macro.events[i].type == RATBAG_MACRO_EVENT_NONE)
break;
ratbag_button_set_macro_event(button,
ratbag_button_macro_set_event(m,
i,
macro.events[i].type,
macro.events[i].data);
}
rc = ratbag_button_write_macro(button);
rc = ratbag_button_set_macro(button, m);
ratbag_button_macro_unref(m);
if (rc != 0)
return ERR_DEVICE;

141
tools/ratbag-command.man Normal file
View File

@@ -0,0 +1,141 @@
.TH RATBAG_COMMAND "1"
.SH NAME
ratbag-command \- Query or change a device's settings
.SH SYNOPSIS
.B ratbag-command [OPTIONS] {COMMAND} ... /path/to/device
.SH DESCRIPTION
.PP
The
.I ratbag-commandq
tool query or change a device's settings.
.PP
This tool usually needs to be run as root to have access to the
/dev/input/eventX nodes.
.SH OPTIONS
.TP 8
.B --verbose
Print debugging output
.TP 8
.B --verbose=raw
Print debugging output with protocol output. No guarantees are given regarding
the output format when this flag is on.
.TP 8
.B --help
Print the help.
.SH General Commands
.TP 8
.B list
List supported devices (does not take a device argument)
.SH Device Commands
.TP 8
.B info
Print information about a device
.SH Profile Commands
.TP 8
.B profile active get
Print the currently active profile
.TP 8
.B profile active set N
Set profile N as to the active profile
.TP 8
.B profile N {COMMAND}
Use profile N for COMMAND
.SH Resolution Commands
Resolution commands work on the given profile, or on the active profile if none
is given.
.TP 8
.B resolution active get
Print the currently active resolution
.TP 8
.B resolution active set N
Set resolution N as the active resolution
.TP 8
.B resolution N {COMMAND}
Use resolution N for COMMAND
.SH DPI Commands
DPI commands work on the given profile and resolution, or on the active
resolution of the active profile if none are given.
.TP 8
.B dpi get
Print the dpi value
.TP 8
.B dpi set N
Set the dpi value to N
.TP 8
.B rate get
Print the report rate in Hz
.TP 8
.B rate set N
Set the report rate in N Hz
.SH Button Commands
Button commands work on the given profile, or on the active profile if none is
given.
.TP 8
.B button count
Print the number of buttons
.TP 8
.B button N action get
Print the button action
.TP 8
.B button N action set button B
Set the button action to button B
.TP 8
.B button N action set special S
Set the button action to special action S
.TP 8
.B button N action set macro ...
Set the button action to the given macro
.PP
.B Macro syntax:
.HP 8
A macro is a series of key events or waiting periods. Keys must be specified
in linux/input.h key names.
.RS
.TP 8
.B KEY_A
Press and release 'a'
.TP 8
.B +KEY_A
Press 'a'
.TP 8
.B -KEY_A
Release 'a'
.TP 8
.B t300
Wait 300ms
.RE
.SH Special Commands
These commands are for testing purposes and may be removed without notice
.TP 8
.B switch-etekcity
Switch the Etekcity mouse active profile
.SH Examples
.TP 8
ratbag-command profile active get
.TP 8
ratbag-command profile 0 resolution active set 4
.TP 8
ratbag-command profile 0 resolution 1 dpi get
.TP 8
ratbag-command resolution 4 rate get
.TP 8
ratbag-command dpi set 800
.SH Exit codes
.TP 8
.B 0
Success
.TP 8
.B 1
Unsupported feature or index out of available range
.TP 8
.B 2
Commandline arguments are invalid
.TP 8
.B 3
Invalid device or a command failed on the device
.SH NOTES
.PP
There is currently no guarantees that the output format of
.B ratbag-command
will not change in the future. There should be some stability with the commands
mentioned in this man page, but do not expect it to stay the same.

View File

@@ -174,18 +174,20 @@ static const char *strip_ev_key(int key)
char *
button_action_macro_to_str(struct ratbag_button *button)
{
struct ratbag_button_macro *macro;
char str[4096] = {0};
const char *name;
int offset;
unsigned int i;
name = ratbag_button_get_macro_name(button);
macro = ratbag_button_get_macro(button);
name = ratbag_button_macro_get_name(macro);
offset = snprintf(str, sizeof(str), "macro \"%s\":",
name ? name : "UNKNOWN");
for (i = 0; i < MAX_MACRO_EVENTS; i++) {
enum ratbag_macro_event_type type = ratbag_button_get_macro_event_type(button, i);
int key = ratbag_button_get_macro_event_key(button, i);
int timeout = ratbag_button_get_macro_event_timeout(button, i);
enum ratbag_macro_event_type type = ratbag_button_macro_get_event_type(macro, i);
int key = ratbag_button_macro_get_event_key(macro, i);
int timeout = ratbag_button_macro_get_event_timeout(macro, i);
if (type == RATBAG_MACRO_EVENT_NONE)
break;
@@ -205,6 +207,8 @@ button_action_macro_to_str(struct ratbag_button *button)
}
}
ratbag_button_macro_unref(macro);
return strdup_safe(str);
}
@@ -236,13 +240,17 @@ ratbag_cmd_open_device(struct ratbag *ratbag, const char *path)
struct ratbag_device *device;
_cleanup_udev_unref_ struct udev *udev = NULL;
_cleanup_udev_device_unref_ struct udev_device *udev_device = NULL;
enum ratbag_error_code error;
udev = udev_new();
udev_device = udev_device_from_path(udev, path);
if (!udev_device)
return NULL;
device = ratbag_device_new_from_udev_device(ratbag, udev_device);
error = ratbag_device_new_from_udev_device(ratbag, udev_device,
&device);
if (error != RATBAG_SUCCESS)
return NULL;
return device;
}