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
Post a Comment