From 2d93c014218ed3506acb4d13ff10747a4a314f74 Mon Sep 17 00:00:00 2001 From: Hrvoje Cavrak Date: Mon, 13 May 2024 13:53:38 +0200 Subject: [PATCH] Updates and bugfixes - Make MacOS multi-desktop workaround more reliable - Partial media keys support --- .clang-format | 23 +++++++++++++++++++++++ binaries/board_A.uf2 | Bin 157696 -> 159744 bytes binaries/board_B.uf2 | Bin 157696 -> 159744 bytes src/handlers.c | 5 +++++ src/hid_parser.h | 8 ++++++++ src/keyboard.c | 27 +++++++++++++++++++++++++++ src/main.h | 12 +++++++++--- src/mouse.c | 6 +++--- src/uart.c | 1 + src/usb.c | 25 ++++++++++++++++++++++--- src/usb_descriptors.c | 4 +++- src/usb_descriptors.h | 19 ++++++++++++++++++- 12 files changed, 119 insertions(+), 11 deletions(-) create mode 100644 .clang-format diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000..e70f291 --- /dev/null +++ b/.clang-format @@ -0,0 +1,23 @@ +BasedOnStyle: LLVM +BinPackParameters: 'false' +BinPackArguments: 'false' +AlignAfterOpenBracket: Align +AlignConsecutiveMacros: 'true' +AlignConsecutiveAssignments: 'true' +AlignConsecutiveDeclarations: 'false' +AlignEscapedNewlines: Left +AlignOperands: 'true' +AlignTrailingComments: 'true' +AllowAllArgumentsOnNextLine: 'true' +AllowShortFunctionsOnASingleLine: 'false' +BreakBeforeBinaryOperators: 'All' +ColumnLimit: '110' +IndentWidth: '4' +IndentCaseLabels: 'true' +IndentWrappedFunctionNames: 'false' +KeepEmptyLinesAtTheStartOfBlocks: 'true' +MaxEmptyLinesToKeep: '2' +PointerAlignment: Right +ReflowComments: 'true' +Standard: Cpp11 +UseTab: Never diff --git a/binaries/board_A.uf2 b/binaries/board_A.uf2 index fa092216959d39840074b177eae013bc309810e0..234d2ca0fade1ba5b11fa367e8aa63babc4ea2c2 100644 GIT binary patch delta 22525 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 diff --git a/binaries/board_B.uf2 b/binaries/board_B.uf2 index 546f5fc0541fe87aaee58e6ffa4a32b4a1a59c28..3cd3995b93f24cb7352977c4a760d877283319f9 100644 GIT binary patch delta 22550 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 CiTVxz delta 22063 zcmcJ1Yj{&t*6`k^X?jfwEnr$o*-3gyFO<-hS`{&*CGuS7E8`DIM(JJ8AtFUHtKa*e@sZ>)*#EpCIgHB*JlCjp zzgYm!;XreF!EGaxd^8o4lK}fTB)6u1APtYlNd*|8THmYJ!mN@Cl#Q&d)8w7ZlG|E7 zPpXmz9_yv)(RC9s*oBb&CcjadqH2IwW;QA{P1~x(1Z%Jr!!s`R*dpQmDB;gYi#WIQ z14+aPoF3Hkqw{B*sRL_kjuvI$1|hoc+)J{N%_Bv2VGLD}RrEu_5w{ zjVc?tOS}gUPYXwK1h$5Q1wmOS(=oXLX7n-3Ky~lv5Avd~`(qpXIoIy`;96{fKj3jf z+~op_7tja+jbeyTRD7CS=0&6TPeGZ;YU<=FTJ`-sVfHky)Ao>l7?OAV{HuK3vLhB{ zSZNuKvpf1fh)#?f3ST(VPHa}yl}XV0HVulfZ}xtWmn4{yJdJY=@N<)MxqZqHwj^)x zt4rCesTlx~uP~7#{33U{U-?zu48LuJ--u+t9>tZ$+5hF{&!v<^AM|i22I&l~%0NWM zCNrzan>dC4kYpx0OEGyl0UgbV*bGk^wW&jbPBo+u8Dxlr|4^m8@ACnI8noCvcS#IRDvncH+mZb@UQ=f#8Vmf_ zTu39ea;iIM-{|9Lo}zyKWm_gng_18n7_N@MBZHqW!u>MoT z$|w%ox(xP?vxaE~DYA4-gldRXA*Im}Vejil%19NrFT(y^KSvrSrc`8_QEIDUjX{&a zWsb3y8rBr!OiB0ChKLD?ricmKO;ZeKp4hEVv_`5hNI>?l2G|p~582NT;G9v9S&JrS znsF+Zd8K=?AzVGhkYE~?&zl(2_uWRr1c<;5mlposap9c4?(nv*V;>pX4ED}IT#?Ul z*F)eh9*FVB^2-5vXDg@}%=V@PA={xw2eUm4LT_m()wR|{O+fZ9fThbI2PXErFHb0u zK*?XBMBah5v0y-li?he{lR0zd$U99PQWT4@7THgFel@q76S?8VbJm+yPF%@xE6iEN z*Vpe}&)ILg8TC^p5Ux?nJM`vQbf)H7{^Czh_CY zxju!TB3JqHUac`f=EysW&5`KuCS>0V{9Oj2yqW(xecYhayi5}_Jy`4CDSp5k^^q6r z7euNeA$7+=FI9Z9+(yL7V)7a8ip0&_#F!f|} z@kv5bjuIv1x|MI}$5>CUNkmj!S zX#-X!nGxagBkflp#{aP{G7u=8I?!j^pptilp=uP}fU+dkn-d~YB9sXAC-30OSO{D! z{lFzt$0!t$sr)ADz6$+gQ%V#B4d)#>LoJAx<;Dy~xZ(+%9o4--RgESzpv;looIS;* zo%75bQzvWK1d?EDzthHAth`@~l<0u5Wt!%Br0MPc5B#b`Oz}q$yD&f3cmAZacf8aV zp^_jOf-XWCVV~o|s;3Rr`a09NGK;p=^k`8W|8s75PHdsC@ZBfS_(IV7os%`L$UhSF zRlCn&@SC#Vi)&h9QTq=thT3dg>G#l5SwrzPA%rbHpS|OhAr7Gqs3fHX z-2)y-RbxIr~F?s(;wZ^fOFTCNLvj2P6IoMw}YijnnXWbP1)sLZ+YvHJ{j+_k*2C zNum&*L{WHHAO4OzsPnuv7_RN^_iRYL*T%xa!efWNBTIc|b~FEa-s4R(e5?-iOJ3Kz zFA}sk+2<(r-LYZ*z0rs#C?EQPbKd{>N1e-tD#N3OsfON;?QJ8F6pet9CmhC`9On<} zUg$Vc_nqDw$^{Kd^mNLbQ+}6ta)JhV9sGb2g|}EISPblK6TC@V!06yVn$yU2^Pc?V z@?bx4X+i|Z@;cTtQWVj0)Gy}6foIy+7`ocImaxrb22Gk=9kqGx6H^Vo{N9FF$_!|W zA$nht>Q#f(?(*?_3ku~@`&I86<>%p2d$(6=_j>u81&U;;{j|?{&wYw1I-H3v?d_Go z-;Ulm`1@fmPYRQO>jUo^RX1?$2Cjd4`SQY~K+iCdi=Q9_eKZ&!v^J4@P5N=!^egebDt?l#_K=-ttvu|*- z?kmEMyu7<8-QaaR*N-&cKyI_b@$Md5g#E_ARmg|XUd$8d#jd;9u%}U@juQIf`rPVGDz0Mt;z!W&YST2N3)gK_YhhAWhtzd1wV~`Z>n8rI`?Is- zh)=769(F|cM&)$0NvST!56qjGq0%# zqvBfr(4n3;$*UT58CG!Cz|c8Q}XS6^=MEu-G8; zlVYVc`Aax-}fIG-s+c0&rx`!`7&r3Tt%EG;2&wu{AD7V?`PFu1KxA zxABxsU8dxJnLIvmWMkC01K)6I6IZ-zLzywwxrULA4qMoy;rxBNY>710CUoA^^AMYK z>!MXb6QfhVw?(CXXNyd|Vv9)q*2c!(mJ&>iDt?15wJA>3Z1Ux8hiVVADxkZmhVDkH z^f@%X9|HaP1{l3?MKwxQKeSNZY_OusYPYx-dzP>BNI zb=>w|_sijH%T<|MK^)9-N@MIsn5@Y=g?C)k)gEI{6Xx{(=L-Jq@`rS7vtY>$?=PW5 z#c4KuEPqL%c)nD}CflqGRseqLdx4Yv#%8~3VTOzMYtSeZY3E6$D!OZcYcs)OVQt%> zp}foxGq_ln987J-MQAHC;YTl<%(0ogAQ;xPiz|=tq$(%CJ1sdfnAm(})p?#&3nkQ3 z#`3;AT2x#O#WRD9cz8m(5S?^Ubok1dKvW|l$`FV$LWpY4^98kXUR#?SFympd8MPpy zP9!2z5Rn-oqRyz=3xlhum+8QrKHq@@Fy-q+=ql4^_xX4-Hz)!R=Vc9I^X4v( zV`3N!GfiL1pPf6CC-Vgc>Um<&>G2_k&2Qn7Yx&Fb^*mWPBs@VYI04h@!ASvMxe%N% z4iWLPxnc{9P`Wr+I#2B4VjYKS`PUZDF0g}%$>80U97N{iBBBHF2;NN{;YdN^P`G_b z|47(~;b1I5_H`b)k~H#UNl+?eTfSgeeu!a9lH)=p@++1c;K@>fk9wYBNo*7+@zQ_u zN|TTftdC2WD2SaHBGv>REz4oUlYbj4p->Um-o(cdS~-xoq})Dr;vgvo-s$sy|20?|4V z(L(~!Lm@=#fM~-I5ihfd^=yFB=3wa>v3(i zb7X^9!6qYDP|F|Lw3sKa1@%DnmI#tcLL|LrVYFvog9h3nqMa(xP7R@LY2ln&{&EX6 z&@DmQSH<>k0kgISOF-i^LCUlcDO=AoDXMK*Lq3)YbfqD5+vYR6_H9df(kga!i`dmx z4TsA36|EZ>^0umZ4MTR>n57(I*48sB+jdGa^m6HL~ne#j6mNor)3HVB*EL-Pv9{Y^XV|___>3j#df= zRf4#oL2joe{unfoF92XvgaPB4&zj6{*tvuE?1Uj{S8zyzfKC_qr-$(GI=|&@!s~X+ zMEUTBI7qv}<2^x--xPbi2TJw^OF(|LAip|9{$3#3H$=qCc8i7YgVF;-r3o_y5i>(X z8~~z&BBDnGqDMlA4g%4kAkn*GGY>&YTd)MooF%Z&3Sn;pqIMBctw2;8LevgKhlhxG z*&(qnhtKo5N8)++;W%D*BzCCU>I6}BA)=0esG~tqe-WE|6iPl0max`&SghpZ3%u%> zDES{3gg+i4{1}M%WJp9pgFw^}Li7m`bp?q&5?jy(B`1O<5U|+-`|J?*6F_uQMD(OU z^kfLpNgz5kM8wOw#J-$@($hnw33CJyb3#O%2BI@TqEE$Uo~ayl4YK|cfMs3ol$(GN z>V2p$nLl(!#Tirib7!h}@`-aKd_n#E5cOw)$SNXQAP_AGA+lD- zdrC2x)riPxSkuR@7M9a%Ai(R?~lCBSxCYS_C zrVvTjfv7J?bVY1!AC%k>MP!-4zAS|O1`yp85j`sqJsU!F6Nr8a>R_4GCpPmZD76Pm ze-K+>hmu>t5{TCdLHLRg;kSV3_7D*-`$;VPHk95SDorp8BFrHo?gEihM6^;MS{Xv* zJRj|K)Oo^TH|O^=`7F08&}aRcoEIElU`x!2h|9*(`-Pc^;8OVTR-u?iG?*m94mz&* zqfr4PG|})Y+%Qx1h;%+L=zKmzr)ME|#KRv3d7JqGkD4c55yxtQV|56JcNNaz|K@${ zb%K-PZ}lS;Qln1xAri(^rOCg%_s?p1nR_TquUF#plyF!i{6#_diz4B)l4E3&L9&6N zx}ud5Rwf-R!^2;f;TTOYGNUUVH+l@1kL;9u`=|vG#o>D@MhAXD-_EhnB~qNsCB8&A zN^!2Va}BH!^64j1JeQJ4EK096f>~=q%!NppRWT)kuD#T1huJSj2Vv` zX_bF721fdco-vh_M2jp;SSv_d8zL49C5HBJ~*dSQAA;iLXMm9o3MrCm!azLW zfkv6J{rZBCYybZolbv4pq}9&&MH_Kfp9R4F9*U{K+h_0>acC_y)PU#hv73k z?E98coQUr!U{gRgqq_~G6I&d{qL?aH{2YA#gROV_3j+dq<^XIpTEi{F z&TSMqhkG>0)EQRlak!mg;lY-v9c-DS{VkKdgPVb8x-kiFkz7iJbv{WJg^|ieg~U4< zYo+I5GTK{0*TP4BuBV?KO~#cu(>!-0;F>_gzFJ&{uMbuJ?+@$SBEYdP zd{mo)hi0Ein*?7riG0yi5(vdc`bY}?gQBOOZCw9P;nbai(__*rX6n-)W*h1$G@FRN zQd3z{h~)&&PkE;Q-!}YucZj8LH=}^H^en-XN6a6Ci4Gcr4zRtW%E0WWL=}h$^^6Xw zdlgI2)R2Isgs4qr1nDAzgciZy7LmWSG99-{m%{?pGKStr$AuL7(V;Gi%2XjTH6ZhJ z7FI=%v05^ECSnq{d1zL-MG(IwM0^%-tjdC>9auI{Pg;l@IZz%u4v+Bvkt8&RPaYDu zRS>u}L|`s+OB-TiR)~#Syopmxr5CjrqL(Kk9Jfu7w@oB(c$w#@@!5 z#(8sl=UP(3?ce(7!aSTJb=^V4Swc7F;cb)@h=fsDZivfW~ z01%c}%R9pDqI5l!=|1UQG8#~@ZJ>x?nRfy;6 zmcrK-iPfTPAra-TatYNeSVjbMj91p4#t*tYw1P1}9gcFi(j%J&Zl~JV<{k z#95I&4`MPO8X+Y`;8Ac7hRX6nJSxJQ(is(_ZUJb3=bXuyXaNxXyB|{ZFr>heH0mwF zDoXAbg(qQ$5bGU47#yEy<^8PgCW*+XtT069Bt|efFc?wKy&(aZjB`2SrmH98J(TG1 z2nDl_S6;&hC4(HHf2Hzg&a5tGU$hj>wfS8!+C^kfNsf+`JoXuh4WOOU)PM6v;! zl7@l_Hl-kv6R`8g2k8X^E~lh45H;$Vf|ExD&5DB~8BMOv@0G9Ibv*B)^`$t8`=gJp zD8&aTDHjDgVYi@pcZlY4oIdKV;{#{BnnQ8>VV}%ybEbWN*I{(g=5pLD9|x8=J6JDz z8T!#!L`kJcCY2dN+^)n8QXygJp-QZhvSfjjyHJS@QX%E2stOOS6i4n6Y}zBT>DWYC zRfYHF9D}-Qh5C_qu&>5ksn>DD&9>Ru?=ah&!_t{OL$iVjM>Qk^doy(uRgOVwvlLy7 z`aEi*UT#I=WGD|Yw;Efef*Put88C}_Dne3jCa&gk3hB<7cx}#p*FSAJg-m5@z@%ON zkC&mpZS(&o%D^fd6CJEB5LH!!&&6#u;5^>2!?4}Z2_k83ElwHaNZ2PtWuGW2w6Yc( zIXXa()Z)dI)P+>S%n+~Ya3Qz6pRTLJOSlL6>8(1POG&+mA@P79|A0t7b75T?omr2| zIh&jAtjBrG?Q`{TdT|}?ug7UQ68lllchIkx;4lDIN>Q1fAc=jUC*NEb@!2rwmA+>0 zdtnY?>h$|UJ+neW*}$6iY>^=e2L(e8iVUHZvqANVerlPG=dvOG+H71XUEU9e8eXBK z5xU5C`-_mX^Yx(_36<4{1fUTw&s6r4MQ~0DI>i}!i9M+wse6s{)~MGYIE*Q=*ZWJ^ z(=7T!BfgiCxp>s5>uyf1F+Te{i9NI5Lh{TX81FW7x}j=0Bv^YW#M-&IH1{KAP<-T$d=riPr2BQ7q%^{8vfb8UVui%r zqlZJTPzfxpB^7Xb43-jus;O)?j>!t<5c^30!3wMIDl=KJV+Aj=owp|xqy zG!{}2;twYa9}DS&N8l_o^oT-r(-kJXq591MX?cRV`T7(Hdqg-wK^jKSssa+B0#19G zeVN$mbI9R9DXU*LJ7gz1EpT{Hg4h{`5#1Kpw;gUB3ds?{l_OxpP)L^HN_mIZ_`>ma z);Nm5kGo#FZy8SKu6n6;8Lp;exhNh~wp5gNn{8obk>-VGw3hN@%Zo?jbZkCY1#^$F=XUX!N{W_My|j$NlZ42Q!sOw4i;0$ z?T=UBg_OYYgh4S>wk)Jx&G_F`xhgQ~QqQv?$-j!#=4#*`n)R#*;a-go=CbNI4AsWW zU{%Jdg;kG5iZC+?Fc)koeQ7lPMVvlpO~Nt3sbe8dy~xyBLX2J&qSnF))`|!cJ`v=6 z5+Y|U^KIRrZ!d)SwhkMUn0Z5{2`->044FmGu7id3vE|T$zI6#XFlcmgm!Pamq%2r} zW9h67cmkHvmp9-SQvQ3*tdSxlsvT9cXnd!#wIMz>GaomKVxMqAPd_K8OL*r)ft5}LIMt67D9O+D*FBC-jm#`VGMdL7Ip)M1eb zAEz&F!fOfpjriZ;<6*~V=2zO#xXkXCj8gMsE5|&%Y%C?OiL2tIVCG3MVyH2_hV}9q z?~gDf3eqHKdKcaK8eSW1XVNi7Yr1Gw3rvjJWS)HqrLv77@n~W3*dkVRN>FqvM9~&Z z;{7V{2oQ-tv>g2&9NB{3k-^N!<~#wI3sv|CdBg{OxYVEGAi4KW5x#S;B8xM*<%g+^|U)i z8I!idb`lb$Y%HQ*?}Wwpx;O9}lo(nqPKRlS=Szsaw^*y5~e*k2}u9pq>J}JJqQM!6r7`PpYL^djsk3|J-gBEVG7K zwioN785a}&%HQa=y?B|z{~iTbM?Pnb0EQ9GFl$VvtcQ|)B2TGocZlKpVD-T`d*Dzq zo0y+N{f-yl@G-dX;y$)8IxrZ+cS2%#fW`1&NJ#dENIr-aaS1+5s%?l=`Mspe4&p9vPQ5bF z0~2_Ux&>v{>_Gb(cIlDzIa_8KJ5Uy(Bw64$vwnFsSc`1obf1NLg(_7OXmq_fm31EU!n9*ApV|2)4xdt3KMFXa3d_ z6Xrj`Btdr^H|VEF@xAelPB^QJhLJmtGAHbAtE}SbXgiKc4mLux1@l-f*~anVTf?L% z6{SPtBOhY}r1w3L-XG(ttQRi8?k1d^Sqb>p2v}uyTrfOrFc`YvusXYZpn>YpLLOy0 z>D7-#14zb2!GVh+2mXehSM-EEQ1P>wT~%>%VQ~A0l4E#T@kZC2MPyOGV}t98AFp-g z!KEcQh-!b_bJ&cPz3sOhX9n)TQy)BiHqd4cQ+C0Vb>LTc>Vc=f(|;es<0D~%nOFcs z9rqDDbZTA!Mb~23But8CO|PxYLhIWmfF3xB=;PGk9m!S6G?FT?R+x8o_`IOYAcT~CV3)HNC?Dfjao^Og#H zO##OG0OP~}V+AlC0LF4s7+}oxGw$-1geaUG;7bhfjR(HhfKQWbNXsmnH_Ppa_w%ju zR)+AY0({W}1A?W{tc2~U4{`Ef8n_+HKvoq|*BpKx<-}T(s)9mO z7deR=Ic+&zdlD}nW%Xv5^pN0lP4AkHm@&Ci{A2r9QG-IM>=RM@xndG-K{>$$Z8?VR zmZPbZoWi^C^Yr*BTrtR&(JR=}E3##0_vL1k`$ucaN|gIK{LRy!vQlyycg4LhfXHv4 zuVEr5rO=;F2WAG;b6iww`S`kGd~ZX6+Dy=!`UhcM*`TH53^rk&ZaxDR1g9<;R|Vx) zMaqlKZ|Qe*f7%S!BfGcR!dC9kcYyLQ@XbLkDmx|ebRN)u*!>;QAGWH2`e*n{$ysb- zf!lHx>!ZK%AoBI~E`yoS%V%K(9n^kJ(0)y%oy&=^mY5rKIl8CNt;a`4KceGQlvwd< zt}Bu5wBno*$u2x`e&n5Q;oxiwfi$e8m#sKUvI&+egTkrojL1k+M@%eA9T|(VHQi|3 zr0!SSH^Wl;94^66(FN!5queG9{p1{0<*-9D4B%=`1x5-Z-0pL-G-9&t9aH_A_f>H9 zK?Vynzb@+eyD0K86H&{kaTz`GO!U?1US#Lp@-#}$hXn7e$gcB^n7k@))#;|z^b{My z^wRDyH6<5B^cj6ZkorVH!hd{8kG}e-_po7lMWS(sVNOY6BPBifKmOUWFeg1H(t_+N z7eSHQx2|KdTQS3ki)R4+MVy?}l>@6-fP>H~hshCI4R{a0zKOKGZW;Jc?WM9o^dt zYtdkmQrSh3Hwi`!8a+Cp(dS5kDNP?-%+NqDaTSv|7RjH72@!to;_6EC%hG?FOFCHG1gs8@Q6Y z&qGh#fX(ee_iqXI+!ER2a>RQ$b+w_)FwgY30qxjjQa(e;O<2rqET^?M@dmDK7QK8^ z)LT&5bx}n;`3JnRDf8x6;m;uBUw?h_4=61hQu-&@PEB;vjXz;S!e?%`N{XOH;65T! zZUHmx^t+#Mrr$T}v5Dd7xM{2CCPuiGyonM!J~(PJj9QzDVP%Gq91guz zu>0b_FQ!-RqUj8k-4GcTUslxIIxVkxjbS)EwM>(jSs>82V6f%%OJea_hGHiI4XC1N}Tkd z8>hq5cqhH!#yL?gm~~pzlZu~Y2Kg^pWVi)`+#-XpQj6}jAp3E*MK!x@R9M`Cb{i$0 zkk09@C?bf6WOVI&xN{mH{ubWh6bYw@Ujzp+KMq3( z?ieGu4U4vpq2(M`&-K9C9&qefuSH1~#c&%E#}xZ3hkE)&shmFNosHLFg7A{j1iQ^+ zjO>0toIBxiu!~NYa7}Sj8kVlZeogio{gZn8(=9c0jQ_;hdjB^)3t6H<{ zNCNcP9xH3IZ_goMo!e32ZCv#3B7Y-Jl{CH#|0_TqT4dIkT@HRZ-(r{Ap4GJ@^7fJyHR7T_mqYk7lSE5 ztK(@L$3@>4%+62?_s?NRC)|#61I9(~4=P^ow{VV`nB9&m^ucH@L&`QWHHCC>G`Bk_ zcz6aUgo6`>V>`~Ygc;X7y$$V1tTN**d0d>ClGs3+P)|5FH1&>_jOG%G)s6EF+@fdD zpLMS#4u`3C95R#UtzK@HuYLL?*bK_)5 ztJBfvdRhHdxYOZvIUP^9yV^0AC5bN9LMITrCH6hN!R07-(rP)U!GESJ?n-u+8JIm=2O=tp&@YOLl;b9iYut{dh$^ongJ#`9hC#JvWE>*N*GtEfpPVF zZy2M>KH;KudBst-Nbvr)+hQobE`_I`-IA8mFxQ7;J8!`m*+2VU^7;J6Q_nC_a_iDD z*$Pk%^EwIYYKTK4q5o5e`pb+cp+cfW6*Bzk3B|+b$)A?!J#cT6-5B>dC`l4=QP~J? zXcOZeQ(illm1jL`#1CB8jc%W)kAluHd60f&{8&Lrj7UjC$&7*wQ;lIyJC{>MA4=iU z=;Rdc>|hOK#0osIA|3_$FZ5R3194-yqT;_5uQOB|{tC+r!Yya3mTd$&Nj4XvoI~zZr1M>z|Vt9^JegjsD-pU zs4y0KNWw)A{{JN7t8xC5=%0_jt4HVlKz~W+5@?Qw>kZVgQsm$T+g}xb2j~JgY};D0 z7ceDRgVD#sGvWmU;zb7Rf_wFlJiWdqJ6zls&U#UjBjTd6bWt5+@=nA(-LtFO7Jsm~ z74pKGmMx_uS45vNLeMfoq~&-s%IvWgKaaBiZPmdTx8BnY69p}23I>0hHc)B2Clex& z#YGS9iL5P-Zqys_&VMAHo|xM>%!uABDuxqDTtSK)_BUYR_&i3EQuaO9=diA6V~=$vRPoI z;d4CH|0R=jsDOKt)eqbOhA7@6_;-)UKSUa5nL2fTo{0Xte)(_~NfZ?-(~6>Khb`y< zhic&cr_s18Rt(R{18|H;M4yo;Xh{@lxuEOSVHH-(b)$53y4kuZXaYpye(qW%+wEa# z9LTl&_;i6gNyOa@a|q@)0a~`7ai$q%!7-wMPU@K`iqTi?Z!g<&efKJqb=taX75i-c z&N4Vr#O>iA8mA_6h4QY^m>_h#Yt3;T#-DbD4Q6>pvYn~3GigKv4yG-y$!+|cDhnp(~6YIMmF;b2NF8xE%*06z#=0(cH!*djnH z0ZReD0vL9i(RRR*fcFEA0_*||#-Wk%h`{#{6b?8J@EE|ka{>o1*!A3@|BL2oBO(ma zp*Z;bzu}ZXxk5xIhv(T(A)*Id9l(rG>MLuT zn+Cn0vMO$9OFuS1@?XA5M^fQg2I+B-B2uy)5qB#h?D-PllK@o!Zg~F*!14wn3jtI+ z5UC8{0>C8j91Hm3ABFN;Zy~Z3-p}t8-hroy9Dx`1BNOm{gWW*0e-9#^0Nnt8`4b}F zyo(5AEV>NOh47pL5DCEE|2v%8i^vXu6#xYv3vloVIB*22m;F%k;oxDThvOTC_Nfuo z?rbPu4Zs~mWEsFI0Le!n0N_7o5h?o@j0xxA=EXk|xvv|MH&23*05d*A6tn%i+dxT-US@n0)72q0ymkH2gd|Fd`zZbRHn$N93W6Y zRZU8!h4nD8zd{$)a}N#w3-k>L$jH=DOd2 z#@Cqde=LE<)r-2u;O{s-Ay?qa6>+h=zeyDfIJt!F53*MnAf6EQaKUXuwsmL?Ko4LB zy#eS0%)lN1CtwC>oB)x48OQ^m0L*{{Km(Y8HULHAa1(()L>GWkzznJbPzRVnV*reR z8JGfK2F$<`fM&o9S_04tn8B_9>;uf8EdWQyMZ>l>ymSHhgCgvSH;VcOR&+W5R=^B; z0?-SXL021U6nFz}!YKq+7b)d8pj%%Cv< zM!*bA0Wbq*U->CM`TLC<=fMFoV(nR0C#E7l1~< z42%IV0cKzhfCVsv<^Z$+X3!ddU4R+v6JR81g9ipj1JDIH5T1F#oq;@YbfEln0IYx+ z^aP+6FoV7T*a0(e1^~gw1_qGN-0CoXpurB~3+Tek~(Eu!meYL^lf#a8)=oBjo{rCOL gFsMC;$nTpFIlckLjvF6VE#(gRyF!Wfw||NLKWt^}V*mgE diff --git a/src/handlers.c b/src/handlers.c index 55db6da..3566688 100644 --- a/src/handlers.c +++ b/src/handlers.c @@ -231,6 +231,11 @@ void handle_output_config_msg(uart_packet_t *packet, device_t *state) { save_config(state); } +/* Process consumer control keyboard message. Send immediately, w/o queing */ +void handle_consumer_control_msg(uart_packet_t *packet, device_t *state) { + tud_hid_n_report(0, REPORT_ID_CONSUMER, &packet->data[0], CONSUMER_CONTROL_LENGTH); +} + /**==================================================== * * ============== Output Switch Routines ============ * * ==================================================== */ diff --git a/src/hid_parser.h b/src/hid_parser.h index f0d62be..45324e9 100644 --- a/src/hid_parser.h +++ b/src/hid_parser.h @@ -74,6 +74,14 @@ typedef struct { bool uses_report_id; } mouse_t; +/* Defines information about HID report format for the keyboard. */ +typedef struct { + uint8_t keyboard_report_id; + uint8_t consumer_report_id; + uint8_t system_report_id; + uint8_t protocol; +} keyboard_t; + /* For each element type we're interested in there is an entry in an array of these, defining its usage and in case matched, where to store the data. */ diff --git a/src/keyboard.c b/src/keyboard.c index a234fa0..47def28 100644 --- a/src/keyboard.c +++ b/src/keyboard.c @@ -181,6 +181,16 @@ void send_key(hid_keyboard_report_t *report, device_t *state) { } } +/* Decide if consumer control reports go local or to the other board */ +void send_consumer_control(uint8_t *raw_report, device_t *state) { + if (CURRENT_BOARD_IS_ACTIVE_OUTPUT) { + tud_hid_n_report(0, REPORT_ID_CONSUMER, raw_report, CONSUMER_CONTROL_LENGTH); + state->last_activity[BOARD_ROLE] = time_us_64(); + } else { + send_packet((uint8_t *)raw_report, CONSUMER_CONTROL_MSG, CONSUMER_CONTROL_LENGTH); + } +} + /* ==================================================== * * Parse and interpret the keys pressed on the keyboard * ==================================================== */ @@ -218,3 +228,20 @@ void process_keyboard_report(uint8_t *raw_report, int length, device_t *state) { /* This method will decide if the key gets queued locally or sent through UART */ send_key(keyboard_report, state); } + +void process_consumer_report(uint8_t *raw_report, int length, device_t *state) { + uint8_t new_report[CONSUMER_CONTROL_LENGTH] = {0}; + + /* We expect length not to be zero or bail out */ + if (!length) + return; + + /* Consumer control report ID rewrite and forward */ + if (raw_report[0] && raw_report[0] == global_state.kbd_dev.consumer_report_id) { + for (int i = 0; i < length - 1 || i < CONSUMER_CONTROL_LENGTH; i++) { + new_report[i] = raw_report[i + 1]; + } + + send_consumer_control(new_report, &global_state); + } +} \ No newline at end of file diff --git a/src/main.h b/src/main.h index fd07b04..dbd9c30 100644 --- a/src/main.h +++ b/src/main.h @@ -109,6 +109,7 @@ enum packet_type_e { SWAP_OUTPUTS_MSG = 12, HEARTBEAT_MSG = 13, OUTPUT_CONFIG_MSG = 14, + CONSUMER_CONTROL_MSG = 15, }; /* @@ -142,9 +143,10 @@ typedef struct { #define KBD_QUEUE_LENGTH 128 #define MOUSE_QUEUE_LENGTH 2048 -#define KEYS_IN_USB_REPORT 6 -#define KBD_REPORT_LENGTH 8 -#define MOUSE_REPORT_LENGTH 7 +#define KEYS_IN_USB_REPORT 6 +#define KBD_REPORT_LENGTH 8 +#define MOUSE_REPORT_LENGTH 7 +#define CONSUMER_CONTROL_LENGTH 4 /********* Screen **********/ #define MIN_SCREEN_COORD 0 @@ -260,6 +262,7 @@ typedef struct { config_t config; // Device configuration, loaded from flash or defaults used mouse_t mouse_dev; // Mouse device specifics, e.g. stores locations for keys in report + keyboard_t kbd_dev; // Keyboard device specifics, like report IDs queue_t kbd_queue; // Queue that stores keyboard reports queue_t mouse_queue; // Queue that stores mouse reports @@ -288,11 +291,13 @@ void core1_main(void); /********* Keyboard **********/ bool check_specific_hotkey(hotkey_combo_t, const hid_keyboard_report_t *); void process_keyboard_report(uint8_t *, int, device_t *); +void process_consumer_report(uint8_t *, int, device_t *); void release_all_keys(device_t *); void queue_kbd_report(hid_keyboard_report_t *, device_t *); void process_kbd_queue_task(device_t *); void send_key(hid_keyboard_report_t *, device_t *); bool key_in_report(uint8_t, const hid_keyboard_report_t *); +void send_consumer_control(uint8_t *, device_t *); /********* Mouse **********/ bool tud_mouse_report(uint8_t mode, uint8_t buttons, int16_t x, int16_t y, int8_t wheel); @@ -355,6 +360,7 @@ void handle_flash_led_msg(uart_packet_t *, device_t *); void handle_fw_upgrade_msg(uart_packet_t *, device_t *); void handle_wipe_config_msg(uart_packet_t *, device_t *); void handle_screensaver_msg(uart_packet_t *, device_t *); +void handle_consumer_control_msg(uart_packet_t *, device_t *); void switch_output(device_t *, uint8_t); diff --git a/src/mouse.c b/src/mouse.c index 75ae968..07b8318 100644 --- a/src/mouse.c +++ b/src/mouse.c @@ -139,9 +139,9 @@ void switch_desktop(device_t *state, output_t *output, int new_index, int direct switch (output->os) { case MACOS: - /* Once doesn't seem reliable enough, do it twice */ - output_mouse_report(&move_relative_one, state); - output_mouse_report(&move_relative_one, state); + /* Once isn't reliable enough, but repeating it does the trick */ + for (int move_cnt=0; move_cnt<5; move_cnt++) + output_mouse_report(&move_relative_one, state); break; case WINDOWS: diff --git a/src/uart.c b/src/uart.c index e2dc8fb..3f7b7ba 100644 --- a/src/uart.c +++ b/src/uart.c @@ -57,6 +57,7 @@ const uart_handler_t uart_handler[] = { {.type = SCREENSAVER_MSG, .handler = handle_screensaver_msg}, {.type = WIPE_CONFIG_MSG, .handler = handle_wipe_config_msg}, {.type = OUTPUT_CONFIG_MSG, .handler = handle_output_config_msg}, + {.type = CONSUMER_CONTROL_MSG, .handler = handle_consumer_control_msg}, }; void process_packet(uart_packet_t *packet, device_t *state) { diff --git a/src/usb.c b/src/usb.c index 834dc9e..1027198 100644 --- a/src/usb.c +++ b/src/usb.c @@ -87,6 +87,7 @@ void tuh_hid_umount_cb(uint8_t dev_addr, uint8_t instance) { switch (itf_protocol) { case HID_ITF_PROTOCOL_KEYBOARD: global_state.keyboard_connected = false; + memset(&global_state.kbd_dev, 0, sizeof(global_state.kbd_dev)); break; case HID_ITF_PROTOCOL_MOUSE: @@ -99,7 +100,9 @@ void tuh_hid_umount_cb(uint8_t dev_addr, uint8_t instance) { } void tuh_hid_mount_cb(uint8_t dev_addr, uint8_t instance, uint8_t const *desc_report, uint16_t desc_len) { - uint8_t const itf_protocol = tuh_hid_interface_protocol(dev_addr, instance); + uint8_t const itf_protocol = tuh_hid_interface_protocol(dev_addr, instance); + tuh_hid_report_info_t report_info[MAX_REPORT_ITEMS] = {0}; + tuh_hid_report_info_t *info; switch (itf_protocol) { case HID_ITF_PROTOCOL_KEYBOARD: @@ -120,13 +123,25 @@ void tuh_hid_mount_cb(uint8_t dev_addr, uint8_t instance, uint8_t const *desc_re at least we get all the information we need (looking at you, mouse wheel) */ if (tuh_hid_get_protocol(dev_addr, instance) == HID_PROTOCOL_BOOT) { tuh_hid_set_protocol(dev_addr, instance, HID_PROTOCOL_REPORT); - } + } global_state.mouse_dev.protocol = tuh_hid_get_protocol(dev_addr, instance); parse_report_descriptor(&global_state.mouse_dev, MAX_REPORTS, desc_report, desc_len); global_state.mouse_connected = true; break; + + case HID_ITF_PROTOCOL_NONE: + uint8_t num_parsed + = tuh_hid_parse_report_descriptor(&report_info[0], MAX_REPORT_ITEMS, desc_report, desc_len); + + for (int report_num = 0; report_num < num_parsed; report_num++) { + info = &report_info[report_num]; + + if (info->usage == HID_USAGE_CONSUMER_CONTROL && info->usage_page == HID_USAGE_PAGE_CONSUMER) + global_state.kbd_dev.consumer_report_id = info->report_id; + } + break; } /* Flash local led to indicate a device was connected */ blink_led(&global_state); @@ -134,7 +149,7 @@ void tuh_hid_mount_cb(uint8_t dev_addr, uint8_t instance, uint8_t const *desc_re /* Also signal the other board to flash LED, to enable easy verification if serial works */ send_value(ENABLE, FLASH_LED_MSG); - /* Kick off the report querying */ + /* Kick off the report querying */ tuh_hid_receive_report(dev_addr, instance); } @@ -150,6 +165,10 @@ void tuh_hid_report_received_cb(uint8_t dev_addr, uint8_t instance, uint8_t cons case HID_ITF_PROTOCOL_MOUSE: process_mouse_report((uint8_t *)report, len, &global_state); break; + + case HID_ITF_PROTOCOL_NONE: + process_consumer_report((uint8_t *)report, len, &global_state); + break; } /* Continue requesting reports */ diff --git a/src/usb_descriptors.c b/src/usb_descriptors.c index ba2addc..7baac05 100644 --- a/src/usb_descriptors.c +++ b/src/usb_descriptors.c @@ -62,7 +62,9 @@ uint8_t const *tud_descriptor_device_cb(void) { // Relative mouse is used to overcome limitations of multiple desktops on MacOS and Windows uint8_t const desc_hid_report[] = {TUD_HID_REPORT_DESC_KEYBOARD(HID_REPORT_ID(REPORT_ID_KEYBOARD)), - TUD_HID_REPORT_DESC_ABSMOUSE(HID_REPORT_ID(REPORT_ID_MOUSE))}; + TUD_HID_REPORT_DESC_ABSMOUSE(HID_REPORT_ID(REPORT_ID_MOUSE)), + TUD_HID_REPORT_DESC_CONSUMER_CTRL(HID_REPORT_ID(REPORT_ID_CONSUMER)) + }; uint8_t const desc_hid_report_relmouse[] = {TUD_HID_REPORT_DESC_MOUSE(HID_REPORT_ID(REPORT_ID_RELMOUSE))}; diff --git a/src/usb_descriptors.h b/src/usb_descriptors.h index 197373b..1571e7f 100644 --- a/src/usb_descriptors.h +++ b/src/usb_descriptors.h @@ -29,7 +29,8 @@ enum { REPORT_ID_KEYBOARD = 1, REPORT_ID_MOUSE, - REPORT_ID_COUNT + REPORT_ID_COUNT, + REPORT_ID_CONSUMER }; enum @@ -86,4 +87,20 @@ HID_COLLECTION ( HID_COLLECTION_APPLICATION ) ,\ HID_COLLECTION_END , \ HID_COLLECTION_END \ +// Consumer Control Report Descriptor Template +#define TUD_HID_REPORT_DESC_CONSUMER_CTRL(...) \ + HID_USAGE_PAGE ( HID_USAGE_PAGE_CONSUMER ) ,\ + HID_USAGE ( HID_USAGE_CONSUMER_CONTROL ) ,\ + HID_COLLECTION ( HID_COLLECTION_APPLICATION ) ,\ + /* Report ID if any */\ + __VA_ARGS__ \ + HID_LOGICAL_MIN ( 0x01 ) ,\ + HID_LOGICAL_MAX_N( 0x0FFF, 2 ) ,\ + HID_USAGE_MIN ( 0x01 ) ,\ + HID_USAGE_MAX_N ( 0x0FFF, 2 ) ,\ + HID_REPORT_SIZE ( 16 ) ,\ + HID_REPORT_COUNT ( 2 ) ,\ + HID_INPUT ( HID_DATA | HID_ARRAY | HID_ABSOLUTE ) ,\ + HID_COLLECTION_END \ + #endif /* USB_DESCRIPTORS_H_ */