From 8f0b8f356edf441b9b21dd7e06d81bcba70a4bb3 Mon Sep 17 00:00:00 2001 From: Josh Tynjala Date: Fri, 8 Nov 2024 16:16:59 -0800 Subject: [PATCH] Application: onDisplayOrientation and onDeviceOrientation events for iOS and Android Device orientation is the orientation of the phone/tablet. Display orientation is the orientation of what is rendered on the display. By default, they should usually be the same. If orientation is locked, device orientation will update, but display orientation usually won't. --- project/Build.xml | 1 + project/include/system/OrientationEvent.h | 40 +++++ project/include/system/System.h | 2 + project/src/ExternalInterface.cpp | 37 ++++ project/src/backend/sdl/SDLApplication.cpp | 20 +++ project/src/backend/sdl/SDLApplication.h | 2 + project/src/backend/sdl/SDLSystem.cpp | 9 + project/src/system/OrientationEvent.cpp | 64 +++++++ project/src/system/System.cpp | 9 + project/src/system/System.mm | 163 ++++++++++++++++++ .../backend/native/NativeApplication.hx | 90 +++++++++- .../_internal/backend/native/NativeCFFI.hx | 18 ++ src/lime/app/Application.hx | 32 +++- src/lime/system/Display.hx | 5 + src/lime/system/Orientation.hx | 10 ++ src/lime/system/System.hx | 1 + .../main/java/org/haxe/lime/GameActivity.java | 52 ++++++ 17 files changed, 549 insertions(+), 6 deletions(-) create mode 100644 project/include/system/OrientationEvent.h create mode 100644 project/src/system/OrientationEvent.cpp create mode 100644 src/lime/system/Orientation.hx diff --git a/project/Build.xml b/project/Build.xml index 7fe7c97f2..72301b0fa 100755 --- a/project/Build.xml +++ b/project/Build.xml @@ -319,6 +319,7 @@ + diff --git a/project/include/system/OrientationEvent.h b/project/include/system/OrientationEvent.h new file mode 100644 index 000000000..09b078159 --- /dev/null +++ b/project/include/system/OrientationEvent.h @@ -0,0 +1,40 @@ +#ifndef LIME_SYSTEM_ORIENTATION_EVENT_H +#define LIME_SYSTEM_ORIENTATION_EVENT_H + + +#include +#include + + +namespace lime { + + + enum OrientationEventType { + + DISPLAY_ORIENTATION_CHANGE, + DEVICE_ORIENTATION_CHANGE + + }; + + + struct OrientationEvent { + + hl_type* t; + int orientation; + int display; + OrientationEventType type; + + static ValuePointer* callback; + static ValuePointer* eventObject; + + OrientationEvent (); + + static void Dispatch (OrientationEvent* event); + + }; + + +} + + +#endif \ No newline at end of file diff --git a/project/include/system/System.h b/project/include/system/System.h index ec67cdd16..63abfd4bb 100644 --- a/project/include/system/System.h +++ b/project/include/system/System.h @@ -40,6 +40,7 @@ namespace lime { static bool GetIOSTablet (); #endif static int GetNumDisplays (); + static int GetDeviceOrientation (); static std::wstring* GetPlatformLabel (); static std::wstring* GetPlatformName (); static std::wstring* GetPlatformVersion (); @@ -53,6 +54,7 @@ namespace lime { #if defined(HX_WINDOWS) && !defined (HX_WINRT) static bool SetWindowsConsoleMode (int handleType, int mode); #endif + static void EnableDeviceOrientationChange(bool enable); private: diff --git a/project/src/ExternalInterface.cpp b/project/src/ExternalInterface.cpp index 1718f4aa0..bc24680d1 100644 --- a/project/src/ExternalInterface.cpp +++ b/project/src/ExternalInterface.cpp @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -2594,6 +2595,23 @@ namespace lime { } + void lime_orientation_event_manager_register (value callback, value eventObject) { + + OrientationEvent::callback = new ValuePointer (callback); + OrientationEvent::eventObject = new ValuePointer (eventObject); + System::EnableDeviceOrientationChange(true); + + } + + + HL_PRIM void HL_NAME(hl_orientation_event_manager_register) (vclosure* callback, OrientationEvent* eventObject) { + + OrientationEvent::callback = new ValuePointer (callback); + OrientationEvent::eventObject = new ValuePointer ((vobj*)eventObject); + + } + + value lime_png_decode_bytes (value data, bool decodeData, value buffer) { ImageBuffer imageBuffer (buffer); @@ -2881,6 +2899,20 @@ namespace lime { } + int lime_system_get_device_orientation () { + + return System::GetDeviceOrientation(); + + } + + + HL_PRIM int HL_NAME(hl_system_get_device_orientation) () { + + return System::GetDeviceOrientation(); + + } + + value lime_system_get_platform_label () { std::wstring* label = System::GetPlatformLabel (); @@ -4017,6 +4049,7 @@ namespace lime { DEFINE_PRIME2 (lime_lzma_decompress); DEFINE_PRIME2v (lime_mouse_event_manager_register); DEFINE_PRIME1v (lime_neko_execute); + DEFINE_PRIME2v (lime_orientation_event_manager_register); DEFINE_PRIME3 (lime_png_decode_bytes); DEFINE_PRIME3 (lime_png_decode_file); DEFINE_PRIME2v (lime_render_event_manager_register); @@ -4028,6 +4061,7 @@ namespace lime { DEFINE_PRIME1 (lime_system_get_display); DEFINE_PRIME0 (lime_system_get_ios_tablet); DEFINE_PRIME0 (lime_system_get_num_displays); + DEFINE_PRIME0 (lime_system_get_device_orientation); DEFINE_PRIME0 (lime_system_get_platform_label); DEFINE_PRIME0 (lime_system_get_platform_name); DEFINE_PRIME0 (lime_system_get_platform_version); @@ -4097,6 +4131,7 @@ namespace lime { #define _TJOYSTICK_EVENT _OBJ (_I32 _I32 _I32 _I32 _F64 _F64) #define _TKEY_EVENT _OBJ (_F64 _I32 _I32 _I32) #define _TMOUSE_EVENT _OBJ (_I32 _F64 _F64 _I32 _I32 _F64 _F64 _I32) + #define _TORIENTATION_EVENT _OBJ (_I32 _I32) #define _TRECTANGLE _OBJ (_F64 _F64 _F64 _F64) #define _TRENDER_EVENT _OBJ (_I32) #define _TSENSOR_EVENT _OBJ (_I32 _F64 _F64 _F64 _I32) @@ -4205,6 +4240,7 @@ namespace lime { DEFINE_HL_PRIM (_TBYTES, hl_lzma_decompress, _TBYTES _TBYTES); DEFINE_HL_PRIM (_VOID, hl_mouse_event_manager_register, _FUN (_VOID, _NO_ARG) _TMOUSE_EVENT); // DEFINE_PRIME1v (lime_neko_execute); + DEFINE_HL_PRIM (_VOID, hl_orientation_event_manager_register, _FUN (_VOID, _NO_ARG) _TORIENTATION_EVENT); DEFINE_HL_PRIM (_TIMAGEBUFFER, hl_png_decode_bytes, _TBYTES _BOOL _TIMAGEBUFFER); DEFINE_HL_PRIM (_TIMAGEBUFFER, hl_png_decode_file, _STRING _BOOL _TIMAGEBUFFER); DEFINE_HL_PRIM (_VOID, hl_render_event_manager_register, _FUN (_VOID, _NO_ARG) _TRENDER_EVENT); @@ -4216,6 +4252,7 @@ namespace lime { DEFINE_HL_PRIM (_DYN, hl_system_get_display, _I32); DEFINE_HL_PRIM (_BOOL, hl_system_get_ios_tablet, _NO_ARG); DEFINE_HL_PRIM (_I32, hl_system_get_num_displays, _NO_ARG); + DEFINE_HL_PRIM (_I32, hl_system_get_device_orientation, _NO_ARG); DEFINE_HL_PRIM (_BYTES, hl_system_get_platform_label, _NO_ARG); DEFINE_HL_PRIM (_BYTES, hl_system_get_platform_name, _NO_ARG); DEFINE_HL_PRIM (_BYTES, hl_system_get_platform_version, _NO_ARG); diff --git a/project/src/backend/sdl/SDLApplication.cpp b/project/src/backend/sdl/SDLApplication.cpp index 53674f53a..6d355ba8e 100644 --- a/project/src/backend/sdl/SDLApplication.cpp +++ b/project/src/backend/sdl/SDLApplication.cpp @@ -53,6 +53,7 @@ namespace lime { JoystickEvent joystickEvent; KeyEvent keyEvent; MouseEvent mouseEvent; + OrientationEvent orientationEvent; RenderEvent renderEvent; SensorEvent sensorEvent; TextEvent textEvent; @@ -183,6 +184,25 @@ namespace lime { ProcessGamepadEvent (event); break; + case SDL_DISPLAYEVENT: + + switch (event->display.event) { + + case SDL_DISPLAYEVENT_ORIENTATION: + + // this is the orientation of what is rendered, which + // may not exactly match the orientation of the device, + // if the app was locked to portrait or landscape. + orientationEvent.type = DISPLAY_ORIENTATION_CHANGE; + orientationEvent.orientation = event->display.data1; + orientationEvent.display = event->display.display; + OrientationEvent::Dispatch (&orientationEvent); + + break; + + } + break; + case SDL_DROPFILE: ProcessDropEvent (event); diff --git a/project/src/backend/sdl/SDLApplication.h b/project/src/backend/sdl/SDLApplication.h index 85d2930f2..1ac1fdf74 100644 --- a/project/src/backend/sdl/SDLApplication.h +++ b/project/src/backend/sdl/SDLApplication.h @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include @@ -69,6 +70,7 @@ namespace lime { Uint32 lastUpdate; MouseEvent mouseEvent; Uint32 nextUpdate; + OrientationEvent orientationEvent; RenderEvent renderEvent; SensorEvent sensorEvent; TextEvent textEvent; diff --git a/project/src/backend/sdl/SDLSystem.cpp b/project/src/backend/sdl/SDLSystem.cpp index 058f2d3dd..4c5fe09a1 100644 --- a/project/src/backend/sdl/SDLSystem.cpp +++ b/project/src/backend/sdl/SDLSystem.cpp @@ -52,6 +52,7 @@ namespace lime { static int id_dpi; static int id_height; static int id_name; + static int id_orientation; static int id_pixelFormat; static int id_refreshRate; static int id_supportedModes; @@ -306,6 +307,7 @@ namespace lime { id_dpi = val_id ("dpi"); id_height = val_id ("height"); id_name = val_id ("name"); + id_orientation = val_id ("orientation"); id_pixelFormat = val_id ("pixelFormat"); id_refreshRate = val_id ("refreshRate"); id_supportedModes = val_id ("supportedModes"); @@ -335,6 +337,9 @@ namespace lime { #endif alloc_field (display, id_dpi, alloc_float (dpi)); + SDL_DisplayOrientation orientation = SDL_GetDisplayOrientation(id); + alloc_field (display, id_orientation, alloc_int (orientation)); + SDL_DisplayMode displayMode = { SDL_PIXELFORMAT_UNKNOWN, 0, 0, 0, 0 }; DisplayMode mode; @@ -411,6 +416,7 @@ namespace lime { const int id_dpi = hl_hash_utf8 ("dpi"); const int id_height = hl_hash_utf8 ("height"); const int id_name = hl_hash_utf8 ("name"); + const int id_orientation = hl_hash_utf8 ("orientation"); const int id_pixelFormat = hl_hash_utf8 ("pixelFormat"); const int id_refreshRate = hl_hash_utf8 ("refreshRate"); const int id_supportedModes = hl_hash_utf8 ("supportedModes"); @@ -450,6 +456,9 @@ namespace lime { #endif hl_dyn_setf (display, id_dpi, dpi); + SDL_DisplayOrientation orientation = SDL_GetDisplayOrientation(id); + hl_dyn_seti (display, id_orientation, &hlt_i32, orientation); + SDL_DisplayMode displayMode = { SDL_PIXELFORMAT_UNKNOWN, 0, 0, 0, 0 }; DisplayMode mode; diff --git a/project/src/system/OrientationEvent.cpp b/project/src/system/OrientationEvent.cpp new file mode 100644 index 000000000..a2cdee3cc --- /dev/null +++ b/project/src/system/OrientationEvent.cpp @@ -0,0 +1,64 @@ +#include +#include + + +namespace lime { + + + ValuePointer* OrientationEvent::callback = 0; + ValuePointer* OrientationEvent::eventObject = 0; + + static int id_type; + static int id_orientation; + static int id_display; + static bool init = false; + + + OrientationEvent::OrientationEvent () { + + orientation = 0; // SDL_ORIENTATION_UNKNOWN + display = 0; + type = DISPLAY_ORIENTATION_CHANGE; + + } + + + void OrientationEvent::Dispatch (OrientationEvent* event) { + + if (OrientationEvent::callback) { + + if (OrientationEvent::eventObject->IsCFFIValue ()) { + + if (!init) { + + id_orientation = val_id ("orientation"); + id_display = val_id ("display"); + id_type = val_id ("type"); + init = true; + + } + + value object = (value)OrientationEvent::eventObject->Get (); + + alloc_field (object, id_orientation, alloc_int (event->orientation)); + alloc_field (object, id_display, alloc_int (event->display)); + alloc_field (object, id_type, alloc_int (event->type)); + + } else { + + OrientationEvent* eventObject = (OrientationEvent*)OrientationEvent::eventObject->Get (); + + eventObject->orientation = event->orientation; + eventObject->display = event->display; + eventObject->type = event->type; + + } + + OrientationEvent::callback->Call (); + + } + + } + + +} \ No newline at end of file diff --git a/project/src/system/System.cpp b/project/src/system/System.cpp index 4399f399c..0c88fb66e 100644 --- a/project/src/system/System.cpp +++ b/project/src/system/System.cpp @@ -246,6 +246,15 @@ namespace lime { } #endif + int System::GetDeviceOrientation () { + + return 0; // SDL_ORIENTATION_UNKNOWN + + } + + void System::EnableDeviceOrientationChange (bool enable) { + + } } diff --git a/project/src/system/System.mm b/project/src/system/System.mm index 7336c499c..53669c61c 100644 --- a/project/src/system/System.mm +++ b/project/src/system/System.mm @@ -4,10 +4,112 @@ #import #include +#include +#ifdef IPHONE +@interface OrientationObserver: NSObject +- (id) init; +- (void) dealloc; +- (void) dispatchEventForDevice:(UIDevice *) device; +- (void) orientationChanged:(NSNotification *) notification; +@end + +@implementation OrientationObserver { +} + +- (void) dealloc +{ + + UIDevice * device = [UIDevice currentDevice]; + // [device endGeneratingDeviceOrientationNotifications]; + [[NSNotificationCenter defaultCenter] removeObserver:self]; + + [super dealloc]; + +} + +- (id) init +{ + + self = [super init]; + if (!self) + { + return nil; + } + + UIDevice * device = [UIDevice currentDevice]; + // [device beginGeneratingDeviceOrientationNotifications]; + [[NSNotificationCenter defaultCenter] + addObserver:self selector:@selector(orientationChanged:) + name:UIDeviceOrientationDidChangeNotification + object:device]; + + return self; + +} + +- (void) dispatchEventForCurrentDevice +{ + + UIDevice * device = [UIDevice currentDevice]; + [self dispatchEventForDevice:device]; + +} + +- (void) dispatchEventForDevice:(UIDevice *) device +{ + + int orientation = 0; // SDL_ORIENTATION_UNKNOWN + switch (device.orientation) + { + + case UIDeviceOrientationLandscapeLeft: + + orientation = 1; // SDL_ORIENTATION_LANDSCAPE + break; + + case UIDeviceOrientationLandscapeRight: + + orientation = 2; // SDL_ORIENTATION_LANDSCAPE_FLIPPED + break; + + case UIDeviceOrientationPortrait: + + orientation = 3; // SDL_ORIENTATION_PORTRAIT + break; + + case UIDeviceOrientationPortraitUpsideDown: + + orientation = 4; // SDL_ORIENTATION_PORTRAIT_FLIPPED + break; + + default: + + break; + }; + + lime::OrientationEvent event; + event.orientation = orientation; + event.display = -1; + event.type = lime::DEVICE_ORIENTATION_CHANGE; + lime::OrientationEvent::Dispatch(&event); + +} + +- (void) orientationChanged:(NSNotification *) notification +{ + + UIDevice * device = notification.object; + [self dispatchEventForDevice:device]; + +} +@end +#endif + namespace lime { + OrientationObserver* orientationObserver; void System::GCEnterBlocking () { @@ -84,6 +186,44 @@ namespace lime { } + int System::GetDeviceOrientation () { + + UIDevice * device = [UIDevice currentDevice]; + + int orientation = 0; // SDL_ORIENTATION_UNKNOWN + switch (device.orientation) + { + + case UIDeviceOrientationLandscapeLeft: + + orientation = 1; // SDL_ORIENTATION_LANDSCAPE + break; + + case UIDeviceOrientationLandscapeRight: + + orientation = 2; // SDL_ORIENTATION_LANDSCAPE_FLIPPED + break; + + case UIDeviceOrientationPortrait: + + orientation = 3; // SDL_ORIENTATION_PORTRAIT + break; + + case UIDeviceOrientationPortraitUpsideDown: + + orientation = 4; // SDL_ORIENTATION_PORTRAIT_FLIPPED + break; + + default: + + break; + }; + + return orientation; + + } + + std::wstring* System::GetDeviceModel () { #ifdef IPHONE @@ -133,6 +273,29 @@ namespace lime { } + void System::EnableDeviceOrientationChange (bool enable) { + + #ifdef IPHONE + if (enable && !orientationObserver) + { + + orientationObserver = [[OrientationObserver alloc] init]; + // SDL forces dispatch of a display orientation event immediately. + // for consistency, we should dispatch one for device orientation. + [orientationObserver dispatchEventForCurrentDevice]; + + } + else if (!enable && orientationObserver) + { + + orientationObserver = nil; + + } + #endif + + } + + void System::OpenFile (const char* path) { OpenURL (path, NULL); diff --git a/src/lime/_internal/backend/native/NativeApplication.hx b/src/lime/_internal/backend/native/NativeApplication.hx index 2208624bf..56b1677cf 100644 --- a/src/lime/_internal/backend/native/NativeApplication.hx +++ b/src/lime/_internal/backend/native/NativeApplication.hx @@ -13,6 +13,7 @@ import lime.system.Clipboard; import lime.system.Display; import lime.system.DisplayMode; import lime.system.JNI; +import lime.system.Orientation; import lime.system.Sensor; import lime.system.SensorType; import lime.system.System; @@ -50,6 +51,7 @@ class NativeApplication private var gamepadEventInfo = new GamepadEventInfo(); private var joystickEventInfo = new JoystickEventInfo(); private var keyEventInfo = new KeyEventInfo(); + private var orientationEventInfo = new OrientationEventInfo(); private var mouseEventInfo = new MouseEventInfo(); private var renderEventInfo = new RenderEventInfo(RENDER); private var sensorEventInfo = new SensorEventInfo(); @@ -60,6 +62,10 @@ class NativeApplication public var handle:Dynamic; + #if android + private var deviceOrientationListener:OrientationChangeListener; + #end + private var pauseTimer:Int; private var parent:Application; private var toggleFullscreen:Bool; @@ -83,6 +89,13 @@ class NativeApplication Sensor.registerSensor(SensorType.ACCELEROMETER, 0); #end + #if android + var setDeviceOrientationListener = JNI.createStaticMethod("org/haxe/lime/GameActivity", "setDeviceOrientationListener", + "(Lorg/haxe/lime/HaxeObject;)V"); + deviceOrientationListener = new OrientationChangeListener(handleJNIOrientationEvent); + setDeviceOrientationListener(deviceOrientationListener); + #end + #if (!macro && lime_cffi) handle = NativeCFFI.lime_application_create(); #end @@ -118,6 +131,9 @@ class NativeApplication NativeCFFI.lime_text_event_manager_register(handleTextEvent, textEventInfo); NativeCFFI.lime_touch_event_manager_register(handleTouchEvent, touchEventInfo); NativeCFFI.lime_window_event_manager_register(handleWindowEvent, windowEventInfo); + #if (ios || android) + NativeCFFI.lime_orientation_event_manager_register(handleOrientationEvent, orientationEventInfo); + #end #if (ios || android || tvos) NativeCFFI.lime_sensor_event_manager_register(handleSensorEvent, sensorEventInfo); #end @@ -353,6 +369,27 @@ class NativeApplication } } + private function handleOrientationEvent():Void + { + var orientation:Orientation = cast orientationEventInfo.orientation; + var display = orientationEventInfo.display; + switch (orientationEventInfo.type) + { + case DISPLAY_ORIENTATION_CHANGE: + parent.onDisplayOrientationChange.dispatch(display, orientation); + case DEVICE_ORIENTATION_CHANGE: + parent.onDeviceOrientationChange.dispatch(orientation); + } + } + + #if android + private function handleJNIOrientationEvent(newOrientation:Int):Void + { + var orientation:Orientation = cast newOrientation; + parent.onDeviceOrientationChange.dispatch(orientation); + } + #end + private function handleRenderEvent():Void { // TODO: Allow windows to render independently @@ -430,8 +467,7 @@ class NativeApplication window.onTextInput.dispatch(CFFI.stringValue(textEventInfo.text)); case TEXT_EDIT: - window.onTextEdit.dispatch(CFFI.stringValue(textEventInfo.text), textEventInfo.start, - textEventInfo.length); + window.onTextEdit.dispatch(CFFI.stringValue(textEventInfo.text), textEventInfo.start, textEventInfo.length); default: } @@ -757,12 +793,12 @@ class NativeApplication @:keep /*private*/ class KeyEventInfo { - public var keyCode: Float; + public var keyCode:Float; public var modifier:Int; public var type:KeyEventType; public var windowID:Int; - public function new(type:KeyEventType = null, windowID:Int = 0, keyCode: Float = 0, modifier:Int = 0) + public function new(type:KeyEventType = null, windowID:Int = 0, keyCode:Float = 0, modifier:Int = 0) { this.type = type; this.windowID = windowID; @@ -793,7 +829,8 @@ class NativeApplication public var y:Float; public var clickCount:Int; - public function new(type:MouseEventType = null, windowID:Int = 0, x:Float = 0, y:Float = 0, button:Int = 0, movementX:Float = 0, movementY:Float = 0, clickCount:Int = 0) + public function new(type:MouseEventType = null, windowID:Int = 0, x:Float = 0, y:Float = 0, button:Int = 0, movementX:Float = 0, movementY:Float = 0, + clickCount:Int = 0) { this.type = type; this.windowID = 0; @@ -978,3 +1015,46 @@ class NativeApplication var WINDOW_SHOW = 13; var WINDOW_HIDE = 14; } + +@:keep /*private*/ class OrientationEventInfo +{ + public var orientation:Int; + public var display:Int; + public var type:OrientationEventType; + + public function new(type:OrientationEventType = null, orientation:Int = 0, display:Int = -1) + { + this.type = type; + this.orientation = orientation; + this.display = display; + } + + public function clone():OrientationEventInfo + { + return new OrientationEventInfo(type, orientation, display); + } +} + +#if (haxe_ver >= 4.0) private enum #else @:enum private #end abstract OrientationEventType(Int) +{ + var DISPLAY_ORIENTATION_CHANGE = 0; + var DEVICE_ORIENTATION_CHANGE = 1; +} + +#if android +private class OrientationChangeListener implements JNISafety +{ + private var callback:Int->Void; + + public function new(callback:Int->Void) + { + this.callback = callback; + } + + @:runOnMainThread + public function onOrientationChanged(orientation:Int):Void + { + callback(orientation); + } +} +#end diff --git a/src/lime/_internal/backend/native/NativeCFFI.hx b/src/lime/_internal/backend/native/NativeCFFI.hx index dd3403c8c..f48ae225b 100644 --- a/src/lime/_internal/backend/native/NativeCFFI.hx +++ b/src/lime/_internal/backend/native/NativeCFFI.hx @@ -233,6 +233,8 @@ class NativeCFFI @:cffi private static function lime_neko_execute(module:String):Void; + @:cffi private static function lime_orientation_event_manager_register(callback:Dynamic, eventObject:Dynamic):Void; + @:cffi private static function lime_png_decode_bytes(data:Dynamic, decodeData:Bool, buffer:Dynamic):Dynamic; @:cffi private static function lime_png_decode_file(path:String, decodeData:Bool, buffer:Dynamic):Dynamic; @@ -257,6 +259,8 @@ class NativeCFFI @:cffi private static function lime_system_get_num_displays():Int; + @:cffi private static function lime_system_get_device_orientation():Int; + @:cffi private static function lime_system_get_platform_label():Dynamic; @:cffi private static function lime_system_get_platform_name():Dynamic; @@ -512,6 +516,8 @@ class NativeCFFI private static var lime_mouse_event_manager_register = new cpp.Callablecpp.Object->cpp.Void>(cpp.Prime._loadPrime("lime", "lime_mouse_event_manager_register", "oov", false)); private static var lime_neko_execute = new cpp.Callablecpp.Void>(cpp.Prime._loadPrime("lime", "lime_neko_execute", "sv", false)); + private static var lime_orientation_event_manager_register = new cpp.Callablecpp.Object->cpp.Void>(cpp.Prime._loadPrime("lime", + "lime_orientation_event_manager_register", "oov", false)); private static var lime_png_decode_bytes = new cpp.CallableBool->cpp.Object->cpp.Object>(cpp.Prime._loadPrime("lime", "lime_png_decode_bytes", "oboo", false)); private static var lime_png_decode_file = new cpp.CallableBool->cpp.Object->cpp.Object>(cpp.Prime._loadPrime("lime", "lime_png_decode_file", @@ -533,6 +539,7 @@ class NativeCFFI private static var lime_system_get_display = new cpp.Callablecpp.Object>(cpp.Prime._loadPrime("lime", "lime_system_get_display", "io", false)); private static var lime_system_get_ios_tablet = new cpp.CallableBool>(cpp.Prime._loadPrime("lime", "lime_system_get_ios_tablet", "b", false)); private static var lime_system_get_num_displays = new cpp.CallableInt>(cpp.Prime._loadPrime("lime", "lime_system_get_num_displays", "i", false)); + private static var lime_system_get_device_orientation = new cpp.CallableInt>(cpp.Prime._loadPrime("lime", "lime_system_get_device_orientation", "i", false)); private static var lime_system_get_platform_label = new cpp.Callablecpp.Object>(cpp.Prime._loadPrime("lime", "lime_system_get_platform_label", "o", false)); private static var lime_system_get_platform_name = new cpp.Callablecpp.Object>(cpp.Prime._loadPrime("lime", "lime_system_get_platform_name", "o", @@ -712,6 +719,7 @@ class NativeCFFI private static var lime_lzma_decompress = CFFI.load("lime", "lime_lzma_decompress", 2); private static var lime_mouse_event_manager_register = CFFI.load("lime", "lime_mouse_event_manager_register", 2); private static var lime_neko_execute = CFFI.load("lime", "lime_neko_execute", 1); + private static var lime_orientation_event_manager_register = CFFI.load("lime", "lime_orientation_event_manager_register", 2); private static var lime_png_decode_bytes = CFFI.load("lime", "lime_png_decode_bytes", 3); private static var lime_png_decode_file = CFFI.load("lime", "lime_png_decode_file", 3); private static var lime_render_event_manager_register = CFFI.load("lime", "lime_render_event_manager_register", 2); @@ -724,6 +732,7 @@ class NativeCFFI private static var lime_system_get_display = CFFI.load("lime", "lime_system_get_display", 1); private static var lime_system_get_ios_tablet = CFFI.load("lime", "lime_system_get_ios_tablet", 0); private static var lime_system_get_num_displays = CFFI.load("lime", "lime_system_get_num_displays", 0); + private static var lime_system_get_device_orientation = CFFI.load("lime", "lime_system_get_device_orientation", 0); private static var lime_system_get_platform_label = CFFI.load("lime", "lime_system_get_platform_label", 0); private static var lime_system_get_platform_name = CFFI.load("lime", "lime_system_get_platform_name", 0); private static var lime_system_get_platform_version = CFFI.load("lime", "lime_system_get_platform_version", 0); @@ -1148,6 +1157,10 @@ class NativeCFFI eventObject:MouseEventInfo):Void {} // @:cffi private static function lime_neko_execute (module:String):Void; + + @:hlNative("lime", "hl_orientation_event_manager_register") private static function lime_orientation_event_manager_register(callback:Void->Void, + eventObject:OrientationEventInfo):Void {} + @:hlNative("lime", "hl_png_decode_bytes") private static function lime_png_decode_bytes(data:Bytes, decodeData:Bool, buffer:ImageBuffer):ImageBuffer { return null; @@ -1204,6 +1217,11 @@ class NativeCFFI return 0; } + @:hlNative("lime", "hl_system_get_device_orientation") private static function lime_system_get_device_orientation():Int + { + return 0; + } + @:hlNative("lime", "hl_system_get_platform_label") private static function lime_system_get_platform_label():hl.Bytes { return null; diff --git a/src/lime/app/Application.hx b/src/lime/app/Application.hx index 87cf6ce6d..7184d763b 100644 --- a/src/lime/app/Application.hx +++ b/src/lime/app/Application.hx @@ -2,6 +2,7 @@ package lime.app; import lime.graphics.RenderContext; import lime.system.System; +import lime.system.Orientation; import lime.ui.Gamepad; import lime.ui.GamepadAxis; import lime.ui.GamepadButton; @@ -15,6 +16,7 @@ import lime.ui.Touch; import lime.ui.Window; import lime.ui.WindowAttributes; import lime.utils.Preloader; +import lime._internal.backend.native.NativeCFFI; /** The Application class forms the foundation for most Lime projects. @@ -22,11 +24,12 @@ import lime.utils.Preloader; to override "on" functions in the class in order to handle standard events that are relevant. **/ -@:access(lime.ui.Window) #if !lime_debug @:fileXml('tags="haxe,release"') @:noDebug #end +@:access(lime.ui.Window) +@:access(lime._internal.backend.native.NativeCFFI) class Application extends Module { /** @@ -34,6 +37,11 @@ class Application extends Module **/ public static var current(default, null):Application; + /** + The device's orientation. + **/ + public var deviceOrientation(get, never):Orientation; + /** Meta-data values for the application, such as a version or a package name **/ @@ -54,6 +62,19 @@ class Application extends Module **/ public var onCreateWindow = new EventVoid>(); + /** + Dispatched when the orientation of the display has changed. + **/ + public var onDisplayOrientationChange = new EventOrientation->Void>(); + + /** + Dispatched when the orientation of the device has changed. Typically, + the display and device orientation values are the same. However, if the + display orientation is locked to portrait or landscape, the display and + device orientations may be different. + **/ + public var onDeviceOrientationChange = new EventVoid>(); + /** The Preloader for the current Application **/ @@ -632,6 +653,15 @@ class Application extends Module { return __windows; } + + @:noCompletion private function get_deviceOrientation():Orientation + { + #if (lime_cffi && !macro) + return cast NativeCFFI.lime_system_get_device_orientation(); + #else + return UNKNOWN; + #end + } } #if air diff --git a/src/lime/system/Display.hx b/src/lime/system/Display.hx index b3eada3ba..602b36b17 100644 --- a/src/lime/system/Display.hx +++ b/src/lime/system/Display.hx @@ -25,6 +25,11 @@ class Display */ public var dpi(default, null):Float; + /** + * Orientation of the display + */ + public var orientation(default, null):Int; + /** * The name of the device, such as "Samsung SyncMaster P2350", "iPhone 6", "Oculus Rift DK2", etc. **/ diff --git a/src/lime/system/Orientation.hx b/src/lime/system/Orientation.hx new file mode 100644 index 000000000..b3d076b90 --- /dev/null +++ b/src/lime/system/Orientation.hx @@ -0,0 +1,10 @@ +package lime.system; + +#if (haxe_ver >= 4.0) enum #else @:enum #end abstract Orientation(Int) +{ + var UNKNOWN = 0; + var LANDSCAPE = 1; + var LANDSCAPE_FLIPPED = 2; + var PORTRAIT = 3; + var PORTRAIT_FLIPPED = 4; +} \ No newline at end of file diff --git a/src/lime/system/System.hx b/src/lime/system/System.hx index 71d1812c7..8aee425b5 100644 --- a/src/lime/system/System.hx +++ b/src/lime/system/System.hx @@ -246,6 +246,7 @@ class System display.id = id; display.name = CFFI.stringValue(displayInfo.name); display.bounds = new Rectangle(displayInfo.bounds.x, displayInfo.bounds.y, displayInfo.bounds.width, displayInfo.bounds.height); + display.orientation = displayInfo.orientation; #if ios var tablet = NativeCFFI.lime_system_get_ios_tablet(); diff --git a/templates/android/template/app/src/main/java/org/haxe/lime/GameActivity.java b/templates/android/template/app/src/main/java/org/haxe/lime/GameActivity.java index 18a276f6e..6f0d3bf11 100644 --- a/templates/android/template/app/src/main/java/org/haxe/lime/GameActivity.java +++ b/templates/android/template/app/src/main/java/org/haxe/lime/GameActivity.java @@ -15,6 +15,7 @@ import android.util.DisplayMetrics; import android.util.Log; import android.view.KeyCharacterMap; import android.view.KeyEvent; +import android.view.OrientationEventListener; import android.view.View; import android.webkit.MimeTypeMap; import android.Manifest; @@ -33,9 +34,22 @@ public class GameActivity extends SDLActivity { private static List extensions; private static DisplayMetrics metrics; private static Vibrator vibrator; + private static OrientationEventListener orientationListener; + private static HaxeObject deviceOrientationListener; + private static int deviceOrientation = SDL_ORIENTATION_UNKNOWN; public Handler handler; + public static void setDeviceOrientationListener (HaxeObject object) { + + deviceOrientationListener = object; + if (deviceOrientationListener != null) + { + deviceOrientationListener.call1("onOrientationChanged", deviceOrientation); + } + + } + public static double getDisplayXDPI () { if (metrics == null) { @@ -111,6 +125,40 @@ public class GameActivity extends SDLActivity { super.onCreate (state); + orientationListener = new OrientationEventListener(this) { + + public void onOrientationChanged(int degrees) { + + int orientation = SDL_ORIENTATION_UNKNOWN; + if (degrees >= 315 || (degrees >= 0 && degrees < 45)) + { + orientation = SDL_ORIENTATION_PORTRAIT; + } + else if (degrees >= 45 && degrees < 135) + { + orientation = SDL_ORIENTATION_LANDSCAPE_FLIPPED; + } + else if (degrees >= 135 && degrees < 225) + { + orientation = SDL_ORIENTATION_PORTRAIT_FLIPPED; + } + else if (degrees >= 225 && degrees < 315) + { + orientation = SDL_ORIENTATION_LANDSCAPE; + } + + if (deviceOrientation != orientation) { + deviceOrientation = orientation; + if (deviceOrientationListener != null) + { + deviceOrientationListener.call1("onOrientationChanged", deviceOrientation); + } + } + + } + + }; + assetManager = getAssets (); if (checkSelfPermission(Manifest.permission.VIBRATE) == PackageManager.PERMISSION_GRANTED) { @@ -192,6 +240,8 @@ public class GameActivity extends SDLActivity { } + orientationListener.disable(); + super.onPause (); for (Extension extension : extensions) { @@ -239,6 +289,8 @@ public class GameActivity extends SDLActivity { super.onResume (); + orientationListener.enable(); + for (Extension extension : extensions) { extension.onResume ();