iPhone_Sensors.mm 33 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122
  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. char buf[128];
  355. sprintf(buf, "joystick button %d", i);
  356. gAggregatedJoystickState[i].buttonCode = UnityStringToKey(buf);
  357. gAggregatedJoystickState[i].state = false;
  358. gAggregatedJoystickState[i].lastRecordedState = false;
  359. }
  360. gJoysticksInited = true;
  361. }
  362. }
  363. static NSArray* QueryControllerCollection()
  364. {
  365. return gGameControllerClass != nil ? (NSArray*)[gGameControllerClass performSelector: @selector(controllers)] : nil;
  366. }
  367. static void HandleAggregatedJoystickState()
  368. {
  369. for (int i = 0; i < BTN_COUNT; i++)
  370. {
  371. // Mirror button state to the aggregate controller 0.
  372. if (gAggregatedJoystickState[i].StateChanged())
  373. {
  374. UnitySetKeyState(gAggregatedJoystickState[i].buttonCode, gAggregatedJoystickState[i].lastRecordedState);
  375. gAggregatedJoystickState[i].state = gAggregatedJoystickState[i].lastRecordedState;
  376. }
  377. gAggregatedJoystickState[i].ClearRecordedState();
  378. }
  379. }
  380. static void SetJoystickButtonState(int joyNum, int buttonNum, int state)
  381. {
  382. char buf[128];
  383. sprintf(buf, "joystick %d button %d", joyNum, buttonNum);
  384. UnitySetKeyState(UnityStringToKey(buf), state);
  385. if (state && buttonNum < BTN_COUNT)
  386. {
  387. gAggregatedJoystickState[buttonNum].lastRecordedState = true;
  388. }
  389. }
  390. static void ReportJoystickButton(int idx, JoystickButtonNumbers num, GCControllerButtonInput* button)
  391. {
  392. SetJoystickButtonState(idx + 1, num, GetButtonPressed(button));
  393. UnitySetJoystickPosition(idx + 1, num, GetButtonValue(button));
  394. }
  395. template<class ClassXYZ>
  396. static void ReportJoystickXYZAxes(int idx, int xaxis, int yaxis, int zaxis, const ClassXYZ& xyz)
  397. {
  398. UnitySetJoystickPosition(idx + 1, xaxis, xyz.x);
  399. UnitySetJoystickPosition(idx + 1, yaxis, xyz.y);
  400. UnitySetJoystickPosition(idx + 1, zaxis, xyz.z);
  401. }
  402. template<class ClassXYZW>
  403. static void ReportJoystickXYZWAxes(int idx, int xaxis, int yaxis, int zaxis, int waxis,
  404. const ClassXYZW& xyzw)
  405. {
  406. UnitySetJoystickPosition(idx + 1, xaxis, xyzw.x);
  407. UnitySetJoystickPosition(idx + 1, yaxis, xyzw.y);
  408. UnitySetJoystickPosition(idx + 1, zaxis, xyzw.z);
  409. UnitySetJoystickPosition(idx + 1, waxis, xyzw.w);
  410. }
  411. static void ReportJoystickMicro(int idx, GCMicroGamepad* gamepad)
  412. {
  413. GCControllerDirectionPad* dpad = [gamepad dpad];
  414. UnitySetJoystickPosition(idx + 1, 0, GetAxisValue([dpad xAxis]));
  415. UnitySetJoystickPosition(idx + 1, 1, -GetAxisValue([dpad yAxis]));
  416. ReportJoystickButton(idx, BTN_DPAD_UP, [dpad up]);
  417. ReportJoystickButton(idx, BTN_DPAD_RIGHT, [dpad right]);
  418. ReportJoystickButton(idx, BTN_DPAD_DOWN, [dpad down]);
  419. ReportJoystickButton(idx, BTN_DPAD_LEFT, [dpad left]);
  420. ReportJoystickButton(idx, BTN_A, [gamepad buttonA]);
  421. ReportJoystickButton(idx, BTN_X, [gamepad buttonX]);
  422. }
  423. static void ReportJoystickExtended(int idx, GCExtendedGamepad* gamepad)
  424. {
  425. GCControllerDirectionPad* dpad = [gamepad dpad];
  426. ReportJoystickButton(idx, BTN_DPAD_UP, [dpad up]);
  427. ReportJoystickButton(idx, BTN_DPAD_RIGHT, [dpad right]);
  428. ReportJoystickButton(idx, BTN_DPAD_DOWN, [dpad down]);
  429. ReportJoystickButton(idx, BTN_DPAD_LEFT, [dpad left]);
  430. ReportJoystickButton(idx, BTN_A, [gamepad buttonA]);
  431. ReportJoystickButton(idx, BTN_B, [gamepad buttonB]);
  432. ReportJoystickButton(idx, BTN_Y, [gamepad buttonY]);
  433. ReportJoystickButton(idx, BTN_X, [gamepad buttonX]);
  434. ReportJoystickButton(idx, BTN_L1, [gamepad leftShoulder]);
  435. ReportJoystickButton(idx, BTN_R1, [gamepad rightShoulder]);
  436. ReportJoystickButton(idx, BTN_L2, [gamepad leftTrigger]);
  437. ReportJoystickButton(idx, BTN_R2, [gamepad rightTrigger]);
  438. if (@available(iOS 12.1, *))
  439. {
  440. ReportJoystickButton(idx, BTN_L3, [gamepad valueForKey: @"leftThumbstickButton"]);
  441. ReportJoystickButton(idx, BTN_R3, [gamepad valueForKey: @"rightThumbstickButton"]);
  442. }
  443. if (@available(iOS 13.0, *))
  444. {
  445. ReportJoystickButton(idx, BTN_MENU, [gamepad valueForKey: @"buttonMenu"]);
  446. ReportJoystickButton(idx, BTN_PAUSE, [gamepad valueForKey: @"buttonOptions"]);
  447. }
  448. // To avoid overwriting axis input with button input when axis index
  449. // overlaps with button enum value, handle directional input after buttons.
  450. GCControllerDirectionPad* leftStick = [gamepad leftThumbstick];
  451. GCControllerDirectionPad* rightStick = [gamepad rightThumbstick];
  452. UnitySetJoystickPosition(idx + 1, 0, GetAxisValue([leftStick xAxis]));
  453. UnitySetJoystickPosition(idx + 1, 1, -GetAxisValue([leftStick yAxis]));
  454. UnitySetJoystickPosition(idx + 1, 2, GetAxisValue([rightStick xAxis]));
  455. UnitySetJoystickPosition(idx + 1, 3, -GetAxisValue([rightStick yAxis]));
  456. }
  457. static void SimulateAttitudeViaGravityVector(const Vector3f& gravity, Quaternion4f& currentAttitude, Vector3f& rotationRate)
  458. {
  459. static Quaternion4f lastAttitude = QuatIdentity();
  460. static double lastTime = 0.0;
  461. double currentTime = [NSDate timeIntervalSinceReferenceDate];
  462. double deltaTime = lastTime - currentTime;
  463. currentAttitude = QuatRotationFromTo(gravity, VecMake(0.0f, 0.0f, -1.0f));
  464. rotationRate = VecScale(1.0f / deltaTime, QuatToEuler(QuatDifference(currentAttitude, lastAttitude)));
  465. lastAttitude = currentAttitude;
  466. lastTime = currentTime;
  467. }
  468. // Note that joystick axis numbers in documentation are shifted
  469. // by one. 1st axis is referred to by index 0, 16th by 15, etc.
  470. static void ReportJoystickMotion(int idx, GCMotion* motion)
  471. {
  472. Vector3f rotationRate = VecMake(0.0f, 0.0f, 0.0f);
  473. Quaternion4f attitude = QuatMake(0.0f, 0.0f, 0.0f, 1.0f);
  474. bool gotRotationData = false;
  475. if (motion.hasAttitudeAndRotationRate)
  476. {
  477. rotationRate = {(float)motion.rotationRate.x, (float)motion.rotationRate.y, (float)motion.rotationRate.z};
  478. attitude = {(float)motion.attitude.x, (float)motion.attitude.y, (float)motion.attitude.z, (float)motion.attitude.w};
  479. gotRotationData = true;
  480. }
  481. #if SIMULATE_ATTITUDE_FROM_GRAVITY
  482. if (!gotRotationData)
  483. SimulateAttitudeViaGravityVector(VecMake((float)motion.gravity.x, (float)motion.gravity.y, (float)motion.gravity.z), attitude, rotationRate);
  484. #endif
  485. // From docs:
  486. // gravity (x,y,z) : 16, 17, 18
  487. // user acceleration: 19, 20, 21
  488. // rotation rate: 22, 23, 24
  489. // attitude quaternion (x,y,z,w): 25, 26, 27, 28
  490. ReportJoystickXYZAxes(idx, 15, 16, 17, motion.gravity);
  491. ReportJoystickXYZAxes(idx, 18, 19, 20, motion.userAcceleration);
  492. ReportJoystickXYZAxes(idx, 21, 22, 23, rotationRate);
  493. ReportJoystickXYZWAxes(idx, 24, 25, 26, 27, attitude);
  494. #if PLATFORM_TVOS
  495. if (sGCMotionForwardingEnabled && !sGCMotionForwardedForCurrentFrame)
  496. {
  497. UnitySensorsSetGravity(0, motion.gravity.x, motion.gravity.y, motion.gravity.z);
  498. UnitySensorsSetUserAcceleration(0, motion.userAcceleration.x, motion.userAcceleration.y, motion.userAcceleration.z);
  499. UnitySensorsSetGyroRotationRate(0, rotationRate.y, rotationRate.x, rotationRate.z);
  500. UnitySensorsSetAttitude(0, attitude.x, attitude.y, attitude.z, attitude.w);
  501. UnityDidAccelerate(motion.userAcceleration.x + motion.gravity.x, motion.userAcceleration.y + motion.gravity.y, motion.userAcceleration.z + motion.gravity.z, [[NSDate date] timeIntervalSince1970]);
  502. sGCMotionForwardedForCurrentFrame = true;
  503. }
  504. #endif
  505. }
  506. static void ReportJoystick(GCController* controller, int idx)
  507. {
  508. if (controller.controllerPausedHandler == nil)
  509. controller.controllerPausedHandler = gControllerHandler;
  510. if ([controller extendedGamepad] != nil)
  511. ReportJoystickExtended(idx, [controller extendedGamepad]);
  512. else if ([controller microGamepad] != nil)
  513. ReportJoystickMicro(idx, [controller microGamepad]);
  514. else
  515. {
  516. // TODO: do something with not supported gamepad profiles
  517. }
  518. if (controller.motion != nil)
  519. ReportJoystickMotion(idx, controller.motion);
  520. // Map pause button
  521. SetJoystickButtonState(idx + 1, BTN_PAUSE, gPausedJoysticks[idx]);
  522. // Reset pause button
  523. gPausedJoysticks[idx] = false;
  524. }
  525. // On tvOS simulator we implement a fake remote as tvOS simulator
  526. // does not support controllers (yet)
  527. #if UNITY_TVOS_SIMULATOR_FAKE_REMOTE
  528. struct FakeRemoteState
  529. {
  530. bool pressedX, pressedA;
  531. bool pressedUp, pressedDown, pressedLeft, pressedRight;
  532. float xAxis, yAxis;
  533. FakeRemoteState() :
  534. pressedX(false),
  535. pressedA(false),
  536. pressedUp(false),
  537. pressedDown(false),
  538. pressedLeft(false),
  539. pressedRight(false),
  540. xAxis(0),
  541. yAxis(0)
  542. {}
  543. };
  544. static FakeRemoteState gFakeRemoteState;
  545. static void ReportFakeRemoteButton(int idx, JoystickButtonNumbers num, bool pressed)
  546. {
  547. SetJoystickButtonState(idx + 1, num, pressed);
  548. UnitySetJoystickPosition(idx + 1, num, pressed);
  549. }
  550. void ReportFakeRemote(int idx)
  551. {
  552. UnitySetJoystickPosition(idx + 1, 0, gFakeRemoteState.xAxis);
  553. UnitySetJoystickPosition(idx + 1, 1, -gFakeRemoteState.yAxis);
  554. ReportFakeRemoteButton(idx, BTN_DPAD_UP, gFakeRemoteState.pressedUp);
  555. ReportFakeRemoteButton(idx, BTN_DPAD_RIGHT, gFakeRemoteState.pressedRight);
  556. ReportFakeRemoteButton(idx, BTN_DPAD_DOWN, gFakeRemoteState.pressedDown);
  557. ReportFakeRemoteButton(idx, BTN_DPAD_LEFT, gFakeRemoteState.pressedLeft);
  558. ReportFakeRemoteButton(idx, BTN_A, gFakeRemoteState.pressedA);
  559. ReportFakeRemoteButton(idx, BTN_X, gFakeRemoteState.pressedX);
  560. }
  561. #endif
  562. extern "C" void UnityUpdateJoystickData()
  563. {
  564. UnityInitJoysticks();
  565. NSArray* list = QueryControllerCollection();
  566. #if PLATFORM_TVOS
  567. sGCMotionForwardedForCurrentFrame = false;
  568. #endif
  569. if (list != nil)
  570. {
  571. for (int i = 0; i < [list count]; i++)
  572. {
  573. id controller = [list objectAtIndex: i];
  574. ReportJoystick(controller, i);
  575. }
  576. }
  577. #if UNITY_TVOS_SIMULATOR_FAKE_REMOTE
  578. int remoteIndex = list != nil ? (int)[list count] : 0;
  579. ReportFakeRemote(remoteIndex);
  580. #endif
  581. // Report all aggregated joystick buttons in bulk
  582. HandleAggregatedJoystickState();
  583. }
  584. static NSString* FormatJoystickIdentifier(int idx, const char* typeString, const char* attachment, const char* vendorName)
  585. {
  586. return [NSString stringWithFormat: @"[%s,%s] joystick %d by %s", typeString, attachment, idx + 1, vendorName];
  587. }
  588. NSString* GetJoystickName(GCController* controller, int idx)
  589. {
  590. NSString* joystickName;
  591. if (controller != nil)
  592. {
  593. // iOS 8 has bug, which is encountered when controller is being attached
  594. // while app is still running. It creates two instances of controller object:
  595. // one original and one "Forwarded", accesing later properties are causing crashes
  596. const char* attached = "unknown";
  597. // Controller is good one
  598. if ([[controller vendorName] rangeOfString: @"Forwarded"].location == NSNotFound)
  599. attached = (controller.attachedToDevice ? "wired" : "wireless");
  600. const char* typeString = [controller extendedGamepad] != nil ? "extended" : "basic";
  601. joystickName = FormatJoystickIdentifier(idx, typeString, attached, [[controller vendorName] UTF8String]);
  602. }
  603. else
  604. {
  605. #if UNITY_TVOS_SIMULATOR_FAKE_REMOTE
  606. if (idx == [QueryControllerCollection() count])
  607. {
  608. joystickName = FormatJoystickIdentifier(idx, "basic", "wireless", "Unity");
  609. }
  610. #endif
  611. joystickName = @"unknown";
  612. }
  613. return joystickName;
  614. }
  615. extern "C" NSArray* UnityGetJoystickNames()
  616. {
  617. NSArray* joysticks = QueryControllerCollection();
  618. int count = joysticks != nil ? (int)[joysticks count] : 0;
  619. #if UNITY_TVOS_SIMULATOR_FAKE_REMOTE
  620. count++;
  621. #endif
  622. NSMutableArray * joystickNames = [NSMutableArray arrayWithCapacity: count];
  623. for (int i = 0; i < count; i++)
  624. {
  625. [joystickNames addObject: GetJoystickName(joysticks[i], i)];
  626. }
  627. return joystickNames;
  628. }
  629. extern "C" void UnityGetJoystickAxisName(int idx, int axis, char* buffer, int maxLen)
  630. {
  631. }
  632. extern "C" void UnityGetNiceKeyname(int key, char* buffer, int maxLen)
  633. {
  634. }
  635. #pragma clang diagnostic pop
  636. #if UNITY_USES_LOCATION
  637. @interface LocationServiceDelegate : NSObject<CLLocationManagerDelegate>
  638. @end
  639. #endif
  640. extern "C" void
  641. UnitySetLastLocation(double timestamp,
  642. float latitude,
  643. float longitude,
  644. float altitude,
  645. float horizontalAccuracy,
  646. float verticalAccuracy);
  647. extern "C" void
  648. UnitySetLastHeading(float magneticHeading,
  649. float trueHeading,
  650. float rawX, float rawY, float rawZ,
  651. 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. reorientedRawHeading.x, reorientedRawHeading.y, reorientedRawHeading.z,
  824. [newHeading.timestamp timeIntervalSince1970]);
  825. }
  826. #endif
  827. - (BOOL)locationManagerShouldDisplayHeadingCalibration:(CLLocationManager*)manager
  828. {
  829. return NO;
  830. }
  831. - (void)locationManager:(CLLocationManager*)manager didFailWithError:(NSError*)error;
  832. {
  833. gLocationServiceStatus.locationStatus = kLocationServiceFailed;
  834. gLocationServiceStatus.headingStatus = kLocationServiceFailed;
  835. }
  836. @end
  837. #endif
  838. #if PLATFORM_TVOS
  839. GCMicroGamepad* QueryMicroController()
  840. {
  841. NSArray* list = QueryControllerCollection();
  842. for (GCController* controller in list)
  843. {
  844. if (controller.microGamepad != nil)
  845. return controller.microGamepad;
  846. }
  847. return nil;
  848. }
  849. extern "C" int UnityGetAppleTVRemoteTouchesEnabled()
  850. {
  851. return gTVRemoteTouchesEnabled;
  852. }
  853. extern "C" void UnitySetAppleTVRemoteTouchesEnabled(int val)
  854. {
  855. gTVRemoteTouchesEnabled = val;
  856. }
  857. extern "C" int UnityGetAppleTVRemoteAllowExitToMenu()
  858. {
  859. return ((GCEventViewController*)UnityGetGLViewController()).controllerUserInteractionEnabled;
  860. }
  861. extern "C" void UnitySetAppleTVRemoteAllowExitToMenu(int val)
  862. {
  863. ((GCEventViewController*)UnityGetGLViewController()).controllerUserInteractionEnabled = val;
  864. }
  865. extern "C" int UnityGetAppleTVRemoteAllowRotation()
  866. {
  867. GCMicroGamepad* controller = QueryMicroController();
  868. if (controller != nil)
  869. return controller.allowsRotation;
  870. else
  871. return false;
  872. }
  873. extern "C" void UnitySetAppleTVRemoteAllowRotation(int val)
  874. {
  875. GCMicroGamepad* controller = QueryMicroController();
  876. if (controller != nil)
  877. controller.allowsRotation = val;
  878. else
  879. gTVRemoteAllowRotationInitialValue = val;
  880. }
  881. extern "C" int UnityGetAppleTVRemoteReportAbsoluteDpadValues()
  882. {
  883. GCMicroGamepad* controller = QueryMicroController();
  884. if (controller != nil)
  885. return controller.reportsAbsoluteDpadValues;
  886. else
  887. return false;
  888. }
  889. extern "C" void UnitySetAppleTVRemoteReportAbsoluteDpadValues(int val)
  890. {
  891. NSArray* list = QueryControllerCollection();
  892. for (GCController* controller in list)
  893. {
  894. if (controller.microGamepad != nil)
  895. controller.microGamepad.reportsAbsoluteDpadValues = val;
  896. else
  897. gTVRemoteReportsAbsoluteDpadValuesInitialValue = val;
  898. }
  899. }
  900. #endif
  901. #if UNITY_TVOS_SIMULATOR_FAKE_REMOTE
  902. static void FakeRemoteStateSetButton(UIPressType type, bool state)
  903. {
  904. switch (type)
  905. {
  906. case UIPressTypeUpArrow: gFakeRemoteState.pressedUp = state; return;
  907. case UIPressTypeDownArrow: gFakeRemoteState.pressedDown = state; return;
  908. case UIPressTypeLeftArrow: gFakeRemoteState.pressedLeft = state; return;
  909. case UIPressTypeRightArrow: gFakeRemoteState.pressedRight = state; return;
  910. case UIPressTypeSelect: gFakeRemoteState.pressedA = state; return;
  911. case UIPressTypePlayPause: gFakeRemoteState.pressedX = state; return;
  912. }
  913. }
  914. void ReportSimulatedRemoteButtonPress(UIPressType type)
  915. {
  916. FakeRemoteStateSetButton(type, true);
  917. }
  918. void ReportSimulatedRemoteButtonRelease(UIPressType type)
  919. {
  920. FakeRemoteStateSetButton(type, false);
  921. }
  922. static float FakeRemoteMapTouchToAxis(float pos, float bounds)
  923. {
  924. float halfRange = bounds / 2;
  925. return (pos - halfRange) / halfRange;
  926. }
  927. void ReportSimulatedRemoteTouchesBegan(UIView* view, NSSet* touches)
  928. {
  929. ReportSimulatedRemoteTouchesMoved(view, touches);
  930. }
  931. void ReportSimulatedRemoteTouchesMoved(UIView* view, NSSet* touches)
  932. {
  933. for (UITouch* touch in touches)
  934. {
  935. gFakeRemoteState.xAxis = FakeRemoteMapTouchToAxis([touch locationInView: view].x, view.bounds.size.width);
  936. gFakeRemoteState.yAxis = FakeRemoteMapTouchToAxis([touch locationInView: view].y, view.bounds.size.height);
  937. // We assume that at most single touch is received.
  938. break;
  939. }
  940. }
  941. void ReportSimulatedRemoteTouchesEnded(UIView* view, NSSet* touches)
  942. {
  943. gFakeRemoteState.xAxis = 0;
  944. gFakeRemoteState.yAxis = 0;
  945. }
  946. #endif