빌더(TWx) 님이 쓰신 글 :
: 100jk 님이 쓰신 글 :
: : 구글검색 중에 나오는 팁들은 전부 윈도우 기반이네요
: :
: : FMX에서 IME조합중인 문자를 가져오는 방법은 없을까요?
:
:
:
: 답변:
:
:
: Java로 프로그래밍 하면...
: 안드로이드 Input Method 클래스나, 키보드 Connection 클래스를 바인드해서
: 간단하게 처리할 수 있지만...
:
: FMX 파이어몽키로 처리하려면 삽질을 해야 합니다.
:
: FMX 프레임웍이 만들어질 때... 기존 윈도우즈 플렛폼에서의 VCL 프레임웍 랜더링을
: DirectX로 대신하는 구조로 설계됐던 건데...
:
: VCL 프레임웍의 TEdit, TListBox, TMemo 와 같은 상위 레이어 컴포넌트를 베이스로 해서
: 안드로이드, Mac, iOS, 윈도우즈... 각기 플렛폼을 one source multi platform을 지원한답시고
:
: legacy 아키텍쳐에 온갖 프록시 클래스를 섞어 놓아서...
: 지금의 멀티디바이스 FMX 프레임웍이 만들어졌기 때문에 프레임웍이 복잡하고 지져분하게 구성되어 있기 때문 입니다.
:
:
:
: 델파이 컴파일러가 FMX 프레임웍을 만들면서 ARC로 닭짓을 해놨기 때문에...
: FMX 프레임웍 ARC 레벨에서 C++ 컴파일러를 이용해서 작업할 수 없어서
: 코드는 파스칼로 구현하는 거로 대신 합니다.
:
: rad studio 10.3.2 기준으로 구현. (10.3 으로 넘어 오면서 FMX 프록시 클래스 구조가 또 바꼈음.)
:
: C++ 컴파일러로 작업할려면 델파이 FMX 프레임웍 ARC 메모리 모델이 폐기 되어야 함.
:
: <델파이 FMX ARC 메모리 모델의 문제점>
:
http://delphi.borlandforum.com/impboard/impboard.dll?action=read&db=del_qna&no=16034
:
:
:
: unit Unit2;
:
: interface
:
: implementation
:
: uses
: FMX.Forms, FMX.Platform.Android, FMX.Platform,
:
: FMX.Controls, FMX.Controls.Presentation,
: FMX.Presentation.Android.Style, FMX.Text,
: AndroidApi.Helpers, System.Messaging,
:
: System.SysUtils, System.Types,
: Androidapi.JNI.GraphicsContentViewText, Androidapi.JNI.Embarcadero,
: FMX.Types, FMX.VirtualKeyboard, Androidapi.JNIBridge,
: Androidapi.JNI.JavaTypes;
:
:
: type
: KeyboardAndroidEx = class;
:
: VKListener = class(TJavaLocal, JOnKeyboardStateChangedListener)
: private
: [weak] FKeyboardService: KeyboardAndroidEx;
: FNeedNotify: Boolean;
:
: public
: constructor Create(Svc: KeyboardAndroidEx);
: procedure onVirtualKeyboardFrameChanged(newFrame: JRect); cdecl;
: procedure onVirtualKeyboardWillShown; cdecl;
: procedure onVirtualKeyboardWillHidden; cdecl;
: end;
:
: FMXListenerEx = class(TJavaLocal, JFMXTextListener)
: strict private
: FProcessed: boolean;
: public
: constructor Create(const Service: KeyboardAndroidEx); overload;
: procedure onEditorAction(aCode: Integer); cdecl;
: procedure onTextUpdated(cs: JCharSequence; pos: Integer); cdecl;
: procedure onComposingText(bPos: Integer; ePos: Integer); cdecl;
: procedure onSkipKeyEvent(event: JKeyEvent); cdecl;
:
: end;
:
: KeyboardAndroidEx = class(TInterfacedObject, IFMXVirtualKeyboardService)
: private
: FVKListener: VKListener;
: FTransient: Boolean;
: FTextListener: FMXListenerEx;
:
: function IsAutoShow: Boolean;
: procedure Register;
: public
: constructor Create;
: destructor Destroy; override;
:
: protected
: function DefineView(const AObject: TFmxObject): JView;
: procedure NotificationKeyboardEvent(const AVKRect: TRect);
:
: function ShowVirtualKeyboard(const AControl: TFmxObject): Boolean;
: function HideVirtualKeyboard: Boolean;
: function GetVirtualKeyBoardState: TVirtualKeyBoardStates;
: procedure SetTransientState(Value: Boolean);
: property VirtualKeyBoardState: TVirtualKeyBoardStates read GetVirtualKeyBoardState;
: end;
:
:
: constructor KeyboardAndroidEx.Create;
: begin
: inherited Create;
: end;
:
: destructor KeyboardAndroidEx.Destroy;
: begin
: inherited;
: end;
:
: function KeyboardAndroidEx.DefineView(const AObject: TFmxObject): JView;
:
: function IsControl: Boolean;
: begin
: Result := (AObject is TPresentedControl) and (TPresentedControl(AObject).ControlType = TControlType.Platform);
: end;
:
: function GetView: JView;
: begin
: Result := JView(TPresentedControl(AObject).PresentationProxy.NativeObject);
: end;
:
: function GetFormView: JView;
: begin
: Result := WindowHandleToPlatform(TCommonCustomForm(TControl(AObject).Root.GetObject).Handle).View;
: end;
:
: function IsStyledControl: Boolean;
: begin
: Result := (AObject is TPresentedControl) and (TPresentedControl(AObject).Presentation is TAndroidStyledPresentation);
: end;
:
: function IsAvailable: Boolean;
: begin
: Result := (AObject is TControl) and (TControl(AObject).Root <> nil) and
: TCommonCustomForm(TControl(AObject).Root.GetObject).IsHandleAllocated;
: end;
:
: begin
: if IsStyledControl and IsAvailable then
: Result := GetFormView
: else if IsControl then
: Result := GetView
: else if Supports(AObject, ITextInput) then
: Result := MainActivity.getEditText
: else if IsAvailable then
: Result := GetFormView
: else
: Result := nil;
: end;
:
: function KeyboardAndroidEx.IsAutoShow: Boolean;
: begin
: Result := VKAutoShowMode in [TVKAutoShowMode.Always, TVKAutoShowMode.DefinedBySystem];
: end;
:
: procedure KeyboardAndroidEx.Register;
: begin
: if not Assigned(FVKListener) then
: begin
: FVKListener := VKListener.Create(Self);
: MainActivity.getVirtualKeyboard.addOnKeyboardStateChangedListener(FVKListener);
: end;
: end;
:
: function KeyboardAndroidEx.GetVirtualKeyBoardState: TVirtualKeyBoardStates;
: begin
: Result := [];
: if IsAutoShow then
: Include(Result, TVirtualKeyboardState.AutoShow);
: if FTransient then
: Include(Result, TVirtualKeyboardState.Transient);
: if MainActivity.getVirtualKeyboard.isVirtualKeyboardShown then
: Include(Result, TVirtualKeyboardState.Visible);
:
: end;
:
: function KeyboardAndroidEx.HideVirtualKeyboard: Boolean;
: begin
: Result := False;
: try
: if not FTransient then
: begin
: Register;
: MainActivity.getEditText().removeTextListener(FTextListener);
: Result := MainActivity.getVirtualKeyboard.hide;
: end;
: except
: Application.HandleException(Screen.ActiveForm);
: end;
: end;
:
:
: procedure KeyboardAndroidEx.NotificationKeyboardEvent(const AVKRect: TRect);
: var
: M: TVKStateChangeMessage;
: begin
: M := TVKStateChangeMessage.Create(TVirtualKeyboardState.Visible in VirtualKeyboardState, AVKRect);
: TMessageManager.DefaultManager.SendMessage(Self, M, True);
: end;
:
: function KeyboardAndroidEx.ShowVirtualKeyboard(const AControl: TFmxObject): Boolean;
: function IsNotFocused(const AControl: TFmxObject): Boolean;
: begin
: Result := (AControl is TControl) and not TControl(AControl).IsFocused;
: end;
:
: begin
: if IsNotFocused(AControl) then
: TControl(AControl).SetFocus;
: Register;
: if not Assigned(FTextListener) then
: FTextListener := FMXListenerEx.Create(Self);
:
: MainActivity.getEditText().addTextListener(FTextListener);
: Result := MainActivity.getVirtualKeyboard.showFor(DefineView(AControl));
: end;
:
:
: procedure KeyboardAndroidEx.SetTransientState(Value: Boolean);
: begin
: FTransient := Value;
: end;
:
:
: constructor VKListener.Create(Svc: KeyboardAndroidEx);
: begin
: inherited Create;
: FKeyboardService := Svc;
: end;
:
: procedure VKListener.onVirtualKeyboardFrameChanged(newFrame: JRect);
: begin
: end;
:
: procedure VKListener.onVirtualKeyboardWillShown;
: begin
: FNeedNotify := FNeedNotify or
: not (TVirtualKeyboardState.Visible in FKeyboardService.VirtualKeyboardState);
: end;
:
: procedure VKListener.onVirtualKeyboardWillHidden;
: begin
: FNeedNotify := FNeedNotify or
: (TVirtualKeyboardState.Visible in FKeyboardService.VirtualKeyboardState);
: end;
:
:
:
: constructor FMXListenerEx.Create(const Service: KeyboardAndroidEx);
: begin
: inherited Create;
: end;
:
: procedure FMXListenerEx.onComposingText(bPos, ePos: Integer);
: begin
: end;
:
: procedure FMXListenerEx.onSkipKeyEvent(event: JKeyEvent);
: begin
: end;
:
: procedure FMXListenerEx.onTextUpdated(cs: JCharSequence; pos: Integer);
: begin
: if pos = 0 then
: Exit;
:
: if not FProcessed then
: begin
: // 디버깅덤프. 문자조합과정 출력
: Log.d(Format('%s', [JCharSequenceToStr(cs)[pos-1]]));
: FProcessed := True;
: end
: else
: FProcessed := False;
: end;
:
: procedure FMXListenerEx.onEditorAction(aCode: Integer);
: begin
: end;
:
:
: var
: FKeyboardAndroidEx: KeyboardAndroidEx = nil;
: FVKService: IFMXVirtualKeyboardService = nil;
:
: initialization
: FKeyboardAndroidEx := KeyboardAndroidEx.Create;
: FVKService := IFMXVirtualKeyboardService(TPlatformServices.Current.GetPlatformService(IFMXVirtualKeyboardService));
: if FVKService <> nil then
: TPlatformServices.Current.RemovePlatformService(IFMXVirtualKeyboardService);
: TPlatformServices.Current.AddPlatformService(IFMXVirtualKeyboardService, FKeyboardAndroidEx);
:
: end.
:
:
:
:
:
:
:
: 메인폼에 TEdit 올려놓고...
: 위의 Unit2를 메인 유닛의 implementaion 섹션의 uses 에 포함해서 컴파일만 하면 됌.
:
: 컴파일 후... TEdit에 "국가"를 입력하면 아래 캡쳐 화면과 같이...
: LogCat을 통해서 문자조합 과정이 출력될 겁니다. (LogCat을 이용한 디버깅 덤프방법은 생략함)
:
:
:
:
:
:
: 간단한가요?
:
: one source multi platform은 초보자들 꼬득이기 위한 상술에 불과한 거고...
: Java와 Android sdk 프레임웍 구조 모르면... 기술적인 문제에 부딛혔을 때... 아무것도 손 못댑니다.
:
: Java와 Android sdk 프레임웍 구조부터 마스터 하세요.
: 이걸 마스터 해놔야...
:
: Android 프레임웍과 비슷한 구조로 만들어져 있는 C# Xamarin도 마음대로 요리할 수 있게 됍니다.
:
: C# Xamarin으로 작성된 코드는 델파이 보다 느리다는 황당한 궤변을 늘어놓는 사람들도 있던데...
: 아마도 이런 사람들은 Android 프레임웍 구조도 모르고, C# 도 디테일하게 잘 모르고 있으면서
: 어설프게 델파이 하나만 맹신적으로 사용하고 있는 사람일 겁니다.
:
:
:
:
답변 정말 감사드립니다.
파이어몽키에도 빨리 리치에디터나 씬에디터같은 좋은 에디터가 나오면 좋겠습니다.