iPhone_Sensors.mm 33 KB

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