Guest User

WiiMotionPlus / IR / Passive Pointer Control MOD

a guest
May 19th, 2012
73
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 16.71 KB | None | 0 0
  1. /*
  2. Wii MotionPlus and IR Mouse v 2011.03.09
  3. by lednerg
  4.  
  5. Control the mouse with the Wii MotionPlus accessory and the Sensor Bar.
  6. You can combine both or just use one or the other.
  7. This is just meant to be used in Windows, not for FPS games.
  8.  
  9. Requires GlovePIE version .42 or higher.
  10.  
  11. Leave the Wiimote on your desk when starting so it can calibrate.
  12. Wait until only the first LED is lit.
  13. When using MotionPlus with Sensor Bar,
  14. move the pointer back and forth diagonally so it can adjust itself.
  15. If there is a lot of drift from the MotionPlus, press Home to re-calibrate.
  16.  
  17. Button remapping and passive pointer control v 2012.05.20
  18. by Mister Smiff
  19.  
  20. D-pad emulates keyboard arrow keys, or mouse scroll wheel with B trigger held.
  21. Placing the wiimote down will allow the PC's mouse pointer and buttons to be used.
  22. Pick it up again to "wake up" the WM+ pointer.
  23.  
  24. D-pad = Arrow Keys
  25. A = Left-click
  26. Minus = Middle-click
  27. Plus = Right-click
  28. B = "Shift" button
  29. B + D-pad = Scroll Wheel
  30. B + A = Space Bar
  31. 1 = Hold mouse still
  32. 1 (Double-click) = Reset mouse to centre
  33. 2 + Roll Wiimote = Adjust zoom
  34. Home = Re-calibrate
  35. Keep wiimote still = Allow PC mouse to control pointer
  36. */
  37.  
  38. // ==== Buttons ================================================================
  39.  
  40. var.LeftMouseButton = wiimote.A
  41. var.RightMouseButton = wiimote.Plus
  42. var.MiddleMouseButton = wiimote.Minus
  43.  
  44. var.ShiftButton = wiimote.B // "Shift" key for alternate functions
  45. var.HoldButton = wiimote.One // Holds mouse still
  46. var.ResetButton = DoubleClicked(wiimote.One) // Resets mouse to center
  47. var.ZoomButton = wiimote.Two // Hold and then roll to zoom
  48. var.RecalibrateButton = wiimote.Home // Press and place Wiimote down
  49. var.wmPointerWakeup = 1.5 // Movement speed trigger to control pointer with WM+
  50.  
  51. // ==== Options ================================================================
  52.  
  53. GlovePIE.FrameRate = 100hz
  54.  
  55. var.Zoom = 1.20
  56. var.MaxSmooth = 95
  57. var.IgnoreSensorBar = false
  58.  
  59. // ==== Script =================================================================
  60. if HeldDown(not starting, 2s) and (var.started = false) and wiimote.Exists then toggle(var.started)
  61. if wiimote.Exists = false then var.started = false
  62. if pressed(var.RecalibrateButton) or delta(var.started) {
  63. // Don't bother changing any of these numbers.
  64. var.wmCalYP = [ 0, 2 ]
  65. var.wmDeadZone = 0
  66. toggle(var.wmCalON)
  67. [ var.wm_x, var.wm_y ] = [ .5, .5 ]
  68. [ var.WMIR_x, var.WMIR_y ] = [ 0, 0 ]
  69. [ var.wmMin_x, var.wmMax_x ] = [ .365, .635 ]
  70. [ var.irMin_x, var.irMax_x ] = [ .333, .667 ]
  71. [ var.wmMin_y, var.wmMax_y ] = [ .400, .600 ]
  72. [ var.irMin_y, var.irMax_y ] = [ .333, .667 ]
  73. [ var.Hold_x, var.Hold_y ] = [ 0, 0 ]
  74. [ var.Recenter_x, var.Recenter_y ] = [ 0, 0 ]
  75. }
  76. // ### Calibration
  77. if var.wmCalON = true {
  78. var.wmCalDiff = EnsureMapRange(|var.wmCalYP|, 0, 1, .01, .5)
  79. [ var.wmCalYaw, var.wmCalPitch ] = [ var.wmCalYaw, var.wmCalPitch ] * (1-var.wmCalDiff) + var.wmSpeedYP_IN * var.wmCalDiff
  80. var.wmStill = |var.wmCalYP| < 2 // this will be true while wiimote is ready to be calibrated.
  81. var.wmMoved = var.wmMoved * .95 + ((|var.wmCalYP|<3)* |var.wmCalYP|) * .05
  82. if var.wmMoved < .0001 then var.wmDeadZone = 0
  83. if HeldDown(var.wmStill, 2s) and |var.wmCalYP| > var.wmDeadZone then var.wmDeadZone = |var.wmCalYP|
  84. if HeldDown(var.wmStill, 5s) then toggle(var.wmCalON)
  85. if smooth(|wiimote.MotionPlus.RawYawSpeed|, 29) = 0 then var.wmCalYaw = 0
  86. if smooth(|wiimote.MotionPlus.RawPitchSpeed|, 29) = 0 then var.wmCalPitch = 0
  87. }
  88. // ### Cancel calibration after 15 seconds and reset variables
  89. if HeldDown(var.wmCalON, 15s) and not HeldDown(var.wmStill, 2s) {
  90. var.wmCalYaw = 0
  91. var.wmCalPitch = 0
  92. var.wmDeadZone = 0
  93. toggle(var.ErrorON)
  94. toggle(var.wmCalON)
  95. }
  96. // ### Calibration LED Countdown - resets when wiimote is moved
  97. if var.wmCalON then wiimote.Leds = 15 - HeldDown(var.wmStill, 1s) * 1 - HeldDown(var.wmStill, 2s) * 2 - HeldDown(var.wmStill, 3s) * 4 - HeldDown(var.wmStill, 4s) * 8 else wiimote.Leds = 1 + var.ErrorLED
  98. // ### LED Error Flash
  99. if var.ErrorON {
  100. var.ErrorLED = ( var.ErrorLED <= 0 ) * 14 - ( var.ErrorLED > 0 ) * 1
  101. wait .1s
  102. var.ErrorON = var.ErrorON - .02 // (when var.ErrorON reaches .5 it will be false)
  103. else
  104. if starting then var.ErrorLED = 15
  105. if var.started then var.ErrorLED = 0
  106. }
  107. // ### Roll - Combines accelerometer and gyroscope roll measurements
  108. var.aRoll_360 = var.aRoll_360 - ((delta(wiimote.Roll) > 100) * 360) + ((delta(wiimote.Roll) < -100) * 360)
  109. var.aRoll_diff = EnsureMapRange(abs(wiimote.Roll - var.aRoll_deg), 1, 10, .01, .05)
  110. var.aRoll_deg = var.aRoll_deg * (1 - var.aRoll_diff) + (wiimote.Roll + var.aRoll_360) * var.aRoll_diff
  111. var.aRoll = RemoveUnits(var.aRoll_deg)
  112. var.gRoll = ( var.Roll + delta(RemoveUnits(wiimote.MotionPlus.GyroRoll)))
  113. var.gaMinus = abs(var.gRoll - var.aRoll)
  114. if HeldDown(var.gaMinus>3, 1s) then var.g_to_aRoll = true
  115. if var.g_to_aRoll = true then var.g_to_aRoll = (var.gaMinus > .1)
  116. if var.g_to_aRoll = true then var.gRoll = var.gRoll + ( - ((var.gRoll - var.aRoll)>0) * var.gaMinus * .1 + ((var.gRoll - var.aRoll)<0) * var.gaMinus * .1 )
  117. var.Roll = var.aRoll * (var.gaMinus<.5) + var.gRoll * (var.gaMinus>.5)
  118. // ### Wii MotionPlus - Converts [ angle & speed ] to [ X & Y ]. Accounts for Roll.
  119. var.wmSpeedYP_IN = [ wiimote.MotionPlus.RawYawSpeed, wiimote.MotionPlus.RawPitchSpeed ]
  120. var.wmCalYP = var.wmSpeedYP_IN - [ var.wmCalYaw, var.wmCalPitch ]
  121. if var.wmCalYP < var.wmDeadZone then var.wmSpeedYP = [ 0, 0 ] else var.wmSpeedYP = var.wmCalYP
  122. [ var.wmSpeedYaw, var.wmSpeedPitch ] = var.wmSpeedYP / RemoveUnits(PIE.FrameRate)
  123. var.wmAngle = atan2(var.wmSpeedYaw, -var.wmSpeedPitch) - var.Roll
  124. var.wmSpeed = [ var.wmSpeedYaw, -var.wmSpeedPitch ]
  125. [ var.wmRollFix_x, var.wmRollFix_y ] = [ sin(var.wmAngle), cos(var.wmAngle) ] * |var.wmSpeed|
  126. if var.started = true and var.wmCalON = false {
  127. [ var.wm_x, var.wm_y ] = [ var.wm_x, var.wm_y ] + [ var.wmRollFix_x, var.wmRollFix_y ] * .015
  128. if var.started = true {
  129. var.wmSpeed_x = var.wmSpeed_x * .8 + abs(delta(var.wm_x)) * 1000
  130. var.wmSpeed_y = var.wmSpeed_y * .8 + abs(delta(var.wm_y)) * 1000
  131. var.wmSpeed_xy = [ var.wmSpeed_x, var.wmSpeed_y ]
  132. }
  133. }
  134. // ### IR Sensor Bar
  135. if wiimote.dot1vis and wiimote.dot2vis and not var.IgnoreSensorBar {
  136. // Resets Hold and Recentering when IR is seen for the first time
  137. if var.UsedIR = false {
  138. [ var.Hold_x, var.Hold_y ] = [ 0, 0 ]
  139. [ var.Recenter_x, var.Recenter_y ] = [ 0, 0 ]
  140. var.UsedIR = true
  141. }
  142. // Finds mid-point of dot1 and dot2
  143. var.irDot1_xy = [ (512 - wiimote.dot1x) / 1024, (wiimote.dot1y - 384) / 768 ]
  144. var.irDot2_xy = [ (512 - wiimote.dot2x) / 1024, (wiimote.dot2y - 384) / 768 ]
  145. [ var.irMid_x, var.irMid_y ] = ( var.irDot1_xy + var.irDot2_xy ) / 2
  146. // Finds angle of dots for Roll
  147. var.irMid_angle = atan2( var.irMid_x, var.irMid_y )
  148. var.irMid_length = [ var.irMid_x, var.irMid_y ]
  149. var.irNew_angle = var.irMid_angle - var.Roll
  150. var.irNew_xy = [ sin(var.irNew_angle) , cos(var.irNew_angle) ] * |var.irMid_length|
  151. [ var.ir_x, var.ir_y ] = var.irNew_xy + [ .5, .5 ]
  152. var.irSpeed_x = var.irSpeed_x * .8 + abs(delta(var.ir_x)) * 1000
  153. var.irSpeed_y = var.irSpeed_y * .8 + abs(delta(var.ir_y)) * 1000
  154. var.irSpeed_xy = [ var.irSpeed_x , var.irSpeed_y ]
  155. // Matches IR and Wii MotionPlus Position and Scale
  156. if (var.irSpeed_x < 40 and var.wmSpeed_x < 40) {
  157. if ((var.ir_x < var.irMin_x) or (var.MinMax_x = 2 and (var.irMax_x - var.ir_x) >= .15)) and ((var.wmMax_x - var.wm_x) > .075) {
  158. [ var.wmMin_x, var.irMin_x ] = [ var.wm_x, var.ir_x ]
  159. var.MinMax_x = 1
  160. }
  161. if ((var.ir_x > var.irMax_x) or (var.MinMax_x = 1 and (var.ir_x - var.irMin_x) >= .15)) and ((var.wm_x - var.wmMin_x) > .075) {
  162. [ var.wmMax_x, var.irMax_x ] = [ var.wm_x, var.ir_x ]
  163. var.MinMax_x = 2
  164. }
  165. }
  166. if (var.irSpeed_y < 40 and var.wmSpeed_y < 40) {
  167. if ((var.ir_y < var.irMin_y) or (var.MinMax_y = 2 and (var.irMax_y - var.ir_y) >= .15)) and ((var.wmMax_y - var.wm_y) > .075) {
  168. [ var.wmMin_y, var.irMin_y ] = [ var.wm_y, var.ir_y ]
  169. var.MinMax_y = 1
  170. }
  171. if ((var.ir_y > var.irMax_y) or (var.MinMax_y = 1 and (var.ir_y - var.irMin_y) >= .15)) and ((var.wm_y - var.wmMin_y) > .075) {
  172. [ var.wmMax_y, var.irMax_y ] = [ var.wm_y, var.ir_y ]
  173. var.MinMax_y = 2
  174. }
  175. }
  176. if var.WMIR_switch = 1 {
  177. [ var.IR_adj_x , var.IR_adj_y ] = [ var.Old_WM_x, var.Old_WM_y ] - [ var.ir_x, var.ir_y ]
  178. var.WMIR_switch = 0
  179. }
  180. if var.WMIR_switch = 0 {
  181. [ var.Rough_x , var.Rough_y ] = ([ var.ir_x, var.ir_y ] + [ var.IR_adj_x , var.IR_adj_y ] - [ .5, .5 ]) * var.NewZoom + [ .5, .5 ]
  182. [ var.WMIR_x, var.WMIR_y ] = [ var.wmNew_x , var.wmNew_y ] - [ var.ir_x , var.ir_y ]
  183. var.WMIR_xy = [ var.WMIR_x, var.WMIR_y ]
  184. var.IR_adj_c = 1 - EnsureRange(|var.WMIR_xy|, 0, .5) / 5
  185. [ var.IR_adj_x , var.IR_adj_y ] = [ var.IR_adj_x , var.IR_adj_y ] * var.IR_adj_c
  186. }
  187. [ var.WMIR_cal_x, var.WMIR_cal_y ] = [ var.wm_x, var.wm_y ] - [ var.ir_x, var.ir_y ]
  188. else // (if no IR dots visible)
  189. [ var.Rough_x , var.Rough_y ] = ([ var.wmNew_x, var.wmNew_y ] - [ var.WMIR_x, var.WMIR_y ] + [ var.IR_adj_x , var.IR_adj_y ] - [ .5, .5 ]) * var.NewZoom + [ .5, .5 ]
  190. [ var.Old_WM_x, var.Old_WM_y ] = ([ var.Rough_x , var.Rough_y ] - [ .5, .5 ]) / var.NewZoom + [ .5, .5 ]
  191. var.WMIR_switch = 1
  192. var.WMIR_xy = [ 0, 0 ]
  193. if var.started = true and var.wmCalON = false then [ var.ir_x, var.ir_y ] = ([ var.Smooth_x , var.Smooth_y ] - [ .5, .5 ]) / var.NewZoom + [ .5, .5 ]
  194. }
  195. // ### WM / IR Ratio Checking
  196. if (var.ratio = 0) or (var.ratio = 1) or IsNAN(var.ratio) then var.ratio = var.ra
  197. if var.ra != 1 and abs(delta(var.ra))>0 then var.ratio = var.ratio * var.rb + var.ra * (1-var.rb)
  198. var.ra = ((var.wmMax_x - var.wmMin_x)/(var.wmMax_y - var.wmMin_y))/((var.irMax_x - var.irMin_x)/(var.irMax_y - var.irMin_y))
  199. if abs(delta(var.ra))>0 then var.rb = .9975
  200. if abs(var.ratio - var.ra) < .05 {
  201. if ( HeldDown(delta(var.wmMin_x)=0, 2s) = false ) and ( HeldDown(delta(var.wmMax_x)=0, 2s) = false ) then [ var.wmNewMin_x, var.wmNewMax_x ] = [ var.wmMin_x, var.wmMax_x ]
  202. if ( HeldDown(delta(var.wmMin_y)=0, 2s) = false ) and ( HeldDown(delta(var.wmMax_y)=0, 2s) = false ) then [ var.wmNewMin_y, var.wmNewMax_y ] = [ var.wmMin_y, var.wmMax_y ]
  203. if ( HeldDown(delta(var.irMin_x)=0, 2s) = false ) and ( HeldDown(delta(var.irMax_x)=0, 2s) = false ) then [ var.irNewMin_x, var.irNewMax_x ] = [ var.irMin_x, var.irMax_x ]
  204. if ( HeldDown(delta(var.irMin_y)=0, 2s) = false ) and ( HeldDown(delta(var.irMax_y)=0, 2s) = false ) then [ var.irNewMin_y, var.irNewMax_y ] = [ var.irMin_y, var.irMax_y ]
  205. }
  206. // ### Map WM to IR
  207. var.wmNew_x = MapRange( var.wm_x, var.wmNewMin_x, var.wmNewMax_x, var.irNewMin_x, var.irNewMax_x )
  208. var.wmNew_y = MapRange( var.wm_y, var.wmNewMin_y, var.wmNewMax_y, var.irNewMin_y, var.irNewMax_y )
  209. // ### Mouse Movement Smoothing
  210. if IsInfinite(var.Smooth_x + var.Smooth_y) or IsNaN(var.Smooth_x + var.Smooth_y) then [ var.Smooth_x , var.Smooth_y ] = [ var.Rough_x , var.Rough_y ]
  211. var.Smooth_delta = [ delta(var.Rough_x) , delta(var.Rough_y) ]
  212. var.Smooth_c = EnsureRange(var.Smooth_c * .95 + (|var.Smooth_delta| * 100) * .05 , 1-EnsureRange(sqrt(var.MaxSmooth)/10, .00001, .99999), 1)
  213. if IsInfinite(var.Smooth_c) or IsNaN(var.Smooth_c) then var.Smooth_c = 1
  214. [ var.Smooth_x, var.Smooth_y ] = [ var.Smooth_x, var.Smooth_y ] * (1-var.Smooth_c) + [ var.Rough_x , var.Rough_y ] * var.Smooth_c
  215. // ### Zoom Button
  216. if delta(var.ZoomButton) then var.ZoomFrom = var.Roll/500
  217. if var.ZoomButton then var.ZoomShift = var.ZoomShift + delta(var.Roll)/500 //(var.Roll/500 - var.ZoomFrom)
  218. var.NewZoom = EnsureRange(var.Zoom + var.ZoomShift, .01, 100)
  219. // ### Zoom Cursors
  220. [ cursor1.Visible, cursor7.Visible ] = [ 1, 1 ] * var.ZoomButton + [ 1, 1 ] * KeepDown(delta(var.ZoomButton)<0, 1 second)
  221. [ cursor13.Visible, cursor19.Visible ] = [ 1, 1 ] * var.ZoomButton + [ 1, 1 ] * KeepDown(delta(var.ZoomButton)<0, 1 second)
  222. [ cursor1.x, cursor1.y ] = [ -.5, 0 ] * var.NewZoom + [ .5, .5 ]
  223. [ cursor7.x, cursor7.y ] = [ -.16666, 0 ] * var.NewZoom + [ .5, .5 ]
  224. [ cursor13.x, cursor13.y ] = [ .16666, 0 ] * var.NewZoom + [ .5, .5 ]
  225. [ cursor19.x, cursor19.y ] = [ .5, 0 ] * var.NewZoom + [ .5, .5 ]
  226. // ### Reset, Hold, and Mouse
  227. if var.ResetButton then [ var.Recenter_x, var.Recenter_y ] = [ var.Smooth_x, var.Smooth_y ] - [ var.Hold_x, var.Hold_y ] - [ .5, .5 ]
  228. if var.started and wiimote.Exists and not var.wmCalON {
  229. if not HeldDown(var.HoldButton, 50ms) {
  230. if var.wmSpeedYP_IN > var.wmPointerWakeup {
  231. [ mouse.x, mouse.y ] = [ var.Smooth_x, var.Smooth_y ] - [ var.Recenter_x, var.Recenter_y ] - [ var.Hold_x, var.Hold_y ]
  232. }
  233. else
  234. [ var.Hold_x, var.Hold_y ] = [ var.Smooth_x, var.Smooth_y ] - [ var.Recenter_x, var.Recenter_y ] - [ mouse.x, mouse.y ]
  235. }
  236. if var.wmSpeedYP_IN > var.wmPointerWakeup {
  237. lmb = var.LeftMouseButton
  238. rmb = var.RightMouseButton
  239. mmb = var.MiddleMouseButton
  240. if HeldDown(var.ShiftButton, 50ms) {
  241. // Use D-pad (with B trigger) as scroll wheel
  242. if wiimote.Up then
  243. mouse.WheelUp = true
  244. wait 50 ms
  245. mouse.WheelUp = false
  246. endif
  247. if wiimote.Down then
  248. mouse.WheelDown = true
  249. wait 50 ms
  250. mouse.WheelDown = false
  251. endif
  252. if wiimote.Left then
  253. mouse.WheelLeft = true
  254. wait 50 ms
  255. mouse.WheelLeft = false
  256. endif
  257. if wiimote.Right then
  258. mouse.WheelRight = true
  259. wait 50 ms
  260. mouse.WheelRight = false
  261. endif
  262. SpaceBar = wiimote.A
  263. else
  264. // Use D-pad as arrow keys
  265. up = wiimote.Up
  266. down = wiimote.Down
  267. left = wiimote.Left
  268. right = wiimote.Right
  269. }
  270. }
  271. }
  272. // ### Battery Test
  273. if var.wmCalON = false and delta(var.wmCalON) {
  274. var.Battery = EnsureRange(wiimote.Battery / 1.92, 0, 100)
  275. if var.Battery < 15 then var.BattDebug = " ### LOW BATTERY ### "+ var.Battery +"%" else var.BattDebug = " Battery: "+ var.Battery +"%"
  276. }
  277. // ### Debug
  278. if (var.wmCalON = true) or (var.BattDebug = 0) then var.BattDebug = ""
  279. if var.UseCalDebug = 0 then var.UseCalDebug = ""
  280. if (var.wmCalON = true) or (var.started = false) then var.ZoomDebug = "" else var.ZoomDebug = " Zoom: "+ var.NewZoom
  281. if (abs(var.wmCalYaw) + abs(var.wmCalPitch) + abs(var.wmDeadZone) > 0.01) and (var.started and not var.wmCalON) {
  282. var.UseCalDebug = " * Secondary Calibration * Out: "+ var.wmSpeedYP +" Cal: "+ [ var.wmCalYaw, var.wmCalPitch ] +" In: "+ var.wmSpeedYP_IN +" DeadZone: "+ var.wmDeadZone
  283. if delta(var.wmCalON)<0 then var.ErrorON = 0.54
  284. elseif (abs(var.wmCalYaw) + abs(var.wmCalPitch) + abs(var.wmDeadZone) <= 0.01) and ( var.started and not var.wmCalON)
  285. var.UseCalDebug = " Default GlovePIE Calibration"
  286. elseif var.wmCalON
  287. var.UseCalDebug = " ### CALIBRATING ### Place the Wiimote down "
  288. }
  289. debug = var.BattDebug +" "+ var.ZoomDebug +" "+ var.UseCalDebug
  290. /*
  291. // ### Debug Cursors
  292. var.debugCursors = false
  293. if var.debugCursors = true and var.started = true and var.wmCalON = false {
  294. [ cursor3.Visible, cursor9.Visible ] = [ true, true ]
  295. [ cursor15.Visible, cursor21.Visible ] = [ true, true ]
  296. [ cursor2.Visible, cursor8.Visible ] = [ true, true ]
  297. [ cursor14.Visible, cursor20.Visible ] = [ true, true ]
  298. [ cursor3.x, cursor3.y ] = [ var.wmNewMin_x, var.wmNewMin_y ] - [ var.WMIR_cal_x, var.WMIR_cal_y ]
  299. [ cursor9.x, cursor9.y ] = [ var.wmNewMax_x, var.wmNewMin_y ] - [ var.WMIR_cal_x, var.WMIR_cal_y ]
  300. [ cursor15.x, cursor15.y ] = [ var.wmNewMax_x, var.wmNewMax_y ] - [ var.WMIR_cal_x, var.WMIR_cal_y ]
  301. [ cursor21.x, cursor21.y ] = [ var.wmNewMin_x, var.wmNewMax_y ] - [ var.WMIR_cal_x, var.WMIR_cal_y ]
  302. [ cursor2.x, cursor2.y ] = [ var.irNewMin_x, var.irNewMin_y ]
  303. [ cursor8.x, cursor8.y ] = [ var.irNewMax_x, var.irNewMin_y ]
  304. [ cursor14.x, cursor14.y ] = [ var.irNewMax_x, var.irNewMax_y ]
  305. [ cursor20.x, cursor20.y ] = [ var.irNewMin_x, var.irNewMax_y ]
  306. else
  307. [ cursor3.Visible, cursor9.Visible ] = [ false, false ]
  308. [ cursor15.Visible, cursor21.Visible ] = [ false, false ]
  309. [ cursor2.Visible, cursor8.Visible ] = [ false, false ]
  310. [ cursor14.Visible, cursor20.Visible ] = [ false, false ]
  311. }
  312. */
Advertisement
Add Comment
Please, Sign In to add comment