暫無描述
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

iPhone_Sensors.mm 35KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171
  1. #define SIMULATE_ATTITUDE_FROM_GRAVITY 1
  2. #import "iPhone_Sensors.h"
  3. #if UNITY_USES_LOCATION
  4. #import <CoreLocation/CoreLocation.h>
  5. #endif
  6. #if !PLATFORM_TVOS
  7. #import <CoreMotion/CoreMotion.h>
  8. #endif
  9. #import <GameController/GameController.h>
  10. #include "OrientationSupport.h"
  11. #include "Unity/UnityInterface.h"
  12. #include "Vector3.h"
  13. #include "Quaternion4.h"
  14. typedef void (^ControllerPausedHandler)(GCController *controller);
  15. static NSArray* QueryControllerCollection();
  16. #if PLATFORM_TVOS
  17. static bool gTVRemoteTouchesEnabled = true;
  18. static bool gTVRemoteAllowRotationInitialValue = false;
  19. static bool gTVRemoteReportsAbsoluteDpadValuesInitialValue = false;
  20. static int gTVControllerUserInteractionEnabled = 0;
  21. #endif
  22. static bool gCompensateSensors = true;
  23. bool gEnableGyroscope = false;
  24. extern "C" void UnityEnableGyroscope(bool value) { gEnableGyroscope = value; }
  25. static bool gJoysticksInited = false;
  26. #define MAX_JOYSTICKS 4
  27. static bool gPausedJoysticks[MAX_JOYSTICKS] = {false, false, false, false};
  28. static id gGameControllerClass = nil;
  29. // This defines the number of maximum acceleration events Unity will queue internally for scripts to access.
  30. extern "C" int UnityMaxQueuedAccelerationEvents() { return 2 * 60; } // 120 events or 2 seconds at 60Hz reporting.
  31. static ControllerPausedHandler gControllerHandler = ^(GCController *controller)
  32. {
  33. NSArray* list = QueryControllerCollection();
  34. if (list != nil)
  35. {
  36. NSUInteger idx = [list indexOfObject: controller];
  37. if (idx < MAX_JOYSTICKS)
  38. {
  39. gPausedJoysticks[idx] = !gPausedJoysticks[idx];
  40. }
  41. }
  42. };
  43. extern "C" bool IsCompensatingSensors() { return gCompensateSensors; }
  44. extern "C" void SetCompensatingSensors(bool val) { gCompensateSensors = val; }
  45. inline float UnityReorientHeading(float heading)
  46. {
  47. if (IsCompensatingSensors())
  48. {
  49. float rotateBy = 0.f;
  50. switch (UnityCurrentOrientation())
  51. {
  52. case portraitUpsideDown:
  53. rotateBy = -180.f;
  54. break;
  55. case landscapeLeft:
  56. rotateBy = -270.f;
  57. break;
  58. case landscapeRight:
  59. rotateBy = -90.f;
  60. break;
  61. default:
  62. break;
  63. }
  64. return fmodf((360.f + heading + rotateBy), 360.f);
  65. }
  66. else
  67. {
  68. return heading;
  69. }
  70. }
  71. inline Vector3f UnityReorientVector3(float x, float y, float z)
  72. {
  73. if (IsCompensatingSensors())
  74. {
  75. Vector3f res;
  76. switch (UnityCurrentOrientation())
  77. {
  78. case portraitUpsideDown:
  79. { res = (Vector3f) {-x, -y, z}; }
  80. break;
  81. case landscapeLeft:
  82. { res = (Vector3f) {-y, x, z}; }
  83. break;
  84. case landscapeRight:
  85. { res = (Vector3f) {y, -x, z}; }
  86. break;
  87. default:
  88. { res = (Vector3f) {x, y, z}; }
  89. }
  90. return res;
  91. }
  92. else
  93. {
  94. return (Vector3f) {x, y, z};
  95. }
  96. }
  97. inline Quaternion4f UnityReorientQuaternion(float x, float y, float z, float w)
  98. {
  99. if (IsCompensatingSensors())
  100. {
  101. Quaternion4f res, inp = {x, y, z, w};
  102. switch (UnityCurrentOrientation())
  103. {
  104. case landscapeLeft:
  105. QuatMultiply(res, inp, gQuatRot[1]);
  106. break;
  107. case portraitUpsideDown:
  108. QuatMultiply(res, inp, gQuatRot[2]);
  109. break;
  110. case landscapeRight:
  111. QuatMultiply(res, inp, gQuatRot[3]);
  112. break;
  113. default:
  114. res = inp;
  115. }
  116. return res;
  117. }
  118. else
  119. {
  120. return (Quaternion4f) {x, y, z, w};
  121. }
  122. }
  123. #if PLATFORM_TVOS
  124. static bool sGCMotionForwardingEnabled = false;
  125. static bool sGCMotionForwardedForCurrentFrame = false;
  126. #else
  127. static CMMotionManager* sMotionManager = nil;
  128. static NSOperationQueue* sMotionQueue = nil;
  129. #endif
  130. // Current update interval or 0.0f if not initialized. This is returned
  131. // to the user as current update interval and this value is set to 0.0f when
  132. // gyroscope is disabled.
  133. static float sUpdateInterval = 0.0f;
  134. // Update interval set by the user. Core motion will be set-up to use
  135. // this update interval after disabling and re-enabling gyroscope
  136. // so users can set update interval, disable gyroscope, enable gyroscope and
  137. // after that gyroscope will be updated at this previously set interval.
  138. #if !PLATFORM_TVOS
  139. static float sUserUpdateInterval = 1.0f / 30.0f;
  140. #endif
  141. void SensorsCleanup()
  142. {
  143. #if !PLATFORM_TVOS
  144. if (sMotionManager != nil)
  145. {
  146. [sMotionManager stopGyroUpdates];
  147. [sMotionManager stopDeviceMotionUpdates];
  148. [sMotionManager stopAccelerometerUpdates];
  149. sMotionManager = nil;
  150. }
  151. sMotionQueue = nil;
  152. #endif
  153. }
  154. extern "C" void UnityCoreMotionStart()
  155. {
  156. #if PLATFORM_TVOS
  157. sGCMotionForwardingEnabled = true;
  158. #else
  159. if (sMotionQueue == nil)
  160. sMotionQueue = [[NSOperationQueue alloc] init];
  161. bool initMotionManager = (sMotionManager == nil);
  162. if (initMotionManager)
  163. sMotionManager = [[CMMotionManager alloc] init];
  164. // iOS might get confused if we repeatedly enable gyroscope/motions
  165. // so we take into account the current state
  166. if (gEnableGyroscope && !sMotionManager.gyroActive && sMotionManager.gyroAvailable)
  167. {
  168. [sMotionManager startGyroUpdates];
  169. [sMotionManager setGyroUpdateInterval: sUpdateInterval];
  170. }
  171. if (gEnableGyroscope && !sMotionManager.deviceMotionActive && sMotionManager.deviceMotionAvailable)
  172. {
  173. [sMotionManager startDeviceMotionUpdates];
  174. [sMotionManager setDeviceMotionUpdateInterval: sUpdateInterval];
  175. }
  176. // we (ab)use UnityCoreMotionStart to both init sensors and restart gyro
  177. // make sure we touch accelerometer only on init
  178. if (initMotionManager && sMotionManager.accelerometerAvailable)
  179. {
  180. const int frequency = UnityGetAccelerometerFrequency();
  181. if (frequency > 0)
  182. {
  183. sMotionManager.accelerometerUpdateInterval = 1.0f / frequency;
  184. [sMotionManager startAccelerometerUpdates];
  185. }
  186. }
  187. #endif
  188. }
  189. extern "C" void UnityCoreMotionStop()
  190. {
  191. #if PLATFORM_TVOS
  192. sGCMotionForwardingEnabled = false;
  193. #else
  194. if (sMotionManager != nil)
  195. {
  196. [sMotionManager stopGyroUpdates];
  197. [sMotionManager stopDeviceMotionUpdates];
  198. }
  199. #endif
  200. }
  201. extern "C" void UnityUpdateAccelerometerData()
  202. {
  203. #if !PLATFORM_TVOS
  204. if (sMotionManager)
  205. {
  206. CMAccelerometerData* data = sMotionManager.accelerometerData;
  207. if (data != nil)
  208. {
  209. Vector3f res = UnityReorientVector3(data.acceleration.x, data.acceleration.y, data.acceleration.z);
  210. UnityDidAccelerate(res.x, res.y, res.z, data.timestamp);
  211. }
  212. }
  213. #endif
  214. }
  215. extern "C" void UnitySetGyroUpdateInterval(int idx, float interval)
  216. {
  217. #if !PLATFORM_TVOS
  218. static const float _MinUpdateInterval = 1.0f / 60.0f;
  219. static const float _MaxUpdateInterval = 1.0f;
  220. if (interval < _MinUpdateInterval)
  221. interval = _MinUpdateInterval;
  222. else if (interval > _MaxUpdateInterval)
  223. interval = _MaxUpdateInterval;
  224. sUserUpdateInterval = interval;
  225. if (sMotionManager)
  226. {
  227. sUpdateInterval = interval;
  228. [sMotionManager setGyroUpdateInterval: interval];
  229. [sMotionManager setDeviceMotionUpdateInterval: interval];
  230. }
  231. #endif
  232. }
  233. extern "C" float UnityGetGyroUpdateInterval(int idx)
  234. {
  235. return sUpdateInterval;
  236. }
  237. extern "C" void UnityUpdateGyroData()
  238. {
  239. #if !PLATFORM_TVOS
  240. CMRotationRate rotationRate = { 0.0, 0.0, 0.0 };
  241. CMRotationRate rotationRateUnbiased = { 0.0, 0.0, 0.0 };
  242. CMAcceleration userAcceleration = { 0.0, 0.0, 0.0 };
  243. CMAcceleration gravity = { 0.0, 0.0, 0.0 };
  244. CMQuaternion attitude = { 0.0, 0.0, 0.0, 1.0 };
  245. if (sMotionManager != nil)
  246. {
  247. CMGyroData *gyroData = sMotionManager.gyroData;
  248. CMDeviceMotion *motionData = sMotionManager.deviceMotion;
  249. if (gyroData != nil)
  250. {
  251. rotationRate = gyroData.rotationRate;
  252. }
  253. if (motionData != nil)
  254. {
  255. CMAttitude *att = motionData.attitude;
  256. attitude = att.quaternion;
  257. rotationRateUnbiased = motionData.rotationRate;
  258. userAcceleration = motionData.userAcceleration;
  259. gravity = motionData.gravity;
  260. }
  261. }
  262. Vector3f reorientedRotRate = UnityReorientVector3(rotationRate.x, rotationRate.y, rotationRate.z);
  263. UnitySensorsSetGyroRotationRate(0, reorientedRotRate.x, reorientedRotRate.y, reorientedRotRate.z);
  264. Vector3f reorientedRotRateUnbiased = UnityReorientVector3(rotationRateUnbiased.x, rotationRateUnbiased.y, rotationRateUnbiased.z);
  265. UnitySensorsSetGyroRotationRateUnbiased(0, reorientedRotRateUnbiased.x, reorientedRotRateUnbiased.y, reorientedRotRateUnbiased.z);
  266. Vector3f reorientedUserAcc = UnityReorientVector3(userAcceleration.x, userAcceleration.y, userAcceleration.z);
  267. UnitySensorsSetUserAcceleration(0, reorientedUserAcc.x, reorientedUserAcc.y, reorientedUserAcc.z);
  268. Vector3f reorientedG = UnityReorientVector3(gravity.x, gravity.y, gravity.z);
  269. UnitySensorsSetGravity(0, reorientedG.x, reorientedG.y, reorientedG.z);
  270. Quaternion4f reorientedAtt = UnityReorientQuaternion(attitude.x, attitude.y, attitude.z, attitude.w);
  271. UnitySensorsSetAttitude(0, reorientedAtt.x, reorientedAtt.y, reorientedAtt.z, reorientedAtt.w);
  272. #endif
  273. }
  274. extern "C" int UnityIsGyroEnabled(int idx)
  275. {
  276. #if PLATFORM_TVOS
  277. return sGCMotionForwardingEnabled;
  278. #else
  279. if (sMotionManager == nil)
  280. return 0;
  281. return sMotionManager.gyroAvailable && sMotionManager.gyroActive;
  282. #endif
  283. }
  284. extern "C" int UnityIsGyroAvailable()
  285. {
  286. #if PLATFORM_TVOS
  287. return true;
  288. #else
  289. if (sMotionManager != nil)
  290. return sMotionManager.gyroAvailable;
  291. #endif
  292. return 0;
  293. }
  294. // -- Joystick stuff --
  295. #pragma clang diagnostic push
  296. #pragma clang diagnostic ignored "-Wobjc-method-access"
  297. enum JoystickButtonNumbers
  298. {
  299. BTN_PAUSE = 0,
  300. BTN_DPAD_UP = 4,
  301. BTN_DPAD_RIGHT = 5,
  302. BTN_DPAD_DOWN = 6,
  303. BTN_DPAD_LEFT = 7,
  304. BTN_Y = 12,
  305. BTN_B = 13,
  306. BTN_A = 14,
  307. BTN_X = 15,
  308. BTN_L1 = 8,
  309. BTN_L2 = 10,
  310. BTN_R1 = 9,
  311. BTN_R2 = 11,
  312. BTN_MENU = 16,
  313. BTN_L3 = 17,
  314. BTN_R3 = 18,
  315. BTN_COUNT
  316. };
  317. struct JoystickButtonState
  318. {
  319. int buttonCode;
  320. bool state;
  321. bool lastRecordedState;
  322. bool StateChanged() { return state ^ lastRecordedState; }
  323. void ClearRecordedState() { lastRecordedState = false; }
  324. };
  325. JoystickButtonState gAggregatedJoystickState[BTN_COUNT];
  326. static float GetAxisValue(GCControllerAxisInput* axis)
  327. {
  328. return axis.value;
  329. }
  330. static float GetButtonValue(GCControllerButtonInput* button)
  331. {
  332. return button.value;
  333. }
  334. static BOOL GetButtonPressed(GCControllerButtonInput* button)
  335. {
  336. return button.pressed;
  337. }
  338. extern "C" void UnityInitJoysticks()
  339. {
  340. if (!gJoysticksInited)
  341. {
  342. NSBundle* bundle = [NSBundle bundleWithPath: @"/System/Library/Frameworks/GameController.framework"];
  343. if (bundle)
  344. {
  345. [bundle load];
  346. gGameControllerClass = NSClassFromString(@"GCController");
  347. //Apply settings that could have been set by user scripts before controller initialization
  348. #if PLATFORM_TVOS
  349. UnitySetAppleTVRemoteAllowRotation(gTVRemoteAllowRotationInitialValue);
  350. UnitySetAppleTVRemoteReportAbsoluteDpadValues(gTVRemoteReportsAbsoluteDpadValuesInitialValue);
  351. #endif
  352. }
  353. for (int i = 0; i < BTN_COUNT; i++)
  354. {
  355. const int bufSize = 128;
  356. char buf[bufSize];
  357. snprintf(buf, bufSize, "joystick button %d", i);
  358. gAggregatedJoystickState[i].buttonCode = UnityStringToKey(buf);
  359. gAggregatedJoystickState[i].state = false;
  360. gAggregatedJoystickState[i].lastRecordedState = false;
  361. }
  362. gJoysticksInited = true;
  363. }
  364. }
  365. static NSArray* QueryControllerCollection()
  366. {
  367. return gGameControllerClass != nil ? (NSArray*)[gGameControllerClass performSelector: @selector(controllers)] : nil;
  368. }
  369. static void HandleAggregatedJoystickState()
  370. {
  371. for (int i = 0; i < BTN_COUNT; i++)
  372. {
  373. // Mirror button state to the aggregate controller 0.
  374. if (gAggregatedJoystickState[i].StateChanged())
  375. {
  376. UnitySetKeyState(gAggregatedJoystickState[i].buttonCode, gAggregatedJoystickState[i].lastRecordedState);
  377. gAggregatedJoystickState[i].state = gAggregatedJoystickState[i].lastRecordedState;
  378. }
  379. gAggregatedJoystickState[i].ClearRecordedState();
  380. }
  381. }
  382. static void SetJoystickButtonState(int joyNum, int buttonNum, int state)
  383. {
  384. const int bufSize = 128;
  385. char buf[bufSize];
  386. snprintf(buf, bufSize, "joystick %d button %d", joyNum, buttonNum);
  387. UnitySetKeyState(UnityStringToKey(buf), state);
  388. if (state && buttonNum < BTN_COUNT)
  389. {
  390. gAggregatedJoystickState[buttonNum].lastRecordedState = true;
  391. }
  392. }
  393. static void ReportJoystickButton(int idx, JoystickButtonNumbers num, GCControllerButtonInput* button)
  394. {
  395. SetJoystickButtonState(idx + 1, num, GetButtonPressed(button));
  396. UnitySetJoystickPosition(idx + 1, num, GetButtonValue(button));
  397. }
  398. template<class ClassXYZ>
  399. static void ReportJoystickXYZAxes(int idx, int xaxis, int yaxis, int zaxis, const ClassXYZ& xyz)
  400. {
  401. UnitySetJoystickPosition(idx + 1, xaxis, xyz.x);
  402. UnitySetJoystickPosition(idx + 1, yaxis, xyz.y);
  403. UnitySetJoystickPosition(idx + 1, zaxis, xyz.z);
  404. }
  405. template<class ClassXYZW>
  406. static void ReportJoystickXYZWAxes(int idx, int xaxis, int yaxis, int zaxis, int waxis,
  407. const ClassXYZW& xyzw)
  408. {
  409. UnitySetJoystickPosition(idx + 1, xaxis, xyzw.x);
  410. UnitySetJoystickPosition(idx + 1, yaxis, xyzw.y);
  411. UnitySetJoystickPosition(idx + 1, zaxis, xyzw.z);
  412. UnitySetJoystickPosition(idx + 1, waxis, xyzw.w);
  413. }
  414. static GCControllerDirectionPad* GetCardinalDPad(GCMicroGamepad* gamepad)
  415. {
  416. if (![gamepad respondsToSelector: @selector(dpadsbling)])
  417. return nil;
  418. NSDictionary<NSString *, GCDeviceDirectionPad *> *dpads = [gamepad performSelector: @selector(dpadsbling)];
  419. return [dpads valueForKey: @"Cardinal Direction Pad"];
  420. }
  421. static GCControllerButtonInput* SelectPreferedButton(GCControllerButtonInput* prefered, GCControllerButtonInput* alternative)
  422. {
  423. if (prefered.isPressed)
  424. return prefered;
  425. return alternative;
  426. }
  427. static void ReportJoystickMicro(int idx, GCMicroGamepad* gamepad)
  428. {
  429. GCControllerDirectionPad* dpad = [gamepad dpad];
  430. GCControllerDirectionPad* cardinalDpad;
  431. #if PLATFORM_TVOS
  432. if (@available(tvOS 14.5, *))
  433. cardinalDpad = [[gamepad dpads] valueForKey: GCInputDirectionalCardinalDpad];
  434. #endif
  435. UnitySetJoystickPosition(idx + 1, 0, GetAxisValue([dpad xAxis]));
  436. UnitySetJoystickPosition(idx + 1, 1, -GetAxisValue([dpad yAxis]));
  437. ReportJoystickButton(idx, BTN_DPAD_UP, SelectPreferedButton([dpad up], [cardinalDpad up]));
  438. ReportJoystickButton(idx, BTN_DPAD_RIGHT, SelectPreferedButton([dpad right], [cardinalDpad right]));
  439. ReportJoystickButton(idx, BTN_DPAD_DOWN, SelectPreferedButton([dpad down], [cardinalDpad down]));
  440. ReportJoystickButton(idx, BTN_DPAD_LEFT, SelectPreferedButton([dpad left], [cardinalDpad left]));
  441. bool isDirectionalButtonPressed = false;
  442. #if PLATFORM_TVOS
  443. if (cardinalDpad)
  444. {
  445. if (@available(tvOS 15, *))
  446. {
  447. ReportJoystickButton(idx, BTN_A, [[gamepad buttons] valueForKey: GCInputDirectionalCenterButton]);
  448. isDirectionalButtonPressed = true;
  449. }
  450. else if (@available(tvOS 14.5, *))
  451. {
  452. isDirectionalButtonPressed =
  453. cardinalDpad.up.pressed || cardinalDpad.right.pressed || cardinalDpad.down.pressed || cardinalDpad.left.pressed;
  454. }
  455. }
  456. #endif
  457. if (!isDirectionalButtonPressed)
  458. ReportJoystickButton(idx, BTN_A, [gamepad buttonA]);
  459. ReportJoystickButton(idx, BTN_X, [gamepad buttonX]);
  460. }
  461. static void ReportJoystickExtended(int idx, GCExtendedGamepad* gamepad)
  462. {
  463. GCControllerDirectionPad* dpad = [gamepad dpad];
  464. ReportJoystickButton(idx, BTN_DPAD_UP, [dpad up]);
  465. ReportJoystickButton(idx, BTN_DPAD_RIGHT, [dpad right]);
  466. ReportJoystickButton(idx, BTN_DPAD_DOWN, [dpad down]);
  467. ReportJoystickButton(idx, BTN_DPAD_LEFT, [dpad left]);
  468. ReportJoystickButton(idx, BTN_A, [gamepad buttonA]);
  469. ReportJoystickButton(idx, BTN_B, [gamepad buttonB]);
  470. ReportJoystickButton(idx, BTN_Y, [gamepad buttonY]);
  471. ReportJoystickButton(idx, BTN_X, [gamepad buttonX]);
  472. ReportJoystickButton(idx, BTN_L1, [gamepad leftShoulder]);
  473. ReportJoystickButton(idx, BTN_R1, [gamepad rightShoulder]);
  474. ReportJoystickButton(idx, BTN_L2, [gamepad leftTrigger]);
  475. ReportJoystickButton(idx, BTN_R2, [gamepad rightTrigger]);
  476. ReportJoystickButton(idx, BTN_L3, [gamepad valueForKey: @"leftThumbstickButton"]);
  477. ReportJoystickButton(idx, BTN_R3, [gamepad valueForKey: @"rightThumbstickButton"]);
  478. ReportJoystickButton(idx, BTN_MENU, [gamepad valueForKey: @"buttonMenu"]);
  479. ReportJoystickButton(idx, BTN_PAUSE, [gamepad valueForKey: @"buttonOptions"]);
  480. // To avoid overwriting axis input with button input when axis index
  481. // overlaps with button enum value, handle directional input after buttons.
  482. GCControllerDirectionPad* leftStick = [gamepad leftThumbstick];
  483. GCControllerDirectionPad* rightStick = [gamepad rightThumbstick];
  484. UnitySetJoystickPosition(idx + 1, 0, GetAxisValue([leftStick xAxis]));
  485. UnitySetJoystickPosition(idx + 1, 1, -GetAxisValue([leftStick yAxis]));
  486. UnitySetJoystickPosition(idx + 1, 2, GetAxisValue([rightStick xAxis]));
  487. UnitySetJoystickPosition(idx + 1, 3, -GetAxisValue([rightStick yAxis]));
  488. }
  489. static void SimulateAttitudeViaGravityVector(const Vector3f& gravity, Quaternion4f& currentAttitude, Vector3f& rotationRate)
  490. {
  491. static Quaternion4f lastAttitude = QuatIdentity();
  492. static double lastTime = 0.0;
  493. double currentTime = [NSDate timeIntervalSinceReferenceDate];
  494. double deltaTime = lastTime - currentTime;
  495. currentAttitude = QuatRotationFromTo(gravity, VecMake(0.0f, 0.0f, -1.0f));
  496. rotationRate = VecScale(1.0f / deltaTime, QuatToEuler(QuatDifference(currentAttitude, lastAttitude)));
  497. lastAttitude = currentAttitude;
  498. lastTime = currentTime;
  499. }
  500. // Note that joystick axis numbers in documentation are shifted
  501. // by one. 1st axis is referred to by index 0, 16th by 15, etc.
  502. static void ReportJoystickMotion(int idx, GCMotion* motion)
  503. {
  504. Vector3f rotationRate = VecMake(0.0f, 0.0f, 0.0f);
  505. Quaternion4f attitude = QuatMake(0.0f, 0.0f, 0.0f, 1.0f);
  506. bool gotRotationData = false;
  507. if (motion.hasAttitudeAndRotationRate)
  508. {
  509. rotationRate = {(float)motion.rotationRate.x, (float)motion.rotationRate.y, (float)motion.rotationRate.z};
  510. attitude = {(float)motion.attitude.x, (float)motion.attitude.y, (float)motion.attitude.z, (float)motion.attitude.w};
  511. gotRotationData = true;
  512. }
  513. #if SIMULATE_ATTITUDE_FROM_GRAVITY
  514. if (!gotRotationData)
  515. SimulateAttitudeViaGravityVector(VecMake((float)motion.gravity.x, (float)motion.gravity.y, (float)motion.gravity.z), attitude, rotationRate);
  516. #endif
  517. // From docs:
  518. // gravity (x,y,z) : 16, 17, 18
  519. // user acceleration: 19, 20, 21
  520. // rotation rate: 22, 23, 24
  521. // attitude quaternion (x,y,z,w): 25, 26, 27, 28
  522. ReportJoystickXYZAxes(idx, 15, 16, 17, motion.gravity);
  523. ReportJoystickXYZAxes(idx, 18, 19, 20, motion.userAcceleration);
  524. ReportJoystickXYZAxes(idx, 21, 22, 23, rotationRate);
  525. ReportJoystickXYZWAxes(idx, 24, 25, 26, 27, attitude);
  526. #if PLATFORM_TVOS
  527. if (sGCMotionForwardingEnabled && !sGCMotionForwardedForCurrentFrame)
  528. {
  529. UnitySensorsSetGravity(0, motion.gravity.x, motion.gravity.y, motion.gravity.z);
  530. UnitySensorsSetUserAcceleration(0, motion.userAcceleration.x, motion.userAcceleration.y, motion.userAcceleration.z);
  531. UnitySensorsSetGyroRotationRate(0, rotationRate.y, rotationRate.x, rotationRate.z);
  532. UnitySensorsSetAttitude(0, attitude.x, attitude.y, attitude.z, attitude.w);
  533. UnityDidAccelerate(motion.userAcceleration.x + motion.gravity.x, motion.userAcceleration.y + motion.gravity.y, motion.userAcceleration.z + motion.gravity.z, [[NSDate date] timeIntervalSince1970]);
  534. sGCMotionForwardedForCurrentFrame = true;
  535. }
  536. #endif
  537. }
  538. static void ReportJoystick(GCController* controller, int idx)
  539. {
  540. if (controller.controllerPausedHandler == nil)
  541. controller.controllerPausedHandler = gControllerHandler;
  542. if ([controller extendedGamepad] != nil)
  543. ReportJoystickExtended(idx, [controller extendedGamepad]);
  544. else if ([controller microGamepad] != nil)
  545. ReportJoystickMicro(idx, [controller microGamepad]);
  546. else
  547. {
  548. // TODO: do something with not supported gamepad profiles
  549. }
  550. if (controller.motion != nil)
  551. ReportJoystickMotion(idx, controller.motion);
  552. // Map pause button
  553. SetJoystickButtonState(idx + 1, BTN_PAUSE, gPausedJoysticks[idx]);
  554. // Reset pause button
  555. gPausedJoysticks[idx] = false;
  556. }
  557. // On tvOS simulator we implement a fake remote as tvOS simulator
  558. // does not support controllers (yet)
  559. #if UNITY_TVOS_SIMULATOR_FAKE_REMOTE
  560. struct FakeRemoteState
  561. {
  562. bool pressedX, pressedA;
  563. bool pressedUp, pressedDown, pressedLeft, pressedRight;
  564. float xAxis, yAxis;
  565. FakeRemoteState() :
  566. pressedX(false),
  567. pressedA(false),
  568. pressedUp(false),
  569. pressedDown(false),
  570. pressedLeft(false),
  571. pressedRight(false),
  572. xAxis(0),
  573. yAxis(0)
  574. {}
  575. };
  576. static FakeRemoteState gFakeRemoteState;
  577. static void ReportFakeRemoteButton(int idx, JoystickButtonNumbers num, bool pressed)
  578. {
  579. SetJoystickButtonState(idx + 1, num, pressed);
  580. UnitySetJoystickPosition(idx + 1, num, pressed);
  581. }
  582. void ReportFakeRemote(int idx)
  583. {
  584. UnitySetJoystickPosition(idx + 1, 0, gFakeRemoteState.xAxis);
  585. UnitySetJoystickPosition(idx + 1, 1, -gFakeRemoteState.yAxis);
  586. ReportFakeRemoteButton(idx, BTN_DPAD_UP, gFakeRemoteState.pressedUp);
  587. ReportFakeRemoteButton(idx, BTN_DPAD_RIGHT, gFakeRemoteState.pressedRight);
  588. ReportFakeRemoteButton(idx, BTN_DPAD_DOWN, gFakeRemoteState.pressedDown);
  589. ReportFakeRemoteButton(idx, BTN_DPAD_LEFT, gFakeRemoteState.pressedLeft);
  590. ReportFakeRemoteButton(idx, BTN_A, gFakeRemoteState.pressedA);
  591. ReportFakeRemoteButton(idx, BTN_X, gFakeRemoteState.pressedX);
  592. }
  593. #endif
  594. extern "C" void UnityUpdateJoystickData()
  595. {
  596. UnityInitJoysticks();
  597. NSArray* list = QueryControllerCollection();
  598. #if PLATFORM_TVOS
  599. sGCMotionForwardedForCurrentFrame = false;
  600. #endif
  601. if (list != nil)
  602. {
  603. for (int i = 0; i < [list count]; i++)
  604. {
  605. id controller = [list objectAtIndex: i];
  606. ReportJoystick(controller, i);
  607. }
  608. }
  609. #if UNITY_TVOS_SIMULATOR_FAKE_REMOTE
  610. int remoteIndex = list != nil ? (int)[list count] : 0;
  611. ReportFakeRemote(remoteIndex);
  612. #endif
  613. // Report all aggregated joystick buttons in bulk
  614. HandleAggregatedJoystickState();
  615. }
  616. static NSString* FormatJoystickIdentifier(int idx, const char* typeString, const char* attachment, const char* vendorName)
  617. {
  618. return [NSString stringWithFormat: @"[%s,%s] joystick %d by %s", typeString, attachment, idx + 1, vendorName];
  619. }
  620. NSString* GetJoystickName(GCController* controller, int idx)
  621. {
  622. if (controller != nil)
  623. {
  624. // iOS 8 has bug, which is encountered when controller is being attached
  625. // while app is still running. It creates two instances of controller object:
  626. // one original and one "Forwarded", accesing later properties are causing crashes
  627. const char* attached = "unknown";
  628. // Controller is good one
  629. if ([[controller vendorName] rangeOfString: @"Forwarded"].location == NSNotFound)
  630. attached = (controller.attachedToDevice ? "wired" : "wireless");
  631. const char* typeString = [controller extendedGamepad] != nil ? "extended" : "basic";
  632. return FormatJoystickIdentifier(idx, typeString, attached, [[controller vendorName] UTF8String]);
  633. }
  634. return @"unknown";
  635. }
  636. extern "C" NSArray* UnityGetJoystickNames()
  637. {
  638. NSArray* joysticks = QueryControllerCollection();
  639. int count = joysticks != nil ? (int)[joysticks count] : 0;
  640. NSMutableArray * joystickNames = [NSMutableArray arrayWithCapacity: count];
  641. for (int i = 0; i < count; i++)
  642. {
  643. [joystickNames addObject: GetJoystickName(joysticks[i], i)];
  644. }
  645. #if UNITY_TVOS_SIMULATOR_FAKE_REMOTE
  646. [joystickNames addObject: FormatJoystickIdentifier(count, "basic", "wireless", "Unity")];
  647. #endif
  648. return joystickNames;
  649. }
  650. extern "C" void UnityGetJoystickAxisName(int idx, int axis, char* buffer, int maxLen)
  651. {
  652. }
  653. extern "C" void UnityGetNiceKeyname(int key, char* buffer, int maxLen)
  654. {
  655. }
  656. #pragma clang diagnostic pop
  657. #if UNITY_USES_LOCATION
  658. @interface LocationServiceDelegate : NSObject<CLLocationManagerDelegate>
  659. @end
  660. #endif
  661. extern "C" void
  662. UnitySetLastLocation(double timestamp,
  663. float latitude,
  664. float longitude,
  665. float altitude,
  666. float horizontalAccuracy,
  667. float verticalAccuracy);
  668. extern "C" void
  669. UnitySetLastHeading(float magneticHeading, float trueHeading, float headingAccuracy,
  670. float rawX, float rawY, float rawZ, double timestamp);
  671. #if UNITY_USES_LOCATION
  672. struct LocationServiceInfo
  673. {
  674. private:
  675. LocationServiceDelegate* delegate;
  676. CLLocationManager* locationManager;
  677. public:
  678. LocationServiceStatus locationStatus;
  679. LocationServiceStatus headingStatus;
  680. float desiredAccuracy;
  681. float distanceFilter;
  682. LocationServiceInfo();
  683. CLLocationManager* GetLocationManager();
  684. };
  685. LocationServiceInfo::LocationServiceInfo()
  686. {
  687. locationStatus = kLocationServiceStopped;
  688. desiredAccuracy = kCLLocationAccuracyKilometer;
  689. distanceFilter = 500;
  690. headingStatus = kLocationServiceStopped;
  691. }
  692. static LocationServiceInfo gLocationServiceStatus;
  693. CLLocationManager* LocationServiceInfo::GetLocationManager()
  694. {
  695. if (locationManager == nil)
  696. {
  697. locationManager = [[CLLocationManager alloc] init];
  698. delegate = [LocationServiceDelegate alloc];
  699. locationManager.delegate = delegate;
  700. }
  701. return locationManager;
  702. }
  703. #endif
  704. bool LocationService::IsServiceEnabledByUser()
  705. {
  706. #if UNITY_USES_LOCATION
  707. return [CLLocationManager locationServicesEnabled];
  708. #else
  709. return false;
  710. #endif
  711. }
  712. void LocationService::SetDesiredAccuracy(float val)
  713. {
  714. #if UNITY_USES_LOCATION
  715. gLocationServiceStatus.desiredAccuracy = val;
  716. #endif
  717. }
  718. float LocationService::GetDesiredAccuracy()
  719. {
  720. #if UNITY_USES_LOCATION
  721. return gLocationServiceStatus.desiredAccuracy;
  722. #else
  723. return NAN;
  724. #endif
  725. }
  726. void LocationService::SetDistanceFilter(float val)
  727. {
  728. #if UNITY_USES_LOCATION
  729. gLocationServiceStatus.distanceFilter = val;
  730. #endif
  731. }
  732. float LocationService::GetDistanceFilter()
  733. {
  734. #if UNITY_USES_LOCATION
  735. return gLocationServiceStatus.distanceFilter;
  736. #else
  737. return NAN;
  738. #endif
  739. }
  740. void LocationService::StartUpdatingLocation()
  741. {
  742. #if UNITY_USES_LOCATION
  743. if (gLocationServiceStatus.locationStatus != kLocationServiceRunning)
  744. {
  745. CLLocationManager* locationManager = gLocationServiceStatus.GetLocationManager();
  746. [locationManager requestWhenInUseAuthorization];
  747. locationManager.desiredAccuracy = gLocationServiceStatus.desiredAccuracy;
  748. // Set a movement threshold for new events
  749. locationManager.distanceFilter = gLocationServiceStatus.distanceFilter;
  750. #if PLATFORM_IOS
  751. [locationManager startUpdatingLocation];
  752. #else
  753. [locationManager requestLocation];
  754. #endif
  755. gLocationServiceStatus.locationStatus = kLocationServiceInitializing;
  756. }
  757. #endif
  758. }
  759. void LocationService::StopUpdatingLocation()
  760. {
  761. #if UNITY_USES_LOCATION
  762. if (gLocationServiceStatus.locationStatus != kLocationServiceStopped)
  763. {
  764. [gLocationServiceStatus.GetLocationManager() stopUpdatingLocation];
  765. gLocationServiceStatus.locationStatus = kLocationServiceStopped;
  766. }
  767. #endif
  768. }
  769. void LocationService::SetHeadingUpdatesEnabled(bool enabled)
  770. {
  771. #if PLATFORM_IOS && UNITY_USES_LOCATION
  772. if (enabled)
  773. {
  774. if (gLocationServiceStatus.headingStatus != kLocationServiceRunning &&
  775. IsHeadingAvailable())
  776. {
  777. CLLocationManager* locationManager = gLocationServiceStatus.GetLocationManager();
  778. [locationManager startUpdatingHeading];
  779. gLocationServiceStatus.headingStatus = kLocationServiceInitializing;
  780. }
  781. }
  782. else
  783. {
  784. if (gLocationServiceStatus.headingStatus != kLocationServiceStopped)
  785. {
  786. [gLocationServiceStatus.GetLocationManager() stopUpdatingHeading];
  787. gLocationServiceStatus.headingStatus = kLocationServiceStopped;
  788. }
  789. }
  790. #endif
  791. }
  792. bool LocationService::IsHeadingUpdatesEnabled()
  793. {
  794. #if UNITY_USES_LOCATION
  795. return (gLocationServiceStatus.headingStatus == kLocationServiceRunning);
  796. #else
  797. return false;
  798. #endif
  799. }
  800. LocationServiceStatus LocationService::GetLocationStatus()
  801. {
  802. #if UNITY_USES_LOCATION
  803. return (LocationServiceStatus)gLocationServiceStatus.locationStatus;
  804. #else
  805. return kLocationServiceFailed;
  806. #endif
  807. }
  808. LocationServiceStatus LocationService::GetHeadingStatus()
  809. {
  810. #if UNITY_USES_LOCATION
  811. return (LocationServiceStatus)gLocationServiceStatus.headingStatus;
  812. #else
  813. return kLocationServiceFailed;
  814. #endif
  815. }
  816. bool LocationService::IsHeadingAvailable()
  817. {
  818. #if PLATFORM_IOS && UNITY_USES_LOCATION
  819. return [CLLocationManager headingAvailable];
  820. #else
  821. return false;
  822. #endif
  823. }
  824. #if UNITY_USES_LOCATION
  825. @implementation LocationServiceDelegate
  826. - (void)locationManager:(CLLocationManager*)manager didUpdateLocations:(NSArray*)locations
  827. {
  828. CLLocation* lastLocation = locations.lastObject;
  829. gLocationServiceStatus.locationStatus = kLocationServiceRunning;
  830. UnitySetLastLocation([lastLocation.timestamp timeIntervalSince1970],
  831. lastLocation.coordinate.latitude, lastLocation.coordinate.longitude, lastLocation.altitude,
  832. lastLocation.horizontalAccuracy, lastLocation.verticalAccuracy
  833. );
  834. }
  835. #if PLATFORM_IOS
  836. - (void)locationManager:(CLLocationManager*)manager didUpdateHeading:(CLHeading*)newHeading
  837. {
  838. gLocationServiceStatus.headingStatus = kLocationServiceRunning;
  839. Vector3f reorientedRawHeading = UnityReorientVector3(newHeading.x, newHeading.y, newHeading.z);
  840. UnitySetLastHeading(UnityReorientHeading(newHeading.magneticHeading),
  841. UnityReorientHeading(newHeading.trueHeading),
  842. newHeading.headingAccuracy,
  843. reorientedRawHeading.x, reorientedRawHeading.y, reorientedRawHeading.z,
  844. [newHeading.timestamp timeIntervalSince1970]);
  845. }
  846. #endif
  847. - (BOOL)locationManagerShouldDisplayHeadingCalibration:(CLLocationManager*)manager
  848. {
  849. return NO;
  850. }
  851. - (void)locationManager:(CLLocationManager*)manager didFailWithError:(NSError*)error;
  852. {
  853. gLocationServiceStatus.locationStatus = kLocationServiceFailed;
  854. gLocationServiceStatus.headingStatus = kLocationServiceFailed;
  855. }
  856. @end
  857. #endif
  858. #if PLATFORM_TVOS
  859. GCMicroGamepad* QueryMicroController()
  860. {
  861. NSArray* list = QueryControllerCollection();
  862. for (GCController* controller in list)
  863. {
  864. if (controller.microGamepad != nil)
  865. return controller.microGamepad;
  866. }
  867. return nil;
  868. }
  869. extern "C" int UnityGetAppleTVRemoteTouchesEnabled()
  870. {
  871. return gTVRemoteTouchesEnabled;
  872. }
  873. extern "C" void UnitySetAppleTVRemoteTouchesEnabled(int val)
  874. {
  875. gTVRemoteTouchesEnabled = val;
  876. }
  877. /*
  878. TVRemoteAllowExitToMenu.
  879. Lowest bit caches the value of .controllerUserInteractionEnabled.
  880. Second lowest bit is set if .controllerUserInteractionEnabled is temporarily changed for internal purposes.
  881. */
  882. extern "C" int UnityGetAppleTVRemoteAllowExitToMenu()
  883. {
  884. if (gTVControllerUserInteractionEnabled & 2)
  885. return gTVControllerUserInteractionEnabled & 1;
  886. return ((GCEventViewController*)UnityGetGLViewController()).controllerUserInteractionEnabled;
  887. }
  888. /*
  889. Same as getter above, except that second lowest bit here indicates fake setting,
  890. meaning we set the value on controller, but cache the true value so getter report no changes.
  891. */
  892. extern "C" void UnitySetAppleTVRemoteAllowExitToMenu(int val)
  893. {
  894. bool newVal = val & 1;
  895. if (val & 2)
  896. {
  897. if (gTVControllerUserInteractionEnabled == val)
  898. return;
  899. if (0 == (gTVControllerUserInteractionEnabled & 2))
  900. {
  901. int cacheVal = ((GCEventViewController*)UnityGetGLViewController()).controllerUserInteractionEnabled;
  902. gTVControllerUserInteractionEnabled = 2 | cacheVal;
  903. }
  904. }
  905. ((GCEventViewController*)UnityGetGLViewController()).controllerUserInteractionEnabled = newVal;
  906. }
  907. extern "C" int UnityGetAppleTVRemoteAllowRotation()
  908. {
  909. GCMicroGamepad* controller = QueryMicroController();
  910. if (controller != nil)
  911. return controller.allowsRotation;
  912. else
  913. return false;
  914. }
  915. extern "C" void UnitySetAppleTVRemoteAllowRotation(int val)
  916. {
  917. GCMicroGamepad* controller = QueryMicroController();
  918. if (controller != nil)
  919. controller.allowsRotation = val;
  920. else
  921. gTVRemoteAllowRotationInitialValue = val;
  922. }
  923. extern "C" int UnityGetAppleTVRemoteReportAbsoluteDpadValues()
  924. {
  925. GCMicroGamepad* controller = QueryMicroController();
  926. if (controller != nil)
  927. return controller.reportsAbsoluteDpadValues;
  928. else
  929. return false;
  930. }
  931. extern "C" void UnitySetAppleTVRemoteReportAbsoluteDpadValues(int val)
  932. {
  933. NSArray* list = QueryControllerCollection();
  934. for (GCController* controller in list)
  935. {
  936. if (controller.microGamepad != nil)
  937. controller.microGamepad.reportsAbsoluteDpadValues = val;
  938. else
  939. gTVRemoteReportsAbsoluteDpadValuesInitialValue = val;
  940. }
  941. }
  942. #endif
  943. #if UNITY_TVOS_SIMULATOR_FAKE_REMOTE
  944. static void FakeRemoteStateSetButton(UIPressType type, bool state)
  945. {
  946. switch (type)
  947. {
  948. case UIPressTypeUpArrow: gFakeRemoteState.pressedUp = state; return;
  949. case UIPressTypeDownArrow: gFakeRemoteState.pressedDown = state; return;
  950. case UIPressTypeLeftArrow: gFakeRemoteState.pressedLeft = state; return;
  951. case UIPressTypeRightArrow: gFakeRemoteState.pressedRight = state; return;
  952. case UIPressTypeSelect: gFakeRemoteState.pressedA = state; return;
  953. case UIPressTypePlayPause: gFakeRemoteState.pressedX = state; return;
  954. }
  955. }
  956. void ReportSimulatedRemoteButtonPress(UIPressType type)
  957. {
  958. FakeRemoteStateSetButton(type, true);
  959. }
  960. void ReportSimulatedRemoteButtonRelease(UIPressType type)
  961. {
  962. FakeRemoteStateSetButton(type, false);
  963. }
  964. static float FakeRemoteMapTouchToAxis(float pos, float bounds)
  965. {
  966. float halfRange = bounds / 2;
  967. return (pos - halfRange) / halfRange;
  968. }
  969. void ReportSimulatedRemoteTouchesBegan(UIView* view, NSSet* touches)
  970. {
  971. ReportSimulatedRemoteTouchesMoved(view, touches);
  972. }
  973. void ReportSimulatedRemoteTouchesMoved(UIView* view, NSSet* touches)
  974. {
  975. for (UITouch* touch in touches)
  976. {
  977. gFakeRemoteState.xAxis = FakeRemoteMapTouchToAxis([touch locationInView: view].x, view.bounds.size.width);
  978. gFakeRemoteState.yAxis = FakeRemoteMapTouchToAxis([touch locationInView: view].y, view.bounds.size.height);
  979. // We assume that at most single touch is received.
  980. break;
  981. }
  982. }
  983. void ReportSimulatedRemoteTouchesEnded(UIView* view, NSSet* touches)
  984. {
  985. gFakeRemoteState.xAxis = 0;
  986. gFakeRemoteState.yAxis = 0;
  987. }
  988. #endif