[futurebasic] Re: [FB] Intercepting backspace and delete in a HITextView

Message: < previous - next > : Reply : Subscribe : Cleanse
Home   : January 2010 : Group Archive : Group : All Groups

From: Brian S <fblistserve@...>
Date: Thu, 28 Jan 2010 10:52:38 -0700
On Jan 28, 2010, at 9:08 AM, Ken Shmidheiser wrote:

> Gentlemen,
>
> I have a HITextView in a nib that is filtered to allow the user to  
> enter numeric data for a calculation. I can capture each of the  
> keystrokes of "0123456789.-" and perform real-time updates with the  
> data in the field.
>
> However, I would like to detect backspaces and/or deletes and also  
> perform real-time updates as data is deleted. I have tried  
> intercepting using the uniChars 8 and 127 without success. I would  
> think I could do this with CallNextEventHandler, and as wondering if  
> anyone had a code snippet to help me.

Ken,

I haven't written anything new in this area in a while but here is  
some code that works in one of my shareware apps. It is not a running  
demo but just a cut/paste of the relevant code. Time is short the next  
few days or I would have written a demo for you. The code filters the  
entry of mileage entered into a EUTC and enters the thousands  
separator ( comma in USA but '.' elsewhere ) automatically as the user  
types. Sorry for mess of functions but should provide some clues.  
Again, this is not the most modern code but is CE and works. I'll  
check my email this evening to see how you are doing.  Take  
care.....Brian

In the FN that builds the window:

c = fn GetControlByIDWrapper (w, _serviceMileage)
fn InstallServiceMileageFilter( c )
err = fn SetWindowProperty( w, _"VMTD", _"tSMD", sizeof( ControlRef ),  
@c ) // save controlRef for fn FormatServiceMileage

and

Register for _kEventTextDidChange for the service mileage field

fn CEAddEvent( _kEventClassTextField, _kEventTextDidChange )
fn CEInstallControlEventHandler( c, @fn ControlHandlerForTabWindow,  
_serviceMileage, 0  )

In ControlHandlerForTabWindow:

eventKind = fn GetEventKind( theEvent )
w = fn GetFrontWindowOfClass( _kDocumentWindowClass, _true ) // get  
the window ref

select eventKind
case _kEventTextDidChange
select
case ( btnNum == _serviceMileage )
fn FormatServiceMileage( w ) //<<<<<<<<<<<<< this is where the mileage  
is formatted with a comma
result = _noErr
end select



Here is the EUTC filter fn:

local fn InstallServiceMileageFilter( c as ControlRef )
'~'1
dim as OSStatus      err
dim as proc          filterProc

filterProc = @fn MyServiceMileageFilterProc
err = fn SetControlData( c, _kControlEditTextPart,  
_kControlEditTextKeyFilterTag, sizeof( proc ), @filterProc )

end fn

Utility fn to get the ControlRef/HIViewRef

local fn GetControlByIDWrapper (w as WindowRef, id as SInt32) as  
ControlRef
dim as ControlID     cID
dim as ControlRef    c

cID.signature = 0
cID.id = id
call GetControlByID( w, cID, @c )

end fn = c


local fn MyServiceMileageFilterProc( c as ControlRef, keyCode as  
^SInt16,charCode as ^SInt16, modifiers as ^EventModifiers )
'~'1
dim as SInt16        ch, result     : result = _kControlKeyFilterPassKey
dim as UInt32        textLen
dim as OSStatus      err

ch = charCode.nil%
err = fn GetControlDataSize( c, _kControlEditTextPart,  
_kControlEditTextTextTag, @textLen )

select
case ( ch == _fbDeleteKey or ch == _fbLeftArrowKey or ch ==  
_fbRightArrowKey ) : result = _kControlKeyFilterPassKey
case ( ch >= _"0" ) and ( ch <=  
_"9" )                                         : result =  
_kControlKeyFilterPassKey
case ( ch ==  
gCommaChar )                                                      :  
result = _kControlKeyFilterPassKey
case else
result = _kControlKeyFilterBlockKey :beep   //block keystroke and give  
them audible feedback
end select
// nine characters #,###,###   is the maximum so prevent the 10th from  
being entered.
if ( textLen == 9 and ch != _fbDeleteKey and ch != _fbLeftArrowKey and  
ch != _fbRightArrowKey ) then result = _kControlKeyFilterBlockKey : beep
end fn = result


local fn FormatServiceMileage( w as WindowRef )
'~'1
dim as ControlRef     c
dim as OSStatus       err
dim as Str31          s
dim as SInt16         oStr, nStr : oStr = 0 : nStr = 0
dim as UInt32         nbr


err = fn GetWindowProperty( w, _"VMTD", _"tSMD", sizeof( ControlRef ),  
#_nil, @c ) // retrieve controlRef
s   = fn GetControlRefText$( c )


s = fn RemoveCommasFromString$( s )
nbr = val&( s )
s = fn FormatMileage$( nbr  )
err = fn SetControlData( c, _kControlButtonPart,  
_kControlEditTextTextTag, s[0], s[1] )

end fn
local fn TrimLeadingSpaces$( s as Str255 )
'~'1
dim as SInt16     i     : i = 1

while  ( s[i] == _" " )
i++
wend

s = mid$( s, i )
end fn = s

local fn RemoveCommasFromString$( t as Str255 )
'~'1
dim as SInt16         oStr, nStr : oStr = 0 : nStr = 0
dim as Str255         s     : s = t

while ( oStr < s[0] )
oStr++
if s[oStr] != gCommaChar then nStr++ : s[nStr] = s[oStr]
wend
s[0] = nStr// set length of pascal string

end fn = s

local fn FormatMileage$( nbr as UInt32 )
'~'1
dim as Str255     s

long if ( nbr > 0 )
s = using "#,###,###";nbr
s = fn TrimLeadingSpaces$( s )
xelse
s = ""// makes zero blank
end if


end fn = s

Brian S