From c58a2888471423127e3d34dcaa37a4a6345f7d23 Mon Sep 17 00:00:00 2001 From: "guilhem.duche" Date: Thu, 27 Mar 2008 20:04:29 +0000 Subject: [PATCH] git-svn-id: http://wiiusej.googlecode.com/svn/trunk@108 ae48ae66-6a45-0410-b38e-211266189506 --- WiiUseJ_0.1/.classpath | 6 + WiiUseJ_0.1/.project | 17 + WiiUseJ_0.1/README.TXT | 38 + WiiUseJ_0.1/img/wiimote.png | Bin 0 -> 44340 bytes WiiUseJ_0.1/libWiiuseJ.dll | Bin 0 -> 25448 bytes WiiUseJ_0.1/src/img/wiimote.png | Bin 0 -> 44340 bytes WiiUseJ_0.1/src/wiiusej/WiiUseApi.java | 211 +++++ WiiUseJ_0.1/src/wiiusej/WiiUseApiManager.java | 567 ++++++++++++ WiiUseJ_0.1/src/wiiusej/Wiimote.java | 323 +++++++ .../src/wiiusej/test/CloseGuiTestCleanly.java | 65 ++ WiiUseJ_0.1/src/wiiusej/test/Main.java | 40 + WiiUseJ_0.1/src/wiiusej/test/Tests.java | 354 ++++++++ .../src/wiiusej/test/WiiuseJGuiTest.java | 836 ++++++++++++++++++ .../src/wiiusej/utils/AccelerationPanel.java | 182 ++++ .../src/wiiusej/utils/ButtonsEventPanel.java | 297 +++++++ .../src/wiiusej/utils/GForcePanel.java | 201 +++++ WiiUseJ_0.1/src/wiiusej/utils/IRPanel.java | 192 ++++ .../src/wiiusej/utils/OrientationPanel.java | 205 +++++ WiiUseJ_0.1/src/wiiusej/values/GForce.java | 75 ++ WiiUseJ_0.1/src/wiiusej/values/IRSource.java | 109 +++ .../src/wiiusej/values/Orientation.java | 76 ++ .../src/wiiusej/values/RawAcceleration.java | 75 ++ .../wiiusej/wiiuseapievents/ButtonsEvent.java | 335 +++++++ .../wiiuseapievents/DisconnectionEvent.java | 44 + .../wiiuseapievents/EventsGatherer.java | 241 +++++ .../wiiusej/wiiuseapievents/GenericEvent.java | 227 +++++ .../src/wiiusej/wiiuseapievents/IREvent.java | 285 ++++++ .../wiiuseapievents/MotionSensingEvent.java | 194 ++++ .../wiiusej/wiiuseapievents/StatusEvent.java | 258 ++++++ .../wiiuseapievents/WiiUseApiEvent.java | 62 ++ .../wiiuseapievents/WiiUseApiListener.java | 39 + .../wiiusej/wiiuseapievents/WiimoteEvent.java | 59 ++ .../wiiuseapievents/WiimoteListener.java | 69 ++ .../wiiuseapirequest/FloatValueRequest.java | 71 ++ .../wiiuseapirequest/IntValueRequest.java | 74 ++ .../wiiusej/wiiuseapirequest/LedsRequest.java | 125 +++ .../wiiuseapirequest/TwoIntValueRequest.java | 73 ++ .../wiiuseapirequest/WiiUseApiRequest.java | 112 +++ WiiUseJ_0.1/wiiuse.dll | Bin 0 -> 114688 bytes 39 files changed, 6137 insertions(+) create mode 100644 WiiUseJ_0.1/.classpath create mode 100644 WiiUseJ_0.1/.project create mode 100644 WiiUseJ_0.1/README.TXT create mode 100644 WiiUseJ_0.1/img/wiimote.png create mode 100644 WiiUseJ_0.1/libWiiuseJ.dll create mode 100644 WiiUseJ_0.1/src/img/wiimote.png create mode 100644 WiiUseJ_0.1/src/wiiusej/WiiUseApi.java create mode 100644 WiiUseJ_0.1/src/wiiusej/WiiUseApiManager.java create mode 100644 WiiUseJ_0.1/src/wiiusej/Wiimote.java create mode 100644 WiiUseJ_0.1/src/wiiusej/test/CloseGuiTestCleanly.java create mode 100644 WiiUseJ_0.1/src/wiiusej/test/Main.java create mode 100644 WiiUseJ_0.1/src/wiiusej/test/Tests.java create mode 100644 WiiUseJ_0.1/src/wiiusej/test/WiiuseJGuiTest.java create mode 100644 WiiUseJ_0.1/src/wiiusej/utils/AccelerationPanel.java create mode 100644 WiiUseJ_0.1/src/wiiusej/utils/ButtonsEventPanel.java create mode 100644 WiiUseJ_0.1/src/wiiusej/utils/GForcePanel.java create mode 100644 WiiUseJ_0.1/src/wiiusej/utils/IRPanel.java create mode 100644 WiiUseJ_0.1/src/wiiusej/utils/OrientationPanel.java create mode 100644 WiiUseJ_0.1/src/wiiusej/values/GForce.java create mode 100644 WiiUseJ_0.1/src/wiiusej/values/IRSource.java create mode 100644 WiiUseJ_0.1/src/wiiusej/values/Orientation.java create mode 100644 WiiUseJ_0.1/src/wiiusej/values/RawAcceleration.java create mode 100644 WiiUseJ_0.1/src/wiiusej/wiiuseapievents/ButtonsEvent.java create mode 100644 WiiUseJ_0.1/src/wiiusej/wiiuseapievents/DisconnectionEvent.java create mode 100644 WiiUseJ_0.1/src/wiiusej/wiiuseapievents/EventsGatherer.java create mode 100644 WiiUseJ_0.1/src/wiiusej/wiiuseapievents/GenericEvent.java create mode 100644 WiiUseJ_0.1/src/wiiusej/wiiuseapievents/IREvent.java create mode 100644 WiiUseJ_0.1/src/wiiusej/wiiuseapievents/MotionSensingEvent.java create mode 100644 WiiUseJ_0.1/src/wiiusej/wiiuseapievents/StatusEvent.java create mode 100644 WiiUseJ_0.1/src/wiiusej/wiiuseapievents/WiiUseApiEvent.java create mode 100644 WiiUseJ_0.1/src/wiiusej/wiiuseapievents/WiiUseApiListener.java create mode 100644 WiiUseJ_0.1/src/wiiusej/wiiuseapievents/WiimoteEvent.java create mode 100644 WiiUseJ_0.1/src/wiiusej/wiiuseapievents/WiimoteListener.java create mode 100644 WiiUseJ_0.1/src/wiiusej/wiiuseapirequest/FloatValueRequest.java create mode 100644 WiiUseJ_0.1/src/wiiusej/wiiuseapirequest/IntValueRequest.java create mode 100644 WiiUseJ_0.1/src/wiiusej/wiiuseapirequest/LedsRequest.java create mode 100644 WiiUseJ_0.1/src/wiiusej/wiiuseapirequest/TwoIntValueRequest.java create mode 100644 WiiUseJ_0.1/src/wiiusej/wiiuseapirequest/WiiUseApiRequest.java create mode 100644 WiiUseJ_0.1/wiiuse.dll diff --git a/WiiUseJ_0.1/.classpath b/WiiUseJ_0.1/.classpath new file mode 100644 index 0000000..d171cd4 --- /dev/null +++ b/WiiUseJ_0.1/.classpath @@ -0,0 +1,6 @@ + + + + + + diff --git a/WiiUseJ_0.1/.project b/WiiUseJ_0.1/.project new file mode 100644 index 0000000..9485f4a --- /dev/null +++ b/WiiUseJ_0.1/.project @@ -0,0 +1,17 @@ + + + WiiUseJava + + + + + + org.eclipse.jdt.core.javabuilder + + + + + + org.eclipse.jdt.core.javanature + + diff --git a/WiiUseJ_0.1/README.TXT b/WiiUseJ_0.1/README.TXT new file mode 100644 index 0000000..268d31d --- /dev/null +++ b/WiiUseJ_0.1/README.TXT @@ -0,0 +1,38 @@ +/** + * This file is part of WiiuseJ. + * + * WiiuseJ is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * WiiuseJ is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with WiiuseJ. If not, see . + */ + + +WiiuseJ is a java API to use wiimotes on your computer. This API is built on top of an excellent API call Wiiuse using JNI. + +WiiuseJ intent to be a very simple, easy to use and lightweight java API for wiimotes. + +Some of the great aspects of this API are : + + * The compatibility which is as large as Wiiuse's API compatibility + + * Cross-platform : Windows and linux (like Wiiuse) + + * Easy to use + + +WiiuseJ is made by Guilhem Duché : guiguito1@hotmail.com. +You can contact me if you need more information. + +Go to : http://wiiusej.googlecode.com/ for further documentations. + + + diff --git a/WiiUseJ_0.1/img/wiimote.png b/WiiUseJ_0.1/img/wiimote.png new file mode 100644 index 0000000000000000000000000000000000000000..3f26f5202b22a89c5fa3e1c1eb524f78e4e76e81 GIT binary patch literal 44340 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 z zGFa~cvUW8<>9Wr`PgE$GTBtA?6rn<9GRgFPS>eBS4RBH;D=Fb14~fETl5?#gN80il z&6SU_=~K#%%>uZs-;WoN7m3U5oD_>DQ-!=}*}=TuV1IBYz@^Qcwgxck`keq54F;6f zaGOoRIc-~7cNRb`eLoGbmz}V5BVza{S)CMIG-)o06lKZKMgX+~fYI^+7&EEE1Kd;! zxZ^V}mx9UNN-`vqaVJC=Yv6f`y~hA!A#?&9WkO~x5ZsRK9bhS`QiMsF{RmNTOnu}j zH*_U71h3(_NnUfu0$4qfsd)bpVbLFDfDe?G!KBS%17lOkQ4q(2+tPk*t!t+#w5b%F z#lla+()2%4Z|DO|_~b=Y`=l$}n18|PiM6x1xx(mNMQ zejfpl-1b;fgGorBP8a}FQST!Fa6^EasztXZn1!yDMZpa;^+G0HC&2eNz{(hfdWm=u zuZDsvk5qM1a49E7TT`yCpGCo0_o1YIwf~`RrvUzl$l#7m!NmZUsDX0hD!kP51Yl~L zbpl*q`(_r!wD$W=rC_Be$*Lh4!K>=#h6=WJvgn*QtF-}Z>h-b!PKyzq11>H}oEpen zb#nt`m0Jd2681B-=r~-+1r-nGhh*JcYrLN|VfqdQ1~efY$!^e!=cse_9yVe8I@eI` z4(+*B>JQJ;wZT*~tkmx;=l%;tuHxUN-=_9@s(J0TuubO16wG64XnXa0Gn3f5qIfWN zFu%9a))fW(?*+hFi$qCwNCIsy$!a7AOl~$zTAcW@f7bykY$opUkC8R{FLN z#wv=3+908vZYfz5n)QCXFG&=jmhc?$%hH_%@VFO&hbh5(fDV`p+2JATM_l?7z6_hWX+W3^DHMg<+Wp-eypJo-CuAGF}vZaey+ z=B>7Ohru~41X}lSk92yW(FfhdmoH!GO{$qxt}j^(HJ5weX<3|hnMwpmJC1=Z)H$YH zfH&A212EfkS`6^Ujaz)8=zG@(o`?{OXzPbY6Eg*NHsPFPG)nmoy0 zcGl6ll}_Do3H4Rt9<=yaTmTD~;W6*QRn}RjPF~|Z?vaY|MAK-|o^<}+>1+<5p|o=E zH6z;qGT2yuW{6C zdu^AVr=eOR`P#MX{XU^E~#dLrkl-loBooE6x`I=7Vr@M05BP;ee#igweN zo_H`y7C(-gN}EYc{x<6)NY6mJY@MjGjv}^^YsdE8VViB-;<(E;al!hSG=S#_W$d)# zpUJTIV2!rvYwx~;W}NRe+ija|=RA~8P=_-4e#{pE>V-hrU0}t^XwAch@14d0)))Y^ zwWEJM6vn+**fqD>HMecq?p&h6lF_&q?t}Yb0njbY7lOr5u^*|r!$ve7vpEf?fwq^f zUAM{F4{Y&T9qetQ>;s$JsPDl(D7MC^9Z&425L=G-T1$x%OID*y9W$vo=fP6*Yx$xP zGjenY;Jh7NF2FR4+-9qpCXiHTJ$%U6@=l|UZ9BuR9lL!Z_ZetVHD8Dfq!ryE+keYm z-TgM99JNQ6Bl~l?F`7T}9u%UDWhgjuIH)$3cWn9awl6XoRkCH0`=R0vAafr(x9>{s z$AI2vg-P~Xc_Hox>PFGR6U068oK4@!Fv>T1%{>6D_7786i^m%`ZS%_Q0#~IV*w>`) zXgrQ(ttdC|W;Ab<+UqriEjIwYEdf@SPl|UksmM|$lRgPPiPm}R$PsH#YYGd)GYxF= z)Ue{{v6DWDaqmA(Bp@?^X%?vcK`J~-H68j3uQIkwS5j~9Zi|9aggj@lvFKp42dx4+ zxk^yA?k9g=2Ao>;u*?6bEk^E58^QsW`-G}_jpMTAt8IZ(eks|F$YwRQ*@2P)KbE)h zM8yt^7_35U_?}TP)B-E?l7BX-OeR|E-aSz50nh47TH08Hs$BayXCJh>vAP$4TWO#l zF%6r^6Z?aT8Bh^>bOD)3l7~w6C`C{Jmy$;Umqn(s!Yn>ImICa)iv7OebWdp5^53ct zB4r)8x8%O8(~JSk{qdN4^KuRbEG(Qw$UQ^d$TjYhU5o$>(AuR4B}>-E{^Me%PrBWF zCb%eKZ9&26(W|aq$UfLLS$vvE%J^`DwY6rbTaznp1PW#%1u&C&$h2rp785B-5!G;`^fLC;(IWj{5>&?o9v# zDj@ToHjM)~r6HCqUFn<5C68g(>JlEaaJD@+!){()L7BF>j3jZsB^)O1SBfhp!K5U zFv*xE{20j@90k*-%?y(!O$`$!ObU}HPqPKF#Q}vv4w$lorV3R^gXM?}hH^O~>o_WK z;Ld)VOu&alqL8UF4keGcCzL-H9hA#Ns^O%(Luy56P_-FsDT!TQ+VzUx+=IEst9ZV3Y-bn=^Njfx6L~Sg?B>8OaKU zdSTg|<0S%(4KkV2t>I+P9zFB&7xui`8d|;b$}3^koOz)F$4JihWWwSB#V~xe6m*3B zxHRc3o-59h*v1Wq79i*Fy)*zTLDas=f|J1R0hjMcyBx~~u1rr>IuYX)!XH- z`uJ5EwY=TEd-!1d#Bd;&pv~j~C&?}u z1qVl=Qk}{*sKqSL5hF}KrIlzwM=LtOQA11D2W;U1va0TgqZC?zN$%4&YsEL)Sv=QP zkKx#X5x1Lf5*scBc9gE8j1B@R0G#*}ngB5E{q0_T!mhn0W~!~3g*j{h z_mIh90nB8j7a!jvD(1+7f!nAYVobqlHr*Bg%bNwj@?@m}W-c00uqxdxTD-!Pi3MT) z{N-WQs*T1T(H=LsvXpehHg{&O9KM=M&7PeAjPqlMd6TM7oeg8gydPeE`4y*LQ3(?S zs8p9@05n4Y<7UGg0bmA;3l=?Z-ZBdUY;@{fW>FKw2cW=ak%#$=2z^U+BT*ViVPY#BFi=DdjK$Yy;w8^xX2bhN>(PotJiD_{5B z862}{Orr@Cr&%G-nKs!=eS)xoF$*qVv4UjgeV}DK{ebEFhe9*Q0PbOC5=srMQ53s$ z*-8gkrbilJWF3eXVim#+{fO?v!IojTn#=I*wlX>Nhn zDp95e3>@SDi%QdzC~z@5m{h99;z)o!TXfJ{(Qz;1Crou^Yq8~hX~97~;wWCq(3)!y zuO)Uo#qMX`{DmH77fwBVM*DM_`sLYfP!Oyu_1AEd|<8C$q-;dnRGN`@8E5q zB6rmlENR|&HFWLTHN5rK+u_YO-}2F|+ncU*!KTx8rOYEHmPx}+$ag>;?&z>ISkhln z>{w{r%Z!;OGE9MB!J#+-usVvf;86CiT(eTcwlXA(p=cZ-$Y%hC>fkcsB!CTd7UM87 zkvNYSpF-d06 zo|^|3kQr#ubLK9{vuh?Rc5+DW0xs+i;BZ8cB11kinlzy~R^{0DC)&Nt^2G+o@=FU~ zz;)_n7XtwcQ?ioI-bs&OV#&Bz^q{sj?ESX3X9wo9YNXLO9((XtpDgs%) zT_zf;k^=#d1u#?$XiyCR!=~|caSqhZJ$l0oTV$|exQZHRagSu5;8sQH&U=<%`ky0@pF2ZX#PFV1AbQBB!wH5^z z(xO`gFq4mx1=aAQ2sS`%C>5F{x%gtL5Qy?nNx_Q!&MXXAKHx#c0LVg$cM*8d-}0S^ zy|MttPnhE8aZhj*z7x+Hnluy(6+^+uT)Ke~h#(n&XcPA7Nnv7<$4r(=is5xXl1&(qYw1ET#oN5G4m0hzXO#O_OdW zg@Bd^Nb-zx6sm(mKn+l4+}VVk1llDCxKJ^1VHOyA0g8@HH)JYu5Q-8TmfKMZRV;5g zN47WM6JwSKOEQ`BVZl(X+V5aZjCyyh|85p2uVW&qWlu|GaIpk|d_1|WC>VfQt;oDd zlg*=K&X0NXmv|6>$WD@1jM9=QE&^I+2d^pbib)ei00^7_O`Qc(bk|O6?jzfns3Cl6=Qv6HDjwP!=p3;Gsr2PL!4lYu3Ff^+pNq ziW*7l2Vl-uvLN@$xyW5Ohp1OkBvG$}T>#)_rNLcJ^iY+k@sfa^MJ;X-V1 zKd>qm8z7SnA_~@`i#bi4Lc~2nnF{}*Swp$7JoE%OknCP5SFmOWw*UpFWolC$8-*Ml zcZGsuV3zxFqQII{1ILEm&zE8_zw(7kR!+ev8OMcU zy@Uw?89=AcnCqegu7cQrqrhnhnn*`bBD=PyD5;KX2so&dMG1$&-wf-=$pZLLxTuw* zv}Yct0WPF4bx42(#&P@cd+7mao4(kU$F9Fs7R_0+W}R;rWtUzS#S$JAzyg=R2hpl? z7m`lh1oU-OJ`{lwI0#93WO~3+h(NL9o!58T#xoXTY`XCnWeU*HlsN)CREr}6)=w}2 zae~I5M97jr1%N{7Qm{nzaURxv2XGd6<-DKneV|?NfLnLo?9EzZpJ#9lk|vXAuC$7! zA8?JO#_ru)>0*OWB0!_zOAbTH0H|#<@*xA967JCnhL3p9xs8-976BrL?*d45FHM8Z z>se+_ho<0i0L(f^l~iNuWjhGq(xIDUO&#nIr6!>ukHgwdiqlp@3ZOZ%TM(zja@+Bb zNZ^PV!PMc%AfF0bT7G4Yh!O=AP`+3MuxHlw zDrKis<(Rm{Q5KNt_tPa0wDl4*E#6a`FJ+LfUtw`kHkP4)sOPWuGqC6U9`*yX>jH5h z(ZP{Y4Qys-vp1XQ$VVgTfqhNdYEtMsvw&>A-Am$rlDuEi#v6&=S(kwdGl%-T@e{Gtw3Kc6!gDh8I44}YEA7jcF z_}b4D16XJgbpmXWpDZm}l$$P8l4hN0U<;K)h-D~LnBGDfUo%cjPg8Q15|#CSCyS1N zPusa-%>tlUTs3QhwSw$YiU2&;jMEfZ?0GRWrzzCiyx>9`%V6qcQJF^jgE1*oOF6Cq zm9D`kid7-AQWV_Ci4oOki~&xATqv2msb)+Tz)c0P_0LCBFGE{5J6MHfD8WcsD575Y zSBa21-1Wo=6+xYWk#_D`MJ3Rw~hE-xNj%nn{)*(~I~krz#+ z`YufYxRA3W4RAiq#+)QsW>8aQZzsUHMUr7AH5=e`fFRv$Lg2<7L|T(#I|06n0LRoE z2MxrQ<1k&hAZL}h?*zDffZ2)JEEZjgCC8MTR;G$6S55I;bpl)(U{ZzgMZ=<71aPcS zNtsFq=?ejuMahMVkiZY9cX!@M7h3|#PXG6mfTd}N}XSbO&0_9ez1KT zW?{C>4weiiiJvMA4U{YajH5%9(g8vmGICds)A`Ds0B1Wf%2|vpb#yctV5n5=7=YtW znay=#WG#lKP;hH!L6!qTTb|SA0OP7;XM-ph5JkBFtz6@_0=JNYCBS7@mkRv1<>cRu zYqvST$lziCV-7Xfr<_H#S&EfFjj21UT*BP|q_w}}t^o`ymLdfO%hoN#KAQqwIp>yQ z(OI6Z)}HXYeZ6}IusW+0oBVQsEBBnH0GwvmcN>t_{=PN`n8s4D=rjc*lMAuOwqV(% z0M5$tXzdBV+t+I|faxE6n-=(EG@cJ{feyp zxSas!935#2ZqERhiZErB7Hofjf5a)c5QTOE+ypJUm<(<&6dV^v(c?~ln*cC&Fe45& zu+38yY|`?vT)A5AdBx;!mJeD{rM8yAZGHV@Z*Y10gQ)>VZZvlAKC7xr;Wuh@k{3g1w@tVpF>O9WT>wL$F(^kOyRCPFchW0a7K)kvxT(Hlb zsj>EXr;l0H_G+sueJY$jb~>D^xfD*FzZ4EvTQ&DHC&PsrD=mEDWFW>$?P=;yowGvY z>e1^9CSw6`Kg=0NYEEmecucN2J&x+EGCkMlu^Mb(&z`r+^}G&XwKbMtkvoU`p@l5> zQK;)m+76z#aG3*4p9xp8ngVcE$__t56Al>Eh-6Y|?V5A}O}dkLJ9Mj{PIF6jE%7E7 zxuT&=k|r}w1mJO8sxZ#9qzUCoqtaui3_zbCYX*I|I#konr}}6(a?&cepQ;K6tcT(0 zqcx%GsP%5DviGSbUt?gNF%W93zO(_rWXq8N5IkpsvjC=;ICH>xDsHOz;NG=(0Fdty zkN^ybe5b(VTopLyH5EKhcU@^SfD3u2_+fay(p0ZT8c-}PaR3$yjyspob5I;WvF8{- zfv=LmI!BZaz}08Zgqn*NLzPkPkwd4#@dGEr!3t|gxwj&0-d7Q}(E9e^iLkGtD(u~J zJnXHsog62v(Pq_&P<_10DA)>u=O~8Br+;xg;aLF7ZOT0|4{$Jm);-dbLcnr;UoQuiq8cu2>h|9X~Pj95y_>-gjttwfo@k z?x-nY@xpashqa*Jf7tHL%J~B>lL=b}WKk~Eb?oR#pZH<`i?hXf;{sc45da%%J6dUd zq-^jVd>7mS@B}s>0ycx!?g@+5WEV<=*AGILuUN4vY}vBSnq(Zc{zbdJ;|bawJq7TU z(y$74P3u^(=wdQn-zBP+tdrbB#veOb9k%Y=V{Lu5hLy|KhY|gTg-3qyV0iS&C&H_} z-U%;u?;pDL9v&X}!873tpZ!Ys?svZ%-XHgYcU7UG7d-%>9DxkDP#lxYQOZ*cbbPxY_$ftTQuauXTpoX5CbdMJ6*hQ-U<#TUCZcOL~kNCDnrfQLB%Lk zD?gUUT2S$OOfuA~*J$6qXxYlJ(Hde+n>sf<{DVis+b_Qo4(!}+eV44iFzw#$`)jXQ z@53rnW)4?{sT0SAuYK(+;h7)394hvkf@$4a06^5sL`zOOdrUV2$rT$1N63S zJACk%KWk1NZe0J+dqY9FyRDzoG;3KuZ|)-J5_FxByq7%IJxC_EsSHlbU4a`H@}?=) zUXykD^L@m&Baz0EC|1Z|l&!1Q6BwXrJl%i5kfh18os-s-i?7wf}m)0pe8)P=)`_Jzlv zc`MK zd75y6tJted767J3B|V5XZQ9ZRTz;HyHN||&nMr_5V<{+ET|CjQd-d)Y7A{z7)OF2& zIICT?p!lIY)MxjbCIW|V6S%t5q?vdApZO*3Go?bok!)9|~i~jL-Mvg}MM65M&3(?EqpWP+W}r zfO6?s#2-gm*8BT*-%u`K@q1wZ5(m7FczF4x*PM$m4=ggim(Ov2Yzy;P3Lu|TJQxb5 z`6tc48ri|=-Gym@^;{GyM+hIG>2I7)+dg~L|%aXUvn{?t}Zy?3E#Wb*SS3(+tE z7cc>lAIFfE87mvC>5MN5yF z2Usxk$2=fvG!Has<~iJn-vk(yChMgwOLONn7V>-Vz8^-79Ft!RywAPFTDIRyO9A%I zVWw2XEE9mWPf2D9o5FXRhK#02g>h{XziEnbd>ggYO zPvH9NxAWAk7V4N$iEFXe--8p-B^0fkPTp78pzQ{mMGhr@FQ@~{p2!?wEmaO|>;YBTN3>A}Q(?W^AmGp&;;3rW-~vn8Eb zB5D@EYfS&ZT7Y&LENt51qJ!|5`yM!Gm{(($SC7}23wQh&z%1A&9)HHOG{mZ9i?=ET z7Xw(Yi&XV}At2jD~<-i4Kb?)Rf25g#ku5Wkm?T`7vlG$x3qVao24;k70E!YeCJhbICj4O`;8g9i`$>w7BpSu58{w|nW_&5fp(b<1zJ}9(eE(|M8++-UD!`UMyYx zdSUg{WJF1O_>m{v|Le||)91s=?FYjfv(|=Z7wid7%&!cO&aMnE%{dlco_8cXzvOV} zw)$vzcGAi)eDS8R&pM2rI(Ezh6KJzfKJlz8L&!jh1lOeLc$)K*%MUJ2hSE1-;$#Pt zKF8=Cn1=ui2Rm;poKB{L1`l_RBV7c?kD6dYsZedNo_#})?(ev)mhW0@S=w~7ShRu- zP^l<2He0lU`ElBD2*A^)&-BTKMMJp&OvA?k0|tejJ$u`#?HBs?8{n&Vz`&v5&9{1b z8&`n##>%;Y$@Hynf8SY|6fya#)#;OkpkM`{L%}E&k3aE@cOgAhUF(5_LuW39iF?n6 zSC=0Ok4)VaM(q7COx|}ZjNfxDbX|5R{Af`{c-!7vbmWrxsSP;0|8uqH9pG<%@>i!cMUyc{DetPwNUU?n+E{iZa#s*LxzQ6rX!3THO7Dc;2|UY_xJ5L$g?lt zXmBGfrja8?`y$JWhMZTc#T1+caO@rgY-AAZc+Q-8PO1E<@HZ0;Bo&gWPJoCmw3TleEOAxDm(Gt`GVqu>)Y zSHrv`b>Y>8+rmpTt*7uQvw_V-I(RdL5! zclh3SA54_0oQWijw-~_81?JJ@Dbt)%0Tv2o;G&&v^Rsl>3VVM>=+k$gH=w3lI`>Wc zTNbl7sm_^A1NsjMPd)iu1I<~k%QmH81p}l-^TVLnS+nN2OHzee=*hedNPz{0Ynfy15!Hj9In@=VrarkHHow$~O|eK>W(?BokK z!ote);g#7N!fSJPg!gyUh84%IJH_@fjr#eS8$;jKm0|Pw#QAa77R+f=tR8&e5tqYg z@@Vuj$vhxnzd_EHI8-UODO3tezG7Ac0hZ)9CyJIFJyNog=GK?|xA8k%KgpR#&ze2{ zYS(W05Tcwd&7$C|SIz!1<>Z*jApE8b)yazGj8?DmqybxXJ8;LrrtwUPy$S?rz5v9J z0#F4QM5$`R{KE$y4Fd-Zb+#xMVQl+CN!W`r{Q2QKw(kj>t(E&Lue=(jOq%Rw(&-DA z!+~=K@X^cR#o1d!*QH0pW7GG9XJ=Q0M<;AFs@@k~n6^F)UA`x5KWp`}kDu|$-D8~Q z6QB6guxQZ|2U4aFzcqHF#-VYV=dOoCRR*9@ z(&*7+!#BVA?R=wX^bCbSv2oLx8?gq>xtlg`cR72>OfMxfAYWO~()#hgGx-nzb0AX@ zlaB?9iT2g6e8b(BEGl%Hv}kBEfF*YU7V1T@;LA~}FqLpO^1~GGeMd`whvQXOTgNCq((P&p0)0N$}}XXyI;i(!r_E%iV#|=2qBUZT9<-v*Ez8noxPX#@O-6@X1enDvTR9!SxD- zC7EErQ(QOgkCv-4ap+tQW5$kmT|;J&Odu#3MT+PAX3Yh_N{hxsdhF4sLbo@%ha-oN z=ewc0n9IeLMa>R!Yg4e?l>(R_1;~KSc>jZmUP2EFmLme~mmk2936N8R*sx5Xp~FUn zzy12R-Gc-Rmi8J4zmbKm$>xIMarz7X+a23>hvkb_gonQWaF}l%DL_6!Y}LN=z;O%V znXOxCO4Bj>{O*Hh7MUljs@j6+W-lK-dN%yv2akoWue_0$vHV7UFB7Y{ce-D3?5cG0 z$$sOm-TO>qe%C>SYNhq_9-sp(zguF7$8b9q{LmpI17eCWqO{J!vUA`#rdD@efa7t%O33{cDgb}ow+FlEoft(3tc#gg}xzBF;tGio2C-_`64Xlo0AR(cVSPI)4uuV-Y|L4(IK15T6;s&ygf%M{g_Fnk zhuYJJ!{rN>`eMmc)x1gato88I?^!?gCd`wR*vEyCmzZVOiFHgQLBdG1POOtPq< zR2DGu7^eowZ!B`=KsLQRb<7o%K6=bJ7f~buC~CxSQ;wT-pEd_r)T+pd`?_B6mrAU zBol&(J$SS_R9GN?&6e#3_Wm$-{J8K&_imwQ-yWgg;J#t#@Ij$hzuw`sH@k(GUVqgd z4-CsJF~OBG<1UC5{s5LqRd$A)Jy{@g&zM%+FTaTlk=e86TZ+(F|LvPLZVM=dX#Hy} z#dX5?DdEKzx(4iC!i9LTILd-hh6wi)d(hg9MFS|SJO05uhLw44R4#!`iV*S?5Y}6H z9|lpMl`GbI$_lSbt^$%+vN9O7l4an>M@3>p@t&1v3LV*$N2<<*!$!?pjVo-i^qsA{ zD#F@LTf>}1wz%dk409GP3Cq{458HO{weyU1n|tz0)?RzYbb>09#m(b&_L7ei_PDy5jL(b4Lh&(MhJ?8@&z`a@O{4fTCrp{a z5p&u`E;m~MD0?KPpe&#ZY1;xa{TpMm=dJ;qm#MJbTw&3YeMD*2w5qu8@7PJ6G-0Vdc0n-;*@nV?mjp7@wz)AFbo$mt&zyZy2#80wXo z7K85BG%zqzj#_>*3YRNMmLpwz*1S|UYAkc(Vx4LEmOFi}))LO`x!*JS)VTzLbXKRH zOX11_u+SXDzgGYk1Np83ER!gv;6jv@rCDZ8O3cQy02akc50K63K$uhFgzZVH#%!xK zr-Olb!uB1VKhKsE1N{`?I7>LUQEPcx$EvJ0w(Vv(bKW9PxCHrZE@>Zj%#fLs_63*o zn_`8i6y?SX;GO_1HWh1;h1hf&oI=1Cd#%uC3n@IBjQIQ2KZ3mI6K72$t}}C~@@Tkf zh9?mn92%tYl6m5uHv^97*7?hpF=^l)h4O7tR2j=AZw&Svi<|g9$^|y9i--m5{$omx z!M~>f$EHylU?~vka9Y-c#K0C(Lek%(o)H37lTW9Z)vMP!fJDPqty<#|r^N=O3{QF8wQG;t!215Yj4ZQl zdm&}Bkj#x)wa-;B7mdSU_N)cI%ka9TCeNS0(%h1J!jk11!h7#cFaRx|+I-)mEln1? ze6j7TC0xh?k&93ov^4gnEZ8j3m7bgY`7y|?0WjM~_wC!~{e#^OHoHnre(hmZ>PQ;Y zLN;+smFWp7#)^vpnxLZRz0^a<2i``YoxMWG?r_Awiz#IyTZ1?*L zbG9(3NJB>E>^TeERf_+Zn6?rKxhH*3OJs1?qG;;-zA$o&AZ-V;0bF^}M6~jG(RqLk z+&;tz_-!SR808Ww~@6DJw*SF2!FXweq zS=n*|7ZdA59!uGZU4=~rrTp`=i?FmSfQzxIwCpVxT+WjM6mt{UD*0aoG%%IO)57sj z5&>XCoq&n?g!3P_=Bm}}{V~pd9!mzZGXWW_Ks(>VcNU5Vmk(T4bsfFm&H*kaOAAdz znk^S|q{QGWx)M7e_#6}m01B=Xk|azA$b{y|-c&RT3Rj3u8{s&gKm&eg_7njw*Apc- z)m7Pi;5!JwrQC99$40C$Wl^%+hXPp5sQH}dhgn!oo7J8rIPrx82DUT zr-<2dDMwE80ZmhO2LiYd$c4OCS)j)6$E;m0M2P{YTe}_r4`9>D@=&gJRd6mWTWPqQ z8>a;~uupTvURn>xVl2CZ0bGod3u)8k03CbPVi~OKLE$(w#AX3RdD>iGtUQim%M{`m zv*kjr){i{Eh2&_KY19;jOWJdsHWcS*3q)m^5WALxL9&`f5W5l6V5d1o+k@J)o(;{? zqN$U0`0!!RMqo#s@}fu^i39CvDvM=SA^8=bAGdX)hGqRC(OdS#((dlgk^+V5PHqzEf`dWcy{&RG)1;?zC+s$E^7H z$N((UD9%^z$N&R+IUwIp08=6(zkL)txU#a+LxoVV_T;L{sS?^-O2M%sq)@OS%ju!* zoOq;^Y|mru29(o7&WyOEuVTmARK~e+O=mJVD*l2;2f!7|-?Z8k$H)V%vD~itJ zJBa@hsF15tay!1RJY=l{Vkrf!odL`bZ;F|e+rfZwByg_IviOjO-X!j{zAA*04s4kX3;K}b0zJwD7lyx z-5h}91q2YHM(#!LQJafWijP13q^Irx2$Tsx+RIF0Ue~U#g&|h)1{Tiy;s#JQ0FE5_ zZs^~Cpg&ewhP%g}lim^Kwzg{#i`Mqdv?nV|MixrMi#6_YoDHQG5kP1|mSVwB3$Fp* zkNwzBcnJm;0-$SG9u)}2TT$>XU4A_L_HX~LgG(hosF!=@d=l>d?%(~n@Y6s2cf1_3 z>T`&CRaUC`)LD-0e3t=c2VjHUeW|7trC4d9_nHE5A)tAUi5A8299ao#rY=`MtHniD zC2SVT<2(TZsJ(mlaS8`;$yH@-aHK{D6s|g(EC8jATvgNJgbtD%v!ZtM8FEt;#_F&-rV#qNE57b}+8WIaWzw!o;bbXh>0Z zuakwNqay&UiZ=iq=PRf8Eb-j;A?0MSs8Kuip?UxXNSR)uTE2sYfy|a|es@fyrcrRK z0W4~64-_mmuMJ|dcO{#Vv2X@aq;i{O>hQik8z%trSX==)4)9z@p04yx!}cJ9%K^B7 ztFjmcOW|q{0IPO}C{!jAG7{|>J9g{V?QQ}AQoP{{Y92M}J!`qM-tAw>a2>hUmfb7u7wW?70nlIm<&TG-`l+7@zwirxzX6p> z3;r+v<-a<3ECTFZ07lNTP*@CK{_1$KL&V98)<%95LaL^0Gae(}p;l9koR@u7$ipMlERIrynh{iQoYWWTdOpk9vb zD*VbYVCFu;`t3`O!j zte3|Mlt9H?gVz96@9R6_yy^}MFxyAzAB+rc3BaXn;aF>pJz%k;BW)X}CsfxLIO)lk zvqPRKT@R3@pv5s|DN`yTuEnJ!dd_KY0IT&6bvoGs3yYp*o8QMzHWq#4Shy`a z_-+DRNKs3JU(CCuIIfP`j3%vDTT>J(R{WRelDDv5DQjZGfEdS;`J5aiEG9kf@Bqt` z6)Rayk-_Cqa2m{b(y}O6!G?H|ARA@pDsV6MDhgGT5tJ$HTq#ZRaA|>XRFn#Czygp> z&2PIe0d9&N+!TNdO;#4bq9la@1r)&X9&LO8N%tXpS?)-x?Z{K56deFX2Fr~}y$`M@ z8=HIL`#9&m0vO7b9jxM?S$1$+11#!d(v`7+azrfm*=K(g{?)(w*Ws&Q{abf>01_0a zs`Rw@;r&1U<4=T@D_7?O`nnd4MgGHo_)p>g{GUJZ*s&H36wftOJGyN_ER!UUk$xHvMfbN~9UzvO`N zoqz`${;l8oXL&pMcYpWyoMNSr@qMbk)1d)occJ3JZ9&1sl&4~mr9xV?SgV?+ZG7!(Uv~$Iw0UC60L=S;=kNS%_;>&A-#h3EI!H#h zEx1h&HZ+-n3jy4eaA6h&$L|+1o3doEQeOG2V#3Pac;k&Xy(JD^NY#fpwws3y8xj8Z z|Ni6fp!GPE^Fu*>t~X=GEN9=mPctvB%jaS9{0a}b=r2X=~6e&Oj1Zm2$X*nts$oHw;t8b*vy$9eb;}6UCuI0I|GJHni$@Wgc z%dOb@OzT-OZqigM=Xl&(?0LQDjsmd26ep0TE3ibFa%{+~lBok|oWpa)grQEZBMn^v z3{~B2uUVCal&rf3a50&h^?DYC2uNjCDv+;SFeT#wo`6wy2A`EVq%9_cP7tay$q;RfGG_~*&?uL zrRv1nS=wW;A+2P!dw{bRfXWOiNDp`b1!z>Kqe>lAih?9Jq}-MOL`7Nx{;+C3r%)gu zb4@DE@;)HT4(6W3+Orm5%inLA9emFKE~I#6fm!T*CR;ve#c~Pt{l#B=+U?x`@jw2j zhyG$vSQy{>)_2?l!p5CoeSQ^kls!y~_&5=-mV?+jdz0>o z3@)TC3*6Sox>RlyR2rwvVh3Zx67c8vy!9}I3YBHK%zF3oI)j}HfBxrx(IBIPoeY4h zfdB9P-v8}#SH5T!6K`8^TW$xpIR&>hz{a0q&fV{ zzwx>e8x3V;3n@U0A`ND;ZL$6-%ilP(~R?{p%74>PmsR9Q|h8Gu*$4h|9UY09VY`#6jgUbOJPgaMe zV3k!+$}E!)#c8L%%qX#SWp40Xsjmv;a}9x)-U1^T&p9j*CE;}h7A=6Op4%Z=wD$Ch zA^}G-QjQJ)l1ED5u{e|~EeDAb29(;P-G&MwD(Ri;wFf0Di-MOdU*o=LC>Ven?M-U$ zG8hVyds6#~cuhMMHf-4B8ZkQ?pgMqos%7(T+qT2wx-10Q((&droF(itMl+Z8tW@3h zus`^|2UvS`<4g^J!VLPxH@+2q@fUw7eC9KsbBY$56-$2o^=`iF;Sc}tkKCihqL4g? zvfqDyT==zL`;G9g|MkE19BPFNRe!o8$lwl7!2m1DWx`>xXw7V0!GVDt`*T0{3tq27 zc~#1^{I~!1|H)@;Oq@75Zzsb6xGv5QWrUFYjvdWs@1BX2?dWJ01*^R*@!)b;v|_M| zz9dvYY&GdpUCg%C`AxNb&&NY2~ndB@#%{ zYA>75+MI%8_9SXdSfvVpwk?Z}_v%7n0zB4mWkzvd+M&;5WT}9XZ#hn;L%ZfTNvqap zc}?P_ZP{~qGPq4ybTK)4w*ZcTl&6V%67?yQLzJpTsC`NDZplp6TlpO#>z5==^ zmur#cLskbMt5B&FHnHoh`)~RC*#M(S(~?i|VC-PUgBLAb6{gLc=XNl5vIiT|c5q7p z&H_0L#8U4oIZoOz-vt;%l%O^?p{XRWf(>z5V0_U~J`Mn-AwZokZy5KjTrSKe1u-NJT27%^ z6=z#U!T6%5&zc`5PnqEqUeJ@(8Wfz?vRgv6@n_}WkOr)*4Y6ZbugoUpN5}h_ zl7*ofAKG&)`|@Kr4Y4^7|o;IIJky18h zTozHTOn`<(vxs0{50TgF9Wl* z+_rwdJPKA`G-yvcWHo?_}*Rs&Z6*+zW_Qoz*zvb^!-kN z?=c0p6u_*{cLIC|;4^2>H7-U9i>5}0WN>S<=q!L*Dx(0j6~S_8oiN z4#ty3Jb3D~S)r!(!ui4%lUw8RhbRiZEzyuqb4REpWU)IF7 z^mFOY7gOM}?xX!HVVwZyYdk9!oCRtryZnBmU`3Or&zKYH&RuG{3~nhUwl<4al6$!z z-|rOMVt`u;P!G9d}UOs1Vp?CiT4!L*S;nF zR;A6x_IBGTYfWR(aXeW2gOR~daH}X;S%5Y5{Vafa9{^*}m~3TUC`U_)?b@5f>v5SR z09B%%>SVF6Sl3eiRh*X|08kKC%E-vYpP0cN;>@0Hd~bDv(C*vl8ccPsL2R z2B52GsTyZ--vT=RzV?)KM@ENs_$#9W3RYfphoxWvs)~1NED2bmN`WHw&5^Y8mwxlPN9E(I_tI~^9_bXPKUV39@*aDWM=0tSt+s3gmv7Ujl` zn**hms9VXPWD=i+T}$Rl28#p5Aa@jiXUv@2JT3ZOD_PQ-Rj@4H$^xkB!$7?&z-0ds zKmj@%vB>miI|~a%1;VFIo8e#so;r}m3Y7qFdvMF!0Ip)Bg;=x#{v8%zO}vuWnS8)j z5f&6CdL%)y0LdRkS5$a~;wvgz%40T}aV^R&(OiqoYs#(WyR_jf9kpsZuv?}@cX)th z0!h0C9Kcn1eoFEKI)8x2Mlu>;0jkRUBWtyhoa^xVh4WV&Sei_;KqSw_v1FpP9k8t< zgSB;~C+;p=Y5BtB_W(YciD5sYHKcpb9I;eIrmNPK>)pe zohH$@tQ68sFP8+kV!e2G$W>xsL!zuCkI#e)7q13_WHm*_D6Cxx}IK zq~tOz`n%tIFznlJO{Z;P0DLFFZA`(E!B8(i4;wlv95c!TY}hp*-?(wZM?%S09bma9 z0T6i#RVLmbtMOs-7YYVwWHjJ&+`I2k_|~_-A7;*)=PcT(IG0D=c45YkI0d6QL&ajx zLk5osb+s46t()e+Fpv{1`ewd!8IBK`P>ro@eIOWz~yXCKoB`b2IvP(3^ z8Z>A~7%*_Cvs}OfRFxvqW55MWY1;4f84#X%_Jy!*`)*$V9iD>Oo3wx5;c(LI!gS(0 zlbQu$sQ`SbNKq-xSxyZ<8o;n-#*A8!ym_nprJ-PQ zh@}}rv49J(9AU#c0_f;5{hL&nCCp(CB$y2+Cp035SxWh=tI$BmyHo_y-LuzJk~?=W`X0?Y)q2Y_Q1&0?H1 zahf|lRDnRj0ab`q{1>(jtA20v2Vwt#BTm7vTn5zY>^JAd659s!p~FVGS8L7Mjb92zooc-UhKm}w5e&|gbw}tK7c01cv0K#>J z9Lwf42G3C-M~`{m3YP44Fah|iDQJ@m%VJLOWX47y@8AOBtrnbDYD^lRakaz9g=f%XJUI4~+_8>(^1Q^HszJ2?wEbmcgV>l3? z47CvV`dDbtC|ViyqO%gqv$XK6tV&ECwPeQ}!uO0KMMeg8ZW18^$XeHo-G3a_R#qg5 z*8x&?FNzj*myeqq-(=<&iE9(g#-3+>?k(H*I7PdogT2VnpwoU;&HQ^ggcx z@Y)Sq!@?yieTN<(uUNey?B09G*>kd38UvgFTW06(%$gvb0DEeUe9Qo=VE(>+2g2HQ zn_M9h(DE?@CPM*#KxQETDnSLjTjUk{?)VvVy^A*6Kz8ih>tRG)Ck=2za62hD(@~N| z!SVJL6$e!fN@v$bnE(b@3<3*0C*?+9R_r|(7--2`x9tk6RI8to70rhqQ++u*mo|O-+g!cSCBy(WEcA;SW$9SNK>#kh2F09|M zC2ZNc(}5>r15j~A;=ZJ&#k~28?Y#9?>tdTJS^FJav2z6<1n`}-+L%3e0^DMNwSg?& zNT$bLw%@{k=Py{6r48gT)Ck?-OrW8kB$CHJHuzS}&4^-eF z;V~u_0T$lF$$>(p%nof4N!rQX3HUeGmOmm&R)f$U;l0#osTQr>2XO*?yl)6|4si3) zubf9K4t-(*Vk_ei0d!15{MtO1i6t#uM_4m^2L))_A{|t*uRCS+;mO zGqOP+LsDlMndVH>D%6#Kz4FZ@#0K03CkzoXbPUd32+Ja+tC4L>&kr%a7>L^ zj|)-JnNz2Yf*X%4%4{zb90Pp$%JutC24@11%h@Wn=l6a97*{JYxD((4c5N|$^?I?O zLVKZLx{m@dj-3JkA1^Ch*q*iMEDBbRRs+pBlF9caz-;ZcdOP-; zx+Agm0It7&yLl8`ijB54i_QXA!HAgJ#9q~(Q2m5O%{&(ykG1Q219IyCj27K2fSW5L zTT2FKeLrB4`F1K&r84esc6e=qAInb0!nloo!SiE>?*tTtl zQ#_l+y^>E#yN*F`dn)b(xKWH*WrS5T>yRb4Q?3x;0E_B&{E>Z04Ud~QZzr{}Y^y1h zylBx9FTunjP%02Wrd^%d_tdr^w;bTvwwJDI1UWwzKIv&^kd@?e54eFjaadKF= zaB*If=DQ`+Rb#qs!7aa(A&Ci!CdGY|mfQZ|85S;FxM-Q%!7hV462K@$fFiqAjtqVS z^(NP>S?3hW9{>telJm&ARMLE`A?rP=15BARExh~g=mwQ*WpcHrdeQeSz)ZGE00Rt@ z4h3%Ax;-pkzS6; zDPM)O?LwxIuA!pe0)y9)xqt#2=fY*$nWw@^(F9z*eP z1U?TH4<0|hmO@r3d+K+N(oW%-i} zg&$)(n#ZtGKIy0?T*4NaVf*Lix-zCgSG!TofnNAJl!%n7A;;L zuHX1Dv4cAjz@lEjq@e~Bj1xoD%WrYz%1kJB?=$wB6JyM{@nQ1x8R6)OlVRb~Wnu7; zVYdIs$|B|Jb4WW^5j1TSr!w9{4?pgk)|gC%6FUJeLg`JRUa``cBgl4z?II(wSNY?) zN(Va#x#~HvWwxB`+Pg2DJaaZ&uD>2Ct4>%|_ffXB)MTr@$2kB7N6;oS)rqD?$9KN_ zfbT}6KT#*ZEwqD+MWF<;Z!j|eVZ#IxFp*HO)Eh}rA*$!Vo{yRn!#9qdwFVnDPSw@<_d+g35`-pY%l%60}qE~%UAoB)M5z%trt7)WYG=;vX%}h zqeqYR$MSCBPxok0uGmVRlFwU}+PZUL-lE0MuD6)y>zXNGlux1ni#%B>P71&jOB*?A zOnCOW7k!U0m3GnqOY!OiI7iv7!J-wz1xz$tCLIb^rUulgx>r=tftn8=J06y-SQ+{a z8XWfQKVbWZFFCNh?=`b>-Ypa?$zgW%4;(Zs^y=NuDYzKGt(z3^5vO2P*-6FZ&IPnXGP5<2A+3)t&2bD&_V>1^7zGpyOL*(rJX>UCbH1KT!V zN6RVz@L9?!Q7jzrSp?Ij&kl3uF0{HGTU(`+VVd$AbAr+ojAE$PcHBE9qSzlyF&Xv; zld?0@3dt;4y0W1i+))5l;9YrFfDIL6GI=LbnrzqxZaFIe3y`bN)`fGI%qMLF7R~Eu z$)Z?x`fG%GgjWv#_8IGg{v4El*wlhPk5}T zO{wZT)QJXgF9vQlvP4K4D7~JgWZg}GZ&;gyMrpI{T?WfliL!&TrPBQ*)8S9vVRa<| znaXt(J_9_C2PvXw@mOTEI~)M>N5g)Bf*z;wgBWoLz+|bocDZeJvQ}u? z4sNRJvQVrzW}ErM0V>^Dl!)Kpdy~v`!X?RX!}CRDJMyh6_8f3W3Dxd+PDF_;OJ#4w zGFRTJQok`v$;y7eX`Zau4o2IDTM-YYT7A7G`lkR+3WB!;;4Hve3a~s#>F+5t>G5}Y z03zzCqz!6-=^Nkes7+{q8wVBQT@G0bI2*vM?WC;%@SFtT8`nD~z-f?UcVT+dSegRU z+e_1#m4#f7@i`p@V0`Bt8sHdYh3sNVD-_m?&l9DU18_{09RXl;41DL;tz%e+WYL=B zG<6E#mb1wsdvkL;9ooALzApfdWpJs8PE4UqQIgVZUppJxI|V1fhIwws->{CI9g>0z zDRP?lG;2-+TrPE|7mcpd(E!F!ip->zYtdQZz?N#!S!Pl?ARo)+7~Hh%%>q6P*iu|1 z>)H+9Z z0nzhv!hz{hOaf4OW86PBxH`pXf$6+92N=qY9Ubc8*;)YewEueTIh_d9q zRAn6|Sy84~Ci7WdkEsXnw2L1{2LTIhV-f3=rwlJw7Q0p6w$9UUQPWDew0=Q}x< zn0B&glTK=FM!^7FY3*d>ss!M;2SOGAS?{xlh+Hbga`|zwxs&yI-WT_Z}e!Hx;u=ljURW@G^@PQeyduF0a{p84Gzm1@Mb zRHq9+I?t1Z+Q9+VR!+$xjxjsU0@%}Xa%GaZRzApJuW2`-LW*g}MtbXL%(k@)Q2;{8 zEEX+3m4e6unDeEv_qIX*FUJ9N_2Eo!KJNfZh z0P{H|xs&+L)=v46dCVp{s7CTt>=v-4n2Bvm!Q(l3T}s~Le#lXyEQGiP-$hDL7Qo7{ z=3WS5@Ex#buEpbn0o|p*=AC1i)pRpK-JV(pT9cWnt9IJrdw?G(1rR?X+tals zcSvNjbQne!1v3c(R0^7uAjxx%0#N2yS_a3OvXm|*(|f4U!i%DKX~z1VEK^CMKnq7= zDAv$p-JqdK)y4ozi!MaLfGhygKh|ZHy?^?Y)n_)4&)G(=+H+RU_d-=TeEUk+Y=P$$ zHkR60Yh&B35Dr;Ofg`n6LZQxf&l|WWP9-20a%Sjz0Rbx2a|QkZ1L}@T67m?z<16@AMX92s zlO5SQqaBdme5(~G7+*B$O1LQ-xhl&6IM#Z#n)O<3jZHEw1vWABMyA*TR|emL2I0s4w~=DFrYS4REl$7hZTNeDRB4 z4&VIdx5Kx-^&NlAeqrtPO}iHh*|BLeYR2@r;o*m#2oL@6@$l#)PlZPwej@biJ1EaJ z?oe+UVC-kRH*|`qtN2Az*4A3t#MfT$7P|N76}r9owrwhZGrZC5E#J2c;OuZ@|CH}^ zZ1(`enk_Yzar&HniLSgyu|NRfb&;IPshhO=XUkxAs_^*Y(_xJum`2P1F@O{Fuhf20+ zDe9H>`^|5BFZ|3;+ckgr*TX;gjeiz?;phKh_@n>%$IdlaSj7QO04HlC-v-ZqE0j9S z7TrJo#a{})_<#L!`1r5>dieF<_|5Ro|HbcEKw!03B4867i-OO#OMqjF;|9;3KI3fq zlUs)Y~(>ksFI|KCh%}4tCmgU&Z@^&liIiJ69vL;+I_73HjqF~8I zDEJTm@Q=c;+Jya+fAU-5mw)-=;g^2tSHcf}_^_KK0IZr=QpjSrrWSzYB`lw7fA6~w zhF|>09}mCr>;Ke2{>6X%E8&0r(Vw_BEr&`1a$yz?xF@K$Wt7Yj;6{vmH~iYK|C8{$ z|MFjjfBMhTiZUCM3AVdD|Ow5m%^Dep3McwO{*< z@SDGBU>Fqx@&gb2Fz=0uohh-hC9OB@n+D*&{o1#}-}{AsZB$4*>;mGfB{Ff ztp4B+{xJO9&;5c^G2`$5{eKu9eDEPJ$^v+zSRSXrjwx8$Hx&P!Z~q|t^iTb4__bgC z&G1iu>$i2SMK{!*3sbNZCO~FT00tKQOSbr+V%ReSppnhjEn#1Kn4$P~ z4KRwrX#?v_jkzCBoAzk(7&B<6ZT1>abw0d!;zHc6?8v%JS?>Cn3dPf)p(&M zR3X2th6WUnrDUNw;}m%5rB}k2zVtV)WHG+*g)e$Z2UxT`Wn#gx-5lGkX(g+7uYTcw z|F2JkPk!Q4;nRQlx$vn!|EuuI%db1Tm)EQm(6Jbh2W$HDnc*{^`CRzqC;u#b{_}tB zgYryN#>HbMcWGj-wcJc9pH z=aptERh~E5bJ6711v8U!1yizEv3J6c&hM7bHC;~I!D%1>m^v7YnmWsCsn?|*mVVjEntHOu)> z?)&~5a}B0d7pz|W!!Oa1f z9eq$StoqbBi^NasW>|g0ipEbQXQr0G1pETpwEf0DIc%OPVWEAVbXz0qtO)Hp(&Otk7z|TP!-w zUegrV6i}OYZhHsVSTo?d{4!9_ojM=tPF?iJXAD4&?ybsE^f?3lf;sjRfK7wG#{d@! z2gX#`JkSzd4efD8L>4=g$ja(Tcs zbow;qGx2Y3*D~1MeWn>>|5EtmECo?)BoQJ~bFlL;<}Dm|);4&Vy-aDrQ}!9kD)5>1 z0B|921bP;5v5ZZBCJuHKauhY!OuDNw7=RgxHjO{pYCxJ+jZIv0mS{-?uqj~G7B0kG zO3t%!kG1HuQl#hQ0xVOgn5k6gIt_IW2;okiT3R0|ls4OJfHC-~KI7@KIoq(90@T1= zsj`JqwsJmd*mvxtKYcc-3L6hLT0_YcJW&x9s@qUEl5wa0RZ?t}Yv4K4b=`T8yKjQ_ z+SiP;LcfEfoEV&|WCmU*)OpHY(?;_A@5e^>Vx@_Wp^3(a%zYfIvf`!g;3-$u7CtWl zxA_3GKbWm6l!3~$gIfx4q3n#T1p=@P)r+KT0zfkaG$1p?`$;IYawP@;izIA4WU@|E&(0DFZ1LZ3O;Cx8+ZV1e-%u!$UrqB{XDPzNgp8Q_vQ zs+B3s0i&X2ymqHTT{6*BZHIc!Uo;9d3ZiHV3xIRQ;sKAxDo_f*)bHT>yv8+I02eJ+ zjC7rIb(friN!9V{cSg}l#RX7exMX6eQZ0*0LHkaCGXQ3?NL_*LCG5}I#9C1^CLb29 z(u2wC7k!dl4jL6R=+_5W0L{64)=L@Ydi}9j0AEE_DAUgXa43Ar`MY3b`!G$8ZS=^8HY767Fjmo4)U5FadDD1w4Qji>2z#sCUPD{pO*= zMtOPPgqqRVlf}SickbF7#*7^w`t}>-o3H?ya>8n2;U=2_K6=bJuOv&kV3ZO-XHRYa zeuG2L9(_WecLsPtHCQy1%=dMBvxj~EkkF@Ze{TnXh@hf8;Bvo7(p<~NeGjnq6y>uf zja@=PwRRjmW_)<3&p?~tL0-dIG8!t9;xl2&^w875dAn!d(0|ZyuZvY}%F`*V0J{!_ zNGXKYXTad_PX9rnXP^FI#hUg0`og6v!kcgP3_W}G4Ly4H@rVqIgM~zaG~Ros&j3r9 z>u&FDa#jtvh!s_q|HuQJmG`Wk3`#gh>m?cgTK#P=5!BNH@&Md_zz}DfOg=IeR!qsl zz5|Aa-uC{Wp`*eZZ}kcvOqd!@nmonfa@=Go)n);d;^2V%W{=)s_r8PS!j*b2R!W6g zD0|A(nJ%AU<$MPv4<}5V>J$&F23R-;i;E-N#y%jFIc&XljsJ(DGY_K$-?zRAiju`7y+{?}xIAmlv zY#ZtT_=K5EXN=v>p0_yk?l;iKd+(3;8kRU&YR+FWN+dTMC5JF!@}TU?>fj(^JXh) zSZgKw0U1_3+DaF~ntSyf;1%Ej_UyTfPQk~kPJ4B{qgDv6+7<*FH%b^sY4bdWV=x3P z)QfH0S^yVIGPvUu>YxC7Vu1Ol6G~1T5Q!J+oXO%V-rd^Sbe|#Cab=>**RxQYjgjwt z;NbS|J0#4Uv)CVZ?=>LInZL~CF9T}s!vZntg+;Ggx6#=%3uOE5z2O~Gvicc^7&dZD z*n6NdTrjigym1LC#>3WWlr?1N$gpeoKBs8JgSOrH;|vyEE(JF*9iwaBHvmJ)xHf%9 zzl(`F-%hf2-RAIi_jkg;fg^qFvv%|VaKLs;AbV<< z?77aUeZ6VMP&VKW9zH7UJ!riQje4PCK;#-M0D#_O+_g=<52D|*H zf5WBA^$lFAZhEy4;3OK?I3}L=iFbGwZAtTWwZ^6`wTA?HPc}zMGJr3fXG8U=(6{eU z(~w6R2t&i#4co(2+vBui^(F_i=Q~48#x6Hdu7>xj=r@p!O`on#90$JT(*UkH%U=%Hi&Y177_2@k~tlPNDsP%@u zw$NEL3t{7y-NvG?hIh@>0zA5~%v-e7*)!ovwCl~=cZGpwWA`&nnMF{s|A@~g|juHhspr`+&IoJAW;2G~=!56F&CuzbJ(j2y13yBd}(S>wO~@Oxt? zg{ta018$-}A2MW&?OQrwIm|c1h7G$yuU@7t_Z}1$ELdT$A2<0q$`v#mAvi_k=jI5& zZuV{F*G!?ki0vw=fLcr9r!@gGIL(5_ob!Lg&GU|hPzEZRIX z?C`%=TJ(i;#xhSFcYtBj+7FzVYG$?=zjiH&T7M>#tlKYqG>=DgL%xMiEL z&p0~=qj2r`7_vd1g{lPPmbobougSD_OALcAX#feY6acvsDp?FUzuDTkCyKtF@87o-#z( z?^JEO5C;w!ZB&dyV~oq%!NcD-$3|bT;(qyx6-zPYsLH~GA56frWuVykBS%lNMKRJB z!nBzS96Y+QAcHY+(2V;H9O0Z`z~J{xfje$a5?FM-QSdI;%2_aQfqlllDLRg=jA@02 zpWgbKl`30kF+jl$H@4mJ2YBc+7ahZ1KjD3zu!9d-`+;57V`5WSvUp{fZpF^Gn`ubX zPX4+8@V4g2BEcI<>%p zQOY>ykZpNAQ=8b&Tn852*G7LcrS_YRjJHdlSNyv508W`)Zb>9DZUKx#=CEn{F$J$M z-}}@lGsB+U`;+bcQ1I2OSFIvUg;8#$Q!pdVqLr82TCBL(bxN~nOT#sV2ex>~SQEj7 zw|eyR`GHX972BD(YV~?|Nxt!R&oFBAxKMQp_Levb$ju@M zfIOx>&OloPJuJfXfq~76zhoXNcTD7VQ(%hivX=1xh`md&0w)NzErS+3gerT#)89Q= z*ulh*lOzO0Legxy&j7ZA%OSTLZs;kEPBzxWnsqjIj%n;gBe|JTNyT}m&P0b z%$ly8 zO=@CDQ_mGJ&2>rRnozh{B5V;*`5X@ZBrlA`mUIy3{`mg81+ae4LF<~j%h>To^U$rb z)S|ZC1TdXRc&rX2cT(7Ny1fCzRkRBE`KfS1Pyxa znvD)@-b{jwZ{ED=iWa2+)u{21Ir4FOP@I(4w0Bl1r^+}~+9|0mSt~eekz{>7A1@^r zy1=Rn@O|%3DJ`45cDHwnm*uiLD07^&f17_<1vZ~L<`Nr`k=?0so zOZu8yUT-=dZDEsJYWRDN04trQ+xYy3AU74@c$0S;$hb;Ryip(xbi6l8`Pl+k`Qd7+ zxnpOAC%Mx|bKd;LVd28XZV^bqau$t}#osyVS{a}K3($HD*ibM-86GjH@rLP^QfSua zi@%>}&#KX-V-`nfe12mpPE)m0b_ohD6s*^M#1#n&#(YJoP^*o2)1E&!F+<`3>>1A+ znHvme&z8wSQB#W0#D95!Z``=yESYw1fQ&yHp!bt=YQvG=l%Cr!m408JlcVL1!zITVa)Ee#E`7c9ruQt_A3Kh;sNGVDevjss zd4_W`@1y~fLX2GwunZbnlllw0Mte>atVHZO!0{6+LgyFSZLT>{F2F+3fDF4vCX13` z8l=P<~rzn@B z27vQrP&4OYQ|5Q{rC3v;9rG=EEhn2?qhxWVhF;h4&UQ;&ij7Bu^T~0>REoyw(}ko%-A#M!2xk-c1Xk>jhJ~w)NvdHV$ukm23 zOFX#e2E*R3s;UYnEW?r`HgutJ=Nfp&?hL;cpTTQpwYeDa=W!hA_59K1PNu1U&YsJX zk)jK+!Bqhl>ZO$|tQonx&#Kb{E`?9|a}1+DcXZql%*i7ZYpSr}=%5TggEIG&qGwRz zo+EZMm0$6E0X8eG&^TZv^BDxn$%a79XCPDX#vH&LGd9Hg%in{22Pw9^e#rC}HfHl&-|Mg2bsG=+%?Fc#>yf!2 z9Ld0MzT1e5NEg7ORKb=PE?Q!gyUM<&()%L;>CM}Bbg7a6%LBqmG`fJz03@aN09Hc) z1AKlsD^KKgJXmE6z}-`Ez~u->egNK>{rizGNBl7pQ*2<^$M5kx{hHqA_2fH}&mh0z z&+JVAD^=``c7WwdAURP5uXpZ0#=I) z?RGbWk>hxD8uyOlK5Q}DsMuo*)dqk9EdFH%REw92$QiPB)#|l2U;Eu%s+|k8kyRtg zvH%vy04sMFpreATO9+5&unk!2tYYfMjhnqA31E{dk{|XOuQRsg#^x>C{KqCg+Q7{H z5d5kBxD@~{1#-L?_^ue>cmc$VBYvC(K9La`>-TFb}uGlN7%G+ zdot|x4I9ypH#(qb$AAm>iOO~%IITkNl+vxp5 zuNAuv=jwdYcH+Tj^nS5p`ZEomueF|m>zy+JZsLg8=7|LS?ycLmnV3rkZFV#OJ3owK zQKaB-5J0k_z0S)H3rHj`z;gW1|EEXcEd#uv2TPd#|GWLjUQ^TVEdT%j07*qoM6N<$ Ef|!^34gdfE literal 0 HcmV?d00001 diff --git a/WiiUseJ_0.1/libWiiuseJ.dll b/WiiUseJ_0.1/libWiiuseJ.dll new file mode 100644 index 0000000000000000000000000000000000000000..d06e041082d970078e1f9eb77cc10be3ba72dc14 GIT binary patch literal 25448 zcmeHP4Rl;poxe#38u~$ol4{TbQw^9(8)lM8(n8Wqnhb3*g_sXuq4+XQCe6TPW}J_< zU~xy2xSbul21HL~Q4(N}pePj)LghecUE1uT#@e%%ZCxV^YifGdh_x22WPksA-<|i~ zyv$_U-Sv2Oy(f3xyTALt|F8S`-n%!OZXaax7-JU1nHk1LaHZhlzuAA{$iDc>eHXK5 zFZ%xSk-VnwFK_GdMQovPaBJApYwPp`0>P+li`N#81#G^6t?}koTW_$-Tef)df)bT= zvzxJ|y!mXf_{e%z#@KK37@J@hesE!4{%TePq7NhHGuC0nm7*Py#Y6laIO&Zd{7N}& zP$a&3c^ z(S;6}UDoA^dVtvprytnNiYcK57h|JkVL>=Vx&q*I@55CWT*xWg5{VErO+U@_V-9iR z=N0_8k2*lJ2yq#rF1U!FPtb86hLA}%l*D%({lQMvmvMk($4W$9a51({m;B4^ zpTGm{iMLw&PFj*nS#vxza5!3*yxfYr#Od8Heu%{PODZ#=Vy@U&>;}iN#L?Z}Gk1LK z&i#uR#KfW9E@{im4n2lsvN@kYYKOPUgZ~@t3C#VU&TB>Fy+Da@lOPwHa93B{rS>chy zxbVp!)km_D6OxxN=Y^Mn-)faS@oMykj$>1m`(QjHPQyf!EZT!woLO2!Qfc^rz*J5H z&vGH_`pb#)ePxcrrw`1FzBqvD*zt+JiL;5~qPF~d8_fCE^*!Rx7*gx!xgUi%c zNFP+xAtW5fCfC6gXlW{&(%sKq4V*bfxp$XxMHW5OkXQswG;uqBMh3nuP3#`rXG5VA zE>z;~hIv!*eJ)BmC@J{CpM56_lAEka!Lsph&vKVG!h$h095tW2lUq-2;1nA;MFCS8 zrP>4ch{{x_t7J^N5@RVJ2IWAkYj1P#Z#ozLDdODuH=hgt6tTviTN}TxD6jCj_GN|7 zZL(c9`n&PI32XemViuj(cgWU%m@cmVvFHVh{8X%jel9&@43?VnE7)@ zN~h1#pHfA1{kb@~saRAg_r1AU__>@S);*Z1|A$mfkbf&pNIR4F6&!R=!@7w=()QlP@q=JT&qi{3NT%D0pHKABv#E7yF?V=FEZ7 z#4FL4g@kI1(#d>u3KQ`u5T7W9I5GZjI=S!t;QG>siS>L;x5TzUnm0(S6Yk@jdttwV zfm8Idr1MLK&)u-H@VW8R`>ng&Q&IGxY1f{Fd;0W#TXX>ueWUpz=~9yxO2+S-Vuic@ z28}X#LuvB8uS{OhH<1TpoL~s#mC5-cZRcs{k0wQOrOciu(xp7zhJqy`CmEZ5WwJnI z+F-@9q~%MmyX-&RTv8;9=8Ie_rBQ_!CS%9BndHeROok^PAm@ncYB&*i7sj@qd}%d2 z^MXrr4|$&^0nl^z2+zM-*k4Zt#57Wvv^-S!eEef@GjuE#sSc4U5~g5Mcbx!ElGGUSV9#>EwzA}=83z=KbuaD41(*vM~HPbuMAy(&~-Ibcr&rqDm)o4 z6&9@K=ByM6az-*$G3HO_7UyuA@X6B%Kf}V9nmv@{_7JVr( zoi`pIIRcQy7WchcG_z^qp2-tE@EjV@TSWU_2waw!o@e<|;mh$ifFNBg(-R_H#M8<6 zagnr&jn4u@Xk6feud_MowNgAn=wWRyNOte6qbPpVK z@2N)^oN4JKRZP0r1 z1n#L-6!w3PI=iLBG4>K=@X0J%QZRXjh#M?}%hAYSv_cMuBTcW`}T#TIL(q%l~IUGlRqIGq0X+PaG z)C>>eda$8U6mTUPHYAspfOgo1pG0djuku7gQ{w3IL;QKT#FjT^so&NA;SDHq<2}FN zK2HqvAjQ3$81U0Axi&EnqFeH3VjxPl+?NA8=$5;4U?<%QkH%Gx_G=#9wR?c1@b-5q zM1Gw{AH(Z{b$BQ~9J?a1tYnhja-|%PT=;(SS`2H61BuJ2ne1+`JT}Cy1&@u=Rjktv zB&H_|K(^*+;_cYCroJ_KH~63*$uM)(B0eqv zmX@XtI5?>3Lk&%zCI@M0dR{uQ{Z}(HszGq$%rqJnm8W~j=P%d)A0DvM43idQJ4nB# zk^Lq4f4~EtuC7L3q%#-@csrxMV8Ff28;G*fjVo?p$ZCyxqOpj?Zoi@R_KmkAAhUF1 zYild6p|CgP343q#`8EZkUX}8Ojkn(*f*=AXj8sqdquet>46npp=fy3+KBI7udTM$M%Q3>DQFb;2BmdFeT%zs1+gtF zyB2?2J3CiZlsU^P>F!#1u-muwT3^NLs%yb-mEgAu49oD4% z;C7`gf{xf5uZYQ9q~fcP!-~4!~w)_BK|94UKi*QZ$CCatbkp_7O;i* zqOq7=%nI>I@e;O#UCN5!%=fVO;*;TJ?0xM0_=I;kyMkTGY-~CE0Q(>-VOO!M*@y7S zZUsKIUV~3^tMD22T6}7BFu!jLx>S3_dt+Ib-_LIJZ1X7FeZE-4dzT_I>O(%ogK=Y< zC+cko2BN+|EEtRAPU&)#&qchkr7i5~yc?rN?vy#OHH=4daW)X=z`P~ayT$LFi>si@ zfn95FFc|I0!2>D6EKEE7!3forI^JheGL0+?!!B>`EnqgO z8g~PEP6D#G295Ka?Li|=RrK8Yrbx5t8q^v@#@^edC(6QXt2Zi^4ViRH5oBQ!_O{*= z=*+}Hv>GikuguRiTpuZ~AL{X>Jeo6McBW0j>bHG)i>Tq&>y4Kauy>plyH^XGZyNJ zMZ1FA1DLXNAaP}GZy|4|&*N_nW?m6QG!nA=FX7MF13kK@|B(px!Xd4HBS7!b7JZzt z$8~fUhOre5*tvwApx=e~Ao0?beG2z4A|66Kf_NNp5^);wEFy&>$SXl~B5pw3j2J@P zh4?VyUc}cBPa+mT-(`qS#AZZ4Vn5;@L>c~Ebjf4&U0w84SPvW64ZeVy_^IJ(k+EOp zxB9)_5Z3C7f`xc6;N9Vi!k8daJdubuO!s@3;thubL9%gazGq7is6D^C+aHVIX@ar3 z{BDfqjD_=iJz#;S8^-R<@AdX#hQSjsU)A$fKJW|GwBieJITo4jhKk6~lW9Ek(lU~G zT`Do~Q~WfeF+7b3zDiiEhlwsk_a2!?^g%u;D$&#mfZ-`fl|lItzNl6_G^3;R0-1*e1FbwL6iSTfyZxT6Y8zUt z$2~OKMU^m3lPGhEKF=3cLcxfSkLAc)l9sm(vPjNlDV)D16wDaGbzj7|DEUvt^a($&zxxMmpm0zuVx$-BK zzpi|@a(Pu*)kmv7R@Gm1f7N%YUadM-HCa_ueP#8^>ZU*j`S^Ze`k?Pm0Evw&J z{hQTiR)1j4$Jcy*&7L*;*Cej{yX)S(?!pxlZK+QunkJfyx=9!v( zHT!G+spfFazt+4_^UIpIYkpsoU%Q}oN$vY;t7{u;Z?5gB?W^5g`<2=!Yxmdwr1p*4 z-`BFWOV-w}y?1T@+C6I@UHgNz|FL#v?b5ny>aMF>S9fDwOWo!=U)|U1p09hc?oi!N z>L%(Y>waGcKiaT|ncQhFuwP=o%)Szyyxs1#hwPuQf5v{l{bBp#_HWu>vA<#et^JSo z3moO}ZHr@zBkcIJ;{nH`j%OVE;omnLmU7}Dw%YQ&zQpr?Ih1w#@T5v@ow0ZE_J3<0 zMi{gdhj?w3l5SD&@?h*dw3pceni3C0JCEO8fnP#3+UwX zqaOJosUazq7NpLChV;1z6h^{x(b`a*)egg9+L-UMPp6VPZbhMZ;tavhMk0ipdOdkx4QAQJ{; z42TsbXq?XiaT$;+q068F*#umf!LuQ)aE4_`z4Sf_*z4L17r}}xw#d* z)a-m{_l;JH_>`FV?8$-8Y7-x)iO*0Dd}yDLQJ)PaK2PMp$7SNP*~DjW4t!{?H|i5I z@fpd15A9_#^4VqLGnxY*+TUd4^RS7}p&a-$oA~TC@fpv7Pn(I)YbHKNbKrBEiO)$B zpNSm!(5^zGe+tlPG=%!aWDa~fOnjD^_)O=(hqm!)(y4zrO?=Mez=y_qBOjU_G=%KJ zr;IuKyWhmeZ{kys10R~HHR)tmzlo1E2R=~~pFJi%#VI~=?!F(!rdD6Q9$&z?++goO z9~&=)RTCtn2RY6Q8X9|11!>`2#(5XYQU%Pqj#5{Qk04*@jPIYb=zIZYyc8c6Dx+0| z2 zXEjE$zMcdmY!5}ev992%Fr9AGDs44%o{$0u1A9d-Z~b?Pz_ASKsY6SyZ&%*%Tkzs4Z-v0pNGo!U{9 z+m)q_4S`1JW0XTFlPo4JO>t(@t|8Eix)5haOR5jS1TpriNaZ5vVL+U5lrkVyPiZvj zSz4F0^qiz0HA!ElaptF6OPtgajM9&5G^+IG^O8>Mego%9o5op{{-8H~% z<0k1v8fR7dE|c^_8jUJFbY9XYOwvm<&Z_i1Ch5}}jVe8UUeaGPNw;d8Rq6dE=`U(D zs`SD0l77S_y;$R{O8=}$`Voyrl|FP{(%&>mFV#4!(jPWSKdaHGYk*6Eh&iR(bGH`- zbfG7Jy-rBS5k(8{j`qX?cjNt*#z(bcue1U=>A^IT%toWmgF`5saf}jnmD8Ieu1_A_ z!4bM3$DabJVIFZa29?IS6R_Yj3ytcZTJXu_A30|J32k={Wz$*sr*h@owpUNe_LFB^ zXOX8&cAe8`{H)~6WL?lQ%`iebqtXgVQ}wt;qqe9~*`m%#I=y`|$f`V>F3TB8N2(q) zNgqEi=}(!YpGlYH^rs_LyG+t2&P)0eCh4crWjX0nlEFV!J2mNQo8JT^Q=6A#g2qRV z2|8J74Ngldz%M=gPmc-2U-ae7W5RTbW|sc0j+tHAXjK2)k;Ol<@B9gEckalhvpObN zWG!bN535IH`^m$DPg;=AO@Wl{v%gor4wWEm#|nS8dN;L=%=Zrn&LMUTEoR6o|RNAGVnVGX0L2=du zmf}6Ou$HlHK!(5v)xqt@9#tUn9T9m1U*Lhrw}k@vHV_Jw63Biai&We3rAB-{X3e}; z+Ekh!5g$A$kyk{icY#PN1airI`5s%+)B_np3G%0)*$l*mq{e3_5b;ex(hLESL6mwL zhwo z5Dl~OmLOSPF7eU$+*wy}>Ajln-YAo6KK@YxPz)KJUAR7wqk z=G#EzyLW+%0g-PM1@Z=v8iN(@01;n&q*qJme>)jCI|)g(Rlbu#Q8+j5Q8_yfM_05)QuNIhF13r(1>q0lFvdcuSyNF zt_C8$_(+-!K;&2_^l1mO7p1iN>IQ=C2dWi{x-G&q(2HoJ_`$)y+DQxeEuECI5IWP3-K<>INH$LG6p)0W;KvK1`XXn z?th$E|3v}hCcu@VerrIfKUh1>cUDJ7}Oy6d;kc|ff|h+$PR-Q8-OfJA&S^G#Rd&J z-vSz|VbuBzkWp~f`q!gCY=+i521Ev-&%XefFwj^qLfBH$iP{RJ23O6`D}aDRXGJ{_ z3YuLlK;-&a$fEylwZXvoUbU3Q`Ex)z3^ZR=X*A9UOvo`p45fYvM1JWL(ti(RocmC= zjrmC3mMW#F+t%U+KVOYhSBi!#bOUi2klTU84L%$IGKvT?wXJ>;sUak(?u9-hK;-IF zAU^;S2aPDD@a=Uj=U&dorj|N|lojsMIA4JgO9s5}MG9Xduw6#sdsviiUpNw#J6aTM z($f-+e*Y$XwPx9ex(3X)lN;b);X9%P^```L&M2NbdqYiB4jv6BuZ?6P9nH9-Xp1n81K=2ImpY(r^#`|j{7M&pdKP1x3W*15MG1N7 zm@IY$V%Z?`Ark18Jv$?oQ=y?>%MZJP{WDxYrlJme6ee;HRZBHg9eABKA=~uQb(Iy~2D~wb2HuU7TH2 z6dZdMyQLKm45N=2Dq(7ezRM{gv0_Ahq5~+wZgOqs-3s0c_44Adv>#!t~8$v6D#0m@hKQASfITf24N)W|KAUhMIDLMA7wFKRMY zz3IrGv^bSGizg!5R|KOUwI__&TLZl~HOT#*bwtS^UN@6K%*IX4 zH@CDYjqcWlmW|Ccs0gQK?8&Lw3WfQgBwM9%Oh9gfeu(02N+s1*8xC6V!xYlrozmZi zQHmd5(MVFmpvp)c6N~~gSg$!>TYPeFV@zDH`&SQqjx;Di&B$~%MQv&PX+k~TV{UvY zBXx!wPO-=inBJK)*kE3RNegrW^ha0}JmUDhX>CW}qjYC_q%QmjQIvO#YJn>5s4ET5^oUwwUL@G7dnu#|?ahEZBSd5N(ON2^ln3vD7(*k7xr-qhaIq_k~l zzv&}NV|`n_tR?lG!4GIA9o7ff;O)4PQKw5(`==WFMhrnRMyA`SWihioz{3 zjfCJYT8FQfhGPAU?hkspykT*)j1R<|n_*hlcQ1J~P8;a&_J#vqKP`}@8)s=xVouSj zLa%|yGi%1hs;@;-Gkr?_EDIr>T;rHz8vL?MvFbU&Ol?5cfquv}54M>nGr7#b0#9?C bT;gSDD~7i%83zPoFQL=&a+-;%?drb(*%kiw literal 0 HcmV?d00001 diff --git a/WiiUseJ_0.1/src/img/wiimote.png b/WiiUseJ_0.1/src/img/wiimote.png new file mode 100644 index 0000000000000000000000000000000000000000..3f26f5202b22a89c5fa3e1c1eb524f78e4e76e81 GIT binary patch literal 44340 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 z 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 Ef|!^34gdfE literal 0 HcmV?d00001 diff --git a/WiiUseJ_0.1/src/wiiusej/WiiUseApi.java b/WiiUseJ_0.1/src/wiiusej/WiiUseApi.java new file mode 100644 index 0000000..f9be625 --- /dev/null +++ b/WiiUseJ_0.1/src/wiiusej/WiiUseApi.java @@ -0,0 +1,211 @@ +/** + * This file is part of WiiuseJ. + * + * WiiuseJ is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * WiiuseJ is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with WiiuseJ. If not, see . + */ +package wiiusej; + +import wiiusej.wiiuseapievents.EventsGatherer; + +/** + * Singleton used to manipulate WiiUse Api. + * @author guiguito + */ +public class WiiUseApi { + + static { + System.loadLibrary("libWiiuseJ"); + } + + private static WiiUseApi instance = new WiiUseApi(); + + /** + * Get the only instance of WiiUseApi. + * @return the only instace of WiiUseApi. + */ + static WiiUseApi getInstance(){ + return instance; + } + + /** + * Try to connect to 2 wiimotes. Make them rumble to show they are + * connected. + * @param nb number of wiimotes to connect + * @return 0 if there is an error otherwise it returns the number of + * wiimotes connected. + */ + native int doConnections(int nb); + + /** + * Close connection to the wiimote with the given id. + * + */ + native void closeConnection(int id); + + /** + * Shutdown Wiiuse API. + */ + native void shutdownApi(); + + /** + * Activate rumble on the wiimote with the given id. + * @param id the id of the wiimote. + */ + native void activateRumble(int id); + + /** + * Deactivate rumble on the wiimote with the given id. + * + * @param id the id of the wiimote. + */ + native void deactivateRumble(int id); + + /** + * Activate IR Tracking on the wiimote with the given id. + * @param id the id of the wiimote. + */ + native void activateIRTracking(int id); + + /** + * Deactivate IR Tracking on the wiimote with the given id. + * @param id the id of the wiimote. + */ + native void deactivateIRTracking(int id); + + /** + * Activate motion sensing on the wiimote with the given id. + * @param id the id of the wiimote. + */ + native void activateMotionSensing(int id); + + /** + * Deactivate motion sensing on the wiimote with the given id. + * @param id the id of the wiimote. + */ + native void deactivateMotionSensing(int id); + + /** + * Set wiimote leds status. + * @param id the id of the wiimote concerned + * @param led1 status of led1: True=ON, False=OFF + * @param led2 status of led2: True=ON, False=OFF + * @param led3 status of led3: True=ON, False=OFF + * @param led4 status of led4: True=ON, False=OFF + */ + native void setLeds(int id, boolean led1, boolean led2, boolean led3, boolean led4); + + /** + * Set how many degrees an angle must change to generate an event. + * @param id id of the wiimote concerned + * @param angle minimum angle detected by an event + */ + native void setOrientThreshold(int id, float angle); + + /** + * Set how much acceleration must change to generate an event. + * @param id id of the wiimote concerned + * @param value minimum value detected by an event + */ + native void setAccelThreshold(int id, int value); + + /** + * Set alpha smoothing parameter for the given id. + * @param id id of the wiimote concerned + * @param value alpha smoothing value + */ + native void setAlphaSmoothing(int id, float value); + + /** + * Try to resync with the wiimote by starting a new handshake. + * @param id id of the wiimote concerned + */ + native void reSync(int id); + + /** + * Make the the accelerometers give smoother results. + * This is set by default. + * @param id the id of the wiimote concerned + */ + native void activateSmoothing(int id); + + /** + * Make the the accelerometers give raw results. + * @param id the id of the wiimote concerned + */ + native void deactivateSmoothing(int id); + + /** + * Make the wiimote generate an event each time we poll. + * Not set by default. + * @param id the id of the wiimote concerned + */ + native void activateContinuous(int id); + + /** + * Make the wiimote generate an event only when there is one. + * @param id the id of the wiimote concerned + */ + native void deactivateContinuous(int id); + + /** + * Notify wiiuse that your screen has an aspect ratio of 4/3. + * @param id the id of the wiimote of which we want the status. + */ + native void setScreenRatio43(int id); + + /** + * Notify wiiuse that your screen has an aspect ratio of 16/9. + * @param id the id of the wiimote of which we want the status. + */ + native void setScreenRatio169(int id); + + /** + * Notify wiiuse that the sensor bar is above your screen. + * @param id the id of the wiimote of which we want the status. + */ + native void setSensorBarAboveScreen(int id); + + /** + * Notify wiiuse that the sensor bar is below your screen. + * @param id the id of the wiimote of which we want the status. + */ + native void setSensorBarBelowScreen(int id); + + /** + * Set virtual screen resolution. It is used to automatically + * compute the position of a cursor on this virtual screen + * using the sensor bar. These results come in the IREvent. + * @param id the id of the wiimote of which we want the status. + * @param x x resolution. + * @param y y resolution. + */ + native void setVirtualScreenResolution(int id, int x, int y); + + /** + * Get status and values from the wiimotes and send it through callbacks. + * + * @param id the id of the wiimote of which we want the status. + */ + native void getStatus(int id); + + /** + * Check for new Events and Get it. + * + * @param gath the object where we store all the new events. + */ + native void specialPoll(EventsGatherer gath); + + + +} diff --git a/WiiUseJ_0.1/src/wiiusej/WiiUseApiManager.java b/WiiUseJ_0.1/src/wiiusej/WiiUseApiManager.java new file mode 100644 index 0000000..647fbd8 --- /dev/null +++ b/WiiUseJ_0.1/src/wiiusej/WiiUseApiManager.java @@ -0,0 +1,567 @@ +/** + * This file is part of WiiuseJ. + * + * WiiuseJ is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * WiiuseJ is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with WiiuseJ. If not, see . + */ +package wiiusej; + +import java.util.concurrent.ConcurrentLinkedQueue; +import java.util.concurrent.atomic.AtomicBoolean; + +import javax.swing.event.EventListenerList; + +import wiiusej.wiiuseapievents.EventsGatherer; +import wiiusej.wiiuseapievents.WiiUseApiEvent; +import wiiusej.wiiuseapievents.WiiUseApiListener; +import wiiusej.wiiuseapirequest.FloatValueRequest; +import wiiusej.wiiuseapirequest.IntValueRequest; +import wiiusej.wiiuseapirequest.LedsRequest; +import wiiusej.wiiuseapirequest.TwoIntValueRequest; +import wiiusej.wiiuseapirequest.WiiUseApiRequest; + +/** + * Class that manages the use of Wiiuse API. + * + * @author guiguito + */ +public class WiiUseApiManager extends Thread { + + private static WiiUseApiManager instance = new WiiUseApiManager(); + + private final EventListenerList listeners = new EventListenerList(); + + private Wiimote[] wiimotes; + + private WiiUseApi wiiuse = WiiUseApi.getInstance(); + + private int connected = -1; + + private int nbMaxWiimotes = -1; + + private AtomicBoolean running = new AtomicBoolean(false); + + private ConcurrentLinkedQueue requests = new ConcurrentLinkedQueue(); + + public static WiiUseApiManager getInstance() { + return instance; + } + + /** + * Get wiimotes. Load library if necessary. Connect to wiimotes if + * necessary. Start polling if necessary. Return an array with the connected + * wiimotes. + * + * @param nb + * try to connect nb wiimotes + * @return an array with connected wiimotes or NULL. + */ + public synchronized static Wiimote[] getWiimotes(int nb) { + WiiUseApiManager manager = getInstance(); + if (manager.connected < 0) { + int nbWiimotes = manager.connectWiimotes(nb); + manager.wiimotes = new Wiimote[nbWiimotes]; + for (int i = 1; i <= nbWiimotes; i++) { + Wiimote wim = new Wiimote(i, manager); + manager.wiimotes[i - 1] = wim; + manager.addWiiUseApiListener(wim); + } + } + + if (manager.connected == 0) { + return new Wiimote[0]; + } + + if (!manager.isAlive()) + manager.start(); + + return manager.wiimotes; + } + + /** + * Connect wiimote and get the number of wiimotes connected. Supposed to be + * used once. + * + * @param nb + * try to connect nb wiimotes + * @return 0 if nothing connected or the number of wiimotes connected. + */ + private int connectWiimotes(int nb) { + nbMaxWiimotes = nb; + if (connected < 0) { + connected = wiiuse.doConnections(nb); + return connected; + } else {// library not loaded, no wiimotes connected + return 0; + } + } + + /** + * Ask the thread to close a connection. + * + * @param id + * id of the wiimote to disconnect. + */ + public void closeConnection(int id) { + removeWiiUseApiListener(wiimotes[id - 1]); + wiimotes[id - 1] = null; + requests.add(new WiiUseApiRequest(id, + WiiUseApiRequest.WIIUSE_CLOSE_CONNECTION_REQUEST)); + // System.out.println("Wiimote " + id + " disconnected !"); + } + + /** + * Get the number of wiimotes connected. + * + * @return the number of wiimotes connected. + */ + public int getNbConnectedWiimotes() { + return connected; + } + + /** + * Stop thread and shutdown wiiuse Api. + */ + public void shutdown() { + if (connected > 0) { + for (Wiimote wim : wiimotes) { + if (wim != null) + wim.disconnect(); + } + } + running.set(false); + wiiuse.shutdownApi(); + } + + /** + * Activate the rumble for the wiimote with the given id. + * + * @param id + * id of the wiimote. + */ + public void activateRumble(int id) { + requests.add(new WiiUseApiRequest(id, + WiiUseApiRequest.WIIUSE_ACTIVATE_RUMBLE_REQUEST)); + } + + /** + * Deactivate the rumble for the wiimote with the given id. + * + * @param id + * id of the wiimote. + */ + public void deactivateRumble(int id) { + requests.add(new WiiUseApiRequest(id, + WiiUseApiRequest.WIIUSE_DEACTIVATE_RUMBLE_REQUEST)); + } + + /** + * Activate IR Tracking for the wiimote with the given id. + * + * @param id + * id of the wiimote. + */ + public void activateIRTRacking(int id) { + requests.add(new WiiUseApiRequest(id, + WiiUseApiRequest.WIIUSE_ACTIVATE_IR_TRACKING_REQUEST)); + } + + /** + * Deactivate IR Tracking for the wiimote with the given id. + * + * @param id + * id of the wiimote. + */ + public void deactivateIRTRacking(int id) { + requests.add(new WiiUseApiRequest(id, + WiiUseApiRequest.WIIUSE_DEACTIVATE_IR_TRACKING_REQUEST)); + } + + /** + * Activate motion sensing for the wiimote with the given id. + * + * @param id + * id of the wiimote. + */ + public void activateMotionSensing(int id) { + requests.add(new WiiUseApiRequest(id, + WiiUseApiRequest.WIIUSE_ACTIVATE_MOTION_SENSING_REQUEST)); + } + + /** + * Deactivate motion sensing for the wiimoter with the given id. + * + * @param id + * id of the wiimote. + */ + public void deactivateMotionSensing(int id) { + requests.add(new WiiUseApiRequest(id, + WiiUseApiRequest.WIIUSE_DEACTIVATE_MOTION_SENSING_REQUEST)); + } + + /** + * Activate smoothing the wiimotes with the given id. + * + * @param id + * id of the wiimote. + */ + public void activateSmoothing(int id) { + requests.add(new WiiUseApiRequest(id, + WiiUseApiRequest.WIIUSE_ACTIVATE_SMOOTHING_REQUEST)); + } + + /** + * Deactivate smoothing the wiimotes with the given id. + * + * @param id + * id of the wiimote. + */ + public void deactivateSmoothing(int id) { + requests.add(new WiiUseApiRequest(id, + WiiUseApiRequest.WIIUSE_DEACTIVATE_SMOOTHING_REQUEST)); + } + + /** + * Activate continuous for the wiimotes with the given id. + * + * @param id + * id of the wiimote. + */ + public void activateContinuous(int id) { + requests.add(new WiiUseApiRequest(id, + WiiUseApiRequest.WIIUSE_ACTIVATE_CONTINUOUS_REQUEST)); + } + + /** + * Deactivate continuous for the wiimotes with the given id. + * + * @param id + * id of the wiimote + */ + public void deactivateContinuous(int id) { + requests.add(new WiiUseApiRequest(id, + WiiUseApiRequest.WIIUSE_DEACTIVATE_CONTINUOUS_REQUEST)); + } + + /** + * Set leds for the wiimotes with the given id. + * + * @param id + * id of the wiimote + * @param l1 + * status of led1. True : ON, False : OFF + * @param l2 + * status of led2. True : ON, False : OFF + * @param l3 + * status of led3. True : ON, False : OFF + * @param l4 + * status of led4. True : ON, False : OFF + */ + public void setLeds(int id, boolean l1, boolean l2, boolean l3, boolean l4) { + requests.add(new LedsRequest(id, WiiUseApiRequest.WIIUSE_LEDS_REQUEST, + l1, l2, l3, l4)); + } + + /** + * Set the orientation threshold for the given id. + * + * @param id + * id of the wiimote + * @param th + * threshold in degrees + */ + public void setOrientationThreshold(int id, float th) { + requests.add(new FloatValueRequest(id, + WiiUseApiRequest.WIIUSE_ORIENT_THRESHOLHD_REQUEST, th)); + } + + /** + * Set the acceleration threshold for the given id. + * + * @param id + * id of the wiimote + * @param th + * threshold + */ + public void setAccelerationThreshold(int id, int th) { + requests.add(new IntValueRequest(id, + WiiUseApiRequest.WIIUSE_ACCEL_THRESHOLHD_REQUEST, th)); + } + + /** + * Set alpha smoothing for the given id. + * + * @param id + * id of the wiimote + * @param th + * threshold + */ + public void setAlphaSmoothing(int id, float th) { + requests.add(new FloatValueRequest(id, + WiiUseApiRequest.WIIUSE_ALPHA_SMOOTHING_REQUEST, th)); + } + + /** + * Try to resync with the wiimote by starting a new handshake. + * + * @param id + * id of the wiimote + */ + public void reSync(int id) { + requests.add(new WiiUseApiRequest(id, WiiUseApiRequest.WIIUSE_RESYNC)); + } + + /** + * Set screen aspect ratio to 4/3 for the given id. + * + * @param id + * id of the wiimote + */ + public void setScreenAspectRatio43(int id) { + requests.add(new WiiUseApiRequest(id, + WiiUseApiRequest.WIIUSE_ASPECT_RATIO_4_3)); + } + + /** + * Set screen aspect ratio to 16/9 for the given id. + * + * @param id + * id of the wiimote + */ + public void setScreenAspectRatio169(int id) { + requests.add(new WiiUseApiRequest(id, + WiiUseApiRequest.WIIUSE_ASPECT_RATIO_16_9)); + } + + /** + * Set the sensor bar to be above the screen. + * + * @param id + * id of the wiimote + */ + public void setSensorBarAboveScreen(int id) { + requests.add(new WiiUseApiRequest(id, + WiiUseApiRequest.WIIUSE_SENSOR_BAR_ABOVE)); + } + + /** + * Set the sensor bar to be below the screen. + * + * @param id + * id of the wiimote + */ + public void setSensorBarBelowScreen(int id) { + requests.add(new WiiUseApiRequest(id, + WiiUseApiRequest.WIIUSE_SENSOR_BAR_BELOW)); + } + + /** + * Set virtual resolution. It is used to automatically compute the position + * of a cursor on this virtual screen using the sensor bar. These results + * come in the IREvent. + * + * @param id + * id of the wiimote + * @param x + * x resolution + * @param y + * y resolution + */ + public void setVirtualResolution(int id, int x, int y) { + requests.add(new TwoIntValueRequest(id, + WiiUseApiRequest.WIIUSE_SET_VIRTUAL_RESOLUTION, x, y)); + } + + /** + * Get Status for the wiimote for the given id. + * + * @param id + * id of the wiimote + */ + public void getStatus(int id) { + requests.add(new WiiUseApiRequest(id, + WiiUseApiRequest.WIIUSE_STATUS_REQUEST)); + } + + @Override + public void run() { + + if (connected > 0) { + running.set(true); + + EventsGatherer gather = new EventsGatherer(nbMaxWiimotes); + + // Start polling and tell the observers when there Wiimote events + while (running.get() && connected > 0) { + + /* Polling */ + wiiuse.specialPoll(gather); + + /* deal with events gathered in Wiiuse API */ + for (WiiUseApiEvent evt : gather.getEvents()) { + if (evt.getWiimoteId() != -1) {// event filled + // there is an event notify observers + notifyWiiUseApiListener(evt); + if (evt.getEventType() == WiiUseApiEvent.DISCONNECTION_EVENT) { + // check if it was a disconnection + // in this case disconnect the wiimote + closeConnection(evt.getWiimoteId()); + } + } else { + System.out + .println("There is an event with id == -1 ??? there is a problem !!! : " + + evt); + } + } + gather.clearEvents(); + + /* deal with request done to wiiuse API */ + WiiUseApiRequest req = requests.poll(); + if (req != null) {// there is a request for the wiiuse api + int id = req.getId(); + if (req.getRequestType() == WiiUseApiRequest.WIIUSE_CLOSE_CONNECTION_REQUEST) { + /* Close connections requests */ + wiiuse.closeConnection(id); + + connected--; + if (connected == 0) {// stop this thread if there is + // no more wiimotes connected. + // System.out.println("No more wiimotes connected + // !!!"); + shutdown(); + } + } else if (req.getRequestType() == WiiUseApiRequest.WIIUSE_STATUS_REQUEST) { + /* Status requests */ + wiiuse.getStatus(id); + } else if (req.getRequestType() == WiiUseApiRequest.WIIUSE_ACTIVATE_RUMBLE_REQUEST) { + /* Activate Rumble requests */ + wiiuse.activateRumble(id); + } else if (req.getRequestType() == WiiUseApiRequest.WIIUSE_DEACTIVATE_RUMBLE_REQUEST) { + /* Deactivate Rumble requests */ + wiiuse.deactivateRumble(id); + } else if (req.getRequestType() == WiiUseApiRequest.WIIUSE_ACTIVATE_IR_TRACKING_REQUEST) { + /* Activate IR Tracking requests */ + wiiuse.activateIRTracking(id); + } else if (req.getRequestType() == WiiUseApiRequest.WIIUSE_DEACTIVATE_IR_TRACKING_REQUEST) { + /* Deactivate IR Tracking requests */ + wiiuse.deactivateIRTracking(id); + } else if (req.getRequestType() == WiiUseApiRequest.WIIUSE_ACTIVATE_MOTION_SENSING_REQUEST) { + /* Activate Motion sensing requests */ + wiiuse.activateMotionSensing(id); + } else if (req.getRequestType() == WiiUseApiRequest.WIIUSE_DEACTIVATE_MOTION_SENSING_REQUEST) { + /* Deactivate Motion sensing requests */ + wiiuse.deactivateMotionSensing(id); + } else if (req.getRequestType() == WiiUseApiRequest.WIIUSE_LEDS_REQUEST) { + /* leds requests */ + LedsRequest reqLed = (LedsRequest) req; + wiiuse.setLeds(id, reqLed.isLed1(), reqLed.isLed2(), + reqLed.isLed3(), reqLed.isLed4()); + } else if (req.getRequestType() == WiiUseApiRequest.WIIUSE_ACTIVATE_SMOOTHING_REQUEST) { + /* Activate smoothing requests */ + wiiuse.activateSmoothing(id); + } else if (req.getRequestType() == WiiUseApiRequest.WIIUSE_DEACTIVATE_SMOOTHING_REQUEST) { + /* Deactivate smoothing requests */ + wiiuse.deactivateSmoothing(id); + } else if (req.getRequestType() == WiiUseApiRequest.WIIUSE_ACTIVATE_CONTINUOUS_REQUEST) { + /* Activate continuous requests */ + wiiuse.activateContinuous(id); + } else if (req.getRequestType() == WiiUseApiRequest.WIIUSE_DEACTIVATE_CONTINUOUS_REQUEST) { + /* Deactivate continuous requests */ + wiiuse.deactivateContinuous(id); + } else if (req.getRequestType() == WiiUseApiRequest.WIIUSE_ORIENT_THRESHOLHD_REQUEST) { + /* set orientation threshold request */ + wiiuse.setOrientThreshold(req.getId(), + ((FloatValueRequest) req).getFloatValue()); + } else if (req.getRequestType() == WiiUseApiRequest.WIIUSE_ACCEL_THRESHOLHD_REQUEST) { + /* set acceleration threshold request */ + wiiuse.setAccelThreshold(req.getId(), + ((IntValueRequest) req).getIntValue()); + } else if (req.getRequestType() == WiiUseApiRequest.WIIUSE_ALPHA_SMOOTHING_REQUEST) { + /* set alpha smoothing request */ + wiiuse.setAlphaSmoothing(req.getId(), + ((FloatValueRequest) req).getFloatValue()); + } else if (req.getRequestType() == WiiUseApiRequest.WIIUSE_RESYNC) { + /* set resync request */ + wiiuse.reSync(req.getId()); + } else if (req.getRequestType() == WiiUseApiRequest.WIIUSE_ASPECT_RATIO_4_3) { + /* set screen aspect ratio to 4/3 */ + wiiuse.setScreenRatio43(req.getId()); + } else if (req.getRequestType() == WiiUseApiRequest.WIIUSE_ASPECT_RATIO_16_9) { + /* set screen aspect ratio to 16/9 */ + wiiuse.setScreenRatio169(req.getId()); + } else if (req.getRequestType() == WiiUseApiRequest.WIIUSE_SENSOR_BAR_ABOVE) { + /* set sensor bar above the screen */ + wiiuse.setSensorBarAboveScreen(req.getId()); + } else if (req.getRequestType() == WiiUseApiRequest.WIIUSE_SENSOR_BAR_BELOW) { + /* set sensor bar above the screen */ + wiiuse.setSensorBarBelowScreen(req.getId()); + } else if (req.getRequestType() == WiiUseApiRequest.WIIUSE_SET_VIRTUAL_RESOLUTION) { + /* set virtual resolution */ + wiiuse.setVirtualScreenResolution(req.getId(), + ((TwoIntValueRequest) req).getIntValue(), + ((TwoIntValueRequest) req).getSecondIntValue()); + } else { + System.out.println("Bad request to Wiiuse API !!!!!"); + } + } + } + } else { + if (connected <= 0) { + System.out.println("No wiimotes connected !"); + } + } + + } + + /** + * Add WiiUseApiListener to the listeners list. + * + * @param listener + * a WiiUseApiListener + */ + public void addWiiUseApiListener(WiiUseApiListener listener) { + listeners.add(WiiUseApiListener.class, listener); + } + + /** + * Remove WiiUseApiListener from the listeners list. + * + * @param listener + * a WiiUseApiListener + */ + public void removeWiiUseApiListener(WiiUseApiListener listener) { + listeners.remove(WiiUseApiListener.class, listener); + } + + /** + * Get the list of WiiUseApiListeners. + * + * @return the list of WiiUseApiListeners. + */ + public WiiUseApiListener[] getWiiUseApiListeners() { + return listeners.getListeners(WiiUseApiListener.class); + } + + /** + * Notify WiiUseApiListeners that an event occured. + * + * @param evt + * WiimoteEvent occured + */ + private void notifyWiiUseApiListener(WiiUseApiEvent evt) { + for (WiiUseApiListener listener : getWiiUseApiListeners()) { + listener.onWiiUseApiEvent(evt); + } + } + +} diff --git a/WiiUseJ_0.1/src/wiiusej/Wiimote.java b/WiiUseJ_0.1/src/wiiusej/Wiimote.java new file mode 100644 index 0000000..f04e66c --- /dev/null +++ b/WiiUseJ_0.1/src/wiiusej/Wiimote.java @@ -0,0 +1,323 @@ +/** + * This file is part of WiiuseJ. + * + * WiiuseJ is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * WiiuseJ is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with WiiuseJ. If not, see . + */ +package wiiusej; + +import javax.swing.event.EventListenerList; + +import wiiusej.wiiuseapievents.DisconnectionEvent; +import wiiusej.wiiuseapievents.StatusEvent; +import wiiusej.wiiuseapievents.GenericEvent; +import wiiusej.wiiuseapievents.WiiUseApiEvent; +import wiiusej.wiiuseapievents.WiiUseApiListener; +import wiiusej.wiiuseapievents.WiimoteListener; +import wiiusej.wiiuseapirequest.WiiUseApiRequest; + +/** + * Class that represents a wiimote. + * You can register as an observer of this wiimote to listen events from it. + * You manage it. + * @author guiguito + */ +public class Wiimote implements WiiUseApiListener { + + private int id = -1;//wiimote id + + private EventListenerList listeners = new EventListenerList(); + + private WiiUseApiManager manager; + + + /** + * Constructor. + * @param idd id of the wiimote + * @param manager manager wo built it. + */ + public Wiimote(int idd, WiiUseApiManager manager){ + id = idd; + this.manager = manager; + } + + /** + * Disconnect this wiimote. + */ + public void disconnect(){ + deactivateIRTRacking(); + deactivateMotionSensing(); + deactivateRumble(); + manager.closeConnection(id); + } + + /** + * Activate the rumble. + */ + public void activateRumble() { + manager.activateRumble(id); + } + + /** + * Deactivate the rumble. + */ + public void deactivateRumble() { + manager.deactivateRumble(id); + } + + /** + * Activate IR Tracking. + */ + public void activateIRTRacking() { + manager.activateIRTRacking(id); + } + + /** + * Deactivate IR Tracking. + */ + public void deactivateIRTRacking() { + manager.deactivateIRTRacking(id); + } + + /** + * Activate motion sensing. + */ + public void activateMotionSensing() { + manager.activateMotionSensing(id); + } + + /** + * Deactivate motion sensing. + */ + public void deactivateMotionSensing() { + manager.deactivateMotionSensing(id); + } + + /** + * Activate smoothing. + */ + public void activateSmoothing() { + manager.activateSmoothing(id); + } + + /** + * Deactivate smoothing. + */ + public void deactivateSmoothing() { + manager.deactivateSmoothing(id); + } + + /** + * Activate continuous. + */ + public void activateContinuous() { + manager.activateContinuous(id); + } + + /** + * Deactivate continuous. + */ + public void deactivateContinuous() { + manager.deactivateContinuous(id); + + } + + /** + * Set leds status. + * + * @param l1 + * status of led1. True : ON, False : OFF + * @param l2 + * status of led2. True : ON, False : OFF + * @param l3 + * status of led3. True : ON, False : OFF + * @param l4 + * status of led4. True : ON, False : OFF + */ + public void setLeds(boolean l1, boolean l2, boolean l3, boolean l4) { + manager.setLeds(id, l1, l2, l3, l4); + } + + /** + * Set the orientation threshold (minimum angle between two degrees with accelerometer). + * @param th + * threshold in degrees + */ + public void setOrientationThreshold(float th) { + manager.setOrientationThreshold(id,th); + } + + /** + * Set the acceleration threshold . + * @param th + * threshold + */ + public void setAccelerationThreshold(int th) { + manager.setAccelerationThreshold(id,th); + } + + /** + * Set the alpha smoothing value. + * @param th + * threshold + */ + public void setAlphaSmoothingValue(float th) { + manager.setAlphaSmoothing(id,th); + } + + /** + * Set the screen aspect ratio to be considered as 4/3. + */ + public void setScreenAspectRatio43() { + manager.setScreenAspectRatio43(id); + } + + /** + * Set the screen aspect ratio to be considered as 16/9. + */ + public void setScreenAspectRatio169() { + manager.setScreenAspectRatio169(id); + } + + /** + * Set the sensor bar to be considered above the screen. + */ + public void setSensorBarAboveScreen() { + manager.setSensorBarAboveScreen(id); + } + + /** + * Set the sensor bar to be considered below the screen. + */ + public void setSensorBarBelowScreen() { + manager.setSensorBarBelowScreen(id); + } + + /** + * Set the screen resolution of the you are pointing at + * with your wiimote. + * + * @param x x resolution. + * @param y y resolution. + */ + public void setVirtualResolution(int x, int y) { + manager.setVirtualResolution(id, x ,y); + } + + /** + * Try to resync the wiimote by starting a new handshake. + */ + public void reSync() { + manager.reSync(id); + } + + /** + * Ask for the status of the wiimote. + * The result will be received in a status event object. + * Implements onStatusEvent on wiimote listener to get it. + */ + public void getStatus() { + manager.getStatus(id); + } + + /** + * Method called when a WiiUseApiEvent occurs. + * @param e the WiiUseApiEvent. + */ + public void onWiiUseApiEvent(WiiUseApiEvent e) { + if (e.getWiimoteId() == id){ + if (e.getEventType() == WiiUseApiEvent.GENERIC_EVENT){ + notifyWiiMoteEventListeners((GenericEvent)e); + }else if (e.getEventType() == WiiUseApiEvent.STATUS_EVENT + ||e.getEventType() == WiiUseApiEvent.WIIUSE_NUNCHUK_INSERTED + ||e.getEventType() == WiiUseApiEvent.WIIUSE_NUNCHUK_REMOVED + ||e.getEventType() == WiiUseApiEvent.WIIUSE_CLASSIC_CTRL_INSERTED + ||e.getEventType() == WiiUseApiEvent.WIIUSE_CLASSIC_CTRL_REMOVED + ||e.getEventType() == WiiUseApiEvent.WIIUSE_GUITAR_HERO_3_CTRL_INSERTED + ||e.getEventType() == WiiUseApiEvent.WIIUSE_GUITAR_HERO_3_CTRL_REMOVED){ + notifyStatusEventListeners((StatusEvent)e); + }else if (e.getEventType() == WiiUseApiEvent.DISCONNECTION_EVENT){ + notifyDisconnectionEventListeners((DisconnectionEvent)e); + } + } + } + + /** + * Add a WiimoteListener to the listeners list. + * @param listener a WiimoteListener + */ + public void addWiiMoteEventListeners(WiimoteListener listener) { + listeners.add(WiimoteListener.class, listener); + } + + /** + * Remove a WiimoteListener from the listeners list. + * @param listener a WiimoteListener + */ + public void removeWiiMoteEventListeners(WiimoteListener listener) { + listeners.remove(WiimoteListener.class, listener); + } + + /** + * Get the list of WiimoteListener. + * @return the list of WiimoteListener. + */ + public WiimoteListener[] getWiiMoteEventListeners() { + return listeners.getListeners(WiimoteListener.class); + } + + /** + * Notify WiimoteListeners that an event occured. + * Notify in first the listeners for Buttons Events. + * In second the listeners for IR Events. + * In third the listeners for Motion sensing events. + * @param evt WiimoteEvent occured + */ + private void notifyWiiMoteEventListeners(GenericEvent evt) { + for (WiimoteListener listener : getWiiMoteEventListeners()) { + listener.onButtonsEvent(evt.getButtonsEvent()); + if (evt.isThereIrEvent()){ + listener.onIrEvent(evt.getIREvent()); + } + if (evt.isThereMotionSensingEvent()){ + listener.onMotionSensingEvent(evt.getMotionSensingEvent()); + } + } + } + + /** + * Notify WiimoteListener that a status event occured. + * @param evt status event occured + */ + private void notifyStatusEventListeners(StatusEvent evt) { + for (WiimoteListener listener : getWiiMoteEventListeners()) { + listener.onStatusEvent(evt); + } + } + + /** + * Notify WiimoteListener that a status event occured. + * @param evt status event occured + */ + private void notifyDisconnectionEventListeners(DisconnectionEvent evt) { + for (WiimoteListener listener : getWiiMoteEventListeners()) { + listener.onDisconnectionEvent(evt); + } + } + + @Override + public String toString() { + return "Wiimote with ID : "+id; + } + +} diff --git a/WiiUseJ_0.1/src/wiiusej/test/CloseGuiTestCleanly.java b/WiiUseJ_0.1/src/wiiusej/test/CloseGuiTestCleanly.java new file mode 100644 index 0000000..ae136bf --- /dev/null +++ b/WiiUseJ_0.1/src/wiiusej/test/CloseGuiTestCleanly.java @@ -0,0 +1,65 @@ +/** + * This file is part of WiiuseJ. + * + * WiiuseJ is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * WiiuseJ is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with WiiuseJ. If not, see . + */ +package wiiusej.test; + +import java.awt.event.WindowEvent; +import java.awt.event.WindowListener; +import wiiusej.WiiUseApiManager; +import wiiusej.Wiimote; + +/** + * This class is used to close wiiusej cleanly. + * @author guiguito + */ +public class CloseGuiTestCleanly implements WindowListener{ + + Wiimote wiimote; + + + public CloseGuiTestCleanly(Wiimote wim) { + wiimote = wim; + } + + public void windowOpened(WindowEvent e) { + //nothing + } + + public void windowClosing(WindowEvent e) { + WiiUseApiManager.getInstance().shutdown(); + } + + public void windowClosed(WindowEvent e) { + //nothing + } + + public void windowIconified(WindowEvent e) { + //nothing + } + + public void windowDeiconified(WindowEvent e) { + //nothing + } + + public void windowActivated(WindowEvent e) { + //nothing + } + + public void windowDeactivated(WindowEvent e) { + //nothing + } + +} diff --git a/WiiUseJ_0.1/src/wiiusej/test/Main.java b/WiiUseJ_0.1/src/wiiusej/test/Main.java new file mode 100644 index 0000000..0f873bb --- /dev/null +++ b/WiiUseJ_0.1/src/wiiusej/test/Main.java @@ -0,0 +1,40 @@ +/** + * This file is part of WiiuseJ. + * + * WiiuseJ is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * WiiuseJ is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with WiiuseJ. If not, see . + */ +package wiiusej.test; + +import wiiusej.WiiUseApiManager; +import wiiusej.Wiimote; + +/** + * Main Class to launch WiiuseJ GUI Test. + * @author guiguito + */ +public class Main { + + /** + * @param args the command line arguments + */ + public static void main(String[] args) { + Wiimote[] wiimotes = WiiUseApiManager.getWiimotes(1); + if (wiimotes.length>0){ + WiiuseJGuiTest gui = new WiiuseJGuiTest(wiimotes[0]); + gui.setDefaultCloseOperation(gui.EXIT_ON_CLOSE); + gui.setVisible(true); + } + } + +} diff --git a/WiiUseJ_0.1/src/wiiusej/test/Tests.java b/WiiUseJ_0.1/src/wiiusej/test/Tests.java new file mode 100644 index 0000000..f9e20f9 --- /dev/null +++ b/WiiUseJ_0.1/src/wiiusej/test/Tests.java @@ -0,0 +1,354 @@ +/** + * This file is part of WiiuseJ. + * + * WiiuseJ is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * WiiuseJ is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with WiiuseJ. If not, see . + */ +package wiiusej.test; + +import java.awt.AWTException; +import java.awt.Robot; +import java.awt.event.InputEvent; + +import wiiusej.WiiUseApiManager; +import wiiusej.Wiimote; +import wiiusej.values.IRSource; +import wiiusej.wiiuseapievents.ButtonsEvent; +import wiiusej.wiiuseapievents.DisconnectionEvent; +import wiiusej.wiiuseapievents.IREvent; +import wiiusej.wiiuseapievents.MotionSensingEvent; +import wiiusej.wiiuseapievents.StatusEvent; +import wiiusej.wiiuseapievents.GenericEvent; +import wiiusej.wiiuseapievents.WiimoteListener; + +/** + * This class used to test WiiuseJ. + * + * @author guiguito + */ +public class Tests implements WiimoteListener { + + Robot robot; + + private static int DISPLAY_EACH_VALUE = 1; + private static int DUMP = 2; + private static int MOVE_MOUSE = 3; + private static int TEST_LEDS = 5; + + private Wiimote wiimote; + + int dump = DISPLAY_EACH_VALUE; + + public Tests(Wiimote wim) { + wiimote = wim; + wiimote.addWiiMoteEventListeners(this); + try { + robot = new Robot(); + } catch (AWTException e) { + e.printStackTrace(); + } + } + + private static int nb = 0; + + public void onButtonsEvent(ButtonsEvent e) { + if (dump == DISPLAY_EACH_VALUE) { + // System.out.println("*********** WIIMOTE ID : "+ + // e.getWiimoteId() + " **************"); + /* button ONE */ + if (e.isButtonOneJustPressed()) { + System.out.println("button one pressed"); + } + if (e.isButtonOneHeld()) { + System.out.println("button one held"); + } + if (e.isButtonOneJustReleased()) { + System.out.println("button one released"); + } + + /* button TWO */ + if (e.isButtonTwoJustPressed()) { + System.out.println("button two pressed"); + } + if (e.isButtonTwoHeld()) { + System.out.println("button two held"); + } + if (e.isButtonTwoJustReleased()) { + System.out.println("button two released"); + } + + /* button A */ + if (e.isButtonAJustPressed()) { + System.out.println("button A pressed"); + } + if (e.isButtonAHeld()) { + System.out.println("button A held"); + } + if (e.isButtonAJustReleased()) { + System.out.println("button A released"); + } + + /* button B */ + if (e.isButtonBJustPressed()) { + System.out.println("button B pressed"); + } + if (e.isButtonBHeld()) { + System.out.println("button B held"); + } + if (e.isButtonBJustReleased()) { + System.out.println("button B released"); + } + + /* button LEFT */ + if (e.isButtonLeftJustPressed()) { + System.out.println("button Left pressed"); + } + if (e.isButtonLeftHeld()) { + System.out.println("button Left held"); + } + if (e.isButtonLeftJustReleased()) { + System.out.println("button Left released"); + } + + /* button RIGHT */ + if (e.isButtonRightJustPressed()) { + System.out.println("button Right pressed"); + } + if (e.isButtonRightHeld()) { + System.out.println("button Right held"); + } + if (e.isButtonRightJustReleased()) { + System.out.println("button Right released"); + } + + /* button UP */ + if (e.isButtonUpJustPressed()) { + System.out.println("button UP pressed"); + } + if (e.isButtonUpHeld()) { + System.out.println("button UP held"); + } + if (e.isButtonUpJustReleased()) { + System.out.println("button UP released"); + } + + /* button DOWN */ + if (e.isButtonDownJustPressed()) { + System.out.println("button DOWN pressed"); + } + if (e.isButtonDownHeld()) { + System.out.println("button DOWN held"); + } + if (e.isButtonDownJustReleased()) { + System.out.println("button DOWN released"); + } + + /* button MINUS */ + if (e.isButtonMinusJustPressed()) { + System.out.println("button MINUS pressed"); + } + if (e.isButtonMinusHeld()) { + System.out.println("button MINUS held"); + } + if (e.isButtonMinusJustReleased()) { + System.out.println("button MINUS released"); + } + + /* button PLUS */ + if (e.isButtonPlusJustPressed()) { + System.out.println("button PLUS pressed"); + } + if (e.isButtonPlusHeld()) { + System.out.println("button PLUS held"); + } + if (e.isButtonPlusJustReleased()) { + System.out.println("button PLUS released"); + } + + /* button HOME */ + if (e.isButtonHomeJustPressed()) { + System.out.println("button HOME pressed"); + } + if (e.isButtonHomeHeld()) { + System.out.println("button HOME held"); + } + if (e.isButtonHomeJustReleased()) { + System.out.println("button HOME released"); + } + + /* get status */ + if (e.isButtonUpJustPressed()) { + wiimote.getStatus(); + } + + /* Activate rumble */ + if (e.isButtonOneJustPressed()) { + System.out.println("Rumble Activated"); + wiimote.activateRumble(); + } + if (e.isButtonTwoJustPressed()) { + System.out.println("Rumble Deactivated"); + wiimote.deactivateRumble(); + } + + /* Activate IR Tracking */ + if (e.isButtonAJustPressed()) { + System.out.println("IR Activated"); + wiimote.activateIRTRacking(); + } + if (e.isButtonBJustPressed()) { + System.out.println("IR Deactivated"); + wiimote.deactivateIRTRacking(); + } + + /* Activate Motion sensing */ + if (e.isButtonPlusJustPressed()) { + System.out.println("Motion sensing Activated"); + wiimote.activateMotionSensing(); + } + if (e.isButtonMinusJustPressed()) { + System.out.println("Motion sensing Deactivated"); + wiimote.deactivateMotionSensing(); + } + + /* leave test */ + if (e.isButtonHomeJustPressed()) { + System.out.println("LEAVING TEST"); + wiimote.disconnect(); + } + + } else if (dump == DUMP) { + System.out.println(e); + /* Activate all */ + if (e.isButtonAJustPressed()) { + System.out.println("IR, rumble and motion sensing Activated"); + wiimote.activateIRTRacking(); + wiimote.activateMotionSensing(); + wiimote.activateRumble(); + } + if (e.isButtonBJustPressed()) { + System.out.println("IR, rumble and motion sensing Deactivated"); + wiimote.deactivateIRTRacking(); + wiimote.deactivateMotionSensing(); + wiimote.deactivateRumble(); + } + + /* leave test */ + if (e.isButtonHomeJustPressed()) { + System.out.println("LEAVING TEST"); + wiimote.disconnect(); + } + } else if (dump == MOVE_MOUSE) { + /* Activate IR Tracking */ + if (e.isButtonOneJustPressed()) { + System.out.println("IR Activated"); + wiimote.activateIRTRacking(); + } + if (e.isButtonTwoJustPressed()) { + System.out.println("IR Deactivated"); + wiimote.deactivateIRTRacking(); + } + + /* button A */ + if (e.isButtonAJustPressed()) { + robot.mousePress(InputEvent.BUTTON1_MASK); + } + if (e.isButtonAJustReleased()) { + robot.mouseRelease(InputEvent.BUTTON1_MASK); + } + + /* button B */ + if (e.isButtonBJustPressed()) { + robot.mousePress(InputEvent.BUTTON2_MASK); + } + if (e.isButtonBJustReleased()) { + robot.mouseRelease(InputEvent.BUTTON2_MASK); + } + + /* leave test */ + if (e.isButtonHomeJustPressed()) { + System.out.println("LEAVING TEST"); + wiimote.disconnect(); + } + } else if (dump == TEST_LEDS) { + wiimote.activateMotionSensing(); + if (e.isButtonUpJustPressed()) { + wiimote.setLeds(true, false, false, false); + } + if (e.isButtonDownJustPressed()) { + wiimote.setLeds(false, true, false, false); + } + if (e.isButtonLeftJustPressed()) { + wiimote.setLeds(false, false, true, false); + } + if (e.isButtonRightJustPressed()) { + wiimote.setLeds(false, false, false, true); + } + + /* leave test */ + if (e.isButtonHomeJustPressed()) { + System.out.println("LEAVING TEST"); + wiimote.disconnect(); + } + } + + } + + public void onIrEvent(IREvent e) { + if (dump == MOVE_MOUSE) { + IRSource[] list = e.getIRPoints(); + if (list.length > 0) { + int x1 = (int) list[0].getX(); + int y1 = (int) list[0].getY(); + + int mousex = (int) Math.round(((double) x1 / 1024.0) * 1280.0); + int mousey = (int) Math.round(((double) y1 / 768.0) * 1024.0); + robot.mouseMove(mousex, mousey); + } + } else { + System.out.println(e); + } + } + + public void onMotionSensingEvent(MotionSensingEvent e) { + /* display motion sensing */ + System.out.println(e); + } + + public void onStatusEvent(StatusEvent e) { + // Display status variables + System.out.println(e); + } + + public void onDisconnectionEvent(DisconnectionEvent e) { + System.out.println(" wiimote " + e.getWiimoteId() + + "has been disconnected !!"); + } + + /** + * @param args + */ + public static void main(String[] args) { + Wiimote[] wiimotes = WiiUseApiManager.getWiimotes(4); + if (wiimotes.length > 0) { + System.out.println(wiimotes[0]); + Tests tests = new Tests(wiimotes[0]); + } else { + System.out.println("No wiimotes found !!!"); + } + + // java.util.Timer timer = new java.util.Timer(); + // timer.scheduleAtFixedRate(new LedsTask(), 0, 100); + + } +} diff --git a/WiiUseJ_0.1/src/wiiusej/test/WiiuseJGuiTest.java b/WiiUseJ_0.1/src/wiiusej/test/WiiuseJGuiTest.java new file mode 100644 index 0000000..8bac8ae --- /dev/null +++ b/WiiUseJ_0.1/src/wiiusej/test/WiiuseJGuiTest.java @@ -0,0 +1,836 @@ +/** + * This file is part of WiiuseJ. + * + * WiiuseJ is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * WiiuseJ is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with WiiuseJ. If not, see . + */ +package wiiusej.test; + +import java.awt.AWTException; +import java.awt.Robot; +import java.awt.event.InputEvent; +import java.util.logging.Level; +import java.util.logging.Logger; +import wiiusej.utils.IRPanel; +import wiiusej.Wiimote; +import wiiusej.utils.AccelerationPanel; +import wiiusej.utils.GForcePanel; +import wiiusej.utils.ButtonsEventPanel; +import wiiusej.utils.OrientationPanel; +import wiiusej.wiiuseapievents.ButtonsEvent; +import wiiusej.wiiuseapievents.DisconnectionEvent; +import wiiusej.wiiuseapievents.IREvent; +import wiiusej.wiiuseapievents.MotionSensingEvent; +import wiiusej.wiiuseapievents.StatusEvent; +import wiiusej.wiiuseapievents.WiimoteListener; + +/** + * Gui class to test WiiuseJ. + * @author guiguito + */ +public class WiiuseJGuiTest extends javax.swing.JFrame implements WiimoteListener { + + private Wiimote wiimote; + private Robot robot = null; + private boolean statusMotionRequested = false; + private boolean statusIRRequested = false; + + /** Creates new form WiiuseJGuiTest */ + public WiiuseJGuiTest(Wiimote wiimote) { + initComponents(); + this.wiimote = wiimote; + wiimote.addWiiMoteEventListeners((IRPanel) irViewPanel); + wiimote.addWiiMoteEventListeners((ButtonsEventPanel) buttonsPanel); + wiimote.addWiiMoteEventListeners((OrientationPanel) motionSensingPanel); + wiimote.addWiiMoteEventListeners((GForcePanel) gForcePanel); + wiimote.addWiiMoteEventListeners((AccelerationPanel) accelerationPanel); + wiimote.addWiiMoteEventListeners(this); + wiimote.deactivateContinuous(); + wiimote.deactivateSmoothing(); + wiimote.setScreenAspectRatio169(); + wiimote.setSensorBarBelowScreen(); + getStatusButtonMousePressed(null); + this.addWindowListener(new CloseGuiTestCleanly(wiimote)); + } + + public void onButtonsEvent(ButtonsEvent arg0) { + if (robot != null) { + if (arg0.isButtonAPressed()) { + robot.mousePress(InputEvent.BUTTON1_MASK); + + } + if (arg0.isButtonBPressed()) { + robot.mousePress(InputEvent.BUTTON2_MASK); + + } + if (arg0.isButtonOnePressed()) { + robot.mousePress(InputEvent.BUTTON3_MASK); + + } + if (arg0.isButtonAJustReleased()) { + robot.mouseRelease(InputEvent.BUTTON1_MASK); + + } + if (arg0.isButtonBJustReleased()) { + robot.mouseRelease(InputEvent.BUTTON2_MASK); + + } + if (arg0.isButtonOneJustReleased()) { + robot.mouseRelease(InputEvent.BUTTON3_MASK); + + } + if (arg0.isButtonUpPressed()) {//mouse wheel up + robot.mouseWheel(-1); + } + if (arg0.isButtonDownPressed()) {//mouse wheel down + robot.mouseWheel(1); + } + + if (arg0.isButtonTwoPressed()) {//stop mouse control + mouseIRControlButtonMousePressed(null); + } + } + } + + public void onIrEvent(IREvent arg0) { + if (robot != null) {//if mouse control activated + robot.mouseMove(arg0.getX(), arg0.getY()); + } + if (statusIRRequested){ + xResolutionTextField.setText(""+arg0.getXVRes()); + yResolutionTextField.setText(""+arg0.getYVRes()); + statusIRRequested = false; + } + } + + public void onMotionSensingEvent(MotionSensingEvent arg0) { + if (statusMotionRequested){//Status requested + accelerationThresholdTextField.setText(""+arg0.getAccelerationThreshold()); + orientationThresholdTextField.setText(""+arg0.getOrientationThreshold()); + alphaSmoothingTextField.setText(""+arg0.getAlphaSmoothing()); + statusMotionRequested = false; + } + } + + public void onStatusEvent(StatusEvent arg0) { + messageText.setText("Status received !"); + batteryLevelText.setText(arg0.getBatteryLevel() + " %"); + led1Button.setEnabled(arg0.isLed1Set()); + led2Button.setEnabled(arg0.isLed2Set()); + led3Button.setEnabled(arg0.isLed3Set()); + led4Button.setEnabled(arg0.isLed4Set()); + //attachments + int eventType = arg0.getEventType(); + if (eventType == StatusEvent.WIIUSE_CLASSIC_CTRL_INSERTED){ + expansionText.setText("Classic control connected."); + }else + if (eventType == StatusEvent.WIIUSE_CLASSIC_CTRL_REMOVED){ + expansionText.setText("Classic control removed."); + }else + if (eventType == StatusEvent.WIIUSE_NUNCHUK_INSERTED){ + expansionText.setText("Nunchuk connected."); + }else + if (eventType == StatusEvent.WIIUSE_NUNCHUK_REMOVED){ + expansionText.setText("Nunchuk removed."); + }else + if (eventType == StatusEvent.WIIUSE_GUITAR_HERO_3_CTRL_INSERTED){ + expansionText.setText("Guitar Hero 3 control connected."); + }else + if (eventType == StatusEvent.WIIUSE_GUITAR_HERO_3_CTRL_REMOVED){ + expansionText.setText("Guitar Hero 3 control removed."); + } + } + + public void onDisconnectionEvent(DisconnectionEvent arg0) { + messageText.setText("Wiimote Disconnected !"); + } + + /** This method is called from within the constructor to + * initialize the form. + * WARNING: Do NOT modify this code. The content of this method is + * always regenerated by the Form Editor. + */ + // //GEN-BEGIN:initComponents + private void initComponents() { + + leftPanel = new javax.swing.JPanel(); + irViewPanel = new IRPanel(); + jTabbedPane1 = new javax.swing.JTabbedPane(); + motionSensingPanel = new OrientationPanel(); + gForcePanel = new wiiusej.utils.GForcePanel(); + accelerationPanel = new AccelerationPanel(); + rightPanel = new javax.swing.JPanel(); + fixedWiimotePanel = new javax.swing.JPanel(); + buttonsPanel = new ButtonsEventPanel(); + controlsPanel = new javax.swing.JPanel(); + activateRumblePanel = new javax.swing.JPanel(); + toggleRumbleButton = new javax.swing.JButton(); + deactivateRumblePanel = new javax.swing.JPanel(); + toggleIRTrackingButton = new javax.swing.JButton(); + activateIRtrackingPanel = new javax.swing.JPanel(); + toggleMotionSensingTrackingButton = new javax.swing.JButton(); + deactivateIRTrackingPanel = new javax.swing.JPanel(); + toggleSmoothingButton = new javax.swing.JButton(); + activateMotionSensingTrackingPanel = new javax.swing.JPanel(); + toggleContinuousButton = new javax.swing.JButton(); + deactivateMotionSensingTrackingPanel = new javax.swing.JPanel(); + led1Button = new javax.swing.JButton(); + led2Button = new javax.swing.JButton(); + led3Button = new javax.swing.JButton(); + led4Button = new javax.swing.JButton(); + setLedsButton = new javax.swing.JButton(); + activateSmoothingPanel = new javax.swing.JPanel(); + alphaSmoothingTextField = new javax.swing.JTextField(); + alphaSmoothingButton = new javax.swing.JButton(); + deactivateSmoothingPanel = new javax.swing.JPanel(); + orientationThresholdTextField = new javax.swing.JTextField(); + orientationThresholdButton = new javax.swing.JButton(); + activateContinuousPanel = new javax.swing.JPanel(); + accelerationThresholdTextField = new javax.swing.JTextField(); + accelerationThresholdButton = new javax.swing.JButton(); + deactivateContinuousPanel = new javax.swing.JPanel(); + getStatusButton = new javax.swing.JButton(); + batteryText = new javax.swing.JLabel(); + batteryLevelText = new javax.swing.JLabel(); + ledsPanel = new javax.swing.JPanel(); + toggleSensorBarPositionButton = new javax.swing.JButton(); + alphaSmoothingPanel = new javax.swing.JPanel(); + toggleScreenAspectRatioButton = new javax.swing.JButton(); + orientationThresholdPanel = new javax.swing.JPanel(); + xLabel = new javax.swing.JLabel(); + xResolutionTextField = new javax.swing.JTextField(); + yLabel = new javax.swing.JLabel(); + yResolutionTextField = new javax.swing.JTextField(); + setVirtualResolutionButton = new javax.swing.JButton(); + accelerationThresholdPanel = new javax.swing.JPanel(); + mouseIRControlButton = new javax.swing.JButton(); + batteryPanel = new javax.swing.JPanel(); + expansionText = new javax.swing.JLabel(); + messagesPanel = new javax.swing.JPanel(); + messageLabelText = new javax.swing.JLabel(); + messageText = new javax.swing.JLabel(); + + setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE); + setTitle("WiiuseJ Test GUI"); + setName("WiiuseJ Test GUI"); // NOI18N + + leftPanel.setBorder(javax.swing.BorderFactory.createEtchedBorder()); + + irViewPanel.setBackground(new java.awt.Color(0, 0, 0)); + irViewPanel.setBorder(javax.swing.BorderFactory.createTitledBorder(new javax.swing.border.LineBorder(new java.awt.Color(0, 153, 153), 2, true), "IR View", javax.swing.border.TitledBorder.DEFAULT_JUSTIFICATION, javax.swing.border.TitledBorder.DEFAULT_POSITION, new java.awt.Font("Tahoma", 0, 11), new java.awt.Color(255, 0, 51))); + + javax.swing.GroupLayout irViewPanelLayout = new javax.swing.GroupLayout(irViewPanel); + irViewPanel.setLayout(irViewPanelLayout); + irViewPanelLayout.setHorizontalGroup( + irViewPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGap(0, 272, Short.MAX_VALUE) + ); + irViewPanelLayout.setVerticalGroup( + irViewPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGap(0, 299, Short.MAX_VALUE) + ); + + javax.swing.GroupLayout motionSensingPanelLayout = new javax.swing.GroupLayout(motionSensingPanel); + motionSensingPanel.setLayout(motionSensingPanelLayout); + motionSensingPanelLayout.setHorizontalGroup( + motionSensingPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGap(0, 279, Short.MAX_VALUE) + ); + motionSensingPanelLayout.setVerticalGroup( + motionSensingPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGap(0, 213, Short.MAX_VALUE) + ); + + jTabbedPane1.addTab("Orientation", motionSensingPanel); + + javax.swing.GroupLayout gForcePanelLayout = new javax.swing.GroupLayout(gForcePanel); + gForcePanel.setLayout(gForcePanelLayout); + gForcePanelLayout.setHorizontalGroup( + gForcePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGap(0, 279, Short.MAX_VALUE) + ); + gForcePanelLayout.setVerticalGroup( + gForcePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGap(0, 213, Short.MAX_VALUE) + ); + + jTabbedPane1.addTab("GForce", gForcePanel); + + javax.swing.GroupLayout accelerationPanelLayout = new javax.swing.GroupLayout(accelerationPanel); + accelerationPanel.setLayout(accelerationPanelLayout); + accelerationPanelLayout.setHorizontalGroup( + accelerationPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGap(0, 279, Short.MAX_VALUE) + ); + accelerationPanelLayout.setVerticalGroup( + accelerationPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGap(0, 213, Short.MAX_VALUE) + ); + + jTabbedPane1.addTab("Raw Acceleration", accelerationPanel); + + javax.swing.GroupLayout leftPanelLayout = new javax.swing.GroupLayout(leftPanel); + leftPanel.setLayout(leftPanelLayout); + leftPanelLayout.setHorizontalGroup( + leftPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(irViewPanel, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(jTabbedPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 284, Short.MAX_VALUE) + ); + leftPanelLayout.setVerticalGroup( + leftPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, leftPanelLayout.createSequentialGroup() + .addComponent(jTabbedPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 238, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(irViewPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + ); + + jTabbedPane1.getAccessibleContext().setAccessibleName("Orientation"); + + rightPanel.setBorder(javax.swing.BorderFactory.createEtchedBorder()); + rightPanel.setLayout(new javax.swing.BoxLayout(rightPanel, javax.swing.BoxLayout.LINE_AXIS)); + + fixedWiimotePanel.setMaximumSize(new java.awt.Dimension(120, 32767)); + fixedWiimotePanel.setMinimumSize(new java.awt.Dimension(120, 100)); + fixedWiimotePanel.setPreferredSize(new java.awt.Dimension(120, 100)); + fixedWiimotePanel.setRequestFocusEnabled(false); + fixedWiimotePanel.setLayout(null); + + buttonsPanel.setMaximumSize(new java.awt.Dimension(120, 484)); + buttonsPanel.setMinimumSize(new java.awt.Dimension(120, 484)); + buttonsPanel.setOpaque(false); + buttonsPanel.setPreferredSize(new java.awt.Dimension(120, 484)); + + javax.swing.GroupLayout buttonsPanelLayout = new javax.swing.GroupLayout(buttonsPanel); + buttonsPanel.setLayout(buttonsPanelLayout); + buttonsPanelLayout.setHorizontalGroup( + buttonsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGap(0, 120, Short.MAX_VALUE) + ); + buttonsPanelLayout.setVerticalGroup( + buttonsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGap(0, 484, Short.MAX_VALUE) + ); + + fixedWiimotePanel.add(buttonsPanel); + buttonsPanel.setBounds(0, 0, 120, 484); + + rightPanel.add(fixedWiimotePanel); + + controlsPanel.setMinimumSize(new java.awt.Dimension(100, 264)); + controlsPanel.setPreferredSize(new java.awt.Dimension(190, 264)); + controlsPanel.setLayout(new java.awt.GridLayout(16, 1)); + + toggleRumbleButton.setText("Activate Rumble"); + toggleRumbleButton.addMouseListener(new java.awt.event.MouseAdapter() { + public void mousePressed(java.awt.event.MouseEvent evt) { + toggleRumbleButtonMousePressed(evt); + } + }); + activateRumblePanel.add(toggleRumbleButton); + + controlsPanel.add(activateRumblePanel); + + toggleIRTrackingButton.setText("Activate IR Tracking"); + toggleIRTrackingButton.addMouseListener(new java.awt.event.MouseAdapter() { + public void mousePressed(java.awt.event.MouseEvent evt) { + toggleIRTrackingButtonMousePressed(evt); + } + }); + deactivateRumblePanel.add(toggleIRTrackingButton); + + controlsPanel.add(deactivateRumblePanel); + + toggleMotionSensingTrackingButton.setText("Activate motion sensing Tracking"); + toggleMotionSensingTrackingButton.addMouseListener(new java.awt.event.MouseAdapter() { + public void mousePressed(java.awt.event.MouseEvent evt) { + toggleMotionSensingTrackingButtonMousePressed(evt); + } + }); + activateIRtrackingPanel.add(toggleMotionSensingTrackingButton); + + controlsPanel.add(activateIRtrackingPanel); + + toggleSmoothingButton.setText("Activate Smoothing"); + toggleSmoothingButton.addMouseListener(new java.awt.event.MouseAdapter() { + public void mousePressed(java.awt.event.MouseEvent evt) { + toggleSmoothingButtonMousePressed(evt); + } + }); + deactivateIRTrackingPanel.add(toggleSmoothingButton); + + controlsPanel.add(deactivateIRTrackingPanel); + + toggleContinuousButton.setText("Activate Continuous"); + toggleContinuousButton.addMouseListener(new java.awt.event.MouseAdapter() { + public void mousePressed(java.awt.event.MouseEvent evt) { + toggleContinuousButtonMousePressed(evt); + } + }); + activateMotionSensingTrackingPanel.add(toggleContinuousButton); + + controlsPanel.add(activateMotionSensingTrackingPanel); + + led1Button.setText("Led1"); + led1Button.addMouseListener(new java.awt.event.MouseAdapter() { + public void mousePressed(java.awt.event.MouseEvent evt) { + led1ButtonMousePressed(evt); + } + }); + deactivateMotionSensingTrackingPanel.add(led1Button); + + led2Button.setText("Led2"); + led2Button.addMouseListener(new java.awt.event.MouseAdapter() { + public void mousePressed(java.awt.event.MouseEvent evt) { + led2ButtonMousePressed(evt); + } + }); + deactivateMotionSensingTrackingPanel.add(led2Button); + + led3Button.setText("Led3"); + led3Button.addMouseListener(new java.awt.event.MouseAdapter() { + public void mousePressed(java.awt.event.MouseEvent evt) { + led3ButtonMousePressed(evt); + } + }); + deactivateMotionSensingTrackingPanel.add(led3Button); + + led4Button.setText("Led4"); + led4Button.addMouseListener(new java.awt.event.MouseAdapter() { + public void mousePressed(java.awt.event.MouseEvent evt) { + led4ButtonMousePressed(evt); + } + }); + deactivateMotionSensingTrackingPanel.add(led4Button); + + setLedsButton.setText("Set leds"); + setLedsButton.addMouseListener(new java.awt.event.MouseAdapter() { + public void mousePressed(java.awt.event.MouseEvent evt) { + setLedsButtonMousePressed(evt); + } + }); + deactivateMotionSensingTrackingPanel.add(setLedsButton); + + controlsPanel.add(deactivateMotionSensingTrackingPanel); + + alphaSmoothingTextField.setMinimumSize(new java.awt.Dimension(100, 20)); + alphaSmoothingTextField.setPreferredSize(new java.awt.Dimension(100, 20)); + activateSmoothingPanel.add(alphaSmoothingTextField); + + alphaSmoothingButton.setText("Set alpha smoothing"); + alphaSmoothingButton.addMouseListener(new java.awt.event.MouseAdapter() { + public void mousePressed(java.awt.event.MouseEvent evt) { + alphaSmoothingButtonMousePressed(evt); + } + }); + activateSmoothingPanel.add(alphaSmoothingButton); + + controlsPanel.add(activateSmoothingPanel); + + orientationThresholdTextField.setMinimumSize(new java.awt.Dimension(100, 20)); + orientationThresholdTextField.setPreferredSize(new java.awt.Dimension(100, 20)); + deactivateSmoothingPanel.add(orientationThresholdTextField); + + orientationThresholdButton.setText("Set orientation threshold"); + orientationThresholdButton.addMouseListener(new java.awt.event.MouseAdapter() { + public void mousePressed(java.awt.event.MouseEvent evt) { + orientationThresholdButtonMousePressed(evt); + } + }); + deactivateSmoothingPanel.add(orientationThresholdButton); + + controlsPanel.add(deactivateSmoothingPanel); + + accelerationThresholdTextField.setPreferredSize(new java.awt.Dimension(100, 20)); + activateContinuousPanel.add(accelerationThresholdTextField); + + accelerationThresholdButton.setText("Set acceleration threshold"); + accelerationThresholdButton.addMouseListener(new java.awt.event.MouseAdapter() { + public void mousePressed(java.awt.event.MouseEvent evt) { + accelerationThresholdButtonMousePressed(evt); + } + }); + activateContinuousPanel.add(accelerationThresholdButton); + + controlsPanel.add(activateContinuousPanel); + + getStatusButton.setText("Get status"); + getStatusButton.addMouseListener(new java.awt.event.MouseAdapter() { + public void mousePressed(java.awt.event.MouseEvent evt) { + getStatusButtonMousePressed(evt); + } + }); + deactivateContinuousPanel.add(getStatusButton); + + batteryText.setFont(new java.awt.Font("Tahoma", 0, 14)); + batteryText.setText("Battery level :"); + deactivateContinuousPanel.add(batteryText); + + batteryLevelText.setFont(new java.awt.Font("Arial", 0, 14)); + batteryLevelText.setText(" %"); + deactivateContinuousPanel.add(batteryLevelText); + + controlsPanel.add(deactivateContinuousPanel); + + toggleSensorBarPositionButton.setText("Set sensor bar above"); + toggleSensorBarPositionButton.addMouseListener(new java.awt.event.MouseAdapter() { + public void mousePressed(java.awt.event.MouseEvent evt) { + toggleSensorBarPositionButtonMousePressed(evt); + } + }); + ledsPanel.add(toggleSensorBarPositionButton); + + controlsPanel.add(ledsPanel); + + toggleScreenAspectRatioButton.setText("Set screen aspect ratio 4/3"); + toggleScreenAspectRatioButton.addMouseListener(new java.awt.event.MouseAdapter() { + public void mousePressed(java.awt.event.MouseEvent evt) { + toggleScreenAspectRatioButtonMousePressed(evt); + } + }); + alphaSmoothingPanel.add(toggleScreenAspectRatioButton); + + controlsPanel.add(alphaSmoothingPanel); + + xLabel.setText("X"); + orientationThresholdPanel.add(xLabel); + + xResolutionTextField.setMinimumSize(new java.awt.Dimension(40, 20)); + xResolutionTextField.setPreferredSize(new java.awt.Dimension(40, 20)); + orientationThresholdPanel.add(xResolutionTextField); + + yLabel.setText("Y"); + orientationThresholdPanel.add(yLabel); + + yResolutionTextField.setFocusTraversalPolicyProvider(true); + yResolutionTextField.setMinimumSize(new java.awt.Dimension(40, 20)); + yResolutionTextField.setPreferredSize(new java.awt.Dimension(40, 20)); + orientationThresholdPanel.add(yResolutionTextField); + + setVirtualResolutionButton.setText("Set virtual resolution"); + setVirtualResolutionButton.addMouseListener(new java.awt.event.MouseAdapter() { + public void mousePressed(java.awt.event.MouseEvent evt) { + setVirtualResolutionButtonMousePressed(evt); + } + }); + orientationThresholdPanel.add(setVirtualResolutionButton); + + controlsPanel.add(orientationThresholdPanel); + + mouseIRControlButton.setText("Start infrared mouse control"); + mouseIRControlButton.addMouseListener(new java.awt.event.MouseAdapter() { + public void mousePressed(java.awt.event.MouseEvent evt) { + mouseIRControlButtonMousePressed(evt); + } + }); + accelerationThresholdPanel.add(mouseIRControlButton); + + controlsPanel.add(accelerationThresholdPanel); + + expansionText.setText("No expansion connected"); + batteryPanel.add(expansionText); + + controlsPanel.add(batteryPanel); + + messageLabelText.setFont(new java.awt.Font("Tahoma", 0, 14)); + messageLabelText.setText("Message : "); + messagesPanel.add(messageLabelText); + + messageText.setFont(new java.awt.Font("Arial", 0, 14)); + messageText.setText("None"); + messagesPanel.add(messageText); + + controlsPanel.add(messagesPanel); + + rightPanel.add(controlsPanel); + + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane()); + getContentPane().setLayout(layout); + layout.setHorizontalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addComponent(leftPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(rightPanel, javax.swing.GroupLayout.DEFAULT_SIZE, 498, Short.MAX_VALUE)) + ); + layout.setVerticalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(leftPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(rightPanel, javax.swing.GroupLayout.DEFAULT_SIZE, 573, Short.MAX_VALUE) + ); + + java.awt.Dimension screenSize = java.awt.Toolkit.getDefaultToolkit().getScreenSize(); + setBounds((screenSize.width-800)/2, (screenSize.height-600)/2, 800, 600); + }// //GEN-END:initComponents + private void toggleRumbleButtonMousePressed(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_toggleRumbleButtonMousePressed + if (toggleRumbleButton.isEnabled()) { + wiimote.activateRumble(); + toggleRumbleButton.setEnabled(false); + toggleRumbleButton.setText("Deactivate Rumble"); + messageText.setText("Rumble activated"); + } else { + wiimote.deactivateRumble(); + toggleRumbleButton.setEnabled(true); + toggleRumbleButton.setText("Activate Rumble"); + messageText.setText("Rumble deactivated"); + } + }//GEN-LAST:event_toggleRumbleButtonMousePressed + + private void toggleIRTrackingButtonMousePressed(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_toggleIRTrackingButtonMousePressed + if (toggleIRTrackingButton.isEnabled()) { + wiimote.activateIRTRacking(); + toggleIRTrackingButton.setEnabled(false); + toggleIRTrackingButton.setText("Deactivate IR Tracking"); + messageText.setText("IR Tracking activated"); + } else { + wiimote.deactivateIRTRacking(); + toggleIRTrackingButton.setEnabled(true); + toggleIRTrackingButton.setText("Activate IR Tracking"); + ((IRPanel) irViewPanel).onDisconnectionEvent(null); + messageText.setText("IR Tracking deactivated"); + } + }//GEN-LAST:event_toggleIRTrackingButtonMousePressed + + private void toggleMotionSensingTrackingButtonMousePressed(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_toggleMotionSensingTrackingButtonMousePressed + if (toggleMotionSensingTrackingButton.isEnabled()) { + wiimote.activateMotionSensing(); + toggleMotionSensingTrackingButton.setEnabled(false); + toggleMotionSensingTrackingButton.setText("Deactivate Motion Sensing"); + messageText.setText("Motion Sensing activated"); + } else { + wiimote.deactivateMotionSensing(); + toggleMotionSensingTrackingButton.setEnabled(true); + toggleMotionSensingTrackingButton.setText("Activate Motion Sensing"); + ((OrientationPanel) motionSensingPanel).onDisconnectionEvent(null); + ((GForcePanel) gForcePanel).onDisconnectionEvent(null); + messageText.setText("Motion Sensing deactivated"); + } + }//GEN-LAST:event_toggleMotionSensingTrackingButtonMousePressed + + private void toggleSmoothingButtonMousePressed(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_toggleSmoothingButtonMousePressed + if (toggleSmoothingButton.isEnabled()) { + wiimote.activateSmoothing(); + toggleSmoothingButton.setEnabled(false); + toggleSmoothingButton.setText("Deactivate Alpha Smoothing"); + messageText.setText("Alpha Smoothing activated"); + } else { + wiimote.deactivateSmoothing(); + toggleSmoothingButton.setEnabled(true); + toggleSmoothingButton.setText("Activate Alpha Smoothing"); + messageText.setText("Alpha Smoothing deactivated"); + } + }//GEN-LAST:event_toggleSmoothingButtonMousePressed + + private void toggleContinuousButtonMousePressed(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_toggleContinuousButtonMousePressed + if (toggleContinuousButton.isEnabled()) { + wiimote.activateContinuous(); + toggleContinuousButton.setEnabled(false); + toggleContinuousButton.setText("Deactivate Continuous"); + messageText.setText("Continuous activated"); + } else { + wiimote.deactivateContinuous(); + toggleContinuousButton.setEnabled(true); + toggleContinuousButton.setText("Activate Continuous"); + messageText.setText("Continuous deactivated"); + } + }//GEN-LAST:event_toggleContinuousButtonMousePressed + + private void led1ButtonMousePressed(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_led1ButtonMousePressed + if (led1Button.isEnabled()) { + led1Button.setEnabled(false); + } else { + led1Button.setEnabled(true); + } + }//GEN-LAST:event_led1ButtonMousePressed + + private void led2ButtonMousePressed(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_led2ButtonMousePressed + if (led2Button.isEnabled()) { + led2Button.setEnabled(false); + } else { + led2Button.setEnabled(true); + } + }//GEN-LAST:event_led2ButtonMousePressed + + private void led3ButtonMousePressed(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_led3ButtonMousePressed + if (led3Button.isEnabled()) { + led3Button.setEnabled(false); + } else { + led3Button.setEnabled(true); + } + }//GEN-LAST:event_led3ButtonMousePressed + + private void led4ButtonMousePressed(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_led4ButtonMousePressed + if (led4Button.isEnabled()) { + led4Button.setEnabled(false); + } else { + led4Button.setEnabled(true); + } + }//GEN-LAST:event_led4ButtonMousePressed + + private void setLedsButtonMousePressed(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_setLedsButtonMousePressed + wiimote.setLeds(led1Button.isEnabled(), led2Button.isEnabled(), + led3Button.isEnabled(), led4Button.isEnabled()); + messageText.setText("Leds set"); + }//GEN-LAST:event_setLedsButtonMousePressed + + private void alphaSmoothingButtonMousePressed(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_alphaSmoothingButtonMousePressed + try { + float nb = Float.parseFloat(alphaSmoothingTextField.getText()); + wiimote.setAlphaSmoothingValue(nb); + messageText.setText("Alpha smoothing set to " + nb); + } catch (NumberFormatException e) { + messageText.setText("Number is not a float, alpha smoothing not set !"); + } + }//GEN-LAST:event_alphaSmoothingButtonMousePressed + + private void orientationThresholdButtonMousePressed(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_orientationThresholdButtonMousePressed + try { + float nb = Float.parseFloat(orientationThresholdTextField.getText()); + wiimote.setOrientationThreshold(nb); + messageText.setText("Orientation threshold set to " + nb); + } catch (NumberFormatException e) { + messageText.setText("Number is not a float, orientation threshold not set !"); + } + }//GEN-LAST:event_orientationThresholdButtonMousePressed + + private void accelerationThresholdButtonMousePressed(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_accelerationThresholdButtonMousePressed + try { + int nb = Integer.parseInt(accelerationThresholdTextField.getText()); + wiimote.setAccelerationThreshold(nb); + messageText.setText("Acceleration threshold set to " + nb); + } catch (NumberFormatException e) { + messageText.setText("Number is not an integer, acceleration threshold not set !"); + } + }//GEN-LAST:event_accelerationThresholdButtonMousePressed + + private void getStatusButtonMousePressed(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_getStatusButtonMousePressed + wiimote.getStatus(); + statusMotionRequested = true; + statusIRRequested = true; + }//GEN-LAST:event_getStatusButtonMousePressed + + private void toggleSensorBarPositionButtonMousePressed(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_toggleSensorBarPositionButtonMousePressed + if (toggleSensorBarPositionButton.isEnabled()) { + wiimote.setSensorBarBelowScreen(); + toggleSensorBarPositionButton.setEnabled(false); + toggleSensorBarPositionButton.setText("Set sensor bar below"); + messageText.setText("Sensor bar set above"); + } else { + wiimote.setSensorBarAboveScreen(); + toggleSensorBarPositionButton.setEnabled(true); + toggleSensorBarPositionButton.setText("Set sensor bar above"); + messageText.setText("Sensor bar set below"); + } + }//GEN-LAST:event_toggleSensorBarPositionButtonMousePressed + + private void toggleScreenAspectRatioButtonMousePressed(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_toggleScreenAspectRatioButtonMousePressed + if (toggleScreenAspectRatioButton.isEnabled()) { + wiimote.setScreenAspectRatio43(); + toggleScreenAspectRatioButton.setEnabled(false); + toggleScreenAspectRatioButton.setText("Set screen aspect ratio 16/9"); + messageText.setText("creen aspect ratio to 4/3"); + } else { + wiimote.setScreenAspectRatio169(); + toggleScreenAspectRatioButton.setEnabled(true); + toggleScreenAspectRatioButton.setText("Set screen aspect ratio 4/3"); + messageText.setText("Screen aspect ratio to 16/9"); + } + }//GEN-LAST:event_toggleScreenAspectRatioButtonMousePressed + + private void setVirtualResolutionButtonMousePressed(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_setVirtualResolutionButtonMousePressed + try { + int xres = Integer.parseInt(xResolutionTextField.getText()); + int yres = Integer.parseInt(yResolutionTextField.getText()); + wiimote.setVirtualResolution(xres, yres); + messageText.setText("Virtual resolution set to " + xres + "X" + yres); + } catch (NumberFormatException e) { + messageText.setText("A number in the virtual resolution is not an integer. Virtual resolution not set!"); + } + }//GEN-LAST:event_setVirtualResolutionButtonMousePressed + + private void mouseIRControlButtonMousePressed(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_mouseIRControlButtonMousePressed + if (mouseIRControlButton.isEnabled()) { + try { + mouseIRControlButton.setEnabled(false); + mouseIRControlButton.setText("Stop infrared mouse control"); + robot = new Robot(); + messageText.setText("Infrared mouse control started"); + } catch (AWTException ex) { + Logger.getLogger(WiiuseJGuiTest.class.getName()).log(Level.SEVERE, null, ex); + } + } else { + mouseIRControlButton.setEnabled(true); + mouseIRControlButton.setText("Start infrared mouse control"); + robot = null; + messageText.setText("Infrared mouse control stopped"); + } + }//GEN-LAST:event_mouseIRControlButtonMousePressed + + // Variables declaration - do not modify//GEN-BEGIN:variables + private javax.swing.JPanel accelerationPanel; + private javax.swing.JButton accelerationThresholdButton; + private javax.swing.JPanel accelerationThresholdPanel; + private javax.swing.JTextField accelerationThresholdTextField; + private javax.swing.JPanel activateContinuousPanel; + private javax.swing.JPanel activateIRtrackingPanel; + private javax.swing.JPanel activateMotionSensingTrackingPanel; + private javax.swing.JPanel activateRumblePanel; + private javax.swing.JPanel activateSmoothingPanel; + private javax.swing.JButton alphaSmoothingButton; + private javax.swing.JPanel alphaSmoothingPanel; + private javax.swing.JTextField alphaSmoothingTextField; + private javax.swing.JLabel batteryLevelText; + private javax.swing.JPanel batteryPanel; + private javax.swing.JLabel batteryText; + private javax.swing.JPanel buttonsPanel; + private javax.swing.JPanel controlsPanel; + private javax.swing.JPanel deactivateContinuousPanel; + private javax.swing.JPanel deactivateIRTrackingPanel; + private javax.swing.JPanel deactivateMotionSensingTrackingPanel; + private javax.swing.JPanel deactivateRumblePanel; + private javax.swing.JPanel deactivateSmoothingPanel; + private javax.swing.JLabel expansionText; + private javax.swing.JPanel fixedWiimotePanel; + private javax.swing.JPanel gForcePanel; + private javax.swing.JButton getStatusButton; + private javax.swing.JPanel irViewPanel; + private javax.swing.JTabbedPane jTabbedPane1; + private javax.swing.JButton led1Button; + private javax.swing.JButton led2Button; + private javax.swing.JButton led3Button; + private javax.swing.JButton led4Button; + private javax.swing.JPanel ledsPanel; + private javax.swing.JPanel leftPanel; + private javax.swing.JLabel messageLabelText; + private javax.swing.JLabel messageText; + private javax.swing.JPanel messagesPanel; + private javax.swing.JPanel motionSensingPanel; + private javax.swing.JButton mouseIRControlButton; + private javax.swing.JButton orientationThresholdButton; + private javax.swing.JPanel orientationThresholdPanel; + private javax.swing.JTextField orientationThresholdTextField; + private javax.swing.JPanel rightPanel; + private javax.swing.JButton setLedsButton; + private javax.swing.JButton setVirtualResolutionButton; + private javax.swing.JButton toggleContinuousButton; + private javax.swing.JButton toggleIRTrackingButton; + private javax.swing.JButton toggleMotionSensingTrackingButton; + private javax.swing.JButton toggleRumbleButton; + private javax.swing.JButton toggleScreenAspectRatioButton; + private javax.swing.JButton toggleSensorBarPositionButton; + private javax.swing.JButton toggleSmoothingButton; + private javax.swing.JLabel xLabel; + private javax.swing.JTextField xResolutionTextField; + private javax.swing.JLabel yLabel; + private javax.swing.JTextField yResolutionTextField; + // End of variables declaration//GEN-END:variables +} diff --git a/WiiUseJ_0.1/src/wiiusej/utils/AccelerationPanel.java b/WiiUseJ_0.1/src/wiiusej/utils/AccelerationPanel.java new file mode 100644 index 0000000..0403255 --- /dev/null +++ b/WiiUseJ_0.1/src/wiiusej/utils/AccelerationPanel.java @@ -0,0 +1,182 @@ +/** + * This file is part of WiiuseJ. + * + * WiiuseJ is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * WiiuseJ is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with WiiuseJ. If not, see . + */ +package wiiusej.utils; + +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.Image; +import java.awt.RenderingHints; +import java.awt.geom.AffineTransform; +import java.util.ArrayList; +import wiiusej.values.RawAcceleration; +import wiiusej.wiiuseapievents.ButtonsEvent; +import wiiusej.wiiuseapievents.DisconnectionEvent; +import wiiusej.wiiuseapievents.IREvent; +import wiiusej.wiiuseapievents.MotionSensingEvent; +import wiiusej.wiiuseapievents.StatusEvent; +import wiiusej.wiiuseapievents.WiimoteListener; + +/** + * This panel is used to watch raw acceleration values from a MotionSensingEvent. + * @author guiguito + */ +public class AccelerationPanel extends javax.swing.JPanel implements WiimoteListener { + + private Image mImage;//image for double buffering + private Color xColor = Color.RED; + private Color yColor = Color.GREEN; + private Color zColor = Color.BLUE; + private Color backgroundColor = Color.WHITE; + private Color lineColor = Color.BLACK; + private ArrayList values = new ArrayList(); + + /** Creates new form AccelerationPanel */ + public AccelerationPanel() { + initComponents(); + } + + @Override + public void paintComponent(Graphics g) { + super.paintComponent(g); + Dimension d = getSize(); + checkOffScreenImage(); + Graphics offG = mImage.getGraphics(); + offG.setColor(backgroundColor); + offG.fillRect(0, 0, d.width, d.height); + Graphics2D g2 = (Graphics2D) mImage.getGraphics(); + g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); + + //draw medium line + int yLine = getHeight() - 25; + + g2.setPaint(lineColor); + g2.drawLine(0, yLine, getWidth(), yLine); + + RawAcceleration[] valuesArray = values.toArray(new RawAcceleration[0]); + + double unit = yLine / 255.0; + int previousX = 0; + int previousY = 0; + int previousZ = 0; + //draw curves + for (int i = 0; i < valuesArray.length && i < getWidth(); i++) { + RawAcceleration acceleration = valuesArray[i]; + //draw X + g2.setPaint(xColor); + int yDelta = (int) Math.round(unit * acceleration.getX()); + int y = -1 * yDelta + yLine; + g2.drawLine(i - 1, previousX, i, y); + g2.setTransform(new AffineTransform()); + previousX = y; + //draw Y + g2.setPaint(yColor); + yDelta = (int) Math.round(unit * acceleration.getY()); + y = -1 * yDelta + yLine; + g2.drawLine(i - 1, previousY, i, y); + g2.setTransform(new AffineTransform()); + previousY = y; + //draw Z + g2.setPaint(zColor); + yDelta = (int) Math.round(unit * acceleration.getZ()); + y = -1 * yDelta + yLine; + g2.drawLine(i - 1, previousZ, i, y); + g2.setTransform(new AffineTransform()); + previousZ = y; + } + + //draw legend + g2.setPaint(xColor); + g2.drawLine(5, getHeight() - 10, 25, getHeight() - 10); + g2.setPaint(yColor); + g2.drawLine(60, getHeight() - 10, 80, getHeight() - 10); + g2.setPaint(zColor); + g2.drawLine(120, getHeight() - 10, 140, getHeight() - 10); + + g2.setPaint(lineColor); + g2.drawString("X", 30, getHeight() - 5); + g2.drawString("Y", 85, getHeight() - 5); + g2.drawString("Z", 145, getHeight() - 5); + g2.drawString("0", 2, yLine - 5); + g2.drawString("255", 2, 15); + //put offscreen image on the screen + g.drawImage(mImage, 0, 0, null); + } + + /** + * check if the mImage variable has been initialized. If it's not the case it initializes it + * with the dimensions of the panel. mImage is for double buffering. + */ + private void checkOffScreenImage() { + Dimension d = getSize(); + if (mImage == null || mImage.getWidth(null) != d.width || mImage.getHeight(null) != d.height) { + mImage = createImage(d.width, d.height); + } + } + + public void onButtonsEvent(ButtonsEvent arg0) { + //nothing + } + + public void onIrEvent(IREvent arg0) { + //nothing + } + + public void onMotionSensingEvent(MotionSensingEvent arg0) { + if (values.size() >= getWidth()) { + //if there are as many values as pixels in the width + //clear points + values.clear(); + } + values.add(arg0.getRawAcceleration()); + repaint(); + } + + public void onStatusEvent(StatusEvent arg0) { + //nothing + } + + public void onDisconnectionEvent(DisconnectionEvent arg0) { + //Clear points. + values.clear(); + repaint(); + } + + /** This method is called from within the constructor to + * initialize the form. + * WARNING: Do NOT modify this code. The content of this method is + * always regenerated by the Form Editor. + */ + // //GEN-BEGIN:initComponents + private void initComponents() { + + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); + this.setLayout(layout); + layout.setHorizontalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGap(0, 400, Short.MAX_VALUE) + ); + layout.setVerticalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGap(0, 300, Short.MAX_VALUE) + ); + }// //GEN-END:initComponents + + // Variables declaration - do not modify//GEN-BEGIN:variables + // End of variables declaration//GEN-END:variables +} diff --git a/WiiUseJ_0.1/src/wiiusej/utils/ButtonsEventPanel.java b/WiiUseJ_0.1/src/wiiusej/utils/ButtonsEventPanel.java new file mode 100644 index 0000000..2a4a48f --- /dev/null +++ b/WiiUseJ_0.1/src/wiiusej/utils/ButtonsEventPanel.java @@ -0,0 +1,297 @@ +/** + * This file is part of WiiuseJ. + * + * WiiuseJ is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * WiiuseJ is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with WiiuseJ. If not, see . + */ +package wiiusej.utils; + +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.Image; +import java.awt.RenderingHints; +import java.awt.Shape; +import java.awt.Toolkit; +import java.awt.geom.AffineTransform; +import wiiusej.wiiuseapievents.ButtonsEvent; +import wiiusej.wiiuseapievents.DisconnectionEvent; +import wiiusej.wiiuseapievents.IREvent; +import wiiusej.wiiuseapievents.MotionSensingEvent; +import wiiusej.wiiuseapievents.StatusEvent; +import wiiusej.wiiuseapievents.WiimoteListener; + +/** + * This panel is used to see what buttons are pressed. + * It displays the result of last ButtonsEvent. + * @author guiguito + */ +public class ButtonsEventPanel extends javax.swing.JPanel implements WiimoteListener { + + private Image mImage;//image for double buffering + private Image wiimoteImage;//image for double buffering + private ButtonsEvent buttons; + private Color pressedColor = Color.RED; + private Color heldColor = Color.ORANGE; + private Color releasedColor = Color.YELLOW; + private Shape shape; + + /** + * Default constructor. + * Red : button just pressed. + * Orange : button held. + * Yellow : button just released. + */ + public ButtonsEventPanel() { + Toolkit toolkit = java.awt.Toolkit.getDefaultToolkit(); + java.net.URL url = ButtonsEventPanel.class.getResource("/img/wiimote.png"); + wiimoteImage = toolkit.createImage(url); + shape = new java.awt.geom.Ellipse2D.Double(0, 0, 13, 13); + initComponents(); + } + + /** + * Constructor used to set colors and shape used. + * @param pressColor color of a button just pressed. + * @param hColor color of a button held. + * @param relColor color of a button just released. + * @param sh shape draw on the buttons. + */ + public ButtonsEventPanel(Color pressColor, Color hColor, Color relColor, Shape sh) { + pressedColor = pressColor; + heldColor = hColor; + releasedColor = relColor; + shape = sh; + Toolkit toolkit = java.awt.Toolkit.getDefaultToolkit(); + wiimoteImage = toolkit.createImage("img\\wiimote.png"); + shape = new java.awt.geom.Ellipse2D.Double(0, 0, 13, 13); + initComponents(); + } + + @Override + public void paintComponent(Graphics g) { + super.paintComponent(g); + Dimension d = getSize(); + checkOffScreenImage(); + Graphics offG = mImage.getGraphics(); + //offG.setColor(backgroundColor); + offG.fillRect(0, 0, d.width, d.height); + Graphics2D g2 = (Graphics2D) mImage.getGraphics(); + g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); + + //draw buttons pushed + g2.drawImage(wiimoteImage, 0, 0, this); + g2.setTransform(new AffineTransform()); + + if (buttons != null) { + /* button ONE */ + if (buttons.isButtonOneJustPressed()) { + drawFunction(g2,pressedColor,53,353); + } + if (buttons.isButtonOneHeld()) { + drawFunction(g2,heldColor,53,353); + } + if (buttons.isButtonOneJustReleased()) { + drawFunction(g2, releasedColor, 53, 353); + } + + /* button TWO */ + if (buttons.isButtonTwoJustPressed()) { + drawFunction(g2,pressedColor,53,395); + } + if (buttons.isButtonTwoHeld()) { + drawFunction(g2,heldColor,53,395); + } + if (buttons.isButtonTwoJustReleased()) { + drawFunction(g2,releasedColor,53,395); + } + + /* button A */ + if (buttons.isButtonAJustPressed()) { + drawFunction(g2,pressedColor,53,150); + } + if (buttons.isButtonAHeld()) { + drawFunction(g2,heldColor,53,150); + } + if (buttons.isButtonAJustReleased()) { + drawFunction(g2,releasedColor,53,150); + } + + /* button B */ + if (buttons.isButtonBJustPressed()) { + drawFunction(g2,pressedColor,16,149); + } + if (buttons.isButtonBHeld()) { + drawFunction(g2,heldColor,16,149); + } + if (buttons.isButtonBJustReleased()) { + drawFunction(g2,releasedColor,16,149); + } + + /* button LEFT */ + if (buttons.isButtonLeftJustPressed()) { + drawFunction(g2,pressedColor,33,77); + } + if (buttons.isButtonLeftHeld()) { + drawFunction(g2,heldColor,33,77); + } + if (buttons.isButtonLeftJustReleased()) { + drawFunction(g2,releasedColor,33,77); + } + + /* button RIGHT */ + if (buttons.isButtonRightJustPressed()) { + drawFunction(g2,pressedColor,73,77); + } + if (buttons.isButtonRightHeld()) { + drawFunction(g2,heldColor,73,77); + } + if (buttons.isButtonRightJustReleased()) { + drawFunction(g2,releasedColor,73,77); + } + + /* button UP */ + if (buttons.isButtonUpJustPressed()) { + drawFunction(g2,pressedColor,54,60); + } + if (buttons.isButtonUpHeld()) { + drawFunction(g2,heldColor,54,60); + } + if (buttons.isButtonUpJustReleased()) { + drawFunction(g2,releasedColor,54,60); + } + + /* button DOWN */ + if (buttons.isButtonDownJustPressed()) { + drawFunction(g2,pressedColor,54,97); + } + if (buttons.isButtonDownHeld()) { + drawFunction(g2,heldColor,54,97); + } + if (buttons.isButtonDownJustReleased()) { + drawFunction(g2,releasedColor,54,97); + } + + /* button MINUS */ + if (buttons.isButtonMinusJustPressed()) { + drawFunction(g2,pressedColor,20,230); + } + if (buttons.isButtonMinusHeld()) { + drawFunction(g2,heldColor,20,230); + } + if (buttons.isButtonMinusJustReleased()) { + drawFunction(g2,releasedColor,20,230); + } + + /* button PLUS */ + if (buttons.isButtonPlusJustPressed()) { + drawFunction(g2,pressedColor,86,230); + } + if (buttons.isButtonPlusHeld()) { + drawFunction(g2,heldColor,86,230); + } + if (buttons.isButtonPlusJustReleased()) { + drawFunction(g2,releasedColor,86,230); + } + + /* button HOME */ + if (buttons.isButtonHomeJustPressed()) { + drawFunction(g2,pressedColor,53,230); + } + if (buttons.isButtonHomeHeld()) { + drawFunction(g2,heldColor,53,230); + } + if (buttons.isButtonHomeJustReleased()) { + drawFunction(g2,releasedColor,53,230); + } + + buttons = null; + } + + + //put offscreen image on the screen + g.drawImage(mImage, 0, 0, null); + } + + /** + * Function used to factorize code. + * @param g2 where to draw a shape. + * @param col color to use. + * @param x x coordinates. + * @param y y coordinates. + */ + private void drawFunction(Graphics2D g2, Color col, int x, int y) { + g2.setPaint(col); + g2.translate(x, y); + g2.draw(shape); + g2.fill(shape); + g2.setTransform(new AffineTransform()); + } + + /** + * check if the mImage variable has been initialized. If it's not the case it initializes it + * with the dimensions of the panel. mImage is for double buffering. + */ + private void checkOffScreenImage() { + Dimension d = getSize(); + if (mImage == null || mImage.getWidth(null) != d.width || mImage.getHeight(null) != d.height) { + mImage = createImage(d.width, d.height); + } + } + + public void onButtonsEvent(ButtonsEvent arg0) { + setSize(wiimoteImage.getWidth(this), wiimoteImage.getHeight(this)); + buttons = arg0; + repaint(); + } + + public void onIrEvent(IREvent arg0) { + //nothing + } + + public void onMotionSensingEvent(MotionSensingEvent arg0) { + //nothing + } + + public void onStatusEvent(StatusEvent arg0) { + //nothing + } + + public void onDisconnectionEvent(DisconnectionEvent arg0) { + buttons = null; + repaint(); + } + + /** This method is called from within the constructor to + * initialize the form. + * WARNING: Do NOT modify this code. The content of this method is + * always regenerated by the Form Editor. + */ + // //GEN-BEGIN:initComponents + private void initComponents() { + + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); + this.setLayout(layout); + layout.setHorizontalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGap(0, 400, Short.MAX_VALUE) + ); + layout.setVerticalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGap(0, 300, Short.MAX_VALUE) + ); + }// //GEN-END:initComponents + // Variables declaration - do not modify//GEN-BEGIN:variables + // End of variables declaration//GEN-END:variables +} diff --git a/WiiUseJ_0.1/src/wiiusej/utils/GForcePanel.java b/WiiUseJ_0.1/src/wiiusej/utils/GForcePanel.java new file mode 100644 index 0000000..9802688 --- /dev/null +++ b/WiiUseJ_0.1/src/wiiusej/utils/GForcePanel.java @@ -0,0 +1,201 @@ +/** + * This file is part of WiiuseJ. + * + * WiiuseJ is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * WiiuseJ is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with WiiuseJ. If not, see . + */ +package wiiusej.utils; + +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.Image; +import java.awt.RenderingHints; +import java.awt.geom.AffineTransform; +import java.util.ArrayList; +import wiiusej.values.GForce; +import wiiusej.wiiuseapievents.ButtonsEvent; +import wiiusej.wiiuseapievents.DisconnectionEvent; +import wiiusej.wiiuseapievents.IREvent; +import wiiusej.wiiuseapievents.MotionSensingEvent; +import wiiusej.wiiuseapievents.StatusEvent; +import wiiusej.wiiuseapievents.WiimoteListener; + +/** + * This panel is used to watch gravity force values from a MotionSensingEvent. + * @author guiguito + */ +public class GForcePanel extends javax.swing.JPanel implements WiimoteListener { + + private Image mImage;//image for double buffering + private Color xColor = Color.RED; + private Color yColor = Color.GREEN; + private Color zColor = Color.BLUE; + private Color backgroundColor = Color.WHITE; + private Color lineColor = Color.BLACK; + private ArrayList values = new ArrayList(); + + /** + * Default constructor of the AccelerationPanel. + */ + public GForcePanel() { + initComponents(); + } + + /** + * Constructor used to choose the colors used by the AccelerationPanel. + * @param bgColor background color. + * @param xxColor color of the acceleration on X axis. + * @param yyColor color of the acceleration on Y axis. + * @param zzColor color of the acceleration on Z axis. + * @param lColor line color. + */ + public GForcePanel(Color bgColor, Color xxColor, Color yyColor, Color zzColor, Color lColor) { + backgroundColor = bgColor; + xColor = xxColor; + yColor = yyColor; + zColor = zzColor; + lineColor = lColor; + initComponents(); + } + + @Override + public void paintComponent(Graphics g) { + super.paintComponent(g); + Dimension d = getSize(); + checkOffScreenImage(); + Graphics offG = mImage.getGraphics(); + offG.setColor(backgroundColor); + offG.fillRect(0, 0, d.width, d.height); + Graphics2D g2 = (Graphics2D) mImage.getGraphics(); + g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); + + //draw medium line + double yMiddleFloat = getHeight() / 2.0; + int yMiddle = (int) Math.round(yMiddleFloat); + + g2.setPaint(lineColor); + g2.drawLine(0, yMiddle, getWidth(), yMiddle); + + GForce[] valuesArray = values.toArray(new GForce[0]); + double unit = yMiddleFloat / 5.0; + int previousX = 0; + int previousY = 0; + int previousZ = 0; + //draw curves + for (int i = 0; i < valuesArray.length && i < getWidth(); i++) { + GForce gforce = valuesArray[i]; + //draw X + g2.setPaint(xColor); + int yDelta = (int) Math.round(unit * gforce.getX()); + int y = -1 * yDelta + yMiddle; + g2.drawLine(i - 1, previousX, i, y); + g2.setTransform(new AffineTransform()); + previousX = y; + //draw Y + g2.setPaint(yColor); + yDelta = (int) Math.round(unit * gforce.getY()); + y = -1 * yDelta + yMiddle; + g2.drawLine(i - 1, previousY, i, y); + g2.setTransform(new AffineTransform()); + previousY = y; + //draw Z + g2.setPaint(zColor); + yDelta = (int) Math.round(unit * gforce.getZ()); + y = -1 * yDelta + yMiddle; + g2.drawLine(i - 1, previousZ, i, y); + g2.setTransform(new AffineTransform()); + previousZ = y; + } + + //draw legend + g2.setPaint(xColor); + g2.drawLine(5, getHeight() - 10, 25, getHeight() - 10); + g2.setPaint(yColor); + g2.drawLine(60, getHeight() - 10, 80, getHeight() - 10); + g2.setPaint(zColor); + g2.drawLine(120, getHeight() - 10, 140, getHeight() - 10); + + g2.setPaint(lineColor); + g2.drawString("X", 30, getHeight() - 5); + g2.drawString("Y", 85, getHeight() - 5); + g2.drawString("Z", 145, getHeight() - 5); + g2.drawString("0", 2, yMiddle-5); + g2.drawString("5", 2, 10); + g2.drawString("-5", 2, getHeight()-15); + //put offscreen image on the screen + g.drawImage(mImage, 0, 0, null); + } + + /** + * check if the mImage variable has been initialized. If it's not the case it initializes it + * with the dimensions of the panel. mImage is for double buffering. + */ + private void checkOffScreenImage() { + Dimension d = getSize(); + if (mImage == null || mImage.getWidth(null) != d.width || mImage.getHeight(null) != d.height) { + mImage = createImage(d.width, d.height); + } + } + + public void onButtonsEvent(ButtonsEvent arg0) { + //nothing + } + + public void onIrEvent(IREvent arg0) { + //nothing + } + + public void onMotionSensingEvent(MotionSensingEvent arg0) { + if (values.size() >= getWidth()) { + //if there are as many values as pixels in the width + //clear points + values.clear(); + } + values.add(arg0.getGforce()); + repaint(); + } + + public void onStatusEvent(StatusEvent arg0) { + //nothing + } + + public void onDisconnectionEvent(DisconnectionEvent arg0) { + //Clear points. + values.clear(); + repaint(); + } + + /** This method is called from within the constructor to + * initialize the form. + * WARNING: Do NOT modify this code. The content of this method is + * always regenerated by the Form Editor. + */ + // //GEN-BEGIN:initComponents + private void initComponents() { + + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); + this.setLayout(layout); + layout.setHorizontalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGap(0, 400, Short.MAX_VALUE) + ); + layout.setVerticalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGap(0, 300, Short.MAX_VALUE) + ); + }// //GEN-END:initComponents + // Variables declaration - do not modify//GEN-BEGIN:variables + // End of variables declaration//GEN-END:variables +} diff --git a/WiiUseJ_0.1/src/wiiusej/utils/IRPanel.java b/WiiUseJ_0.1/src/wiiusej/utils/IRPanel.java new file mode 100644 index 0000000..b4213a1 --- /dev/null +++ b/WiiUseJ_0.1/src/wiiusej/utils/IRPanel.java @@ -0,0 +1,192 @@ +/** + * This file is part of WiiuseJ. + * + * WiiuseJ is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * WiiuseJ is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with WiiuseJ. If not, see . + */ +package wiiusej.utils; + +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.Image; +import java.awt.RenderingHints; +import java.awt.Shape; +import java.awt.geom.AffineTransform; +import wiiusej.wiiuseapievents.ButtonsEvent; +import wiiusej.wiiuseapievents.DisconnectionEvent; +import wiiusej.wiiuseapievents.IREvent; +import wiiusej.wiiuseapievents.MotionSensingEvent; +import wiiusej.wiiuseapievents.StatusEvent; +import wiiusej.wiiuseapievents.WiimoteListener; + +/** + * This panel is used to see what the IR camera of the wiimote sees. + * @author guiguito + */ +public class IRPanel extends javax.swing.JPanel implements WiimoteListener { + + private static int MAX_NB_POINTS = 4; + private Color color = Color.YELLOW; + private Color backgroundColor = Color.BLACK; + private Color borderColor = Color.BLUE; + private Shape shape; + private Image mImage;//image for double buffering + private int[] xCoordinates; + private int[] yCoordinates; + private int nbPoints=-1; + + /** + * Default constructor for IR Panel. + * Background color : black. + * IR sources color : yellow. + * Border color of IR sources : blue. + * Shape of the IR sources : circle with a diameter of 10. + */ + public IRPanel() { + shape = new java.awt.geom.Ellipse2D.Double(0, 0, 10, 10); + initArrays(); + initComponents(); + } + + /** + * Constructor used to parameterize the IR panel. + * @param bgColor color. + * @param ptColor IR sources color. + * @param bdColor border color of IR sources. + * @param sh Shape of the IR sources. + */ + public IRPanel(Color bgColor, Color ptColor, Color bdColor, Shape sh) { + backgroundColor = bgColor; + color = ptColor; + borderColor = bdColor; + shape = sh; + initArrays(); + initComponents(); + } + + private void initArrays(){ + xCoordinates = new int[MAX_NB_POINTS]; + yCoordinates = new int[MAX_NB_POINTS]; + for (int i = 0; i < MAX_NB_POINTS; i++) { + xCoordinates[i] = -1; + yCoordinates[i] = -1; + } + } + + @Override + public void paintComponent(Graphics g) { + super.paintComponent(g); + Dimension d = getSize(); + checkOffScreenImage(); + Graphics offG = mImage.getGraphics(); + offG.setColor(backgroundColor); + offG.fillRect(0, 0, d.width, d.height); + Graphics2D g2 = (Graphics2D) mImage.getGraphics(); + g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); + + //draw points + int i = 0; + while (xCoordinates[i] != -1 && yCoordinates[i] != -1 && i < nbPoints) { + double x = xCoordinates[i]; + double y = yCoordinates[i]; + + long xx = getWidth() - Math.round((double) getWidth() * x / 1024.0); + long yy = getHeight() - Math.round((double) getHeight() * y / 768.0); + g2.translate(xx, yy); + + g2.setPaint(borderColor); + g2.draw(shape); + g2.setPaint(color); + g2.fill(shape); + + g2.setTransform(new AffineTransform()); + i++; + } + //put offscreen image on the screen + g.drawImage(mImage, 0, 0, null); + } + + /** + * check if the mImage variable has been initialized. If it's not the case it initializes it + * with the dimensions of the panel. mImage is for double buffering. + */ + private void checkOffScreenImage() { + Dimension d = getSize(); + if (mImage == null || mImage.getWidth(null) != d.width || mImage.getHeight(null) != d.height) { + mImage = createImage(d.width, d.height); + } + } + + public void onButtonsEvent(ButtonsEvent arg0) { + //nothing + } + + public void onIrEvent(IREvent arg0) { + //transfer points + wiiusej.values.IRSource[] points = arg0.getIRPoints(); + nbPoints = points.length; + for (int i = 0; i < points.length; i++) { + xCoordinates[i] = (int) points[i].getRx(); + yCoordinates[i] = (int) points[i].getRy(); + } + for (int i = points.length; i < MAX_NB_POINTS; i++) { + xCoordinates[i] = -1; + yCoordinates[i] = -1; + } + + //redraw panel + repaint(); + } + + public void onMotionSensingEvent(MotionSensingEvent arg0) { + //nothing + } + + public void onStatusEvent(StatusEvent arg0) { + //nothing + } + + public void onDisconnectionEvent(DisconnectionEvent arg0) { + //clear previous points + for (int i = 0; i < MAX_NB_POINTS; i++) { + xCoordinates[i] = -1; + yCoordinates[i] = -1; + } + //redraw panel + repaint(); + } + + /** This method is called from within the constructor to + * initialize the form. + * WARNING: Do NOT modify this code. The content of this method is + * always regenerated by the Form Editor. + */ + // //GEN-BEGIN:initComponents + private void initComponents() { + + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); + this.setLayout(layout); + layout.setHorizontalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGap(0, 400, Short.MAX_VALUE) + ); + layout.setVerticalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGap(0, 300, Short.MAX_VALUE) + ); + }// //GEN-END:initComponents + // Variables declaration - do not modify//GEN-BEGIN:variables + // End of variables declaration//GEN-END:variables +} diff --git a/WiiUseJ_0.1/src/wiiusej/utils/OrientationPanel.java b/WiiUseJ_0.1/src/wiiusej/utils/OrientationPanel.java new file mode 100644 index 0000000..b50a2ce --- /dev/null +++ b/WiiUseJ_0.1/src/wiiusej/utils/OrientationPanel.java @@ -0,0 +1,205 @@ +/** + * This file is part of WiiuseJ. + * + * WiiuseJ is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * WiiuseJ is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with WiiuseJ. If not, see . + */ +package wiiusej.utils; + +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.Image; +import java.awt.RenderingHints; +import java.awt.geom.AffineTransform; +import java.util.ArrayList; +import wiiusej.values.Orientation; +import wiiusej.wiiuseapievents.ButtonsEvent; +import wiiusej.wiiuseapievents.DisconnectionEvent; +import wiiusej.wiiuseapievents.IREvent; +import wiiusej.wiiuseapievents.MotionSensingEvent; +import wiiusej.wiiuseapievents.StatusEvent; +import wiiusej.wiiuseapievents.WiimoteListener; + +/** + * This panel is used to watch orientation values from a MotionSensingEvent. + * @author guiguito + */ +public class OrientationPanel extends javax.swing.JPanel implements WiimoteListener { + + private Image mImage;//image for double buffering + private Color rollColor = Color.RED; + private Color pitchColor = Color.GREEN; + private Color yawColor = Color.BLUE; + private Color backgroundColor = Color.WHITE; + private Color lineColor = Color.BLACK; + private ArrayList values = new ArrayList(); + + /** + * Default constructor. + * Background color : White. + * Roll color : Red. + * Pitch color : Green. + * Yaw color : Blue. + */ + public OrientationPanel() { + initComponents(); + } + + /** + * Constructor used to choose the colors used by the OrientationPanel. + * @param bgColor background color. + * @param rColor roll color. + * @param pColor pitch color. + * @param yColor yaw color. + * @param lColor line color. + */ + public OrientationPanel(Color bgColor, Color rColor, Color pColor, Color yColor, Color lColor) { + backgroundColor = bgColor; + rollColor = rColor; + pitchColor = pColor; + yawColor = yColor; + lineColor = lColor; + initComponents(); + } + + @Override + public void paintComponent(Graphics g) { + super.paintComponent(g); + Dimension d = getSize(); + checkOffScreenImage(); + Graphics offG = mImage.getGraphics(); + offG.setColor(backgroundColor); + offG.fillRect(0, 0, d.width, d.height); + Graphics2D g2 = (Graphics2D) mImage.getGraphics(); + g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); + + //draw medium line + double yMiddleFloat = getHeight() / 2.0; + int yMiddle = (int) Math.round(yMiddleFloat); + + g2.setPaint(lineColor); + g2.drawLine(0, yMiddle, getWidth(), yMiddle); + + Orientation[] valuesArray = values.toArray(new Orientation[0]); + double unit = yMiddleFloat / 180.0; + int previousRoll = 0; + int previousPitch = 0; + int previousYaw = 0; + //draw curves + for (int i = 0; i < valuesArray.length && i < getWidth(); i++) { + Orientation orientation = valuesArray[i]; + //draw roll + g2.setPaint(rollColor); + int yDelta = (int) Math.round(unit * orientation.getRoll()); + int y = -1 * yDelta + yMiddle; + g2.drawLine(i-1, previousRoll, i, y); + g2.setTransform(new AffineTransform()); + previousRoll = y; + //draw pitch + g2.setPaint(pitchColor); + yDelta = (int) Math.round(unit * orientation.getPitch()); + y = -1 * yDelta + yMiddle; + g2.drawLine(i-1, previousPitch, i, y); + g2.setTransform(new AffineTransform()); + previousPitch = y; + //draw yaw + g2.setPaint(yawColor); + yDelta = (int) Math.round(unit * orientation.getYaw()); + y = -1 * yDelta + yMiddle; + g2.drawLine(i-1, previousYaw, i, y); + g2.setTransform(new AffineTransform()); + previousYaw = y; + } + + //draw legend + g2.setPaint(rollColor); + g2.drawLine(5, getHeight()-10, 25, getHeight()-10); + g2.setPaint(pitchColor); + g2.drawLine(60, getHeight()-10, 80, getHeight()-10); + g2.setPaint(yawColor); + g2.drawLine(120, getHeight()-10, 140, getHeight()-10); + + g2.setPaint(lineColor); + g2.drawString("Roll", 30, getHeight()-5); + g2.drawString("Pitch", 85, getHeight()-5); + g2.drawString("Yaw", 145, getHeight()-5); + g2.drawString("0", 2, yMiddle-5); + g2.drawString("180", 2, 10); + g2.drawString("-180", 2, getHeight()-15); + //put offscreen image on the screen + g.drawImage(mImage, 0, 0, null); + } + + /** + * check if the mImage variable has been initialized. If it's not the case it initializes it + * with the dimensions of the panel. mImage is for double buffering. + */ + private void checkOffScreenImage() { + Dimension d = getSize(); + if (mImage == null || mImage.getWidth(null) != d.width || mImage.getHeight(null) != d.height) { + mImage = createImage(d.width, d.height); + } + } + + public void onButtonsEvent(ButtonsEvent arg0) { + //nothing + } + + public void onIrEvent(IREvent arg0) { + //nothing + } + + public void onMotionSensingEvent(MotionSensingEvent arg0) { + if (values.size() >= getWidth()) { + //if there are as many values as pixels in the width + //clear points + values.clear(); + } + values.add(arg0.getOrientation()); + repaint(); + } + + public void onStatusEvent(StatusEvent arg0) { + //nothing + } + + public void onDisconnectionEvent(DisconnectionEvent arg0) { + //Clear points. + values.clear(); + repaint(); + } + + /** This method is called from within the constructor to + * initialize the form. + * WARNING: Do NOT modify this code. The content of this method is + * always regenerated by the Form Editor. + */ + // //GEN-BEGIN:initComponents + private void initComponents() { + + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); + this.setLayout(layout); + layout.setHorizontalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGap(0, 400, Short.MAX_VALUE) + ); + layout.setVerticalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGap(0, 300, Short.MAX_VALUE) + ); + }// //GEN-END:initComponents + // Variables declaration - do not modify//GEN-BEGIN:variables + // End of variables declaration//GEN-END:variables +} diff --git a/WiiUseJ_0.1/src/wiiusej/values/GForce.java b/WiiUseJ_0.1/src/wiiusej/values/GForce.java new file mode 100644 index 0000000..9732121 --- /dev/null +++ b/WiiUseJ_0.1/src/wiiusej/values/GForce.java @@ -0,0 +1,75 @@ +/** + * This file is part of WiiuseJ. + * + * WiiuseJ is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * WiiuseJ is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with WiiuseJ. If not, see . + */ +package wiiusej.values; + +/** + * Represents gravity force on each axis. + * @author guiguito + */ +public class GForce { + + private float x; + private float y; + private float z; + + /** + * Default constructor; + */ + public GForce(){ + x = 0; + y = 0; + z = 0; + } + + /** + * Constructor with gravity force on each axis. + * @param xx x value + * @param yy x value + * @param zz x value + */ + public GForce(float xx, float yy, float zz){ + x = xx; + y = yy; + z = zz; + } + + /** + * @return the x + */ + public float getX() { + return x; + } + + /** + * @return the y + */ + public float getY() { + return y; + } + + /** + * @return the z + */ + public float getZ() { + return z; + } + + @Override + public String toString() { + return "Gravity force : ("+x+", "+y+","+z+")"; + } +} diff --git a/WiiUseJ_0.1/src/wiiusej/values/IRSource.java b/WiiUseJ_0.1/src/wiiusej/values/IRSource.java new file mode 100644 index 0000000..7caef55 --- /dev/null +++ b/WiiUseJ_0.1/src/wiiusej/values/IRSource.java @@ -0,0 +1,109 @@ +/** + * This file is part of WiiuseJ. + * + * WiiuseJ is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * WiiuseJ is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with WiiuseJ. If not, see . + */ +package wiiusej.values; + +/** + * Class used for IR sources. + * @author guiguito + */ +public class IRSource{ + + private int x; + private int y; + private short rx; + private short ry; + private short size; + + /** + * Build an IR source with all details. + * + * @param xx + * xx interpolated coordinates. + * @param yy + * yy interpolated coordinates. + * @param rxx + * raw X coordinate (0-1023). + * @param ryy + * raw Y coordinate (0-1023). + * @param si + * size of the IR dot (0-15). + */ + public IRSource(int xx, int yy, short rxx, short ryy, short si) { + x = xx; + y = yy; + rx = rxx; + ry = ryy; + size = si; + } + + + /** + * Return x interpolated coordinates. + * @return the x + */ + public int getX() { + return x; + } + + + + /** + * Return y interpolated coordinates. + * @return the y + */ + public int getY() { + return y; + } + + + + /** + * Return raw X coordinate (0-1023). + * @return the rx + */ + public short getRx() { + return rx; + } + + + + /** + * Return raw Y coordinate (0-1023). + * @return the ry + */ + public short getRy() { + return ry; + } + + + + /** + * Return size of the IR dot (0-15). + * @return the size + */ + public short getSize() { + return size; + } + + + + @Override + public String toString() { + return "Interpolated coordinates ("+x+","+y+"), Raw coordinates("+rx+","+ry+"), source size : "+size+")"; + } + +} diff --git a/WiiUseJ_0.1/src/wiiusej/values/Orientation.java b/WiiUseJ_0.1/src/wiiusej/values/Orientation.java new file mode 100644 index 0000000..4c4f741 --- /dev/null +++ b/WiiUseJ_0.1/src/wiiusej/values/Orientation.java @@ -0,0 +1,76 @@ +/** + * This file is part of WiiuseJ. + * + * WiiuseJ is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * WiiuseJ is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with WiiuseJ. If not, see . + */ +package wiiusej.values; + +/** + * Class that represents the orientation of the wiimote. + * @author guiguito + */ +public class Orientation { + + private float roll; + private float pitch; + private float yaw; + + /** + * Default constructor. + */ + public Orientation(){ + roll = 0; + pitch = 0; + yaw = 0; + } + + /** + * Contructor with raw, pitch , yaw. + * @param r raw + * @param p pitch + * @param y yaw + */ + public Orientation(float r, float p, float y){ + roll = r; + pitch = p; + yaw = y; + } + + /** + * @return the roll + */ + public float getRoll() { + return roll; + } + + /** + * @return the pitch + */ + public float getPitch() { + return pitch; + } + + /** + * @return the yaw + */ + public float getYaw() { + return yaw; + } + + @Override + public String toString() { + return "Orientation : (roll: "+roll+", pitch: "+pitch+", yaw: "+yaw+")"; + } + +} diff --git a/WiiUseJ_0.1/src/wiiusej/values/RawAcceleration.java b/WiiUseJ_0.1/src/wiiusej/values/RawAcceleration.java new file mode 100644 index 0000000..903a51c --- /dev/null +++ b/WiiUseJ_0.1/src/wiiusej/values/RawAcceleration.java @@ -0,0 +1,75 @@ +/** + * This file is part of WiiuseJ. + * + * WiiuseJ is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * WiiuseJ is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with WiiuseJ. If not, see . + */ +package wiiusej.values; + +/** + * Represents raw acceleration on each axis. + * @author guiguito + */ +public class RawAcceleration { + + private short x; + private short y; + private short z; + + /** + * Default constructor; + */ + public RawAcceleration() { + x = 0; + y = 0; + z = 0; + } + + /** + * Constructor with raw acceleration on each axis. + * @param xx x value + * @param yy x value + * @param zz x value + */ + public RawAcceleration(short xx, short yy, short zz) { + x = xx; + y = yy; + z = zz; + } + + /** + * @return the x + */ + public short getX() { + return x; + } + /** + * @return the y + */ + public short getY() { + return y; + } + + /** + * @return the z + */ + public short getZ() { + return z; + } + + @Override + public String toString() { + return "Raw acceleration : ("+x+", "+y+","+z+")"; + } + +} diff --git a/WiiUseJ_0.1/src/wiiusej/wiiuseapievents/ButtonsEvent.java b/WiiUseJ_0.1/src/wiiusej/wiiuseapievents/ButtonsEvent.java new file mode 100644 index 0000000..ce78551 --- /dev/null +++ b/WiiUseJ_0.1/src/wiiusej/wiiuseapievents/ButtonsEvent.java @@ -0,0 +1,335 @@ +/** + * This file is part of WiiuseJ. + * + * WiiuseJ is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * WiiuseJ is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with WiiuseJ. If not, see . + */ +package wiiusej.wiiuseapievents; + +/** + * Class which represents a buttons event. + * @author guiguito + */ +public class ButtonsEvent extends WiimoteEvent{ + + /* Buttons MACRO */ + private static short WIIMOTE_BUTTON_TWO = 0x0001; + private static short WIIMOTE_BUTTON_ONE = 0x0002; + private static short WIIMOTE_BUTTON_B = 0x0004; + private static short WIIMOTE_BUTTON_A = 0x0008; + private static short WIIMOTE_BUTTON_MINUS = 0x0010; + private static short WIIMOTE_BUTTON_ZACCEL_BIT6 = 0x0020; + private static short WIIMOTE_BUTTON_ZACCEL_BIT7 = 0x0040; + private static short WIIMOTE_BUTTON_HOME = 0x0080; + private static short WIIMOTE_BUTTON_LEFT = 0x0100; + private static short WIIMOTE_BUTTON_RIGHT = 0x0200; + private static short WIIMOTE_BUTTON_DOWN = 0x0400; + private static short WIIMOTE_BUTTON_UP = 0x0800; + private static short WIIMOTE_BUTTON_PLUS = 0x1000; + private static short WIIMOTE_BUTTON_ZACCEL_BIT4 = 0x2000; + private static short WIIMOTE_BUTTON_ZACCEL_BIT5 = 0x4000; + private static int WIIMOTE_BUTTON_UNKNOWN = 0x8000; + private static short WIIMOTE_BUTTON_ALL = 0x1F9F; + + /* Buttons */ + private short buttonsJustPressed = 0; + private short buttonsJustReleased = 0; + private short buttonsHeld = 0; + + /** + * Constructor of the button Event. + * @param id id of the wiimote concerned. + * @param buttonsJustPressed buttons just pressed. + * @param buttonsJustReleased buttons just released. + * @param buttonsHeld buttons just held. + */ + public ButtonsEvent(int id, short buttonsJustPressed, + short buttonsJustReleased, short buttonsHeld){ + super(id); + setAllButtons(buttonsJustPressed, buttonsJustReleased, buttonsHeld); + } + + /** + * Set all buttons in one method. + * + * @param buttonsJustPressed + * @param buttonsJustReleased + * @param buttonsHeld + */ + private void setAllButtons(short buttonsJustPressed, + short buttonsJustReleased, short buttonsHeld) { + this.buttonsJustPressed = buttonsJustPressed; + this.buttonsJustReleased = buttonsJustReleased; + this.buttonsHeld = buttonsHeld; + } + + /** + * Get the short storing the buttons just pressed + * + * @return the short storing the buttons just pressed + */ + public short getButtonsJustPressed() { + return buttonsJustPressed; + } + + /** + * Get the short storing the buttons just released + * + * @return the short storing the buttons just released + */ + public short getButtonsJustReleased() { + return buttonsJustReleased; + } + + /** + * get the short storing the buttons held + * + * @return the short storing the buttons held + */ + public short getButtonsHeld() { + return buttonsHeld; + } + + /** **************** BUTTONS Methods ***************** */ + /* generic button functions */ + + private boolean buttonTest(short buttonBitsDefinition, short buttons) { + return (buttons & buttonBitsDefinition) == buttonBitsDefinition; + } + + private boolean isButtonJustPressed(short buttonBitsDefinition) { + return buttonTest(buttonBitsDefinition, buttonsJustPressed) + && !isButtonHeld(buttonBitsDefinition); + } + + private boolean isButtonJustReleased(short buttonBitsDefinition) { + return buttonTest(buttonBitsDefinition, buttonsJustReleased); + } + + private boolean isButtonHeld(short buttonBitsDefinition) { + return buttonTest(buttonBitsDefinition, buttonsHeld); + } + + private boolean isButtonPressed(short buttonBitsDefinition) { + return isButtonHeld(buttonBitsDefinition)||isButtonJustPressed(buttonBitsDefinition); + } + /* Button ONE */ + + public boolean isButtonOneJustPressed() { + return isButtonJustPressed(WIIMOTE_BUTTON_ONE); + } + + public boolean isButtonOneJustReleased() { + return isButtonJustReleased(WIIMOTE_BUTTON_ONE); + } + + public boolean isButtonOneHeld() { + return isButtonHeld(WIIMOTE_BUTTON_ONE); + } + + public boolean isButtonOnePressed() { + return isButtonPressed(WIIMOTE_BUTTON_ONE); + } + + /* Button TWO */ + + public boolean isButtonTwoJustPressed() { + return isButtonJustPressed(WIIMOTE_BUTTON_TWO); + } + + public boolean isButtonTwoJustReleased() { + return isButtonJustReleased(WIIMOTE_BUTTON_TWO); + } + + public boolean isButtonTwoHeld() { + return isButtonHeld(WIIMOTE_BUTTON_TWO); + } + + public boolean isButtonTwoPressed() { + return isButtonPressed(WIIMOTE_BUTTON_TWO); + } + + /* Button A */ + + public boolean isButtonAJustPressed() { + return isButtonJustPressed(WIIMOTE_BUTTON_A); + } + + public boolean isButtonAJustReleased() { + return isButtonJustReleased(WIIMOTE_BUTTON_A); + } + + public boolean isButtonAHeld() { + return isButtonHeld(WIIMOTE_BUTTON_A); + } + + public boolean isButtonAPressed() { + return isButtonPressed(WIIMOTE_BUTTON_A); + } + + /* Button B */ + + public boolean isButtonBJustPressed() { + return isButtonJustPressed(WIIMOTE_BUTTON_B); + } + + public boolean isButtonBJustReleased() { + return isButtonJustReleased(WIIMOTE_BUTTON_B); + } + + public boolean isButtonBHeld() { + return isButtonHeld(WIIMOTE_BUTTON_B); + } + + public boolean isButtonBPressed() { + return isButtonPressed(WIIMOTE_BUTTON_B); + } + + /* Button LEFT */ + + public boolean isButtonLeftJustPressed() { + return isButtonJustPressed(WIIMOTE_BUTTON_LEFT); + } + + public boolean isButtonLeftJustReleased() { + return isButtonJustReleased(WIIMOTE_BUTTON_LEFT); + } + + public boolean isButtonLeftHeld() { + return isButtonHeld(WIIMOTE_BUTTON_LEFT); + } + + public boolean isButtonLeftPressed() { + return isButtonPressed(WIIMOTE_BUTTON_LEFT); + } + + /* Button RIGHT */ + + public boolean isButtonRightJustPressed() { + return isButtonJustPressed(WIIMOTE_BUTTON_RIGHT); + } + + public boolean isButtonRightJustReleased() { + return isButtonJustReleased(WIIMOTE_BUTTON_RIGHT); + } + + public boolean isButtonRightHeld() { + return isButtonHeld(WIIMOTE_BUTTON_RIGHT); + } + + public boolean isButtonRightPressed() { + return isButtonPressed(WIIMOTE_BUTTON_RIGHT); + } + + /* Button UP */ + + public boolean isButtonUpJustPressed() { + return isButtonJustPressed(WIIMOTE_BUTTON_UP); + } + + public boolean isButtonUpJustReleased() { + return isButtonJustReleased(WIIMOTE_BUTTON_UP); + } + + public boolean isButtonUpHeld() { + return isButtonHeld(WIIMOTE_BUTTON_UP); + } + + public boolean isButtonUpPressed() { + return isButtonPressed(WIIMOTE_BUTTON_UP); + } + + /* Button DOWN */ + + public boolean isButtonDownJustPressed() { + return isButtonJustPressed(WIIMOTE_BUTTON_DOWN); + } + + public boolean isButtonDownJustReleased() { + return isButtonJustReleased(WIIMOTE_BUTTON_DOWN); + } + + public boolean isButtonDownHeld() { + return isButtonHeld(WIIMOTE_BUTTON_DOWN); + } + + public boolean isButtonDownPressed() { + return isButtonPressed(WIIMOTE_BUTTON_DOWN); + } + + /* Button - */ + + public boolean isButtonMinusJustPressed() { + return isButtonJustPressed(WIIMOTE_BUTTON_MINUS); + } + + public boolean isButtonMinusJustReleased() { + return isButtonJustReleased(WIIMOTE_BUTTON_MINUS); + } + + public boolean isButtonMinusHeld() { + return isButtonHeld(WIIMOTE_BUTTON_MINUS); + } + + public boolean isButtonMinusPressed() { + return isButtonPressed(WIIMOTE_BUTTON_MINUS); + } + + /* Button + */ + + public boolean isButtonPlusJustPressed() { + return isButtonJustPressed(WIIMOTE_BUTTON_PLUS); + } + + public boolean isButtonPlusJustReleased() { + return isButtonJustReleased(WIIMOTE_BUTTON_PLUS); + } + + public boolean isButtonPlusHeld() { + return isButtonHeld(WIIMOTE_BUTTON_PLUS); + } + + public boolean isButtonPlusPressed() { + return isButtonPressed(WIIMOTE_BUTTON_PLUS); + } + + /* Button HOME */ + + public boolean isButtonHomeJustPressed() { + return isButtonJustPressed(WIIMOTE_BUTTON_HOME); + } + + public boolean isButtonHomeJustReleased() { + return isButtonJustReleased(WIIMOTE_BUTTON_HOME); + } + + public boolean isButtonHomeHeld() { + return isButtonHeld(WIIMOTE_BUTTON_HOME); + } + + public boolean isButtonHomePressed() { + return isButtonPressed(WIIMOTE_BUTTON_HOME); + } + + @Override + public String toString() { + String out = ""; + /* Display buttons */ + out += "/******** Buttons ********/\n"; + out += "--- Buttons just pressed : " + buttonsJustPressed + "\n"; + out += "--- Buttons just released : " + buttonsJustReleased + "\n"; + out += "--- Buttons held : " + buttonsHeld + "\n"; + return out; + } + +} diff --git a/WiiUseJ_0.1/src/wiiusej/wiiuseapievents/DisconnectionEvent.java b/WiiUseJ_0.1/src/wiiusej/wiiuseapievents/DisconnectionEvent.java new file mode 100644 index 0000000..341b626 --- /dev/null +++ b/WiiUseJ_0.1/src/wiiusej/wiiuseapievents/DisconnectionEvent.java @@ -0,0 +1,44 @@ +/** + * This file is part of WiiuseJ. + * + * WiiuseJ is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * WiiuseJ is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with WiiuseJ. If not, see . + */ +package wiiusej.wiiuseapievents; + +/** + * Class representing a disconnection event. + * @author guiguito + */ +public class DisconnectionEvent extends WiiUseApiEvent { + + /** + * Construct the DisconnectionEvent setting up the id. + * + * @param id + * the Wiimote id + */ + public DisconnectionEvent(int id) { + super(id,WiiUseApiEvent.DISCONNECTION_EVENT); + } + + @Override + public String toString() { + String out = ""; + /* Status */ + out += "/*********** DISCONNECTION EVENT : WIIMOTE ID :" + super.getWiimoteId() + " ********/\n"; + + return out; + } + +} diff --git a/WiiUseJ_0.1/src/wiiusej/wiiuseapievents/EventsGatherer.java b/WiiUseJ_0.1/src/wiiusej/wiiuseapievents/EventsGatherer.java new file mode 100644 index 0000000..5c83d78 --- /dev/null +++ b/WiiUseJ_0.1/src/wiiusej/wiiuseapievents/EventsGatherer.java @@ -0,0 +1,241 @@ +/** + * This file is part of WiiuseJ. + * + * WiiuseJ is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * WiiuseJ is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with WiiuseJ. If not, see . + */ +package wiiusej.wiiuseapievents; + +/** + * This class is used to gather events during a call to the Wiiuse API. + * + * @author guiguito + */ +public class EventsGatherer { + + private WiiUseApiEvent[] events; + private int index = 0; + private GenericEvent genericEvent = null; + + /** + * Create EventsGatherer. + * + * @param nbWiimotes + * nb wiimotes (nb a of events possible in a call to Wiiuse API) + */ + public EventsGatherer(int nbWiimotes) { + events = new WiiUseApiEvent[nbWiimotes]; + } + + /** + * Add an event to the array. + * + * @param e + * the event to add. + */ + private void addEvent(WiiUseApiEvent e) { + events[index] = e; + index++; + } + + /** + * Prepare a wiimote event to add. + * + * @param id + * id of the wiimote. + * @param buttonsJustPressed + * buttons just pressed + * @param buttonsJustReleased + * buttons just released + * @param buttonsHeld + * buttons held + */ + public void prepareWiiMoteEvent(int id, short buttonsJustPressed, + short buttonsJustReleased, short buttonsHeld) { + genericEvent = new GenericEvent(id, buttonsJustPressed, + buttonsJustReleased, buttonsHeld); + } + + /** + * Prepare an IR event to populate. + * + * @param x + * calculated X coordinate. + * @param y + * calculated Y coordinate. + * @param z + * calculated distance. + * @param ax + * absolute X coordinate. + * @param ay + * absolute Y coordinate + * @param xVRes + * IR virtual screen x resolution. + * @param yVRes + * IR virtual screen y resolution. + * @param xOffset + * IR X correction offset. + * @param yOffset + * IR Y correction offset. + * @param sensorBarPostion + * aspect ratio of the screen. + * @param screenAsPectRatio + * IR sensor bar position. + */ + public void prepareIRevent(int x, int y, int z, int ax, int ay, int xVRes, + int yVRes, int xOffset, int yOffset, short sensorBarPostion, + short screenAsPectRatio) { + genericEvent.prepareIRevent(x, y, z, ax, ay, xVRes, yVRes, xOffset, + yOffset, sensorBarPostion, screenAsPectRatio); + + } + + /** + * Add an IR point to the WiiMoteEvent prepared + * + * @param x + * x coordinates + * @param y + * y coordinates + * @param rx + * raw X coordinate (0-1023). + * @param ry + * raw Y coordinate (0-1023). + * @param size + * size of the IR dot (0-15). + */ + public void addIRPointToPreparedWiiMoteEvent(int x, int y, short rx, + short ry, short size) { + if (genericEvent != null) { + genericEvent.addIRpoint(x, y, rx, ry, size); + } + } + + /** + * Set orientation and gravity force of the prepared event. + * + * @param orientationThreshold + * value of the minimum angle between two events with the + * accelerometer + * @param accelerationThreshold + * value of the value variation between two events with the + * accelerometer + * @param smoothingState + * true if smoothing flag is activated + * @param alphaSmooth + * value of the alpha smoothing parameter + * @param r + * roll + * @param p + * pitch + * @param ya + * yaw + * @param x + * gravity force on x axis + * @param y + * gravity force on y axis + * @param z + * gravity force on z axis + * @param xx + * raw acceleration on x axis + * @param yy + * raw acceleration on y axis + * @param zz + * raw acceleration on z axis + */ + public void addMotionSensingValues(float orientationThreshold, + int accelerationThreshold, boolean smoothingState, + float alphaSmooth, float r, float p, float ya, float x, float y, + float z, short xx, short yy, short zz) { + if (genericEvent != null) { + genericEvent.setMotionSensingEvent(orientationThreshold, + accelerationThreshold, smoothingState, alphaSmooth, r, p, + ya, x, y, z, xx, yy, zz); + } + } + + /** + * Add the prepared WiimoteEvent to the gatherer. + */ + public void addWiimoteEvent() { + if (genericEvent != null) { + addEvent(genericEvent); + genericEvent = null; + } + } + + /** + * Add a StatusEvent to the gatherer. + * + * @param id + * id of the wiimote + * @param connect + * true if the wiimote is connected + * @param batt + * battery level + * @param led + * status of leds + * @param speak + * speakers status + * @param attach + * attachment status + * @param rumbleState + * true if rumble is active + * @param continuousState + * true if continuous flag is activated + * @param irState + * true if ir is active + * @param motionSensingState + * true if accelerometer is active + */ + public void addStatusEvent(int id, boolean connect, float batt, short led, + boolean speak, int attach, boolean rumbleState, + boolean continuousState, boolean irState, boolean motionSensingState) { + StatusEvent evt = new StatusEvent(id, connect, batt, led, speak, + attach, rumbleState, continuousState, irState, + motionSensingState); + addEvent(evt); + } + + /** + * Add a DisconnectionEvent to the gatherer. + * + * @param id + * id of the wiimote + */ + public void addDisconnectionEvent(int id) { + DisconnectionEvent evt = new DisconnectionEvent(id); + addEvent(evt); + } + + /** + * Return an array containing the events. + * + * @return events received + */ + public WiiUseApiEvent[] getEvents() { + return java.util.Arrays.copyOfRange(events, 0, index); + } + + /** + * Clear the gatherer and remove objects. + */ + public void clearEvents() { + for (int i = 0; i < events.length; i++) { + events[i] = null; + } + genericEvent = null; + index = 0; + } + +} diff --git a/WiiUseJ_0.1/src/wiiusej/wiiuseapievents/GenericEvent.java b/WiiUseJ_0.1/src/wiiusej/wiiuseapievents/GenericEvent.java new file mode 100644 index 0000000..e8ea39b --- /dev/null +++ b/WiiUseJ_0.1/src/wiiusej/wiiuseapievents/GenericEvent.java @@ -0,0 +1,227 @@ +/** + * This file is part of WiiuseJ. + * + * WiiuseJ is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * WiiuseJ is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with WiiuseJ. If not, see . + */ +package wiiusej.wiiuseapievents; + +/** + * Class that is a bean to be filled by the wiiuse API. + * + * @author guiguito + */ +public class GenericEvent extends WiiUseApiEvent { + + ButtonsEvent buttonsEvent = null; + IREvent infraredEvent = null; + MotionSensingEvent motionSensingEvent = null; + + /** + * Construct the Wiimote setting up the id. + * + * @param id + * the Wiimote id + */ + public GenericEvent(int id) { + super(id, WiiUseApiEvent.GENERIC_EVENT); + } + + /** + * Construct the Wiimote setting up the id and the buttons. + * + * @param id + * the Wiimote id + * @param buttonsJustPressed + * buttons just pressed + * @param buttonsJustReleased + * buttons just released + * @param buttonsHeld + * buttons held + */ + public GenericEvent(int id, short buttonsJustPressed, + short buttonsJustReleased, short buttonsHeld) { + super(id, WiiUseApiEvent.GENERIC_EVENT); + buttonsEvent = new ButtonsEvent(id, buttonsJustPressed, + buttonsJustReleased, buttonsHeld); + } + + /** + * Tell if there is an IR Event. + * + * @return TRUE if there is an IR event. + */ + public boolean isThereIrEvent() { + return infraredEvent != null; + } + + /** + * Tell if there is a motion sensing Event. + * + * @return TRUE if there is a motion sensing event. + */ + public boolean isThereMotionSensingEvent() { + return motionSensingEvent != null; + } + + /** + * Get buttons event. + * + * @return the buttons event. + */ + public ButtonsEvent getButtonsEvent() { + return buttonsEvent; + } + + /** + * Get IR event. + * + * @return the IR event if there is one or null. + */ + public IREvent getIREvent() { + return infraredEvent; + } + + /** + * Get motion sensing event. + * + * @return the motion sensing event if there is one or null. + */ + public MotionSensingEvent getMotionSensingEvent() { + return motionSensingEvent; + } + + /** + * Prepare an IR event to populate. + * + * @param x + * calculated X coordinate. + * @param y + * calculated Y coordinate. + * @param z + * calculated distance. + * @param ax + * absolute X coordinate. + * @param ay + * absolute Y coordinate + * @param xVRes + * IR virtual screen x resolution. + * @param yVRes + * IR virtual screen y resolution. + * @param xOffset + * IR X correction offset. + * @param yOffset + * IR Y correction offset. + * @param sensorBarPostion + * aspect ratio of the screen. + * @param screenAsPectRatio + * IR sensor bar position. + */ + public void prepareIRevent(int x, int y, int z, int ax, int ay, int xVRes, + int yVRes, int xOffset, int yOffset, short sensorBarPostion, + short screenAsPectRatio) { + if (infraredEvent == null) { + infraredEvent = new IREvent(getWiimoteId(), x, y, z, ax, ay, xVRes, + yVRes, xOffset, yOffset, sensorBarPostion, + screenAsPectRatio); + } + } + + /** + * Add an IR point to the generic event. Create an IR Event if it's not + * created yet. + * + * @param x + * x coordinates. + * @param y + * y coordinates + * @param rx + * raw X coordinate (0-1023). + * @param ry + * raw Y coordinate (0-1023). + * @param size + * size of the IR dot (0-15). + */ + public void addIRpoint(int x, int y, short rx, short ry, short size) { + if (infraredEvent != null) + infraredEvent.addIRpoint(x, y, rx, ry, size); + } + + /** + * Set the Motion Sensing Event. + * + * @param orientationThreshold + * value of the minimum angle between two events with the + * accelerometer + * @param accelerationThreshold + * value of the value variation between two events with the + * accelerometer + * @param smoothingState + * true if smoothing flag is activated + * @param alphaSmooth + * value of the alpha smoothing parameter + * @param r + * roll + * @param p + * pitch + * @param ya + * yaw + * @param x + * gravity force on x axis + * @param y + * gravity force on y axis + * @param z + * gravity force on z axis + * @param xx + * raw acceleration on x axis + * @param yy + * raw acceleration on y axis + * @param zz + * raw acceleration on z axis + */ + public void setMotionSensingEvent(float orientationThreshold, + int accelerationThreshold, boolean smoothingState, + float alphaSmooth, float r, float p, float ya, float x, float y, + float z, short xx, short yy, short zz) { + motionSensingEvent = new MotionSensingEvent(getWiimoteId(), + orientationThreshold, accelerationThreshold, smoothingState, + alphaSmooth, r, p, ya, x, y, z, xx, yy, zz); + } + + @Override + public String toString() { + String out = ""; + /* Status */ + out += "/*********** GENERIC EVENT : WIIMOTE ID :" + + super.getWiimoteId() + " ********/\n"; + + out += buttonsEvent; + + if (infraredEvent != null) { + out += infraredEvent; + } else { + out += "/******** IR Tracking ********/\n"; + out += "--- Active : false\n"; + } + + if (motionSensingEvent != null) { + out += motionSensingEvent; + } else { + out += "/******** Motion sensing ********/\n"; + out += "--- Motion sensing : false \n"; + } + + return out; + } + +} diff --git a/WiiUseJ_0.1/src/wiiusej/wiiuseapievents/IREvent.java b/WiiUseJ_0.1/src/wiiusej/wiiuseapievents/IREvent.java new file mode 100644 index 0000000..6007e97 --- /dev/null +++ b/WiiUseJ_0.1/src/wiiusej/wiiuseapievents/IREvent.java @@ -0,0 +1,285 @@ +/** + * This file is part of WiiuseJ. + * + * WiiuseJ is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * WiiuseJ is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with WiiuseJ. If not, see . + */ +package wiiusej.wiiuseapievents; + +import wiiusej.values.IRSource; + +/** + * Class which represents an IR event. + * + * @author guiguito + */ +public class IREvent extends WiimoteEvent { + + /* IR Tracking */ + private IRSource[] IRPoints; + private short indexPoints = 0; + private int x; + private int y; + private int z;// distance from the sensor bar + private int ax; + private int ay; + private int xVRes; + private int yVRes; + private int xOffset; + private int yOffset; + private short sensorBarPostion; + private short screenAsPectRatio; + + static private short WIIUSE_IR_ABOVE = 0; + static private short WIIUSE_IR_BELOW = 1; + static private short WIIUSE_SCREEN_RATIO_4_3 = 0; + static private short WIIUSE_SCREEN_RATIO_16_9 = 1; + + private static short NB_POINTS = 4;// number of points IR can track + + /** + * Constructor of IREvent with full infos. + * + * @param id + * d of the wiimote concerned. + * @param x + * calculated X coordinate. + * @param y + * calculated Y coordinate. + * @param z + * calculated distance. + * @param ax + * absolute X coordinate. + * @param ay + * absolute Y coordinate + * @param xVRes + * IR virtual screen x resolution. + * @param yVRes + * IR virtual screen y resolution. + * @param xOffset + * IR X correction offset. + * @param yOffset + * IR Y correction offset. + * @param sensorBarPostion + * aspect ratio of the screen. + * @param screenAsPectRatio + * IR sensor bar position. + */ + public IREvent(int id, int x, int y, int z, int ax, int ay, int xVRes, + int yVRes, int xOffset, int yOffset, short sensorBarPostion, + short screenAsPectRatio) { + super(id); + this.x = x; + this.y = y; + this.z = z; + this.ax = ax; + this.ay = ay; + this.xVRes = xVRes; + this.yVRes = yVRes; + this.xOffset = xOffset; + this.yOffset = yOffset; + this.sensorBarPostion = sensorBarPostion; + this.screenAsPectRatio = screenAsPectRatio; + IRPoints = new IRSource[NB_POINTS]; + } + + /** + * Get list of IR points. + * + * @return the list of 2D points + */ + public IRSource[] getIRPoints() { + return java.util.Arrays.copyOfRange(IRPoints, 0, indexPoints); + } + + /** + * Add IR Point in the list (Max 4 points) + * + * @param x + * x value + * @param y + * y value + * @param rx + * raw X coordinate (0-1023). + * @param ry + * raw Y coordinate (0-1023). + * @param size + * size of the IR dot (0-15). + */ + public void addIRpoint(int x, int y, short rx, short ry, short size) { + IRPoints[indexPoints] = new IRSource(x, y, rx, ry, size); + indexPoints++; + return; + } + + /** + * Return calculated X coordinate. + * + * @return the x + */ + public int getX() { + return x; + } + + /** + * Return calculated Y coordinate. + * + * @return the y + */ + public int getY() { + return y; + } + + /** + * Return calculated distance. + * + * @return the z + */ + public int getZ() { + return z; + } + + /** + * Return absolute X coordinate. + * + * @return the ax + */ + public int getAx() { + return ax; + } + + /** + * Return absolute Y coordinate. + * + * @return the ay + */ + public int getAy() { + return ay; + } + + /** + * Return IR virtual screen x resolution. + * + * @return the xVRes + */ + public int getXVRes() { + return xVRes; + } + + /** + * Return IR virtual screen y resolution. + * + * @return the yVRes + */ + public int getYVRes() { + return yVRes; + } + + /** + * Return IR X correction offset. + * + * @return the xOffset + */ + public int getXOffset() { + return xOffset; + } + + /** + * Return IR Y correction offset. + * + * @return the yOffset + */ + public int getYOffset() { + return yOffset; + } + + /** + * Return true if the sensor bar is above. + * + * @return true if the sensor bar is above. + */ + public boolean isSensorBarAbove() { + return sensorBarPostion == WIIUSE_IR_ABOVE; + } + + /** + * Return true if the sensor bar is below. + * + * @return true if the sensor bar is below. + */ + public boolean isSensorBarBelow() { + return sensorBarPostion == WIIUSE_IR_BELOW; + } + + /** + * Return true if screen aspect ratio set is 4/3. + * + * @return true if screen aspect ratio set is 4/3. + */ + public boolean isScreenAspectRatio43() { + return screenAsPectRatio == WIIUSE_SCREEN_RATIO_4_3; + } + + /** + * Return true if screen aspect ratio set is 16/9. + * + * @return true if screen aspect ratio set is 16/9. + */ + public boolean isScreenAspectRatio169() { + return screenAsPectRatio == WIIUSE_SCREEN_RATIO_16_9; + } + + /** + * Return aspect ratio of the screen. + * + * @return the screenAsPectRatio + */ + public short getScreenAsPectRatio() { + return screenAsPectRatio; + } + + @Override + public String toString() { + String out = ""; + /* Display IR Tracking */ + out += "/******** IR Tracking ********/\n"; + out += "--- Active : true\n"; + out += "--- calculated X coordinate : " + x + "\n"; + out += "--- calculated Y coordinate : " + y + "\n"; + out += "--- calculated distance : " + z + "\n"; + out += "--- absolute X coordinate : " + ax + "\n"; + out += "--- absolute Y coordinate : " + ay + "\n"; + out += "--- IR virtual screen x resolution : " + xVRes + "\n"; + out += "--- IR virtual screen y resolution : " + yVRes + "\n"; + out += "--- IR X correction offset : " + xOffset + "\n"; + out += "--- IR Y correction offset : " + yOffset + "\n"; + if (isScreenAspectRatio43()) { + out += "--- aspect ratio of the screen : 4/3\n"; + } else if (isScreenAspectRatio169()) { + out += "--- aspect ratio of the screen : 16/9\n"; + } + if (isSensorBarAbove()) { + out += "--- IR sensor bar position. : Above\n"; + } else if (isSensorBarBelow()) { + out += "--- IR sensor bar position. : Below\n"; + } + out += "--- Seen points\n"; + for (int i = 0; i < IRPoints.length; i++) { + if (IRPoints[i] != null) { + out += IRPoints[i].toString(); + } + } + out += "\n"; + return out; + } +} diff --git a/WiiUseJ_0.1/src/wiiusej/wiiuseapievents/MotionSensingEvent.java b/WiiUseJ_0.1/src/wiiusej/wiiuseapievents/MotionSensingEvent.java new file mode 100644 index 0000000..6ec7712 --- /dev/null +++ b/WiiUseJ_0.1/src/wiiusej/wiiuseapievents/MotionSensingEvent.java @@ -0,0 +1,194 @@ +/** + * This file is part of WiiuseJ. + * + * WiiuseJ is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * WiiuseJ is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with WiiuseJ. If not, see . + */ +package wiiusej.wiiuseapievents; + +import wiiusej.values.GForce; +import wiiusej.values.Orientation; +import wiiusej.values.RawAcceleration; + +/** + * Class which represents a motion sensing event. + * + * @author guiguito + */ +public class MotionSensingEvent extends WiimoteEvent { + + /* Motion Sensing */ + private Orientation orientation; + private GForce gforce; + private RawAcceleration acceleration; + + private float orientationThreshold = 0; + private int accelerationThreshold = 0; + private float alphaSmoothing = 0; + private boolean isSmoothingActive = false; + + /** + * Constructor for a Motion Sensing Event. + * + * @param id + * id of the wiimote concerned. + * @param orientationThreshold + * value of the minimum angle between two events with the + * accelerometer + * @param accelerationThreshold + * value of the value variation between two events with the + * accelerometer + * @param smoothingState + * true if smoothing flag is activated + * @param alphaSmooth + * value of the alpha smoothing parameter + * @param r + * roll + * @param p + * pitch + * @param ya + * yaw + * @param x + * gravity force on x axis + * @param y + * gravity force on y axis + * @param z + * gravity force on z axis + * @param xx + * raw acceleration on x axis + * @param yy + * raw acceleration on y axis + * @param zz + * raw acceleration on z axis + */ + public MotionSensingEvent(int id, float orientationThreshold, + int accelerationThreshold, boolean smoothingState, + float alphaSmooth, float r, float p, float ya, float x, float y, + float z, short xx, short yy, short zz) { + super(id); + this.orientationThreshold = orientationThreshold; + this.accelerationThreshold = accelerationThreshold; + this.isSmoothingActive = smoothingState; + this.alphaSmoothing = alphaSmooth; + setOrientationAndGforce(r, p, ya, x, y, z, xx, yy, zz); + } + + /** + * Set orientation, gravity force and raw acceleration. + * + * @param r + * roll + * @param p + * pitch + * @param ya + * yaw + * @param x + * gravity force on x axis + * @param y + * gravity force on y axis + * @param z + * gravity force on z axis + * @param xx + * raw acceleration on x axis + * @param yy + * raw acceleration on y axis + * @param zz + * raw acceleration on z axis + */ + private void setOrientationAndGforce(float r, float p, float ya, float x, + float y, float z, short xx, short yy, short zz) { + this.orientation = new Orientation(r, p, ya); + this.gforce = new GForce(x, y, z); + this.acceleration = new RawAcceleration(xx, yy, zz); + } + + /** + * @return the orientation + */ + public Orientation getOrientation() { + return orientation; + } + + /** + * Get the gravity force. + * + * @return the gforce + */ + public GForce getGforce() { + return gforce; + } + + /** + * Get the raw acceleration. + * + * @return the raw acceleration + */ + public RawAcceleration getRawAcceleration() { + return acceleration; + } + + /** + * Get orientation threshold. + * + * @return the orientationThreshold + */ + public float getOrientationThreshold() { + return orientationThreshold; + } + + /** + * Get acceleration threshold. + * + * @return the accelerationThreshold + */ + public int getAccelerationThreshold() { + return accelerationThreshold; + } + + /** + * Get alpha smoothing. + * + * @return the alphaSmoothing + */ + public float getAlphaSmoothing() { + return alphaSmoothing; + } + + /** + * Tell if the option SMOOTHING is activated. + * + * @return the isSmoothingActive + */ + public boolean isSmoothingActive() { + return isSmoothingActive; + } + + @Override + public String toString() { + String out = ""; + /* Motion sensing */ + out += "/******** Motion sensing ********/\n"; + out += "--- Motion sensing : true \n"; + out += "--- Orientation threshold value ? : " + orientationThreshold + + "\n"; + out += "--- Acceleration threshold value ? : " + accelerationThreshold + + "\n"; + out += "--- Alpha smoothing threshold value ? : " + alphaSmoothing + + "\n"; + out += "--- Smoothing ? : " + isSmoothingActive + "\n"; + out += "--- " + orientation + "\n"; + out += "--- " + gforce + "\n"; + out += "--- " + acceleration + "\n"; + return out; + } +} diff --git a/WiiUseJ_0.1/src/wiiusej/wiiuseapievents/StatusEvent.java b/WiiUseJ_0.1/src/wiiusej/wiiuseapievents/StatusEvent.java new file mode 100644 index 0000000..7a365fc --- /dev/null +++ b/WiiUseJ_0.1/src/wiiusej/wiiuseapievents/StatusEvent.java @@ -0,0 +1,258 @@ +/** + * This file is part of WiiuseJ. + * + * WiiuseJ is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * WiiuseJ is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with WiiuseJ. If not, see . + */ +package wiiusej.wiiuseapievents; + +/** + * Class used to represent a status event. This class is used to know what are + * the settings of the wiimote. + * + * @author guiguito + */ +public class StatusEvent extends WiiUseApiEvent { + + private static short WIIMOTE_LED_1 = 1; + private static short WIIMOTE_LED_2 = 2; + private static short WIIMOTE_LED_3 = 4; + private static short WIIMOTE_LED_4 = 8; + + /* ATTACHMENT CONSTANTS */ + + private static short EXP_NONE = 0; + private static short EXP_NUNCHUK = 1; + private static short EXP_CLASSIC = 2; + private static short EXP_GUITAR_HERO_3 = 3; + + /* Status variables */ + private boolean connected = false; + + private float batteryLevel = -1; + + private short leds = 0; + + private boolean isSpeakerEnabled = false; + + private int attachment = 0; + + private boolean isRumbleActive = false; + + private boolean isContinuousActive = false; + + private boolean isIrActive = false; + + private boolean isMotionSensingActive = false; + + /** + * Construct the StatusEvent setting up the id. + * + * @param id + * the Wiimote id + */ + public StatusEvent(int id) { + super(id, WiiUseApiEvent.STATUS_EVENT); + } + + /** + * Build a StatusEvent with all fields set. + * + * @param id + * id of the wiimote + * @param connect + * true if the wiimote is connected + * @param batt + * battery level + * @param led + * status of leds + * @param speak + * speakers status + * @param attach + * attachment status + * @param rumbleState + * true if rumble is active + * @param continuousState + * true if continuous flag is activated + * @param irState + * true if ir is active + * @param motionSensingState + * true if accelerometer is active + */ + public StatusEvent(int id, boolean connect, float batt, short led, + boolean speak, int attach, boolean rumbleState, + boolean continuousState, boolean irState, boolean motionSensingState) { + super(id, WiiUseApiEvent.STATUS_EVENT); + connected = connect; + this.batteryLevel = batt; + this.leds = led; + this.isSpeakerEnabled = speak; + this.attachment = attach; + isRumbleActive = rumbleState; + isContinuousActive = continuousState; + isIrActive = irState; + isMotionSensingActive = motionSensingState; + } + + /** + * True if the wiimote is connected false otherwise. + * + * @return return the connected status. + */ + public boolean isConnected() { + return connected; + } + + /** + * Get battery level. + * + * @return battery level. 1 = 100% + */ + public float getBatteryLevel() { + return batteryLevel; + } + + /** + * Get status of the leds . + * + * @return a short representing LEDS turned on. + */ + public short getLeds() { + return leds; + } + + /** + * Get led1 status. + * + * @return true if the led is set. + */ + public boolean isLed1Set() { + if ((leds & WIIMOTE_LED_1) > 0) { + return true; + } else { + return false; + } + } + + /** + * Get led2 status. + * + * @return true if the led is set. + */ + public boolean isLed2Set() { + if ((leds & WIIMOTE_LED_2) > 0) { + return true; + } else { + return false; + } + } + + /** + * Get led3 status. + * + * @return true if the led is set. + */ + public boolean isLed3Set() { + if ((leds & WIIMOTE_LED_3) > 0) { + return true; + } else { + return false; + } + } + + /** + * Get led4 status. + * + * @return true if the led is set. + */ + public boolean isLed4Set() { + if ((leds & WIIMOTE_LED_4) > 0) { + return true; + } else { + return false; + } + } + + /** + * Tell if the speaker is enable for this wiimote + * + * @return TRUE if it enabled false otherwise + */ + public boolean isSpeakerEnabled() { + return isSpeakerEnabled; + } + + /** + * Get the int representing the attachment type. + * + * @return value of the Attachment Type + */ + public int getAttachment() { + return attachment; + } + + /** + * Get the status of rumble. + * + * @return true if the rumble is active false otherwise + */ + public boolean isRumbleActive() { + return isRumbleActive; + } + + /** + * Tell if the CONTINUOUS option is activated. + * + * @return the isContinuousActive + */ + public boolean isContinuousActive() { + return isContinuousActive; + } + + /** + * Tell if the IR Tracking is active. + * + * @return TRUE if it is active or false otherwise. + */ + public boolean isIrActive() { + return isIrActive; + } + + /** + * Get the flag indicating if the motion sensing is active. + * + * @return true if the motion sensing is active false otherwise + */ + public boolean isMotionSensingActive() { + return isMotionSensingActive; + } + + @Override + public String toString() { + String out = ""; + /* Status */ + out += "/*********** STATUS EVENT : WIIMOTE ID :" + + super.getWiimoteId() + " ********/\n"; + out += "--- connected : " + connected + "\n"; + out += "--- Battery level : " + batteryLevel + "\n"; + out += "--- Leds : " + leds + "\n"; + out += "--- Speaker enabled : " + isSpeakerEnabled + "\n"; + out += "--- Attachment ? : " + attachment + "\n"; + out += "--- Rumble ? : " + isRumbleActive + "\n"; + out += "--- Continuous ? : " + isContinuousActive + "\n"; + out += "--- IR active ? : " + isIrActive + "\n"; + out += "--- Motion sensing active ? : " + isMotionSensingActive + "\n"; + return out; + } + +} diff --git a/WiiUseJ_0.1/src/wiiusej/wiiuseapievents/WiiUseApiEvent.java b/WiiUseJ_0.1/src/wiiusej/wiiuseapievents/WiiUseApiEvent.java new file mode 100644 index 0000000..880c632 --- /dev/null +++ b/WiiUseJ_0.1/src/wiiusej/wiiuseapievents/WiiUseApiEvent.java @@ -0,0 +1,62 @@ +/** + * This file is part of WiiuseJ. + * + * WiiuseJ is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * WiiuseJ is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with WiiuseJ. If not, see . + */ +package wiiusej.wiiuseapievents; + +/** + * This class describes the structure of an event from the WiiUse API event. + * + * @author guiguito + */ +public abstract class WiiUseApiEvent extends WiimoteEvent{ + + public static int GENERIC_EVENT = 1; + public static int STATUS_EVENT = 2; + public static int DISCONNECTION_EVENT = 3; + public static int WIIUSE_NUNCHUK_INSERTED = 4; + public static int WIIUSE_NUNCHUK_REMOVED = 5; + public static int WIIUSE_CLASSIC_CTRL_INSERTED = 6; + public static int WIIUSE_CLASSIC_CTRL_REMOVED = 7; + public static int WIIUSE_GUITAR_HERO_3_CTRL_INSERTED = 8; + public static int WIIUSE_GUITAR_HERO_3_CTRL_REMOVED = 9; + + /* Event Type */ + private int eventType; + + /** + * Construct the WiiUseApiEvent setting up the id. + * + * @param id + * the Wiimote id + * @param type + * type of the event + */ + public WiiUseApiEvent(int id, int type) { + super(id); + eventType = type; + } + + /** + * Get the event type. + * @return the eventType + */ + public int getEventType() { + return eventType; + } + + public abstract String toString(); + +} diff --git a/WiiUseJ_0.1/src/wiiusej/wiiuseapievents/WiiUseApiListener.java b/WiiUseJ_0.1/src/wiiusej/wiiuseapievents/WiiUseApiListener.java new file mode 100644 index 0000000..3f6bb22 --- /dev/null +++ b/WiiUseJ_0.1/src/wiiusej/wiiuseapievents/WiiUseApiListener.java @@ -0,0 +1,39 @@ +/** + * This file is part of WiiuseJ. + * + * WiiuseJ is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * WiiuseJ is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with WiiuseJ. If not, see . + */ +package wiiusej.wiiuseapievents; + + + +/** + * This is the interface to implement to listen to events from the wiiuse API. + * + * @author guiguito + */ +public interface WiiUseApiListener extends java.util.EventListener { + + /** + * Method called when a WiiUseApiEvent occurs. + * A WiiUseApiEvent can be : + * - GenericEvent (Storing ButtonsEvent and + * eventually IREvent and MotionSensingEvent) + * - StatusEvent + * - DisconnectionEvent + * @param e + */ + void onWiiUseApiEvent(WiiUseApiEvent e); + +} diff --git a/WiiUseJ_0.1/src/wiiusej/wiiuseapievents/WiimoteEvent.java b/WiiUseJ_0.1/src/wiiusej/wiiuseapievents/WiimoteEvent.java new file mode 100644 index 0000000..1504a37 --- /dev/null +++ b/WiiUseJ_0.1/src/wiiusej/wiiuseapievents/WiimoteEvent.java @@ -0,0 +1,59 @@ +/** + * This file is part of WiiuseJ. + * + * WiiuseJ is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * WiiuseJ is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with WiiuseJ. If not, see . + */ +package wiiusej.wiiuseapievents; + +/** + * Abstract mother class representing an event with a wiimote id. + * + * @author guiguito + */ +public abstract class WiimoteEvent { + + /* ID */ + private int wiimoteId = -1; + + /** + * Construct the WiiUseApiEvent setting up the id. + * + * @param id + * the Wiimote id + */ + public WiimoteEvent(int id) { + wiimoteId = id; + } + + /** + * Get Wiimote ID + * + * @return the wiimote id. + */ + public int getWiimoteId() { + return wiimoteId; + } + + /** + * Set Wiimote ID + * + * @param wiimoteId + * id of the wiimote + */ + void setWiimoteId(int wiimoteId) { + this.wiimoteId = wiimoteId; + } + + public abstract String toString(); +} diff --git a/WiiUseJ_0.1/src/wiiusej/wiiuseapievents/WiimoteListener.java b/WiiUseJ_0.1/src/wiiusej/wiiuseapievents/WiimoteListener.java new file mode 100644 index 0000000..3ea3c05 --- /dev/null +++ b/WiiUseJ_0.1/src/wiiusej/wiiuseapievents/WiimoteListener.java @@ -0,0 +1,69 @@ +/** + * This file is part of WiiuseJ. + * + * WiiuseJ is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * WiiuseJ is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with WiiuseJ. If not, see . + */ +package wiiusej.wiiuseapievents; + +/** + * This is the interface to implement to listen to events from wiimotes. + * The differents methods are called in this order : + * onButtonsEvent, onIrEvent, onMotionSensingEvent, onStatusEvent, onDisconnectionEvent. + * + * @author guiguito + */ +public interface WiimoteListener extends java.util.EventListener { + + /** + * Method called on a button Event. + * @param e the buttonEvent with the last informations + * about the buttons of the wiimote. + */ + void onButtonsEvent(ButtonsEvent e); + + /** + * Method called when an IR event occurs. + * @param e the IREvent with the IR points seen. + */ + void onIrEvent(IREvent e); + + /** + * Method called when a motion sensing event occurs. + * @param e the motion sensing event with orientation and acceleration. + */ + void onMotionSensingEvent(MotionSensingEvent e); + + /** + * Method called on a status event. + * A status event occurs when : + * - we ask it + * - an expansion controller has been plugged + * - an expansion controller has been unplugged + * This is where you can get the different values of + * the parameters setup on your wiimote. + * @param e the status event. + */ + void onStatusEvent(StatusEvent e); + + /** + * This is the method called when a disconnection event occurs. + * A disconnection event happens when : + * - there are no battery left + * - the wiimote has just been turned off + * - the connection is dropped + * @param e the disconnection event. + */ + void onDisconnectionEvent(DisconnectionEvent e); + +} diff --git a/WiiUseJ_0.1/src/wiiusej/wiiuseapirequest/FloatValueRequest.java b/WiiUseJ_0.1/src/wiiusej/wiiuseapirequest/FloatValueRequest.java new file mode 100644 index 0000000..a003239 --- /dev/null +++ b/WiiUseJ_0.1/src/wiiusej/wiiuseapirequest/FloatValueRequest.java @@ -0,0 +1,71 @@ +/** + * This file is part of WiiuseJ. + * + * WiiuseJ is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * WiiuseJ is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with WiiuseJ. If not, see . + */ +package wiiusej.wiiuseapirequest; + +/** + * Represents a request with a float value to pass to wiiuse API. + * + * @author guiguito + */ +public class FloatValueRequest extends WiiUseApiRequest { + + private float floatValue; + + /** + * Constructor setting the id of the wiimote concerned. + * + * @param id + * the id of the wiimote concerned. + */ + public FloatValueRequest(int id, int type) { + super(id, type); + } + + /** + * Constructor setting the id of the wiimote concerned. + * + * @param id + * the id of the wiimote concerned. + * @param type + * type of the request + * @param th + * threshold in degrees + */ + public FloatValueRequest(int id, int type, float th) { + super(id, type); + floatValue = th; + } + + /** + * Get the float value. + * @return the float value + */ + public float getFloatValue() { + return floatValue; + } + + /** + * Set the float value. + * @param val the value to set + */ + public void setFloatValue(float val) { + this.floatValue = val; + } + + + +} diff --git a/WiiUseJ_0.1/src/wiiusej/wiiuseapirequest/IntValueRequest.java b/WiiUseJ_0.1/src/wiiusej/wiiuseapirequest/IntValueRequest.java new file mode 100644 index 0000000..801093d --- /dev/null +++ b/WiiUseJ_0.1/src/wiiusej/wiiuseapirequest/IntValueRequest.java @@ -0,0 +1,74 @@ +/** + * This file is part of WiiuseJ. + * + * WiiuseJ is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * WiiuseJ is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with WiiuseJ. If not, see . + */ +package wiiusej.wiiuseapirequest; + +/** + * Represents a request with an int value to pass to wiiuse API. + * + * @author guiguito + */ +public class IntValueRequest extends WiiUseApiRequest { + + private int intValue; + + /** + * Constructor setting the id of the wiimote + * concerned and the type of the request. + * + * @param id + * the id of the wiimote concerned. + */ + public IntValueRequest(int id, int type) { + super(id, type); + } + + /** + * Constructor setting the id of the wiimote + * concerned, the type of the request + * and the int value. + * + * @param id + * the id of the wiimote concerned. + * @param type + * type of the request + * @param th + * the int value. + */ + public IntValueRequest(int id, int type, int th) { + super(id, type); + intValue = th; + } + + /** + * Get the int value. + * @return the int value + */ + public int getIntValue() { + return intValue; + } + + /** + * Set the int value. + * @param val the value to set + */ + public void setIntValue(int val) { + this.intValue = val; + } + + + +} diff --git a/WiiUseJ_0.1/src/wiiusej/wiiuseapirequest/LedsRequest.java b/WiiUseJ_0.1/src/wiiusej/wiiuseapirequest/LedsRequest.java new file mode 100644 index 0000000..1a21024 --- /dev/null +++ b/WiiUseJ_0.1/src/wiiusej/wiiuseapirequest/LedsRequest.java @@ -0,0 +1,125 @@ +/** + * This file is part of WiiuseJ. + * + * WiiuseJ is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * WiiuseJ is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with WiiuseJ. If not, see . + */ +package wiiusej.wiiuseapirequest; + +/** + * Represents a request to set leds of the wiimote with WiiUse API. + * + * @author guiguito + */ +public class LedsRequest extends wiiusej.wiiuseapirequest.WiiUseApiRequest { + + private boolean led1, led2, led3, led4; + + /** + * Constructor setting the id of the wiimote concerned. + * + * @param id + * id of the wiimote concerned + * @param type + * type of the request + */ + public LedsRequest(int id, int type) { + super(id, type); + } + + /** + * Constructor setting the id of the wiimote concerned. + * + * @param id + * id of the wiimote concerned + * @param type + * type of the request + * @param l1 + * led1 status. True=ON, False=OFF + * @param l2 + * led2 status. True=ON, False=OFF + * @param l3 + * led3 status. True=ON, False=OFF + * @param l4 + * led4 status. True=ON, False=OFF + */ + public LedsRequest(int id, int type, boolean l1, boolean l2, boolean l3, + boolean l4) { + super(id, type); + led1 = l1; + led2 = l2; + led3 = l3; + led4 = l4; + } + + /** + * @return the led1 + */ + public boolean isLed1() { + return led1; + } + + /** + * @param led1 + * the led1 to set + */ + public void setLed1(boolean led1) { + this.led1 = led1; + } + + /** + * @return the led2 + */ + public boolean isLed2() { + return led2; + } + + /** + * @param led2 + * the led2 to set + */ + public void setLed2(boolean led2) { + this.led2 = led2; + } + + /** + * @return the led3 + */ + public boolean isLed3() { + return led3; + } + + /** + * @param led3 + * the led3 to set + */ + public void setLed3(boolean led3) { + this.led3 = led3; + } + + /** + * @return the led4 + */ + public boolean isLed4() { + return led4; + } + + /** + * @param led4 + * the led4 to set + */ + public void setLed4(boolean led4) { + this.led4 = led4; + } + +} diff --git a/WiiUseJ_0.1/src/wiiusej/wiiuseapirequest/TwoIntValueRequest.java b/WiiUseJ_0.1/src/wiiusej/wiiuseapirequest/TwoIntValueRequest.java new file mode 100644 index 0000000..98e907e --- /dev/null +++ b/WiiUseJ_0.1/src/wiiusej/wiiuseapirequest/TwoIntValueRequest.java @@ -0,0 +1,73 @@ +/** + * This file is part of WiiuseJ. + * + * WiiuseJ is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * WiiuseJ is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with WiiuseJ. If not, see . + */ +package wiiusej.wiiuseapirequest; + + +/** + * Represents a request with two int values to pass to wiiuse API. + * + * @author guiguito + */ +public class TwoIntValueRequest extends IntValueRequest { + + private int secondIntValue; + + /** + * Constructor setting the id of the wiimote + * concerned and the type of the request. + * + * @param id the id of the wiimote concerned. + * @param type type of the request + */ + public TwoIntValueRequest(int id, int type) { + super(id, type); + } + + /** + * Constructor setting the id of the wiimote + * concerned, the type of the request + * and the two int values. + * + * @param id the id of the wiimote concerned. + * @param type type of the request + * @param x first int value. + * @param y second int value. + */ + public TwoIntValueRequest(int id, int type, int x, int y) { + super(id, type, x); + secondIntValue = y; + } + + /** + * Get the second int value. + * @return the secondIntValue + */ + public int getSecondIntValue() { + return secondIntValue; + } + + /** + * Set the second int value. + * @param secondIntValue the secondIntValue to set. + */ + public void setSecondIntValue(int secondIntValue) { + this.secondIntValue = secondIntValue; + } + + + +} diff --git a/WiiUseJ_0.1/src/wiiusej/wiiuseapirequest/WiiUseApiRequest.java b/WiiUseJ_0.1/src/wiiusej/wiiuseapirequest/WiiUseApiRequest.java new file mode 100644 index 0000000..1f4525b --- /dev/null +++ b/WiiUseJ_0.1/src/wiiusej/wiiuseapirequest/WiiUseApiRequest.java @@ -0,0 +1,112 @@ +/** + * This file is part of WiiuseJ. + * + * WiiuseJ is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * WiiuseJ is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with WiiuseJ. If not, see . + */ +package wiiusej.wiiuseapirequest; + +/** + * Represents a request we could do to the WiiUse API. + * + * @author guiguito + */ +public class WiiUseApiRequest { + + public static int WIIUSE_STATUS_REQUEST = 1; + public static int WIIUSE_ACTIVATE_SMOOTHING_REQUEST = 2; + public static int WIIUSE_DEACTIVATE_SMOOTHING_REQUEST = -2; + public static int WIIUSE_ACTIVATE_IR_TRACKING_REQUEST = 3; + public static int WIIUSE_DEACTIVATE_IR_TRACKING_REQUEST = -3; + public static int WIIUSE_ACTIVATE_MOTION_SENSING_REQUEST = 4; + public static int WIIUSE_DEACTIVATE_MOTION_SENSING_REQUEST = -4; + public static int WIIUSE_CLOSE_CONNECTION_REQUEST = 5; + public static int WIIUSE_ACTIVATE_CONTINUOUS_REQUEST = 6; + public static int WIIUSE_DEACTIVATE_CONTINUOUS_REQUEST = -6; + public static int WIIUSE_ACTIVATE_RUMBLE_REQUEST = 7; + public static int WIIUSE_DEACTIVATE_RUMBLE_REQUEST = -7; + public static int WIIUSE_LEDS_REQUEST = 8; + public static int WIIUSE_ORIENT_THRESHOLHD_REQUEST = 9; + public static int WIIUSE_ACCEL_THRESHOLHD_REQUEST = 10; + public static int WIIUSE_ALPHA_SMOOTHING_REQUEST = 11; + public static int WIIUSE_RESYNC = 12; + public static int WIIUSE_ASPECT_RATIO_4_3 = 13; + public static int WIIUSE_ASPECT_RATIO_16_9 = 14; + public static int WIIUSE_SENSOR_BAR_ABOVE = 15; + public static int WIIUSE_SENSOR_BAR_BELOW = 16; + public static int WIIUSE_SET_VIRTUAL_RESOLUTION = 17; + + private int wiimoteId = 0; + private int requestType = 0; + + /** + * Constructor setting the id of the wiimote concerned. + * + * @param id + * the id of the wiimote concerned. + */ + public WiiUseApiRequest(int id) { + wiimoteId = id; + } + + /** + * Constructor setting the id of the wiimote concerned. + * + * @param id + * the id of the wiimote concerned. + * + */ + public WiiUseApiRequest(int id, int type) { + wiimoteId = id; + requestType = type; + } + + /** + * Get id of the wiimote concerned by this request. + * + * @return id of the wiimote concerned + */ + public int getId() { + return wiimoteId; + } + + /** + * Set id of the wiimote concerned by this request. + * + * @param id + * id fh the wiimote concernet + */ + public void setId(int id) { + wiimoteId = id; + } + + /** + * Get the request type. + * + * @return the requestType + */ + public int getRequestType() { + return requestType; + } + + /** + * Set the request type. + * + * @param requestType + * the requestType to set + */ + public void setRequestType(int requestType) { + this.requestType = requestType; + } + +} diff --git a/WiiUseJ_0.1/wiiuse.dll b/WiiUseJ_0.1/wiiuse.dll new file mode 100644 index 0000000000000000000000000000000000000000..6855619edad1c5156421d3af3983f527fe6db9ce GIT binary patch literal 114688 zcmeFaeS8!}wm06B=}9`tBt6Ikf<_52xY2+&8gPjNng|o3k~kq`Lc}EOF6L&lzOdM> zhzU%#6P->oiqER6*O!$?@BO)V-`xA`0=_a~FfWK2z+E#y*x<6-aS)@hNx+!-eNXjF zGO+INbDw+f=l7RRXys_K;9wv97$9LM7qiE!L5yy;ⅆWhv29TXT z^R;yD_sQ?h+GSet?yOY}KfE`4{f2w~dBgYa%KpLk?!NmTDf|0(WN(n~&i>)u*~@ON z$iC~Ib$48qmX_j(qQ0i>&1LtUI5a)>E1&)5bPwX?vwt(a0dMGv|Y zgVU$7{I{kH?EQ=B_p|pe*?Z*=f6zdvTVA&kE_Noo*z9)T;<6f&k zDsXaZqi?)o{|X@vR~cX&pNCX0;IgA{ykh?f!Og2S+;QhUKj65-7a=teg?j<-xPOHl zcVk@i+u*kx_?83Ta^PDIe9M7vIq)q9zU9ET9Qc+4-*Vtv4*dVX0d1K>2%XYaIIJPJ zP#Icn6?fk0uzT`{tMVhxQ}t?Iy}CXDKYnv&*zCWFYqyKuFQBrf>~m*RFo^|cQ&3<* z2L+Q^a25qqSa44JiuBaLpxIY47xdZcYP$+o(R#kCFgpdWU9@7Y3GUyIOujL%k#p-m zL93L#R;0!ME3c^ZRB4hUOWctt?kF>fJ3I*srhC7b4leQ2y&a5I$SF4aD6@?Bc@h9) z`8yZ_K&D09Sl)uh&+#v1HB7>Ya{kq&h-bj+OfRKtd5^FRyfEQ#N9m$g0wRk1TMruC``P zbv#Rf4J@~cJ4$$QhuZ?oRtTrfgMv1qLEJGViYFSSTB$YBsM{P1YpWcY#|95e4qNDA zamSBMDnjCp^(K~&a4iDXV}pGQ9HHA#*G*`8Au-QN>1ZN*BVTgxq1yyyufWLkpsxk$ zM?g}wLI{wdK>w$I9tfQp-n%TMZ%XMu(jN+~atPt#(7wJye;yd#YmyMzB)Pw36BZx3mXEUlpWt)WlP=8;4C|uBg zxbFZ}RI~{L#$)O~eC&Ac0r1O;_FKbff3dm0j~bQReRv(3hh|dFF{*)ZTG32FpLs3E zA;CtK^jiXuo1;CUo}&wQArwnLI`@@W>=fVxqh8CVbSiZ0FQI(|7*6OvOmWKW525{1 z;?cC1sa&nWu#RKjG(0{!EHP%{dCq#fcU(rn-vGrM!5ZxrU&BRzFu7`@PkdFQ= zhh9%~o>KM-Z2@^ke;-njM;VLaGRz^5wa-J+V`ZF?Q~Jtz3Rxb^LOKg=%Id3TX+^R< zRKzn%`upNTw!V66Uzx41*cxL%sN8@vND`tX9a{MJBr#h5H7)}r34I=6lBDFmDF#Is zBiW#6M&Aqy6v-EbOyE{+5cEt0imZM00wYJ5AZH4Lis_`#sftPs8az}fkf=i9r-?gi z%~ed7>=4oMSrCg%^>&9H;smX=+ysHhglJ?!NK6n4J1}PAaD@JmJ_NLUuq= zY62iL0b!>!dLzw3VK(dtk3D4BPrZ(sNEAXkxW6eKqoW7oBa4#5GhzZ{WrKz#B6}Zx zsJri=!Icznfy!itr}iB&_#*%Y2~kMHk`hphr5iM99l3j+ z&fk-}#~BnKeF(A^+NZn|=?gLNO;ZhVeVwKO;zz6n)G=1j5>0}fhx(cvcKxr{7;ws0 z5duA$#s&`?I7cnf0h1-u7(pHz2vH27N-k7m4V^NGB7DXyvfPy0!N|jK=AC=QM_Y*! zaAY@;L~Q9lOnPNXs7HA}GJ!LbQ3SRaY)b^8l+=fkb`0@MeQ}J?$Ui1DlM$LZiInOM zRq~-4TbPHw=~J2<*_@QoXsYz+w~R$1jR^?ch=4*n)S|fa zKW;}O>gWD^Ce3M`G^hQf7AdKn+7}~#n$wBsS^`kp32st1kc^XX1A~k6X!kFU&XeNK zpT#3&ljOq;VRW8s8?IL$Hc&oFkn)U%t+P!w{R(IwB~a+r4}dFBC$%-fc2`1sxA(Z{ zJuAqW4Q_%m$Dn>`K!vaLo=uXI8U$p9kGJ+n*NHni+zq`DD*eO!D8?-e)~c1+JnF5B z^^dNm3V3D9VorLxwnlAo@Pp;Kuzq${nkxc2&zn}Z_Zch#PwK@T!TKwT(_ssw=O3(h z7F+98Ps#?&^&X^k9S1NB?D&4wH1n#xgE1T1~HDcSfkw`?`S!UHdyp~wL zvMSOWqvCc(g^j2XTSb6HDe1bBgD_RAmD_u^Hsd&g&tW-Kym+PyhFb)NcSmFrv zwGfRhau|7pg3XV^#W{u216nadia5LD8HSEz7(=qZT>)`p&X3V|S!>NWQS*fs-9ih_BG zoX}I)LIMqJ;6Jr7zIdo`UFfN22@fR2$AAkZv~(*gMm2{DH%2S>`;1hozx}2J%j0<0 zt2SRr0vn}Td5*ScE}>9PS{Hle>$DbXqO*k!wYL!G+aIIexNZ-uNO8wO%oPG= zBYs0>?jD4#8xt{$Si=rH$w=bE({g*sh>50?MMf5+(D%-45y++mleDJ2WiLZaQWMvT|1#oZ24ea9P|}C% zHO8I(PUS?YBRSZrGbMjP$Du7%nww%tf6j}f8QJw}Mc zwmhUL<9w*)S4a%C5R1gNClNO4FWNNM$m-ipS;kaqlD><1Bd$bvj#092J7I|dT|_`s zDvAMJ6KYvEiCWZ7u*_Fj&9uE7S0^R*ZKuQ-I#%Z-EY-=fw=+=mG8vPsPD&27u;dHt zd{6>OtiCtSua6S@wo~GH^-aQ3eJp!B1C6hbk`1&Ze&@HbT}7tG*w7!+9wX9VZZqC# z44?WK5vn~FK#t02(^~dY_%Z5MwdD;wCp$Pgq{Q}(NH*GNuwf#jj%7^JJ&{q23`2*D ztrmo#cWI3vRU#m^z0MOprXY&$oG5b-OO*&^(fWzhYL@yGOI;gF)gA}YlZ3`_O_rJy zhf9i;YENUS>j_tj7Z@fo&Ok6jEk-k2<1>!1j04KqBONO4 zE?VvE6F>#m5wr=tY&3Uc6v?J3(4>zMY4rsRkpwHXzi$$SR=z;_2&&A`dtTO( zZ2*rGW=ibaPKoCU*CZ?n7t7wxK;wmrlEE6nz=Vr<5k)O(pR&wWRwwa4u1-qq+fIq+ z)j0`Eb+YX33^cw@N)ENKmdK}#7?Ec<8>#kaHlX=IZ9sxdD0_i2w2i7I1@#&D{S5xLr9&$4vFkLilSk8MR* zZP|wBWS)SY`hIiOSH+v5D+^?JcDK+aG)6n-E_dosQvNz;tU3=fo!7 zaAtHuj^(7&bWFL&-Z}PBsK<~@lkCAd0mBCq8gZ$;g=)cMMvU{ZiYGg%ou&5oUB^J> zkBt^z*Fr6p``RBPGOuG~%KPfImH?t;61UurK&|-19&Hazi4z7N*`L<7Vfl7io|7Hg zi3Y%s@#x?G8#5}gMxEPe^24W8-cZQB#Cz1@>`2BL_$3YJW!dcWoR`dT>4`ZmbCj~2 z!rGwrhdc6IUHP4_S)J4(w&~Jhr7{69%%I!Ckw1H3as?_ zm#=nL>5D(5R#5?Gv_K*i*f3dOg;Ai~f6T>!J8%SH1esS^`iXA-MMC2`?u|7Ph2*nU|7U z%5pd)w;h2Gg1iPKM#9mB+#K=}@*7t0X*RSDXA`ob?GkwIcUG9Ez2 z{}oAhUqDi&{%@a6l2oa$Hc0YUSy0nEXz<`Lh(%4}f4`>1=hbv-5RL7!0QH%v95+bH z1mTxI2Q^hzR9;5R?@B=0?=NCv9li%)AM*d34gSN)_y+$o$naN*sIZ@y%m`Y_Dx8P3 zSHWwHzsu{4kwPL#K9KST0ivwGJqLu*=)Vh!1v1RKON+eu9nSV^{0bpO*W+D^-_1Fk ztqbn~{CPji zNtgLwrU3w5yt=TmLN`OG;76*^&rzT6%~U!~PTE%4dNYP_%^E05p$-kBcj%NSv|1qV zW|g?J$&s1g<2+lh3iWCUcB)GF%~RX$SI0J~uEwZxzK>0+>mzc$cQZDr<{Nsx9tz<6 zO{%O5H>tqMU}vFq?00YbO42(EZ3CT!Y3F<;VrSu$0rFGVVb2J5=6QQY=X0$E#lQ8K`pYXMK-m_t`=n)a~7Mg{wMd2s$!c*@Oz6p3nn&?dbKXvFe*w&?b6QG zt5ZfkoYRFUc0N4jmQO!NGq5ABJ8acPCTTW`M%lUF1IM`3Ny{odk5CS~Aj zrJL8fTaJ6F(!GNBtQYEEzU7S=TbhVh9?Cv1!+z zngPTYc|0&a7Qi36jJ(i&hH$D);PK<1SD5fzoVE3`{jAUkph!j@UCZ$&i}!jNs`G`*4Qa&Z{r95%$VS5~qT z<&i^#EQ29yKwe>^8R*Ou4EQT~ST^&ri8}bR#nw|uMX@Y*1)2kE3id@;Cg$}PxPdoY z#5Phh6q%i97Td^bg&t|R57N_UQmgq!Q~nV&Adm3bcd9pLLJg>^ZGcg$?FcI+IVR&J zAb+KPTSinLAyK|aS(`JWfFC9ed>TB2`L3eEtv?Ba90;^25WJNQZqlBme>S?VX%-u~wE{-mr_fIGvbB zv(@fPh#}-dhAh|tkD@3^gx0Mg#i)!%(46%0hK*G2&%|0P_pnjUfI(}StlC$SRL90qR2@CM(KEUinJ5e(^L?OH`(qXEP`D1BR1rW#cp=k_v&yl)A3s zEV6kS0z24HUbRy1hiIa3EFTO+egp3S1CCLSQqCX>r!9*cL!Bro~WJ>l*31I1pXPG*0y>1H2DIRR5L8 zrc@g0jTd|L=MYu)X17ITEIT-6van^x5?b(7pg4(BLmu}E@9D%b4I%QOc4-b+fE7aH zHIYM&$qkFqI;aHzKshEfETZVeMzp;w$9ufcd$thEFotS@yCI*l{Hrc9`Bpg!BOfYz z^9YYeZ)N)j{F=C-!8#bajt4(4MmGu6O-e^Z*%MKHd0>~iZ2_K9L5Ph%z~>)y?vWa( zgzB3Ih}?b50WVi-z8plAvnF-hA_U~rF7INze+dgB=-ekSG@=qk{{iT|U@?KF7@&7k zG+MLqiqd;K)!qghh$@u7qcJ+VyhL>##HPzjl)r=@?dW4P@`FoJYdqNF6JQ(S!Lo?B zxEd?9lgf!vY<8ctg_Fdln%S{DZH9>;2F6a zs9`v^q+YKUco%V!sJVI5G|erTrm#&@??yW(rD^U=O3X4%!SN;U#vGP3kCO7DN!X$T zR3VZImzhj}(h{E@iKvO139mZU6yH7jD?I)m+p4rq#wDDO>LfKlWXXSHE8YBncEEcb zCnb6}**Iy6GRljOwu6l{S?sZgPk0MBX{z^nPEOYz;Qe;5v*|JZ-h}*s_W=+)-TQ!p zlc#78WX5tVOksK-0NKb~#4_hiW|GG8K7a-wa|O#RoXjLs)z5oYs-hyl{UPl}K6lw8ynn$X+RZ|4nV=mIe|tdd7Ju7qrqd~8MDqGCpq9v@B$-1E zal(%vwwkRbcA~*kC0pO3QL~!{OgQB&8fd#|jO`*PNp9!UxqGzkU38l*w~NA1>e@vI z&K?*wziSRU4>Vn2e$RPe%N(p5>{`0ByJ?2G%h|nUDp^~(e^hN(Tvk`hxLXr6j;Ap~ z%0Yl&s*tU(Qq`{;RliDAzdl)Y2dX8;)!(7=13B3Jf4o*9L8LvUyLbM zO*)c@1Re=?J(&^`qsO2~zi1`vTL#(4z~X@oDYglCG|i1MdyLL8Fkbb&(uy9{8{^m) zf9@a#c0NO4;7=S8fh%d)m6I**c+LSXR{7uj0QjVoP#dkwP&~7NaRnjXy8;RJUNgl2Z zJ+~Seb?Or<@KT>}<5{yt!6tKmUpYi0TN}Z_G5zE@T5Vv~SKcH%3EKP3cVZ05Q%MG) z4@d@U>x_bsL2bpuyq|yA|0Y8UjUZ?p{yz|IZJ#<#dxF%o+O~}1ZKS+cs{Rs+_(`w3 z%k{6x^Sjp?!w7l*M|Ih~?aO{<^Dp>We$Qf)oC)*dNHJ!%=EOeBT69}q+bUoTU%WU$ zz7)nB<@HSD{VV0^CYTUfHwtR^31&m24ARs;Fq*2?haRRLZ~2tT26_()l}_r|vAVE@ zI^yKR-q!@da@$xp+QB`$)IYWD2|24W7%jGuKT?~iTr8j&9hkf+C4Cu6lo*;e^2}kFz25+@4Lw58CP=c5& z8q!tj6V$D08}Uy6SCDBmO!E^X;#q*!&~gf<&^))k6?G|l?J!B4nx8fK32JgV{H?Jj z4*~==*g7>2UVD}+tsyFx0|5VDuDNe#;&Og}x z1q#5)=r*%L7~xdN8ZE@vcN|YNip)llq=~9aEYZ3r>sx@LNt5*@#@BbPQ8>Onfz?-H z6pGcCJXzn(yJ*l~(^KEFIXz;Qd0%=su`|)+E1RNp+F{PiA6MzOu^u2RHO8L`!^h=+ z^dl5j0ts&slBiEh+<_x*tH-?`5&I4r^dG8!o%nUQUacNC@*_qQ4%VC5|I|ZpfFQ^F zkyzhS5Hb78%`jnoPVLaVG|%$5)c$ zE4ji~a%EM><<1|@kAzm+oChEwnVT~z+OtIO>FM6!bYB)bGkvb-$6#2ffgPG=zNpIBzQctFrhRBM4omyo@XX+(w9k#ht2i6&bDQaH@wwq%!KrAU z+d^-_=Vr&KlYMR+2E++ypBu;bR;8!<-0bwU)#sj$mXz5Z#^JRI3{s-(S0r4VaLnPtwngQED+3O(J3Ey^5Hs=S(Q(~MM z);dRe=X7fwcy?+V7NmYb0rkcOq>+vBE1N^7g388Krcj}q#tj?YZnumf-hePqhnDFz z;s1~>1$OYbt!ML8REZVS;)jSI9coop)9E;;KvX}ZFpN);5X21@jGtIO5v%%0FupN= z3OPsJorQ~FAG7_0m|j9TSYFaqhS&t!hBwb{hXSu?hnKJl>o@e3ug-xdQP=6KnhS5< znwT?+>Nm=}w4$7s1?hTP9dPaC^Wg2^(L>!fFrGJs&C0;%YEjNyFM0@v>Zm(-I6`4( z2rC<>mg|Y|Dk^(P4@BFOsg>m9AM_r#dC%G~6~R&UQ;0bR{`sw&sDA;@?G5h{qWNc z-m?kV-@!hma-4tJ<^zvm(f61rkl&;AdOyncp34>=@1S6zNBaUR#dC#-vxep$T5ILg}Z1(HC_tb0mK^T!df}1s8^|Mb70E%n#=xXd4M#+ykq{+mVlIlEc#h znNHaY!d7}+9k$RbuQ35aZgn?aRHb*vOw-ND;tu511@i-SQAXhud&*lWncn8a36D@YZ3}{KXhyah+0* z4#YJCkZ9(lOl)t#NeS++a3qyCVn|+UAeda$Dkrlh>C4OykQ_RkLqupE`igu-$@rz= zHwC{8{ANfSnDg^a=V*mQg1YFsKIsML#f=%@SeCnS znn!<<*;H9;>ULqkaMYYkv?hbKCM&pxR8lm}6iq`k8_VGR`2qbDn^dxlMl*pYp@lvx z$;o!>zl3a62jQmwvs?c;3$uAY_Lz{jZK#-fL2P{pA$Cb2v+XmFgmbIlKs~yp5lSz! z?TGaKM!VikB8gi?YNp!2t0mamTaPo)>(jdmp|_A#wOH9pdTUyhx_q&o#D)_OS3YZB zT~NE(1~IbIcs{_w@(4238*R~ia{5DLnAk+-@^E-Y=HlxocnWwnS{n*69qAisOW}?a zoF)s-h5LVQvfV$sk=OIE6J4#`F@|Fa8?a)lR$V8$Tw|ahqQivaG}j5e6$OI;osXq? zbh%GU$p!#_tpHf!9d!&8+%T(Gd|3C!nT%bEHcbJ1Uy=@||ff%pm!r{6UTMXR^J zfm)SOlbr56CGpzZVd&{Xcla`8)GTAir~;KbJFDgC&Qs9fk>yI4sC+V1<%uxF*bf@Q zNtnwEECWwbqw1uzN4*6N z(tfQ0d0NXk4uZWQU0L!H7{*DKK?SI)w6i$1wc+ZKkaFBCS#uBgk}xGQZ-ds|F@Qxj zy=-{xQ$8|x3?@j4r+*2=DFz&Tc*8WhAx_3zMluck(rqGe*_X_}e<(Z*#$`T$8!`a&(0QxlxlKp8mugNyJ7I8og zZIS2w0+uHy&t(HmzAU_7e;XLWvyJ30jpQ(Thx1CW^!FW^zZN`XVm*O8@qFaE2n4sq z^y88jh(luQPl))Fg7_Ou-_*XjUig8R&_fo{ih7NA)GGs9>Xp$gI5!~3m4mMW?KZ_I zFJ1G0Q`Rzg2g*iSw-VHx&$_R#iLy?*Hp;fd(ENs67=(K0^hB%jQ0_HsXMknd#IpH> z=NBj%zWjXN5K|h#6vlOFcW5B|`uY6%7=_|6>7PSZZVT3f3n}$;hqmPR)Gry@f_YHu zpq@{8b#x2I;gSjx~N5H*}yYUH9L zJ7X182rj=((?_5uw4q1_ZTz|Q-yo(YR_kUEK-74Nn%`kRIRA)Ra{|6-XtLAd69H#X z&eq=ma2JRDFs_3B>7}=jINO!($RLfT{6ImCmBC6MsIuVE4)&GzW;A>1))@h@(B;dv-K{VmF?Rt9GND3D`L3R`yVeb{6hE_7^> zT^@aV9FiyEkf;|RdEg%)@k&|x=h^2s#(T5Tn9>uGf|?WZ9FP7xCpb0gciG$(Y&R@v z33%l?;i=N+FDBTm82gjK5z^vsVUIhA9?)~C;lW)wkhe^ub!B+`y*s`6VRcnIM zk*)0ETh6|WLj_HrHjdW%z2BDGfhv>$ z1ZpW}0L<=zY?vCWv(bJ6S4Qp4@cAQ~4g(lxaxMV*#~5cox?>n`|9gz*QqIT7Kw`!O z-q;VT@@TSEE469OaOP?U%$?5h`vm8x_>-5=Pc3KJOfWMx6HKe}D4&SR$D(t*woVq{ zm>Wz6Lq@u2-6m&1=|lA^XN3({p8nT};|YhGvu)G5UZY%Pkl$cc2F&JeIIkDoN{9aZ z3n(A&U5IWg!9&9DDg5RfXixMd;WD*vxe1rBf!DV@LFqIrT@3sF3GA>*CSVzqN$E_$ z88)Kf-zK2888BGf6NQ+xkn5Ys1&&KVh=3o5-ze%I!cWI<0KY!`v}KQ+P?tS=0&g8} z9q*HPpTv6z?;*U;;C%+~QM^a-9>aUg&->AI&OBrujj}_FP@@;)SAyT|_-QWiu_w5V zS{xrXS|3dTjpuO$?1;horK`vMO$B4oPH;?iLfY4-;i+{z5hzD3k&zHMy&gfbXW^o1rP+h?E{2I@ykY}z1TeGfN!}Oemp|`Ipf}c#GxkIqA-(vbqbKI7kqJ$ z+v4ER0<B?nSl{4#0?W;D zeZk^rZCpQ~ZGbV-&g(m88Xakp6HW&QcSGmK4Zr=-`TxISKRgZ9^Ix?eTqqm0A1=zh z(0+LH%9#D&zQBHnJoD#)=QmwCVMCk*VM7Ga!ofkrVJwiT(G&U`10KZ%;Yj#h z{Z?d!FZp}R;_uC^pPi3Xf8mNrbL+puuNjz+|Ev6Z`{oILeFSpOx3~OAVWz5dA-~2i z;MW^~d<}~k@T-^j^(x}uz^`%eYbLV(bNu?}^O5T7bI#+JVZqO*gAX{2cw!Xy`o9$C z@s6HgOs7v#PVz8OSI6vA=@0|XR!$6s0(2)F#|vzKzLTB%!QgUWzLpjr8*DrHz-4gm zYF04&+nod8Dm5VX7t?k+n2nAt=2)eB@_ zm19YYBVoe@vOwlir+lgYJ(v!LY2~4R`j-7JF%d?HyYs^7+qe=hOD3;IF zsywDYi)5tf$*^my$xy+i0J1(>qv=&Jp<%D+k`b@c?*pK+H}gWXB?;sN^)f)woQx`- zVO0c~+d=6z<@Xd=Y*>Ym8>a({)05?z%ZfE7Jn>@NbWEYzrFUXp-u*auR0WIk5T<@w zv9iTvQhs3Y8Nhhd>mwNrNF`GUCjb}}8KvQ4TCq*rY*k%!;!1Vl+?b%c##%m!z=)oJ zVl`s9)$%^)MTMnfFSgQ37|^{P9|`6II5?QG6)7)n!$VDboSsX3cxIYsv(d2lTyZL6RIb?ZRNi$}@Ixn(8Cy_kvi>c4@RhYi^zeFFvu)>RwJDc+Q= zkCm~&^hQqahH{|gacab3N14H2feHE_t_OS%9N}H^!h$7~Emh3~Y zh$9Of&w^4XAgd$25ZmcE&dvc*b#)|TE!w1%@i>VR&h+TpPD5}8?;_6!oB>Hy`b{uv zs<9A(f466km4kE!NIL%ymJZrk?Mtl&=N1cT$uTTj3o=+MTHi+VXhGr}f@gU=LB4AH zBKXfyuTbTwi1Y%Q)*;6EU8Lym!DJ*90kKs^kYba=v3&> z13rc_ky6koc&C+dvwS%f-i&+{GS4z9lBUFfC+d$%H|+87rJC!cCTPjnmj6B~sD|Nr zhaSy`n@U7OgS0$0p)Uv^f&&(C6|mEP`e$HNHP}Lam)$w&Hf8bOPC%uZB`i5QJ!pg$y%(8JDLtMz6KQsgT!bLe*r(vdUS~AEh<~3T@NqgRAn=7 zlG3UohpO~1=w`y@SQ~W;E#q7(%<-cPvQA5+H6KCBW_RS!Wd6t4MZjpplpR^{HX((F z5*5^to*AH?9E9ZzCy&~EBL7IirQ|w-<4Bpx97jhX|Ayme0b5F9q32(~h%LAbj-#&d z-Hn<0HmrD{S)5T2}Q^eTN8+EcBo z6Q!`645zBshaq^0ly#vNY5}o9puG~qgj`_ME|1@6n1bU@Q?YnJ7L7Hbaf-fxmd255 zjYS4N!_ZI&B{R9)CH>PDc(I!nR3_S};FY->!2nK~yBBHPi@kVa2PciZbX}GY@WjC5 z3WHi26qAd2pJXrtgE%DYULTtGp1IKYL#b( z_n6cgt1NY#<8M~Z-Eg0|@rK*9TX^R!f_$TLF8g(m=e>7^w(n5bzaoJjIW+6`UCYLk z-oM(6K1vD}fDYKf_YOGp?psnGdIL)PJ)Z2Ki(yHOPQcx=d(4-wW zuhyDT3^sX@T@+>0i>hQ(>TLxJA?+t1xi_!aIkO?e; zb`!6b8DU<#Nx)G>Fga|7UQ(LRaBxf<7F)fjK`R~dTMuZ}fEKWKr=mQ*wuJI!yt7P@ z*S3RQzEW|#16=eWeD7RuGaP2=+CIk9Lt)U9JcET9cbDy2mYf;Bf&tmU);OqY9`V&h_KML60k%d%CRg8=# z@B-5#9AV*&iZT9-Qf$orXxMIM@C|#5Fsy}GDH_(!F16Subv5!0TsCwVjmoM>#>Qxl zRlX>4-()q+!gxk06X=lVW-H{NWjK04rb;b37gGJOAx#E0$e5m*t=fmV<h}v47#ln*Ah(Xjqt2oGdf7e?O;AH z!b|l36Y;UedWDROASU&eG5_uPW9X@lalT9$zX3A`(x^$b!>%!OfR~yqk43Xt2AJc# zl_rz%iOJ+WOc_#QjNj>#lSvtyOjyp}F&mQ!_Q`wZ0MH?P)248=^~|Lx^jF7Q!`|<0>YW?se+gCy~v?c zO6h1MoCcv&_C@lC4}D4#bQ)O{Dxm4Z5>W-lAPf zh`$LYWWa>vHDRmrpun+`NOSgW7(&Ubqa~9k@|>*1kTWD_=>LX;Wm;bwT=IfU3#w!? zAoN1)(N=4>*i@6Y)TS(oNPkr?WkfEuX*T6t1o}p@Yg?JvX-(Uf%_$|C-TJOGh`8WI9L0RuhTw&AjtwLB1WMiH)D;%eD7uc*DoH2(qZwoSbvJ zZ<&hUxG3jqr6)1v&q@u?!`LyvwzA34fSxsDTto>u6+i%;bqgOg5k^supl#yS2Y6Jd zZ6dWGw)$yYOvvTUf(n3g0#M6^C|$LNT&7~U8*vCp)!C5gkiz z@+~8C0U&9U;+gy)SzG=$3{uMmm@RbZRPuMB#<10#s-~zbrqGawCX|QF2WV6y=^6~` zGg^9EkN*K2iIOjNUP?18*j+m2WM+h%6t!fLq6+>SaqbZseEg^^}u#I&73(>Cx^L@)wfduS!c)M#npsIi_;B@0W=l=KK%Za3`XSH@}~6U8MJi zA;0*(Sg~Nl-=#PX#10qo_0i8Y{>Z9)Jq|lP4|}8Vb>fHf1Zu^YRO?@M7k2g^vV$eJ zKV;J|vK@A5n)adI1a}uZNHNvav~0@?AjE0zaZQ)s^)`VN$-&5qBg1n68N~(}>{|SPMXy~Z~Yi*RdAF52T`yx$Z0g;x*KIEd+9Tc z^Ym%R2PyLk8m!XP27^6+)VlS|XgYxGYKiqi+FrwLW@3?tvFJMe-zkn6=)=KZk!S8f z>$uqJ#`-6U@txPmouCJiH<*DCvtvAd^zg77z9Cf})#)|~R!dTv;Zb_&Dx%x&ca6IB z56{n1jV#QS3AMPJ(L8F|V1e$0!^*t62iued*urV##K!~7*nxMa6~-1;S8PRz0|r68 z86?1~@FHzp%8rIn?1t!#?3R1AoDnnLyeOs2r9xbIAMgip(lEB$xeBXevejTS7R)C_ zz4>ZbkxWZ>!e;hzTxI0Gu}B7)(2;8^qbRW$wl8-sA^4`lwT6W`kyp1SzG8JgRa_I) z72a6r>xZF4BMW(~wDmFi{%{06AL*s-`GytnX+$!%vQ|pd8WtmpR{M;2BDo17y+L~E z2hi|pmXNUx+4~y>y@*z~K?K&~>Ob~iwV`k-Tf-*+dnb=Orox8LqxUvp{o~y zO9_z!M!t1JnB5}eagxvZ9=wA~K{M+`!$qinFrW2h<239CZYM_=w(}0FCU&zCeMQB{ zsc5~R*mH5k3Kmj1>4=ubJZ5n9;D+Xsd1xuFcQ(*lKT~1|P^!^BN~_ja!xn95#ckMz zJMqxz(}CpnkXL!C8q|Nsw!)1N$+y=k7rMOiXp)=*KXQ*?xHbaB;!Hz0`mosSC-Q*6yF#P znys9?JhJc=!aDa_48_sN!e3D&6A}1L;fsn$)0DeT@CD5$Hl)E#q+ygury{-KPa7Tw zy}NwWu43~3G(1c3rzn0c#bYjunUEBv*~ZB^DkB1v0RiLy&exCOpaON2EeXh2Lm5H+ zMay2&}gys280_%uQb_Sw_}V~ zyx9$&SL$;J3C@uQV#?;bpc%@hfd}|o#{mPMZ>Qz2PomQ!8BeisBwyYz06Yy}v8Em` zjbRY;18(}KpT2_O@aWeeuTU9XTz%gnk3OFOPdUw7E)1&;vn^o0drD`;5;v1&}Oc6MJ9nA3q3E6z+oM4)aGcje%;3pVMIfy(=7xGcfa;U zXE8?Q5A>g-F11+DO72wCwUP#M?xZ`@e2-8&w6vG}m{dyE%SrklD*=~?-2kWM<*mq^ z2E$=8U(jEIxZ(aPQiluIC&+fCWPJjvFojbz0hkMU%IvJ&!*hm<4!a^&f9a5ZC$$TE zE^j5e_4}%b`FDh^#kfh}*1zL1*#8B~tY(=TtL22^Vwgml`Ubi}OKwkWPxhr3x2O9O z+dJCRi(7l-(~C;SY9(xHk1A`|e;r*(;}Z}@gV3$VZEOd<4rypQy(|JtJ)jbF{POD=h7>5mYoIk{{riM=NS?d~{ z1BoWPa<%ap%X*sdeJl}t>iKdXvnOKIm3%+!12u?lC%lOZ=bH2p;B zOd+$&Y90bhBeDfwfeu@8kC|(P20J!}D?IvCLp|glA&qF9m6|)3HKU*gE7%0d+?nXo zmRpOdd#}=#^Cb^hM*2Dv=NBuZ>zY!YZd_M465$fHJ&31JJS7_EicQ0oH=cu9mh9ew zJXvfs<9;pnH>NEn^w#sZgu|*6&YgM28RECGvj%~rJ2cJK#%Z-4f9Z*Gf9VJ1k@b8e zPhWwK&p!fg!{eW+zl%wi5wGUy-#5tDI>Yy1)6E&Y?>LSTX|f%y?~a7+U~BUS#Mj&o z=%&-+&k-QBSk#oe(Jw3$%x78VE^~Le-he?4L2(8p-ZwKmgCxQAL4`Yln~+@?Klm~- z`VhO7kW3saes_)j)Sn{}HozcDa;7247-ux;&R_zWiNmP02keN-)zL23NxIdRAHl?( zN6Pd^Xi-74z1gfb+u=)gjzHW#!ORR!RM9^)6!)hMal=O=Fsx6|u+};UZNP)Ay8C)H zmt6^@7PxGki5vv&7gTz7I6y~>l2q3j^d*jn4%%PCi9fDl&OY2T*(bJbL*@8vS(}g4 zhzsX)BQl>Fz@h)ZI5o!ZuT7vUK-sJrG=t6XHtQT}z(yLTN3HaP^1bz654I!hb%cF?3o@CSe4Xli1+eDIPg;$r0r*11-nttSNdj_?`TNsU7kx0F$#VspUAG zJ}pL)MXfv;P6N-!!K*NkUR|tp78g|7v9pVdd$zEsl^&f?rO7_>9L37R9eBThkCs35 z2T+AgkuKLLtPN0a=QfvWRXki2T9UZCbZn06Ov^`9qi%=xs<-6f8*_pBB?a7l31+Nb zN0qzAcweICIwSt7o9`IpizB7>dU67yZ%|3|uUVw2{F`wGAd~e=1n$18{l$@Xd z7h}#ALo;xBCE-&}msPS;a)F%W4PNKV3@49w_=K=|yfDH@or1n>%)|G@4l(=AEZd=& z=xTg|23?WK{cb^wyX!$@5{M|)SD?=PBXdb!<{Zj(ovf(7c(||GDV>PQcN(Ae}bAxP$?TS0hI!%BNYZN14^wKBE+5eOf1Rd#F)Uz;Pr`^kIXQ9x`bQ6vcwBgfPx(~++Fuc^fm|2%OD>}g9^?B#ui|BZoq3(OvOQv(C zQ?|-eA#YA-m4La^+=VXa#2z0Kv=MYj(tQ8@@O$C5+48o)mNa~Q?{3`XB@qrMkYa`o zUxvhLy5M`h28X8?V%~iD$PubZw&2ielNtU~a(Q>^IVey?eYh7(yZ^pMJ%=L$lN$BG z;Yp2Z%VvClM!juPqcXLS8mCR6Vo8r`rG4i2;xwtb3w`b;1Th7g0i8$+lvJnozP=6< zEixyR=bFP&<*A&^yI?AyolDHORmN1%8=VS@CI~+*U!w29r!bAFV3A&hKY(b-%CBFoQ?Pw=b<@0;RNg~xq6}4?f6{fhFd3zzAU_&iWRs9 z#AiE{(XpoaPM5to=el>Kl=h_MIHiBqS2xb)g3$}1pEQd`Qoye!$ z|4pY@;wFtBgre;xy*+w|RHux(q}!CydKoiLHk(KAg*P^dT+Uc#ufd0kz9-?rM3H2G zpd!pRF{oDo70zR2&(COq;Do1tLq-#Z0!U($6KQ*+7*QLoxR$B?tePNJYZ3oWx-)@Q z!x-5;UAz*>sa6v==-8|BV6V$e8(t<33mn~v9y)I&vnPvn4BOOFPG??F@O@-7>z^y}`j} zKrtKnyoy~FOnul`8BD4dKM#b3=r!wY_2L$!Y*}ujM>aih;d;yRLVCFAv6dd|{ky%8 zqMPJi+MmJaSPX?iXkEh7+Gzf{T%2MS=>>JNm=5tCP(Ip%DZ;r=x+r%a)_ruYhn#ON z0h{Q!jNvl7Z1^0lYZRx~n@8d6J^k;<3tu(zXQj)gHV;uUC?2BZA=tQDrOn)(+l#NG zmFt@sE-T?O$Wi9L0OtXx`!LvEq#&FU@uwU2@Aqy>x5!iKwdZa}S?~J^-cQE=&kbR| z{`DKC)~nA^--doo&)1vKuc5!HPtYplnf^EF>``aidOW#j+Wp_dyZ3nS+1`%!4u|-m z_*S6hI1l%YcG%pf1Z|Ny{{z*8dW?EPe~ng;gkQ6Y|JwU?@7wKfqvG~~I4XKi^qxrB z`}efy9q6)9Pk&!f--%FonEu2E?su}69z62q_tBaozozGK+Yj+9lmw%xNkQXnI%<)? zj$o+gn}Cy}z+rqtgcxKx*71!xPLfsICk_nPLB?RhC({NZuE73h+V2}`3R$%Q}%7C$A@kb@wuYJ;4e5%z?Xn_ z!8YK6M=fhH7I$IY13&$ZJnXljEm&*~ZIR6V36!FoOi6?nnUv(bioBzdX}IWm*L=Kwv_SAp9fgL zx=R2OeQ-Pyxh=>baqtqCoM`EZk;t%y>9YIfh>G_i^rex_@|6sz={g3FTSZZcO2HjxNu%v zI6E$Eiwkpc;UU&?gX#f<|1;Eqen% z{M%0%x7#HnJT3JVvB&l=?D0lO;qOcIhjO^{dd?R|Pj^&=~E|XGWp#WgBE2r(ImOe#~#B>Cj{rTB~&o@GbcJMUhA<{;ra1 z9NLT7^`TQoE7_kITec}F|KQ;Nf{fv!+lVV2x7vO%;`sWd6hm=^~Qku?rK~Z^m zIe4P4hQfzg6P{ZRolU8f$i9VFncnd!kJTTvAplxFCEC##6}viU80PHuQaE4edu|(f z#BhUcBUuGYhdXTQMl1FKT|)9|zRP8Ml;Z-!9SKr8Qj`)t0ZBhaQtLah6aspT0r9aU z0ZEUrBq5e$LlQ;!Yyqqmz1&p?0lkru$kvpeD zTDXJ*7HRepOemaW#TCRWsPTe1JPU6PG>>X$ z?ys@pvsvC>!WT#3KT&#k>~k4~!%7cahZHHbcO19m3oXY7A|~!?N=jaxUC^9OdCgh) zt5IvSk7J?@p(F7r2ph{^i>I=7?eP%Z6$-6(hZkri*~;<15P>Bqnb}X!{c+G*$=X={ z+I}k4k3SnlUlAjBCLM)?t)1~Kx#>%V;Ud9?Pp@7+jsSgw_42O};3+VI0H$o^^3PkV zSq)Ee%U;AA{WObXhxw8H)LRlRma3=l_5soHN@y*h|%}q zaW1tU#h)PTx4Zz8j{aKWig3w9D#hm+S>bEqQ#V}}O}*^ARH5Ip4QRsAcW9u0hVt?F z;2%NH%L!uZy9R~$R&5ZW{9%ZFf_6G|iu{>JXR^O5C2FLq`jg1VZD@~wLKnd|gr!hR z2M328X^*q-A+b5F9~R!}qiNlwDW0k}av)?con{+VGwwhh-| zPtc|lb7>p%YaGxTc0nAcfa%#%YGbx8v#gIl$A?dbYq5^T(GF%+jpC21ZO+0L`|t-)3=*rFOt? z2FG0JE~~iPHP#a>FK@>uD{w+tN7t+g6+d+hC2j_EG#1ln)n$+piiZgBlCX+ zAW9kT;H6~zJwpB17yW&RLHmTll!48vMxh~__HXO@=__pomY1-Cl00a0p;S^}*#!(z zAzaepZz{1sqtp7F#x1cxr%EYHE~OWpE})|VIJmFOC3xIE5Ox!MbTc+A#1ixyPzko% zvA^!ox4;s1>!*qhU#Rq;e$QU?dmtMJQt8O4sMoQ0A>z37S{SidvDaBYQf#%Fo)FgSTzu4ZGfQ>9QakW~UiOr^Pns$S_S-=s~+Dx24 zZYi@SOu?54;Ug==gdV#C1 z4GtGs3#CNm0T};|$W8plRBehcA%ahL1;SP=$FS(#fR^EUG#tt1rlv?$jG?88(0UkKRwtRv!^25umg*e_hq=lpf$`+hKy9%;pH6@1Ux0@sM*`fFK zpP!* z?KwI+i<1ad+M8B{B7Y!l<1c+yb@i&vxF7y|Rn}EGpvnWPyjPW9QRO%EcTi=4+zYp1 zIYP7p6ulFre*|^Qc7a}IF36Y2El=lbd!cwWSMP8k-7tR%!@#Y#rUG;{QY~E@k$d&~ zSZusn%Ar^TVtCU<^9AfawC(b%6+Q*D_`X&_;xp}o25$geon2~C2l>ASo@xN*^5`- zKSg{Ce+17Pm=CcW5J4!9t^I)bR%^!qk{XjbM)_)d9m%y-eE30>!fn^)pK>;(bReS2 zKE_}08jJ?h-x#b01n?<(Hoi!to2B`RE=V&=N~DVr6WgvswoJ=Y*D@}9d> z%J81MUu=5->7bIP<-xlM#(Ae~TS_Sy&EV|dY9ykCw!vGCK=xoU0`2C-*UHnq51JOp zQTB^mV(T!yWqb>t-W$c% zkLkTyY(0jzDsT0>o^^{m_TaGA8~PR(26J1W-StVeG(#)x^~?M9vzVUR%}ZMYBnPc~ zP$-%)fQ-SX5vTqeT_-+DUzinJ!+0vA72>16M9;v(sTWB$^k*S{LP-h!5EU#E@1E=~ zmk)p(L=CMkERYBMH7D6e3DlaSs_QAy--YZh*8m#Bv16t%`1L$NmZRJZ-x*E7bjR4M zl@7qyD_dTLJa0kgQMOGmgg|XRDz^R}#*K4a7PbeVy;avy&4qorH;9PAN06o9L{V!2 zR09aD$?XtZ*8vd`{5)mG;gh~2?p!|RZXoUAcb#~i%{6p*NMupG!Ve9MJ*c7il)xt8$G_oVL-u^c{tjr%!Ar77$iyfNCcP=ZDZ z9dp_KhC#Yp|1Hk7R1Y#g&FFgk6<|~$wn})yw=8ZAgEVFIpT$RBfNE4me<(pg-!08l zM(+{Z-bdcBOZS2<2qh=oMEpZqxKR79A@lmy|ChbDfsd*@^S>vVNf?p|GeFP?0ipz@ zjoR3NB~DVq%K$3DU`#@kfc^_<8f~TF9MD|`5+|XV97gG`-Nh|!rC^s<+R_#U>svxF z2`?gVA}ZRbSv_&6Mx{xR$UNWcJ~IJqx7+90&;P&sJkREnd(M6CbHBge*L_{Tt4(;R z-1V=JBwjPLp_PX3KqdQ1?zayF6Qd>U4)R@EkEoJ}$|y7|8}_<`GsuRzQwp>@yYJye zA6EO>H}%=HCNH+|*CDj8wnNye^LK8>Vf8hJ-dWdH!N*ebXN+KaV9EP%NNv-SsI#EH z!8j2fLTK@v(<{}7U}mi`dm!kmm+l+U8|i})CUE~TUN(e$wcOuM5da_a7mPCm5)Hoz zPDb7PwM3zfrn~8*BxG@9iU9eT^_H*l@>>7<-_$Roo5Vf~;*Ys>@H3a5$x>nDbp}1P zxVwfLCTmia!NMKk%LC?ecl|Q<#B`ndccuDe9=iko?YOMME47`2f{#<&mMR*?7@+$ z(Cm-OK9SG7b8B^cP3kH-+45n1ClCUV)ht* zaSIi8m^b5wKPNm=JRG{athhRxZ)S?+IpBYm#7}7R8=AQ%*3}fYGci)Qp$K5M20@-= zo>)JtXqIU!psHl1(8uTc)@!39`g%ztq|hnfKT%hi*rGZvMaz04uy<=%F8 zy-Y%z1#>4jWj(*4Mgh(Yf2pm&VM9o&tso%@GD=%Prmd}DVp3bdl}Ul-Nk)nU;4p<( z?x2rW=K2r1>pxdL;gCf7iCCwG7JxwEh2?UWEX3aaRq1e^2iu`(z6!M;Jqc ziB0y#Sq>%L8k*%o74@Z3Z8AykrG$}L&WNvbM!+Y`q@An&k@NSb62lZJjWBpev}8Ea zf%2c{s14V&&2rQ=yrCyl_bz}_t#wY{i7{|2{fXN(#X;B~fW$CEum_PLi{@=|@aq$W zFInWlC6mO>%NICq8c|c>M_d9`Db|a zOcm`E?4-@OLvng5dtT*Tgp;oeeNQ#RXgMlqNuk*;a=J{2D2ajgNeQaz`)l6es`C0L z>G?`@*->{+F3DCs&vm7oTVtHa558(`=cD_1b0i&_?L6t?uRxTp;Cb^YVJnoQ#R4Ys zx>J+rAcIGXEp*e;pyHqjhU%%3;16o$w_;ULzdz{LD%btsG2ScJg&t9lie;7SeD_wa zTUu4Q?%PW?KHRVYXXD9jL=$R|-(bT=T+}up&K7)fy?ibhs4faNti#G$CJ@Ch{04kp zUoB@Awi}H0c3&+A%Vzd(LEo{+sAs7SG$!@HuZ&IIa*x`9jaf!iN;<3K%?Dx3DzB12 zkx|?EL>+G9VT7bWIWH|TTYfJid@FB?>Kd6MwP02cRi{nOUJ>aemOP22qPvqu6_#E& z@m%KdUqjXCZ-|uZSLG)35NO4CU~wl&M%D^@h}UwoQ_1v1qetJXFk~e>6fq!_#h4#> zDR)0b<9hXPjHhKV9%4{jf#z=Vr}9#+Uz0mC)1&>3Q9ZAss`gafC9_uUOUzn=I|kmt z*%szqWD2Y8i-Z17Z@%DR`OA#HmiOWn@RhwSH%*&q*f{wGGo|FQx4CM53$nq*sF?T3H5~}ba$M)Q* z$ZT7cSW5nH-GTq|oFmhb9gEiAc4H1?p@8<4+!CigyvQsfU#g?&!3<~K%|7o&8 z{}j>s)<=yF2(UT(vi1eucFW^p&IRKzl7crQB5529yuBt^XnH@^MrM6nie9p-C>n#0 z&}`$80a=LzDng+4qgjVxr?a2PdJP6FLqBEsVO20c-Gaw(vG-+t3J{fCYj6=At%)wa z6*}!W5V}O}r?Y%rMYqj2=MJU-tv*(5NbYyXfBHBumT%itqy{CCBA$-&U|6&7X4}88 zFGv}9l;2VP@;mml{7&hS-~3bjR<0YBhNsGPDK7OGYbwWtF7=q$sUFvyq4;M z1VJ|KKm;w=AbKUN8F}*@0?}=Te2p=}RHr8As=RB3uSI6(K)!eYKmb4QUXPzDiTk4I z`GPxpMPEOEKkSIz4_CTJux3@dUu?ElPK>Onye2!lGXF)7`+L*LA0JcJU#~7oJFt)1 zpzPNi<`$Fd;1OfDtM`R+H9YDu%OBUnse9{odsd{|K5=_G1Ml3($7^c&7)mH2?=9~n z*mrYbNgNAXxe-m-WySF>@!jtva5KS9^6?!!nU(H^c%C%nE-Uf@+)rBW<@j6pI^VcT zUAUjX3)0BdQC>bH)?;|;;VGUEVVdQldYKhT2KFgM*d-zoBNq!6kaGFUypX~Iva;Y$ z#8~AdHg2pJlAQ%}#QP^$2(sW0n3pj7F$XK%qk84Z)g_O&E8QcPSa+!G(_7bMov&K= z9<(f+BAyW`omQc#)RAC%$gQS$?!J;Kh3)ZQxX=IF+pFNl^X)Z9+0VDvUFzLxuOiD| zw7qN>w^ueFLkYI8{e||bvf}vb?d7o||If8oh82lwFB|s%BkgsQv`~xbsLcP|rC&l9 zN~l#ykED%a?L-TXU1nwO1lyGUd`07s`GyBJfN8M2Y%oD(kJB#1|{ z#$O7VK|V%~E6gLOQ7b2;@R+LYL^jC0HoEFDURnF2f_q79SDauJafi-!(=Q4GOvw-grw1e>v0{zt;A87xaWBDrl6bmZ zJRwDxqM)BPNfk(S45N$(2oXq8mD2qWJK?!?Rc)0G!N0YN%;;dXa2P`ZrhV4Je!>bi z&}v~f&$MdF7%MduIT~Cm)mbGais)VPE=3NmUe>m@gSmG`+uB=rpRud9k%@O!6{#O0 zT(!%b#SvJ^=W*E-oOLh7b8Zsx9_*17_nN=VV6u%Z`$Azf*O5Emip(kG7*R;}@sP#6}dOQ2CD%>3F?T^;m!hC5RiT0#8RHvAKe2S+M+h1M9 z(QGtXK0%hLV0T?ann43r>DS^pR=s89j*8tO0db?fY{u$)2|J<8d;$*Ma&Nv8yh^Q$ zY)9}4aP}K*0t&X5Yq!Bj#u2L2ER%T6x7m=>eJMQoY2d_%C>nN``GB$q@>QSI=0@?` z^(+5;P>r~#MH#zB|034s3xUjPSjFk#Ws3c4@n8=h%3&;Gjf%1hdb1ok^r7Za0tqrZ z62sDgt9t0TWs&1mUGm(V&dA~AgnE&&#>*k~BG74(fdWs?lI_5=y|wM~#-6bhRPYmIY8xD4srqT?;<|KZRXj{;>Rt|{?`R{eu&$Lun5 zB{I^2D~3RB{uabTwf$BECEr#~A}xiNpdg)5q|lCj|U_JpnESB61ObGe9MBEKjpn-3^Y zVkO_iPZxY`A^!ln%s=qaDm5gf^#b?w)$&>^Md`UZY?1sCy?TqC1N^bX&FBL&LL7AzYdWG)b$~Xlm$~Pzmg`fJQ+N*yoWl5}W)=E?!on+ybyrJ4`R4?Q=9N|K`NSk2(h~2iFS5uk* z@p4&(i@==}D`_~z{JW?Z`>e z#l<22X>%Csg2-;}apjZdjmvL_T^wrR^65r@%lq*mha2kV^+jeQH}rrnep;@5DH_~< zuB=odc!>kQ6~Ua%8%QZQWh1{(*o5q&#P8(lfUfeA1Kz+*tQDJw3P`(&rZY!h$gAqz(W$rkmO&ex^ zu`)MJKVv;UG4f54Lu@0ft@v<1@|nfO?0qH^)bxh6ua=m<`J)Y>+bX z6?v7}ZkP~v%sV$R6`+mMgEYBlHt!-vqcyz1`=W+~l3p7b)hRBNg6kKmaOyZMsbFfF zepY^Zv)T#_lkrPBYP6$MI5O%a0lH`6w*(~hMT|abKk6*hpo%-;8!0W@mAwQ=QTg$< z8$Ex9ARyupWxJ+|ANl$B{K#mY52Hn&v>!W%VIp#&4uRc;RJT#OaMLPQPq>Gi#=hd* zTv+=~-17!Hgk#A9R4qi@2m{MvkAcb zL#k%J?3VpO;4Jd#clIye?`Remn`8?hJ2lC}Ty6PP{tlRR18_`(3L?7BdYl)C_!i(}DVm7PyI(eU$ zFFcIuUAj&9>-ql}dvB2UYx6^~_Xp*DT)r?yD*tQceONw>RL%Mj;&0+TvSJB9Y)8w3 ztCv8>qLAo>r|XvoXWd0#SJGg+1TiI-4Zofud+j1~mD+c~0wYX3fN843v_}zj155kW z)K*;f!o2qip7FM`FhT%NX=v4k_8rZ3)>^VIaxT!o( zt9Kx5@Yf^$e5Z4KJvl(7>O-Etm6*fH4WH`3?W4FOxhJRqYx<5eFOa~Z#ZmsM&3Ozk zh3F9(WdrX)a_h7~RO^vV-zK)Ta+}f>nIitomtY1&CY}_ELl9Za`Oot1Z3oCx{>&S? zt<}ii6{lTZm02KD(mHa6j}cV^>^#V+>{C<>3D3W=&E_dJQzTB64JcfeU{K^Zm$l)q zMA@RalFiwhe<>|u;qbx{Rp&n`@9e^y))rQ7J)#>x?hMUq$+wWr{?qvPjNgA3|Nhti z9{&BWEc|=t5_fKh?J zci8j;RSG|ChSMzlip}=4>=+DQs(1-+U-B^5v9dD;(CSWwdD}P5A;;`p;!n#FqK7fZ znbTnwJ|^;eRcQhdy37+T^_X?ILiwQ>!T4QVA=#KczyUG76!~s?>ci%(^88|-8;XVm~*6|w+xQ6v=!q-y&D%A-ZM2rsd^A9 z&!VwocN}-x-s3gzDZ~Uh>w7Ah=6}I0k!-#NuhDaxk~8G$SIeizWbH1x&HM+dLN0@~ zETbS3sf@lufzG(-^b2da#m&l`O{<)rv!maEpI%S&!1PdyQMjTNOtThPkSq4aFvHHLNaDjTK$$ z`Uq8Dp;^E~)p#xESy5*#tL1EbQ7CVN`N%0*cmywrTduUAFe8k! zih~jrt&72Hx7B!THFx9F0@r#5e{#juccOfbv`Uf0mMXE8$cDV&e(L@b73rZcu!xFF zI2PyGt2t(0BN0~Jzk|{KOR(O`Hy6k)`b=|(YUH5*1f&e5O6hJ!>+_PmP4W}IE3$H-an!tvx`4aC z&1obeFy0z4-CAD2Ow_XGpv!0i3;jiWCFXD6mc~g9|LS?k-X{48U-G<^ca!{tlb)9n zZ<3#OUzf}eMP@IMbL=>PgoiYq2TN#jJ^@vo?AU(0d-*6mWWMlQ8SpR%s1J`38AA3XCy({ z?+20n6jbbAl9{RvYGdbQx2O=(1(&m&ij2~r*6|e@6!0eR7n#|_)b7Y!C2pG~y2$Y& zbByH(a5;|mMjaDz+`Nnzh0xPa|K&{0q1pnG>3mDIDhPe?V6M-#k|;6{o9Z05`F_G_ zsa2C>?oZ=hzFEU{ll%Zd1Ww$ybEhbOON-0|5`*kR9w&whPtC6eB&lUDUWRF|wfhex`-Sapn~lWcErC#6icIXF2E} zsSQI^Vn6yY;(i}FcW$-)P@pH0vl}GXpWEW%>NL}sHbBU))^}-{Kj)-o(?;@uk0d_) zQfQjMg*mcXT0_$W!_%^TK4=?=+TG^Sy1~Y~jK&jnS@ASj z>-h$|%>1&1jW$@b)nJl{!cAN?E^sD(wJUH27?w>L5COqTlt(bddNKdV0<2J`qNs|i zt&};;UZB2L=?{ZEz@)f0^2x8LKW^SXifi(@KIg4HZt4($J43pseEvip{wproGh;5hq!V z{^QVU&l68Pp{`n3Y_r;$TxpHTGYa*-&_iQop%9kXrqsB`;nU{neX>j|2C5}cYU@s= z)4YQWR2xVT!4@AVqAMJz&t~3gXnsM0BXmGZ<}^3fCu|`51>W|W(@nmn`sTI zFg=fALC$%j7)^%po1KB$7LGgSmPp>FXnaDltoa@^l(n`Z> z=O&KzG_6aJIK#t*6J?Y*Wr!28G_FgOdI~$+>Xk(muO(auj*P(B%T~H-=ME$C!!XW=-GR?8TS;oei288t2N?hw+1qTkY2KG>UNk~d zyNd;->XS!=oogenO5e|V*$&*jl`YFp|BVH_f0IJFo4rgM8(4F%O}o@sS)~}oGR$v0 z!E6fv%>#ID<%;FAjl9d|1}{Oq%R5Cu;a!h5l+jSj25*1PS+_rEE2Q6)ZxT-ER~NLf*}6TsVdV$F5@H)yK6b$dej@i6WH_ zGqqws^9jllXjI|6z`4)$5f^&#;3fP<;M@Rk#mLnaIL?0z?~$;GX7*cvTF_mrg*Mhd zeFMd?(tthhEHkTQuLGy32$48JS#OQr@N_RFD-;T<`>yR2RQsmzdNpU~_mIPyaL8vC zaWQ7~Y@@zFWcJC@kuW_$Zre85yPYZg>{{V=Tn_b59$c3Tc2sOdJ^$yfUfr&PH48-{Ro zVsM5lG{X}L?jW8!Dvj%=RR*)C6%^d8e`hV{h81UQHr zG=W179XYjXyL99YkMp&#Gh)8-jW27ONN42QeEOe#NvA!*Ki zRr)pH40~65iL%>f6DA25(+>bR3$ano@WJT3rFCT8qs>-+e zd6Bud3D3brRmDcW^z6v1y|b3ZyBmbs+M6Jw3o7}WywJmUK8ja0gl0H4ucLgNl{c?f zPuJ#0c*-ueE6|_d_f#5lXCUM0^3~#85H{79e3_d4DNS?J(iz_ZZ+iFdl5D22D3dr~7O@WpvRAI*Z2E}m&&^WWuDm@#9LN^EYq#SD8GljkB>fI!tq`MmyOcLH?JObH$Ws!^{PrZS@5+s} zJ1+7tgThGw*$9OY_h-y z-C4J$f2-VV4>yKTuw;_w@M4IE-1`Oq9G&er@2rV4@IbfddrQr4%8Ob`qxDy2b+uA% zPE@UN?6eoji&Wa+i)3Z+rTP2|xmi?HQTO*&ZiX86sHec+a}k%ssEob0dJ6Ru##$+1 zf<#6VDi=zmm3ef}+LKsE5ejp9Ssu-Geuc0^?lw|4!!~`{!D{5=^W4IxR6D!$u zD2r(EJDn0W6e}f0P-LdUiLOqRBajlVj&Jl0G**1x<~wIA506sZChfK_6Hm_G#)^S9 z-{-bz#0dD>GDoPSzuJBqSfK;+OCcCatmf}=Y_zT%T^ADNjp}1FUm9)t-VPXY!B4lfa4*jtx(}f z^CxhngnTE9*tzh>#`Z*!w59p8Z1xB~K$&`2^hJ4nV9%sp-zmGECHWgZwZfE2>ykM@WO9khsEGXhtkT?P0U}(<(Z%T%;j&W^8Zb_ z{057T$|Xn~@UhD|*86Fh@qkMoXa14Z{DR}^nwMpYO$F?Q z8c}=WlvOFRXU+!II9KaC2Uo*&dO~EHBRnd!I}%;B)zX=q+>wlGG=N>+ zNp3hOs+K(Zc=QPtIgHorM_R(;laJc>*0lrRW@|W(vZkO@dz%Q8UtYYZ5`9duEpGPt zJ`4yUyIfBx@+5Rvr`2K8)ocNFV-ckB;pnUl={?54OLs~x+oB?LF?|9G- zRKv0042Se}KnY9DCwio!7=YR!YWi~rtX8C(vcpBXKn^7ptY|To=CV?bnmK=D@TDd< z`$x_8$*o1-iN4nZCv03!2zZc;%yd4c&gNU%`ETibOG|FnCvnCWHL0mNNBTYn^%MR9 zo;^lu-xAzAj5c}N4~J*-O?=)C%^g37!-rox{K4T9$#3YV#Xr8%@ja6y-m@RB8Ro^` zN@tDRi{BMP=VkF>49Y;jU%>%eYT*Mz`d&w{@^zcB&p2wlCQ03@$J{CwE#B?19jHB1 zuzXbQnT+L$?q41{`a!F)JLgF4+vAU#EI>I&Ai9r;Y!^mcV>R`#1MXal*?o>VAt&Y4WSf5$T8@1=&DO%GIDoC7DhQ1b;P@^;F zXk+JSm&{Rc0wCUK)li<>6JKGQ~B*86dX2p-5PZhIBqp!cwcc#(zS)=c)tf9Wo8-3>*eX!z2rmREw z&-}$vA_Yt0hc9!(SeW{IIYoj5{jkW2yX)`dmu1iWu$(_F#xCQqTn-$z5N>XE*FVRX zzy}HL`p2>GzSerzzI(Ig3w$ut-EfRJkY0ld!{emDLI8PFc;d~9&iQZJ->fj-OayvH zsJG?rhRygj&;3Ns5Le*8`yW-L~M{PZ0Ez4cUNDOi1-gbN@_b)K$424)O`j1 zf`uodpSo-4K-ixZ|F2r^V(-4ga+l18*9N*rYx8c>ZoEm$zDdgnbdLpmq8p)YVWc7O zBjV{_u&fiy_pw-Id~;m5KKi1lpX6G$eBFI)8(uTJ;Uc-9TGme^)h@o&wWM)a4xDkh zzxP9Ya0&iRT84O39)FHS$`pPKiz?+mW2qOHhp^lwmIf>fuyhNjHugDU|F&gcCLScV zd&Ppx{K+aTZw@&L=+Gr^4vAHiYM!3?O6HI}NZaViX628iT`nhA0u(gPB6CL$9JF~} z!MufeAJc<5gQ>?PkoE8IT#6ZveKckQhT+O=>OkaFA7;8$v_pv&XC;TZ%IQ_|wKeJH zCrp7+(x><^1FT}K{c>w(bXagGEoTx8S4gBm-A~Poa|AjI6tL`k8Ska$coXPg{PQn)hFq9;dh}kA%J_yRu3pS?t0m081tNg&U3+G zNXHRbp!1_ZM||baU2(jNE>C!@t~P(SirfiykLEJ}RoMl%2cc`1>7oIo8aZer%8V;= za?ZFicYUqIjoOH>hvvkg6JlOkR{u@jv#6X{J+@5dYV!{+*>t&>L&JrEjttU+?h$@~ z1wq7x$B4M_B}R)?7ozAi!S48h)W#q{j3Yw>2B^4rzPbDc(9w1W_9$ljiKN<8=mZx0 z68P)YGB3$38%!?OKY%)4kpm<>K}1tq^Tl^wfTm3qTl+MWLl5_!T_MnQ+|tAc1yyg2 z^Y#+WmOGD0=2pH}U$H2b z@(otXLhP%H68pM!GAWqsQiQ~IA)VOx?yk?qJ?1A9d#KPgzqqWlIxbY0I=>i1Zc$1w zN_ZFvn97FK-SEF8NTJiaUwbYX7k)a%EBSZshBdDgx58$6{*pOZR8>MrIT z+B8?=7aFsPxq*&vt*J;ms59bB%EUPakvvp?s6*IJ$27I){K8RCMd&nNAZ|`9)`d$c zLy(=7+9b(F$~Cx2at>~iJkd>(M{SZigtwASk_+F?!`+A9P@AN^Y?3}zo1|2=N%9PC zl3dYElGEBGsjZRPBstk6x&Ca2w1{0%U}7U(7yZhvD$h4ro?iaGsz>;>UtV!-b>{-f zBk1;HnhW&t<|~lREKSdFv%$|+iI9ex925$h``0Mv{WysF-9FupG`|wq4V>#-`K_2P zuUi6b?!bFJ=n9rLPY?~uE58QZ+$2O=MHp2M+uwRf?B`hk7Rzw0=wibTB7~DYflpKI z=KX_ycj?9YUyTzu&dts5L=+H0gsBOYPbi17>aZyh{DC5@RuQ^=SVaKUMGg+ukqHMlS$=#1h(>q1g%S|E#>gSL~AC+C0Xvv-e z3%n5XsUGrpl`&&r4%`RucYvFscbQo%K*i?m#0SNc&^k7@JgBqM=g=mJvwB}z`9veL|efn=Igwj&&>CE3noIm3Ljyciwro}q6lwO$z#p!d{e_CdU-gl zSq&1I)2H{cmS|rqHCtO)Wl?UkG*`rEPCYMz+v}#vvcuJzU+Im3w4F{PCl#3=FPD<9 zPUqH7Y2}r%S|q)30z)NG*oEYU9N$UZ{exyC%g376kOeDsYn(p+!eAC$WT8NFNnE}z z^GaesvT4Q&Nx?r*YF!3sc7Sb2<;7^oXo zli<VAb?Et)1XG`HxM69JbSzp5Ic)O@K|Z684ElF>b+cc$G@%YK{}^OL=F zg@Su?_U6uk+EovaS&=a$GTCl?OkY)(r|$Y@JVKaFs`Wp?HvYG~MMkCZEwFUEE%2OV zk||>&a7h40xYvpzaH|)H4p`T-219vo|k^1VoY|SlDPje#Y9=jAkkH zZG((8kq*QJ!PS7f{@273&Nh4-v)b$pk_2Qe_u5Bst&X>R_o*&s`L4r#R>ZeO@MfwL zLLnCcVDShQZkx|8s9rviH*1v@4taO|tr8RX7u$G&Oh|nb@n8V9<$KKA z=3bYTt$@TI3)!YDDb(Bf2)fv>gB=v-UiU7x2zSN4$HGhU;*e{J*T=Yb z4$C=G88}0Q?4C6%;M)=(EZio58zqfVFS&xYlaJtbrPsHO)6F9)md7L)+E_H86#-#o zjy?Zfv%Zs%p(-rbx5fS7157~O-{6ZuKcjch>=Wh9w=oB$T2FAzxXs-F|GX{M&9}SP zE)@@j+ocV&3O9y)JG`nRF2Bks*&gw2ZyGVJ_Om2CiG>(?c6~d(Shf4;4TkTLXw|-`-nM7?HhNXQYXaTU#mF7^T|c@wYbs>n_MF~} zGIkvq3;4FjyLXP5Hmx#1=28N_4e^!jwiH`I0lLln>nnpEvDKZE-dTgF#ea~+t1il- zocrhtgIRPxxRR-*I~nI#y=`%?m7{=BxJ5<<*`u2_>>{y6(b~J(DA_^==`Ag-dV+Qch2)xaekdeSWwj{mwj!gYsI;p4a~X!R zZGTT!TfiiCn5zTU81&?mK_cKs3Wxi!baL#>5~9>gouh%JLf3;G^& zKX^T*Q4Xv!=cc6@dwhcXhRoI{mM5c)9sD z9=P6VAM|IfG7Fwovub!RdalkSgwoX!QQ-~)ePlrSpL?An@OGT`LXo)=l9VhshP`)Y zwu5uuAaj@bL#8-pG`1t*OUxyMNtpMlL}j^)Z9(KrDT~)TabesPW|%5WTaoz-Xt4rF zBW;sNVXl+BWQrr=92sgs(34}mr;F?Limu#>F6}b&QPPBC09}f!22=k_1*~OztP0pE zkq(|n&@Itp{+5uONDve}-BglVe|y|meVkG;ieBgo&L|Uno~VeD9cuj-4=d>K!su9{ShBnRfNTIoYT_^}@{vLS6JDx|c*wshhZ|$gKu(7_lwC1A$M4~#Xqr^m^+c_-l)A*Vs{P4mFAJJ|A zZT4!=Ytff`^@?lYgg0Ej6B?ti!ms)ryzrM=yzn!B=QMAUJ|Y%5Muc}twxepS*%(t6 zNWV)AZoU8oeZV1k;1+4V%ec*zJKw1%D9UJS@%(4DLmmt#M=eC+620{^9Km~BCG(3G zlvkAB3D-ONZ|Hm5rSAnfPOvMhkX_jyV!N_`UU%`XY|>L|yvSHBj-8OEvP&NQfVCSd zHiOD0M*}U{SUwQ=aHz18ut^wXke*1+WuxpV9^A}l(&Hexx0yGQiB=9cFvG&u<1jy9 z2DUbE{|<^)Z$dNWj4Op{HpzTNF6qs$L9OKU;jF&I%oW0=+d=tI^?)!fTB{({k zQe)d#SdD;6&mFr5qHdY-u|Bo9SSU4BjysSY7xF|g^SK((nlqR$zQUudfh|&*N$m;Z z#1h0ES?cO5pzd;*ylHBh<}C2;*Lz_Tgtn5^GDnnI#T5j7shh+<*NpD^Cy3k&&brWJ zW!u)U9}Bqe@D=MYc8lgxUxqPd5{W}~uE<0bQ%|L1F>i((vK@dY0IgNWh2hv;{}2wV zXH<9Q99huUNBlKk3(dUInJ;^dl_SkP+%Ot@pq!+)BS^up0J~{3R1pNJwV~}csUQ@< zif$XGs?)i!HP`18Au2gfTe`GF=N4(nmhT->Hl|3OaMP+hh{i1P(c#^XSfjhX1rGpC zy0}sJQf@`MyM8+k-okYE!*Ww?>AboyVE20YzJImP%KgWZ``pmXq0!u5VkS!NPeWy@ zZcmil!zL9TU1Yuk0qEiaAi#`vUp!7jt3793$-T;4tO>6mKgGqmqqsPn7*oF0UrNPh zSepcHLy&m?oNhu`b0-#PQss)3JGa6~)d0X`H4f^2oHW+?mXhf*i0BRba!ymH)CuTv z>d@=UaM!;<2@x`eltt@Fvzd>J*F9;%0DW3JW=zRe^+{#()v8bV)K4_M-8%`rIzQ0g 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