The Enter key and the OnKeyDown/OnKeyUp events on Android

A problem surfaced on Stack Overflow recently from a Delphi developer, Tom Byrnes, who discovered that on Android, the Enter (or Return) key no longer triggers the OnKeyDown and OnKeyUp events. This was unfortunate as Tom wanted to code to run in (one of) those handlers.The problem had been reported as RSP-27496 but alas it had been closed at the time Tom was hunting for a solution (to my mind closed wrongly).What to do?Well, after some valiant fighting with the problem accompanied with the inevitable wailing and gnashing of teeth, Tom found a workaround of sorts. Setting the TEdit control's ReturnKeyType property Go, Search or Send allows the OnKeyDown event to fire for the Enter key. Good stuff! But not ideal....I sent a note to a relevant party within EMBT and after reviewing the report it has since been re-opened. That's a start.To try and be a bit more helpful I'd like to offer a solution to having the Enter key get OnKeyDown and OnKeyUp events triggered. This involves editing one of the Java files that underpins the Delphi Android FireMonkey. implementationThe default RAD Studio installation for 10.3.3 is to C:\Program Files (x86)\Embarcadero\Studio\20.0. If we assume an environment variable BDS is set to that value (as it is in a RAD Studio Command Prompt) then the Java source files can be found in:%BDS%\source\rtl\androiddex\java\fmx\src\com\embarcadero\firemonkeyThe file of interest is in a subfolder and is:text\FMXEditText.javaso to put it another way:%BDS%\source\rtl\androiddex\java\fmx\src\com\embarcadero\firemonkey\text\FMXEditText.javaIn this file just over halfway down is a routine called onEditorAction, which needs a slight tweak. It's only a short subroutine, but if you examine the logic you'll appreciate that it contains a condition with some logic in the if section and some more logic in the else section.The required change is to remove the else section and leave the logic currently contained there to run unconditionally. I don't want to copy out code from the RTL to avoid transgressing any inappropriate boundaries, but if the code currently looks like this:public void onEditorAction(int actionCode) { if (condition) { // if block } else { // else block }}we want to alter it to look like this:public void onEditorAction(int actionCode) { if (condition) { // if block } // else block}Assuming this is all done, what next?Well the next step is to rebuild all the Java files and replace the compiled Java archives with the updated re-compiled ones. Fortunately I can help out there. I posted yesterday a full command script that will do just this exact job, so please make use of that to follow the required steps to get the fix.Once you have run the script to generate new Java archives and re-built and re-run your Android app your events should trigger on Android when you press the soft Enter key.One final thing: don't forget to backup the original Java archive files before running the script as mentioned in the post!
Read More

Rebuilding the Delphi & C++Builder Android Java files

Some while back I posted a command script (or batch file as we used to call them) that could be used by RAD Studio 10.3 users if they felt the need to change any of the few Java files underlying Delphi's (and C++Builder's) Android RTL and FireMonkey code.The script would rebuild all the Java files into the required fmx.dex.jar and fmx.jar archives and copy them into the relevant RAD Studio installation folders to be used on subsequent builds.When I tried to use the script with RAD Studio 10.3.3 of course it didn't work as things have changed, different files need to be involved in the process. I have updated the script now to work with RAD Studio 10.3.3 and thought I'd share it in case anyone else needs to do this.An obvious question is: Why would anyone else want to rebuild the Java Android RTL files? Well this is normally a necessary step if you find an issue in the code as Embarcadero ships it and you want to try to fix it or enhance it. Indeed the previous post on rebuilding the 10.3 Java files was all about patching the Java code to get Android Intent support working.If you have no interest in tweaking the Java code or fixing any issues you encounter in the Java code then you probably won't be needing this script.If you do need the script, remember to take a backup of your original compiled archives before you proceed. These are found in:C:\Program Files (x86)\Embarcadero\Studio\20.0\lib\android\debug\fmx.jarC:\Program Files (x86)\Embarcadero\Studio\20.0\lib\android\debug\fmx.dex.jarC:\Program Files (x86)\Embarcadero\Studio\20.0\lib\android\release\fmx.jarC:\Program Files (x86)\Embarcadero\Studio\20.0\lib\android\release\fmx.dex.jarThe script needs to be run from an administrative command prompt and before you run it you should double-check the various paths set up in the environment variables at the start are all valid on your system.The script can be found below (apologies for any layout issues caused by longer lines than the narrow blog width); hat-tip and thanks to Tom Byrnes for test-driving it:@echo offclsrem Android RTL Java files rebuilder for RAD Studio 10.3.3setlocal enabledelayedexpansionrem Set environment variablesrem *NOTE*: check these folders match your setupset EMBT=Embarcadero\Studio\20.0set BDS=%ProgramFiles(x86)%\%EMBT%set JAVA_PATH=%ProgramFiles%\Java\jdk1.8.0_60\binrem This is the default path for the Android SDK when installed from the .iso installerset SDK_PATH=%PUBLIC%\Documents\%EMBT%\PlatformSDKs\android-sdk-windowsif not exist "%SDK_PATH%\" ( rem This is the default path for the Android SDK when installed from the web install (aka ESD install) set SDK_PATH=%PUBLIC%\Documents\%EMBT%\CatalogRepository\AndroidSDK-2525_20.0.36039.7899)rem Set more environment variables based on those aboveset DX_PATH=%SDK_PATH%\build-tools\28.0.2set ANDROID_JAR=%SDK_PATH%\platforms\android-26\android.jarset BDS_LIB=%BDS%\libset BDS_DEBUG_LIB=%BDS%\lib\android\debugset BDS_RELEASE_LIB=%BDS%\lib\android\releaseset FMX_SRC_PATH=%BDS%\source\rtl\androiddex\java\fmxset CLASS_PATH=%ANDROID_JAR%set CLASS_PATH=%CLASS_PATH%;%BDS_DEBUG_LIB%\android-support-v4.jarset CLASS_PATH=%CLASS_PATH%;%BDS_DEBUG_LIB%\cloud-messaging.jarset CLASS_PATH=%CLASS_PATH%;%BDS_DEBUG_LIB%\com-google-android-gms.play-services-base.16.0.1.jarset CLASS_PATH=%CLASS_PATH%;%BDS_DEBUG_LIB%\com-google-android-gms.play-services-maps.16.1.0.jarset CLASS_PATH=%CLASS_PATH%;%BDS_DEBUG_LIB%\debug\com-google-android-gms.play-services-ads.17.2.0.jarrem For adListenerset CLASS_PATH=%CLASS_PATH%;%BDS_DEBUG_LIB%\com-google-android-gms.play-services-ads-lite.17.2.0.jarrem For AbstractSafeParcelableset CLASS_PATH=%CLASS_PATH%;%BDS_DEBUG_LIB%\com-google-android-gms.play-services-basement.16.2.0.jarrem For ReflectedParcelableset CLASS_PATH=%CLASS_PATH%;%BDS_DEBUG_LIB%\com-google-android-gms.play-services-basement.16.2.0.jarecho.echo Checking environment variablesif not exist "%BDS%\" ( echo Path used to set BDS environment variable does not exist^^! Is RAD Studio installed elsewhere? goto :Error)if not exist "%JAVA_PATH%\" ( echo Path used to set JAVA_PATH environment variable does not exist^^! Is the JDK installed elsewhere? goto :Error)if not exist "%SDK_PATH%\" ( echo Path used to set SDK_PATH environment variable does not exist^^! Is the Android SDK installed elsewhere? goto :Error)if not exist "%ANDROID_JAR%" ( echo Path used to set ANDROID_JAR environment variable does not exist^^! Is your android.jar in a different platform folder? goto :Error)echo.echo Changing to the FMX source folderecho.pushd %FMX_SRC_PATH%echo Getting fully qualified list of all Java source file we need to rebuildecho.if not exist bin\classes mkdir bin\classesif not exist bin\debug mkdir bin\debugif not exist bin\release mkdir bin\releasedir src\android\bluetooth\*.java /s /b > JavaSources.txtdir src\android\telephony\*.java /s /b >> JavaSources.txtdir src\com\*.java /s /b >> JavaSources.txtecho Ensuring FMX source path ends in a '\'echo.set LAST_CHAR=%FMX_SRC_PATH:~-1%if not "%LAST_CHAR%"=="\" set FMX_SRC_PATH=%FMX_SRC_PATH%\echo Making Java source file paths relative to current directoryecho.if exist JavaSources2.txt del JavaSources2.txtfor /F "tokens=*" %%A in (JavaSources.txt) do ( set STR=%%A set "STR=!STR:%FMX_SRC_PATH%=!" echo !STR!>>JavaSources2.txt)echo Compiling all the FMX Java code into class files with debug infoecho."%JAVA_PATH%"\javac -g -d bin\classes -classpath "%CLASS_PATH%" -encoding UTF-8 -g @JavaSources2.txtif errorlevel 1 ( echo. echo Problem encountered during Java compilation goto :Error)echo.echo Creating jar containing the new compiled FMX Java classes with debug infoecho."%JAVA_PATH%"\jar cf bin\debug\fmx.jar -C bin\classes .if errorlevel 1 ( echo. echo Problem encountered during Java archiving goto :Error)echo Creating DEX jar containing the new compiled FMX Java classes with debug infoecho.call %DX_PATH%\dx --dex --output=bin\debug\fmx.dex.jar --positions=lines bin\debug\fmx.jarif errorlevel 1 ( echo. echo Problem encountered during DEXing goto :Error)echo Compiling all the FMX Java code into class files without debug infoecho."%JAVA_PATH%"\javac -g:none -d bin\classes -classpath "%CLASS_PATH%" -encoding UTF-8 @JavaSources2.txtif errorlevel 1 ( echo. echo Problem encountered during Java compilation goto :Error)echo.echo Creating jar containing the new compiled FMX Java classes without debug infoecho."%JAVA_PATH%"\jar cf bin\release\fmx.jar -C bin\classes .if errorlevel 1 ( echo. echo Problem encountered during Java archiving goto :Error)echo Creating DEX jar containing the new compiled FMX Java classes without debug infoecho.call %DX_PATH%\dx --dex --output=bin\release\fmx.dex.jar --positions=lines bin\release\fmx.jarif errorlevel 1 ( echo. echo Problem encountered during DEXing goto :Error)copy bin\debug\* "%BDS_DEBUG_LIB%"copy bin\release\* "%BDS_RELEASE_LIB%"echo Tidying up...echo.if exist JavaSources.txt del JavaSources.txtif exist JavaSources2.txt del JavaSources2.txtrd /s /q bingoto :End:Errorecho.echo Sorry, we had a problem :(echo.:Endecho Changing back to the folder we started inpopdendlocal
Read More

Questioning Your Software Design Assumptions

While it is likely this post can stir some controversy, among my friends who are more "purist of design rules", I think a dicussion is well worth.  I was searching totally unrelated information, when I hit the web site of my long time friend Bruce Eckel (of Thinking in Java and Thinking in C++ fame) and read this very interesting blog post: Unspoken Assumptions Underlying OO Design Maxims In the post Bruce refers to and comment this blog post by Julia @coding: Flexible code considered harmful Both are quite interesting, even if I don't agree in full I think they have a point. It is true developer very often over-architect their code in light of future extensions, resuming they know how the requirements will change and how they'll be able to extend the software because of their nice architecture. But how often this is true compared the times the software is never extended into that direction -- but in a different one -- and the over-architecture becomes immediately a cumbersome technical debt making negatively affecting other changes required (but unexpected)? From Julia's blog, I find this provocative but honestly quite relevant: "Keep in mind that speed is achieved by writing simple and direct code with as few abstractions as possible." This is a thing I countered to the "RAD = bad design" crowd out there. I think this particularly applies to some over-designed JavaScript libraries out there, even though I'm far from an expert in the JavaScript world. Not don't take me wrong, it totally depends on the task at hand, the size of the application, and the requirements you are starting from. Honestly, it is another way of stating the KISS principle: Keep It Simple, Stupid! Now, considering Bruce blog post he underlines some unspoken assumptions we have as developers (and software architects): "We somehow know how a system will change" "Abstractions are always worth their cost" We need to question these assumption, and consider if they apply to the task at hand. It is not they are always false, but also they are not always true. What I found particularly interesting is his comment about "programming against interfaces" and how this rule got morphed from "interface" as a concept to "interface" as a keyword. He refers to Java, but I've seen that applied to Delphi quite often. Now it is undeniable that an interface (in the language) offers much looser coupling than a class "interface" (the collection of public methods and properties) or a unit "interface" (type and symbols exposed by a unit and declared in the interface section), but all three scenarios account for "programming against an interface" in the original terms of the concept. Am I saying you should not use interfaces? Absolutely not, it is a great language feature and helps reduce coupling and creating better and more flexible systems. What I'm saying is that the interface keyword should not be the only abstraction you code against in a Delphi application. I really like the final recommendation by Bruce Eckel, which I'll rephrase as: ​If you can only justify an abstraction by #34ing a maxim, take it out!  Happy coding ;-)
Read More

The magic Delphi ReturnAddress intrinsic

I could not find any official place where ReturnAddress is documented even though it is used at quite a few places in the RTL, VCL, FMX and 3rd party libraries like DUnitX, Spring4D, JCL, ReportBuilder, TeeChart. I tried searching it in the contexts of Delphi 2007, Delphi 2009, but there is only a [Archive.is] different System.ObjAuto.TParameters.ReturnAddress documented in XE2 and higher. procedure Abort; begin raise EAbort.CreateRes(@SOperationAborted) at ReturnAddress; end; There is a (usually broken*) ReturnAddr function used in various places of the RTL/VCL/FMX and (therefore wrongfully copied) in many other peoples code. function ReturnAddr: Pointer; // From classes.pas asm MOV EAX,[EBP+4] // sysutils.pas says [EBP-4], but this works ! end; See the above link; I think this was fixed in Delphi XE, but the issue is still open. Related to the above is the documented ExceptAddr. I’ve used this in my ExceptionHelperUnit to build a GetStackTrace function in the example gist below. I found these posts documenting the behaviour of the above intrinsic functions and more: [WayBack] Undocumented Delphi routines – Chee Wee’s blog: IT solutions for Singapore and companies worldwide [WayBack] delphi – Undocumented intrinsic routines – Stack Overflow [WayBack] Delphi sorcery: New language feature in XE7 [WayBack]  What’s New in Carpathia Beta 1 [WayBack] exception – What does `at ReturnAddress` mean in Delphi? – Stack Overflow *[WayBack] QualityCentral Report #71294: Almost all occurrences of ReturnAddr are broken (Status: Open) –jeroen .gist table { margin-bottom: 0; }
Read More

Dual boot UEFI Windows 10/Linux Mint 19.3 system

After 2 years without Windows, I decided to assemble a desktop with dual Windows 10 / Linux Mint 19.3 boot. I remember making Windows/Ubuntu dual boot system was a pain in the ass since UEFI replaced good old BIOS; but times changed, and I was surprised how smooth and easy is making UEFI dual boot system now. I used ASUS PRIME 365M-K motherboard for my desktop; I think all modern ASUS motherboards have the same UEFI support. You install Windows 10 first. I used brand new HDD, and I allocated half of HDD for Windows and left the rest of HDD unpartitioned. Windows created several partitions in the allocated area, the most important for dual boot is EFI partition which Windows labelled “System” or like that; it will be relabelled as “EFI” subsequently by Linux Mint installation program. Now you install Linux Mint 19.3. When asked how to install Linux Mint, I have chosen default “Install alongside Windows” option. This is a preferable option unless you want a third system on your HDD. If you google “Dual boot Windows Ubuntu UEFI” now, you probably find recommendations to disable Secure boot and do other strange things. I believe this staff is outdated for modern hardware and latest Ubuntu or Mint versions, and all you need is just run installation programs.
Read More

Some ideas on using DataSnap as a data-conversion layer between two systems

For my link archive as it contains some interesting ideas on how to use DataSnap as a conversion later between two systems: [WayBack] I need to write some DataSnap “middleware” between Google Glass and a SwissLog ERP system, and I am trying to figure out if there are significant differ… – Lars Fosdal – Google+ The ideas is basically a session based protocol converter. –jeroen
Read More

Next generation cross-platform components

Our team is very hard at work to continue to extend and improve our products, extend the documentation and make new demos.
We do this on a daily basis to make sure we offer you the best solution for your projects!

In 2019 we focused primarily on our FNC framework. Not only improving our existing components, but also adding new products, such as the TMS FNC Cloud Pack, TMS FNC Dashboard Pack, …

And that because we truly believe that FNC is the next generation cross-platform framework!

Our FNC development originated from our vast experience and deep technical expertise developing FMX components since it first appeared in Delphi in 2011 and as it became available in TMS FMX UI Pack, TMS FMX Chart and TMS FMX Cloud Pack.
We developed it because with our experience, we thought there was a better way to create cross-platform UI controls.

The most important differences between FMX and FNC are:

  • Architecture based on orginal FireMonkey classes
     
  • Not easy to extend/customize
     
  • Performance is hard to achieve when complex UI controls involve many objects
  • Basic design-time integration
  • Supports the FMX framework only
  • New independent architecture built-up from scratch
  • Easily extendible with many customization options/events
  • Faster performance, high quality graphics
  • Enhanced design-time integration
  • Supports multiple frameworks (FMX, VCL, LCL and WEB)
  • High level of compatibility with older FMX code

TMS FNC components can be simultaneously used on these 4 frameworks:

TMS FNC components can be simultaneously used on different operating systems and browsers:

Unique advantages of FNC

  • an easy maintainable single-source cross-framework/cross-platform code base
  • seamless integration in new and existing applications, can be mixed with other regular FMX or VCL controls
  • high performance and high quality graphics
  • intuitive & consistent property layout to smoothen the learning curve
  • only 1 license & only 1 learning curve to create applications for VCL, FMX, LCL and WEB

Large range of FNC controls available

  • TMS FNC Blox: Add diagram and flowchart capabilities to your application.
  • TMS FNC Chart: Fully cross-platform chart for business, statistical, financial & scientific data
  • TMS FNC UI Pack: Powerful, feature-rich UI controls for 4 frameworks and 5+ operating systems
  • TMS FNC Dashboard Pack: Create dashboard applications for Windows, cross-platform and the web
  • TMS FNC Cloud Pack: Seamless access to cloud services from Windows, cross-platform and the web
  • TMS FNC Component Studio: Our time & cost saving bundle of all FNC components

Looking for components to enhance your cross-platform project? We invite you to visit the TMS FNC landing page where more information is provided, including key features, demos and more…

Upgrade your license to TMS FNC components and take advantage of the different possibilities to develop extraordinary projects.

Eager to try out our FNC components?

Contact sales@tmssoftware.com for the best discount upgrade offer depending on your currently purchased products.

Read More

Read More

Delphi Datasnap: How to know the name of the methods called by client in delphi datasnap server?

A great tip from [WayBack] Hi, need help regarding Datasnap. How to know the name of the methods called by client in delphi datasnap server? – sujansiddhi – Google+ that I needed a few months ago: Walter Prins: Inside TDSAuthenticationManager.OnUserAuthorize, inspect the EventObject.MethodAlias property. (Obviously once the method is actually called you implicitly know the methodname.) This was introduced in Delphi XE: [Archive.is] DSAuth.TDSAuthenticationManager.OnUserAuthorize – XE API Documentation [Archive.is] Authentication and Authorization – RAD Studio XE –jeroen
Read More