From 2d3f51d2a4413069b221269da3e084c9b905caa6 Mon Sep 17 00:00:00 2001 From: Joshua Granick Date: Tue, 12 May 2015 07:11:21 -0700 Subject: [PATCH] Initial support for text input/edit events --- lime/_backend/flash/FlashApplication.hx | 6 +++ lime/_backend/flash/FlashWindow.hx | 15 ++++++ lime/_backend/html5/HTML5Application.hx | 6 +++ lime/_backend/html5/HTML5Window.hx | 15 ++++++ lime/_backend/native/NativeApplication.hx | 60 ++++++++++++++++++++++ lime/_backend/native/NativeWindow.hx | 28 ++++++++++ lime/app/Application.hx | 24 +++++++++ lime/app/IModule.hx | 16 ++++++ lime/app/Module.hx | 16 ++++++ lime/ui/Window.hx | 17 ++++++ project/Build.xml | 1 + project/include/ui/TextEvent.h | 41 +++++++++++++++ project/include/ui/Window.h | 2 + project/src/ExternalInterface.cpp | 30 +++++++++++ project/src/backend/sdl/SDLApplication.cpp | 36 +++++++++++++ project/src/backend/sdl/SDLApplication.h | 3 ++ project/src/backend/sdl/SDLWindow.cpp | 22 ++++++++ project/src/backend/sdl/SDLWindow.h | 2 + project/src/ui/TextEvent.cpp | 59 +++++++++++++++++++++ 19 files changed, 399 insertions(+) create mode 100644 project/include/ui/TextEvent.h create mode 100644 project/src/ui/TextEvent.cpp diff --git a/lime/_backend/flash/FlashApplication.hx b/lime/_backend/flash/FlashApplication.hx index 7488b6795..23c46bb1b 100644 --- a/lime/_backend/flash/FlashApplication.hx +++ b/lime/_backend/flash/FlashApplication.hx @@ -163,6 +163,12 @@ class FlashApplication { parent.window.onKeyDown.dispatch (keyCode, modifier); + if (parent.window.enableTextEvents) { + + parent.window.onTextInput.dispatch (String.fromCharCode (event.charCode)); + + } + } else { parent.window.onKeyUp.dispatch (keyCode, modifier); diff --git a/lime/_backend/flash/FlashWindow.hx b/lime/_backend/flash/FlashWindow.hx index c35ff4f06..4e5a28146 100644 --- a/lime/_backend/flash/FlashWindow.hx +++ b/lime/_backend/flash/FlashWindow.hx @@ -12,6 +12,7 @@ import lime.ui.Window; class FlashWindow { + private var enableTextEvents:Bool; private var parent:Window; @@ -37,6 +38,13 @@ class FlashWindow { } + public function getEnableTextEvents ():Bool { + + return enableTextEvents; + + } + + public function move (x:Int, y:Int):Void { @@ -51,6 +59,13 @@ class FlashWindow { } + public function setEnableTextEvents (value:Bool):Bool { + + return enableTextEvents = value; + + } + + public function setFullscreen (value:Bool):Bool { return value; diff --git a/lime/_backend/html5/HTML5Application.hx b/lime/_backend/html5/HTML5Application.hx index 0af060c6e..7eda98583 100644 --- a/lime/_backend/html5/HTML5Application.hx +++ b/lime/_backend/html5/HTML5Application.hx @@ -169,6 +169,12 @@ class HTML5Application { parent.window.onKeyDown.dispatch (keyCode, modifier); + if (parent.window.enableTextEvents) { + + parent.window.onTextInput.dispatch (String.fromCharCode (event.keyCode)); + + } + } else { parent.window.onKeyUp.dispatch (keyCode, modifier); diff --git a/lime/_backend/html5/HTML5Window.hx b/lime/_backend/html5/HTML5Window.hx index 6cae8c737..3ebde5693 100644 --- a/lime/_backend/html5/HTML5Window.hx +++ b/lime/_backend/html5/HTML5Window.hx @@ -26,6 +26,7 @@ class HTML5Window { public var stats:Dynamic; #end + private var enableTextEvents:Bool; private var parent:Window; private var setHeight:Int; private var setWidth:Int; @@ -166,6 +167,13 @@ class HTML5Window { } + public function getEnableTextEvents ():Bool { + + return enableTextEvents; + + } + + private function handleMouseEvent (event:MouseEvent):Void { var x = 0.0; @@ -380,6 +388,13 @@ class HTML5Window { } + public function setEnableTextEvents (value:Bool):Bool { + + return enableTextEvents = value; + + } + + public function setFullscreen (value:Bool):Bool { return false; diff --git a/lime/_backend/native/NativeApplication.hx b/lime/_backend/native/NativeApplication.hx index a8803d9a3..f51e5c656 100644 --- a/lime/_backend/native/NativeApplication.hx +++ b/lime/_backend/native/NativeApplication.hx @@ -27,6 +27,7 @@ class NativeApplication { private var keyEventInfo = new KeyEventInfo (); private var mouseEventInfo = new MouseEventInfo (); private var renderEventInfo = new RenderEventInfo (RENDER); + private var textEventInfo = new TextEventInfo (); private var touchEventInfo = new TouchEventInfo (); private var updateEventInfo = new UpdateEventInfo (); private var windowEventInfo = new WindowEventInfo (); @@ -70,6 +71,7 @@ class NativeApplication { lime_key_event_manager_register (handleKeyEvent, keyEventInfo); lime_mouse_event_manager_register (handleMouseEvent, mouseEventInfo); lime_render_event_manager_register (handleRenderEvent, renderEventInfo); + lime_text_event_manager_register (handleTextEvent, textEventInfo); lime_touch_event_manager_register (handleTouchEvent, touchEventInfo); lime_update_event_manager_register (handleUpdateEvent, updateEventInfo); lime_window_event_manager_register (handleWindowEvent, windowEventInfo); @@ -239,6 +241,25 @@ class NativeApplication { } + private function handleTextEvent ():Void { + + switch (textEventInfo.type) { + + case TEXT_INPUT: + + parent.window.onTextInput.dispatch (textEventInfo.text); + + case TEXT_EDIT: + + parent.window.onTextEdit.dispatch (textEventInfo.text, textEventInfo.start, textEventInfo.length); + + default: + + } + + } + + private function handleTouchEvent ():Void { if (parent.window != null) { @@ -394,6 +415,7 @@ class NativeApplication { private static var lime_key_event_manager_register = System.load ("lime", "lime_key_event_manager_register", 2); private static var lime_mouse_event_manager_register = System.load ("lime", "lime_mouse_event_manager_register", 2); private static var lime_render_event_manager_register = System.load ("lime", "lime_render_event_manager_register", 2); + private static var lime_text_event_manager_register = System.load ("lime", "lime_text_event_manager_register", 2); private static var lime_touch_event_manager_register = System.load ("lime", "lime_touch_event_manager_register", 2); private static var lime_update_event_manager_register = System.load ("lime", "lime_update_event_manager_register", 2); private static var lime_window_event_manager_register = System.load ("lime", "lime_window_event_manager_register", 2); @@ -557,6 +579,44 @@ private class RenderEventInfo { } +private class TextEventInfo { + + + public var id:Int; + public var length:Int; + public var start:Int; + public var text:String; + public var type:TextEventType; + + + public function new (type:TextEventType = null, text:String = "", start:Int = 0, length:Int = 0) { + + this.type = type; + this.text = text; + this.start = start; + this.length = length; + + } + + + public function clone ():TextEventInfo { + + return new TextEventInfo (type, text, start, length); + + } + + +} + + +@:enum private abstract TextEventType(Int) { + + var TEXT_INPUT = 0; + var TEXT_EDIT = 1; + +} + + private class TouchEventInfo { diff --git a/lime/_backend/native/NativeWindow.hx b/lime/_backend/native/NativeWindow.hx index 72182d52b..e898e6d2c 100644 --- a/lime/_backend/native/NativeWindow.hx +++ b/lime/_backend/native/NativeWindow.hx @@ -89,6 +89,19 @@ class NativeWindow { } + public function getEnableTextEvents ():Bool { + + if (handle != null) { + + return lime_window_get_enable_text_events (handle); + + } + + return false; + + } + + public function move (x:Int, y:Int):Void { if (handle != null) { @@ -111,6 +124,19 @@ class NativeWindow { } + public function setEnableTextEvents (value:Bool):Bool { + + if (handle != null) { + + return lime_window_set_enable_text_events (handle, value); + + } + + return value; + + } + + public function setFullscreen (value:Bool):Bool { if (handle != null) { @@ -156,12 +182,14 @@ class NativeWindow { private static var lime_window_close = System.load ("lime", "lime_window_close", 1); private static var lime_window_create = System.load ("lime", "lime_window_create", 5); + private static var lime_window_get_enable_text_events = System.load ("lime", "lime_window_get_enable_text_events", 1); private static var lime_window_get_height = System.load ("lime", "lime_window_get_height", 1); private static var lime_window_get_width = System.load ("lime", "lime_window_get_width", 1); private static var lime_window_get_x = System.load ("lime", "lime_window_get_x", 1); private static var lime_window_get_y = System.load ("lime", "lime_window_get_y", 1); private static var lime_window_move = System.load ("lime", "lime_window_move", 3); private static var lime_window_resize = System.load ("lime", "lime_window_resize", 3); + private static var lime_window_set_enable_text_events = System.load ("lime", "lime_window_set_enable_text_events", 2); private static var lime_window_set_fullscreen = System.load ("lime", "lime_window_set_fullscreen", 2); private static var lime_window_set_icon = System.load ("lime", "lime_window_set_icon", 2); private static var lime_window_set_minimized = System.load ("lime", "lime_window_set_minimized", 2); diff --git a/lime/app/Application.hx b/lime/app/Application.hx index 9fa4dad85..69e592424 100644 --- a/lime/app/Application.hx +++ b/lime/app/Application.hx @@ -113,6 +113,8 @@ class Application extends Module { window.onMouseMoveRelative.add (onMouseMoveRelative); window.onMouseUp.add (onMouseUp); window.onMouseWheel.add (onMouseWheel); + window.onTextEdit.add (onTextEdit); + window.onTextInput.add (onTextInput); window.onTouchStart.add (onTouchStart); window.onTouchMove.add (onTouchMove); window.onTouchEnd.add (onTouchEnd); @@ -329,6 +331,28 @@ class Application extends Module { } + public override function onTextEdit (text:String, start:Int, length:Int):Void { + + for (module in modules) { + + module.onTextEdit (text, start, length); + + } + + } + + + public override function onTextInput (text:String):Void { + + for (module in modules) { + + module.onTextInput (text); + + } + + } + + public override function onTouchEnd (x:Float, y:Float, id:Int):Void { for (module in modules) { diff --git a/lime/app/IModule.hx b/lime/app/IModule.hx index 4627999ae..9710ea21c 100644 --- a/lime/app/IModule.hx +++ b/lime/app/IModule.hx @@ -133,6 +133,22 @@ interface IModule { public function onRenderContextRestored (context:RenderContext):Void; + /** + * Called when a text edit event is fired + * @param text The current replacement text + * @param start The starting index for the edit + * @param length The length of the edit + */ + public function onTextEdit (text:String, start:Int, length:Int):Void; + + + /** + * Called when a text input event is fired + * @param text The current input text + */ + public function onTextInput (text:String):Void; + + /** * Called when a touch end event is fired * @param x The current x coordinate of the touch point diff --git a/lime/app/Module.hx b/lime/app/Module.hx index 88b469fad..516ac5b1d 100644 --- a/lime/app/Module.hx +++ b/lime/app/Module.hx @@ -108,6 +108,22 @@ class Module implements IModule { public function onRenderContextRestored (context:RenderContext):Void { } + /** + * Called when a text edit event is fired + * @param text The current replacement text + * @param start The starting index for the edit + * @param length The length of the edit + */ + public function onTextEdit (text:String, start:Int, length:Int):Void { } + + + /** + * Called when a text input event is fired + * @param text The current input text + */ + public function onTextInput (text:String):Void { } + + /** * Called when a touch end event is fired * @param x The current x coordinate of the touch point diff --git a/lime/ui/Window.hx b/lime/ui/Window.hx index 637d01871..2dd7b32d1 100644 --- a/lime/ui/Window.hx +++ b/lime/ui/Window.hx @@ -13,6 +13,7 @@ class Window { public var currentRenderer:Renderer; public var config:Config; + public var enableTextEvents (get, set):Bool; public var fullscreen (get, set):Bool; public var height (get, set):Int; public var minimized (get, set):Bool; @@ -28,6 +29,8 @@ class Window { public var onMouseMoveRelative = new EventFloat->Void> (); public var onMouseUp = new EventFloat->Int->Void> (); public var onMouseWheel = new EventFloat->Void> (); + public var onTextEdit = new EventInt->Int->Void> (); + public var onTextInput = new EventVoid> (); public var onTouchEnd = new EventFloat->Int->Void> (); public var onTouchMove = new EventFloat->Int->Void> (); public var onTouchStart = new EventFloat->Int->Void> (); @@ -141,6 +144,20 @@ class Window { + @:noCompletion private inline function get_enableTextEvents ():Bool { + + return backend.getEnableTextEvents (); + + } + + + @:noCompletion private inline function set_enableTextEvents (value:Bool):Bool { + + return backend.setEnableTextEvents (value); + + } + + @:noCompletion private inline function get_fullscreen ():Bool { return __fullscreen; diff --git a/project/Build.xml b/project/Build.xml index 805a92a13..d56b804e1 100644 --- a/project/Build.xml +++ b/project/Build.xml @@ -194,6 +194,7 @@ + diff --git a/project/include/ui/TextEvent.h b/project/include/ui/TextEvent.h new file mode 100644 index 000000000..4ea3d2251 --- /dev/null +++ b/project/include/ui/TextEvent.h @@ -0,0 +1,41 @@ +#ifndef LIME_UI_TEXT_EVENT_H +#define LIME_UI_TEXT_EVENT_H + + +#include + + +namespace lime { + + + enum TextEventType { + + TEXT_INPUT, + TEXT_EDIT + + }; + + + class TextEvent { + + public: + + static AutoGCRoot* callback; + static AutoGCRoot* eventObject; + + TextEvent (); + + static void Dispatch (TextEvent* event); + + long length; + long start; + char text[32]; + TextEventType type; + + }; + + +} + + +#endif \ No newline at end of file diff --git a/project/include/ui/Window.h b/project/include/ui/Window.h index e58d27420..78c983288 100644 --- a/project/include/ui/Window.h +++ b/project/include/ui/Window.h @@ -19,12 +19,14 @@ namespace lime { public: virtual void Close () = 0; + virtual bool GetEnableTextEvents () = 0; virtual int GetHeight () = 0; virtual int GetWidth () = 0; virtual int GetX () = 0; virtual int GetY () = 0; virtual void Move (int x, int y) = 0; virtual void Resize (int width, int height) = 0; + virtual void SetEnableTextEvents (bool enable) = 0; virtual bool SetFullscreen (bool fullscreen) = 0; virtual void SetIcon (ImageBuffer *imageBuffer) = 0; virtual bool SetMinimized (bool minimized) = 0; diff --git a/project/src/ExternalInterface.cpp b/project/src/ExternalInterface.cpp index 99f7e719a..f253ad9be 100644 --- a/project/src/ExternalInterface.cpp +++ b/project/src/ExternalInterface.cpp @@ -29,6 +29,7 @@ #include #include #include +#include #include #include #include @@ -763,6 +764,15 @@ namespace lime { } + value lime_text_event_manager_register (value callback, value eventObject) { + + TextEvent::callback = new AutoGCRoot (callback); + TextEvent::eventObject = new AutoGCRoot (eventObject); + return alloc_null (); + + } + + void lime_text_layout_destroy (value textHandle) { #ifdef LIME_HARFBUZZ @@ -885,6 +895,14 @@ namespace lime { } + value lime_window_get_enable_text_events (value window) { + + Window* targetWindow = (Window*)(intptr_t)val_float (window); + return alloc_bool (targetWindow->GetEnableTextEvents ()); + + } + + value lime_window_get_height (value window) { Window* targetWindow = (Window*)(intptr_t)val_float (window); @@ -935,6 +953,15 @@ namespace lime { } + value lime_window_set_enable_text_events (value window, value enabled) { + + Window* targetWindow = (Window*)(intptr_t)val_float (window); + targetWindow->SetEnableTextEvents (val_bool (enabled)); + return alloc_null (); + + } + + value lime_window_set_fullscreen (value window, value fullscreen) { Window* targetWindow = (Window*)(intptr_t)val_float (window); @@ -1018,6 +1045,7 @@ namespace lime { DEFINE_PRIM (lime_render_event_manager_register, 2); DEFINE_PRIM (lime_system_get_directory, 3); DEFINE_PRIM (lime_system_get_timer, 0); + DEFINE_PRIM (lime_text_event_manager_register, 2); DEFINE_PRIM (lime_text_layout_create, 3); DEFINE_PRIM (lime_text_layout_position, 5); DEFINE_PRIM (lime_text_layout_set_direction, 2); @@ -1028,12 +1056,14 @@ namespace lime { DEFINE_PRIM (lime_window_close, 1); DEFINE_PRIM (lime_window_create, 5); DEFINE_PRIM (lime_window_event_manager_register, 2); + DEFINE_PRIM (lime_window_get_enable_text_events, 1); DEFINE_PRIM (lime_window_get_height, 1); DEFINE_PRIM (lime_window_get_width, 1); DEFINE_PRIM (lime_window_get_x, 1); DEFINE_PRIM (lime_window_get_y, 1); DEFINE_PRIM (lime_window_move, 3); DEFINE_PRIM (lime_window_resize, 3); + DEFINE_PRIM (lime_window_set_enable_text_events, 2); DEFINE_PRIM (lime_window_set_fullscreen, 2); DEFINE_PRIM (lime_window_set_icon, 2); DEFINE_PRIM (lime_window_set_minimized, 2); diff --git a/project/src/backend/sdl/SDLApplication.cpp b/project/src/backend/sdl/SDLApplication.cpp index 25a153bb7..38a765aae 100644 --- a/project/src/backend/sdl/SDLApplication.cpp +++ b/project/src/backend/sdl/SDLApplication.cpp @@ -41,6 +41,7 @@ namespace lime { KeyEvent keyEvent; MouseEvent mouseEvent; RenderEvent renderEvent; + TextEvent textEvent; TouchEvent touchEvent; UpdateEvent updateEvent; WindowEvent windowEvent; @@ -145,6 +146,12 @@ namespace lime { ProcessMouseEvent (event); break; + case SDL_TEXTINPUT: + case SDL_TEXTEDITING: + + ProcessTextEvent (event); + break; + case SDL_WINDOWEVENT: switch (event->window.event) { @@ -337,6 +344,35 @@ namespace lime { } + void SDLApplication::ProcessTextEvent (SDL_Event* event) { + + if (TextEvent::callback) { + + switch (event->type) { + + case SDL_TEXTINPUT: + + textEvent.type = TEXT_INPUT; + break; + + case SDL_TEXTEDITING: + + textEvent.type = TEXT_EDIT; + textEvent.start = event->edit.start; + textEvent.length = event->edit.length; + break; + + } + + strcpy (textEvent.text, event->text.text); + + TextEvent::Dispatch (&textEvent); + + } + + } + + void SDLApplication::ProcessTouchEvent (SDL_Event* event) { diff --git a/project/src/backend/sdl/SDLApplication.h b/project/src/backend/sdl/SDLApplication.h index 9770cc171..de48a7e0f 100644 --- a/project/src/backend/sdl/SDLApplication.h +++ b/project/src/backend/sdl/SDLApplication.h @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include "SDLWindow.h" @@ -37,6 +38,7 @@ namespace lime { void ProcessGamepadEvent (SDL_Event* event); void ProcessKeyEvent (SDL_Event* event); void ProcessMouseEvent (SDL_Event* event); + void ProcessTextEvent (SDL_Event* event); void ProcessTouchEvent (SDL_Event* event); void ProcessWindowEvent (SDL_Event* event); @@ -54,6 +56,7 @@ namespace lime { MouseEvent mouseEvent; double nextUpdate; RenderEvent renderEvent; + TextEvent textEvent; TouchEvent touchEvent; UpdateEvent updateEvent; WindowEvent windowEvent; diff --git a/project/src/backend/sdl/SDLWindow.cpp b/project/src/backend/sdl/SDLWindow.cpp index ab6a7ca10..eea27001e 100644 --- a/project/src/backend/sdl/SDLWindow.cpp +++ b/project/src/backend/sdl/SDLWindow.cpp @@ -115,6 +115,13 @@ namespace lime { } + bool SDLWindow::GetEnableTextEvents () { + + return SDL_IsTextInputActive (); + + } + + int SDLWindow::GetHeight () { int width; @@ -177,6 +184,21 @@ namespace lime { } + void SDLWindow::SetEnableTextEvents (bool enabled) { + + if (enabled) { + + SDL_StartTextInput (); + + } else { + + SDL_StopTextInput (); + + } + + } + + bool SDLWindow::SetFullscreen (bool fullscreen) { if (fullscreen) { diff --git a/project/src/backend/sdl/SDLWindow.h b/project/src/backend/sdl/SDLWindow.h index f26d580c6..4342166df 100644 --- a/project/src/backend/sdl/SDLWindow.h +++ b/project/src/backend/sdl/SDLWindow.h @@ -18,12 +18,14 @@ namespace lime { ~SDLWindow (); virtual void Close (); + virtual bool GetEnableTextEvents (); virtual int GetHeight (); virtual int GetWidth (); virtual int GetX (); virtual int GetY (); virtual void Move (int x, int y); virtual void Resize (int width, int height); + virtual void SetEnableTextEvents (bool enabled); virtual bool SetFullscreen (bool fullscreen); virtual void SetIcon (ImageBuffer *imageBuffer); virtual bool SetMinimized (bool minimized); diff --git a/project/src/ui/TextEvent.cpp b/project/src/ui/TextEvent.cpp new file mode 100644 index 000000000..a90aac52f --- /dev/null +++ b/project/src/ui/TextEvent.cpp @@ -0,0 +1,59 @@ +#include +#include + + +namespace lime { + + + AutoGCRoot* TextEvent::callback = 0; + AutoGCRoot* TextEvent::eventObject = 0; + + static int id_length; + static int id_start; + static int id_text; + static int id_type; + static bool init = false; + + + TextEvent::TextEvent () { + + length = 0; + start = 0; + + } + + + void TextEvent::Dispatch (TextEvent* event) { + + if (TextEvent::callback) { + + if (!init) { + + id_length = val_id ("length"); + id_start = val_id ("start"); + id_text = val_id ("text"); + id_type = val_id ("type"); + init = true; + + } + + value object = (TextEvent::eventObject ? TextEvent::eventObject->get () : alloc_empty_object ()); + + if (event->type != TEXT_INPUT) { + + alloc_field (object, id_length, alloc_int (event->length)); + alloc_field (object, id_start, alloc_int (event->start)); + + } + + alloc_field (object, id_text, alloc_string (event->text)); + alloc_field (object, id_type, alloc_int (event->type)); + + val_call0 (TextEvent::callback->get ()); + + } + + } + + +} \ No newline at end of file