/******************************************************************************/ #include "stdafx.h" namespace EE{ /******************************************************************************/ #if !IS_POW_2(INPUT_COMBO_NUM) #error INPUT_COMBO_NUM must be a power of 2 #endif /******************************************************************************/ #if ANDROID ASensorEventQueue *SensorEventQueue; #elif IOS CLLocationManager *LocationManager[2]; CMMotionManager *CoreMotionMgr; #endif Vec AccelerometerValue, GyroscopeValue, MagnetometerValue; Bool LocationBackground[2]; Dbl LocationLat[2], LocationLon[2]; Flt LocationAlt[2], LocationAcc[2], LocationSpd[2], LocationInterval[2]={-1, -1}, MagnetometerInterval=-1; DateTime LocationTim[2]; InputComboClass InputCombo; InputDevicesClass InputDevices; /******************************************************************************/ // ACCELEROMETER, GYROSCOPE, MAGNETOMETER, LOCATION /******************************************************************************/ C Vec& Accelerometer() {return AccelerometerValue;} C Vec& Gyroscope () {return GyroscopeValue;} C Vec& Magnetometer () {return MagnetometerValue;} Dbl LocationLatitude (Bool gps) {return LocationLat[gps];} Dbl LocationLongitude(Bool gps) {return LocationLon[gps];} Flt LocationAltitude (Bool gps) {return LocationAlt[gps];} Flt LocationAccuracy (Bool gps) {return LocationAcc[gps];} Flt LocationSpeed (Bool gps) {return LocationSpd[gps];} C DateTime& LocationTimeUTC (Bool gps) {return LocationTim[gps];} /******************************************************************************/ #if !WINDOWS_NEW void SetMagnetometerRefresh(Flt interval) { #if ANDROID if(SensorEventQueue) if(ASensorManager *sensor_manager=ASensorManager_getInstance()) if(C ASensor *magnetometer=ASensorManager_getDefaultSensor(sensor_manager, ASENSOR_TYPE_MAGNETIC_FIELD)) { if(interval>=0) // enable { ASensorEventQueue_setEventRate (SensorEventQueue, magnetometer, RoundU(interval*1000000)); ASensorEventQueue_enableSensor (SensorEventQueue, magnetometer); }else ASensorEventQueue_disableSensor(SensorEventQueue, magnetometer); // disable } #elif IOS const Bool gps=true; if(CLLocationManager *lm=LocationManager[gps]) if(interval>=0 && [CLLocationManager headingAvailable]) { [lm startUpdatingHeading]; }else { [lm stopUpdatingHeading]; } #endif } #endif /******************************************************************************/ void SetLocationRefresh(Flt interval, Bool gps) { #if ANDROID JNI jni; if(jni && EsenthelLocationListener[gps]) { if(interval>=0) // enable { RequirePermission(PERMISSION_LOCATION); ULong min_time=RoundU(interval*1000); jni->CallVoidMethod(LocationManager, requestLocationUpdates, gps ? GPS_PROVIDER() : NETWORK_PROVIDER(), min_time, 0.0f, EsenthelLocationListener[gps]()); }else // disable { jni->CallVoidMethod(LocationManager, removeUpdates, EsenthelLocationListener[gps]()); } if(jni->ExceptionCheck()) { #if DEBUG jni->ExceptionDescribe(); #endif jni->ExceptionClear(); } } #elif IOS if(CLLocationManager *lm=LocationManager[gps]) if(interval>=0 && [CLLocationManager locationServicesEnabled]) { if(LocationBackground[gps]){if([lm respondsToSelector:@selector(requestAlwaysAuthorization )])[lm requestAlwaysAuthorization ];} else {if([lm respondsToSelector:@selector(requestWhenInUseAuthorization)])[lm requestWhenInUseAuthorization];} if(gps)[lm startUpdatingLocation]; else [lm startMonitoringSignificantLocationChanges]; }else { if(gps)[lm stopUpdatingLocation]; else [lm stopMonitoringSignificantLocationChanges]; } #endif } /******************************************************************************/ void MagnetometerRefresh(Flt interval) {MAX(interval, 0); if(!Equal(MagnetometerInterval, interval))SetMagnetometerRefresh(MagnetometerInterval=interval);} void MagnetometerDisable( ) { if(!Equal(MagnetometerInterval, -1))SetMagnetometerRefresh(MagnetometerInterval= -1);} void LocationRefresh(Flt interval, Bool gps, Bool background) {MAX(interval, 0); if(!Equal(LocationInterval[gps], interval) || LocationBackground[gps]!=background){LocationBackground[gps]=background; SetLocationRefresh(LocationInterval[gps]=interval, gps);}} void LocationDisable( Bool gps ) { if(!Equal(LocationInterval[gps], -1) ) SetLocationRefresh(LocationInterval[gps]= -1, gps); } LOCATION_AUTHORIZATION_STATUS LocationAuthorizationStatus() { #if ANDROID return HasPermission(PERMISSION_LOCATION) ? LAS_BACKGROUND : LAS_DENIED; #elif IOS switch([CLLocationManager authorizationStatus]) { case kCLAuthorizationStatusRestricted : return LAS_RESTRICTED; case kCLAuthorizationStatusDenied : return LAS_DENIED; case kCLAuthorizationStatusAuthorizedWhenInUse: return LAS_FOREGROUND; case kCLAuthorizationStatusAuthorizedAlways : return LAS_BACKGROUND; } #endif return LAS_UNKNOWN; } /******************************************************************************/ #if ANDROID static ULong LocationTime[2]; void UpdateLocation(jobject location, Bool gps, JNI &jni) { if(location && jni && getTime) { ULong time=jni->CallLongMethod(location, getTime); // milliseconds since 1st Jan 1970 if(time!=LocationTime[gps]) { LocationTim[gps].from1970ms(LocationTime[gps]=time); LocationLat[gps]=jni->CallDoubleMethod(location, getLatitude ); LocationLon[gps]=jni->CallDoubleMethod(location, getLongitude); LocationAlt[gps]=jni->CallDoubleMethod(location, getAltitude ); LocationAcc[gps]=jni->CallFloatMethod (location, getAccuracy ); LocationSpd[gps]=jni->CallFloatMethod (location, getSpeed ); } } } void UpdateLocation(Bool gps, JNI &jni) { if(jni && getLastKnownLocation) { JObject location=JObject(jni, jni->CallObjectMethod(LocationManager, getLastKnownLocation, gps ? GPS_PROVIDER() : NETWORK_PROVIDER())); if(jni->ExceptionCheck()) { #if DEBUG jni->ExceptionDescribe(); #endif location.clear(); jni->ExceptionClear(); } UpdateLocation(location, gps, jni); } } void UpdateLocation(JNI &jni) { REP(2)UpdateLocation(i!=0, jni); } #endif /******************************************************************************/ // INPUT BUTTON /******************************************************************************/ Bool InputButton::on()C { switch(type) { case INPUT_KEYBOARD: return Kb .b(KB_KEY(button)); case INPUT_MOUSE : return Ms .b( button ); case INPUT_JOYPAD : return InRange(device, Joypads) ? Joypads[device].b( button ) : false; } return false; } Bool InputButton::pd()C { switch(type) { case INPUT_KEYBOARD: return Kb .bp(KB_KEY(button)); case INPUT_MOUSE : return Ms .bp( button ); case INPUT_JOYPAD : return InRange(device, Joypads) ? Joypads[device].bp( button ) : false; } return false; } Bool InputButton::rs()C { switch(type) { case INPUT_KEYBOARD: return Kb .br(KB_KEY(button)); case INPUT_MOUSE : return Ms .br( button ); case INPUT_JOYPAD : return InRange(device, Joypads) ? Joypads[device].br( button ) : false; } return false; } Bool InputButton::db()C { switch(type) { case INPUT_KEYBOARD: return Kb .bd(KB_KEY(button)); case INPUT_MOUSE : return Ms .bd( button ); case INPUT_JOYPAD : return InRange(device, Joypads) ? Joypads[device].bd( button ) : false; } return false; } Str InputButton::name()C { switch(type) { case INPUT_KEYBOARD: return Kb . keyName(KB_KEY(button)); case INPUT_MOUSE : return Ms .buttonName( button ); case INPUT_JOYPAD : return InRange(device, Joypads) ? Joypads[device].buttonName( button ) : S; default : return S; } } Bool InputButton::operator==(C InputButton &b)C { return T.button==b.button && T.type ==b.type && T.device==b.device; } Bool InputButton::operator!=(C InputButton &b)C { return T.button!=b.button || T.type !=b.type || T.device!=b.device; } /******************************************************************************/ // INPUT /******************************************************************************/ Bool Input::on()C {return b[0].on() || b[1].on() || b[2].on();} Bool Input::pd()C {return b[0].pd() || b[1].pd() || b[2].pd();} Bool Input::rs()C {return b[0].rs() || b[1].rs() || b[2].rs();} Bool Input::db()C {return b[0].db() || b[1].db() || b[2].db();} void Input::set(C Str &name, UInt group) { T.name =name ; T.group=group; } void Input::set(C Str &name, UInt group, C InputButton &b0, C InputButton *b1, C InputButton *b2) { T.name =name ; T.group=group; b[0]= b0; if(b1)b[1]=*b1;else Zero(b[1]); if(b2)b[2]=*b2;else Zero(b[2]); } Bool Input::operator()(C InputButton &b)C { return T.b[0]==b || T.b[1]==b || T.b[2]==b; } /******************************************************************************/ // INPUT COMBO /******************************************************************************/ #define INPUT_COMBO_AND (INPUT_COMBO_NUM-1) InputComboClass::InputComboClass() { dt=0.22f; } void InputComboClass::clear() { pos=length=0; } void InputComboClass::add(C InputButton &inp_btn) { t[pos]=Time.appTime(); b[pos]=inp_btn; pos =((pos+1)&INPUT_COMBO_AND); length=Min(length+1, Elms(b)); } Bool InputComboClass::operator()(C Input &i0, C Input &i1)C { if(length>=2) { Byte p1=((pos-1)&INPUT_COMBO_AND), p0=((pos-2)&INPUT_COMBO_AND); return i1(b[p1]) && (Time.appTime()-t[p1]