iPhone_Sensors.mm 35 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201
  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. #if !PLATFORM_TVOS
  31. static NSMutableSet *pressedButtons = nil;
  32. #endif
  33. static ControllerPausedHandler gControllerHandler = ^(GCController *controller)
  34. {
  35. NSArray* list = QueryControllerCollection();
  36. if (list != nil)
  37. {
  38. NSUInteger idx = [list indexOfObject: controller];
  39. if (idx < MAX_JOYSTICKS)
  40. {
  41. gPausedJoysticks[idx] = !gPausedJoysticks[idx];
  42. }
  43. }
  44. };
  45. extern "C" bool IsCompensatingSensors() { return gCompensateSensors; }
  46. extern "C" void SetCompensatingSensors(bool val) { gCompensateSensors = val; }
  47. inline float UnityReorientHeading(float heading)
  48. {
  49. if (IsCompensatingSensors())
  50. {
  51. float rotateBy = 0.f;
  52. switch (UnityCurrentOrientation())
  53. {
  54. case portraitUpsideDown:
  55. rotateBy = -180.f;
  56. break;
  57. case landscapeLeft:
  58. rotateBy = -270.f;
  59. break;
  60. case landscapeRight:
  61. rotateBy = -90.f;
  62. break;
  63. default:
  64. break;
  65. }
  66. return fmodf((360.f + heading + rotateBy), 360.f);
  67. }
  68. else
  69. {
  70. return heading;
  71. }
  72. }
  73. inline Vector3f UnityReorientVector3(float x, float y, float z)
  74. {
  75. if (IsCompensatingSensors())
  76. {
  77. Vector3f res;
  78. switch (UnityCurrentOrientation())
  79. {
  80. case portraitUpsideDown:
  81. { res = (Vector3f) {-x, -y, z}; }
  82. break;
  83. case landscapeLeft:
  84. { res = (Vector3f) {-y, x, z}; }
  85. break;
  86. case landscapeRight:
  87. { res = (Vector3f) {y, -x, z}; }
  88. break;
  89. default:
  90. { res = (Vector3f) {x, y, z}; }
  91. }
  92. return res;
  93. }
  94. else
  95. {
  96. return (Vector3f) {x, y, z};
  97. }
  98. }
  99. inline Quaternion4f UnityReorientQuaternion(float x, float y, float z, float w)
  100. {
  101. if (IsCompensatingSensors())
  102. {
  103. Quaternion4f res, inp = {x, y, z, w};
  104. switch (UnityCurrentOrientation())
  105. {
  106. case landscapeLeft:
  107. QuatMultiply(res, inp, gQuatRot[1]);
  108. break;
  109. case portraitUpsideDown:
  110. QuatMultiply(res, inp, gQuatRot[2]);
  111. break;
  112. case landscapeRight:
  113. QuatMultiply(res, inp, gQuatRot[3]);
  114. break;
  115. default:
  116. res = inp;
  117. }
  118. return res;
  119. }
  120. else
  121. {
  122. return (Quaternion4f) {x, y, z, w};
  123. }
  124. }
  125. #if PLATFORM_TVOS
  126. static bool sGCMotionForwardingEnabled = false;
  127. static bool sGCMotionForwardedForCurrentFrame = false;
  128. #else
  129. static CMMotionManager* sMotionManager = nil;
  130. static NSOperationQueue* sMotionQueue = nil;
  131. #endif
  132. // Current update interval or 0.0f if not initialized. This is returned
  133. // to the user as current update interval and this value is set to 0.0f when
  134. // gyroscope is disabled.
  135. static float sUpdateInterval = 0.0f;
  136. // Update interval set by the user. Core motion will be set-up to use
  137. // this update interval after disabling and re-enabling gyroscope
  138. // so users can set update interval, disable gyroscope, enable gyroscope and
  139. // after that gyroscope will be updated at this previously set interval.
  140. #if !PLATFORM_TVOS
  141. static float sUserUpdateInterval = 1.0f / 30.0f;
  142. #endif
  143. void SensorsCleanup()
  144. {
  145. #if !PLATFORM_TVOS
  146. if (sMotionManager != nil)
  147. {
  148. [sMotionManager stopGyroUpdates];
  149. [sMotionManager stopDeviceMotionUpdates];
  150. [sMotionManager stopAccelerometerUpdates];
  151. sMotionManager = nil;
  152. }
  153. sMotionQueue = nil;
  154. #endif
  155. }
  156. extern "C" void UnityCoreMotionStart()
  157. {
  158. #if PLATFORM_TVOS
  159. sGCMotionForwardingEnabled = true;
  160. #else
  161. if (sMotionQueue == nil)
  162. sMotionQueue = [[NSOperationQueue alloc] init];
  163. bool initMotionManager = (sMotionManager == nil);
  164. if (initMotionManager)
  165. sMotionManager = [[CMMotionManager alloc] init];
  166. if (gEnableGyroscope && sMotionManager.gyroAvailable)
  167. {
  168. [sMotionManager startGyroUpdates];
  169. [sMotionManager setGyroUpdateInterval: sUpdateInterval];
  170. }
  171. if (gEnableGyroscope && 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. } JoystickButtonState;
  322. JoystickButtonState gAggregatedJoystickState[BTN_COUNT];
  323. static float GetAxisValue(GCControllerAxisInput* axis)
  324. {
  325. return axis.value;
  326. }
  327. static float GetButtonValue(GCControllerButtonInput* button)
  328. {
  329. return button.value;
  330. }
  331. static BOOL GetButtonPressed(GCControllerButtonInput* button)
  332. {
  333. return button.pressed;
  334. }
  335. extern "C" void UnityInitJoysticks()
  336. {
  337. if (!gJoysticksInited)
  338. {
  339. NSBundle* bundle = [NSBundle bundleWithPath: @"/System/Library/Frameworks/GameController.framework"];
  340. if (bundle)
  341. {
  342. [bundle load];
  343. gGameControllerClass = [bundle classNamed: @"GCController"];
  344. //Apply settings that could have been set by user scripts before controller initialization
  345. #if PLATFORM_TVOS
  346. UnitySetAppleTVRemoteAllowRotation(gTVRemoteAllowRotationInitialValue);
  347. UnitySetAppleTVRemoteReportAbsoluteDpadValues(gTVRemoteReportsAbsoluteDpadValuesInitialValue);
  348. #endif
  349. }
  350. for (int i = 0; i < BTN_COUNT; i++)
  351. {
  352. char buf[128];
  353. sprintf(buf, "joystick button %d", i);
  354. gAggregatedJoystickState[i].buttonCode = UnityStringToKey(buf);
  355. gAggregatedJoystickState[i].state = false;
  356. }
  357. #if !PLATFORM_TVOS
  358. pressedButtons = [[NSMutableSet alloc] init];
  359. #endif
  360. gJoysticksInited = true;
  361. }
  362. }
  363. static NSArray* QueryControllerCollection()
  364. {
  365. return gGameControllerClass != nil ? (NSArray*)[gGameControllerClass performSelector: @selector(controllers)] : nil;
  366. }
  367. static void ResetAggregatedJoystickState()
  368. {
  369. for (int i = 0; i < BTN_COUNT; i++)
  370. {
  371. BOOL shouldSetState = YES;
  372. #if !PLATFORM_TVOS
  373. shouldSetState = [pressedButtons containsObject: [NSNumber numberWithInteger: gAggregatedJoystickState[i].buttonCode]];
  374. #endif
  375. if (shouldSetState)
  376. {
  377. gAggregatedJoystickState[i].state = false;
  378. }
  379. }
  380. #if !PLATFORM_TVOS
  381. for (NSNumber *code in pressedButtons)
  382. {
  383. UnitySetKeyState((int)[code integerValue], false);
  384. }
  385. [pressedButtons removeAllObjects];
  386. #endif
  387. }
  388. static void SetAggregatedJoystickState()
  389. {
  390. for (int i = 0; i < BTN_COUNT; i++)
  391. {
  392. #if !PLATFORM_TVOS
  393. if (gAggregatedJoystickState[i].state)
  394. {
  395. UnitySetKeyState(gAggregatedJoystickState[i].buttonCode, gAggregatedJoystickState[i].state);
  396. [pressedButtons addObject: [NSNumber numberWithInteger: gAggregatedJoystickState[i].buttonCode]];
  397. }
  398. #else
  399. UnitySetKeyState(gAggregatedJoystickState[i].buttonCode, gAggregatedJoystickState[i].state);
  400. #endif
  401. }
  402. }
  403. // Mirror button input into virtual joystick 0
  404. static void ReportAggregatedJoystickButton(int buttonNum, int state)
  405. {
  406. assert(buttonNum < BTN_COUNT);
  407. gAggregatedJoystickState[buttonNum].state |= (bool)state;
  408. }
  409. static void SetJoystickButtonState(int joyNum, int buttonNum, int state)
  410. {
  411. #if !PLATFORM_TVOS
  412. if (state)
  413. {
  414. char buf[128];
  415. sprintf(buf, "joystick %d button %d", joyNum, buttonNum);
  416. int code = UnityStringToKey(buf);
  417. [pressedButtons addObject: [NSNumber numberWithInteger: code]];
  418. UnitySetKeyState(code, state);
  419. }
  420. #else
  421. char buf[128];
  422. sprintf(buf, "joystick %d button %d", joyNum, buttonNum);
  423. UnitySetKeyState(UnityStringToKey(buf), state);
  424. ReportAggregatedJoystickButton(buttonNum, state);
  425. #endif
  426. }
  427. static void ReportJoystickButton(int idx, JoystickButtonNumbers num, GCControllerButtonInput* button)
  428. {
  429. SetJoystickButtonState(idx + 1, num, GetButtonPressed(button));
  430. UnitySetJoystickPosition(idx + 1, num, GetButtonValue(button));
  431. }
  432. template<class ClassXYZ>
  433. static void ReportJoystickXYZAxes(int idx, int xaxis, int yaxis, int zaxis, const ClassXYZ& xyz)
  434. {
  435. UnitySetJoystickPosition(idx + 1, xaxis, xyz.x);
  436. UnitySetJoystickPosition(idx + 1, yaxis, xyz.y);
  437. UnitySetJoystickPosition(idx + 1, zaxis, xyz.z);
  438. }
  439. template<class ClassXYZW>
  440. static void ReportJoystickXYZWAxes(int idx, int xaxis, int yaxis, int zaxis, int waxis,
  441. const ClassXYZW& xyzw)
  442. {
  443. UnitySetJoystickPosition(idx + 1, xaxis, xyzw.x);
  444. UnitySetJoystickPosition(idx + 1, yaxis, xyzw.y);
  445. UnitySetJoystickPosition(idx + 1, zaxis, xyzw.z);
  446. UnitySetJoystickPosition(idx + 1, waxis, xyzw.w);
  447. }
  448. #if PLATFORM_TVOS
  449. static void ReportJoystickMicro(int idx, GCMicroGamepad* gamepad)
  450. {
  451. GCControllerDirectionPad* dpad = [gamepad dpad];
  452. UnitySetJoystickPosition(idx + 1, 0, GetAxisValue([dpad xAxis]));
  453. UnitySetJoystickPosition(idx + 1, 1, -GetAxisValue([dpad yAxis]));
  454. ReportJoystickButton(idx, BTN_DPAD_UP, [dpad up]);
  455. ReportJoystickButton(idx, BTN_DPAD_RIGHT, [dpad right]);
  456. ReportJoystickButton(idx, BTN_DPAD_DOWN, [dpad down]);
  457. ReportJoystickButton(idx, BTN_DPAD_LEFT, [dpad left]);
  458. ReportJoystickButton(idx, BTN_A, [gamepad buttonA]);
  459. ReportJoystickButton(idx, BTN_X, [gamepad buttonX]);
  460. }
  461. #endif
  462. static void ReportJoystickBasic(int idx, GCGamepad* gamepad)
  463. {
  464. GCControllerDirectionPad* dpad = [gamepad dpad];
  465. UnitySetJoystickPosition(idx + 1, 0, GetAxisValue([dpad xAxis]));
  466. UnitySetJoystickPosition(idx + 1, 1, -GetAxisValue([dpad yAxis]));
  467. ReportJoystickButton(idx, BTN_DPAD_UP, [dpad up]);
  468. ReportJoystickButton(idx, BTN_DPAD_RIGHT, [dpad right]);
  469. ReportJoystickButton(idx, BTN_DPAD_DOWN, [dpad down]);
  470. ReportJoystickButton(idx, BTN_DPAD_LEFT, [dpad left]);
  471. ReportJoystickButton(idx, BTN_A, [gamepad buttonA]);
  472. ReportJoystickButton(idx, BTN_B, [gamepad buttonB]);
  473. ReportJoystickButton(idx, BTN_Y, [gamepad buttonY]);
  474. ReportJoystickButton(idx, BTN_X, [gamepad buttonX]);
  475. ReportJoystickButton(idx, BTN_L1, [gamepad leftShoulder]);
  476. ReportJoystickButton(idx, BTN_R1, [gamepad rightShoulder]);
  477. }
  478. static void ReportJoystickExtended(int idx, GCExtendedGamepad* gamepad)
  479. {
  480. GCControllerDirectionPad* dpad = [gamepad dpad];
  481. GCControllerDirectionPad* leftStick = [gamepad leftThumbstick];
  482. GCControllerDirectionPad* rightStick = [gamepad rightThumbstick];
  483. UnitySetJoystickPosition(idx + 1, 0, GetAxisValue([leftStick xAxis]));
  484. UnitySetJoystickPosition(idx + 1, 1, -GetAxisValue([leftStick yAxis]));
  485. UnitySetJoystickPosition(idx + 1, 2, GetAxisValue([rightStick xAxis]));
  486. UnitySetJoystickPosition(idx + 1, 3, -GetAxisValue([rightStick yAxis]));
  487. ReportJoystickButton(idx, BTN_DPAD_UP, [dpad up]);
  488. ReportJoystickButton(idx, BTN_DPAD_RIGHT, [dpad right]);
  489. ReportJoystickButton(idx, BTN_DPAD_DOWN, [dpad down]);
  490. ReportJoystickButton(idx, BTN_DPAD_LEFT, [dpad left]);
  491. ReportJoystickButton(idx, BTN_A, [gamepad buttonA]);
  492. ReportJoystickButton(idx, BTN_B, [gamepad buttonB]);
  493. ReportJoystickButton(idx, BTN_Y, [gamepad buttonY]);
  494. ReportJoystickButton(idx, BTN_X, [gamepad buttonX]);
  495. ReportJoystickButton(idx, BTN_L1, [gamepad leftShoulder]);
  496. ReportJoystickButton(idx, BTN_R1, [gamepad rightShoulder]);
  497. ReportJoystickButton(idx, BTN_L2, [gamepad leftTrigger]);
  498. ReportJoystickButton(idx, BTN_R2, [gamepad rightTrigger]);
  499. if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 12.1)
  500. {
  501. ReportJoystickButton(idx, BTN_L3, [gamepad valueForKey: @"leftThumbstickButton"]);
  502. ReportJoystickButton(idx, BTN_R3, [gamepad valueForKey: @"rightThumbstickButton"]);
  503. }
  504. if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 13.0)
  505. {
  506. ReportJoystickButton(idx, BTN_MENU, [gamepad valueForKey: @"buttonMenu"]);
  507. ReportJoystickButton(idx, BTN_PAUSE, [gamepad valueForKey: @"buttonOptions"]);
  508. }
  509. }
  510. static void SimulateAttitudeViaGravityVector(const Vector3f& gravity, Quaternion4f& currentAttitude, Vector3f& rotationRate)
  511. {
  512. static Quaternion4f lastAttitude = QuatIdentity();
  513. static double lastTime = 0.0;
  514. double currentTime = [NSDate timeIntervalSinceReferenceDate];
  515. double deltaTime = lastTime - currentTime;
  516. currentAttitude = QuatRotationFromTo(gravity, VecMake(0.0f, 0.0f, -1.0f));
  517. rotationRate = VecScale(1.0f / deltaTime, QuatToEuler(QuatDifference(currentAttitude, lastAttitude)));
  518. lastAttitude = currentAttitude;
  519. lastTime = currentTime;
  520. }
  521. // Note that joystick axis numbers in documentation are shifted
  522. // by one. 1st axis is referred to by index 0, 16th by 15, etc.
  523. static void ReportJoystickMotion(int idx, GCMotion* motion)
  524. {
  525. Vector3f rotationRate = VecMake(0.0f, 0.0f, 0.0f);
  526. Quaternion4f attitude = QuatMake(0.0f, 0.0f, 0.0f, 1.0f);
  527. bool gotRotationData = false;
  528. if (@available(iOS 11.0, tvOS 11.0, *))
  529. {
  530. if (motion.hasAttitudeAndRotationRate)
  531. {
  532. rotationRate = {(float)motion.rotationRate.x, (float)motion.rotationRate.y, (float)motion.rotationRate.z};
  533. attitude = {(float)motion.attitude.x, (float)motion.attitude.y, (float)motion.attitude.z, (float)motion.attitude.w};
  534. gotRotationData = true;
  535. }
  536. }
  537. else
  538. {
  539. #if PLATFORM_IOS
  540. // on iOS we assume that rotationRate and attitude is correct, unless
  541. // hasAttitudeAndRotationRate tells us otherwise.
  542. // on tvOS, rotationRate and attitude are unavailable if hasAttitudeAndRotationRate is unavailable.
  543. rotationRate = {(float)motion.rotationRate.x, (float)motion.rotationRate.y, (float)motion.rotationRate.z};
  544. attitude = {(float)motion.attitude.x, (float)motion.attitude.y, (float)motion.attitude.z, (float)motion.attitude.w};
  545. gotRotationData = true;
  546. #endif
  547. }
  548. #if SIMULATE_ATTITUDE_FROM_GRAVITY
  549. if (!gotRotationData)
  550. SimulateAttitudeViaGravityVector(VecMake((float)motion.gravity.x, (float)motion.gravity.y, (float)motion.gravity.z), attitude, rotationRate);
  551. #endif
  552. // From docs:
  553. // gravity (x,y,z) : 16, 17, 18
  554. // user acceleration: 19, 20, 21
  555. // rotation rate: 22, 23, 24
  556. // attitude quaternion (x,y,z,w): 25, 26, 27, 28
  557. ReportJoystickXYZAxes(idx, 15, 16, 17, motion.gravity);
  558. ReportJoystickXYZAxes(idx, 18, 19, 20, motion.userAcceleration);
  559. ReportJoystickXYZAxes(idx, 21, 22, 23, rotationRate);
  560. ReportJoystickXYZWAxes(idx, 24, 25, 26, 27, attitude);
  561. #if PLATFORM_TVOS
  562. if (sGCMotionForwardingEnabled && !sGCMotionForwardedForCurrentFrame)
  563. {
  564. UnitySensorsSetGravity(0, motion.gravity.x, motion.gravity.y, motion.gravity.z);
  565. UnitySensorsSetUserAcceleration(0, motion.userAcceleration.x, motion.userAcceleration.y, motion.userAcceleration.z);
  566. UnitySensorsSetGyroRotationRate(0, rotationRate.y, rotationRate.x, rotationRate.z);
  567. UnitySensorsSetAttitude(0, attitude.x, attitude.y, attitude.z, attitude.w);
  568. UnityDidAccelerate(motion.userAcceleration.x + motion.gravity.x, motion.userAcceleration.y + motion.gravity.y, motion.userAcceleration.z + motion.gravity.z, [[NSDate date] timeIntervalSince1970]);
  569. sGCMotionForwardedForCurrentFrame = true;
  570. }
  571. #endif
  572. }
  573. static void ReportJoystick(GCController* controller, int idx)
  574. {
  575. if (controller.controllerPausedHandler == nil)
  576. controller.controllerPausedHandler = gControllerHandler;
  577. if ([controller extendedGamepad] != nil)
  578. ReportJoystickExtended(idx, [controller extendedGamepad]);
  579. else if ([controller gamepad] != nil)
  580. ReportJoystickBasic(idx, [controller gamepad]);
  581. #if PLATFORM_TVOS
  582. else if ([controller microGamepad] != nil)
  583. ReportJoystickMicro(idx, [controller microGamepad]);
  584. #endif
  585. else
  586. {
  587. // TODO: do something with not supported gamepad profiles
  588. }
  589. if (controller.motion != nil)
  590. ReportJoystickMotion(idx, controller.motion);
  591. // Map pause button
  592. SetJoystickButtonState(idx + 1, BTN_PAUSE, gPausedJoysticks[idx]);
  593. // Reset pause button
  594. gPausedJoysticks[idx] = false;
  595. }
  596. // On tvOS simulator we implement a fake remote as tvOS simulator
  597. // does not support controllers (yet)
  598. #if UNITY_TVOS_SIMULATOR_FAKE_REMOTE
  599. struct FakeRemoteState
  600. {
  601. bool pressedX, pressedA;
  602. bool pressedUp, pressedDown, pressedLeft, pressedRight;
  603. float xAxis, yAxis;
  604. FakeRemoteState() :
  605. pressedX(false),
  606. pressedA(false),
  607. pressedUp(false),
  608. pressedDown(false),
  609. pressedLeft(false),
  610. pressedRight(false),
  611. xAxis(0),
  612. yAxis(0)
  613. {}
  614. };
  615. static FakeRemoteState gFakeRemoteState;
  616. static void ReportFakeRemoteButton(int idx, JoystickButtonNumbers num, bool pressed)
  617. {
  618. SetJoystickButtonState(idx + 1, num, pressed);
  619. UnitySetJoystickPosition(idx + 1, num, pressed);
  620. }
  621. void ReportFakeRemote(int idx)
  622. {
  623. UnitySetJoystickPosition(idx + 1, 0, gFakeRemoteState.xAxis);
  624. UnitySetJoystickPosition(idx + 1, 1, -gFakeRemoteState.yAxis);
  625. ReportFakeRemoteButton(idx, BTN_DPAD_UP, gFakeRemoteState.pressedUp);
  626. ReportFakeRemoteButton(idx, BTN_DPAD_RIGHT, gFakeRemoteState.pressedRight);
  627. ReportFakeRemoteButton(idx, BTN_DPAD_DOWN, gFakeRemoteState.pressedDown);
  628. ReportFakeRemoteButton(idx, BTN_DPAD_LEFT, gFakeRemoteState.pressedLeft);
  629. ReportFakeRemoteButton(idx, BTN_A, gFakeRemoteState.pressedA);
  630. ReportFakeRemoteButton(idx, BTN_X, gFakeRemoteState.pressedX);
  631. }
  632. #endif
  633. extern "C" void UnityUpdateJoystickData()
  634. {
  635. UnityInitJoysticks();
  636. NSArray* list = QueryControllerCollection();
  637. #if PLATFORM_TVOS
  638. sGCMotionForwardedForCurrentFrame = false;
  639. #endif
  640. // Clear aggregated joystick state
  641. ResetAggregatedJoystickState();
  642. if (list != nil)
  643. {
  644. for (int i = 0; i < [list count]; i++)
  645. {
  646. id controller = [list objectAtIndex: i];
  647. ReportJoystick(controller, i);
  648. }
  649. }
  650. #if UNITY_TVOS_SIMULATOR_FAKE_REMOTE
  651. int remoteIndex = list != nil ? (int)[list count] : 0;
  652. ReportFakeRemote(remoteIndex);
  653. #endif
  654. // Report all aggregated joystick button in bulk
  655. SetAggregatedJoystickState();
  656. }
  657. static NSString* FormatJoystickIdentifier(int idx, const char* typeString, const char* attachment, const char* vendorName)
  658. {
  659. return [NSString stringWithFormat: @"[%s,%s] joystick %d by %s", typeString, attachment, idx + 1, vendorName];
  660. }
  661. NSString* GetJoystickName(GCController* controller, int idx)
  662. {
  663. NSString* joystickName;
  664. if (controller != nil)
  665. {
  666. // iOS 8 has bug, which is encountered when controller is being attached
  667. // while app is still running. It creates two instances of controller object:
  668. // one original and one "Forwarded", accesing later properties are causing crashes
  669. const char* attached = "unknown";
  670. // Controller is good one
  671. if ([[controller vendorName] rangeOfString: @"Forwarded"].location == NSNotFound)
  672. attached = (controller.attachedToDevice ? "wired" : "wireless");
  673. const char* typeString = [controller extendedGamepad] != nil ? "extended" : "basic";
  674. joystickName = FormatJoystickIdentifier(idx, typeString, attached, [[controller vendorName] UTF8String]);
  675. }
  676. else
  677. {
  678. #if UNITY_TVOS_SIMULATOR_FAKE_REMOTE
  679. if (idx == [QueryControllerCollection() count])
  680. {
  681. joystickName = FormatJoystickIdentifier(idx, "basic", "wireless", "Unity");
  682. }
  683. #endif
  684. joystickName = @"unknown";
  685. }
  686. return joystickName;
  687. }
  688. extern "C" NSArray* UnityGetJoystickNames()
  689. {
  690. NSArray* joysticks = QueryControllerCollection();
  691. int count = joysticks != nil ? (int)[joysticks count] : 0;
  692. #if UNITY_TVOS_SIMULATOR_FAKE_REMOTE
  693. count++;
  694. #endif
  695. NSMutableArray * joystickNames = [NSMutableArray arrayWithCapacity: count];
  696. for (int i = 0; i < count; i++)
  697. {
  698. [joystickNames addObject: GetJoystickName(joysticks[i], i)];
  699. }
  700. return joystickNames;
  701. }
  702. extern "C" void UnityGetJoystickAxisName(int idx, int axis, char* buffer, int maxLen)
  703. {
  704. }
  705. extern "C" void UnityGetNiceKeyname(int key, char* buffer, int maxLen)
  706. {
  707. }
  708. #pragma clang diagnostic pop
  709. #if UNITY_USES_LOCATION
  710. @interface LocationServiceDelegate : NSObject<CLLocationManagerDelegate>
  711. @end
  712. #endif
  713. extern "C" void
  714. UnitySetLastLocation(double timestamp,
  715. float latitude,
  716. float longitude,
  717. float altitude,
  718. float horizontalAccuracy,
  719. float verticalAccuracy);
  720. extern "C" void
  721. UnitySetLastHeading(float magneticHeading,
  722. float trueHeading,
  723. float rawX, float rawY, float rawZ,
  724. double timestamp);
  725. #if UNITY_USES_LOCATION
  726. struct LocationServiceInfo
  727. {
  728. private:
  729. LocationServiceDelegate* delegate;
  730. CLLocationManager* locationManager;
  731. public:
  732. LocationServiceStatus locationStatus;
  733. LocationServiceStatus headingStatus;
  734. float desiredAccuracy;
  735. float distanceFilter;
  736. LocationServiceInfo();
  737. CLLocationManager* GetLocationManager();
  738. };
  739. LocationServiceInfo::LocationServiceInfo()
  740. {
  741. locationStatus = kLocationServiceStopped;
  742. desiredAccuracy = kCLLocationAccuracyKilometer;
  743. distanceFilter = 500;
  744. headingStatus = kLocationServiceStopped;
  745. }
  746. static LocationServiceInfo gLocationServiceStatus;
  747. CLLocationManager* LocationServiceInfo::GetLocationManager()
  748. {
  749. if (locationManager == nil)
  750. {
  751. locationManager = [[CLLocationManager alloc] init];
  752. delegate = [LocationServiceDelegate alloc];
  753. locationManager.delegate = delegate;
  754. }
  755. return locationManager;
  756. }
  757. #endif
  758. bool LocationService::IsServiceEnabledByUser()
  759. {
  760. #if UNITY_USES_LOCATION
  761. return [CLLocationManager locationServicesEnabled];
  762. #else
  763. return false;
  764. #endif
  765. }
  766. void LocationService::SetDesiredAccuracy(float val)
  767. {
  768. #if UNITY_USES_LOCATION
  769. gLocationServiceStatus.desiredAccuracy = val;
  770. #endif
  771. }
  772. float LocationService::GetDesiredAccuracy()
  773. {
  774. #if UNITY_USES_LOCATION
  775. return gLocationServiceStatus.desiredAccuracy;
  776. #else
  777. return NAN;
  778. #endif
  779. }
  780. void LocationService::SetDistanceFilter(float val)
  781. {
  782. #if UNITY_USES_LOCATION
  783. gLocationServiceStatus.distanceFilter = val;
  784. #endif
  785. }
  786. float LocationService::GetDistanceFilter()
  787. {
  788. #if UNITY_USES_LOCATION
  789. return gLocationServiceStatus.distanceFilter;
  790. #else
  791. return NAN;
  792. #endif
  793. }
  794. void LocationService::StartUpdatingLocation()
  795. {
  796. #if UNITY_USES_LOCATION
  797. if (gLocationServiceStatus.locationStatus != kLocationServiceRunning)
  798. {
  799. CLLocationManager* locationManager = gLocationServiceStatus.GetLocationManager();
  800. [locationManager requestWhenInUseAuthorization];
  801. locationManager.desiredAccuracy = gLocationServiceStatus.desiredAccuracy;
  802. // Set a movement threshold for new events
  803. locationManager.distanceFilter = gLocationServiceStatus.distanceFilter;
  804. #if PLATFORM_IOS
  805. [locationManager startUpdatingLocation];
  806. #else
  807. [locationManager requestLocation];
  808. #endif
  809. gLocationServiceStatus.locationStatus = kLocationServiceInitializing;
  810. }
  811. #endif
  812. }
  813. void LocationService::StopUpdatingLocation()
  814. {
  815. #if UNITY_USES_LOCATION
  816. if (gLocationServiceStatus.locationStatus != kLocationServiceStopped)
  817. {
  818. [gLocationServiceStatus.GetLocationManager() stopUpdatingLocation];
  819. gLocationServiceStatus.locationStatus = kLocationServiceStopped;
  820. }
  821. #endif
  822. }
  823. void LocationService::SetHeadingUpdatesEnabled(bool enabled)
  824. {
  825. #if PLATFORM_IOS && UNITY_USES_LOCATION
  826. if (enabled)
  827. {
  828. if (gLocationServiceStatus.headingStatus != kLocationServiceRunning &&
  829. IsHeadingAvailable())
  830. {
  831. CLLocationManager* locationManager = gLocationServiceStatus.GetLocationManager();
  832. [locationManager startUpdatingHeading];
  833. gLocationServiceStatus.headingStatus = kLocationServiceInitializing;
  834. }
  835. }
  836. else
  837. {
  838. if (gLocationServiceStatus.headingStatus != kLocationServiceStopped)
  839. {
  840. [gLocationServiceStatus.GetLocationManager() stopUpdatingHeading];
  841. gLocationServiceStatus.headingStatus = kLocationServiceStopped;
  842. }
  843. }
  844. #endif
  845. }
  846. bool LocationService::IsHeadingUpdatesEnabled()
  847. {
  848. #if UNITY_USES_LOCATION
  849. return (gLocationServiceStatus.headingStatus == kLocationServiceRunning);
  850. #else
  851. return false;
  852. #endif
  853. }
  854. LocationServiceStatus LocationService::GetLocationStatus()
  855. {
  856. #if UNITY_USES_LOCATION
  857. return (LocationServiceStatus)gLocationServiceStatus.locationStatus;
  858. #else
  859. return kLocationServiceFailed;
  860. #endif
  861. }
  862. LocationServiceStatus LocationService::GetHeadingStatus()
  863. {
  864. #if UNITY_USES_LOCATION
  865. return (LocationServiceStatus)gLocationServiceStatus.headingStatus;
  866. #else
  867. return kLocationServiceFailed;
  868. #endif
  869. }
  870. bool LocationService::IsHeadingAvailable()
  871. {
  872. #if PLATFORM_IOS && UNITY_USES_LOCATION
  873. return [CLLocationManager headingAvailable];
  874. #else
  875. return false;
  876. #endif
  877. }
  878. #if UNITY_USES_LOCATION
  879. @implementation LocationServiceDelegate
  880. - (void)locationManager:(CLLocationManager*)manager didUpdateLocations:(NSArray*)locations
  881. {
  882. CLLocation* lastLocation = locations.lastObject;
  883. gLocationServiceStatus.locationStatus = kLocationServiceRunning;
  884. UnitySetLastLocation([lastLocation.timestamp timeIntervalSince1970],
  885. lastLocation.coordinate.latitude, lastLocation.coordinate.longitude, lastLocation.altitude,
  886. lastLocation.horizontalAccuracy, lastLocation.verticalAccuracy
  887. );
  888. }
  889. #if PLATFORM_IOS
  890. - (void)locationManager:(CLLocationManager*)manager didUpdateHeading:(CLHeading*)newHeading
  891. {
  892. gLocationServiceStatus.headingStatus = kLocationServiceRunning;
  893. Vector3f reorientedRawHeading = UnityReorientVector3(newHeading.x, newHeading.y, newHeading.z);
  894. UnitySetLastHeading(UnityReorientHeading(newHeading.magneticHeading),
  895. UnityReorientHeading(newHeading.trueHeading),
  896. reorientedRawHeading.x, reorientedRawHeading.y, reorientedRawHeading.z,
  897. [newHeading.timestamp timeIntervalSince1970]);
  898. }
  899. #endif
  900. - (BOOL)locationManagerShouldDisplayHeadingCalibration:(CLLocationManager*)manager
  901. {
  902. return NO;
  903. }
  904. - (void)locationManager:(CLLocationManager*)manager didFailWithError:(NSError*)error;
  905. {
  906. gLocationServiceStatus.locationStatus = kLocationServiceFailed;
  907. gLocationServiceStatus.headingStatus = kLocationServiceFailed;
  908. }
  909. @end
  910. #endif
  911. #if PLATFORM_TVOS
  912. GCMicroGamepad* QueryMicroController()
  913. {
  914. NSArray* list = QueryControllerCollection();
  915. for (GCController* controller in list)
  916. {
  917. if (controller.microGamepad != nil)
  918. return controller.microGamepad;
  919. }
  920. return nil;
  921. }
  922. extern "C" int UnityGetAppleTVRemoteTouchesEnabled()
  923. {
  924. return gTVRemoteTouchesEnabled;
  925. }
  926. extern "C" void UnitySetAppleTVRemoteTouchesEnabled(int val)
  927. {
  928. gTVRemoteTouchesEnabled = val;
  929. }
  930. extern "C" int UnityGetAppleTVRemoteAllowExitToMenu()
  931. {
  932. return ((GCEventViewController*)UnityGetGLViewController()).controllerUserInteractionEnabled;
  933. }
  934. extern "C" void UnitySetAppleTVRemoteAllowExitToMenu(int val)
  935. {
  936. ((GCEventViewController*)UnityGetGLViewController()).controllerUserInteractionEnabled = val;
  937. }
  938. extern "C" int UnityGetAppleTVRemoteAllowRotation()
  939. {
  940. GCMicroGamepad* controller = QueryMicroController();
  941. if (controller != nil)
  942. return controller.allowsRotation;
  943. else
  944. return false;
  945. }
  946. extern "C" void UnitySetAppleTVRemoteAllowRotation(int val)
  947. {
  948. GCMicroGamepad* controller = QueryMicroController();
  949. if (controller != nil)
  950. controller.allowsRotation = val;
  951. else
  952. gTVRemoteAllowRotationInitialValue = val;
  953. }
  954. extern "C" int UnityGetAppleTVRemoteReportAbsoluteDpadValues()
  955. {
  956. GCMicroGamepad* controller = QueryMicroController();
  957. if (controller != nil)
  958. return controller.reportsAbsoluteDpadValues;
  959. else
  960. return false;
  961. }
  962. extern "C" void UnitySetAppleTVRemoteReportAbsoluteDpadValues(int val)
  963. {
  964. NSArray* list = QueryControllerCollection();
  965. for (GCController* controller in list)
  966. {
  967. if (controller.microGamepad != nil)
  968. controller.microGamepad.reportsAbsoluteDpadValues = val;
  969. else
  970. gTVRemoteReportsAbsoluteDpadValuesInitialValue = val;
  971. }
  972. }
  973. #endif
  974. #if UNITY_TVOS_SIMULATOR_FAKE_REMOTE
  975. static void FakeRemoteStateSetButton(UIPressType type, bool state)
  976. {
  977. switch (type)
  978. {
  979. case UIPressTypeUpArrow: gFakeRemoteState.pressedUp = state; return;
  980. case UIPressTypeDownArrow: gFakeRemoteState.pressedDown = state; return;
  981. case UIPressTypeLeftArrow: gFakeRemoteState.pressedLeft = state; return;
  982. case UIPressTypeRightArrow: gFakeRemoteState.pressedRight = state; return;
  983. case UIPressTypeSelect: gFakeRemoteState.pressedA = state; return;
  984. case UIPressTypePlayPause: gFakeRemoteState.pressedX = state; return;
  985. }
  986. }
  987. void ReportSimulatedRemoteButtonPress(UIPressType type)
  988. {
  989. FakeRemoteStateSetButton(type, true);
  990. }
  991. void ReportSimulatedRemoteButtonRelease(UIPressType type)
  992. {
  993. FakeRemoteStateSetButton(type, false);
  994. }
  995. static float FakeRemoteMapTouchToAxis(float pos, float bounds)
  996. {
  997. float halfRange = bounds / 2;
  998. return (pos - halfRange) / halfRange;
  999. }
  1000. void ReportSimulatedRemoteTouchesBegan(UIView* view, NSSet* touches)
  1001. {
  1002. ReportSimulatedRemoteTouchesMoved(view, touches);
  1003. }
  1004. void ReportSimulatedRemoteTouchesMoved(UIView* view, NSSet* touches)
  1005. {
  1006. for (UITouch* touch in touches)
  1007. {
  1008. gFakeRemoteState.xAxis = FakeRemoteMapTouchToAxis([touch locationInView: view].x, view.bounds.size.width);
  1009. gFakeRemoteState.yAxis = FakeRemoteMapTouchToAxis([touch locationInView: view].y, view.bounds.size.height);
  1010. // We assume that at most single touch is received.
  1011. break;
  1012. }
  1013. }
  1014. void ReportSimulatedRemoteTouchesEnded(UIView* view, NSSet* touches)
  1015. {
  1016. gFakeRemoteState.xAxis = 0;
  1017. gFakeRemoteState.yAxis = 0;
  1018. }
  1019. #endif