mirror of
https://github.com/libratbag/libratbag.git
synced 2026-11-07 23:23:52 +01:00
Compare commits
45 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3c879b7389 | ||
|
|
44e7bc1c23 | ||
|
|
0bcaeaeb33 | ||
|
|
da60f0748c | ||
|
|
5418392143 | ||
|
|
6c18b16a00 | ||
|
|
8e5ad717c4 | ||
|
|
1ff263f0a4 | ||
|
|
e9f0ca4385 | ||
|
|
079b67f111 | ||
|
|
a224ef6d0b | ||
|
|
0c0a6d39cb | ||
|
|
3439058a54 | ||
|
|
6414f7901f | ||
|
|
4d6390ea66 | ||
|
|
3f83d5057d | ||
|
|
67f1c00181 | ||
|
|
c4013ca4b0 | ||
|
|
25294d9a63 | ||
|
|
7d241642f9 | ||
|
|
d1e42ac56c | ||
|
|
45129b2bc8 | ||
|
|
0568b4c39d | ||
|
|
5b152a6c3f | ||
|
|
52d4e35192 | ||
|
|
a1a3750bc8 | ||
|
|
3cfda944d0 | ||
|
|
852fc2da2d | ||
|
|
adefb2921b | ||
|
|
27a141fd87 | ||
|
|
2b63ca4935 | ||
|
|
107d7e652f | ||
|
|
7e8d40b57a | ||
|
|
6c40b18229 | ||
|
|
9d51d70f70 | ||
|
|
96a9a0f6a4 | ||
|
|
31b513e6d7 | ||
|
|
d831d6e515 | ||
|
|
89de42ad8e | ||
|
|
01fcef9b9d | ||
|
|
2bcacfc1ac | ||
|
|
1e2edefd93 | ||
|
|
3aabba255d | ||
|
|
e543723856 | ||
|
|
eb8e4bbfa8 |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -42,6 +42,7 @@ test-build-cxx
|
||||
test-build-linker
|
||||
test-build-pedantic-c99
|
||||
test-build-std-gnuc90
|
||||
test-iconv-helper
|
||||
test-suite.log
|
||||
test-context
|
||||
test-device
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
AC_PREREQ([2.64])
|
||||
|
||||
m4_define([libratbag_major_version], [0])
|
||||
m4_define([libratbag_minor_version], [5])
|
||||
m4_define([libratbag_minor_version], [6])
|
||||
m4_define([libratbag_micro_version], [0])
|
||||
m4_define([libratbag_version],
|
||||
[libratbag_major_version.libratbag_minor_version.libratbag_micro_version])
|
||||
@@ -30,8 +30,8 @@ AM_INIT_AUTOMAKE([1.11 foreign no-dist-gzip dist-xz])
|
||||
# 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=3:1:0
|
||||
LIBLUR_LT_VERSION=3:1:0
|
||||
LIBRATBAG_LT_VERSION=4:0:0
|
||||
LIBLUR_LT_VERSION=3:2:0
|
||||
AC_SUBST(LIBRATBAG_LT_VERSION)
|
||||
AC_SUBST(LIBLUR_LT_VERSION)
|
||||
|
||||
|
||||
1030
data/logitech-g300.svg
Normal file
1030
data/logitech-g300.svg
Normal file
File diff suppressed because it is too large
Load Diff
|
After Width: | Height: | Size: 46 KiB |
578
data/logitech-g303.svg
Normal file
578
data/logitech-g303.svg
Normal file
@@ -0,0 +1,578 @@
|
||||
<?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 198.4375 198.43751"
|
||||
version="1.1"
|
||||
id="svg124"
|
||||
inkscape:version="0.92.1 r"
|
||||
sodipodi:docname="g303_FINAL.svg">
|
||||
<defs
|
||||
id="defs118">
|
||||
<marker
|
||||
inkscape:isstock="true"
|
||||
style="overflow:visible;"
|
||||
id="marker10743"
|
||||
refX="0.0"
|
||||
refY="0.0"
|
||||
orient="auto"
|
||||
inkscape:stockid="Arrow2Mend">
|
||||
<path
|
||||
transform="scale(0.6) rotate(180) translate(0,0)"
|
||||
d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
|
||||
style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#000000;stroke-opacity:1;fill:#000000;fill-opacity:1"
|
||||
id="path10741" />
|
||||
</marker>
|
||||
<marker
|
||||
inkscape:stockid="Arrow2Mend"
|
||||
orient="auto"
|
||||
refY="0.0"
|
||||
refX="0.0"
|
||||
id="marker8938"
|
||||
style="overflow:visible;"
|
||||
inkscape:isstock="true"
|
||||
inkscape:collect="always">
|
||||
<path
|
||||
id="path8936"
|
||||
style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#000000;stroke-opacity:1;fill:#000000;fill-opacity:1"
|
||||
d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
|
||||
transform="scale(0.6) rotate(180) translate(0,0)" />
|
||||
</marker>
|
||||
<marker
|
||||
inkscape:isstock="true"
|
||||
style="overflow:visible;"
|
||||
id="marker8458"
|
||||
refX="0.0"
|
||||
refY="0.0"
|
||||
orient="auto"
|
||||
inkscape:stockid="Arrow2Mend"
|
||||
inkscape:collect="always">
|
||||
<path
|
||||
transform="scale(0.6) rotate(180) translate(0,0)"
|
||||
d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
|
||||
style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#000000;stroke-opacity:1;fill:#000000;fill-opacity:1"
|
||||
id="path8456" />
|
||||
</marker>
|
||||
<marker
|
||||
inkscape:stockid="Arrow2Mend"
|
||||
orient="auto"
|
||||
refY="0.0"
|
||||
refX="0.0"
|
||||
id="marker7654"
|
||||
style="overflow:visible;"
|
||||
inkscape:isstock="true"
|
||||
inkscape:collect="always">
|
||||
<path
|
||||
id="path7652"
|
||||
style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#000000;stroke-opacity:1;fill:#000000;fill-opacity:1"
|
||||
d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
|
||||
transform="scale(0.6) rotate(180) translate(0,0)" />
|
||||
</marker>
|
||||
<marker
|
||||
inkscape:isstock="true"
|
||||
style="overflow:visible;"
|
||||
id="marker7210"
|
||||
refX="0.0"
|
||||
refY="0.0"
|
||||
orient="auto"
|
||||
inkscape:stockid="Arrow2Mend"
|
||||
inkscape:collect="always">
|
||||
<path
|
||||
transform="scale(0.6) rotate(180) translate(0,0)"
|
||||
d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
|
||||
style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#000000;stroke-opacity:1;fill:#000000;fill-opacity:1"
|
||||
id="path7208" />
|
||||
</marker>
|
||||
<marker
|
||||
inkscape:stockid="Arrow2Mend"
|
||||
orient="auto"
|
||||
refY="0.0"
|
||||
refX="0.0"
|
||||
id="Arrow2Mend"
|
||||
style="overflow:visible;"
|
||||
inkscape:isstock="true"
|
||||
inkscape:collect="always">
|
||||
<path
|
||||
id="path5595"
|
||||
style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#000000;stroke-opacity:1;fill:#000000;fill-opacity:1"
|
||||
d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
|
||||
transform="scale(0.6) rotate(180) translate(0,0)" />
|
||||
</marker>
|
||||
<marker
|
||||
inkscape:stockid="Arrow2Lend"
|
||||
orient="auto"
|
||||
refY="0.0"
|
||||
refX="0.0"
|
||||
id="Arrow2Lend"
|
||||
style="overflow:visible;"
|
||||
inkscape:isstock="true">
|
||||
<path
|
||||
id="path5589"
|
||||
style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#000000;stroke-opacity:1;fill:#000000;fill-opacity:1"
|
||||
d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z " transform="scale(1.1) rotate(180) translate(1,0)" />
|
||||
</marker>
|
||||
<marker
|
||||
inkscape:stockid="Arrow1Lend"
|
||||
orient="auto"
|
||||
refY="0.0"
|
||||
refX="0.0"
|
||||
id="Arrow1Lend"
|
||||
style="overflow:visible;"
|
||||
inkscape:isstock="true">
|
||||
<path
|
||||
id="path5571"
|
||||
d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
|
||||
style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1;fill:#000000;fill-opacity:1"
|
||||
transform="scale(0.8) rotate(180) translate(12.5,0)" />
|
||||
</marker>
|
||||
<marker
|
||||
inkscape:stockid="Arrow1Lstart"
|
||||
orient="auto"
|
||||
refY="0.0"
|
||||
refX="0.0"
|
||||
id="Arrow1Lstart"
|
||||
style="overflow:visible"
|
||||
inkscape:isstock="true">
|
||||
<path
|
||||
id="path5568"
|
||||
d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
|
||||
style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1;fill:#000000;fill-opacity:1"
|
||||
transform="scale(0.8) translate(12.5,0)" />
|
||||
</marker>
|
||||
<linearGradient
|
||||
gradientTransform="matrix(1.2281683,0,0,1.2458588,-19.641241,-24.549337)"
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient4680-3"
|
||||
id="linearGradient4831"
|
||||
x1="85.155098"
|
||||
y1="123.48504"
|
||||
x2="71.876953"
|
||||
y2="109.32611"
|
||||
gradientUnits="userSpaceOnUse" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
id="linearGradient4680-3">
|
||||
<stop
|
||||
style="stop-color:#212121;stop-opacity:1"
|
||||
offset="0"
|
||||
id="stop4676" />
|
||||
<stop
|
||||
style="stop-color:#525252;stop-opacity:1"
|
||||
offset="1"
|
||||
id="stop4678" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
gradientTransform="matrix(1.2281683,0,0,1.2458588,-19.641241,-24.549337)"
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient4680-3"
|
||||
id="linearGradient4837"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
x1="75.392632"
|
||||
y1="113.90072"
|
||||
x2="78.325882"
|
||||
y2="111.17885" />
|
||||
<linearGradient
|
||||
gradientTransform="matrix(1.2281683,0,0,1.2458588,-19.641241,-24.549337)"
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient4680-3"
|
||||
id="linearGradient4820"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
x1="58.802368"
|
||||
y1="98.166107"
|
||||
x2="67.821754"
|
||||
y2="105.06921" />
|
||||
<linearGradient
|
||||
gradientTransform="matrix(1.2281683,0,0,1.2458588,-19.641241,-24.549337)"
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient4680-3"
|
||||
id="linearGradient4812"
|
||||
x1="65.554306"
|
||||
y1="101.39091"
|
||||
x2="57.845005"
|
||||
y2="94.387032"
|
||||
gradientUnits="userSpaceOnUse" />
|
||||
<linearGradient
|
||||
gradientTransform="matrix(1.2281683,0,0,1.2458588,-19.641241,-24.549337)"
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient4680-3"
|
||||
id="linearGradient4801"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
x1="93.544136"
|
||||
y1="74.89328"
|
||||
x2="97.026817"
|
||||
y2="75.489372" />
|
||||
<linearGradient
|
||||
gradientTransform="matrix(1.2281683,0,0,1.2458588,-19.641241,-24.549337)"
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient4680-3"
|
||||
id="linearGradient4796"
|
||||
x1="100.40672"
|
||||
y1="76.753265"
|
||||
x2="102.15361"
|
||||
y2="76.166771"
|
||||
gradientUnits="userSpaceOnUse" />
|
||||
<linearGradient
|
||||
gradientTransform="matrix(1.2281683,0,0,1.2458588,-19.641241,-24.549337)"
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient4680-3"
|
||||
id="linearGradient4682"
|
||||
x1="78.691124"
|
||||
y1="106.60219"
|
||||
x2="134.32263"
|
||||
y2="145.19518"
|
||||
gradientUnits="userSpaceOnUse" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient4680-3"
|
||||
id="linearGradient4705"
|
||||
x1="63.324043"
|
||||
y1="92.412109"
|
||||
x2="52.236984"
|
||||
y2="73.76532"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(1.2281683,0,0,1.2458588,-20.199812,-21.797201)" />
|
||||
<radialGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient4680-3"
|
||||
id="radialGradient4695"
|
||||
cx="112.96842"
|
||||
cy="113.917"
|
||||
fx="112.96842"
|
||||
fy="113.917"
|
||||
r="41.164257"
|
||||
gradientTransform="matrix(1.2281683,0,0,1.296401,-19.641241,-30.306952)"
|
||||
gradientUnits="userSpaceOnUse" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient4680-3"
|
||||
id="linearGradient4710"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
x1="41.81852"
|
||||
y1="81.23703"
|
||||
x2="81.993874"
|
||||
y2="81.23703"
|
||||
gradientTransform="matrix(1.2281683,0,0,1.2458588,-20.199812,-21.716256)" />
|
||||
<linearGradient
|
||||
gradientTransform="matrix(1.2281683,0,0,1.2458588,-19.641241,-24.549337)"
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient4680-3"
|
||||
id="linearGradient4763"
|
||||
x1="67.125862"
|
||||
y1="69.888031"
|
||||
x2="82.802811"
|
||||
y2="69.888031"
|
||||
gradientUnits="userSpaceOnUse" />
|
||||
<linearGradient
|
||||
gradientTransform="matrix(1.2281683,0,0,1.2458588,-19.641241,-24.549337)"
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient4680-3"
|
||||
id="linearGradient4773"
|
||||
x1="77.743431"
|
||||
y1="69.896729"
|
||||
x2="74.04789"
|
||||
y2="65.264908"
|
||||
gradientUnits="userSpaceOnUse" />
|
||||
<linearGradient
|
||||
gradientTransform="matrix(1.2281683,0,0,1.2458588,-19.641241,-24.549337)"
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient4680-3"
|
||||
id="linearGradient4747"
|
||||
x1="80.881615"
|
||||
y1="74.891853"
|
||||
x2="82.567528"
|
||||
y2="70.608902"
|
||||
gradientUnits="userSpaceOnUse" />
|
||||
<linearGradient
|
||||
gradientTransform="matrix(1.2281683,0,0,1.2458588,-19.641241,-24.549337)"
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient4680-3"
|
||||
id="linearGradient4784"
|
||||
x1="89.6782"
|
||||
y1="82.01104"
|
||||
x2="124.02607"
|
||||
y2="82.01104"
|
||||
gradientUnits="userSpaceOnUse" />
|
||||
<linearGradient
|
||||
gradientTransform="matrix(1.2281683,0,0,1.2458588,-19.641241,-24.549337)"
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient4680-3"
|
||||
id="linearGradient4735"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
x1="81.290771"
|
||||
y1="69.214806"
|
||||
x2="58.49073"
|
||||
y2="60.248428" />
|
||||
<linearGradient
|
||||
gradientTransform="matrix(1.2281683,0,0,1.2458588,-19.641241,-24.549337)"
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient4680-3"
|
||||
id="linearGradient4726"
|
||||
x1="58.34309"
|
||||
y1="66.386375"
|
||||
x2="116.9311"
|
||||
y2="66.386375"
|
||||
gradientUnits="userSpaceOnUse" />
|
||||
</defs>
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="0.92824696"
|
||||
inkscape:cx="267.03408"
|
||||
inkscape:cy="338.19237"
|
||||
inkscape:document-units="mm"
|
||||
inkscape:current-layer="layer7"
|
||||
showgrid="false"
|
||||
units="px"
|
||||
inkscape:snap-page="true"
|
||||
inkscape:snap-others="false"
|
||||
inkscape:window-width="1920"
|
||||
inkscape:window-height="1004"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="48"
|
||||
inkscape:window-maximized="1" />
|
||||
<metadata
|
||||
id="metadata121">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
inkscape:groupmode="layer"
|
||||
id="layer7"
|
||||
inkscape:label="Device"
|
||||
style="display:inline">
|
||||
<path
|
||||
style="display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.32728478px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="m 33.641311,64.982766 -1.732765,5.398727 c 0,0 -0.629464,5.678443 3.26926,11.20272 5.812872,8.815493 5.94101,9.101914 13.151365,19.243577 7.210355,10.14167 20.613506,27.64865 32.12776,42.84454 3.87757,5.11741 16.967127,10.29767 21.949299,12.68881 11.002,5.28032 27.527,13.09076 40.11549,14.1146 15.07422,1.22601 22.74792,-23.13102 22.74792,-23.13102 L 141.75352,83.564426 123.90176,65.732277 102.89006,58.202973 62.293831,52.176488 45.213712,60.714006 Z"
|
||||
id="path4839"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="ccczsssccccccc" />
|
||||
<path
|
||||
sodipodi:nodetypes="cccssccsc"
|
||||
inkscape:connector-curvature="0"
|
||||
id="path4728"
|
||||
d="m 54.76863,55.588789 -2.295328,-2.726405 -0.27808,-2.350686 c 0,0 18.167671,-1.598465 22.431514,-0.940273 4.263843,0.658192 23.729205,5.171504 34.852264,9.590788 11.12306,4.419288 9.18583,4.11904 14.42276,6.57006 -8.85487,-3.133919 -23.66007,-1.760792 -33.812723,-1.477175 -0.158622,1.548423 -0.114268,2.600247 -0.114268,2.600247 C 82.7929,64.986082 54.76863,55.588789 54.76863,55.588789 Z"
|
||||
style="display:inline;fill:url(#linearGradient4726);fill-opacity:1;stroke:none;stroke-width:0.32780018;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||
<path
|
||||
style="display:inline;fill:url(#linearGradient4735);fill-opacity:1;stroke:none;stroke-width:0.32728478px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="m 54.856148,55.855125 -2.382846,-2.992741 -0.27808,-2.350686 c 18.481975,6.870889 20.73837,7.57628 37.893815,13.7434 -0.158622,1.548423 -0.114268,2.600247 -0.114268,2.600247 C 82.7929,64.986082 54.856148,55.855125 54.856148,55.855125 Z"
|
||||
id="path4716"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="ccccsc" />
|
||||
<path
|
||||
style="display:inline;fill:url(#linearGradient4784);fill-opacity:1;stroke:none;stroke-width:0.32728478px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="m 90.498682,64.587538 c 0.0014,2.415136 0.08886,3.214144 0.08886,3.214144 l 37.938998,22.41657 4.1571,0.443891 -3.58823,-15.047953 -32.119065,-9.854412 z"
|
||||
id="path4776"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
style="display:inline;fill:url(#linearGradient4747);fill-opacity:1;stroke:none;stroke-width:0.32728478px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="m 48.926779,56.570799 c 0,0 5.569607,-2.071605 6.497874,-2.13438 4.641336,1.255515 31.870514,10.044141 37.068811,12.052968 9.897016,3.978673 20.493146,9.162891 28.404966,13.999022 5.31807,3.262227 8.52923,5.401083 8.10688,7.972533 -0.42234,2.571452 -4.45568,5.900935 -4.45568,5.900935 0,0 -13.11951,-3.389899 -13.49083,-3.641 -0.37131,-0.251104 -18.627219,-14.438453 -18.627219,-14.438453 0,0 -13.119512,-5.335949 -13.552706,-5.587054 C 78.445686,70.444268 64.831094,63.978353 64.521671,63.915577 64.212247,63.852802 48.926779,56.570799 48.926779,56.570799 Z"
|
||||
id="path4739"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="cccczcccccc" />
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
id="path4765"
|
||||
d="m 62.800615,61.187683 c 0.06391,-0.129654 1.75539,-2.692898 4.595099,-4.082141 1.130065,-0.55285 4.463428,-1.655606 6.038322,-1.200179 4.493777,1.299505 7.905733,3.09382 12.483497,10.149265 -3.2066,1.658274 -3.2066,1.658274 -3.2066,1.658274 l -2.49426,0.310726 z"
|
||||
style="display:inline;fill:url(#linearGradient4773);fill-opacity:1;stroke:none;stroke-width:0.32728478px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
sodipodi:nodetypes="csscccc" />
|
||||
<path
|
||||
style="display:inline;fill:url(#linearGradient4763);fill-opacity:1;stroke:none;stroke-width:0.32728478px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="m 62.800615,61.187683 c 0.08752,-0.177557 3.063124,-5.903769 8.708027,-3.639918 5.644906,2.263853 10.545906,10.120748 10.545906,10.120748 l -1.837875,0.355115 z"
|
||||
id="path4755"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
sodipodi:nodetypes="csscssscc"
|
||||
inkscape:connector-curvature="0"
|
||||
id="path4707"
|
||||
d="m 81.061034,68.55619 c 0,0 -6.675185,12.538586 -10.603076,22.010152 -1.049126,2.529831 -2.28668,5.867231 -2.803926,7.547057 -0.660926,2.146451 -0.08433,2.769521 -0.397665,4.358811 -3.844082,-2.632003 -32.505527,-27.735224 -34.22755,-29.787815 -0.242782,-0.289387 -1.233891,-1.962381 -1.42236,-4.307299 -0.05219,-0.649308 -0.04284,-1.350134 0.06099,-2.087368 0.836918,-5.94284 11.1851,-12.607804 11.1851,-12.607804 z"
|
||||
style="display:inline;fill:url(#linearGradient4710);fill-opacity:1;stroke:none;stroke-width:0.32728478px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
|
||||
<path
|
||||
sodipodi:nodetypes="cscssccsscsscscc"
|
||||
inkscape:connector-curvature="0"
|
||||
id="path4670"
|
||||
d="m 82.41522,69.014086 c 0,0 23.31399,10.073283 38.80002,21.370661 1.81334,1.322871 4.49209,1.676486 6.63621,-0.04062 2.14412,-1.717108 1.62492,-3.937097 -0.92121,-6.104499 -4.95885,-4.221241 -6.85739,-5.122344 -13.18638,-8.905281 -7.90195,-4.723139 -16.853771,-8.967037 -23.245174,-10.746814 9.140702,-0.572366 30.023744,-1.337857 33.403074,1.144738 8.87412,3.960851 24.30645,16.663516 31.24281,27.830947 8.63308,13.899132 12.33164,22.248122 14.23506,36.388812 2.80518,20.83995 -16.13732,43.5 -26.85791,40.5237 3.57946,-0.6342 7.33514,-2.175 6.9966,-5.15132 -0.74082,-6.51284 -8.57647,-16.59867 -48.52475,-38.11975 -18.315639,-9.86707 -32.387452,-23.46711 -32.387452,-23.46711 0,0 -0.214496,-1.83679 0.169271,-3.37698 C 71.534502,89.287367 82.41522,69.014083 82.41522,69.014083 Z"
|
||||
style="display:inline;fill:url(#radialGradient4695);fill-opacity:1;stroke:none;stroke-width:0.32728478px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
|
||||
<path
|
||||
style="display:inline;fill:url(#linearGradient4705);fill-opacity:1;stroke:none;stroke-width:0.32728478px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="m 67.336162,99.153458 -0.07979,3.237812 C 63.412286,99.759262 35.095451,75.716531 33.028818,72.77516 c -1.88514,-2.683054 -1.67797,-6.628929 -0.815272,-8.362198 -0.06626,1.61221 -0.485638,3.84076 1.152105,5.623249 7.675602,8.353979 25.95005,21.003692 33.970511,29.117247 z"
|
||||
id="path178"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="ccscsc" />
|
||||
<path
|
||||
style="display:inline;fill:url(#linearGradient4682);fill-opacity:1;stroke:none;stroke-width:0.32728478px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="m 142.52172,170.47574 c 3.57946,-0.6342 7.33514,-2.17499 6.9966,-5.15132 -0.74082,-6.51285 -8.57647,-16.59867 -48.52476,-38.11975 -18.315635,-9.86707 -32.387446,-23.46711 -32.387446,-23.46711 0,0 -0.214498,-1.8368 0.169271,-3.37698 3.725669,4.47916 22.509918,18.21415 41.851065,29.0174 55.62333,31.06912 43.85529,42.27142 31.89527,41.09776 z"
|
||||
id="path4672"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="cssccsc" />
|
||||
<path
|
||||
style="display:inline;fill:url(#linearGradient4796);fill-opacity:1;stroke:none;stroke-width:0.32728478px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="m 91.506481,71.019901 c 0.743609,0.908331 11.844809,6.076214 14.221649,7.257645 0.71803,0.356899 1.1815,0.799004 2.31924,0.621448 1.13772,-0.177558 2.35863,-1.316437 2.47237,-1.642404 0.12819,-0.367406 -2.52196,-5.346011 -2.73493,-5.570848 -0.15339,-0.161933 -11.5427,-4.126769 -11.902433,-4.194785 -0.229293,-0.04336 -1.679248,0.660653 -2.406747,1.242898 -0.758403,0.606982 -2.320732,1.856577 -1.969149,2.286046 z"
|
||||
id="path4788"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="sscsssss" />
|
||||
<path
|
||||
sodipodi:nodetypes="csssc"
|
||||
inkscape:connector-curvature="0"
|
||||
id="path4798"
|
||||
d="m 105.24679,73.239364 c 0.34525,0.02969 2.75099,-1.328785 2.53802,-1.553622 -0.15339,-0.161933 -11.5427,-4.126769 -11.902433,-4.194785 -0.229293,-0.04336 -2.23807,0.99583 -2.472384,1.487039 -0.208466,0.437022 10.535617,4.077407 11.836797,4.261368 z"
|
||||
style="display:inline;fill:url(#linearGradient4801);fill-opacity:1;stroke:none;stroke-width:0.32728478px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
|
||||
<path
|
||||
style="display:inline;fill:url(#linearGradient4812);fill-opacity:1;stroke:none;stroke-width:0.32728478px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="m 48.060396,93.734116 16.089967,15.317314 1.980305,-0.87885 1.732766,-3.76656 -17.080119,-14.81511 -1.856536,1.129967 z"
|
||||
id="path4804"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
id="path4814"
|
||||
d="m 48.060396,93.734116 16.089967,15.317314 1.608998,-3.8921 C 61.694393,101.39187 50.213564,91.368976 48.926779,90.720877 Z"
|
||||
style="display:inline;fill:url(#linearGradient4820);fill-opacity:1;stroke:none;stroke-width:0.32728478px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
sodipodi:nodetypes="ccccc" />
|
||||
<path
|
||||
sodipodi:nodetypes="cccscssc"
|
||||
inkscape:connector-curvature="0"
|
||||
id="path4833"
|
||||
d="m 68.002673,113.587 c 2.885039,3.27285 9.816521,11.87315 14.171552,17.07503 0.376971,0.45027 0.479604,0.86316 1.593523,0.36097 1.113922,-0.50223 7.5516,-4.23009 10.658617,-6.2986 0.393265,-0.26182 1.06751,-0.26234 -0.417721,-1.26676 -1.485226,-1.0044 -15.684249,-10.57631 -21.967626,-16.10646 -0.272557,-0.23987 -2.024894,0.70814 -2.197279,1.00972 -0.968716,1.69477 -1.430234,3.61135 -1.841066,5.2261 z"
|
||||
style="display:inline;fill:url(#linearGradient4837);fill-opacity:1;stroke:none;stroke-width:0.32728478px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
|
||||
<path
|
||||
style="display:inline;fill:url(#linearGradient4831);fill-opacity:1;stroke:none;stroke-width:0.32728478px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="m 68.002673,113.587 c 2.885039,3.27285 9.816521,11.87315 14.171552,17.07503 0.376971,0.45027 0.479604,0.86316 1.593523,0.36097 1.113922,-0.50223 5.494927,-2.76524 8.601948,-4.83374 0.393264,-0.26183 1.067506,-0.70624 -0.417724,-1.71067 -1.485226,-1.0044 -14.896587,-10.13241 -21.179966,-15.66256 -0.272558,-0.23988 -0.755882,-0.75671 -0.928267,-0.45513 -0.968716,1.69477 -1.430234,3.61135 -1.841066,5.2261 z"
|
||||
id="path4823"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="cccscssc" />
|
||||
</g>
|
||||
<g
|
||||
inkscape:groupmode="layer"
|
||||
id="layer3"
|
||||
inkscape:label="Leaders"
|
||||
style="display:inline">
|
||||
<path
|
||||
style="fill:none;fill-opacity:1;stroke:none;stroke-width:0.26458332px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="m 87.372004,82.225427 c 0,0 19.527816,7.279613 31.390236,17.304521 0,0 3.8591,1.194482 5.60489,-0.183766 1.74578,-1.378252 1.19448,-3.032155 -0.64318,-4.686055 -1.83767,-1.6539 -20.39812,-13.414976 -29.770225,-15.987711 7.442555,-0.459415 24.445965,-1.073843 27.197485,0.918834 7.22549,3.179214 19.79081,13.375125 25.43853,22.33877 7.02923,11.15626 10.04068,17.85767 11.59048,29.20782 2.28404,16.72738 -13.13933,34.91569 -21.86825,32.52672 2.91447,-0.50904 5.97242,-1.74578 5.69677,-4.13475 -0.60319,-5.2276 -6.98314,-13.32309 -39.50986,-30.59717 -14.912972,-7.91989 -26.370532,-18.8361 -26.370532,-18.8361 0,0 -0.174647,-1.47432 0.137824,-2.71056 2.246527,-8.888015 11.105832,-25.160553 11.105832,-25.160553 z"
|
||||
id="path4668"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="csccccsscsscsc" />
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-style:normal;font-weight:normal;font-size:4.23333311px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332"
|
||||
x="14.064545"
|
||||
y="42.284489"
|
||||
id="text4889"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan4887"
|
||||
x="14.064545"
|
||||
y="42.284489"
|
||||
style="font-size:4.23333311px;stroke-width:0.26458332">Button 0</tspan></text>
|
||||
<text
|
||||
id="text4977"
|
||||
y="41.314796"
|
||||
x="99.894806"
|
||||
style="font-style:normal;font-weight:normal;font-size:4.23333311px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332"
|
||||
xml:space="preserve"><tspan
|
||||
style="stroke-width:0.26458332"
|
||||
y="41.314796"
|
||||
x="99.894806"
|
||||
sodipodi:role="line"
|
||||
id="tspan4979">Button 2</tspan></text>
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-style:normal;font-weight:normal;font-size:4.23333311px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332"
|
||||
x="55.512764"
|
||||
y="30.319952"
|
||||
id="text4985"><tspan
|
||||
sodipodi:role="line"
|
||||
x="55.512764"
|
||||
y="30.319952"
|
||||
style="stroke-width:0.26458332"
|
||||
id="tspan4987">Button 1</tspan></text>
|
||||
<text
|
||||
id="text4993"
|
||||
y="122.63442"
|
||||
x="20.689524"
|
||||
style="font-style:normal;font-weight:normal;font-size:4.23333311px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332"
|
||||
xml:space="preserve"><tspan
|
||||
style="stroke-width:0.26458332"
|
||||
y="122.63442"
|
||||
x="20.689524"
|
||||
sodipodi:role="line"
|
||||
id="tspan4995">Button 4</tspan></text>
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-style:normal;font-weight:normal;font-size:4.23333311px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332"
|
||||
x="55.262302"
|
||||
y="153.98589"
|
||||
id="text5001"><tspan
|
||||
sodipodi:role="line"
|
||||
x="55.262302"
|
||||
y="153.98589"
|
||||
style="stroke-width:0.26458332"
|
||||
id="tspan5003">Button 3</tspan></text>
|
||||
<text
|
||||
id="text5009"
|
||||
y="63.37672"
|
||||
x="141.62805"
|
||||
style="font-style:normal;font-weight:normal;font-size:4.23333311px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332"
|
||||
xml:space="preserve"><tspan
|
||||
style="stroke-width:0.26458332"
|
||||
y="63.37672"
|
||||
x="141.62805"
|
||||
sodipodi:role="line"
|
||||
id="tspan5011">Button 5</tspan></text>
|
||||
<path
|
||||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:3.9000001;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#Arrow2Mend)"
|
||||
d="M 65.843199,148.27125 72.399014,138.295"
|
||||
id="path5023"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="cc" />
|
||||
<path
|
||||
sodipodi:nodetypes="cc"
|
||||
inkscape:connector-curvature="0"
|
||||
id="path7206"
|
||||
d="m 41.615182,120.90785 13.396667,-6.27079"
|
||||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:3.9000001;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker7210)" />
|
||||
<path
|
||||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:3.9000001;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker7654)"
|
||||
d="m 22.80284,45.37344 11.401419,9.121127"
|
||||
id="path7650"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="cc" />
|
||||
<path
|
||||
sodipodi:nodetypes="cc"
|
||||
inkscape:connector-curvature="0"
|
||||
id="path8454"
|
||||
d="m 66.128235,34.542092 4.275532,11.686446"
|
||||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:3.9000001;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker8458)" />
|
||||
<path
|
||||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:3.9000001;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker8938)"
|
||||
d="M 98.052209,43.663228 82.660292,57.629958"
|
||||
id="path8934"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="cc" />
|
||||
<path
|
||||
sodipodi:nodetypes="cc"
|
||||
inkscape:connector-curvature="0"
|
||||
id="path10739"
|
||||
d="m 140.23745,65.040889 -28.50355,5.13063"
|
||||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:3.9000001;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker10743)" />
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 29 KiB |
1630
data/logitech-g900.svg
Normal file
1630
data/logitech-g900.svg
Normal file
File diff suppressed because it is too large
Load Diff
|
After Width: | Height: | Size: 65 KiB |
@@ -95,6 +95,11 @@ mouse:usb:v046dpc249:name:*:
|
||||
RATBAG_HIDPP10_DPI=0:5700@23.53
|
||||
RATBAG_HIDPP10_PROFILE=G500
|
||||
|
||||
# G300
|
||||
mouse:usb:v046dpc246:name:*:
|
||||
RATBAG_DRIVER=logitech_g300
|
||||
RATBAG_SVG=logitech-g300.svg
|
||||
|
||||
# G500
|
||||
mouse:usb:v046dpc068:name:*:
|
||||
RATBAG_DRIVER=hidpp10
|
||||
@@ -165,6 +170,7 @@ mouse:usb:v046dp400a:name:*:
|
||||
# G303 over USB
|
||||
mouse:usb:v046dpc080:name:*:
|
||||
RATBAG_DRIVER=hidpp20
|
||||
RATBAG_SVG=logitech-g303.svg
|
||||
|
||||
# Wireless Touchpad (Unifying)
|
||||
mouse:usb:v046dp4011:name:*:
|
||||
@@ -177,6 +183,7 @@ mouse:usb:v046dpc537:name:*:
|
||||
# G900 over wireless USB
|
||||
mouse:usb:v046dpc539:name:*:
|
||||
RATBAG_DRIVER=hidpp20
|
||||
RATBAG_SVG=logitech-g900.svg
|
||||
RATBAG_HIDPP20_INDEX=1
|
||||
|
||||
|
||||
@@ -187,3 +194,12 @@ mouse:usb:v046dpc539:name:*:
|
||||
mouse:usb:v1e7dp2e22:name:*:
|
||||
RATBAG_DRIVER=roccat
|
||||
RATBAG_SVG=roccat-kone-xtd.svg
|
||||
|
||||
|
||||
##########################################
|
||||
# G.Skill
|
||||
##########################################
|
||||
|
||||
# MX-780
|
||||
mouse:usb:v28dap3101:name:*:
|
||||
RATBAG_DRIVER=gskill
|
||||
|
||||
606
release.sh
Executable file
606
release.sh
Executable file
@@ -0,0 +1,606 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# Generate the announce template
|
||||
#
|
||||
# Completely copy/paste of Xorg/util/modular/release.sh:
|
||||
#
|
||||
# Copyright (c) 2009, Oracle and/or its affiliates. All rights reserved.
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a
|
||||
# copy of this software and associated documentation files (the "Software"),
|
||||
# to deal in the Software without restriction, including without limitation
|
||||
# the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
# and/or sell copies of the Software, and to permit persons to whom the
|
||||
# Software is furnished to do so, subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice (including the next
|
||||
# paragraph) shall be included in all copies or substantial portions of the
|
||||
# Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
# DEALINGS IN THE SOFTWARE.
|
||||
|
||||
export LC_ALL=C
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
# Function: check_local_changes
|
||||
#------------------------------------------------------------------------------
|
||||
#
|
||||
check_local_changes() {
|
||||
git diff --quiet HEAD > /dev/null 2>&1
|
||||
if [ $? -ne 0 ]; then
|
||||
echo ""
|
||||
echo "Uncommitted changes found. Did you forget to commit? Aborting."
|
||||
echo ""
|
||||
echo "You can perform a 'git stash' to save your local changes and"
|
||||
echo "a 'git stash apply' to recover them after the tarball release."
|
||||
echo "Make sure to rebuild and run 'make distcheck' again."
|
||||
echo ""
|
||||
echo "Alternatively, you can clone the module in another directory"
|
||||
echo "and run ./configure. No need to build if testing was finished."
|
||||
echo ""
|
||||
return 1
|
||||
fi
|
||||
return 0
|
||||
}
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
# Function: check_option_args
|
||||
#------------------------------------------------------------------------------
|
||||
#
|
||||
# perform sanity checks on cmdline args which require arguments
|
||||
# arguments:
|
||||
# $1 - the option being examined
|
||||
# $2 - the argument to the option
|
||||
# returns:
|
||||
# if it returns, everything is good
|
||||
# otherwise it exit's
|
||||
check_option_args() {
|
||||
option=$1
|
||||
arg=$2
|
||||
|
||||
# check for an argument
|
||||
if [ x"$arg" = x ]; then
|
||||
echo ""
|
||||
echo "Error: the '$option' option is missing its required argument."
|
||||
echo ""
|
||||
usage
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# does the argument look like an option?
|
||||
echo $arg | $GREP "^-" > /dev/null
|
||||
if [ $? -eq 0 ]; then
|
||||
echo ""
|
||||
echo "Error: the argument '$arg' of option '$option' looks like an option itself."
|
||||
echo ""
|
||||
usage
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
# Function: check_modules_specification
|
||||
#------------------------------------------------------------------------------
|
||||
#
|
||||
check_modules_specification() {
|
||||
|
||||
if [ x"$MODFILE" = x ]; then
|
||||
if [ x"${INPUT_MODULES}" = x ]; then
|
||||
echo ""
|
||||
echo "Error: no modules specified (blank command line)."
|
||||
usage
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
}
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
# Function: generate_announce
|
||||
#------------------------------------------------------------------------------
|
||||
#
|
||||
generate_announce()
|
||||
{
|
||||
cat <<RELEASE
|
||||
Subject: [ANNOUNCE] $pkg_name $pkg_version
|
||||
To: $list_to
|
||||
Cc: $list_cc
|
||||
|
||||
libratbag $tag_name is out.
|
||||
|
||||
The list of interesting changes are:
|
||||
|
||||
See the full log at the end if you are interested in the details.
|
||||
|
||||
`git log --no-merges "$tag_range" | git shortlog`
|
||||
|
||||
git tag: $tag_name
|
||||
|
||||
RELEASE
|
||||
|
||||
for tarball in $tarbz2 $targz $tarxz; do
|
||||
cat <<RELEASE
|
||||
The libratbag project does not generate tarballs for releases, you can
|
||||
grab one directly from github:
|
||||
|
||||
https://github.com/libratbag/libratbag/archive/$tag_name/$tarball
|
||||
|
||||
RELEASE
|
||||
done
|
||||
}
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
# Function: read_modfile
|
||||
#------------------------------------------------------------------------------
|
||||
#
|
||||
# Read the module names from the file and set a variable to hold them
|
||||
# This will be the same interface as cmd line supplied modules
|
||||
#
|
||||
read_modfile() {
|
||||
|
||||
if [ x"$MODFILE" != x ]; then
|
||||
# Make sure the file is sane
|
||||
if [ ! -r "$MODFILE" ]; then
|
||||
echo "Error: module file '$MODFILE' is not readable or does not exist."
|
||||
exit 1
|
||||
fi
|
||||
# read from input file, skipping blank and comment lines
|
||||
while read line; do
|
||||
# skip blank lines
|
||||
if [ x"$line" = x ]; then
|
||||
continue
|
||||
fi
|
||||
# skip comment lines
|
||||
if echo "$line" | $GREP -q "^#" ; then
|
||||
continue;
|
||||
fi
|
||||
INPUT_MODULES="$INPUT_MODULES $line"
|
||||
done <"$MODFILE"
|
||||
fi
|
||||
return 0
|
||||
}
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
# Function: print_epilog
|
||||
#------------------------------------------------------------------------------
|
||||
#
|
||||
print_epilog() {
|
||||
|
||||
epilog="======== Successful Completion"
|
||||
if [ x"$NO_QUIT" != x ]; then
|
||||
if [ x"$failed_modules" != x ]; then
|
||||
epilog="======== Partial Completion"
|
||||
fi
|
||||
elif [ x"$failed_modules" != x ]; then
|
||||
epilog="======== Stopped on Error"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "$epilog `date`"
|
||||
|
||||
# Report about modules that failed for one reason or another
|
||||
if [ x"$failed_modules" != x ]; then
|
||||
echo " List of failed modules:"
|
||||
for mod in $failed_modules; do
|
||||
echo " $mod"
|
||||
done
|
||||
echo "========"
|
||||
echo ""
|
||||
fi
|
||||
}
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
# Function: process_modules
|
||||
#------------------------------------------------------------------------------
|
||||
#
|
||||
# Loop through each module to release
|
||||
# Exit on error if --no-quit was not specified
|
||||
#
|
||||
process_modules() {
|
||||
for MODULE_RPATH in ${INPUT_MODULES}; do
|
||||
if ! process_module ; then
|
||||
echo "Error: processing module \"$MODULE_RPATH\" failed."
|
||||
failed_modules="$failed_modules $MODULE_RPATH"
|
||||
if [ x"$NO_QUIT" = x ]; then
|
||||
print_epilog
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
# Function: get_section
|
||||
#------------------------------------------------------------------------------
|
||||
# Code 'return 0' on success
|
||||
# Code 'return 1' on error
|
||||
# Sets global variable $section
|
||||
get_section() {
|
||||
local module_url
|
||||
local full_module_url
|
||||
|
||||
# Obtain the git url in order to find the section to which this module belongs
|
||||
full_module_url=`git config --get remote.$remote_name.url | sed 's:\.git$::'`
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "Error: unable to obtain git url for remote \"$remote_name\"."
|
||||
return 1
|
||||
fi
|
||||
|
||||
# The last part of the git url will tell us the section. Look for xorg first
|
||||
echo "$full_module_url"
|
||||
module_url=`echo "$full_module_url" | $GREP -o "libratbag/.*"`
|
||||
if [ $? -eq 0 ]; then
|
||||
module_url=`echo $module_url | cut -d'/' -f2,3`
|
||||
else
|
||||
echo "Error: unable to locate a valid project url from \"$full_module_url\"."
|
||||
echo "Cannot establish url as one of libratbag"
|
||||
cd $top_src
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Find the section (subdirs) where the tarballs are to be uploaded
|
||||
# The module relative path can be app/xfs, xserver, or mesa/drm for example
|
||||
section=`echo $module_url | cut -d'/' -f1`
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "Error: unable to extract section from $module_url first field."
|
||||
return 1
|
||||
fi
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
# Function: process_module
|
||||
#------------------------------------------------------------------------------
|
||||
# Code 'return 0' on success to process the next module
|
||||
# Code 'return 1' on error to process next module if invoked with --no-quit
|
||||
#
|
||||
process_module() {
|
||||
|
||||
top_src=`pwd`
|
||||
echo ""
|
||||
echo "======== Processing \"$top_src/$MODULE_RPATH\""
|
||||
|
||||
# This is the location where the script has been invoked
|
||||
if [ ! -d $MODULE_RPATH ] ; then
|
||||
echo "Error: $MODULE_RPATH cannot be found under $top_src."
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Change directory to be in the git module
|
||||
cd $MODULE_RPATH
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "Error: failed to cd to $MODULE_RPATH."
|
||||
return 1
|
||||
fi
|
||||
|
||||
# ----- Now in the git module *root* directory ----- #
|
||||
|
||||
# Check that this is indeed a git module
|
||||
if [ ! -d .git ]; then
|
||||
echo "Error: there is no git module here: `pwd`"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Change directory to be in the git build directory (could be out-of-source)
|
||||
# More than one can be found when distcheck has run and failed
|
||||
configNum=`find . -name config.status -type f | wc -l | sed 's:^ *::'`
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "Error: failed to locate config.status."
|
||||
echo "Has the module been configured?"
|
||||
return 1
|
||||
fi
|
||||
if [ x"$configNum" = x0 ]; then
|
||||
echo "Error: failed to locate config.status, has the module been configured?"
|
||||
return 1
|
||||
fi
|
||||
if [ x"$configNum" != x1 ]; then
|
||||
echo "Error: more than one config.status file was found,"
|
||||
echo " clean-up previously failed attempts at distcheck"
|
||||
return 1
|
||||
fi
|
||||
status_file=`find . -name config.status -type f`
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "Error: failed to locate config.status."
|
||||
echo "Has the module been configured?"
|
||||
return 1
|
||||
fi
|
||||
build_dir=`dirname $status_file`
|
||||
cd $build_dir
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "Error: failed to cd to $MODULE_RPATH/$build_dir."
|
||||
cd $top_src
|
||||
return 1
|
||||
fi
|
||||
|
||||
# ----- Now in the git module *build* directory ----- #
|
||||
|
||||
# Check for uncommitted/queued changes.
|
||||
check_local_changes
|
||||
if [ $? -ne 0 ]; then
|
||||
cd $top_src
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Determine what is the current branch and the remote name
|
||||
current_branch=`git branch | $GREP "\*" | sed -e "s/\* //"`
|
||||
remote_name=`git config --get branch.$current_branch.remote`
|
||||
remote_branch=`git config --get branch.$current_branch.merge | cut -d'/' -f3,4`
|
||||
remote_url_root="https://github.com/libratbag/libratbag/archive"
|
||||
echo "Info: working off the \"$current_branch\" branch tracking the remote \"$remote_name/$remote_branch\"."
|
||||
|
||||
# Obtain the section
|
||||
get_section
|
||||
if [ $? -ne 0 ]; then
|
||||
cd $top_src
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Run 'make dist/distcheck' to ensure the tarball matches the git module content
|
||||
# Important to run make dist/distcheck before looking in Makefile, may need to reconfigure
|
||||
echo "Info: running \"make $MAKE_DIST_CMD\" to create tarballs:"
|
||||
${MAKE} $MAKEFLAGS $MAKE_DIST_CMD > /dev/null
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "Error: \"$MAKE $MAKEFLAGS $MAKE_DIST_CMD\" failed."
|
||||
cd $top_src
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Find out the tarname from the makefile
|
||||
pkg_name=`$GREP '^PACKAGE = ' Makefile | sed 's|PACKAGE = ||'`
|
||||
pkg_version=`$GREP '^VERSION = ' Makefile | sed 's|VERSION = ||'`
|
||||
tar_name="$pkg_name-$pkg_version"
|
||||
targz=$tar_name.tar.gz
|
||||
tag_name=$(echo "v$pkg_version" | sed 's|.0$||')
|
||||
|
||||
# Now get the tarballs from github directly to compute their checksum
|
||||
remote_targz_url=$remote_url_root/$tag_name/$targz
|
||||
echo "downloading the tarbal from $remote_targz_url"
|
||||
curl $remote_targz_url > $targz
|
||||
|
||||
# Obtain the top commit SHA which should be the version bump
|
||||
# It should not have been tagged yet (the script will do it later)
|
||||
local_top_commit_sha=`git rev-list --max-count=1 HEAD`
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "Error: unable to obtain the local top commit id."
|
||||
cd $top_src
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Check that the top commit looks like a version bump
|
||||
git diff --unified=0 HEAD^ | $GREP -F $pkg_version >/dev/null 2>&1
|
||||
if [ $? -ne 0 ]; then
|
||||
# Wayland repos use m4_define([wayland_major_version], [0])
|
||||
git diff --unified=0 HEAD^ | $GREP -E "(major|minor|micro)_version" >/dev/null 2>&1
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "Error: the local top commit does not look like a version bump."
|
||||
echo " the diff does not contain the string \"$pkg_version\"."
|
||||
local_top_commit_descr=`git log --oneline --max-count=1 $local_top_commit_sha`
|
||||
echo " the local top commit is: \"$local_top_commit_descr\""
|
||||
cd $top_src
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
|
||||
# Check that the top commit has been pushed to remote
|
||||
remote_top_commit_sha=`git rev-list --max-count=1 $remote_name/$remote_branch`
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "Error: unable to obtain top commit from the remote repository."
|
||||
cd $top_src
|
||||
return 1
|
||||
fi
|
||||
if [ x"$remote_top_commit_sha" != x"$local_top_commit_sha" ]; then
|
||||
echo "Error: the local top commit has not been pushed to the remote."
|
||||
local_top_commit_descr=`git log --oneline --max-count=1 $local_top_commit_sha`
|
||||
echo " the local top commit is: \"$local_top_commit_descr\""
|
||||
cd $top_src
|
||||
return 1
|
||||
fi
|
||||
|
||||
# If a tag exists with the the tar name, ensure it is tagging the top commit
|
||||
# It may happen if the version set in configure.ac has been previously released
|
||||
tagged_commit_sha=`git rev-list --max-count=1 $tag_name 2>/dev/null`
|
||||
if [ $? -eq 0 ]; then
|
||||
# Check if the tag is pointing to the top commit
|
||||
if [ x"$tagged_commit_sha" != x"$remote_top_commit_sha" ]; then
|
||||
echo "Error: the \"$tag_name\" already exists."
|
||||
echo " this tag is not tagging the top commit."
|
||||
remote_top_commit_descr=`git log --oneline --max-count=1 $remote_top_commit_sha`
|
||||
echo " the top commit is: \"$remote_top_commit_descr\""
|
||||
local_tag_commit_descr=`git log --oneline --max-count=1 $tagged_commit_sha`
|
||||
echo " tag \"$tag_name\" is tagging some other commit: \"$local_tag_commit_descr\""
|
||||
cd $top_src
|
||||
return 1
|
||||
else
|
||||
echo "Info: module already tagged with \"$tag_name\"."
|
||||
fi
|
||||
else
|
||||
# Tag the top commit with the tar name
|
||||
if [ x"$DRY_RUN" = x ]; then
|
||||
git tag -s -m $tag_name $tag_name
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "Error: unable to tag module with \"$tag_name\"."
|
||||
cd $top_src
|
||||
return 1
|
||||
else
|
||||
echo "Info: module tagged with \"$tag_name\"."
|
||||
fi
|
||||
else
|
||||
echo "Info: skipping the commit tagging in dry-run mode."
|
||||
fi
|
||||
fi
|
||||
|
||||
# Mailing lists where to post the all [Announce] e-mails
|
||||
list_to="input-tools@lists.freedesktop.org"
|
||||
|
||||
# Pushing the top commit tag to the remote repository
|
||||
if [ x$DRY_RUN = x ]; then
|
||||
echo "Info: pushing tag \"$tag_name\" to remote \"$remote_name\":"
|
||||
git push $remote_name $tag_name
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "Error: unable to push tag \"$tag_name\" to the remote repository."
|
||||
echo " it is recommended you fix this manually and not run the script again"
|
||||
cd $top_src
|
||||
return 1
|
||||
fi
|
||||
else
|
||||
echo "Info: skipped pushing tag \"$tag_name\" to the remote repository in dry-run mode."
|
||||
fi
|
||||
|
||||
# --------- Generate the announce e-mail ------------------
|
||||
# Failing to generate the announce is not considered a fatal error
|
||||
|
||||
# Git-describe returns only "the most recent tag", it may not be the expected one
|
||||
# However, we only use it for the commit history which will be the same anyway.
|
||||
tag_previous=`git describe --abbrev=0 HEAD^ 2>/dev/null`
|
||||
# Git fails with rc=128 if no tags can be found prior to HEAD^
|
||||
if [ $? -ne 0 ]; then
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "Warning: unable to find a previous tag."
|
||||
echo " perhaps a first release on this branch."
|
||||
echo " Please check the commit history in the announce."
|
||||
fi
|
||||
fi
|
||||
if [ x"$tag_previous" != x ]; then
|
||||
# The top commit may not have been tagged in dry-run mode. Use commit.
|
||||
tag_range=$tag_previous..$local_top_commit_sha
|
||||
else
|
||||
tag_range=$tag_name
|
||||
fi
|
||||
generate_announce > "$tar_name.announce"
|
||||
echo "Info: [ANNOUNCE] template generated in \"$tar_name.announce\" file."
|
||||
echo " Please pgp sign and send it."
|
||||
|
||||
# --------- Successful completion --------------------------
|
||||
cd $top_src
|
||||
return 0
|
||||
|
||||
}
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
# Function: usage
|
||||
#------------------------------------------------------------------------------
|
||||
# Displays the script usage and exits successfully
|
||||
#
|
||||
usage() {
|
||||
basename="`expr "//$0" : '.*/\([^/]*\)'`"
|
||||
cat <<HELP
|
||||
|
||||
Usage: $basename [options] path...
|
||||
|
||||
Where "path" is a relative path to a git module, including '.'.
|
||||
|
||||
Options:
|
||||
--dist make 'dist' instead of 'distcheck'; use with caution
|
||||
--distcheck Default, ignored for compatibility
|
||||
--dry-run Does everything except tagging and uploading tarballs
|
||||
--force Force overwriting an existing release
|
||||
--help Display this help and exit successfully
|
||||
--no-quit Do not quit after error; just print error message
|
||||
|
||||
Environment variables defined by the "make" program and used by release.sh:
|
||||
MAKE The name of the make command [make]
|
||||
MAKEFLAGS: Options to pass to all \$(MAKE) invocations
|
||||
|
||||
HELP
|
||||
}
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
# Script main line
|
||||
#------------------------------------------------------------------------------
|
||||
#
|
||||
|
||||
# Choose which make program to use (could be gmake)
|
||||
MAKE=${MAKE:="make"}
|
||||
|
||||
# Choose which grep program to use (on Solaris, must be gnu grep)
|
||||
if [ "x$GREP" = "x" ] ; then
|
||||
if [ -x /usr/gnu/bin/grep ] ; then
|
||||
GREP=/usr/gnu/bin/grep
|
||||
else
|
||||
GREP=grep
|
||||
fi
|
||||
fi
|
||||
|
||||
# Set the default make tarball creation command
|
||||
MAKE_DIST_CMD=distcheck
|
||||
|
||||
# Process command line args
|
||||
while [ $# != 0 ]
|
||||
do
|
||||
case $1 in
|
||||
# Use 'dist' rather than 'distcheck' to create tarballs
|
||||
# You really only want to do this if you're releasing a module you can't
|
||||
# possibly build-test. Please consider carefully the wisdom of doing so.
|
||||
--dist)
|
||||
MAKE_DIST_CMD=dist
|
||||
;;
|
||||
# Use 'distcheck' to create tarballs
|
||||
--distcheck)
|
||||
MAKE_DIST_CMD=distcheck
|
||||
;;
|
||||
# Does everything except uploading tarball
|
||||
--dry-run)
|
||||
DRY_RUN=yes
|
||||
;;
|
||||
# Force overwriting an existing release
|
||||
# Use only if nothing changed in the git repo
|
||||
--force)
|
||||
FORCE=yes
|
||||
;;
|
||||
# Display this help and exit successfully
|
||||
--help)
|
||||
usage
|
||||
exit 0
|
||||
;;
|
||||
# Do not quit after error; just print error message
|
||||
--no-quit)
|
||||
NO_QUIT=yes
|
||||
;;
|
||||
--*)
|
||||
echo ""
|
||||
echo "Error: unknown option: $1"
|
||||
echo ""
|
||||
usage
|
||||
exit 1
|
||||
;;
|
||||
-*)
|
||||
echo ""
|
||||
echo "Error: unknown option: $1"
|
||||
echo ""
|
||||
usage
|
||||
exit 1
|
||||
;;
|
||||
*)
|
||||
if [ x"${MODFILE}" != x ]; then
|
||||
echo ""
|
||||
echo "Error: specifying both modules and --modfile is not permitted"
|
||||
echo ""
|
||||
usage
|
||||
exit 1
|
||||
fi
|
||||
INPUT_MODULES="${INPUT_MODULES} $1"
|
||||
;;
|
||||
esac
|
||||
|
||||
shift
|
||||
done
|
||||
|
||||
# If no modules specified (blank cmd line) display help
|
||||
check_modules_specification
|
||||
|
||||
# Read the module file and normalize input in INPUT_MODULES
|
||||
read_modfile
|
||||
|
||||
# Loop through each module to release
|
||||
# Exit on error if --no-quit no specified
|
||||
process_modules
|
||||
|
||||
# Print the epilog with final status
|
||||
print_epilog
|
||||
@@ -11,7 +11,9 @@ libratbag_la_SOURCES = \
|
||||
driver-etekcity.c \
|
||||
driver-hidpp20.c \
|
||||
driver-hidpp10.c \
|
||||
driver-logitech-g300.c \
|
||||
driver-roccat.c \
|
||||
driver-gskill.c \
|
||||
driver-test.c \
|
||||
libratbag.c \
|
||||
libratbag.h \
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
#define ETEKCITY_PROFILE_MAX 4
|
||||
#define ETEKCITY_BUTTON_MAX 10
|
||||
#define ETEKCITY_NUM_DPI 6
|
||||
#define ETEKCITY_LED 0
|
||||
|
||||
#define ETEKCITY_REPORT_ID_CONFIGURE_PROFILE 4
|
||||
#define ETEKCITY_REPORT_ID_PROFILE 5
|
||||
@@ -657,7 +658,8 @@ etekcity_probe(struct ratbag_device *device)
|
||||
ratbag_device_init_profiles(device,
|
||||
ETEKCITY_PROFILE_MAX + 1,
|
||||
ETEKCITY_NUM_DPI,
|
||||
ETEKCITY_BUTTON_MAX + 1);
|
||||
ETEKCITY_BUTTON_MAX + 1,
|
||||
ETEKCITY_LED);
|
||||
|
||||
ratbag_device_set_capability(device, RATBAG_DEVICE_CAP_BUTTON_MACROS);
|
||||
|
||||
|
||||
1510
src/driver-gskill.c
Normal file
1510
src/driver-gskill.c
Normal file
File diff suppressed because it is too large
Load Diff
@@ -465,7 +465,8 @@ hidpp10drv_fill_from_profile(struct ratbag_device *device, struct hidpp10_device
|
||||
ratbag_device_init_profiles(device,
|
||||
count,
|
||||
profile.num_dpi_modes,
|
||||
profile.num_buttons);
|
||||
profile.num_buttons,
|
||||
profile.num_leds);
|
||||
|
||||
if (dev->profile_type != HIDPP10_PROFILE_UNKNOWN) {
|
||||
ratbag_device_set_capability(device, RATBAG_DEVICE_CAP_SWITCHABLE_PROFILE);
|
||||
@@ -584,7 +585,7 @@ hidpp10drv_probe(struct ratbag_device *device)
|
||||
/* Fall back to something that every mouse has */
|
||||
struct ratbag_profile *profile;
|
||||
|
||||
ratbag_device_init_profiles(device, 1, 1, 3);
|
||||
ratbag_device_init_profiles(device, 1, 1, 3, 0);
|
||||
profile = ratbag_device_get_profile(device, 0);
|
||||
profile->is_active = true;
|
||||
ratbag_profile_unref(profile);
|
||||
|
||||
@@ -51,7 +51,8 @@
|
||||
#define HIDPP_CAP_BUTTON_KEY_1b04 (1 << 2)
|
||||
#define HIDPP_CAP_BATTERY_LEVEL_1000 (1 << 3)
|
||||
#define HIDPP_CAP_KBD_REPROGRAMMABLE_KEYS_1b00 (1 << 4)
|
||||
#define HIDPP_CAP_ONBOARD_PROFILES_8100 (1 << 5)
|
||||
#define HIDPP_CAP_COLOR_LED_EFFECTS_8070 (1 << 5)
|
||||
#define HIDPP_CAP_ONBOARD_PROFILES_8100 (1 << 6)
|
||||
|
||||
struct hidpp20drv_data {
|
||||
struct hidpp20_device *dev;
|
||||
@@ -61,10 +62,12 @@ struct hidpp20drv_data {
|
||||
unsigned num_controls;
|
||||
struct hidpp20_control_id *controls;
|
||||
struct hidpp20_profiles *profiles;
|
||||
struct hidpp20_color_led_zone_info *led_infos;
|
||||
|
||||
unsigned int num_profiles;
|
||||
unsigned int num_resolutions;
|
||||
unsigned int num_buttons;
|
||||
unsigned int num_leds;
|
||||
};
|
||||
|
||||
static void
|
||||
@@ -225,6 +228,7 @@ hidpp20drv_read_button_8100(struct ratbag_button *button)
|
||||
break;
|
||||
default:
|
||||
button->action.type = RATBAG_BUTTON_ACTION_TYPE_UNKNOWN;
|
||||
break;
|
||||
}
|
||||
|
||||
ratbag_button_enable_action_type(button, RATBAG_BUTTON_ACTION_TYPE_BUTTON);
|
||||
@@ -240,6 +244,44 @@ hidpp20drv_read_button(struct ratbag_button *button)
|
||||
hidpp20drv_read_button_8100(button);
|
||||
}
|
||||
|
||||
static void
|
||||
hidpp20drv_read_led(struct ratbag_led *led)
|
||||
{
|
||||
struct ratbag_device *device = led->profile->device;
|
||||
struct hidpp20drv_data *drv_data = ratbag_get_drv_data(device);
|
||||
struct hidpp20_profile *profile;
|
||||
struct hidpp20_color_led_zone_info *led_info;
|
||||
struct hidpp20_led *h_led;
|
||||
|
||||
if (!(drv_data->capabilities & HIDPP_CAP_ONBOARD_PROFILES_8100))
|
||||
return;
|
||||
|
||||
led_info = &drv_data->led_infos[led->index];
|
||||
profile = &drv_data->profiles->profiles[led->profile->index];
|
||||
h_led = &profile->leds[led->index];
|
||||
|
||||
switch (h_led->mode) {
|
||||
case HIDPP20_LED_ON:
|
||||
led->mode = RATBAG_LED_ON;
|
||||
break;
|
||||
case HIDPP20_LED_CYCLE:
|
||||
led->mode = RATBAG_LED_CYCLE;
|
||||
break;
|
||||
case HIDPP20_LED_BREATHING:
|
||||
led->mode = RATBAG_LED_BREATHING;
|
||||
break;
|
||||
default:
|
||||
led->mode = RATBAG_LED_OFF;
|
||||
break;
|
||||
}
|
||||
led->type = hidpp20_8070_get_location_mapping(led_info->location);
|
||||
led->color.red = h_led->color.red;
|
||||
led->color.green = h_led->color.green;
|
||||
led->color.blue = h_led->color.blue;
|
||||
led->hz = h_led->rate;
|
||||
led->brightness = h_led->brightness * 255.0 / 100;
|
||||
}
|
||||
|
||||
static int
|
||||
hidpp20drv_write_button_1b04(struct ratbag_button *button,
|
||||
const struct ratbag_button_action *action)
|
||||
@@ -343,6 +385,52 @@ hidpp20drv_write_button(struct ratbag_button *button,
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
static int
|
||||
hidpp20drv_write_led(struct ratbag_led *led,
|
||||
enum ratbag_led_mode mode,
|
||||
struct ratbag_color color, unsigned int hz,
|
||||
unsigned int brightness)
|
||||
{
|
||||
struct ratbag_profile *profile = led->profile;
|
||||
struct ratbag_device *device = profile->device;
|
||||
struct hidpp20drv_data *drv_data = ratbag_get_drv_data(device);
|
||||
struct hidpp20_profile *h_profile;
|
||||
struct hidpp20_led *h_led;
|
||||
|
||||
if (!(drv_data->capabilities & HIDPP_CAP_COLOR_LED_EFFECTS_8070))
|
||||
return -ENOTSUP;
|
||||
|
||||
h_profile = &drv_data->profiles->profiles[profile->index];
|
||||
|
||||
h_led = &(h_profile->leds[led->index]);
|
||||
|
||||
if (!h_led)
|
||||
return -EINVAL;
|
||||
|
||||
switch (mode) {
|
||||
case RATBAG_LED_ON:
|
||||
h_led->mode = HIDPP20_LED_ON;
|
||||
break;
|
||||
case RATBAG_LED_CYCLE:
|
||||
h_led->mode = HIDPP20_LED_CYCLE;
|
||||
break;
|
||||
case RATBAG_LED_BREATHING:
|
||||
h_led->mode = HIDPP20_LED_BREATHING;
|
||||
break;
|
||||
default:
|
||||
h_led->mode = HIDPP20_LED_OFF;
|
||||
break;
|
||||
}
|
||||
h_led->color.red = color.red;
|
||||
h_led->color.green = color.green;
|
||||
h_led->color.blue = color.blue;
|
||||
h_led->rate = hz;
|
||||
h_led->brightness = brightness / 255.0 * 100;
|
||||
|
||||
return hidpp20_onboard_profiles_write(drv_data->dev, profile->index,
|
||||
drv_data->profiles);
|
||||
}
|
||||
|
||||
static int
|
||||
hidpp20drv_current_profile(struct ratbag_device *device)
|
||||
{
|
||||
@@ -569,6 +657,29 @@ hidpp20drv_read_kbd_reprogrammable_key(struct ratbag_device *device)
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int
|
||||
hidpp20drv_read_color_leds(struct ratbag_device *device)
|
||||
{
|
||||
struct hidpp20drv_data *drv_data = ratbag_get_drv_data(device);
|
||||
int rc;
|
||||
|
||||
if (!(drv_data->capabilities & HIDPP_CAP_COLOR_LED_EFFECTS_8070))
|
||||
return 0;
|
||||
|
||||
free(drv_data->led_infos);
|
||||
drv_data->led_infos = NULL;
|
||||
drv_data->num_leds = 0;
|
||||
|
||||
rc = hidpp20_color_led_effects_get_zone_infos(drv_data->dev, &drv_data->led_infos);
|
||||
|
||||
if (rc > 0) {
|
||||
drv_data->num_leds = rc;
|
||||
rc = 0;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int
|
||||
hidpp20drv_read_onboard_profile(struct ratbag_device *device, unsigned index)
|
||||
{
|
||||
@@ -718,6 +829,15 @@ hidpp20drv_init_feature(struct ratbag_device *device, uint16_t feature)
|
||||
}
|
||||
case HIDPP_PAGE_COLOR_LED_EFFECTS: {
|
||||
log_debug(ratbag, "device has color effects\n");
|
||||
drv_data->capabilities |= HIDPP_CAP_COLOR_LED_EFFECTS_8070;
|
||||
|
||||
/* we read the profile once to get the correct number of
|
||||
* supported leds. */
|
||||
if (hidpp20drv_read_color_leds(device))
|
||||
return 0;
|
||||
|
||||
ratbag_device_set_capability(device, RATBAG_DEVICE_CAP_LED);
|
||||
device->num_leds = drv_data->num_leds;
|
||||
break;
|
||||
}
|
||||
case HIDPP_PAGE_ONBOARD_PROFILES: {
|
||||
@@ -731,6 +851,7 @@ hidpp20drv_init_feature(struct ratbag_device *device, uint16_t feature)
|
||||
drv_data->num_profiles = drv_data->profiles->num_profiles;
|
||||
drv_data->num_resolutions = drv_data->profiles->num_modes;
|
||||
drv_data->num_buttons = drv_data->profiles->num_buttons;
|
||||
drv_data->num_leds = drv_data->profiles->num_leds;
|
||||
|
||||
break;
|
||||
}
|
||||
@@ -859,6 +980,7 @@ hidpp20drv_probe(struct ratbag_device *device)
|
||||
drv_data->num_profiles = 1;
|
||||
drv_data->num_resolutions = 1;
|
||||
drv_data->num_buttons = 8;
|
||||
drv_data->num_leds = 2;
|
||||
|
||||
rc = hidpp20drv_20_probe(device);
|
||||
if (rc)
|
||||
@@ -867,7 +989,8 @@ hidpp20drv_probe(struct ratbag_device *device)
|
||||
ratbag_device_init_profiles(device,
|
||||
drv_data->num_profiles,
|
||||
drv_data->num_resolutions,
|
||||
drv_data->num_buttons);
|
||||
drv_data->num_buttons,
|
||||
drv_data->num_leds);
|
||||
|
||||
return rc;
|
||||
err:
|
||||
@@ -884,6 +1007,8 @@ struct ratbag_driver hidpp20_driver = {
|
||||
.write_profile = hidpp20drv_write_profile,
|
||||
.set_active_profile = hidpp20drv_set_current_profile,
|
||||
.read_button = hidpp20drv_read_button,
|
||||
.read_led = hidpp20drv_read_led,
|
||||
.write_button = hidpp20drv_write_button,
|
||||
.write_resolution_dpi = hidpp20drv_write_resolution_dpi,
|
||||
.write_led = hidpp20drv_write_led,
|
||||
};
|
||||
|
||||
500
src/driver-logitech-g300.c
Normal file
500
src/driver-logitech-g300.c
Normal file
@@ -0,0 +1,500 @@
|
||||
/*
|
||||
* Copyright © 2016 Thomas Hindoe Paaboel Andersen.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the next
|
||||
* paragraph) shall be included in all copies or substantial portions of the
|
||||
* Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <libevdev/libevdev.h>
|
||||
#include <linux/input.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "libratbag-private.h"
|
||||
#include "libratbag-hidraw.h"
|
||||
|
||||
#define LOGITECH_G300_PROFILE_MAX 2
|
||||
#define LOGITECH_G300_BUTTON_MAX 8
|
||||
#define LOGITECH_G300_NUM_DPI 4
|
||||
#define LOGITECH_G300_NUM_LED 0
|
||||
|
||||
#define LOGITECH_G300_REPORT_ID_SET_ACTIVE_PROFILE 0xF0
|
||||
#define LOGITECH_G300_REPORT_ID_GET_ACTIVE_PROFILE 0xF1
|
||||
#define LOGITECH_G300_REPORT_ID_SET_ACTIVE_RESOLUTION 0xF0
|
||||
#define LOGITECH_G300_REPORT_ID_PROFILE_0 0xF3
|
||||
#define LOGITECH_G300_REPORT_ID_PROFILE_1 0xF4
|
||||
#define LOGITECH_G300_REPORT_ID_PROFILE_2 0xF5
|
||||
|
||||
#define LOGITECH_G300_REPORT_SIZE_ACTIVE_PROFILE 2
|
||||
#define LOGITECH_G300_REPORT_SIZE_PROFILE 35
|
||||
|
||||
struct logitech_g300_resolution {
|
||||
uint8_t dpi :7; /* Range 1-10. dpi = 250*value */
|
||||
uint8_t is_default :1;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct logitech_g300_button {
|
||||
uint8_t code;
|
||||
uint8_t modifier;
|
||||
uint8_t key;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct logitech_g300_profile_report {
|
||||
uint8_t id; /* F3, F4, F5 */
|
||||
uint8_t led; /* 00=off, 01=red, 02=green, 03=yellow, 04=blue, 05=pink, 06=turquoise, 07=white */
|
||||
uint8_t frequency; /* 00=1000, 01=125, 02=250, 03=500 */
|
||||
struct logitech_g300_resolution dpi_levels[LOGITECH_G300_NUM_DPI];
|
||||
uint8_t unknown; /* dpi index for shift, but something else too */
|
||||
struct logitech_g300_button buttons[LOGITECH_G300_BUTTON_MAX + 1];
|
||||
} __attribute__((packed));
|
||||
|
||||
struct logitech_g300_profile_data {
|
||||
struct logitech_g300_profile_report report;
|
||||
};
|
||||
|
||||
struct logitech_g300_data {
|
||||
struct logitech_g300_profile_data profile_data[LOGITECH_G300_PROFILE_MAX + 1];
|
||||
};
|
||||
|
||||
_Static_assert(sizeof(struct logitech_g300_profile_report) == LOGITECH_G300_REPORT_SIZE_PROFILE,
|
||||
"Size of logitech_g300_profile_report is wrong");
|
||||
|
||||
struct logitech_g300_button_type_mapping {
|
||||
uint8_t raw;
|
||||
enum ratbag_button_type type;
|
||||
};
|
||||
|
||||
static const struct logitech_g300_button_type_mapping logitech_g300_button_type_mapping[] = {
|
||||
{ 0, RATBAG_BUTTON_TYPE_LEFT },
|
||||
{ 1, RATBAG_BUTTON_TYPE_RIGHT },
|
||||
{ 2, RATBAG_BUTTON_TYPE_MIDDLE },
|
||||
{ 3, RATBAG_BUTTON_TYPE_THUMB },
|
||||
{ 4, RATBAG_BUTTON_TYPE_THUMB2 },
|
||||
{ 5, RATBAG_BUTTON_TYPE_PINKIE },
|
||||
{ 6, RATBAG_BUTTON_TYPE_PINKIE2 },
|
||||
{ 7, RATBAG_BUTTON_TYPE_PROFILE_CYCLE_UP },
|
||||
{ 8, RATBAG_BUTTON_TYPE_RESOLUTION_CYCLE_UP },
|
||||
};
|
||||
|
||||
static enum ratbag_button_type
|
||||
logitech_g300_raw_to_button_type(uint8_t data)
|
||||
{
|
||||
const struct logitech_g300_button_type_mapping *mapping;
|
||||
|
||||
ARRAY_FOR_EACH(logitech_g300_button_type_mapping, mapping) {
|
||||
if (mapping->raw == data)
|
||||
return mapping->type;
|
||||
}
|
||||
|
||||
return RATBAG_BUTTON_TYPE_UNKNOWN;
|
||||
}
|
||||
|
||||
struct logitech_g300_button_mapping {
|
||||
uint8_t raw;
|
||||
struct ratbag_button_action action;
|
||||
};
|
||||
|
||||
static struct logitech_g300_button_mapping logitech_g300_button_mapping[] = {
|
||||
/* 0x00 is either key or unassigned. Must be handled separatly */
|
||||
{ 0x01, BUTTON_ACTION_BUTTON(1) },
|
||||
{ 0x02, BUTTON_ACTION_BUTTON(2) },
|
||||
{ 0x03, BUTTON_ACTION_BUTTON(3) },
|
||||
{ 0x04, BUTTON_ACTION_BUTTON(4) },
|
||||
{ 0x05, BUTTON_ACTION_BUTTON(5) },
|
||||
{ 0x06, BUTTON_ACTION_BUTTON(6) },
|
||||
{ 0x07, BUTTON_ACTION_BUTTON(7) },
|
||||
{ 0x08, BUTTON_ACTION_BUTTON(8) },
|
||||
{ 0x09, BUTTON_ACTION_BUTTON(9) },
|
||||
{ 0x0A, BUTTON_ACTION_SPECIAL(RATBAG_BUTTON_ACTION_SPECIAL_RESOLUTION_UP) },
|
||||
{ 0x0B, BUTTON_ACTION_SPECIAL(RATBAG_BUTTON_ACTION_SPECIAL_RESOLUTION_DOWN) },
|
||||
{ 0x0C, BUTTON_ACTION_SPECIAL(RATBAG_BUTTON_ACTION_SPECIAL_RESOLUTION_CYCLE_UP) },
|
||||
{ 0x0D, BUTTON_ACTION_SPECIAL(RATBAG_BUTTON_ACTION_SPECIAL_PROFILE_CYCLE_UP) },
|
||||
{ 0x0E, BUTTON_ACTION_SPECIAL(RATBAG_BUTTON_ACTION_SPECIAL_RESOLUTION_ALTERNATE) },
|
||||
{ 0x0F, BUTTON_ACTION_SPECIAL(RATBAG_BUTTON_ACTION_SPECIAL_RESOLUTION_DEFAULT) },
|
||||
};
|
||||
|
||||
static const struct ratbag_button_action*
|
||||
logitech_g300_raw_to_button_action(uint8_t data)
|
||||
{
|
||||
struct logitech_g300_button_mapping *mapping;
|
||||
|
||||
ARRAY_FOR_EACH(logitech_g300_button_mapping, mapping) {
|
||||
if (mapping->raw == data)
|
||||
return &mapping->action;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static uint8_t
|
||||
logitech_g300_button_action_to_raw(const struct ratbag_button_action *action)
|
||||
{
|
||||
struct logitech_g300_button_mapping *mapping;
|
||||
|
||||
ARRAY_FOR_EACH(logitech_g300_button_mapping, mapping) {
|
||||
if (ratbag_button_action_match(&mapping->action, action))
|
||||
return mapping->raw;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct logitech_g300_frequency_mapping {
|
||||
uint8_t raw;
|
||||
unsigned int frequency;
|
||||
};
|
||||
|
||||
static struct logitech_g300_frequency_mapping logitech_g300_frequency_mapping[] = {
|
||||
{ 0, 1000 },
|
||||
{ 1, 125 },
|
||||
{ 2, 250 },
|
||||
{ 3, 500 },
|
||||
};
|
||||
|
||||
static unsigned int
|
||||
logitech_g300_raw_to_frequency(uint8_t data)
|
||||
{
|
||||
struct logitech_g300_frequency_mapping *mapping;
|
||||
|
||||
ARRAY_FOR_EACH(logitech_g300_frequency_mapping, mapping) {
|
||||
if (mapping->raw == data)
|
||||
return mapping->frequency;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static uint8_t
|
||||
logitech_g300_frequency_to_raw(unsigned int frequency)
|
||||
{
|
||||
struct logitech_g300_frequency_mapping *mapping;
|
||||
|
||||
ARRAY_FOR_EACH(logitech_g300_frequency_mapping, mapping) {
|
||||
if (mapping->frequency == frequency)
|
||||
return mapping->raw;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
logitech_g300_current_profile(struct ratbag_device *device)
|
||||
{
|
||||
struct logitech_g300_data *drv_data = device->drv_data;
|
||||
uint8_t buf[LOGITECH_G300_REPORT_SIZE_ACTIVE_PROFILE];
|
||||
int i, ret;
|
||||
|
||||
ret = ratbag_hidraw_raw_request(device, LOGITECH_G300_REPORT_ID_GET_ACTIVE_PROFILE, buf,
|
||||
sizeof(buf), HID_FEATURE_REPORT, HID_REQ_GET_REPORT);
|
||||
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
if (ret != sizeof(buf))
|
||||
return -EIO;
|
||||
|
||||
/* The current profile is identifed by its LED color code. */
|
||||
for (i = 0; i <= LOGITECH_G300_PROFILE_MAX; i++) {
|
||||
struct logitech_g300_profile_report report;
|
||||
|
||||
report = drv_data->profile_data[i].report;
|
||||
if (report.led == buf[1])
|
||||
return i;
|
||||
}
|
||||
|
||||
return -EPROTO;
|
||||
}
|
||||
|
||||
static int
|
||||
logitech_g300_set_current_profile(struct ratbag_device *device, unsigned int index)
|
||||
{
|
||||
uint8_t buf[] = {LOGITECH_G300_REPORT_ID_SET_ACTIVE_PROFILE, 0x80 + index, 0x00, 0x00};
|
||||
int ret;
|
||||
|
||||
if (index > LOGITECH_G300_PROFILE_MAX)
|
||||
return -EINVAL;
|
||||
|
||||
ret = ratbag_hidraw_raw_request(device, buf[0], buf, sizeof(buf),
|
||||
HID_FEATURE_REPORT, HID_REQ_SET_REPORT);
|
||||
|
||||
return ret == sizeof(buf) ? 0 : ret;
|
||||
}
|
||||
|
||||
#if 0
|
||||
static int
|
||||
logitech_g300_set_current_resolution(struct ratbag_device *device, unsigned int index)
|
||||
{
|
||||
uint8_t buf[] = {LOGITECH_G300_REPORT_ID_SET_ACTIVE_PROFILE, 0x40 + index*2, 0x00, 0x00};
|
||||
int ret;
|
||||
|
||||
if (index >= LOGITECH_G300_NUM_DPI)
|
||||
return -EINVAL;
|
||||
|
||||
ret = ratbag_hidraw_raw_request(device, buf[0], buf, sizeof(buf),
|
||||
HID_FEATURE_REPORT, HID_REQ_SET_REPORT);
|
||||
|
||||
return ret == sizeof(buf) ? 0 : ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
static void
|
||||
logitech_g300_read_profile(struct ratbag_profile *profile, unsigned int index)
|
||||
{
|
||||
struct ratbag_device *device = profile->device;
|
||||
struct logitech_g300_data *drv_data = device->drv_data;
|
||||
struct logitech_g300_profile_data *pdata;
|
||||
struct logitech_g300_profile_report *report;
|
||||
struct ratbag_resolution *resolution;
|
||||
unsigned int i, hz;
|
||||
uint8_t report_id;
|
||||
int rc;
|
||||
|
||||
assert(index <= LOGITECH_G300_PROFILE_MAX);
|
||||
|
||||
pdata = &drv_data->profile_data[index];
|
||||
report = &pdata->report;
|
||||
|
||||
switch (index) {
|
||||
case 0: report_id = LOGITECH_G300_REPORT_ID_PROFILE_0; break;
|
||||
case 1: report_id = LOGITECH_G300_REPORT_ID_PROFILE_1; break;
|
||||
case 2: report_id = LOGITECH_G300_REPORT_ID_PROFILE_2; break;
|
||||
}
|
||||
|
||||
rc = ratbag_hidraw_raw_request(device, report_id,
|
||||
(uint8_t*)report,
|
||||
sizeof(*report),
|
||||
HID_FEATURE_REPORT,
|
||||
HID_REQ_GET_REPORT);
|
||||
|
||||
if (rc < (signed)sizeof(*report)) {
|
||||
log_error(device->ratbag,
|
||||
"Error while requesting profile: %d\n", rc);
|
||||
return;
|
||||
}
|
||||
|
||||
hz = logitech_g300_raw_to_frequency(report->frequency);
|
||||
|
||||
for (i = 0; i < profile->resolution.num_modes; i++) {
|
||||
struct logitech_g300_resolution *res =
|
||||
&report->dpi_levels[i];
|
||||
|
||||
resolution = &profile->resolution.modes[i];
|
||||
resolution->dpi_x = res->dpi * 250;
|
||||
resolution->dpi_y = res->dpi * 250;
|
||||
resolution->hz = hz;
|
||||
resolution->is_default = res->is_default;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
logitech_g300_read_button(struct ratbag_button *button)
|
||||
{
|
||||
const struct ratbag_button_action *action;
|
||||
struct ratbag_profile *profile = button->profile;
|
||||
struct ratbag_device *device = profile->device;
|
||||
struct logitech_g300_data *drv_data = device->drv_data;
|
||||
struct logitech_g300_profile_data *pdata;
|
||||
struct logitech_g300_profile_report *profile_report;
|
||||
struct logitech_g300_button *button_report;
|
||||
|
||||
pdata = &drv_data->profile_data[profile->index];
|
||||
profile_report = &pdata->report;
|
||||
button_report = &profile_report->buttons[button->index];
|
||||
|
||||
ratbag_button_enable_action_type(button, RATBAG_BUTTON_ACTION_TYPE_BUTTON);
|
||||
ratbag_button_enable_action_type(button, RATBAG_BUTTON_ACTION_TYPE_SPECIAL);
|
||||
ratbag_button_enable_action_type(button, RATBAG_BUTTON_ACTION_TYPE_KEY);
|
||||
|
||||
button->type = logitech_g300_raw_to_button_type(button->index);
|
||||
|
||||
action = logitech_g300_raw_to_button_action(button_report->code);
|
||||
if (action) {
|
||||
button->action = *action;
|
||||
}
|
||||
else if (button_report->code == 0x00 && (button_report->modifier > 0x00 || button_report->key > 0x00))
|
||||
{
|
||||
struct ratbag_button_action *key_action = &button->action;
|
||||
|
||||
key_action->type = RATBAG_BUTTON_ACTION_TYPE_KEY;
|
||||
key_action->action.key.key = ratbag_hidraw_get_keycode_from_keyboard_usage(
|
||||
device, button_report->key);
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
logitech_g300_test_hidraw(struct ratbag_device *device)
|
||||
{
|
||||
return ratbag_hidraw_has_report(device, LOGITECH_G300_REPORT_ID_GET_ACTIVE_PROFILE);
|
||||
}
|
||||
|
||||
static int
|
||||
logitech_g300_probe(struct ratbag_device *device)
|
||||
{
|
||||
int rc;
|
||||
struct ratbag_profile *profile;
|
||||
struct logitech_g300_data *drv_data = NULL;
|
||||
int active_idx;
|
||||
|
||||
rc = ratbag_find_hidraw(device, logitech_g300_test_hidraw);
|
||||
if (rc)
|
||||
goto err;
|
||||
|
||||
drv_data = zalloc(sizeof(*drv_data));
|
||||
ratbag_set_drv_data(device, drv_data);
|
||||
|
||||
/* profiles are 0-indexed */
|
||||
ratbag_device_init_profiles(device,
|
||||
LOGITECH_G300_PROFILE_MAX + 1,
|
||||
LOGITECH_G300_NUM_DPI,
|
||||
LOGITECH_G300_BUTTON_MAX + 1,
|
||||
LOGITECH_G300_NUM_LED);
|
||||
|
||||
ratbag_device_set_capability(device, RATBAG_DEVICE_CAP_SWITCHABLE_RESOLUTION);
|
||||
ratbag_device_set_capability(device, RATBAG_DEVICE_CAP_SWITCHABLE_PROFILE);
|
||||
ratbag_device_set_capability(device, RATBAG_DEVICE_CAP_BUTTON_KEY);
|
||||
|
||||
active_idx = logitech_g300_current_profile(device);
|
||||
|
||||
if (active_idx < 0) {
|
||||
log_error(device->ratbag,
|
||||
"Can't talk to the mouse: '%s' (%d)\n",
|
||||
strerror(-active_idx),
|
||||
active_idx);
|
||||
rc = -ENODEV;
|
||||
goto err;
|
||||
}
|
||||
|
||||
list_for_each(profile, &device->profiles, link) {
|
||||
if (profile->index == (unsigned int)active_idx) {
|
||||
profile->is_active = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
log_raw(device->ratbag,
|
||||
"'%s' is in profile %d\n",
|
||||
ratbag_device_get_name(device),
|
||||
profile->index);
|
||||
|
||||
return 0;
|
||||
|
||||
err:
|
||||
free(drv_data);
|
||||
ratbag_set_drv_data(device, NULL);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int
|
||||
logitech_g300_write_profile(struct ratbag_profile *profile)
|
||||
{
|
||||
struct ratbag_device *device = profile->device;
|
||||
struct logitech_g300_data *drv_data = device->drv_data;
|
||||
struct logitech_g300_profile_data *pdata;
|
||||
struct logitech_g300_profile_report *report;
|
||||
struct ratbag_button *button;
|
||||
uint8_t *buf;
|
||||
unsigned int hz, i;
|
||||
int rc;
|
||||
|
||||
pdata = &drv_data->profile_data[profile->index];
|
||||
report = &pdata->report;
|
||||
|
||||
/* The same hz is used for all resolutions */
|
||||
hz = profile->resolution.modes[0].hz;
|
||||
report->frequency = logitech_g300_frequency_to_raw(hz);
|
||||
|
||||
for (i = 0; i < profile->resolution.num_modes; i++) {
|
||||
struct ratbag_resolution *resolution = &profile->resolution.modes[i];
|
||||
struct logitech_g300_resolution *res = &report->dpi_levels[i];
|
||||
|
||||
res->dpi = resolution->dpi_x / 250;
|
||||
res->is_default = resolution->is_default;
|
||||
}
|
||||
|
||||
list_for_each(button, &profile->buttons, link) {
|
||||
struct ratbag_button_action *action = &button->action;
|
||||
struct logitech_g300_button *raw_button;
|
||||
|
||||
if (!button->dirty)
|
||||
continue;
|
||||
|
||||
raw_button = &report->buttons[button->index];
|
||||
|
||||
raw_button->code = logitech_g300_button_action_to_raw(action);
|
||||
raw_button->modifier = 0x00;
|
||||
raw_button->key = 0x00;
|
||||
if (action->type == RATBAG_BUTTON_ACTION_TYPE_KEY) {
|
||||
raw_button->key = ratbag_hidraw_get_keyboard_usage_from_keycode(
|
||||
device, action->action.key.key);
|
||||
}
|
||||
}
|
||||
|
||||
buf = (uint8_t*)report;
|
||||
|
||||
rc = ratbag_hidraw_raw_request(device, report->id,
|
||||
buf,
|
||||
sizeof(*report),
|
||||
HID_FEATURE_REPORT,
|
||||
HID_REQ_SET_REPORT);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int
|
||||
logitech_g300_commit(struct ratbag_device *device)
|
||||
{
|
||||
struct ratbag_profile *profile;
|
||||
int rc = 0;
|
||||
|
||||
list_for_each(profile, &device->profiles, link) {
|
||||
if (!profile->dirty)
|
||||
continue;
|
||||
|
||||
log_debug(device->ratbag,
|
||||
"Profile %d changed, rewriting\n", profile->index);
|
||||
|
||||
rc = logitech_g300_write_profile(profile);
|
||||
if (rc)
|
||||
return rc;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
logitech_g300_remove(struct ratbag_device *device)
|
||||
{
|
||||
ratbag_close_hidraw(device);
|
||||
free(ratbag_get_drv_data(device));
|
||||
}
|
||||
|
||||
struct ratbag_driver logitech_g300_driver = {
|
||||
.name = "Logitech G300",
|
||||
.id = "logitech_g300",
|
||||
.probe = logitech_g300_probe,
|
||||
.remove = logitech_g300_remove,
|
||||
.read_profile = logitech_g300_read_profile,
|
||||
.commit = logitech_g300_commit,
|
||||
.set_active_profile = logitech_g300_set_current_profile,
|
||||
.read_button = logitech_g300_read_button,
|
||||
};
|
||||
@@ -36,6 +36,7 @@
|
||||
#define ROCCAT_PROFILE_MAX 4
|
||||
#define ROCCAT_BUTTON_MAX 23
|
||||
#define ROCCAT_NUM_DPI 5
|
||||
#define ROCCAT_LED_MAX 0
|
||||
|
||||
#define ROCCAT_MAX_RETRY_READY 10
|
||||
|
||||
@@ -795,7 +796,8 @@ roccat_probe(struct ratbag_device *device)
|
||||
ratbag_device_init_profiles(device,
|
||||
ROCCAT_PROFILE_MAX + 1,
|
||||
ROCCAT_NUM_DPI,
|
||||
ROCCAT_BUTTON_MAX + 1);
|
||||
ROCCAT_BUTTON_MAX + 1,
|
||||
ROCCAT_LED_MAX);
|
||||
|
||||
ratbag_device_set_capability(device, RATBAG_DEVICE_CAP_BUTTON_MACROS);
|
||||
|
||||
|
||||
@@ -122,6 +122,34 @@ test_read_button(struct ratbag_button *button)
|
||||
ratbag_button_enable_action_type(button, RATBAG_BUTTON_ACTION_TYPE_MACRO);
|
||||
}
|
||||
|
||||
static void
|
||||
test_read_led(struct ratbag_led *led)
|
||||
{
|
||||
struct ratbag_device *device = led->profile->device;
|
||||
struct ratbag_test_device *d = ratbag_get_drv_data(device);
|
||||
struct ratbag_test_profile *p = &d->profiles[led->profile->index];
|
||||
struct ratbag_test_led t_led = p->leds[led->index];
|
||||
|
||||
switch (t_led.mode) {
|
||||
case RATBAG_LED_ON:
|
||||
led->mode = RATBAG_LED_ON;
|
||||
break;
|
||||
case RATBAG_LED_CYCLE:
|
||||
led->mode = RATBAG_LED_CYCLE;
|
||||
break;
|
||||
case RATBAG_LED_BREATHING:
|
||||
led->mode = RATBAG_LED_BREATHING;
|
||||
break;
|
||||
default:
|
||||
led->mode = RATBAG_LED_OFF;
|
||||
}
|
||||
led->color.red = t_led.color.red;
|
||||
led->color.green = t_led.color.green;
|
||||
led->color.blue = t_led.color.blue;
|
||||
led->hz = t_led.hz;
|
||||
led->brightness = t_led.brightness;
|
||||
}
|
||||
|
||||
static int
|
||||
test_write_button(struct ratbag_button *button,
|
||||
const struct ratbag_button_action *action)
|
||||
@@ -131,6 +159,17 @@ test_write_button(struct ratbag_button *button,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
test_write_led(struct ratbag_led *led,
|
||||
enum ratbag_led_mode mode,
|
||||
struct ratbag_color color, unsigned int hz,
|
||||
unsigned int brightness)
|
||||
{
|
||||
/* check if the device is still valid */
|
||||
assert(ratbag_get_drv_data(led->profile->device) != NULL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
test_fake_probe(struct ratbag_device *device)
|
||||
{
|
||||
@@ -146,7 +185,8 @@ test_probe(struct ratbag_device *device, void *data)
|
||||
ratbag_device_init_profiles(device,
|
||||
test_device->num_profiles,
|
||||
test_device->num_resolutions,
|
||||
test_device->num_buttons);
|
||||
test_device->num_buttons,
|
||||
test_device->num_leds);
|
||||
if (test_device->num_profiles > 1)
|
||||
ratbag_device_set_capability(device, RATBAG_DEVICE_CAP_BUTTON_MACROS);
|
||||
|
||||
@@ -175,6 +215,8 @@ struct ratbag_driver test_driver = {
|
||||
.write_profile = test_write_profile,
|
||||
.set_active_profile = test_set_active_profile,
|
||||
.read_button = test_read_button,
|
||||
.read_led = test_read_led,
|
||||
.write_button = test_write_button,
|
||||
.write_resolution_dpi = NULL,
|
||||
.write_led = test_write_led,
|
||||
};
|
||||
|
||||
@@ -138,6 +138,21 @@ static const struct hidpp20_1b04_physical_mapping hidpp20_1b04_physical_mapping[
|
||||
BUTTON_PHYS_MAPPING(221, "LedToggle" , RATBAG_BUTTON_TYPE_UNKNOWN),
|
||||
};
|
||||
|
||||
struct hidpp20_8070_location_mapping {
|
||||
uint16_t value;
|
||||
const char *name;
|
||||
enum ratbag_led_type type;
|
||||
};
|
||||
|
||||
#define LED_LOC_MAPPING(v_, n_, t_) \
|
||||
{ v_, n_, t_ }
|
||||
|
||||
static const struct hidpp20_8070_location_mapping hidpp20_8070_location_mapping[] = {
|
||||
LED_LOC_MAPPING(0, "None", RATBAG_LED_TYPE_UNKNOWN),
|
||||
LED_LOC_MAPPING(256, "Logo LED", RATBAG_LED_TYPE_LOGO),
|
||||
LED_LOC_MAPPING(512, "Side LED", RATBAG_LED_TYPE_SIDE),
|
||||
};
|
||||
|
||||
const struct ratbag_button_action *
|
||||
hidpp20_1b04_get_logical_mapping(uint16_t value)
|
||||
{
|
||||
@@ -203,6 +218,32 @@ hidpp20_1b04_get_physical_mapping_name(uint16_t value)
|
||||
return "UNKNOWN";
|
||||
}
|
||||
|
||||
enum ratbag_led_type
|
||||
hidpp20_8070_get_location_mapping(uint16_t value)
|
||||
{
|
||||
const struct hidpp20_8070_location_mapping *map;
|
||||
|
||||
ARRAY_FOR_EACH(hidpp20_8070_location_mapping, map) {
|
||||
if (map->value == value)
|
||||
return map->type;
|
||||
}
|
||||
|
||||
return RATBAG_LED_TYPE_UNKNOWN;
|
||||
}
|
||||
|
||||
const char *
|
||||
hidpp20_8070_get_location_mapping_name(uint16_t value)
|
||||
{
|
||||
const struct hidpp20_8070_location_mapping *map;
|
||||
|
||||
ARRAY_FOR_EACH(hidpp20_8070_location_mapping, map) {
|
||||
if (map->value == value)
|
||||
return map->name;
|
||||
}
|
||||
|
||||
return "UNKNOWN";
|
||||
}
|
||||
|
||||
int
|
||||
hidpp_write_command(struct hidpp_device *dev, uint8_t *cmd, int size)
|
||||
{
|
||||
|
||||
@@ -106,6 +106,12 @@ hidpp20_1b04_get_physical_mapping_name(uint16_t value);
|
||||
enum ratbag_button_type
|
||||
hidpp20_1b04_get_physical_mapping(uint16_t value);
|
||||
|
||||
enum ratbag_led_type
|
||||
hidpp20_8070_get_location_mapping(uint16_t value);
|
||||
|
||||
const char *
|
||||
hidpp20_8070_get_location_mapping_name(uint16_t value);
|
||||
|
||||
const char *
|
||||
hidpp20_1b04_get_logical_mapping_name(uint16_t value);
|
||||
|
||||
|
||||
@@ -305,7 +305,7 @@ hidpp10_get_hidpp_notifications(struct hidpp10_device *dev,
|
||||
return res;
|
||||
|
||||
*reporting_flags = notifications.msg.parameters[0];
|
||||
*reporting_flags |= (notifications.msg.parameters[0] & 0x1F) << 8;
|
||||
*reporting_flags |= (notifications.msg.parameters[1] & 0x1F) << 8;
|
||||
*reporting_flags |= (notifications.msg.parameters[2] & 0x7 ) << 16;
|
||||
|
||||
return res;
|
||||
@@ -1582,11 +1582,12 @@ static const enum ratbag_button_action_special hidpp10_profiles_specials[] = {
|
||||
[0x02] = RATBAG_BUTTON_ACTION_SPECIAL_WHEEL_RIGHT,
|
||||
[0x03] = RATBAG_BUTTON_ACTION_SPECIAL_BATTERY_LEVEL,
|
||||
[0x04] = RATBAG_BUTTON_ACTION_SPECIAL_RESOLUTION_UP,
|
||||
[0x05] = RATBAG_BUTTON_ACTION_SPECIAL_RESOLUTION_CYCLE_UP,
|
||||
|
||||
[0x05 ... 0x07] = RATBAG_BUTTON_ACTION_SPECIAL_INVALID,
|
||||
[0x06 ... 0x07] = RATBAG_BUTTON_ACTION_SPECIAL_INVALID,
|
||||
|
||||
[0x08] = RATBAG_BUTTON_ACTION_SPECIAL_RESOLUTION_DOWN,
|
||||
[0x09] = RATBAG_BUTTON_ACTION_SPECIAL_RESOLUTION_CYCLE_UP,
|
||||
[0x09] = RATBAG_BUTTON_ACTION_SPECIAL_RESOLUTION_CYCLE_DOWN,
|
||||
|
||||
[0x0a ... 0x0f] = RATBAG_BUTTON_ACTION_SPECIAL_INVALID,
|
||||
|
||||
@@ -1596,8 +1597,9 @@ static const enum ratbag_button_action_special hidpp10_profiles_specials[] = {
|
||||
[0x12 ... 0x1f] = RATBAG_BUTTON_ACTION_SPECIAL_INVALID,
|
||||
|
||||
[0x20] = RATBAG_BUTTON_ACTION_SPECIAL_PROFILE_DOWN,
|
||||
[0x21] = RATBAG_BUTTON_ACTION_SPECIAL_PROFILE_CYCLE_DOWN,
|
||||
|
||||
[0x21 ... 0xff] = RATBAG_BUTTON_ACTION_SPECIAL_INVALID,
|
||||
[0x22 ... 0xff] = RATBAG_BUTTON_ACTION_SPECIAL_INVALID,
|
||||
};
|
||||
|
||||
enum ratbag_button_action_special
|
||||
|
||||
@@ -494,6 +494,7 @@ struct hidpp10_profile {
|
||||
} buttons[PROFILE_NUM_BUTTONS];
|
||||
union hidpp10_macro_data *macros[PROFILE_NUM_BUTTONS];
|
||||
size_t num_buttons;
|
||||
size_t num_leds;
|
||||
|
||||
unsigned int initialized;
|
||||
};
|
||||
|
||||
179
src/hidpp20.c
179
src/hidpp20.c
@@ -500,6 +500,118 @@ err:
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* 0x8070 - Color LED effects */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
#define CMD_COLOR_LED_EFFECTS_GET_INFO 0x00
|
||||
#define CMD_COLOR_LED_EFFECTS_GET_ZONE_INFO 0x10
|
||||
|
||||
static int
|
||||
hidpp20_color_led_zones_get_count(struct hidpp20_device *device, uint8_t reg)
|
||||
{
|
||||
int rc;
|
||||
union hidpp20_message msg = {
|
||||
.msg.report_id = REPORT_ID_SHORT,
|
||||
.msg.device_idx = device->index,
|
||||
.msg.address = CMD_COLOR_LED_EFFECTS_GET_INFO,
|
||||
};
|
||||
struct hidpp20_color_led_info *info;
|
||||
uint8_t feature_index;
|
||||
|
||||
feature_index = hidpp_root_get_feature_idx(device,
|
||||
HIDPP_PAGE_COLOR_LED_EFFECTS);
|
||||
if (feature_index == 0)
|
||||
return -ENOTSUP;
|
||||
|
||||
msg.msg.sub_id = feature_index;
|
||||
|
||||
rc = hidpp20_request_command(device, &msg);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
info = (struct hidpp20_color_led_info *)msg.msg.parameters;
|
||||
|
||||
return info->zone_count;
|
||||
}
|
||||
|
||||
int
|
||||
hidpp20_color_led_effects_get_zone_info(struct hidpp20_device *device,
|
||||
uint8_t reg,
|
||||
struct hidpp20_color_led_zone_info *info)
|
||||
{
|
||||
int rc;
|
||||
struct hidpp20_color_led_zone_info *msg_info;
|
||||
union hidpp20_message msg = {
|
||||
.msg.report_id = REPORT_ID_LONG,
|
||||
.msg.device_idx = device->index,
|
||||
.msg.sub_id = reg,
|
||||
.msg.address = CMD_COLOR_LED_EFFECTS_GET_ZONE_INFO,
|
||||
.msg.parameters[0] = info->index,
|
||||
};
|
||||
|
||||
rc = hidpp20_request_command(device, &msg);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
msg_info = (struct hidpp20_color_led_zone_info *)msg.msg.parameters;
|
||||
info->location = msg_info->location;
|
||||
info->num_effects = msg_info->num_effects;
|
||||
info->persistency_caps = msg_info->persistency_caps;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
hidpp20_color_led_effects_get_zone_infos(struct hidpp20_device *device,
|
||||
struct hidpp20_color_led_zone_info **infos_list)
|
||||
{
|
||||
uint8_t feature_index;
|
||||
struct hidpp20_color_led_zone_info *i_list, *info;
|
||||
uint8_t num_infos;
|
||||
unsigned i;
|
||||
int rc;
|
||||
|
||||
feature_index = hidpp_root_get_feature_idx(device,
|
||||
HIDPP_PAGE_COLOR_LED_EFFECTS);
|
||||
if (feature_index == 0)
|
||||
return -ENOTSUP;
|
||||
|
||||
rc = hidpp20_color_led_zones_get_count(device, feature_index);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
num_infos = rc;
|
||||
if (num_infos == 0) {
|
||||
*infos_list = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
i_list = zalloc(num_infos * sizeof(struct hidpp20_color_led_zone_info));
|
||||
|
||||
for (i = 0; i < num_infos; i++) {
|
||||
info = &i_list[i];
|
||||
info->index = i;
|
||||
rc = hidpp20_color_led_effects_get_zone_info(device, feature_index, info);
|
||||
if (rc)
|
||||
goto err;
|
||||
|
||||
hidpp_log_raw(&device->base,
|
||||
"led_info %d: location: %d type %s num_effects: %d persistency_caps: 0x%02x\n",
|
||||
info->index,
|
||||
info->location,
|
||||
hidpp20_8070_get_location_mapping_name(info->location),
|
||||
info->num_effects,
|
||||
info->persistency_caps);
|
||||
}
|
||||
|
||||
*infos_list = i_list;
|
||||
return num_infos;
|
||||
err:
|
||||
free(i_list);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* 0x1b04: Special keys and mouse buttons */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
@@ -1289,6 +1401,7 @@ hidpp20_onboard_profiles_initialize(struct hidpp20_device *device,
|
||||
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->num_leds = HIDPP20_LED_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) {
|
||||
@@ -1653,11 +1766,7 @@ union hidpp20_internal_profile {
|
||||
uint8_t default_dpi;
|
||||
uint8_t switched_dpi;
|
||||
uint16_t dpi[5];
|
||||
struct {
|
||||
uint8_t red;
|
||||
uint8_t green;
|
||||
uint8_t blue;
|
||||
} profile_color;
|
||||
struct hidpp20_color profile_color;
|
||||
uint8_t power_mode;
|
||||
uint8_t angle_snapping;
|
||||
uint8_t reserved[14];
|
||||
@@ -1667,8 +1776,7 @@ union hidpp20_internal_profile {
|
||||
char txt[16 * 3];
|
||||
uint8_t raw[16 * 3];
|
||||
} name;
|
||||
uint8_t logo_effect[11]; /* G303 only */
|
||||
uint8_t side_effects[11]; /* G303 only */
|
||||
struct hidpp20_internal_led leds[2]; /* G303, g502, g900 only */
|
||||
uint8_t free[24];
|
||||
uint16_t crc;
|
||||
} __attribute__((packed)) profile;
|
||||
@@ -1781,6 +1889,30 @@ hidpp20_buttons_from_cpu(struct hidpp20_profile *profile,
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
hidpp20_onboard_profile_read_led(struct hidpp20_led *led,
|
||||
struct hidpp20_internal_led internal_led)
|
||||
{
|
||||
uint16_t rate = 0;
|
||||
uint8_t brightness = 0;
|
||||
|
||||
switch (internal_led.mode) {
|
||||
case HIDPP20_LED_CYCLE:
|
||||
rate = internal_led.effect.cycle.rate;
|
||||
brightness = internal_led.effect.cycle.brightness;
|
||||
break;
|
||||
case HIDPP20_LED_BREATHING:
|
||||
rate = internal_led.effect.breath.rate;
|
||||
brightness = internal_led.effect.breath.brightness;
|
||||
break;
|
||||
}
|
||||
|
||||
led->mode = (enum hidpp20_led_mode)internal_led.mode;
|
||||
led->color = internal_led.color;
|
||||
led->rate = rate;
|
||||
led->brightness = brightness;
|
||||
}
|
||||
|
||||
int hidpp20_onboard_profiles_read(struct hidpp20_device *device,
|
||||
unsigned int index,
|
||||
struct hidpp20_profiles *profiles_list)
|
||||
@@ -1809,6 +1941,9 @@ int hidpp20_onboard_profiles_read(struct hidpp20_device *device,
|
||||
profile->dpi[i] = hidpp_get_unaligned_le_u16(&data[2 * i + 3]);
|
||||
}
|
||||
|
||||
for (i = 0; i < profiles_list->num_leds; i++)
|
||||
hidpp20_onboard_profile_read_led(&profile->leds[i], pdata.profile.leds[i]);
|
||||
|
||||
hidpp20_buttons_to_cpu(device, profile, pdata.profile.buttons, profiles_list->num_buttons);
|
||||
|
||||
memcpy(profile->name, pdata.profile.name.txt, sizeof(profile->name));
|
||||
@@ -1826,6 +1961,33 @@ int hidpp20_onboard_profiles_read(struct hidpp20_device *device,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
hidpp20_onboard_write_profile_led(struct hidpp20_internal_led *internal_led,
|
||||
struct hidpp20_led *led)
|
||||
{
|
||||
uint16_t rate = led->rate;
|
||||
uint8_t brightness = led->brightness;
|
||||
|
||||
internal_led->mode = (uint8_t)led->mode;
|
||||
internal_led->color.red = led->color.red;
|
||||
internal_led->color.blue = led->color.blue;
|
||||
internal_led->color.green = led->color.green;
|
||||
|
||||
switch (led->mode) {
|
||||
case HIDPP20_LED_CYCLE:
|
||||
internal_led->effect.cycle.rate = rate;
|
||||
internal_led->effect.cycle.brightness = brightness;
|
||||
break;
|
||||
case HIDPP20_LED_BREATHING:
|
||||
internal_led->effect.breath.rate = rate;
|
||||
internal_led->effect.breath.brightness = brightness;
|
||||
break;
|
||||
case HIDPP20_LED_ON:
|
||||
case HIDPP20_LED_OFF:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
int hidpp20_onboard_profiles_write(struct hidpp20_device *device,
|
||||
unsigned int index,
|
||||
struct hidpp20_profiles *profiles_list)
|
||||
@@ -1858,6 +2020,9 @@ int hidpp20_onboard_profiles_write(struct hidpp20_device *device,
|
||||
pdata.profile.dpi[i] = hidpp_cpu_to_le_u16(profile->dpi[i]);
|
||||
}
|
||||
|
||||
for (i = 0; i < profiles_list->num_leds; i++)
|
||||
hidpp20_onboard_write_profile_led(&pdata.profile.leds[i], &profile->leds[i]);
|
||||
|
||||
hidpp20_buttons_from_cpu(profile, pdata.profile.buttons, profiles_list->num_buttons);
|
||||
|
||||
memcpy(pdata.profile.name.txt, profile->name, sizeof(profile->name));
|
||||
|
||||
107
src/hidpp20.h
107
src/hidpp20.h
@@ -117,6 +117,13 @@ enum hidpp20_battery_status {
|
||||
BATTERY_STATUS_INVALID,
|
||||
};
|
||||
|
||||
enum hidpp20_led_mode {
|
||||
HIDPP20_LED_OFF = 0x00,
|
||||
HIDPP20_LED_ON = 0x01,
|
||||
HIDPP20_LED_CYCLE = 0x03,
|
||||
HIDPP20_LED_BREATHING = 0x0a,
|
||||
};
|
||||
|
||||
/**
|
||||
* Retrieves the battery level status.
|
||||
*
|
||||
@@ -258,6 +265,41 @@ int hidpp20_adjustable_dpi_set_sensor_dpi(struct hidpp20_device *device,
|
||||
|
||||
#define HIDPP_PAGE_COLOR_LED_EFFECTS 0x8070
|
||||
|
||||
|
||||
struct hidpp20_color_led_info;
|
||||
|
||||
struct hidpp20_color_led_zone_info;
|
||||
|
||||
int
|
||||
hidpp20_color_led_effects_get_zone_info(struct hidpp20_device *device,
|
||||
uint8_t reg, struct hidpp20_color_led_zone_info *info);
|
||||
|
||||
int
|
||||
hidpp20_color_led_effects_get_zone_infos(struct hidpp20_device *device,
|
||||
struct hidpp20_color_led_zone_info **infos_list);
|
||||
|
||||
enum hidpp20_color_led_location {
|
||||
HIDPP20_COLOR_LED_LOCATION_UNDEFINED = 0,
|
||||
HIDPP20_COLOR_LED_LOCATION_PRIMARY,
|
||||
HIDPP20_COLOR_LED_LOCATION_LOGO,
|
||||
HIDPP20_COLOR_LED_LOCATION_LEFT,
|
||||
HIDPP20_COLOR_LED_LOCATION_RIGHT,
|
||||
HIDPP20_COLOR_LED_LOCATION_COMBINED,
|
||||
HIDPP20_COLOR_LED_LOCATION_PRIMARY_1,
|
||||
HIDPP20_COLOR_LED_LOCATION_PRIMARY_2,
|
||||
HIDPP20_COLOR_LED_LOCATION_PRIMARY_3,
|
||||
HIDPP20_COLOR_LED_LOCATION_PRIMARY_4,
|
||||
HIDPP20_COLOR_LED_LOCATION_PRIMARY_5,
|
||||
HIDPP20_COLOR_LED_LOCATION_PRIMARY_6,
|
||||
};
|
||||
|
||||
enum hidpp20_color_led_persistency {
|
||||
HIDPP20_COLOR_LED_PERSISTENCY_UNSUPPORTED,
|
||||
HIDPP20_COLOR_LED_PERSISTENCY_ON,
|
||||
HIDPP20_COLOR_LED_PERSISTENCY_OFF,
|
||||
HIDPP20_COLOR_LED_PERSISTENCY_ON_OFF,
|
||||
};
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* 0x8100 - Onboard Profiles */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
@@ -276,6 +318,7 @@ int hidpp20_adjustable_dpi_set_sensor_dpi(struct hidpp20_device *device,
|
||||
#define HIDPP20_MODIFIER_KEY_SHIFT 0x02
|
||||
|
||||
#define HIDPP20_DPI_COUNT 5
|
||||
#define HIDPP20_LED_COUNT 2
|
||||
|
||||
union hidpp20_button_binding {
|
||||
struct {
|
||||
@@ -317,6 +360,68 @@ union hidpp20_button_binding {
|
||||
} __attribute__((packed));
|
||||
_Static_assert(sizeof(union hidpp20_button_binding) == 4, "Invalid size");
|
||||
|
||||
struct hidpp20_color_led_info {
|
||||
uint8_t zone_count;
|
||||
/* we don't care about NV capabilities for libratbag, they just
|
||||
* indicate sale demo effects */
|
||||
uint16_t nv_caps;
|
||||
uint16_t ext_caps;
|
||||
} __attribute__((packed));
|
||||
_Static_assert(sizeof(struct hidpp20_color_led_info) == 5, "Invalid size");
|
||||
|
||||
struct hidpp20_color_led_zone_info {
|
||||
uint8_t index;
|
||||
uint16_t location;
|
||||
uint8_t num_effects;
|
||||
uint8_t persistency_caps;
|
||||
} __attribute__((packed));
|
||||
_Static_assert(sizeof(struct hidpp20_color_led_zone_info) == 5, "Invalid size");
|
||||
|
||||
struct hidpp20_color {
|
||||
uint8_t red;
|
||||
uint8_t green;
|
||||
uint8_t blue;
|
||||
} __attribute__((packed));
|
||||
_Static_assert(sizeof(struct hidpp20_color) == 3, "Invalid size");
|
||||
|
||||
enum hidpp20_led_type {
|
||||
HIDPP20_LED_UNKNOWN = -1,
|
||||
HIDPP20_LED_LOGO = 0,
|
||||
HIDPP20_LED_SIDE,
|
||||
};
|
||||
|
||||
struct hidpp20_internal_led {
|
||||
uint8_t mode; /* 00 - off; 01 - on; 03 - cycle; 0a - breath */
|
||||
struct hidpp20_color color;
|
||||
union {
|
||||
struct hidpp20_led_cycle {
|
||||
uint16_t pad_1;
|
||||
uint16_t rate; /* 16000 - 20000Hz */
|
||||
uint8_t brightness; /* 0 - 100 percent */
|
||||
uint16_t pad_2;
|
||||
} __attribute__((packed)) cycle;
|
||||
struct hidpp20_led_breath {
|
||||
uint16_t rate;
|
||||
uint8_t pad_1;
|
||||
uint8_t brightness;
|
||||
uint8_t pad_2;
|
||||
uint16_t pad_3;
|
||||
} __attribute__((packed)) breath;
|
||||
} __attribute__((packed)) effect;
|
||||
};
|
||||
_Static_assert(sizeof(struct hidpp20_led_cycle) == 7, "Invalid size");
|
||||
_Static_assert(sizeof(struct hidpp20_led_breath) == 7, "Invalid size");
|
||||
_Static_assert(sizeof(struct hidpp20_internal_led) == 11, "Invalid size");
|
||||
|
||||
typedef uint8_t percent_t;
|
||||
|
||||
struct hidpp20_led {
|
||||
enum hidpp20_led_mode mode;
|
||||
struct hidpp20_color color;
|
||||
uint16_t rate;
|
||||
percent_t brightness;
|
||||
};
|
||||
|
||||
#define HIDPP20_MACRO_NOOP 0x01
|
||||
#define HIDPP20_MACRO_DELAY 0x40
|
||||
#define HIDPP20_MACRO_KEY_PRESS 0x43
|
||||
@@ -358,6 +463,7 @@ struct hidpp20_profile {
|
||||
uint16_t dpi[HIDPP20_DPI_COUNT];
|
||||
union hidpp20_button_binding buttons[32];
|
||||
union hidpp20_macro_data *macros[32];
|
||||
struct hidpp20_led leds[32];
|
||||
};
|
||||
|
||||
struct hidpp20_profiles {
|
||||
@@ -365,6 +471,7 @@ struct hidpp20_profiles {
|
||||
uint8_t num_rom_profiles;
|
||||
uint8_t num_buttons;
|
||||
uint8_t num_modes;
|
||||
uint8_t num_leds;
|
||||
uint8_t has_g_shift;
|
||||
uint8_t has_dpi_shift;
|
||||
uint8_t corded;
|
||||
|
||||
@@ -95,6 +95,7 @@ struct ratbag_device {
|
||||
struct list profiles;
|
||||
|
||||
unsigned num_buttons;
|
||||
unsigned num_leds;
|
||||
|
||||
void *drv_data;
|
||||
|
||||
@@ -130,6 +131,18 @@ struct ratbag_driver {
|
||||
*/
|
||||
void (*remove)(struct ratbag_device *device);
|
||||
|
||||
/**
|
||||
* Callback called when the driver should write any profiles that
|
||||
* were modified back to the device.
|
||||
*
|
||||
* Both profile and button structs have a dirty variable that can
|
||||
* be used to tell whether or not they've actually changed since
|
||||
* the last commit. In order to reduce the amount of time
|
||||
* committing takes, drivers should use this information to avoid
|
||||
* writing back profiles and buttons that haven't actually changed.
|
||||
*/
|
||||
int (*commit)(struct ratbag_device *device);
|
||||
|
||||
/**
|
||||
* Callback called when a read profile is requested by the
|
||||
* caller of the library.
|
||||
@@ -141,9 +154,10 @@ struct ratbag_driver {
|
||||
*/
|
||||
void (*read_profile)(struct ratbag_profile *profile, unsigned int index);
|
||||
|
||||
/**
|
||||
* Here, the driver should actually write the profile to the
|
||||
* device.
|
||||
/*
|
||||
* FIXME: This function is deprecated and should not be removed. Once
|
||||
* we've updated all the device drivers to stop using it we'll remove
|
||||
* it. Look at commit() instead.
|
||||
*/
|
||||
int (*write_profile)(struct ratbag_profile *profile);
|
||||
|
||||
@@ -168,29 +182,44 @@ struct ratbag_driver {
|
||||
*/
|
||||
void (*read_button)(struct ratbag_button *button);
|
||||
|
||||
/**
|
||||
* For the given button, store in the profile and in the device
|
||||
* the given struct ratbag_button.
|
||||
/*
|
||||
* FIXME: This function is deprecated and should not be removed. Once
|
||||
* we've updated all the device drivers to stop using it we'll remove
|
||||
* it. Look at commit() instead.
|
||||
*/
|
||||
int (*write_button)(struct ratbag_button *button,
|
||||
const struct ratbag_button_action *action);
|
||||
|
||||
/**
|
||||
* For the given profile, overwrite the current resolution
|
||||
* of the sensor expressed in DPI, and commit it to the hardware.
|
||||
*
|
||||
* Mandatory if the driver exports RATBAG_DEVICE_CAP_SWITCHABLE_RESOLUTION.
|
||||
/*
|
||||
* FIXME: This function is deprecated and should not be removed. Once
|
||||
* we've updated all the device drivers to stop using it we'll remove
|
||||
* it. Look at commit() instead.
|
||||
*/
|
||||
int (*write_resolution_dpi)(struct ratbag_resolution *resolution,
|
||||
int dpi_x, int dpi_y);
|
||||
|
||||
/**
|
||||
* For the given led, fill in the struct ratbag_led
|
||||
* with the available information.
|
||||
*/
|
||||
void (*read_led)(struct ratbag_led *led);
|
||||
|
||||
/*
|
||||
* FIXME: This function is deprecated and should be removed. Once
|
||||
* we've updated all the device drivers to stop using it we'll remove
|
||||
* it. Look at commit() instead.
|
||||
*/
|
||||
int (*write_led)(struct ratbag_led *led, enum ratbag_led_mode mode,
|
||||
struct ratbag_color color, unsigned int hz,
|
||||
unsigned int brightness);
|
||||
|
||||
/* private */
|
||||
int (*test_probe)(struct ratbag_device *device, void *data);
|
||||
|
||||
struct list link;
|
||||
};
|
||||
|
||||
struct ratbag_resolution{
|
||||
struct ratbag_resolution {
|
||||
struct ratbag_profile *profile;
|
||||
int refcount;
|
||||
void *userdata;
|
||||
@@ -202,6 +231,20 @@ struct ratbag_resolution{
|
||||
uint32_t capabilities;
|
||||
};
|
||||
|
||||
struct ratbag_led {
|
||||
int refcount;
|
||||
void *userdata;
|
||||
struct list link;
|
||||
struct ratbag_profile *profile;
|
||||
unsigned index;
|
||||
enum ratbag_led_type type;
|
||||
enum ratbag_led_mode mode;
|
||||
struct ratbag_color color;
|
||||
unsigned int hz; /**< rate of action in hz */
|
||||
unsigned int brightness; /**< brightness of the LED */
|
||||
bool dirty;
|
||||
};
|
||||
|
||||
struct ratbag_profile {
|
||||
int refcount;
|
||||
void *userdata;
|
||||
@@ -216,8 +259,11 @@ struct ratbag_profile {
|
||||
struct ratbag_resolution *modes;
|
||||
unsigned int num_modes;
|
||||
} resolution;
|
||||
struct list leds;
|
||||
|
||||
bool is_active; /**< profile is the currently active one */
|
||||
bool is_enabled;
|
||||
bool dirty; /**< profile changed since last commit */
|
||||
};
|
||||
|
||||
#define BUTTON_ACTION_NONE \
|
||||
@@ -277,6 +323,7 @@ struct ratbag_button {
|
||||
enum ratbag_button_type type;
|
||||
struct ratbag_button_action action;
|
||||
uint32_t action_caps;
|
||||
bool dirty; /* changed since last commit to device */
|
||||
};
|
||||
|
||||
static inline void
|
||||
@@ -318,7 +365,8 @@ int
|
||||
ratbag_device_init_profiles(struct ratbag_device *device,
|
||||
unsigned int num_profiles,
|
||||
unsigned int num_resolutions,
|
||||
unsigned int num_buttons);
|
||||
unsigned int num_buttons,
|
||||
unsigned int num_leds);
|
||||
|
||||
void
|
||||
ratbag_device_set_capability(struct ratbag_device *device,
|
||||
@@ -417,7 +465,9 @@ log_buffer(struct ratbag *ratbag,
|
||||
struct ratbag_driver etekcity_driver;
|
||||
struct ratbag_driver hidpp20_driver;
|
||||
struct ratbag_driver hidpp10_driver;
|
||||
struct ratbag_driver logitech_g300_driver;
|
||||
struct ratbag_driver roccat_driver;
|
||||
struct ratbag_driver gskill_driver;
|
||||
|
||||
struct ratbag_device*
|
||||
ratbag_device_new(struct ratbag *ratbag, struct udev_device *udev_device,
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
#define RATBAG_TEST_MAX_PROFILES 12
|
||||
#define RATBAG_TEST_MAX_BUTTONS 25
|
||||
#define RATBAG_TEST_MAX_RESOLUTIONS 8
|
||||
#define RATBAG_TEST_MAX_LEDS 8
|
||||
|
||||
struct ratbag_test_button {
|
||||
enum ratbag_button_action_type type;
|
||||
@@ -48,9 +49,24 @@ struct ratbag_test_resolution {
|
||||
uint32_t caps;
|
||||
};
|
||||
|
||||
struct ratbag_test_color {
|
||||
unsigned short red;
|
||||
unsigned short green;
|
||||
unsigned short blue;
|
||||
};
|
||||
|
||||
struct ratbag_test_led {
|
||||
enum ratbag_led_type type;
|
||||
enum ratbag_led_mode mode;
|
||||
struct ratbag_test_color color;
|
||||
unsigned int hz;
|
||||
unsigned int brightness;
|
||||
};
|
||||
|
||||
struct ratbag_test_profile {
|
||||
struct ratbag_test_button buttons[RATBAG_TEST_MAX_BUTTONS];
|
||||
struct ratbag_test_resolution resolutions[RATBAG_TEST_MAX_RESOLUTIONS];
|
||||
struct ratbag_test_led leds[RATBAG_TEST_MAX_LEDS];
|
||||
bool active;
|
||||
bool dflt;
|
||||
};
|
||||
@@ -59,6 +75,7 @@ struct ratbag_test_device {
|
||||
unsigned int num_profiles;
|
||||
unsigned int num_resolutions;
|
||||
unsigned int num_buttons;
|
||||
unsigned int num_leds;
|
||||
struct ratbag_test_profile profiles[RATBAG_TEST_MAX_PROFILES];
|
||||
void (*destroyed)(struct ratbag_device *device, void *data);
|
||||
void *destroyed_data;
|
||||
|
||||
@@ -35,6 +35,8 @@
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <iconv.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "libratbag-util.h"
|
||||
#include "libratbag-private.h"
|
||||
@@ -85,3 +87,95 @@ udev_prop_value(struct udev_device *device,
|
||||
|
||||
return prop_value;
|
||||
}
|
||||
|
||||
ssize_t
|
||||
ratbag_utf8_to_enc(char *buf, size_t buf_len, const char *to_enc,
|
||||
const char *format, ...)
|
||||
{
|
||||
va_list args;
|
||||
iconv_t converter;
|
||||
char str[buf_len];
|
||||
char *in_buf = str, *out_buf = (char*)buf;
|
||||
size_t in_bytes_left, out_bytes_left = buf_len;
|
||||
int ret;
|
||||
|
||||
memset(buf, 0, buf_len);
|
||||
|
||||
va_start(args, format);
|
||||
ret = vsnprintf(str, buf_len, format, args);
|
||||
va_end(args);
|
||||
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
in_bytes_left = ret;
|
||||
|
||||
converter = iconv_open(to_enc, "UTF-8");
|
||||
if (converter == (iconv_t)-1)
|
||||
return -errno;
|
||||
|
||||
ret = iconv(converter, &in_buf, &in_bytes_left, &out_buf,
|
||||
&out_bytes_left);
|
||||
if (ret)
|
||||
ret = -errno;
|
||||
else
|
||||
ret = buf_len - out_bytes_left;
|
||||
|
||||
iconv_close(converter);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
ssize_t
|
||||
ratbag_utf8_from_enc(char *in_buf, size_t in_len, const char *from_enc,
|
||||
char **out)
|
||||
{
|
||||
iconv_t converter;
|
||||
size_t len = in_len * 6,
|
||||
in_bytes_left = in_len,
|
||||
out_bytes_left = len;
|
||||
char *pos;
|
||||
ssize_t ret;
|
||||
|
||||
converter = iconv_open("UTF-8", from_enc);
|
||||
if (converter == (iconv_t)-1)
|
||||
return -errno;
|
||||
|
||||
/*
|
||||
* We *could* dynamically allocate the out buffer. However iconv's
|
||||
* obnoxious semantics, mainly the fact that it modifies every pointer
|
||||
* given to it, would make this code a lot larger and complex then it
|
||||
* needs to be for a mouse with blinking lights.
|
||||
*
|
||||
* So, since there's no encoding that takes more then 6 bytes per
|
||||
* character, allocate for that and just fail if that's not enough.
|
||||
*/
|
||||
*out = zalloc(len);
|
||||
pos = *out;
|
||||
if (!*out) {
|
||||
ret = -errno;
|
||||
goto err;
|
||||
}
|
||||
|
||||
ret = iconv(converter, &in_buf, &in_bytes_left, &pos, &out_bytes_left);
|
||||
if (ret) {
|
||||
ret = -errno;
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* Now get rid of any space in the buffer we don't need */
|
||||
*out = realloc(*out, (len - out_bytes_left) + 1);
|
||||
if (!*out)
|
||||
ret = -errno;
|
||||
else
|
||||
ret = (len - out_bytes_left) + 1;
|
||||
|
||||
err:
|
||||
if (ret < 0 && *out) {
|
||||
free(*out);
|
||||
*out = NULL;
|
||||
}
|
||||
|
||||
iconv_close(converter);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -200,4 +200,21 @@ long_set_bit_state(unsigned long *array, int bit, int state)
|
||||
const char *
|
||||
udev_prop_value(struct udev_device *device,
|
||||
const char *property_name);
|
||||
|
||||
/**
|
||||
* Converts a string from UTF-8 to the encoding specified. Returns the number
|
||||
* of bytes written to buf on success, or negative errno value on failure.
|
||||
*/
|
||||
ssize_t
|
||||
ratbag_utf8_to_enc(char *buf, size_t buf_len, const char *to_enc,
|
||||
const char *format, ...) __attribute__((format(printf, 4, 5)));
|
||||
/**
|
||||
* Converts a string from the given encoding into UTF-8. The memory for the
|
||||
* result is allocated and a pointer to the result is placed in *out. Returns
|
||||
* the number of bytes in the UTF-8 version of the string on success, negative
|
||||
* errno value on failure.
|
||||
*/
|
||||
ssize_t
|
||||
ratbag_utf8_from_enc(char *in_buf, size_t in_len, const char *from_enc,
|
||||
char **out);
|
||||
#endif /* LIBRATBAG_UTIL_H */
|
||||
|
||||
456
src/libratbag.c
456
src/libratbag.c
@@ -59,6 +59,8 @@ static void
|
||||
ratbag_profile_destroy(struct ratbag_profile *profile);
|
||||
static void
|
||||
ratbag_button_destroy(struct ratbag_button *button);
|
||||
static void
|
||||
ratbag_led_destroy(struct ratbag_led *led);
|
||||
|
||||
static void
|
||||
ratbag_default_log_func(struct ratbag *ratbag,
|
||||
@@ -533,7 +535,9 @@ ratbag_create_context(const struct ratbag_interface *interface,
|
||||
ratbag_register_driver(ratbag, &etekcity_driver);
|
||||
ratbag_register_driver(ratbag, &hidpp20_driver);
|
||||
ratbag_register_driver(ratbag, &hidpp10_driver);
|
||||
ratbag_register_driver(ratbag, &logitech_g300_driver);
|
||||
ratbag_register_driver(ratbag, &roccat_driver);
|
||||
ratbag_register_driver(ratbag, &gskill_driver);
|
||||
|
||||
return ratbag;
|
||||
}
|
||||
@@ -580,6 +584,25 @@ ratbag_create_button(struct ratbag_profile *profile, unsigned int index)
|
||||
return button;
|
||||
}
|
||||
|
||||
static struct ratbag_led *
|
||||
ratbag_create_led(struct ratbag_profile *profile, unsigned int index)
|
||||
{
|
||||
struct ratbag_device *device = profile->device;
|
||||
struct ratbag_led *led;
|
||||
|
||||
led = zalloc(sizeof(*led));
|
||||
led->refcount = 0;
|
||||
led->profile = profile;
|
||||
led->index = index;
|
||||
|
||||
list_insert(&profile->leds, &led->link);
|
||||
|
||||
if (device->driver->read_led)
|
||||
device->driver->read_led(led);
|
||||
|
||||
return led;
|
||||
}
|
||||
|
||||
static int
|
||||
ratbag_profile_init_buttons(struct ratbag_profile *profile, unsigned int count)
|
||||
{
|
||||
@@ -593,11 +616,25 @@ ratbag_profile_init_buttons(struct ratbag_profile *profile, unsigned int count)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
ratbag_profile_init_leds(struct ratbag_profile *profile, unsigned int count)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < count; i++)
|
||||
ratbag_create_led(profile, i);
|
||||
|
||||
profile->device->num_leds = count;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct ratbag_profile *
|
||||
ratbag_create_profile(struct ratbag_device *device,
|
||||
unsigned int index,
|
||||
unsigned int num_resolutions,
|
||||
unsigned int num_buttons)
|
||||
unsigned int num_buttons,
|
||||
unsigned int num_leds)
|
||||
{
|
||||
struct ratbag_profile *profile;
|
||||
unsigned i;
|
||||
@@ -609,9 +646,11 @@ ratbag_create_profile(struct ratbag_device *device,
|
||||
profile->resolution.modes = zalloc(num_resolutions *
|
||||
sizeof(*profile->resolution.modes));
|
||||
profile->resolution.num_modes = num_resolutions;
|
||||
profile->is_enabled = true;
|
||||
|
||||
list_insert(&device->profiles, &profile->link);
|
||||
list_init(&profile->buttons);
|
||||
list_init(&profile->leds);
|
||||
|
||||
for (i = 0; i < num_resolutions; i++)
|
||||
ratbag_resolution_init(profile, i, 0, 0, 0);
|
||||
@@ -620,6 +659,7 @@ ratbag_create_profile(struct ratbag_device *device,
|
||||
device->driver->read_profile(profile, index);
|
||||
|
||||
ratbag_profile_init_buttons(profile, num_buttons);
|
||||
ratbag_profile_init_leds(profile, num_leds);
|
||||
|
||||
return profile;
|
||||
}
|
||||
@@ -628,12 +668,13 @@ int
|
||||
ratbag_device_init_profiles(struct ratbag_device *device,
|
||||
unsigned int num_profiles,
|
||||
unsigned int num_resolutions,
|
||||
unsigned int num_buttons)
|
||||
unsigned int num_buttons,
|
||||
unsigned int num_leds)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < num_profiles; i++) {
|
||||
ratbag_create_profile(device, i, num_resolutions, num_buttons);
|
||||
ratbag_create_profile(device, i, num_resolutions, num_buttons, num_leds);
|
||||
}
|
||||
|
||||
device->num_profiles = num_profiles;
|
||||
@@ -649,6 +690,9 @@ ratbag_device_init_profiles(struct ratbag_device *device,
|
||||
if (num_resolutions > 1)
|
||||
ratbag_device_set_capability(device, RATBAG_DEVICE_CAP_SWITCHABLE_RESOLUTION);
|
||||
|
||||
if (num_leds > 1)
|
||||
ratbag_device_set_capability(device, RATBAG_DEVICE_CAP_LED);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -665,14 +709,18 @@ ratbag_profile_ref(struct ratbag_profile *profile)
|
||||
static void
|
||||
ratbag_profile_destroy(struct ratbag_profile *profile)
|
||||
{
|
||||
struct ratbag_button *button, *next;
|
||||
struct ratbag_button *button, *b_next;
|
||||
struct ratbag_led *led, *l_next;
|
||||
|
||||
/* if we get to the point where the profile is destroyed, buttons,
|
||||
* resolutions , etc. are at a refcount of 0, so we can destroy
|
||||
* everything */
|
||||
list_for_each_safe(button, next, &profile->buttons, link)
|
||||
list_for_each_safe(button, b_next, &profile->buttons, link)
|
||||
ratbag_button_destroy(button);
|
||||
|
||||
list_for_each_safe(led, l_next, &profile->leds, link)
|
||||
ratbag_led_destroy(led);
|
||||
|
||||
free(profile->resolution.modes);
|
||||
|
||||
list_remove(&profile->link);
|
||||
@@ -713,12 +761,31 @@ ratbag_device_get_profile(struct ratbag_device *device, unsigned int index)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
LIBRATBAG_EXPORT enum ratbag_error_code
|
||||
ratbag_profile_set_enabled(struct ratbag_profile *profile, bool enabled)
|
||||
{
|
||||
if (!ratbag_device_has_capability(profile->device,
|
||||
RATBAG_DEVICE_CAP_DISABLE_PROFILE))
|
||||
return RATBAG_ERROR_CAPABILITY;
|
||||
|
||||
profile->is_enabled = enabled;
|
||||
profile->dirty = true;
|
||||
|
||||
return RATBAG_SUCCESS;
|
||||
}
|
||||
|
||||
LIBRATBAG_EXPORT int
|
||||
ratbag_profile_is_active(struct ratbag_profile *profile)
|
||||
{
|
||||
return profile->is_active;
|
||||
}
|
||||
|
||||
LIBRATBAG_EXPORT bool
|
||||
ratbag_profile_is_enabled(const struct ratbag_profile *profile)
|
||||
{
|
||||
return profile->is_enabled;
|
||||
}
|
||||
|
||||
LIBRATBAG_EXPORT unsigned int
|
||||
ratbag_device_get_num_profiles(struct ratbag_device *device)
|
||||
{
|
||||
@@ -731,6 +798,12 @@ ratbag_device_get_num_buttons(struct ratbag_device *device)
|
||||
return device->num_buttons;
|
||||
}
|
||||
|
||||
LIBRATBAG_EXPORT unsigned int
|
||||
ratbag_device_get_num_leds(struct ratbag_device *device)
|
||||
{
|
||||
return device->num_leds;
|
||||
}
|
||||
|
||||
void
|
||||
ratbag_device_set_capability(struct ratbag_device *device,
|
||||
enum ratbag_device_capability cap)
|
||||
@@ -748,6 +821,105 @@ ratbag_device_has_capability(const struct ratbag_device *device,
|
||||
return !!(device->capabilities & (1UL << cap));
|
||||
}
|
||||
|
||||
static inline enum ratbag_error_code
|
||||
write_led_helper(struct ratbag_device *device, struct ratbag_led *led)
|
||||
{
|
||||
return device->driver->write_led(led, led->mode, led->color, led->hz, led->brightness);
|
||||
}
|
||||
|
||||
/* FIXME: This is a temporary fix for all of the drivers that have yet to be
|
||||
* converted to the new profile-oriented API. Once all of the drivers have been
|
||||
* converted, this code should be removed.
|
||||
*/
|
||||
static enum ratbag_error_code
|
||||
ratbag_old_write_profile(struct ratbag_device *device)
|
||||
{
|
||||
struct ratbag_profile *profile;
|
||||
struct ratbag_button *button;
|
||||
struct ratbag_led *led;
|
||||
struct ratbag_resolution *resolution;
|
||||
int rc;
|
||||
unsigned int i;
|
||||
|
||||
assert(device->driver->write_profile);
|
||||
|
||||
list_for_each(profile, &device->profiles, link) {
|
||||
if (!profile->dirty)
|
||||
continue;
|
||||
|
||||
rc = device->driver->write_profile(profile);
|
||||
if (rc)
|
||||
return RATBAG_ERROR_DEVICE;
|
||||
|
||||
if (device->driver->write_resolution_dpi) {
|
||||
for (i = 0; i < profile->resolution.num_modes; i++) {
|
||||
resolution = &profile->resolution.modes[i];
|
||||
|
||||
rc = device->driver->write_resolution_dpi(
|
||||
resolution, resolution->dpi_x,
|
||||
resolution->dpi_y);
|
||||
if (rc)
|
||||
return RATBAG_ERROR_DEVICE;
|
||||
}
|
||||
}
|
||||
|
||||
if (device->driver->write_button) {
|
||||
list_for_each(button, &profile->buttons, link) {
|
||||
struct ratbag_button_action action =
|
||||
button->action;
|
||||
|
||||
if (!button->dirty)
|
||||
continue;
|
||||
|
||||
rc = device->driver->write_button(button,
|
||||
&action);
|
||||
if (rc)
|
||||
return RATBAG_ERROR_DEVICE;
|
||||
}
|
||||
}
|
||||
|
||||
if (device->driver->write_led) {
|
||||
list_for_each(led, &profile->leds, link) {
|
||||
if (!led->dirty)
|
||||
continue;
|
||||
|
||||
rc = write_led_helper(device, led);
|
||||
if (rc)
|
||||
return RATBAG_ERROR_DEVICE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return RATBAG_SUCCESS;
|
||||
}
|
||||
|
||||
LIBRATBAG_EXPORT enum ratbag_error_code
|
||||
ratbag_device_commit(struct ratbag_device *device)
|
||||
{
|
||||
struct ratbag_profile *profile;
|
||||
struct ratbag_button *button;
|
||||
int rc;
|
||||
|
||||
if (!device->driver->commit) {
|
||||
rc = ratbag_old_write_profile(device);
|
||||
if (rc != RATBAG_SUCCESS)
|
||||
return rc;
|
||||
} else {
|
||||
rc = device->driver->commit(device);
|
||||
if (rc)
|
||||
return RATBAG_ERROR_DEVICE;
|
||||
}
|
||||
|
||||
list_for_each(profile, &device->profiles, link) {
|
||||
profile->dirty = false;
|
||||
|
||||
list_for_each(button, &profile->buttons, link)
|
||||
button->dirty = false;
|
||||
}
|
||||
|
||||
return RATBAG_SUCCESS;
|
||||
}
|
||||
|
||||
LIBRATBAG_EXPORT enum ratbag_error_code
|
||||
ratbag_profile_set_active(struct ratbag_profile *profile)
|
||||
{
|
||||
@@ -758,11 +930,6 @@ ratbag_profile_set_active(struct ratbag_profile *profile)
|
||||
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 RATBAG_ERROR_DEVICE;
|
||||
|
||||
assert(device->driver->set_active_profile);
|
||||
rc = device->driver->set_active_profile(device, profile->index);
|
||||
if (rc)
|
||||
@@ -842,15 +1009,14 @@ 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;
|
||||
if (resolution->dpi_x != dpi || resolution->dpi_y != dpi) {
|
||||
resolution->dpi_x = dpi;
|
||||
resolution->dpi_y = dpi;
|
||||
profile->dirty = true;
|
||||
}
|
||||
|
||||
assert(profile->device->driver->write_resolution_dpi);
|
||||
rc = profile->device->driver->write_resolution_dpi(resolution, dpi, dpi);
|
||||
|
||||
return rc == 0 ? RATBAG_SUCCESS : RATBAG_ERROR_DEVICE;
|
||||
return RATBAG_SUCCESS;
|
||||
}
|
||||
|
||||
LIBRATBAG_EXPORT enum ratbag_error_code
|
||||
@@ -858,7 +1024,6 @@ 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))
|
||||
@@ -867,18 +1032,41 @@ ratbag_resolution_set_dpi_xy(struct ratbag_resolution *resolution,
|
||||
if ((x == 0 && y != 0) || (x != 0 && y == 0))
|
||||
return RATBAG_ERROR_VALUE;
|
||||
|
||||
assert(profile->device->driver->write_resolution_dpi);
|
||||
rc = profile->device->driver->write_resolution_dpi(resolution, x, y);
|
||||
return rc == 0 ? RATBAG_SUCCESS : RATBAG_ERROR_DEVICE;
|
||||
if (resolution->dpi_x != x || resolution->dpi_y != y) {
|
||||
resolution->dpi_x = x;
|
||||
resolution->dpi_y = y;
|
||||
profile->dirty = true;
|
||||
}
|
||||
|
||||
return RATBAG_SUCCESS;
|
||||
}
|
||||
|
||||
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 RATBAG_ERROR_IMPLEMENTATION;
|
||||
if (ratbag_resolution_has_capability(resolution,
|
||||
RATBAG_RESOLUTION_CAP_INDIVIDUAL_REPORT_RATE)) {
|
||||
if (resolution->hz != hz) {
|
||||
resolution->hz = hz;
|
||||
resolution->profile->dirty = true;
|
||||
}
|
||||
} else {
|
||||
struct ratbag_profile *profile = resolution->profile;
|
||||
unsigned int i;
|
||||
|
||||
/* No indvidual report rate per resolution. Loop through all of
|
||||
* them and update. */
|
||||
for (i = 0; i < profile->resolution.num_modes; i++) {
|
||||
struct ratbag_resolution *res = &profile->resolution.modes[i];
|
||||
if (res->hz != hz) {
|
||||
res->hz = hz;
|
||||
profile->dirty = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return RATBAG_SUCCESS;
|
||||
}
|
||||
|
||||
LIBRATBAG_EXPORT int
|
||||
@@ -929,9 +1117,26 @@ ratbag_resolution_is_default(const struct ratbag_resolution *resolution)
|
||||
LIBRATBAG_EXPORT enum ratbag_error_code
|
||||
ratbag_resolution_set_default(struct ratbag_resolution *resolution)
|
||||
{
|
||||
resolution->is_default = true;
|
||||
/* FIXME: call into the driver */
|
||||
return RATBAG_ERROR_IMPLEMENTATION;
|
||||
struct ratbag_profile *profile = resolution->profile;
|
||||
unsigned int i;
|
||||
|
||||
/* Unset the default on the other resolutions */
|
||||
for (i = 0; i < profile->resolution.num_modes; i++) {
|
||||
struct ratbag_resolution *other = &profile->resolution.modes[i];
|
||||
|
||||
if (other == resolution || !other->is_default)
|
||||
continue;
|
||||
|
||||
other->is_default = false;
|
||||
profile->dirty = true;
|
||||
}
|
||||
|
||||
if (!resolution->is_default) {
|
||||
resolution->is_default = true;
|
||||
profile->dirty = true;
|
||||
}
|
||||
|
||||
return RATBAG_SUCCESS;
|
||||
}
|
||||
|
||||
LIBRATBAG_EXPORT struct ratbag_button*
|
||||
@@ -999,20 +1204,19 @@ LIBRATBAG_EXPORT enum ratbag_error_code
|
||||
ratbag_button_set_button(struct ratbag_button *button, unsigned int btn)
|
||||
{
|
||||
struct ratbag_button_action action = {0};
|
||||
int rc;
|
||||
|
||||
if (!button->profile->device->driver->write_button)
|
||||
if (!ratbag_device_has_capability(button->profile->device,
|
||||
RATBAG_DEVICE_CAP_BUTTON_KEY))
|
||||
return RATBAG_ERROR_CAPABILITY;
|
||||
|
||||
action.type = RATBAG_BUTTON_ACTION_TYPE_BUTTON;
|
||||
action.action.button = btn;
|
||||
|
||||
rc = button->profile->device->driver->write_button(button, &action);
|
||||
button->action = action;
|
||||
button->dirty = true;
|
||||
button->profile->dirty = true;
|
||||
|
||||
if (rc == 0)
|
||||
button->action = action;
|
||||
|
||||
return rc == 0 ? RATBAG_SUCCESS : RATBAG_ERROR_DEVICE;
|
||||
return RATBAG_SUCCESS;
|
||||
}
|
||||
|
||||
LIBRATBAG_EXPORT enum ratbag_button_action_special
|
||||
@@ -1029,22 +1233,21 @@ ratbag_button_set_special(struct ratbag_button *button,
|
||||
enum ratbag_button_action_special act)
|
||||
{
|
||||
struct ratbag_button_action action = {0};
|
||||
int rc;
|
||||
|
||||
/* FIXME: range checks */
|
||||
|
||||
if (!button->profile->device->driver->write_button)
|
||||
if (!ratbag_device_has_capability(button->profile->device,
|
||||
RATBAG_DEVICE_CAP_BUTTON_KEY))
|
||||
return RATBAG_ERROR_CAPABILITY;
|
||||
|
||||
action.type = RATBAG_BUTTON_ACTION_TYPE_SPECIAL;
|
||||
action.action.special = act;
|
||||
|
||||
rc = button->profile->device->driver->write_button(button, &action);
|
||||
button->action = action;
|
||||
button->dirty = true;
|
||||
button->profile->dirty = true;
|
||||
|
||||
if (rc == 0)
|
||||
button->action = action;
|
||||
|
||||
return rc == 0 ? RATBAG_SUCCESS : RATBAG_ERROR_DEVICE;
|
||||
return RATBAG_SUCCESS;
|
||||
}
|
||||
|
||||
LIBRATBAG_EXPORT unsigned int
|
||||
@@ -1067,41 +1270,41 @@ ratbag_button_set_key(struct ratbag_button *button,
|
||||
size_t sz)
|
||||
{
|
||||
struct ratbag_button_action action = {0};
|
||||
int rc;
|
||||
|
||||
/* FIXME: range checks */
|
||||
|
||||
if (!button->profile->device->driver->write_button)
|
||||
if (!ratbag_device_has_capability(button->profile->device,
|
||||
RATBAG_DEVICE_CAP_BUTTON_KEY))
|
||||
return RATBAG_ERROR_CAPABILITY;
|
||||
|
||||
/* FIXME: modifiers */
|
||||
|
||||
action.type = RATBAG_BUTTON_ACTION_TYPE_KEY;
|
||||
action.action.key.key = key;
|
||||
rc = button->profile->device->driver->write_button(button, &action);
|
||||
|
||||
if (rc == 0)
|
||||
button->action = action;
|
||||
button->action = action;
|
||||
button->dirty = true;
|
||||
button->profile->dirty = true;
|
||||
|
||||
return rc == 0 ? RATBAG_SUCCESS : RATBAG_ERROR_DEVICE;
|
||||
return RATBAG_SUCCESS;
|
||||
}
|
||||
|
||||
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)
|
||||
if (!ratbag_device_has_capability(button->profile->device,
|
||||
RATBAG_DEVICE_CAP_BUTTON_KEY))
|
||||
return RATBAG_ERROR_CAPABILITY;
|
||||
|
||||
action.type = RATBAG_BUTTON_ACTION_TYPE_NONE;
|
||||
rc = button->profile->device->driver->write_button(button, &action);
|
||||
|
||||
if (rc == 0)
|
||||
button->action = action;
|
||||
button->action = action;
|
||||
button->dirty = true;
|
||||
button->profile->dirty = true;
|
||||
|
||||
return rc == 0 ? RATBAG_SUCCESS : RATBAG_ERROR_DEVICE;
|
||||
return RATBAG_SUCCESS;
|
||||
}
|
||||
|
||||
LIBRATBAG_EXPORT struct ratbag_button *
|
||||
@@ -1114,6 +1317,16 @@ ratbag_button_ref(struct ratbag_button *button)
|
||||
return button;
|
||||
}
|
||||
|
||||
LIBRATBAG_EXPORT struct ratbag_led *
|
||||
ratbag_led_ref(struct ratbag_led *led)
|
||||
{
|
||||
assert(led->refcount < INT_MAX);
|
||||
|
||||
ratbag_profile_ref(led->profile);
|
||||
led->refcount++;
|
||||
return led;
|
||||
}
|
||||
|
||||
static void
|
||||
ratbag_button_destroy(struct ratbag_button *button)
|
||||
{
|
||||
@@ -1126,6 +1339,13 @@ ratbag_button_destroy(struct ratbag_button *button)
|
||||
free(button);
|
||||
}
|
||||
|
||||
static void
|
||||
ratbag_led_destroy(struct ratbag_led *led)
|
||||
{
|
||||
list_remove(&led->link);
|
||||
free(led);
|
||||
}
|
||||
|
||||
LIBRATBAG_EXPORT struct ratbag_button *
|
||||
ratbag_button_unref(struct ratbag_button *button)
|
||||
{
|
||||
@@ -1140,6 +1360,126 @@ ratbag_button_unref(struct ratbag_button *button)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
LIBRATBAG_EXPORT struct ratbag_led *
|
||||
ratbag_led_unref(struct ratbag_led *led)
|
||||
{
|
||||
if (led == NULL)
|
||||
return NULL;
|
||||
|
||||
assert(led->refcount > 0);
|
||||
led->refcount--;
|
||||
|
||||
ratbag_profile_unref(led->profile);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
LIBRATBAG_EXPORT enum ratbag_led_mode
|
||||
ratbag_led_get_mode(struct ratbag_led *led)
|
||||
{
|
||||
return led->mode;
|
||||
}
|
||||
|
||||
LIBRATBAG_EXPORT enum ratbag_led_type
|
||||
ratbag_led_get_type(struct ratbag_led *led)
|
||||
{
|
||||
return led->type;
|
||||
}
|
||||
|
||||
LIBRATBAG_EXPORT struct ratbag_color
|
||||
ratbag_led_get_color(struct ratbag_led *led)
|
||||
{
|
||||
return led->color;
|
||||
}
|
||||
|
||||
LIBRATBAG_EXPORT int
|
||||
ratbag_led_get_effect_rate(struct ratbag_led *led)
|
||||
{
|
||||
return led->hz;
|
||||
}
|
||||
|
||||
LIBRATBAG_EXPORT unsigned int
|
||||
ratbag_led_get_brightness(struct ratbag_led *led)
|
||||
{
|
||||
return led->brightness;
|
||||
}
|
||||
|
||||
LIBRATBAG_EXPORT enum ratbag_error_code
|
||||
ratbag_led_set_mode(struct ratbag_led *led, enum ratbag_led_mode mode)
|
||||
{
|
||||
|
||||
if (!ratbag_device_has_capability(led->profile->device,
|
||||
RATBAG_DEVICE_CAP_LED))
|
||||
return RATBAG_ERROR_CAPABILITY;
|
||||
|
||||
led->mode = mode;
|
||||
led->dirty = true;
|
||||
led->profile->dirty = true;
|
||||
return RATBAG_SUCCESS;
|
||||
}
|
||||
|
||||
LIBRATBAG_EXPORT enum ratbag_error_code
|
||||
ratbag_led_set_color(struct ratbag_led *led, struct ratbag_color color)
|
||||
{
|
||||
if (!ratbag_device_has_capability(led->profile->device,
|
||||
RATBAG_DEVICE_CAP_LED))
|
||||
return RATBAG_ERROR_CAPABILITY;
|
||||
|
||||
led->color = color;
|
||||
led->dirty = true;
|
||||
led->profile->dirty = true;
|
||||
return RATBAG_SUCCESS;
|
||||
}
|
||||
|
||||
LIBRATBAG_EXPORT enum ratbag_error_code
|
||||
ratbag_led_set_effect_rate(struct ratbag_led *led, unsigned int hz)
|
||||
{
|
||||
if (!ratbag_device_has_capability(led->profile->device,
|
||||
RATBAG_DEVICE_CAP_LED))
|
||||
return RATBAG_ERROR_CAPABILITY;
|
||||
|
||||
led->hz = hz;
|
||||
led->dirty = true;
|
||||
led->profile->dirty = true;
|
||||
return RATBAG_SUCCESS;
|
||||
}
|
||||
|
||||
LIBRATBAG_EXPORT enum ratbag_error_code
|
||||
ratbag_led_set_brightness(struct ratbag_led *led, unsigned int brightness)
|
||||
{
|
||||
if (!ratbag_device_has_capability(led->profile->device,
|
||||
RATBAG_DEVICE_CAP_LED))
|
||||
return RATBAG_ERROR_CAPABILITY;
|
||||
|
||||
led->brightness = brightness;
|
||||
led->dirty = true;
|
||||
led->profile->dirty = true;
|
||||
return RATBAG_SUCCESS;
|
||||
}
|
||||
|
||||
LIBRATBAG_EXPORT struct ratbag_led *
|
||||
ratbag_profile_get_led(struct ratbag_profile *profile,
|
||||
unsigned int index)
|
||||
{
|
||||
struct ratbag_device *device = profile->device;
|
||||
struct ratbag_led *led;
|
||||
|
||||
if (index >= ratbag_device_get_num_leds(device)) {
|
||||
log_bug_client(device->ratbag, "Requested invalid led %d\n", index);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
list_for_each(led, &profile->leds, link) {
|
||||
if (led->index == index)
|
||||
return ratbag_led_ref(led);
|
||||
}
|
||||
|
||||
log_bug_libratbag(device->ratbag, "Led %d, profile %d not found\n",
|
||||
index, profile->index);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
LIBRATBAG_EXPORT void
|
||||
ratbag_set_user_data(struct ratbag *ratbag, void *userdata)
|
||||
{
|
||||
@@ -1240,13 +1580,15 @@ LIBRATBAG_EXPORT enum ratbag_error_code
|
||||
ratbag_button_set_macro(struct ratbag_button *button,
|
||||
const struct ratbag_button_macro *macro)
|
||||
{
|
||||
int rc;
|
||||
if (!ratbag_device_has_capability(button->profile->device,
|
||||
RATBAG_DEVICE_CAP_BUTTON_MACROS))
|
||||
return RATBAG_ERROR_CAPABILITY;
|
||||
|
||||
ratbag_button_copy_macro(button, macro);
|
||||
button->dirty = true;
|
||||
button->profile->dirty = true;
|
||||
|
||||
rc = button->profile->device->driver->write_button(button, &button->action);
|
||||
|
||||
return rc == 0 ? RATBAG_SUCCESS : RATBAG_ERROR_DEVICE;
|
||||
return RATBAG_SUCCESS;
|
||||
}
|
||||
|
||||
LIBRATBAG_EXPORT enum ratbag_error_code
|
||||
|
||||
301
src/libratbag.h
301
src/libratbag.h
@@ -30,6 +30,7 @@ extern "C" {
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdbool.h>
|
||||
#include <libudev.h>
|
||||
|
||||
#define LIBRATBAG_ATTRIBUTE_PRINTF(_format, _args) \
|
||||
@@ -54,6 +55,8 @@ extern "C" {
|
||||
*
|
||||
* @defgroup button Button configuration
|
||||
*
|
||||
* @defgroup led LED configuration
|
||||
*
|
||||
* @defgroup resolution Resolution and frequency mappings
|
||||
*
|
||||
* A device's sensor resolution and report rate can be configured per
|
||||
@@ -125,6 +128,28 @@ struct ratbag_button;
|
||||
*/
|
||||
struct ratbag_resolution;
|
||||
|
||||
/**
|
||||
* @ingroup led
|
||||
* @struct ratbag_color
|
||||
*
|
||||
* Represents LED color in RGB format.
|
||||
* each color component is integer 0 - 255
|
||||
*/
|
||||
|
||||
struct ratbag_color {
|
||||
unsigned int red;
|
||||
unsigned int green;
|
||||
unsigned int blue;
|
||||
};
|
||||
|
||||
/**
|
||||
* @ingroup led
|
||||
* @struct ratbag_led
|
||||
*
|
||||
* Represents a led on the device.
|
||||
*/
|
||||
struct ratbag_led;
|
||||
|
||||
/**
|
||||
* @ingroup button
|
||||
* @struct ratbag_macro
|
||||
@@ -151,7 +176,7 @@ enum ratbag_error_code {
|
||||
RATBAG_ERROR_DEVICE = -1000,
|
||||
|
||||
/**
|
||||
* Insufficient capabilities. This error occurs when a requestd change is
|
||||
* Insufficient capabilities. This error occurs when a requested change is
|
||||
* beyond the device's capabilities.
|
||||
*/
|
||||
RATBAG_ERROR_CAPABILITY = -1001,
|
||||
@@ -490,6 +515,11 @@ enum ratbag_device_capability {
|
||||
*/
|
||||
RATBAG_DEVICE_CAP_BUTTON_KEY,
|
||||
|
||||
/**
|
||||
* The device supports assigning LED colors and effects
|
||||
*/
|
||||
RATBAG_DEVICE_CAP_LED,
|
||||
|
||||
/**
|
||||
* The device supports user-defined key or button sequences.
|
||||
*/
|
||||
@@ -519,6 +549,15 @@ enum ratbag_device_capability {
|
||||
* libratbag can be used to query the device as normal.
|
||||
*/
|
||||
RATBAG_DEVICE_CAP_QUERY_CONFIGURATION,
|
||||
|
||||
/**
|
||||
* The device has the capability to disable and enable profiles. While
|
||||
* profiles are not immediately deleted after being disabled, it is not
|
||||
* guaranteed that the device will remember any disabled profiles the
|
||||
* next time ratbag runs. Furthermore, the order of profiles may get
|
||||
* changed the next time ratbag runs if profiles are disabled.
|
||||
*/
|
||||
RATBAG_DEVICE_CAP_DISABLE_PROFILE,
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -537,6 +576,18 @@ int
|
||||
ratbag_device_has_capability(const struct ratbag_device *device,
|
||||
enum ratbag_device_capability cap);
|
||||
|
||||
/**
|
||||
* @ingroup device
|
||||
*
|
||||
* Write any changes to the device. Depending on the device, this may take
|
||||
* a couple of seconds.
|
||||
*
|
||||
* @param device A previously initialized ratbag device
|
||||
* @return 0 on success or an error code otherwise
|
||||
*/
|
||||
enum ratbag_error_code
|
||||
ratbag_device_commit(struct ratbag_device *device);
|
||||
|
||||
/**
|
||||
* @ingroup device
|
||||
*
|
||||
@@ -566,6 +617,17 @@ ratbag_device_get_num_profiles(struct ratbag_device *device);
|
||||
unsigned int
|
||||
ratbag_device_get_num_buttons(struct ratbag_device *device);
|
||||
|
||||
/**
|
||||
* @ingroup device
|
||||
*
|
||||
* Return the number of LEDs available on this device.
|
||||
*
|
||||
* @param device A previously initialized ratbag device
|
||||
* @return The number of LEDs available on this device.
|
||||
*/
|
||||
unsigned int
|
||||
ratbag_device_get_num_leds(struct ratbag_device *device);
|
||||
|
||||
/**
|
||||
* @ingroup profile
|
||||
*
|
||||
@@ -591,6 +653,34 @@ ratbag_profile_ref(struct ratbag_profile *profile);
|
||||
struct ratbag_profile *
|
||||
ratbag_profile_unref(struct ratbag_profile *profile);
|
||||
|
||||
/**
|
||||
* @ingroup profile
|
||||
*
|
||||
* Enable/disable the ratbag profile. For this to work, the device must support
|
||||
* @ref RATBAG_DEVICE_CAP_DISABLE_PROFILE.
|
||||
*
|
||||
* @param profile A previously initialized ratbag profile
|
||||
* @param enabled Whether to enable or disable the profile
|
||||
*
|
||||
* @return 0 on success or an error code otherwise
|
||||
*/
|
||||
enum ratbag_error_code
|
||||
ratbag_profile_set_enabled(struct ratbag_profile *profile, bool enabled);
|
||||
|
||||
/**
|
||||
* @ingroup profile
|
||||
*
|
||||
* Check whether the ratbag profile is enabled or not. For devices that don't
|
||||
* support @ref RATBAG_DEVICE_CAP_DISABLE_PROFILE the profile will always be
|
||||
* set to enabled.
|
||||
*
|
||||
* @param profile A previously initialized ratbag profile
|
||||
*
|
||||
* @return Whether the profile is enabled or not.
|
||||
*/
|
||||
bool
|
||||
ratbag_profile_is_enabled(const struct ratbag_profile *profile);
|
||||
|
||||
/**
|
||||
* @ingroup profile
|
||||
*
|
||||
@@ -677,7 +767,7 @@ ratbag_profile_set_active(struct ratbag_profile *profile);
|
||||
*
|
||||
* @param profile A previously initialized ratbag profile
|
||||
*
|
||||
* @return The number of profiles available.
|
||||
* @return The number of resolutions available.
|
||||
*/
|
||||
unsigned int
|
||||
ratbag_profile_get_num_resolutions(struct ratbag_profile *profile);
|
||||
@@ -885,13 +975,18 @@ ratbag_resolution_get_dpi_y(struct ratbag_resolution *resolution);
|
||||
/**
|
||||
* @ingroup resolution
|
||||
*
|
||||
* Set the the report rate in Hz for the resolution mode.
|
||||
* Set the report rate in Hz for the resolution mode.
|
||||
*
|
||||
* A value of 0 hz disables the mode.
|
||||
*
|
||||
* If the resolution mode is the currently active mode and the profile is
|
||||
* the currently active profile, the change takes effect immediately.
|
||||
*
|
||||
* If the resolution does not have the @ref
|
||||
* RATBAG_RESOLUTION_CAP_INDIVIDUAL_REPORT_RATE capability, changing the
|
||||
* report rate on one resolution changes the report rate for all resolutions
|
||||
* in this profile.
|
||||
*
|
||||
* @param resolution A previously initialized ratbag resolution
|
||||
* @param hz Set to the report rate in Hz, may be 0
|
||||
*
|
||||
@@ -904,15 +999,10 @@ ratbag_resolution_set_report_rate(struct ratbag_resolution *resolution,
|
||||
/**
|
||||
* @ingroup resolution
|
||||
*
|
||||
* Get the the report rate in Hz for the resolution mode.
|
||||
* Get the report rate in Hz for the resolution mode.
|
||||
*
|
||||
* A value of 0 hz indicates the mode is disabled.
|
||||
*
|
||||
* If the resolution does not have the @ref
|
||||
* RATBAG_RESOLUTION_CAP_INDIVIDUAL_REPORT_RATE capability, changing the
|
||||
* report rate on one resolution changes the report rate for all resolutions
|
||||
* in this profile.
|
||||
*
|
||||
* @param resolution A previously initialized ratbag resolution
|
||||
*
|
||||
* @return The report rate for this resolution in Hz
|
||||
@@ -1177,6 +1267,7 @@ enum ratbag_button_action_special {
|
||||
|
||||
/* DPI switch */
|
||||
RATBAG_BUTTON_ACTION_SPECIAL_RESOLUTION_CYCLE_UP,
|
||||
RATBAG_BUTTON_ACTION_SPECIAL_RESOLUTION_CYCLE_DOWN,
|
||||
RATBAG_BUTTON_ACTION_SPECIAL_RESOLUTION_UP,
|
||||
RATBAG_BUTTON_ACTION_SPECIAL_RESOLUTION_DOWN,
|
||||
RATBAG_BUTTON_ACTION_SPECIAL_RESOLUTION_ALTERNATE,
|
||||
@@ -1184,6 +1275,7 @@ enum ratbag_button_action_special {
|
||||
|
||||
/* Profile */
|
||||
RATBAG_BUTTON_ACTION_SPECIAL_PROFILE_CYCLE_UP,
|
||||
RATBAG_BUTTON_ACTION_SPECIAL_PROFILE_CYCLE_DOWN,
|
||||
RATBAG_BUTTON_ACTION_SPECIAL_PROFILE_UP,
|
||||
RATBAG_BUTTON_ACTION_SPECIAL_PROFILE_DOWN,
|
||||
|
||||
@@ -1249,6 +1341,172 @@ ratbag_button_set_button(struct ratbag_button *button,
|
||||
enum ratbag_button_action_special
|
||||
ratbag_button_get_special(struct ratbag_button *button);
|
||||
|
||||
/**
|
||||
* @ingroup led
|
||||
*
|
||||
* RATBAG_LED_OFF - led is now off,
|
||||
* RATBAG_LED_ON - led is on with static color,
|
||||
* RATBAG_LED_CYCLE - led is cycling between all colors.
|
||||
* RATBAG_LED_BREATHING - led is pulsating with static color
|
||||
*
|
||||
* Each LED mode has different properties, e.g. the brightness and rate are only
|
||||
* available in modes @ref RATBAG_LED_CYCLE and @ref RATBAG_LED_BREATHING modes
|
||||
*/
|
||||
enum ratbag_led_mode {
|
||||
RATBAG_LED_OFF = 0,
|
||||
RATBAG_LED_ON,
|
||||
RATBAG_LED_CYCLE,
|
||||
RATBAG_LED_BREATHING,
|
||||
};
|
||||
/**
|
||||
* @ingroup led
|
||||
*
|
||||
* LED types, usually based on their physical location
|
||||
*/
|
||||
enum ratbag_led_type {
|
||||
RATBAG_LED_TYPE_UNKNOWN = -1,
|
||||
RATBAG_LED_TYPE_LOGO = 0,
|
||||
RATBAG_LED_TYPE_SIDE
|
||||
};
|
||||
|
||||
/**
|
||||
* @ingroup led
|
||||
*
|
||||
* Return a reference to the LED given by the index. The order of the
|
||||
* LEDs is device-specific though.
|
||||
*
|
||||
* The LED is refcounted with an initial value of at least 1.
|
||||
* Use ratbag_led_unref() to release the LED.
|
||||
*
|
||||
* @param profile A previously initialized ratbag profile
|
||||
* @param index The index of the LED
|
||||
*
|
||||
* @return A LED context, or NULL if the LED does not exist.
|
||||
*
|
||||
* @see ratbag_device_get_profile
|
||||
*/
|
||||
struct ratbag_led *
|
||||
ratbag_profile_get_led(struct ratbag_profile *profile, unsigned int index);
|
||||
/**
|
||||
* @ingroup led
|
||||
*
|
||||
* This function returns the type for ratbag_led.
|
||||
*
|
||||
* @param led A previously initialized ratbag LED
|
||||
* @return The LED type @ref ratbag_led_type
|
||||
*
|
||||
* @see ratbag_led_set_mode
|
||||
*/
|
||||
enum ratbag_led_type
|
||||
ratbag_led_get_type(struct ratbag_led *led);
|
||||
/**
|
||||
* @ingroup led
|
||||
*
|
||||
* This function returns the mode for ratbag_led.
|
||||
*
|
||||
* @param led A previously initialized ratbag LED
|
||||
* @return The LED mod @ref ratbag_led_mode
|
||||
*
|
||||
* @see ratbag_led_set_mode
|
||||
*/
|
||||
enum ratbag_led_mode
|
||||
ratbag_led_get_mode(struct ratbag_led *led);
|
||||
/**
|
||||
* @ingroup led
|
||||
*
|
||||
* This function returns the led color.
|
||||
*
|
||||
* @param led A previously initialized ratbag LED
|
||||
* @return The LED color in @ref ratbag_led_mode
|
||||
*
|
||||
* @see ratbag_led_set_color
|
||||
*/
|
||||
struct ratbag_color
|
||||
ratbag_led_get_color(struct ratbag_led *led);
|
||||
/**
|
||||
* @ingroup led
|
||||
*
|
||||
* This function returns the LED effect rate.
|
||||
*
|
||||
* @param led A previously initialized ratbag LED
|
||||
* @return The LED rate in Hz, can be 100 - 20000
|
||||
*
|
||||
* @see ratbag_led_set_effect_rate
|
||||
*/
|
||||
int
|
||||
ratbag_led_get_effect_rate(struct ratbag_led *led);
|
||||
/**
|
||||
* @ingroup led
|
||||
*
|
||||
* This function returns the LED brightness.
|
||||
*
|
||||
* @param led A previously initialized ratbag LED
|
||||
* @return The LED brightness 0 - 255
|
||||
*
|
||||
* @see ratbag_led_get_brightness
|
||||
*/
|
||||
unsigned int
|
||||
ratbag_led_get_brightness(struct ratbag_led *led);
|
||||
|
||||
/**
|
||||
* @ingroup led
|
||||
*
|
||||
* this function sets the LED mode.
|
||||
*
|
||||
* @param led A previously initialized ratbag LED
|
||||
* @param mode LED mode @ref ratbag_led_mode.
|
||||
* @return 0 on success or an error code otherwise.
|
||||
*
|
||||
* @see ratbag_led_get_mode
|
||||
*/
|
||||
enum ratbag_error_code
|
||||
ratbag_led_set_mode(struct ratbag_led *led, enum ratbag_led_mode mode);
|
||||
|
||||
/**
|
||||
* @ingroup led
|
||||
*
|
||||
* If the LED's mode is @ref RATBAG_LED_ON or @ref RATBAG_LED_BREATHING
|
||||
* then this function sets the LED color, otherwise it has no effect.
|
||||
*
|
||||
* @param led A previously initialized ratbag LED
|
||||
* @param color A LED color.
|
||||
* @return 0 on success or an error code otherwise.
|
||||
*
|
||||
* @see ratbag_led_get_color
|
||||
*/
|
||||
enum ratbag_error_code
|
||||
ratbag_led_set_color(struct ratbag_led *led, struct ratbag_color color);
|
||||
|
||||
/**
|
||||
* @ingroup led
|
||||
*
|
||||
* If the LED's mode is @ref RATBAG_LED_CYCLE or @ref RATBAG_LED_BREATHING
|
||||
* then this function sets the LED rate in Hz
|
||||
*
|
||||
* @param led A previously initialized ratbag LED
|
||||
* @param rate Effect rate in hz, 100 - 20000
|
||||
* @return 0 on success or an error code otherwise.
|
||||
*
|
||||
* @see ratbag_led_get_effect_rate
|
||||
*/
|
||||
enum ratbag_error_code
|
||||
ratbag_led_set_effect_rate(struct ratbag_led *led, unsigned int rate);
|
||||
|
||||
/**
|
||||
* @ingroup led
|
||||
*
|
||||
* If the LED's mode is @ref RATBAG_LED_CYCLE or @ref RATBAG_LED_BREATHING
|
||||
* then this function sets the LED brightness, otherwise it has no effect.
|
||||
*
|
||||
* @param led A previously initialized ratbag LED
|
||||
* @param brightness Effect brightness 0 - 255
|
||||
* @return 0 on success or an error code otherwise.
|
||||
*
|
||||
* @see ratbag_led_get_brightness
|
||||
*/
|
||||
enum ratbag_error_code
|
||||
ratbag_led_set_brightness(struct ratbag_led *led, unsigned int brightness);
|
||||
|
||||
/**
|
||||
* @ingroup button
|
||||
*
|
||||
@@ -1532,6 +1790,31 @@ ratbag_button_ref(struct ratbag_button *button);
|
||||
struct ratbag_button *
|
||||
ratbag_button_unref(struct ratbag_button *button);
|
||||
|
||||
/**
|
||||
* @ingroup led
|
||||
*
|
||||
* Add a reference to the led. A led is destroyed whenever the
|
||||
* reference count reaches 0. See @ref ratbag_led_unref.
|
||||
*
|
||||
* @param led A previously initialized valid ratbag led
|
||||
* @return The passed ratbag led
|
||||
*/
|
||||
struct ratbag_led *
|
||||
ratbag_led_ref(struct ratbag_led *led);
|
||||
|
||||
/**
|
||||
* @ingroup led
|
||||
*
|
||||
* Dereference the ratbag led. 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 led A previously initialized ratbag led
|
||||
* @return Always NULL
|
||||
*/
|
||||
struct ratbag_led *
|
||||
ratbag_led_unref(struct ratbag_led *led);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* in alphabetical order! */
|
||||
|
||||
LIBRATBAG_0.3.0 {
|
||||
LIBRATBAG_0.5.0 {
|
||||
global:
|
||||
ratbag_create_context;
|
||||
ratbag_button_disable;
|
||||
@@ -28,6 +28,7 @@ global:
|
||||
ratbag_button_set_special;
|
||||
ratbag_button_set_user_data;
|
||||
ratbag_button_unref;
|
||||
ratbag_device_commit;
|
||||
ratbag_device_get_name;
|
||||
ratbag_device_get_num_buttons;
|
||||
ratbag_device_get_num_profiles;
|
||||
@@ -44,14 +45,29 @@ global:
|
||||
ratbag_log_get_priority;
|
||||
ratbag_log_set_handler;
|
||||
ratbag_log_set_priority;
|
||||
ratbag_profile_get_led;
|
||||
ratbag_led_get_mode;
|
||||
ratbag_led_get_type;
|
||||
ratbag_led_get_color;
|
||||
ratbag_led_get_effect_rate;
|
||||
ratbag_led_get_brightness;
|
||||
ratbag_led_ref;
|
||||
ratbag_led_set_mode;
|
||||
ratbag_led_set_color;
|
||||
ratbag_led_set_effect_rate;
|
||||
ratbag_led_set_brightness;
|
||||
ratbag_led_unref;
|
||||
ratbag_device_get_num_leds;
|
||||
ratbag_profile_get_button;
|
||||
ratbag_profile_get_num_resolutions;
|
||||
ratbag_profile_get_resolution;
|
||||
ratbag_profile_get_user_data;
|
||||
ratbag_profile_is_active;
|
||||
ratbag_profile_is_enabled;
|
||||
ratbag_profile_ref;
|
||||
ratbag_profile_set_user_data;
|
||||
ratbag_profile_set_active;
|
||||
ratbag_profile_set_enabled;
|
||||
ratbag_profile_unref;
|
||||
ratbag_resolution_get_dpi;
|
||||
ratbag_resolution_get_dpi_x;
|
||||
|
||||
@@ -11,7 +11,8 @@ TEST_LIBS = $(CHECK_LIBS) $(LIBEVDEV_LIBS) $(top_builddir)/src/libratbag.la
|
||||
|
||||
run_tests = \
|
||||
test-context \
|
||||
test-device
|
||||
test-device \
|
||||
test-iconv-helper
|
||||
|
||||
build_tests = \
|
||||
test-build-cxx \
|
||||
@@ -31,6 +32,10 @@ test_device_SOURCES = test-device.c
|
||||
test_device_LDADD = $(TEST_LIBS)
|
||||
test_device_LDFLAGS = -no-install
|
||||
|
||||
test_iconv_helper_SOURCES = test-iconv-helper.c
|
||||
test_iconv_helper_LDADD = $(TEST_LIBS) $(top_builddir)/src/libutil.la
|
||||
test_iconv_helper_LDFLAGS = -no-install
|
||||
|
||||
# build-test only
|
||||
test_build_pedantic_c99_SOURCES = build-pedantic.c
|
||||
test_build_pedantic_c99_CFLAGS = -std=c99 -pedantic -Werror
|
||||
|
||||
@@ -53,6 +53,7 @@ const struct ratbag_test_device sane_device = {
|
||||
.num_profiles = 3,
|
||||
.num_resolutions = 3,
|
||||
.num_buttons = 1,
|
||||
.num_leds = 2,
|
||||
.profiles = {
|
||||
{
|
||||
.resolutions = {
|
||||
@@ -78,6 +79,20 @@ const struct ratbag_test_device sane_device = {
|
||||
{ .xres = 2200, .yres = 2300, .hz = 3000 },
|
||||
{ .xres = 2300, .yres = 2400, .hz = 3000 },
|
||||
},
|
||||
.leds = {
|
||||
{
|
||||
.mode = RATBAG_LED_ON,
|
||||
.color = { .red = 255, .green = 0, .blue = 0 },
|
||||
.hz = 1,
|
||||
.brightness = 20
|
||||
},
|
||||
{
|
||||
.mode = RATBAG_LED_CYCLE,
|
||||
.color = { .red = 255, .green = 255, .blue = 0 },
|
||||
.hz = 3,
|
||||
.brightness = 40
|
||||
}
|
||||
},
|
||||
.active = false,
|
||||
.dflt = false,
|
||||
},
|
||||
@@ -110,7 +125,7 @@ START_TEST(device_init)
|
||||
{
|
||||
struct ratbag *r;
|
||||
struct ratbag_device *d;
|
||||
int nprofiles, nbuttons;
|
||||
int nprofiles, nbuttons, nleds;
|
||||
struct ratbag_test_device td = sane_device;
|
||||
int device_freed_count = 0;
|
||||
|
||||
@@ -124,6 +139,8 @@ START_TEST(device_init)
|
||||
ck_assert_int_eq(nprofiles, 3);
|
||||
nbuttons = ratbag_device_get_num_buttons(d);
|
||||
ck_assert_int_eq(nbuttons, 1);
|
||||
nleds = ratbag_device_get_num_leds(d);
|
||||
ck_assert_int_eq(nleds, 2);
|
||||
|
||||
ratbag_device_unref(d);
|
||||
ratbag_unref(r);
|
||||
@@ -751,6 +768,119 @@ START_TEST(device_buttons_set)
|
||||
}
|
||||
END_TEST
|
||||
|
||||
static void
|
||||
assert_led_equals(struct ratbag_led *l, struct ratbag_test_led e_l)
|
||||
{
|
||||
enum ratbag_led_mode mode;
|
||||
struct ratbag_color color;
|
||||
int brightness, hz;
|
||||
|
||||
ck_assert(l != NULL);
|
||||
mode = ratbag_led_get_mode(l);
|
||||
color = ratbag_led_get_color(l);
|
||||
hz = ratbag_led_get_effect_rate(l);
|
||||
brightness = ratbag_led_get_brightness(l);
|
||||
ck_assert_int_eq(mode, e_l.mode);
|
||||
ck_assert_int_eq(color.red, e_l.color.red);
|
||||
ck_assert_int_eq(color.green, e_l.color.green);
|
||||
ck_assert_int_eq(color.blue, e_l.color.blue);
|
||||
ck_assert_int_eq(hz, e_l.hz);
|
||||
ck_assert_int_eq(brightness, e_l.brightness);
|
||||
}
|
||||
|
||||
START_TEST(device_leds)
|
||||
{
|
||||
struct ratbag *r;
|
||||
struct ratbag_device *d;
|
||||
struct ratbag_profile *p;
|
||||
struct ratbag_led *led_logo, *led_side;
|
||||
int nprofiles;
|
||||
int device_freed_count = 0;
|
||||
|
||||
struct ratbag_test_device td = sane_device;
|
||||
|
||||
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);
|
||||
|
||||
p = ratbag_device_get_profile(d, 2);
|
||||
ck_assert(p != NULL);
|
||||
|
||||
led_logo = ratbag_profile_get_led(p, RATBAG_LED_TYPE_LOGO);
|
||||
assert_led_equals(led_logo, td.profiles[2].leds[RATBAG_LED_TYPE_LOGO]);
|
||||
led_side = ratbag_profile_get_led(p, RATBAG_LED_TYPE_SIDE);
|
||||
assert_led_equals(led_side, td.profiles[2].leds[RATBAG_LED_TYPE_SIDE]);
|
||||
|
||||
ratbag_led_unref(led_logo);
|
||||
ratbag_led_unref(led_side);
|
||||
ratbag_profile_unref(p);
|
||||
ratbag_device_unref(d);
|
||||
ratbag_unref(r);
|
||||
ck_assert_int_eq(device_freed_count, 1);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(device_leds_set)
|
||||
{
|
||||
struct ratbag *r;
|
||||
struct ratbag_device *d;
|
||||
struct ratbag_profile *p;
|
||||
struct ratbag_led *l;
|
||||
int nprofiles;
|
||||
int device_freed_count = 0;
|
||||
|
||||
struct ratbag_test_device td = sane_device;
|
||||
|
||||
struct ratbag_color c = {
|
||||
.red = 0,
|
||||
.green = 111,
|
||||
.blue = 222
|
||||
};
|
||||
|
||||
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);
|
||||
|
||||
p = ratbag_device_get_profile(d, 0);
|
||||
ck_assert(p != NULL);
|
||||
|
||||
l = ratbag_profile_get_led(p, RATBAG_LED_TYPE_LOGO);
|
||||
|
||||
ratbag_led_set_mode(l, RATBAG_LED_BREATHING);
|
||||
ratbag_led_set_color(l, c);
|
||||
ratbag_led_set_effect_rate(l, 11);
|
||||
ratbag_led_set_brightness(l, 22);
|
||||
|
||||
l = ratbag_profile_get_led(p, RATBAG_LED_TYPE_LOGO);
|
||||
struct ratbag_test_led e_l = {
|
||||
.mode = RATBAG_LED_BREATHING,
|
||||
.color = {
|
||||
.red = c.red,
|
||||
.green = c.green,
|
||||
.blue = c.blue
|
||||
},
|
||||
.hz = 11,
|
||||
.brightness = 22
|
||||
};
|
||||
assert_led_equals(l, e_l);
|
||||
|
||||
ratbag_led_unref(l);
|
||||
ratbag_led_unref(l);
|
||||
ratbag_profile_unref(p);
|
||||
ratbag_device_unref(d);
|
||||
ratbag_unref(r);
|
||||
ck_assert_int_eq(device_freed_count, 1);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
static Suite *
|
||||
test_context_suite(void)
|
||||
{
|
||||
@@ -789,6 +919,11 @@ test_context_suite(void)
|
||||
tcase_add_test(tc, device_buttons_set);
|
||||
suite_add_tcase(s, tc);
|
||||
|
||||
tc = tcase_create("led");
|
||||
tcase_add_test(tc, device_leds);
|
||||
tcase_add_test(tc, device_leds_set);
|
||||
suite_add_tcase(s, tc);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
178
test/test-iconv-helper.c
Normal file
178
test/test-iconv-helper.c
Normal file
@@ -0,0 +1,178 @@
|
||||
/*
|
||||
* Copyright © 2016 Red Hat, Inc.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the next
|
||||
* paragraph) shall be included in all copies or substantial portions of the
|
||||
* Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include <check.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "libratbag-util.h"
|
||||
|
||||
static const char sample_utf16le[] = { 'F', '\0', 'o', '\0', 'o', '\0' };
|
||||
static const char sample_single_char_utf16le[] = { 'A', '\0' };
|
||||
|
||||
/* Sample UTF-8 string used: 🐺🖖🗺🗹💯👏 */
|
||||
static const char sample_emoji_utf8[] = {
|
||||
0xf0, 0x9f, 0x90, 0xba, 0xf0, 0x9f, 0x96, 0x96, 0xf0, 0x9f, 0x97, 0xba,
|
||||
0xf0, 0x9f, 0x97, 0xb9, 0xf0, 0x9f, 0x92, 0xaf, 0xf0, 0x9f, 0x91, 0x8f,
|
||||
0x0a, 0x00
|
||||
};
|
||||
|
||||
static const char sample_emoji_utf16le[] = {
|
||||
0x3d, 0xd8, 0x3a, 0xdc, 0x3d, 0xd8, 0x96, 0xdd, 0x3d, 0xd8, 0xfa, 0xdd,
|
||||
0x3d, 0xd8, 0xf9, 0xdd, 0x3d, 0xd8, 0xaf, 0xdc, 0x3d, 0xd8, 0x4f, 0xdc,
|
||||
0x0a, 0x00
|
||||
};
|
||||
|
||||
START_TEST(iconv_convert_to_utf16le)
|
||||
{
|
||||
char output[4096];
|
||||
ssize_t rc;
|
||||
|
||||
rc = ratbag_utf8_to_enc(output, sizeof(sample_utf16le),
|
||||
"UTF-16LE", "%s", "Foo");
|
||||
|
||||
ck_assert_int_eq(rc, sizeof(sample_utf16le));
|
||||
ck_assert(memcmp(output, sample_utf16le, sizeof(sample_utf16le)) == 0);
|
||||
|
||||
rc = ratbag_utf8_to_enc(output, sizeof(sample_emoji_utf16le),
|
||||
"UTF-16LE", "%s", sample_emoji_utf8);
|
||||
|
||||
ck_assert_int_eq(rc, sizeof(sample_emoji_utf16le));
|
||||
ck_assert(memcmp(output, sample_emoji_utf16le,
|
||||
sizeof(sample_emoji_utf16le)) == 0);
|
||||
|
||||
rc = ratbag_utf8_to_enc(output, sizeof(sample_single_char_utf16le),
|
||||
"UTF-16LE", "%s", "A");
|
||||
|
||||
ck_assert_int_eq(rc, sizeof(sample_single_char_utf16le));
|
||||
ck_assert(memcmp(output, sample_single_char_utf16le,
|
||||
sizeof(sample_single_char_utf16le)) == 0);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(iconv_convert_from_utf16le)
|
||||
{
|
||||
char input[4096];
|
||||
char *output;
|
||||
ssize_t rc;
|
||||
|
||||
memcpy(input, sample_utf16le, sizeof(sample_utf16le));
|
||||
rc = ratbag_utf8_from_enc(input, sizeof(sample_utf16le),
|
||||
"UTF-16LE", &output);
|
||||
|
||||
ck_assert_int_eq(rc, sizeof("Foo"));
|
||||
ck_assert(memcmp(output, "Foo", sizeof("Foo")) == 0);
|
||||
free(output);
|
||||
|
||||
memcpy(input, sample_emoji_utf16le, sizeof(sample_emoji_utf16le));
|
||||
rc = ratbag_utf8_from_enc(input, sizeof(sample_emoji_utf16le),
|
||||
"UTF-16LE", &output);
|
||||
|
||||
ck_assert_int_eq(rc, sizeof(sample_emoji_utf8));
|
||||
ck_assert(memcmp(output, sample_emoji_utf8,
|
||||
sizeof(sample_emoji_utf8)) == 0);
|
||||
free(output);
|
||||
|
||||
memcpy(input, sample_single_char_utf16le,
|
||||
sizeof(sample_single_char_utf16le));
|
||||
rc = ratbag_utf8_from_enc(input, sizeof(sample_single_char_utf16le),
|
||||
"UTF-16LE", &output);
|
||||
|
||||
ck_assert_int_eq(rc, sizeof("A"));
|
||||
ck_assert(memcmp(output, "A", sizeof("A")) == 0);
|
||||
free(output);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(iconv_invalid_encoding)
|
||||
{
|
||||
char output[10] = { 0 };
|
||||
ssize_t rc;
|
||||
|
||||
rc = ratbag_utf8_to_enc(output, sizeof(output),
|
||||
"This encoding is invalid", "%s", "Foo");
|
||||
|
||||
ck_assert_int_eq(rc, -EINVAL);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(iconv_bad_utf16le)
|
||||
{
|
||||
char odd_numbered[] = { 'F', '\0', 'o' };
|
||||
char single_char[] = { 'F' };
|
||||
char single_null[] = { '\0' };
|
||||
char double_null[] = { 'F', '\0', '\0', 'o', '\0', 'o', '\0' };
|
||||
char *output;
|
||||
ssize_t rc;
|
||||
|
||||
rc = ratbag_utf8_from_enc(odd_numbered, sizeof(odd_numbered),
|
||||
"UTF-16LE", &output);
|
||||
ck_assert_int_eq(rc, -EINVAL);
|
||||
|
||||
rc = ratbag_utf8_from_enc(single_char, sizeof(single_char), "UTF-16LE",
|
||||
&output);
|
||||
ck_assert_int_eq(rc, -EINVAL);
|
||||
|
||||
rc = ratbag_utf8_from_enc(single_null, sizeof(single_null), "UTF-16LE",
|
||||
&output);
|
||||
ck_assert_int_eq(rc, -EINVAL);
|
||||
|
||||
rc = ratbag_utf8_from_enc(double_null, sizeof(double_null), "UTF-16LE",
|
||||
&output);
|
||||
ck_assert_int_eq(rc, -EINVAL);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
static Suite *
|
||||
test_context_suite(void)
|
||||
{
|
||||
TCase *tc;
|
||||
Suite *s;
|
||||
|
||||
s = suite_create("iconv-helper");
|
||||
tc = tcase_create("iconv-helper");
|
||||
tcase_add_test(tc, iconv_convert_to_utf16le);
|
||||
tcase_add_test(tc, iconv_convert_from_utf16le);
|
||||
tcase_add_test(tc, iconv_invalid_encoding);
|
||||
tcase_add_test(tc, iconv_bad_utf16le);
|
||||
suite_add_tcase(s, tc);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
int nfailed;
|
||||
Suite *s;
|
||||
SRunner *sr;
|
||||
|
||||
s = test_context_suite();
|
||||
sr = srunner_create(s);
|
||||
|
||||
srunner_run_all(sr, CK_ENV);
|
||||
nfailed = srunner_ntests_failed(sr);
|
||||
srunner_free(sr);
|
||||
|
||||
return (nfailed == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
|
||||
}
|
||||
@@ -58,6 +58,7 @@ enum cmd_flags {
|
||||
FLAG_NEED_PROFILE = 1 << 11,
|
||||
FLAG_NEED_RESOLUTION = 1 << 12,
|
||||
FLAG_NEED_BUTTON = 1 << 13,
|
||||
FLAG_NEED_LED = 1 << 14,
|
||||
};
|
||||
|
||||
struct ratbag_cmd_options {
|
||||
@@ -66,6 +67,7 @@ struct ratbag_cmd_options {
|
||||
struct ratbag_profile *profile;
|
||||
struct ratbag_resolution *resolution;
|
||||
struct ratbag_button *button;
|
||||
struct ratbag_led *led;
|
||||
};
|
||||
|
||||
struct ratbag_cmd {
|
||||
@@ -101,6 +103,8 @@ usage(void)
|
||||
"Profile Commands:\n"
|
||||
" profile active get Print the currently active profile\n"
|
||||
" profile active set N Set profile N as to the active profile\n"
|
||||
" profile enable N Enable profile N\n"
|
||||
" profile disable N Disable profile N\n"
|
||||
" profile N {COMMAND} Use profile N for COMMAND\n"
|
||||
"\n"
|
||||
"Resolution Commands\n"
|
||||
@@ -143,12 +147,27 @@ usage(void)
|
||||
"\n"
|
||||
" switch-etekcity Switch the Etekcity mouse active profile\n"
|
||||
"\n"
|
||||
"LED Commands:\n"
|
||||
" LED commands work on the given profile, or on the\n"
|
||||
" active profile if none is given.\n"
|
||||
"\n"
|
||||
" led N {COMMAND}\n"
|
||||
" get print the LED properties\n"
|
||||
" set {COMMAND} sets LED properties\n"
|
||||
" mode [on|off|cycle|breath] sets LED mode\n"
|
||||
" color COLOR sets LED's color in hex format\n"
|
||||
" rate N sets LED's effect rate in Hz\n"
|
||||
" brightness N sets LED's effect brightness\n"
|
||||
"\n"
|
||||
"Examples:\n"
|
||||
" %s profile active get\n"
|
||||
" %s profile 0 resolution active set 4\n"
|
||||
" %s profile 0 resolution 1 dpi get\n"
|
||||
" %s resolution 4 rate get\n"
|
||||
" %s dpi set 800\n"
|
||||
" %s profile 0 led 0 set mode on\n"
|
||||
" %s profile 0 led 0 set color ff00ff\n"
|
||||
" %s profile 0 led 0 set rate 20\n"
|
||||
"\n"
|
||||
"Exit codes:\n"
|
||||
" 0 Success\n"
|
||||
@@ -161,6 +180,9 @@ usage(void)
|
||||
program_invocation_short_name,
|
||||
program_invocation_short_name,
|
||||
program_invocation_short_name,
|
||||
program_invocation_short_name,
|
||||
program_invocation_short_name,
|
||||
program_invocation_short_name,
|
||||
program_invocation_short_name);
|
||||
}
|
||||
|
||||
@@ -316,9 +338,11 @@ ratbag_cmd_info(const struct ratbag_cmd *cmd,
|
||||
struct ratbag_device *device;
|
||||
struct ratbag_profile *profile;
|
||||
struct ratbag_button *button;
|
||||
struct ratbag_led *led;
|
||||
char *action;
|
||||
int num_profiles, num_buttons;
|
||||
int i, j, b;
|
||||
int num_profiles, num_buttons, num_leds;
|
||||
int i, j, b, l;
|
||||
struct ratbag_color color;
|
||||
|
||||
device = options->device;
|
||||
|
||||
@@ -337,11 +361,17 @@ ratbag_cmd_info(const struct ratbag_cmd *cmd,
|
||||
if (ratbag_device_has_capability(device,
|
||||
RATBAG_DEVICE_CAP_BUTTON_MACROS))
|
||||
printf(" btn-macros");
|
||||
if (ratbag_device_has_capability(device,
|
||||
RATBAG_DEVICE_CAP_LED))
|
||||
printf(" led");
|
||||
printf("\n");
|
||||
|
||||
num_buttons = ratbag_device_get_num_buttons(device);
|
||||
printf("Number of buttons: %d\n", num_buttons);
|
||||
|
||||
num_leds = ratbag_device_get_num_leds(device);
|
||||
printf("Number of leds: %d\n", num_leds);
|
||||
|
||||
num_profiles = ratbag_device_get_num_profiles(device);
|
||||
printf("Profiles supported: %d\n", num_profiles);
|
||||
|
||||
@@ -351,7 +381,8 @@ ratbag_cmd_info(const struct ratbag_cmd *cmd,
|
||||
if (!profile)
|
||||
continue;
|
||||
|
||||
printf(" Profile %d%s\n", i,
|
||||
printf(" Profile %d (%s)%s\n", i,
|
||||
ratbag_profile_is_enabled(profile) ? "enabled" : "disabled",
|
||||
ratbag_profile_is_active(profile) ? " (active)" : "");
|
||||
printf(" Resolutions:\n");
|
||||
for (j = 0; j < ratbag_profile_get_num_resolutions(profile); j++) {
|
||||
@@ -390,6 +421,21 @@ ratbag_cmd_info(const struct ratbag_cmd *cmd,
|
||||
button = ratbag_button_unref(button);
|
||||
}
|
||||
|
||||
for (l = 0; l < num_leds; l++) {
|
||||
led = ratbag_profile_get_led(profile, l);
|
||||
color = ratbag_led_get_color(led);
|
||||
|
||||
printf(" LED: %d type %s mode %s color %02x%02x%02x rate %d brightness: %d\n",
|
||||
l,
|
||||
led_type_to_str(ratbag_led_get_type(led)),
|
||||
led_mode_to_str(ratbag_led_get_mode(led)),
|
||||
color.red, color.green, color.blue,
|
||||
ratbag_led_get_effect_rate(led),
|
||||
ratbag_led_get_brightness(led));
|
||||
|
||||
led = ratbag_led_unref(led);
|
||||
}
|
||||
|
||||
profile = ratbag_profile_unref(profile);
|
||||
}
|
||||
|
||||
@@ -1431,6 +1477,291 @@ static const struct ratbag_cmd cmd_button = {
|
||||
},
|
||||
};
|
||||
|
||||
static int
|
||||
ratbag_cmd_led_set_brightness(const struct ratbag_cmd *cmd,
|
||||
struct ratbag *ratbag,
|
||||
struct ratbag_cmd_options *options,
|
||||
int argc, char **argv)
|
||||
{
|
||||
struct ratbag_device *device;
|
||||
struct ratbag_led *led;
|
||||
char *str, *endptr;
|
||||
int brightness, b;
|
||||
int rc;
|
||||
|
||||
if (argc < 1)
|
||||
return ERR_USAGE;
|
||||
|
||||
led = options->led;
|
||||
brightness = atoi(argv[0]);
|
||||
|
||||
device = options->device;
|
||||
|
||||
rc = ratbag_led_set_brightness(led, brightness);
|
||||
if (rc != 0)
|
||||
return ERR_DEVICE;
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
static const struct ratbag_cmd cmd_led_set_brightness = {
|
||||
.name = "brightness",
|
||||
.cmd = ratbag_cmd_led_set_brightness,
|
||||
.flags = FLAG_NEED_DEVICE | FLAG_NEED_PROFILE | FLAG_NEED_LED,
|
||||
.subcommands = {
|
||||
NULL,
|
||||
},
|
||||
};
|
||||
|
||||
static int
|
||||
ratbag_cmd_led_set_effect_rate(const struct ratbag_cmd *cmd,
|
||||
struct ratbag *ratbag,
|
||||
struct ratbag_cmd_options *options,
|
||||
int argc, char **argv)
|
||||
{
|
||||
|
||||
struct ratbag_device *device;
|
||||
struct ratbag_led *led;
|
||||
char *str, *endptr;
|
||||
int hz, b;
|
||||
int rc;
|
||||
|
||||
if (argc < 1)
|
||||
return ERR_USAGE;
|
||||
|
||||
led = options->led;
|
||||
str = argv[0];
|
||||
hz = strtoul(str, &endptr, 10);
|
||||
if (*endptr != '\0')
|
||||
return ERR_USAGE;
|
||||
|
||||
rc = ratbag_led_set_effect_rate(led, hz);
|
||||
if (rc != 0)
|
||||
return ERR_DEVICE;
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
static const struct ratbag_cmd cmd_led_set_effect_rate = {
|
||||
.name = "rate",
|
||||
.cmd = ratbag_cmd_led_set_effect_rate,
|
||||
.flags = FLAG_NEED_DEVICE | FLAG_NEED_PROFILE | FLAG_NEED_LED,
|
||||
.subcommands = {
|
||||
NULL,
|
||||
},
|
||||
};
|
||||
|
||||
static int
|
||||
ratbag_cmd_led_set_color(const struct ratbag_cmd *cmd,
|
||||
struct ratbag *ratbag,
|
||||
struct ratbag_cmd_options *options,
|
||||
int argc, char **argv)
|
||||
{
|
||||
struct ratbag_device *device;
|
||||
struct ratbag_led *led;
|
||||
struct ratbag_color color;
|
||||
char *str, *endptr;
|
||||
int rc;
|
||||
char red[2], green[2], blue[2];
|
||||
char *p;
|
||||
|
||||
if (argc < 1)
|
||||
return ERR_USAGE;
|
||||
|
||||
led = options->led;
|
||||
|
||||
sscanf(argv[0], "%2s%2s%2s", &red, &green, &blue);
|
||||
|
||||
color.red = strtoul(red, &p, 16);
|
||||
color.green = strtoul(green, &p, 16);
|
||||
color.blue = strtoul(blue, &p, 16);
|
||||
|
||||
rc = ratbag_led_set_color(led, color);
|
||||
if (rc != 0)
|
||||
return ERR_DEVICE;
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
static const struct ratbag_cmd cmd_led_set_color = {
|
||||
.name = "color",
|
||||
.cmd = ratbag_cmd_led_set_color,
|
||||
.flags = FLAG_NEED_DEVICE | FLAG_NEED_PROFILE | FLAG_NEED_LED,
|
||||
.subcommands = {
|
||||
NULL,
|
||||
},
|
||||
};
|
||||
|
||||
static int
|
||||
ratbag_cmd_led_set_mode(const struct ratbag_cmd *cmd,
|
||||
struct ratbag *ratbag,
|
||||
struct ratbag_cmd_options *options,
|
||||
int argc, char **argv)
|
||||
{
|
||||
struct ratbag_device *device;
|
||||
struct ratbag_led *led;
|
||||
struct ratbag_color color;
|
||||
char *str, *endptr;
|
||||
int rc;
|
||||
|
||||
if (argc < 1)
|
||||
return ERR_USAGE;
|
||||
|
||||
led = options->led;
|
||||
str = argv[0];
|
||||
|
||||
enum ratbag_led_mode mode;
|
||||
|
||||
if (streq(str, "off"))
|
||||
mode = RATBAG_LED_OFF;
|
||||
else if (streq(str, "on"))
|
||||
mode = RATBAG_LED_ON;
|
||||
else if (streq(str, "cycle"))
|
||||
mode = RATBAG_LED_CYCLE;
|
||||
else if (streq(str, "breathing"))
|
||||
mode = RATBAG_LED_BREATHING;
|
||||
else {
|
||||
usage();
|
||||
return ERR_USAGE;
|
||||
}
|
||||
|
||||
/* set default rate and brightness */
|
||||
switch (mode) {
|
||||
case RATBAG_LED_ON:
|
||||
color.red = 255;
|
||||
color.green = 255;
|
||||
color.blue = 255;
|
||||
ratbag_led_set_color(led, color);
|
||||
break;
|
||||
case RATBAG_LED_CYCLE:
|
||||
case RATBAG_LED_BREATHING:
|
||||
ratbag_led_set_effect_rate(led, 20);
|
||||
ratbag_led_set_brightness(led, 100);
|
||||
}
|
||||
|
||||
rc = ratbag_led_set_mode(led, mode);
|
||||
if (rc != 0)
|
||||
return ERR_DEVICE;
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
static const struct ratbag_cmd cmd_led_set_mode = {
|
||||
.name = "mode",
|
||||
.cmd = ratbag_cmd_led_set_mode,
|
||||
.flags = FLAG_NEED_DEVICE | FLAG_NEED_PROFILE | FLAG_NEED_LED,
|
||||
.subcommands = {
|
||||
NULL,
|
||||
},
|
||||
};
|
||||
|
||||
static int
|
||||
ratbag_cmd_led_set(const struct ratbag_cmd *cmd,
|
||||
struct ratbag *ratbag,
|
||||
struct ratbag_cmd_options *options,
|
||||
int argc, char **argv)
|
||||
{
|
||||
if (argc < 1)
|
||||
return ERR_USAGE;
|
||||
|
||||
return run_subcommand(argv[0], cmd, ratbag, options,
|
||||
argc, argv);
|
||||
}
|
||||
|
||||
static const struct ratbag_cmd cmd_led_set = {
|
||||
.name = "set",
|
||||
.cmd = ratbag_cmd_led_set,
|
||||
.flags = FLAG_NEED_DEVICE | FLAG_NEED_PROFILE | FLAG_NEED_LED,
|
||||
.subcommands = {
|
||||
&cmd_led_set_mode,
|
||||
&cmd_led_set_color,
|
||||
&cmd_led_set_effect_rate,
|
||||
&cmd_led_set_brightness,
|
||||
NULL,
|
||||
},
|
||||
};
|
||||
|
||||
static int
|
||||
ratbag_cmd_led_get(const struct ratbag_cmd *cmd,
|
||||
struct ratbag *ratbag,
|
||||
struct ratbag_cmd_options *options,
|
||||
int argc, char **argv)
|
||||
{
|
||||
struct ratbag_led *led;
|
||||
enum ratbag_led_mode mode;
|
||||
struct ratbag_color color;
|
||||
int hz;
|
||||
int brightness;
|
||||
enum ratbag_led_type type;
|
||||
|
||||
led = options->led;
|
||||
|
||||
type = ratbag_led_get_type(led);
|
||||
mode = ratbag_led_get_mode(led);
|
||||
color = ratbag_led_get_color(led);
|
||||
hz = ratbag_led_get_effect_rate(led);
|
||||
brightness = ratbag_led_get_brightness(led);
|
||||
printf("type: %s, mode: %s, color: %02x%02x%02x, rate: %d, brightness: %d\n",
|
||||
led_type_to_str(type),
|
||||
led_mode_to_str(mode),
|
||||
color.red, color.green, color.blue,
|
||||
hz, brightness);
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
static const struct ratbag_cmd cmd_led_get = {
|
||||
.name = "get",
|
||||
.cmd = ratbag_cmd_led_get,
|
||||
.flags = FLAG_NEED_DEVICE | FLAG_NEED_PROFILE | FLAG_NEED_LED,
|
||||
.subcommands = {
|
||||
NULL,
|
||||
},
|
||||
};
|
||||
|
||||
static int
|
||||
ratbag_cmd_led(const struct ratbag_cmd *cmd,
|
||||
struct ratbag *ratbag,
|
||||
struct ratbag_cmd_options *options,
|
||||
int argc, char **argv)
|
||||
{
|
||||
struct ratbag_profile *profile;
|
||||
struct ratbag_led *led;
|
||||
int rc, index;
|
||||
|
||||
if (argc < 1)
|
||||
return ERR_USAGE;
|
||||
|
||||
profile = options->profile;
|
||||
|
||||
index = atoi(argv[0]);
|
||||
|
||||
led = ratbag_profile_get_led(profile, index);
|
||||
if (!led) {
|
||||
error("Invalid led %d\n", index);
|
||||
return ERR_UNSUPPORTED;
|
||||
}
|
||||
options->led = led;
|
||||
argc--;
|
||||
argv++;
|
||||
|
||||
rc = run_subcommand(argv[0], cmd, ratbag, options,
|
||||
argc, argv);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static const struct ratbag_cmd cmd_led = {
|
||||
.name = "led",
|
||||
.cmd = ratbag_cmd_led,
|
||||
.flags = FLAG_NEED_DEVICE | FLAG_NEED_PROFILE,
|
||||
.subcommands = {
|
||||
&cmd_led_get,
|
||||
&cmd_led_set,
|
||||
NULL,
|
||||
},
|
||||
};
|
||||
|
||||
static int
|
||||
ratbag_cmd_profile_active_set(const struct ratbag_cmd *cmd,
|
||||
struct ratbag *ratbag,
|
||||
@@ -1562,6 +1893,60 @@ static const struct ratbag_cmd cmd_profile_active = {
|
||||
},
|
||||
};
|
||||
|
||||
static int
|
||||
ratbag_cmd_profile_enable(const struct ratbag_cmd *cmd,
|
||||
struct ratbag *ratbag,
|
||||
struct ratbag_cmd_options *options,
|
||||
int argc, char **argv)
|
||||
{
|
||||
int rc;
|
||||
|
||||
if (!ratbag_device_has_capability(options->device,
|
||||
RATBAG_DEVICE_CAP_DISABLE_PROFILE))
|
||||
return ERR_UNSUPPORTED;
|
||||
|
||||
ratbag_profile_set_enabled(options->profile, true);
|
||||
rc = ratbag_device_commit(options->device);
|
||||
|
||||
return rc ? ERR_DEVICE : SUCCESS;
|
||||
}
|
||||
|
||||
static const struct ratbag_cmd cmd_profile_enable = {
|
||||
.name = "enable",
|
||||
.cmd = ratbag_cmd_profile_enable,
|
||||
.flags = FLAG_NEED_DEVICE | FLAG_NEED_PROFILE,
|
||||
.subcommands = {
|
||||
NULL,
|
||||
},
|
||||
};
|
||||
|
||||
static int
|
||||
ratbag_cmd_profile_disable(const struct ratbag_cmd *cmd,
|
||||
struct ratbag *ratbag,
|
||||
struct ratbag_cmd_options *options,
|
||||
int argc, char **argv)
|
||||
{
|
||||
int rc;
|
||||
|
||||
if (!ratbag_device_has_capability(options->device,
|
||||
RATBAG_DEVICE_CAP_DISABLE_PROFILE))
|
||||
return ERR_UNSUPPORTED;
|
||||
|
||||
ratbag_profile_set_enabled(options->profile, false);
|
||||
rc = ratbag_device_commit(options->device);
|
||||
|
||||
return rc ? ERR_DEVICE : SUCCESS;
|
||||
}
|
||||
|
||||
static const struct ratbag_cmd cmd_profile_disable = {
|
||||
.name = "disable",
|
||||
.cmd = ratbag_cmd_profile_disable,
|
||||
.flags = FLAG_NEED_DEVICE | FLAG_NEED_PROFILE,
|
||||
.subcommands = {
|
||||
NULL,
|
||||
},
|
||||
};
|
||||
|
||||
static int
|
||||
ratbag_cmd_profile(const struct ratbag_cmd *cmd,
|
||||
struct ratbag *ratbag,
|
||||
@@ -1613,8 +1998,11 @@ static const struct ratbag_cmd cmd_profile = {
|
||||
.flags = FLAG_NEED_DEVICE,
|
||||
.subcommands = {
|
||||
&cmd_profile_active,
|
||||
&cmd_profile_enable,
|
||||
&cmd_profile_disable,
|
||||
&cmd_resolution,
|
||||
&cmd_button,
|
||||
&cmd_led,
|
||||
NULL,
|
||||
},
|
||||
};
|
||||
@@ -1701,9 +2089,14 @@ main(int argc, char **argv)
|
||||
ratbag,
|
||||
&options,
|
||||
argc, argv);
|
||||
|
||||
if (options.device)
|
||||
rc = ratbag_device_commit(options.device);
|
||||
|
||||
out:
|
||||
ratbag_resolution_unref(options.resolution);
|
||||
ratbag_button_unref(options.button);
|
||||
ratbag_led_unref(options.led);
|
||||
ratbag_profile_unref(options.profile);
|
||||
ratbag_device_unref(options.device);
|
||||
ratbag_unref(ratbag);
|
||||
|
||||
@@ -48,6 +48,48 @@ udev_device_from_path(struct udev *udev, const char *path)
|
||||
return udev_device;
|
||||
}
|
||||
|
||||
const char*
|
||||
led_type_to_str(enum ratbag_led_type type)
|
||||
{
|
||||
const char *str = "UNKNOWN";
|
||||
|
||||
switch(type) {
|
||||
case RATBAG_LED_TYPE_UNKNOWN:
|
||||
str = "unknown";
|
||||
break;
|
||||
case RATBAG_LED_TYPE_LOGO:
|
||||
str = "logo";
|
||||
break;
|
||||
case RATBAG_LED_TYPE_SIDE:
|
||||
str = "side";
|
||||
break;
|
||||
}
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
const char *
|
||||
led_mode_to_str(enum ratbag_led_mode mode)
|
||||
{
|
||||
const char *str = "UNKNOWN";
|
||||
switch (mode) {
|
||||
case RATBAG_LED_OFF:
|
||||
str = "off";
|
||||
break;
|
||||
case RATBAG_LED_ON:
|
||||
str = "on";
|
||||
break;
|
||||
case RATBAG_LED_CYCLE:
|
||||
str = "cycle";
|
||||
break;
|
||||
case RATBAG_LED_BREATHING:
|
||||
str = "breath";
|
||||
break;
|
||||
}
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
const char*
|
||||
button_type_to_str(enum ratbag_button_type type)
|
||||
{
|
||||
@@ -99,9 +141,11 @@ const static struct map {
|
||||
{ RATBAG_BUTTON_ACTION_SPECIAL_WHEEL_RIGHT, "wheel right" },
|
||||
{ RATBAG_BUTTON_ACTION_SPECIAL_WHEEL_UP, "wheel up" },
|
||||
{ RATBAG_BUTTON_ACTION_SPECIAL_WHEEL_DOWN, "wheel down" },
|
||||
{ RATBAG_BUTTON_ACTION_SPECIAL_RATCHET_MODE_SWITCH, "ratchet mode switch" },
|
||||
|
||||
/* DPI switch */
|
||||
{ RATBAG_BUTTON_ACTION_SPECIAL_RESOLUTION_CYCLE_UP, "resolution cycle up" },
|
||||
{ RATBAG_BUTTON_ACTION_SPECIAL_RESOLUTION_CYCLE_DOWN, "resolution cycle down" },
|
||||
{ RATBAG_BUTTON_ACTION_SPECIAL_RESOLUTION_UP, "resolution up" },
|
||||
{ RATBAG_BUTTON_ACTION_SPECIAL_RESOLUTION_DOWN, "resolution down" },
|
||||
{ RATBAG_BUTTON_ACTION_SPECIAL_RESOLUTION_ALTERNATE, "resolution alternate" },
|
||||
@@ -109,6 +153,7 @@ const static struct map {
|
||||
|
||||
/* Profile */
|
||||
{ RATBAG_BUTTON_ACTION_SPECIAL_PROFILE_CYCLE_UP, "profile cycle up" },
|
||||
{ RATBAG_BUTTON_ACTION_SPECIAL_PROFILE_CYCLE_DOWN, "profile cycle down" },
|
||||
{ RATBAG_BUTTON_ACTION_SPECIAL_PROFILE_UP, "profile up" },
|
||||
{ RATBAG_BUTTON_ACTION_SPECIAL_PROFILE_DOWN, "profile down" },
|
||||
|
||||
|
||||
@@ -59,6 +59,12 @@ udev_device_from_path(struct udev *udev, const char *path);
|
||||
const char*
|
||||
button_type_to_str(enum ratbag_button_type type);
|
||||
|
||||
const char*
|
||||
led_type_to_str(enum ratbag_led_type type);
|
||||
|
||||
const char *
|
||||
led_mode_to_str(enum ratbag_led_mode mode);
|
||||
|
||||
const char *
|
||||
button_action_special_to_str(struct ratbag_button *button);
|
||||
|
||||
|
||||
@@ -58,7 +58,12 @@ cmds+=("profile 0 button 0 action set key KEY_ENTER")
|
||||
cmds+=("button 0 action set special doubleclick")
|
||||
cmds+=("profile 0 button 0 action set special doubleclick")
|
||||
cmds+=("profile 0 button 0 action set macro +KEY_ENTER t05 -KEY_ENTER")
|
||||
|
||||
cmds+=("profile 0 led 0 get")
|
||||
cmds+=("profile 0 led side get")
|
||||
cmds+=("profile 0 led 0 set mode on")
|
||||
cmds+=("profile 0 led 0 set color ffffff")
|
||||
cmds+=("profile 0 led 0 set rate 1")
|
||||
cmds+=("profile 0 led 0 set brightness 1")
|
||||
for i in "${cmds[@]}"; do
|
||||
echo "Testing arguments '$i $device'"
|
||||
eval $command "$i" $device
|
||||
|
||||
Reference in New Issue
Block a user