iPhone_Sensors.mm 35 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180
  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. typedef struct
  318. {
  319. int buttonCode;
  320. bool state;
  321. bool lastRecordedState;
  322. bool StateChanged() { return state ^ lastRecordedState; }
  323. void ClearRecordedState() { lastRecordedState = false; }
  324. } JoystickButtonState;
  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 (@available(tvOS 14.5, *))
  432. {
  433. cardinalDpad = [[gamepad dpads] valueForKey: @"Cardinal Direction Pad"];
  434. }
  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 14.5, *))
  446. {
  447. isDirectionalButtonPressed = [cardinalDpad up].isPressed ||
  448. [cardinalDpad right].isPressed ||
  449. [cardinalDpad down].isPressed ||
  450. [cardinalDpad left].isPressed;
  451. }
  452. else if (@available(tvOS 15, *))
  453. {
  454. ReportJoystickButton(idx, BTN_A, [[gamepad buttons] valueForKey: GCInputDirectionalCenterButton]);
  455. isDirectionalButtonPressed = true;
  456. }
  457. }
  458. #endif
  459. if (!isDirectionalButtonPressed)
  460. ReportJoystickButton(idx, BTN_A, [gamepad buttonA]);
  461. ReportJoystickButton(idx, BTN_X, [gamepad buttonX]);
  462. }
  463. static void ReportJoystickExtended(int idx, GCExtendedGamepad* gamepad)
  464. {
  465. GCControllerDirectionPad* dpad = [gamepad dpad];
  466. ReportJoystickButton(idx, BTN_DPAD_UP, [dpad up]);
  467. ReportJoystickButton(idx, BTN_DPAD_RIGHT, [dpad right]);
  468. ReportJoystickButton(idx, BTN_DPAD_DOWN, [dpad down]);
  469. ReportJoystickButton(idx, BTN_DPAD_LEFT, [dpad left]);
  470. ReportJoystickButton(idx, BTN_A, [gamepad buttonA]);
  471. ReportJoystickButton(idx, BTN_B, [gamepad buttonB]);
  472. ReportJoystickButton(idx, BTN_Y, [gamepad buttonY]);
  473. ReportJoystickButton(idx, BTN_X, [gamepad buttonX]);
  474. ReportJoystickButton(idx, BTN_L1, [gamepad leftShoulder]);
  475. ReportJoystickButton(idx, BTN_R1, [gamepad rightShoulder]);
  476. ReportJoystickButton(idx, BTN_L2, [gamepad leftTrigger]);
  477. ReportJoystickButton(idx, BTN_R2, [gamepad rightTrigger]);
  478. if (@available(iOS 12.1, *))
  479. {
  480. ReportJoystickButton(idx, BTN_L3, [gamepad valueForKey: @"leftThumbstickButton"]);
  481. ReportJoystickButton(idx, BTN_R3, [gamepad valueForKey: @"rightThumbstickButton"]);
  482. }
  483. if (@available(iOS 13.0, *))
  484. {
  485. ReportJoystickButton(idx, BTN_MENU, [gamepad valueForKey: @"buttonMenu"]);
  486. ReportJoystickButton(idx, BTN_PAUSE, [gamepad valueForKey: @"buttonOptions"]);
  487. }
  488. // To avoid overwriting axis input with button input when axis index
  489. // overlaps with button enum value, handle directional input after buttons.
  490. GCControllerDirectionPad* leftStick = [gamepad leftThumbstick];
  491. GCControllerDirectionPad* rightStick = [gamepad rightThumbstick];
  492. UnitySetJoystickPosition(idx + 1, 0, GetAxisValue([leftStick xAxis]));
  493. UnitySetJoystickPosition(idx + 1, 1, -GetAxisValue([leftStick yAxis]));
  494. UnitySetJoystickPosition(idx + 1, 2, GetAxisValue([rightStick xAxis]));
  495. UnitySetJoystickPosition(idx + 1, 3, -GetAxisValue([rightStick yAxis]));
  496. }
  497. static void SimulateAttitudeViaGravityVector(const Vector3f& gravity, Quaternion4f& currentAttitude, Vector3f& rotationRate)
  498. {
  499. static Quaternion4f lastAttitude = QuatIdentity();
  500. static double lastTime = 0.0;
  501. double currentTime = [NSDate timeIntervalSinceReferenceDate];
  502. double deltaTime = lastTime - currentTime;
  503. currentAttitude = QuatRotationFromTo(gravity, VecMake(0.0f, 0.0f, -1.0f));
  504. rotationRate = VecScale(1.0f / deltaTime, QuatToEuler(QuatDifference(currentAttitude, lastAttitude)));
  505. lastAttitude = currentAttitude;
  506. lastTime = currentTime;
  507. }
  508. // Note that joystick axis numbers in documentation are shifted
  509. // by one. 1st axis is referred to by index 0, 16th by 15, etc.
  510. static void ReportJoystickMotion(int idx, GCMotion* motion)
  511. {
  512. Vector3f rotationRate = VecMake(0.0f, 0.0f, 0.0f);
  513. Quaternion4f attitude = QuatMake(0.0f, 0.0f, 0.0f, 1.0f);
  514. bool gotRotationData = false;
  515. if (motion.hasAttitudeAndRotationRate)
  516. {
  517. rotationRate = {(float)motion.rotationRate.x, (float)motion.rotationRate.y, (float)motion.rotationRate.z};
  518. attitude = {(float)motion.attitude.x, (float)motion.attitude.y, (float)motion.attitude.z, (float)motion.attitude.w};
  519. gotRotationData = true;
  520. }
  521. #if SIMULATE_ATTITUDE_FROM_GRAVITY
  522. if (!gotRotationData)
  523. SimulateAttitudeViaGravityVector(VecMake((float)motion.gravity.x, (float)motion.gravity.y, (float)motion.gravity.z), attitude, rotationRate);
  524. #endif
  525. // From docs:
  526. // gravity (x,y,z) : 16, 17, 18
  527. // user acceleration: 19, 20, 21
  528. // rotation rate: 22, 23, 24
  529. // attitude quaternion (x,y,z,w): 25, 26, 27, 28
  530. ReportJoystickXYZAxes(idx, 15, 16, 17, motion.gravity);
  531. ReportJoystickXYZAxes(idx, 18, 19, 20, motion.userAcceleration);
  532. ReportJoystickXYZAxes(idx, 21, 22, 23, rotationRate);
  533. ReportJoystickXYZWAxes(idx, 24, 25, 26, 27, attitude);
  534. #if PLATFORM_TVOS
  535. if (sGCMotionForwardingEnabled && !sGCMotionForwardedForCurrentFrame)
  536. {
  537. UnitySensorsSetGravity(0, motion.gravity.x, motion.gravity.y, motion.gravity.z);
  538. UnitySensorsSetUserAcceleration(0, motion.userAcceleration.x, motion.userAcceleration.y, motion.userAcceleration.z);
  539. UnitySensorsSetGyroRotationRate(0, rotationRate.y, rotationRate.x, rotationRate.z);
  540. UnitySensorsSetAttitude(0, attitude.x, attitude.y, attitude.z, attitude.w);
  541. UnityDidAccelerate(motion.userAcceleration.x + motion.gravity.x, motion.userAcceleration.y + motion.gravity.y, motion.userAcceleration.z + motion.gravity.z, [[NSDate date] timeIntervalSince1970]);
  542. sGCMotionForwardedForCurrentFrame = true;
  543. }
  544. #endif
  545. }
  546. static void ReportJoystick(GCController* controller, int idx)
  547. {
  548. if (controller.controllerPausedHandler == nil)
  549. controller.controllerPausedHandler = gControllerHandler;
  550. if ([controller extendedGamepad] != nil)
  551. ReportJoystickExtended(idx, [controller extendedGamepad]);
  552. else if ([controller microGamepad] != nil)
  553. ReportJoystickMicro(idx, [controller microGamepad]);
  554. else
  555. {
  556. // TODO: do something with not supported gamepad profiles
  557. }
  558. if (controller.motion != nil)
  559. ReportJoystickMotion(idx, controller.motion);
  560. // Map pause button
  561. SetJoystickButtonState(idx + 1, BTN_PAUSE, gPausedJoysticks[idx]);
  562. // Reset pause button
  563. gPausedJoysticks[idx] = false;
  564. }
  565. // On tvOS simulator we implement a fake remote as tvOS simulator
  566. // does not support controllers (yet)
  567. #if UNITY_TVOS_SIMULATOR_FAKE_REMOTE
  568. struct FakeRemoteState
  569. {
  570. bool pressedX, pressedA;
  571. bool pressedUp, pressedDown, pressedLeft, pressedRight;
  572. float xAxis, yAxis;
  573. FakeRemoteState() :
  574. pressedX(false),
  575. pressedA(false),
  576. pressedUp(false),
  577. pressedDown(false),
  578. pressedLeft(false),
  579. pressedRight(false),
  580. xAxis(0),
  581. yAxis(0)
  582. {}
  583. };
  584. static FakeRemoteState gFakeRemoteState;
  585. static void ReportFakeRemoteButton(int idx, JoystickButtonNumbers num, bool pressed)
  586. {
  587. SetJoystickButtonState(idx + 1, num, pressed);
  588. UnitySetJoystickPosition(idx + 1, num, pressed);
  589. }
  590. void ReportFakeRemote(int idx)
  591. {
  592. UnitySetJoystickPosition(idx + 1, 0, gFakeRemoteState.xAxis);
  593. UnitySetJoystickPosition(idx + 1, 1, -gFakeRemoteState.yAxis);
  594. ReportFakeRemoteButton(idx, BTN_DPAD_UP, gFakeRemoteState.pressedUp);
  595. ReportFakeRemoteButton(idx, BTN_DPAD_RIGHT, gFakeRemoteState.pressedRight);
  596. ReportFakeRemoteButton(idx, BTN_DPAD_DOWN, gFakeRemoteState.pressedDown);
  597. ReportFakeRemoteButton(idx, BTN_DPAD_LEFT, gFakeRemoteState.pressedLeft);
  598. ReportFakeRemoteButton(idx, BTN_A, gFakeRemoteState.pressedA);
  599. ReportFakeRemoteButton(idx, BTN_X, gFakeRemoteState.pressedX);
  600. }
  601. #endif
  602. extern "C" void UnityUpdateJoystickData()
  603. {
  604. UnityInitJoysticks();
  605. NSArray* list = QueryControllerCollection();
  606. #if PLATFORM_TVOS
  607. sGCMotionForwardedForCurrentFrame = false;
  608. #endif
  609. if (list != nil)
  610. {
  611. for (int i = 0; i < [list count]; i++)
  612. {
  613. id controller = [list objectAtIndex: i];
  614. ReportJoystick(controller, i);
  615. }
  616. }
  617. #if UNITY_TVOS_SIMULATOR_FAKE_REMOTE
  618. int remoteIndex = list != nil ? (int)[list count] : 0;
  619. ReportFakeRemote(remoteIndex);
  620. #endif
  621. // Report all aggregated joystick buttons in bulk
  622. HandleAggregatedJoystickState();
  623. }
  624. static NSString* FormatJoystickIdentifier(int idx, const char* typeString, const char* attachment, const char* vendorName)
  625. {
  626. return [NSString stringWithFormat: @"[%s,%s] joystick %d by %s", typeString, attachment, idx + 1, vendorName];
  627. }
  628. NSString* GetJoystickName(GCController* controller, int idx)
  629. {
  630. if (controller != nil)
  631. {
  632. // iOS 8 has bug, which is encountered when controller is being attached
  633. // while app is still running. It creates two instances of controller object:
  634. // one original and one "Forwarded", accesing later properties are causing crashes
  635. const char* attached = "unknown";
  636. // Controller is good one
  637. if ([[controller vendorName] rangeOfString: @"Forwarded"].location == NSNotFound)
  638. attached = (controller.attachedToDevice ? "wired" : "wireless");
  639. const char* typeString = [controller extendedGamepad] != nil ? "extended" : "basic";
  640. return FormatJoystickIdentifier(idx, typeString, attached, [[controller vendorName] UTF8String]);
  641. }
  642. return @"unknown";
  643. }
  644. extern "C" NSArray* UnityGetJoystickNames()
  645. {
  646. NSArray* joysticks = QueryControllerCollection();
  647. int count = joysticks != nil ? (int)[joysticks count] : 0;
  648. NSMutableArray * joystickNames = [NSMutableArray arrayWithCapacity: count];
  649. for (int i = 0; i < count; i++)
  650. {
  651. [joystickNames addObject: GetJoystickName(joysticks[i], i)];
  652. }
  653. #if UNITY_TVOS_SIMULATOR_FAKE_REMOTE
  654. [joystickNames addObject: FormatJoystickIdentifier(count, "basic", "wireless", "Unity")];
  655. #endif
  656. return joystickNames;
  657. }
  658. extern "C" void UnityGetJoystickAxisName(int idx, int axis, char* buffer, int maxLen)
  659. {
  660. }
  661. extern "C" void UnityGetNiceKeyname(int key, char* buffer, int maxLen)
  662. {
  663. }
  664. #pragma clang diagnostic pop
  665. #if UNITY_USES_LOCATION
  666. @interface LocationServiceDelegate : NSObject<CLLocationManagerDelegate>
  667. @end
  668. #endif
  669. extern "C" void
  670. UnitySetLastLocation(double timestamp,
  671. float latitude,
  672. float longitude,
  673. float altitude,
  674. float horizontalAccuracy,
  675. float verticalAccuracy);
  676. extern "C" void
  677. UnitySetLastHeading(float magneticHeading, float trueHeading, float headingAccuracy,
  678. float rawX, float rawY, float rawZ, double timestamp);
  679. #if UNITY_USES_LOCATION
  680. struct LocationServiceInfo
  681. {
  682. private:
  683. LocationServiceDelegate* delegate;
  684. CLLocationManager* locationManager;
  685. public:
  686. LocationServiceStatus locationStatus;
  687. LocationServiceStatus headingStatus;
  688. float desiredAccuracy;
  689. float distanceFilter;
  690. LocationServiceInfo();
  691. CLLocationManager* GetLocationManager();
  692. };
  693. LocationServiceInfo::LocationServiceInfo()
  694. {
  695. locationStatus = kLocationServiceStopped;
  696. desiredAccuracy = kCLLocationAccuracyKilometer;
  697. distanceFilter = 500;
  698. headingStatus = kLocationServiceStopped;
  699. }
  700. static LocationServiceInfo gLocationServiceStatus;
  701. CLLocationManager* LocationServiceInfo::GetLocationManager()
  702. {
  703. if (locationManager == nil)
  704. {
  705. locationManager = [[CLLocationManager alloc] init];
  706. delegate = [LocationServiceDelegate alloc];
  707. locationManager.delegate = delegate;
  708. }
  709. return locationManager;
  710. }
  711. #endif
  712. bool LocationService::IsServiceEnabledByUser()
  713. {
  714. #if UNITY_USES_LOCATION
  715. return [CLLocationManager locationServicesEnabled];
  716. #else
  717. return false;
  718. #endif
  719. }
  720. void LocationService::SetDesiredAccuracy(float val)
  721. {
  722. #if UNITY_USES_LOCATION
  723. gLocationServiceStatus.desiredAccuracy = val;
  724. #endif
  725. }
  726. float LocationService::GetDesiredAccuracy()
  727. {
  728. #if UNITY_USES_LOCATION
  729. return gLocationServiceStatus.desiredAccuracy;
  730. #else
  731. return NAN;
  732. #endif
  733. }
  734. void LocationService::SetDistanceFilter(float val)
  735. {
  736. #if UNITY_USES_LOCATION
  737. gLocationServiceStatus.distanceFilter = val;
  738. #endif
  739. }
  740. float LocationService::GetDistanceFilter()
  741. {
  742. #if UNITY_USES_LOCATION
  743. return gLocationServiceStatus.distanceFilter;
  744. #else
  745. return NAN;
  746. #endif
  747. }
  748. void LocationService::StartUpdatingLocation()
  749. {
  750. #if UNITY_USES_LOCATION
  751. if (gLocationServiceStatus.locationStatus != kLocationServiceRunning)
  752. {
  753. CLLocationManager* locationManager = gLocationServiceStatus.GetLocationManager();
  754. [locationManager requestWhenInUseAuthorization];
  755. locationManager.desiredAccuracy = gLocationServiceStatus.desiredAccuracy;
  756. // Set a movement threshold for new events
  757. locationManager.distanceFilter = gLocationServiceStatus.distanceFilter;
  758. #if PLATFORM_IOS
  759. [locationManager startUpdatingLocation];
  760. #else
  761. [locationManager requestLocation];
  762. #endif
  763. gLocationServiceStatus.locationStatus = kLocationServiceInitializing;
  764. }
  765. #endif
  766. }
  767. void LocationService::StopUpdatingLocation()
  768. {
  769. #if UNITY_USES_LOCATION
  770. if (gLocationServiceStatus.locationStatus != kLocationServiceStopped)
  771. {
  772. [gLocationServiceStatus.GetLocationManager() stopUpdatingLocation];
  773. gLocationServiceStatus.locationStatus = kLocationServiceStopped;
  774. }
  775. #endif
  776. }
  777. void LocationService::SetHeadingUpdatesEnabled(bool enabled)
  778. {
  779. #if PLATFORM_IOS && UNITY_USES_LOCATION
  780. if (enabled)
  781. {
  782. if (gLocationServiceStatus.headingStatus != kLocationServiceRunning &&
  783. IsHeadingAvailable())
  784. {
  785. CLLocationManager* locationManager = gLocationServiceStatus.GetLocationManager();
  786. [locationManager startUpdatingHeading];
  787. gLocationServiceStatus.headingStatus = kLocationServiceInitializing;
  788. }
  789. }
  790. else
  791. {
  792. if (gLocationServiceStatus.headingStatus != kLocationServiceStopped)
  793. {
  794. [gLocationServiceStatus.GetLocationManager() stopUpdatingHeading];
  795. gLocationServiceStatus.headingStatus = kLocationServiceStopped;
  796. }
  797. }
  798. #endif
  799. }
  800. bool LocationService::IsHeadingUpdatesEnabled()
  801. {
  802. #if UNITY_USES_LOCATION
  803. return (gLocationServiceStatus.headingStatus == kLocationServiceRunning);
  804. #else
  805. return false;
  806. #endif
  807. }
  808. LocationServiceStatus LocationService::GetLocationStatus()
  809. {
  810. #if UNITY_USES_LOCATION
  811. return (LocationServiceStatus)gLocationServiceStatus.locationStatus;
  812. #else
  813. return kLocationServiceFailed;
  814. #endif
  815. }
  816. LocationServiceStatus LocationService::GetHeadingStatus()
  817. {
  818. #if UNITY_USES_LOCATION
  819. return (LocationServiceStatus)gLocationServiceStatus.headingStatus;
  820. #else
  821. return kLocationServiceFailed;
  822. #endif
  823. }
  824. bool LocationService::IsHeadingAvailable()
  825. {
  826. #if PLATFORM_IOS && UNITY_USES_LOCATION
  827. return [CLLocationManager headingAvailable];
  828. #else
  829. return false;
  830. #endif
  831. }
  832. #if UNITY_USES_LOCATION
  833. @implementation LocationServiceDelegate
  834. - (void)locationManager:(CLLocationManager*)manager didUpdateLocations:(NSArray*)locations
  835. {
  836. CLLocation* lastLocation = locations.lastObject;
  837. gLocationServiceStatus.locationStatus = kLocationServiceRunning;
  838. UnitySetLastLocation([lastLocation.timestamp timeIntervalSince1970],
  839. lastLocation.coordinate.latitude, lastLocation.coordinate.longitude, lastLocation.altitude,
  840. lastLocation.horizontalAccuracy, lastLocation.verticalAccuracy
  841. );
  842. }
  843. #if PLATFORM_IOS
  844. - (void)locationManager:(CLLocationManager*)manager didUpdateHeading:(CLHeading*)newHeading
  845. {
  846. gLocationServiceStatus.headingStatus = kLocationServiceRunning;
  847. Vector3f reorientedRawHeading = UnityReorientVector3(newHeading.x, newHeading.y, newHeading.z);
  848. UnitySetLastHeading(UnityReorientHeading(newHeading.magneticHeading),
  849. UnityReorientHeading(newHeading.trueHeading),
  850. newHeading.headingAccuracy,
  851. reorientedRawHeading.x, reorientedRawHeading.y, reorientedRawHeading.z,
  852. [newHeading.timestamp timeIntervalSince1970]);
  853. }
  854. #endif
  855. - (BOOL)locationManagerShouldDisplayHeadingCalibration:(CLLocationManager*)manager
  856. {
  857. return NO;
  858. }
  859. - (void)locationManager:(CLLocationManager*)manager didFailWithError:(NSError*)error;
  860. {
  861. gLocationServiceStatus.locationStatus = kLocationServiceFailed;
  862. gLocationServiceStatus.headingStatus = kLocationServiceFailed;
  863. }
  864. @end
  865. #endif
  866. #if PLATFORM_TVOS
  867. GCMicroGamepad* QueryMicroController()
  868. {
  869. NSArray* list = QueryControllerCollection();
  870. for (GCController* controller in list)
  871. {
  872. if (controller.microGamepad != nil)
  873. return controller.microGamepad;
  874. }
  875. return nil;
  876. }
  877. extern "C" int UnityGetAppleTVRemoteTouchesEnabled()
  878. {
  879. return gTVRemoteTouchesEnabled;
  880. }
  881. extern "C" void UnitySetAppleTVRemoteTouchesEnabled(int val)
  882. {
  883. gTVRemoteTouchesEnabled = val;
  884. }
  885. /*
  886. TVRemoteAllowExitToMenu.
  887. Lowest bit caches the value of .controllerUserInteractionEnabled.
  888. Second lowest bit is set if .controllerUserInteractionEnabled is temporarily changed for internal purposes.
  889. */
  890. extern "C" int UnityGetAppleTVRemoteAllowExitToMenu()
  891. {
  892. if (gTVControllerUserInteractionEnabled & 2)
  893. return gTVControllerUserInteractionEnabled & 1;
  894. return ((GCEventViewController*)UnityGetGLViewController()).controllerUserInteractionEnabled;
  895. }
  896. /*
  897. Same as getter above, except that second lowest bit here indicates fake setting,
  898. meaning we set the value on controller, but cache the true value so getter report no changes.
  899. */
  900. extern "C" void UnitySetAppleTVRemoteAllowExitToMenu(int val)
  901. {
  902. bool newVal = val & 1;
  903. if (val & 2)
  904. {
  905. if (gTVControllerUserInteractionEnabled == val)
  906. return;
  907. if (0 == (gTVControllerUserInteractionEnabled & 2))
  908. {
  909. int cacheVal = ((GCEventViewController*)UnityGetGLViewController()).controllerUserInteractionEnabled;
  910. gTVControllerUserInteractionEnabled = 2 | cacheVal;
  911. }
  912. }
  913. ((GCEventViewController*)UnityGetGLViewController()).controllerUserInteractionEnabled = newVal;
  914. }
  915. extern "C" int UnityGetAppleTVRemoteAllowRotation()
  916. {
  917. GCMicroGamepad* controller = QueryMicroController();
  918. if (controller != nil)
  919. return controller.allowsRotation;
  920. else
  921. return false;
  922. }
  923. extern "C" void UnitySetAppleTVRemoteAllowRotation(int val)
  924. {
  925. GCMicroGamepad* controller = QueryMicroController();
  926. if (controller != nil)
  927. controller.allowsRotation = val;
  928. else
  929. gTVRemoteAllowRotationInitialValue = val;
  930. }
  931. extern "C" int UnityGetAppleTVRemoteReportAbsoluteDpadValues()
  932. {
  933. GCMicroGamepad* controller = QueryMicroController();
  934. if (controller != nil)
  935. return controller.reportsAbsoluteDpadValues;
  936. else
  937. return false;
  938. }
  939. extern "C" void UnitySetAppleTVRemoteReportAbsoluteDpadValues(int val)
  940. {
  941. NSArray* list = QueryControllerCollection();
  942. for (GCController* controller in list)
  943. {
  944. if (controller.microGamepad != nil)
  945. controller.microGamepad.reportsAbsoluteDpadValues = val;
  946. else
  947. gTVRemoteReportsAbsoluteDpadValuesInitialValue = val;
  948. }
  949. }
  950. #endif
  951. #if UNITY_TVOS_SIMULATOR_FAKE_REMOTE
  952. static void FakeRemoteStateSetButton(UIPressType type, bool state)
  953. {
  954. switch (type)
  955. {
  956. case UIPressTypeUpArrow: gFakeRemoteState.pressedUp = state; return;
  957. case UIPressTypeDownArrow: gFakeRemoteState.pressedDown = state; return;
  958. case UIPressTypeLeftArrow: gFakeRemoteState.pressedLeft = state; return;
  959. case UIPressTypeRightArrow: gFakeRemoteState.pressedRight = state; return;
  960. case UIPressTypeSelect: gFakeRemoteState.pressedA = state; return;
  961. case UIPressTypePlayPause: gFakeRemoteState.pressedX = state; return;
  962. }
  963. }
  964. void ReportSimulatedRemoteButtonPress(UIPressType type)
  965. {
  966. FakeRemoteStateSetButton(type, true);
  967. }
  968. void ReportSimulatedRemoteButtonRelease(UIPressType type)
  969. {
  970. FakeRemoteStateSetButton(type, false);
  971. }
  972. static float FakeRemoteMapTouchToAxis(float pos, float bounds)
  973. {
  974. float halfRange = bounds / 2;
  975. return (pos - halfRange) / halfRange;
  976. }
  977. void ReportSimulatedRemoteTouchesBegan(UIView* view, NSSet* touches)
  978. {
  979. ReportSimulatedRemoteTouchesMoved(view, touches);
  980. }
  981. void ReportSimulatedRemoteTouchesMoved(UIView* view, NSSet* touches)
  982. {
  983. for (UITouch* touch in touches)
  984. {
  985. gFakeRemoteState.xAxis = FakeRemoteMapTouchToAxis([touch locationInView: view].x, view.bounds.size.width);
  986. gFakeRemoteState.yAxis = FakeRemoteMapTouchToAxis([touch locationInView: view].y, view.bounds.size.height);
  987. // We assume that at most single touch is received.
  988. break;
  989. }
  990. }
  991. void ReportSimulatedRemoteTouchesEnded(UIView* view, NSSet* touches)
  992. {
  993. gFakeRemoteState.xAxis = 0;
  994. gFakeRemoteState.yAxis = 0;
  995. }
  996. #endif