Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
610db86
commit 1e866dd
Showing
45 changed files
with
49,082 additions
and
9,237 deletions.
There are no files selected for viewing
2,842 changes: 2,842 additions & 0 deletions
2,842
HODLER_Multiplatform_Win_And_iOS_Linux/FMX.Ani.pas
Large diffs are not rendered by default.
Oops, something went wrong.
942 changes: 942 additions & 0 deletions
942
HODLER_Multiplatform_Win_And_iOS_Linux/FMX.Context.GLES.Android.pas
Large diffs are not rendered by default.
Oops, something went wrong.
6,122 changes: 6,122 additions & 0 deletions
6,122
HODLER_Multiplatform_Win_And_iOS_Linux/FMX.Platform.Win.pas
Large diffs are not rendered by default.
Oops, something went wrong.
365 changes: 365 additions & 0 deletions
365
HODLER_Multiplatform_Win_And_iOS_Linux/FMX.VirtualKeyboard.Android.xxx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,365 @@ | ||
{*******************************************************} | ||
{ } | ||
{ Delphi FireMonkey Platform } | ||
{ Copyright(c) 2013-2017 Embarcadero Technologies, Inc. } | ||
{ All rights reserved } | ||
{ } | ||
{*******************************************************} | ||
|
||
unit FMX.VirtualKeyboard.Android; | ||
|
||
interface | ||
|
||
{$SCOPEDENUMS ON} | ||
|
||
uses | ||
System.Classes, System.SysUtils, System.UITypes, System.Types, | ||
System.SyncObjs, Androidapi.JNI.GraphicsContentViewText, Androidapi.JNI.Embarcadero, Androidapi.JNI.JavaTypes, | ||
Androidapi.JNIBridge, FMX.Types, FMX.Helpers.Android, FMX.VirtualKeyboard,System.Messaging, FMX.Forms, FMX.Platform.Android, FMX.Platform,Androidapi.JNI.Util; | ||
type | ||
TVirtualKeyboardRect = class; | ||
|
||
TGlobalLayoutListener = class(TJavaLocal, JViewTreeObserver_OnGlobalLayoutListener) | ||
private | ||
FVirtualKeyboardRect: TVirtualKeyboardRect; | ||
public | ||
{ JViewTreeObserver_OnGlobalLayoutListener } | ||
procedure onGlobalLayout; cdecl; | ||
public | ||
constructor Create(const AVirtualKeyboardRect: TVirtualKeyboardRect); | ||
end; | ||
|
||
TVirtualKeyboardRect = class(TInterfacedObject) | ||
private | ||
FCanFireEvent: Boolean; | ||
FListener: JViewTreeObserver_OnGlobalLayoutListener; | ||
FPendingShow: Boolean; | ||
FVKListener: TVKListener; | ||
FVKVisible: Boolean; | ||
procedure ApplicationEventMessageHandler(const Sender: TObject; const M: TMessage); | ||
procedure InstallListener; | ||
procedure RemoveListener; | ||
procedure VirtualKeyboardHidden; | ||
procedure VirtualKeyboardShown; | ||
protected | ||
procedure GlobalLayoutChange; | ||
property CanFireEvent: Boolean read FCanFireEvent; | ||
property VKListener: TVKListener read FVKListener write FVKListener; | ||
public | ||
constructor Create; | ||
destructor Destroy; override; | ||
end; | ||
|
||
{ TGlobalLayoutListener } | ||
|
||
constructor TGlobalLayoutListener.Create(const AVirtualKeyboardRect: TVirtualKeyboardRect); | ||
begin | ||
inherited Create; | ||
FVirtualKeyboardRect := AVirtualKeyboardRect; | ||
end; | ||
|
||
procedure TGlobalLayoutListener.onGlobalLayout; | ||
begin | ||
FVirtualKeyboardRect.GlobalLayoutChange; | ||
end; | ||
|
||
{ TVirtualKeyboardRect } | ||
|
||
constructor TVirtualKeyboardRect.Create; | ||
begin | ||
inherited; | ||
TMessageManager.DefaultManager.SubscribeToMessage(TApplicationEventMessage, ApplicationEventMessageHandler); | ||
end; | ||
|
||
destructor TVirtualKeyboardRect.Destroy; | ||
begin | ||
if FListener <> nil then | ||
RemoveListener; | ||
TMessageManager.DefaultManager.Unsubscribe(TApplicationEventMessage, ApplicationEventMessageHandler); | ||
inherited; | ||
end; | ||
|
||
procedure TVirtualKeyboardRect.ApplicationEventMessageHandler(const Sender: TObject; const M: TMessage); | ||
begin | ||
case TApplicationEventMessage(M).Value.Event of | ||
TApplicationEvent.BecameActive: | ||
begin | ||
if FListener = nil then | ||
InstallListener; | ||
end; | ||
end; | ||
end; | ||
|
||
procedure TVirtualKeyboardRect.VirtualKeyboardHidden; | ||
begin | ||
FVKVisible := False; | ||
end; | ||
|
||
procedure TVirtualKeyboardRect.VirtualKeyboardShown; | ||
begin | ||
FPendingShow := True; | ||
FVKVisible := True; | ||
end; | ||
|
||
procedure TVirtualKeyboardRect.GlobalLayoutChange; | ||
begin | ||
if FPendingShow then | ||
begin | ||
FCanFireEvent := True; | ||
try | ||
FVKListener.onVirtualKeyboardShown; | ||
finally | ||
FCanFireEvent := False; | ||
end; | ||
end | ||
else if FVKVisible and not FCanFireEvent then | ||
TMessageManager.DefaultManager.SendMessage(Self, TVKStateChangeMessage.Create(True, FVKListener.ObtainKeyboardRect), True); | ||
FPendingShow := False; | ||
end; | ||
|
||
procedure TVirtualKeyboardRect.InstallListener; | ||
begin | ||
FListener := TGlobalLayoutListener.Create(Self); | ||
MainActivity.getWindow.getDecorView.getViewTreeObserver.addOnGlobalLayoutListener(FListener); | ||
end; | ||
|
||
procedure TVirtualKeyboardRect.RemoveListener; | ||
begin | ||
MainActivity.getWindow.getDecorView.getViewTreeObserver.removeGlobalOnLayoutListener(FListener); | ||
end; | ||
|
||
var | ||
VirtualKeyboardRect: TVirtualKeyboardRect; | ||
|
||
type | ||
TVirtualKeyboardAndroid = class; | ||
|
||
TVKListener = class(TJavaLocal, JVKStateChangeListener) | ||
private | ||
[Weak] FKeyboardService: TVirtualKeyboardAndroid; | ||
FEvent: TEvent; | ||
function ObtainKeyboardRect: TRect; | ||
public | ||
constructor Create(const AService: TVirtualKeyboardAndroid); | ||
destructor Destroy; override; | ||
procedure ResetEvent; | ||
procedure WaitEvent; | ||
{ JVKStateChangeListener } | ||
procedure onVirtualKeyboardShown; cdecl; | ||
procedure onVirtualKeyboardHidden; cdecl; | ||
end; | ||
|
||
TVirtualKeyboardAndroid = class(TInterfacedObject, IFMXVirtualKeyboardService) | ||
private type | ||
TvkbState = (Hidden, Shown); | ||
private | ||
FState: TvkbState; | ||
FVKListener: TVKListener; | ||
FTransient: Boolean; | ||
function IsAutoShow: Boolean; | ||
procedure SetState(Value: TvkbState); | ||
procedure RegisterListener; | ||
procedure RegisterService; | ||
procedure UnregisterService; | ||
public | ||
constructor Create; | ||
destructor Destroy; override; | ||
{ IFMXVirtualKeyboardService } | ||
function ShowVirtualKeyboard(const AControl: TFmxObject): Boolean; | ||
function HideVirtualKeyboard: Boolean; | ||
function GetVirtualKeyboardState: TVirtualKeyboardStates; | ||
procedure SetTransientState(Value: Boolean); | ||
property VirtualKeyboardState: TVirtualKeyboardStates read GetVirtualKeyboardState; | ||
end; | ||
|
||
implementation | ||
|
||
uses | ||
System.Messaging, FMX.Forms, FMX.Platform.Android, FMX.Platform; | ||
|
||
{ TAndroidVirtualKeyboardService } | ||
|
||
function TVirtualKeyboardAndroid.IsAutoShow: Boolean; | ||
begin | ||
Result := VKAutoShowMode in [TVKAutoShowMode.Always, TVKAutoShowMode.DefinedBySystem]; | ||
end; | ||
|
||
procedure TVirtualKeyboardAndroid.RegisterListener; | ||
begin | ||
if FVKListener = nil then | ||
begin | ||
FVKListener := TVKListener.Create(Self); | ||
MainActivity.getTextEditorProxy.addOnVKStateChangeListener(FVKListener); | ||
end; | ||
end; | ||
|
||
procedure TVirtualKeyboardAndroid.RegisterService; | ||
begin | ||
if not TPlatformServices.Current.SupportsPlatformService(IFMXVirtualKeyboardService) then | ||
TPlatformServices.Current.AddPlatformService(IFMXVirtualKeyboardService, Self); | ||
end; | ||
|
||
constructor TVirtualKeyboardAndroid.Create; | ||
begin | ||
inherited; | ||
RegisterService; | ||
end; | ||
|
||
destructor TVirtualKeyboardAndroid.Destroy; | ||
begin | ||
UnregisterService; | ||
inherited; | ||
end; | ||
|
||
function TVirtualKeyboardAndroid.GetVirtualKeyboardState: TVirtualKeyboardStates; | ||
begin | ||
Result := []; | ||
if IsAutoShow then | ||
Include(Result, TVirtualKeyboardState.AutoShow); | ||
if FTransient then | ||
Include(Result, TVirtualKeyboardState.Transient); | ||
if FState = TvkbState.Shown then | ||
Include(Result, TVirtualKeyboardState.Visible); | ||
end; | ||
|
||
function TVirtualKeyboardAndroid.HideVirtualKeyboard: Boolean; | ||
var | ||
TextView: JFMXTextEditorProxy; | ||
begin | ||
Result := False; | ||
try | ||
if not FTransient then | ||
begin | ||
RegisterListener; | ||
TextView := MainActivity.getTextEditorProxy; | ||
FVKListener.ResetEvent; | ||
TextView.setFocusable(false); | ||
TextView.setFocusableInTouchMode(false); | ||
TextView.showSoftInput(false); | ||
TextView.clearFocus; | ||
FVKListener.WaitEvent; | ||
Result := FState = TvkbState.Hidden; | ||
end | ||
except | ||
Application.HandleException(Screen.ActiveForm); | ||
end; | ||
end; | ||
|
||
function TVirtualKeyboardAndroid.ShowVirtualKeyboard(const AControl: TFmxObject): Boolean; | ||
var | ||
TextView: JFMXTextEditorProxy; | ||
begin | ||
RegisterListener; | ||
TextView := MainActivity.getTextEditorProxy; | ||
FVKListener.ResetEvent; | ||
TextView.setFocusable(true); | ||
TextView.setFocusableInTouchMode(true); | ||
TextView.requestFocus; | ||
TextView.showSoftInput(true); | ||
FVKListener.WaitEvent; | ||
Result := FState = TvkbState.Shown; | ||
end; | ||
|
||
procedure TVirtualKeyboardAndroid.UnregisterService; | ||
begin | ||
TPlatformServices.Current.RemovePlatformService(IFMXVirtualKeyboardService); | ||
end; | ||
|
||
procedure TVirtualKeyboardAndroid.SetState(Value: TvkbState); | ||
begin | ||
if FState <> Value then | ||
begin | ||
FState := Value; | ||
TMessageManager.DefaultManager.SendMessage(Self, | ||
TVKStateChangeMessage.Create(FState = TvkbState.Shown, FVKListener.ObtainKeyboardRect), True); | ||
end; | ||
end; | ||
|
||
procedure TVirtualKeyboardAndroid.SetTransientState(Value: Boolean); | ||
begin | ||
FTransient := Value; | ||
end; | ||
|
||
{ TVKListener } | ||
|
||
constructor TVKListener.Create(const AService: TVirtualKeyboardAndroid); | ||
begin | ||
inherited Create; | ||
FKeyboardService := AService; | ||
FEvent := TEvent.Create; | ||
VirtualKeyboardRect.VKListener := Self; | ||
end; | ||
|
||
procedure TVKListener.ResetEvent; | ||
begin | ||
FEvent.ResetEvent; | ||
end; | ||
|
||
procedure TVKListener.WaitEvent; | ||
begin | ||
FEvent.WaitFor(250); | ||
end; | ||
|
||
procedure WaitingForContentChanged(const Listener: TVKListener); | ||
// The only way to get correct keyboard size is waiting little bit to time when system changes ContentView properties | ||
// 1000ms maximum timeout. Usually it takes only one iteration. This procedure called from separated thread and main | ||
// thread not blocked. | ||
const | ||
MaxCounter = 20; | ||
SleepingTime = 50; | ||
var | ||
Counter: Integer; | ||
KeyboardRect: TRect; | ||
begin | ||
Counter := 0; | ||
KeyboardRect := Listener.ObtainKeyboardRect; | ||
while (KeyboardRect = Listener.ObtainKeyboardRect) and (Counter < MaxCounter) do | ||
begin | ||
Sleep(SleepingTime); | ||
Inc(Counter); | ||
end; | ||
end; | ||
|
||
procedure TVKListener.onVirtualKeyboardShown; | ||
begin | ||
//WaitingForContentChanged(Self); | ||
if VirtualKeyboardRect.CanFireEvent then | ||
TThread.Synchronize(nil, procedure | ||
begin | ||
FKeyboardService.SetState(TVirtualKeyboardAndroid.TvkbState.Shown); | ||
FEvent.SetEvent; | ||
end); | ||
else | ||
VirtualKeyboardRect.VirtualKeyboardShown; | ||
end; | ||
|
||
procedure TVKListener.onVirtualKeyboardHidden; | ||
begin | ||
TThread.Synchronize(nil, procedure | ||
begin | ||
FKeyboardService.SetState(TVirtualKeyboardAndroid.TvkbState.Hidden); | ||
FEvent.SetEvent; | ||
end); | ||
VirtualKeyboardRect.VirtualKeyboardHidden; | ||
end; | ||
|
||
destructor TVKListener.Destroy; | ||
begin | ||
FEvent.Free; | ||
inherited; | ||
end; | ||
|
||
function TVKListener.ObtainKeyboardRect: TRect; | ||
var | ||
ContentRect, TotalRect: JRect; | ||
begin | ||
ContentRect := TJRect.Create; | ||
TotalRect := TJRect.Create; | ||
MainActivity.getWindow.getDecorView.getWindowVisibleDisplayFrame(ContentRect); | ||
MainActivity.getWindow.getDecorView.getDrawingRect(TotalRect); | ||
Result := TRectF.Create(ConvertPixelToPoint(TPointF.Create(TotalRect.left, TotalRect.top + ContentRect.height)), | ||
ConvertPixelToPoint(TPointF.Create(TotalRect.right, TotalRect.bottom))).Truncate; | ||
end; | ||
initialization | ||
VirtualKeyboardRect := TVirtualKeyboardRect.Create; | ||
end. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.