Get KeyDown messages as they happen from SoftKeyboard in Delphi on Android -


hiyas.

i'm wanting know keys user pressing, press them in delphi app on android (from soft/virtual keyboard).

i've got bit of code show keyboard in form's onshow event , wired other code in onkeydown event onkeydown event fired when user presses enter not press each key.

do using addtextlistener on jfmxtexteditorproxy of jfmxnativeactivity? work, if have no views/edit controls (just form on i'm rendering image).

can assist?

tia.

daniel.

oh dear, long haul.

i have code working now. there may still bugs in odd corner cases i've done best test them.

in example code, place keys pressed (including enter , delete key presses) tqueue in form , display them in label (one one). adapt code produce events instead. beware of threading issues.

to code working, you'll need blank firemonkey application targeting android. place 3 labels on form , name "testkeydownmainform". name unit "formtestkeydownmain". place timer.

make label1 caption, label2 display area , label3 header. set timer every 30ms or (more if want). paste in code (replacing that's there) , connect oncreate, onshow, ondestroy , onkeydown events form , ontimer event timer. should able figure out if haven't been entirely specific.

unit formtestkeydownmain;  interface  uses     system.sysutils, system.types, system.uitypes, system.classes, system.variants,     system.syncobjs, system.generics.collections,     androidapi.appglue,     androidapi.nativeactivity,     androidapi.jnibridge,     androidapi.jni.javatypes,     androidapi.jni.graphicscontentviewtext,     androidapi.jni.embarcadero,     fmx.helpers.android,     fmx.types, fmx.controls, fmx.forms, fmx.graphics, fmx.dialogs,     fmx.controls.presentation, fmx.stdctrls;  type     ttextlistener = class(tjavalocal, jfmxtextlistener)     private         flastlen,         flastenter,         flastaddskip,         faddskip: integer;         fwasendword,         fwasdelete,         fwasenter,         fgotspace,         fcomposing: boolean;         flastchar: char;         fhistory: tstack<char>;         flock: tcriticalsection;      public         constructor create;         destructor  destroy; override;          procedure oncomposingtext(beginposition: integer; endposition: integer); cdecl;         procedure onskipkeyevent(event: jkeyevent); cdecl;         procedure ontextupdated(text: jcharsequence; position: integer); cdecl;     end;      ttestkeydownmainform = class(tform)         label1: tlabel;         label2: tlabel;         timer1: ttimer;         label3: tlabel;         procedure formshow(sender: tobject);         procedure timer1timer(sender: tobject);         procedure formkeydown(sender: tobject; var key: word; var keychar: char;                 shift: tshiftstate);         procedure formcreate(sender: tobject);         procedure formdestroy(sender: tobject);     private         ffmxact: jfmxnativeactivity;         ffmxtxp: jfmxtexteditorproxy;         ftxtlsn: ttextlistener;          fcharcs: tcriticalsection;         fcharin: tqueue<char>;      public         { public declarations }     end;  var     testkeydownmainform: ttestkeydownmainform;  implementation  {$r *.fmx}  { ttextlistener }  constructor ttextlistener.create;     begin     inherited;      flock:= tcriticalsection.create;      flastenter:= -1;     flastlen:= 0;     flastaddskip:= 0;     faddskip:= 0;     fwasendword:= false;     fgotspace:= false;     fcomposing:= false;      fhistory:= tstack<char>.create;     end;  destructor ttextlistener.destroy;     begin     fhistory.clear;     fhistory.free;      flock.free;      inherited;     end;  procedure ttextlistener.oncomposingtext(beginposition, endposition: integer);     begin     flock.acquire;     try         fcomposing:= true;          if  beginposition > 0             faddskip:= beginposition;                  flock.release;         end;     end;  procedure ttextlistener.onskipkeyevent(event: jkeyevent);     begin     end;  procedure ttextlistener.ontextupdated(text: jcharsequence; position: integer);     var     i,     skip,     l,     t: integer;     s: string;      begin     flock.acquire;     try         l:= text.length;         s:= string(text.tostring);          skip:= 3;         i:= l - 3;         while >= 10             begin             i:= div 10;             inc(skip);             end;          if  faddskip > (l - 3)             faddskip:= 0;         inc(skip, faddskip);          t:= l - skip;          fwasdelete:= (not fwasendword) , (not fgotspace) ,                 ((t = 0) or (t < flastlen) or ((flastlen <= 0) ,                 (flastaddskip > faddskip)));         if  (not fwasdelete)         , fgotspace         , (faddskip = flastaddskip)         , (t <= flastlen)             fwasdelete:= true;          fwasendword:= (not fwasdelete) , (not fgotspace) , (flastlen = t) ,                 (skip < l);         if  (not fwasendword)         , (not fcomposing)         , fwasenter             fwasendword:= true         else if  fwasendword         , (fhistory.count > 0)         , (fhistory.peek = #13)             begin             fwasdelete:= true;             fwasendword:= false;             end;          fwasenter:= false;         fcomposing:= false;          flastlen:= t;         flastaddskip:= faddskip;          if  fwasendword             exit         else if fwasdelete             flastchar:= #07         else             flastchar:= text.charat(l - 1);          fgotspace:= flastchar = ' ';          if  fwasdelete             begin             if  fhistory.count > 0                 fhistory.pop             end         else             fhistory.push(flastchar);          testkeydownmainform.fcharcs.acquire;         try             testkeydownmainform.fcharin.enqueue(flastchar);                          testkeydownmainform.fcharcs.release;             end;                 flock.release;         end;     end;   { tform1 }  procedure ttestkeydownmainform.formcreate(sender: tobject);     begin     ffmxact:= tjfmxnativeactivity.wrap(pandroid_app(panativeactivity(delphiactivity)^.instance)^.activity.clazz);     ffmxtxp:= ffmxact.gettexteditorproxy;      fcharcs:= tcriticalsection.create;     fcharin:= tqueue<char>.create;      ftxtlsn:= ttextlistener.create;      ffmxtxp.addtextlistener(ftxtlsn);     end;  procedure ttestkeydownmainform.formdestroy(sender: tobject);     begin     ffmxtxp.removetextlistener(ftxtlsn);      ftxtlsn.free;     fcharin.free;     fcharcs.free;     end;  procedure ttestkeydownmainform.formkeydown(sender: tobject; var key: word; var keychar: char;         shift: tshiftstate);     begin     ftxtlsn.flock.acquire;     try         if  not ftxtlsn.fwasdelete             begin             ftxtlsn.fwasenter:= true;             ftxtlsn.fwasendword:= false;              ftxtlsn.fhistory.push(#13);              ftxtlsn.flastchar:= #13;             ftxtlsn.flastenter:= ftxtlsn.flastlen;              fcharcs.acquire;             try                 fcharin.enqueue(ftxtlsn.flastchar);                                  fcharcs.release;                 end;             end;          ftxtlsn.fwasdelete:= false;         ftxtlsn.fcomposing:= false;                  ftxtlsn.flock.release;         end;     end;  procedure ttestkeydownmainform.formshow(sender: tobject);     begin     label2.text:= '';      callinuithread(procedure         begin         ffmxtxp.setfocusable(true);         ffmxtxp.setfocusableintouchmode(true);         ffmxtxp.requestfocus;         ffmxtxp.showsoftinput(true);         end);     end;  procedure ttestkeydownmainform.timer1timer(sender: tobject);     var     c: char;      begin     fcharcs.acquire;     try         while fcharin.count > 0             begin             c:= fcharin.dequeue;             if  c = #13                 begin                 label3.text:= 'got enter';                 label2.text:= label2.text + #13;                 end             else if c = #07                 begin                 label3.text:= 'got delete';                 label2.text:= copy(label2.text, low(label2.text), length(label2.text) - 1);                 end             else                 begin                 if  c = ' '                     label3.text:= 'got space'                 else                     label3.text:= 'got regular';                 label2.text:= label2.text + c;                 end;             end;                  fcharcs.release;         end;     end;  end. 

if @ code, quite hideous. not because haven't commented because of hoops had go through key press sequence (please excuse ancient - algol - strict block style). if can come better way, i'd sure see it! '[nn]' tags in sequence, anyway??

i haven't tried test using real keyboard, soft/virtual keyboard. i'm pretty sure shift, alt , control keys kill logic. however, if need support should able start examining event parameter of onskipkeyevent.

it should possible use code without fmx framework well, long can show soft keyboard (by replacing callinuithread). believe you'll need hook logic in onkeydown event oninputevent of application instead. i'll trying next.

enjoy.

daniel.

edit:

my apologies everywhere "delete" should "backspace". hope doesn't cause confusion.

unfortunately, have found more cases code doesn't work. example pressing enter after backspace. have fix case there more. trying find code work i'm concerned won't able come code functions reliably.


Comments

Popular posts from this blog

get url and add instance to a model with prefilled foreign key :django admin -

css - Make div keyboard-scrollable in jQuery Mobile? -

ruby on rails - Seeing duplicate requests handled with Unicorn -