Jump to content

get(triggerkeystroke)


This topic is 3345 days old. Please don't post here. Open a new topic instead.

Recommended Posts

Hi all

 

Trying to use some key commands in the navigation of my database. In list view I have the character "e" (for Edit - char 101) set to open up a separate window where the selected record can be edited via a script that is activated by the OnLayoutKeystroke script trigger. The command works, however I'm presented with the "Before typing, press Tab or click in a field, or choose the New Record Command..." FileMaker dialogue box once the script has finished running. I've tried using Set Error Capture On to prevent this but I'm failing. 

 

Any advice?

Link to comment
Share on other sites

Here is my script. It is triggered by OnLayoutKeystroke. All other aspects of the script work without any error messages, except for the final If statement when induced by the keystroke "e" where I get the message I stated in my OP.

​Set Error Capture [On]
Set Variable [$code; Value: Code (Get(TriggerKeystroke))]
If [$code = 27]
Perform Script ["close window"]
Else
If [$code = 29]
Go to Record/Request/Page [Previous]
Else
If [$code = 31]
Go to Record/Request/Page [Next]
Else
If [$code = 10 or $code = 13]
Perform Script ["open asset record"]
Else
If [$code = 101]
Perform Script ["modify asset information"]
End If
End If
End If
End If
End If
Link to comment
Share on other sites

If you are not really typing anything in the sense that FM has to store your typed character then you need to exit the OnLayoutTrigger script with:

 

Exit Script[ False ]     --> note: no quotes around the false, it is a true boolean

 

That makes FM "eat" the keystroke.  OnLayoutKeystorke is a pre-event.  If you let the actual event happen, FM tries to put the "e" somewhere but since you are not in a field, you get the message that you are getting.

Link to comment
Share on other sites

Hi,

 

I have yet to try your script...

General question : what is the reason you are using a nested if in stead of 

Set Error Capture [On]

Set Variable [$code; Value: Code (Get(TriggerKeystroke))]
If [$code = 27]
Perform Script ["close window"]
Else If [$code = 29]
Go to Record/Request/Page [Previous]
Else If [$code = 31]
Go to Record/Request/Page [Next]
Else If [$code = 10 or $code = 13]
Perform Script ["open asset record"]
Else If [$code = 101]
Perform Script ["modify asset information"]
End If

Link to comment
Share on other sites

Wim, thank you! Will try your approach.

 

Joost, good question. Didn't even cross my mind. This script was written a long time ago and I have only just reopened it to add this particular function. I will take your advice and tidy it up.

Link to comment
Share on other sites

Hi guys

 

Additionally, is there a way to preface the script to detect if it is in an active field? I know this isn't necessarily the "traditional" way to navigate layouts by using key commands, but the key commands in the script I originally wrote should only be active if the cursor isn't in an active field.

Link to comment
Share on other sites

If you are on an active object, the OnObjectKeystroke will fire before the OnLayoutKeystroke.

 

Use Get(ActiveFieldName) in the OnLayoutKeystroke to exit the script, but exit with :

 

exit script [ true ] to make sure that FM lets the keystroke pass

 

use Get(ActiveLayoutObjectName) if you need to let the character on other objects than fields.


It's crucial that you understand which events happen in what order and which ones you can cancel and which ones not:

 

http://www.soliantconsulting.com/blog/2014/01/script-triggers-filemaker-13

  • Like 1
Link to comment
Share on other sites

Thanks, Wim

 

I'm a little confused - should this be defined in an "IF" statement within the script, or should OnObjectKeystroke appear under the script triggers within the layout setup menu?

Link to comment
Share on other sites

You need to two scripts.  One to handle the OnObjectKeystroke event and another one to handle the OnLayoutKeystroke event.

 

Although in your case you can probably just use the script for the OnLayoutKeystroke event and not handle the OnObjectKeystroke event at all.

I'm guessing that you want your OnLayoutKeystroke to always Exit[ True ] if you are in a field.  Otherwise if the user uses the arrows or types a return in a multi-line field your LayoutKeystroke event would take the user away from what they were doing in the field.

Link to comment
Share on other sites

Wim, I appreciate your patience with me here.

 

Before you posted your last response I had created another script called "disable commands" and set it as OnObjectKeystroke script trigger on all fields it is applicable to, but I know something is missing here:

If [Get(ActiveFieldName)]
Exit Script [Result: True]
End If

Your latest post is exactly correct: The OnLayoutKeystroke always needs to exit if the cursor is in an active field -- doesn't matter what field. The script I originally posted about will only execute should a field not be active.

Link to comment
Share on other sites

As an aside, I see this many times by many developers - and forgive me for ranting

If [Get(ActiveFieldName)]

And I consider it be really bad implicit programming.  I drill it out of everyone I train.

 

It is an incomplete statement.  If active field name what?

When I do code review I do not know wether the developer meant to complete it with

If active field name = A 

or

if active field name <> A

I can only *guess* at the purpose and assume that the developer wants FM to implicitly convert the string (the active field name) to a boolean.  Bad bad bad.  IF expects a boolean, give it a boolean, not a string.

 

Assumptions are bad.  Don't make me assume, make me read what you mean.

Link to comment
Share on other sites

Hi Wim,

 

I do not agree on this one.  There is nothing wrong with using boolean logic; in fact, it is basic in the world of programming.  But if someone uses boolean logic on a text field, they deserve for it to fail, as it certainly would in the example you provided.

 

Boolean logic is not an assumption - it is a solid, clean principle.  :-)

Link to comment
Share on other sites

Forgot to add in my morning grumpiness:

 

Get(ActiveFieldName) returns a string, say that the field is named "Wim"

IF[ "Wim" ] 

returns False (0)  because FM tries to convert the string to a boolean and it makes a False out it it.

 

A better test is

IF[ not isempty( Get(activeFieldName)) ]

or

IF[ Length( Get(ActiveFieldName ) > 0 ]
Link to comment
Share on other sites

Thank you for clarifying!

 

IF[ Length( Get(ActiveFieldName ) > 0 ]

 

Or apply true boolean logic, dropping the '> 0' as:

IF [ Length ( Get ( ActiveFieldName ) ]

Once a person understands boolean logic, it is easy to read, is more efficient, is shorter to type, and decreases calculation clutter.

 

I've NEVER known you to be grumpy, Wim!  I couldn't even imagine it!   :laugh2:

Link to comment
Share on other sites

 

Or apply true boolean logic, dropping the '> 0' as:

IF [ Length ( Get ( ActiveFieldName ) ]

Once a person understands boolean logic, it is easy to read, is more efficient, is shorter to type, and decreases calculation clutter.

 

I've NEVER known you to be grumpy, Wim!  I couldn't even imagine it!   :laugh2:

 

 

Still grumpy I guess :)

Length( get( activefieldname) ) 

can be 23, which is not a boolean.  Boolean is 0 or 1, True or False.

You're still asking FM to convert an integer to a boolean data type before it can evaluate the IF

 

When I read

IF [ Length ( Get ( ActiveFieldName ) ]

I still don't know if you mean

IF [ Length ( Get ( ActiveFieldName ) ] > 5

and just forgot the last part

IF [ Length ( Get ( ActiveFieldName ) ] > 0

is explicit and leaves no room for doubt or misinterpretation

 

 

(off to get more coffee :) )

Link to comment
Share on other sites

@ Wim,  I agree with your explicit use of conditional statements above, and do the same thing.  Mine often become "conditional grids" or matrices. :)  Filemaker wasn't my first go at programming, so I tend to use structural techniques and best practices from other programming languages out of habit in my FM scripts and custom functions.  They work here too.  (I use FM internally for some custom solutions at my day job, as well as for personal use).

 

P.S. I never understood Filemaker's intention for a function or two, one of which being "GetField ( fieldName )", where a variable name alone or field name alone would suffice.  It is not the same as something like "GetValue ( listOfValues ; valueNumber )", where you are interested in just a small piece of an array.  I just haven't seen the need for it in FM9 ADV, but maybe I am missing something.

Link to comment
Share on other sites

I never understood Filemaker's intention for […] "GetField ( fieldName )", where a variable name alone or field name alone would suffice

 

It suffices when you use it directly as a reference; to dynamically calculate a field name and/or pass it around, you need to use a string – and to get the value of the field the string references (which was probably the idea all along), you must evaluate that string expression as a field reference:

Let (
  myFieldName = GetFieldName ( MyTable::myField ) ;
  List (
    myFieldName ; // field name as string
    GetField ( myFieldName ) // or Evaluate ( myFieldName ): the field value
  )
)
  • Like 1
Link to comment
Share on other sites

Once a person understands boolean logic, it is easy to read, is more efficient, is shorter to type, and decreases calculation clutter.

 

I'm going to have to go with Wim on this one, LaRetta.  I love brevity, and I love the fact that FileMaker is loose enough (in settings where it expects a Boolean result) to interpret any non-zero value as Boolean True.  That said, whether I'm reading my own code or trying to grok someone else's, to my eyes the more explicit statement is instantly more readable, at the cost of relatively few extra keystrokes.  I always write this or similar tests along the lines of Wim's first suggestion, however…

IF[ not isempty( Get(activeFieldName)) ]

…otherwise I find myself wondering why we're counting characters when all we really want to know whether the function returns a value at all.  (As an aside, I wonder if there is any performance difference — at the millisecond level, of course — between the approaches.  In one-off cases, it would be unnoticeable, but could add up in a loop, import routine, etc.)

 

Mark

Link to comment
Share on other sites

Any function that employs a test, e.g.

If(test;result1;result2)

will implicitly read that test as a Boolean - no explicit conversion is necessary. IOW,

If ( SomeValue ; result1 ; result2 )

is read by Filemaker as =

If ( GetAsBoolean ( SomeValue ) ; result1 ; result2 )

and so should it be read by the human developer.

 

 

 

Of course, the result of =

GetAsBoolean ( SomeTextValue )

is rather unpredictable (since "textvalue" is converted to False, while "text1value" is True), so certainly the construct =

If ( SomeTextValue ; result1 ; result2 )

is bad code and should be replaced by =

If ( not IsEmpty ( SomeTextValue ) ; result1 ; result2 )

However, that is not so with numerical values (in this context: values that are obviously numerical). I cannot find any justification for writing =

If ( SomeNumber > 0 ; result1 ; result2 )

 when you actually mean =

If ( GetAsBoolean ( SomeNumber ) ; result1 ; result2 )

and - as I have stated at the beginning - the explicit GetAsBoolean ( ) adds nothing but redundant verbosity.

  • Like 1
Link to comment
Share on other sites

 

It suffices when you use it directly as a reference; to dynamically calculate a field name and/or pass it around, you need to use a string – and to get the value of the field the string references (which was probably the idea all along), you must evaluate that string expression as a field reference:

Let (
  myFieldName = GetFieldName ( MyTable::myField ) ;
  List (
    myFieldName ; // field name as string
    GetField ( myFieldName ) // or Evaluate ( myFieldName ): the field value
  )
)

 

Thanks for that.  I also don't think I have the GetFieldName() function on FMP9, which they probably added in a later release.  Makes sense now.

Link to comment
Share on other sites

Hi Mark,

 

I admit trying to explain boolean on that text example fell short (because I tried to use Length()  to keep the example relative) but using boolean logic is quite acceptable.  If I see:

 

If ( date ; ...

 

I do not need to ask what kind of date.  All dates are numbers so if there is ANY date it will be true.  

 

I would never use a boolean test on a text field unless I was looking for text with a number in it.  Boolean logic is used all the time as in naming a flag field 'isActive' which holds a '1' like:  If ( IsActive ; ... ).  We don't need to write:  If ( IsActive = 1 ; ... )  but rather it is clear that if there is not an operator, it is boolean.

 

As -Queue- (JT) once said here (paraphrased):  ' I do not plan to dumb down my code but rather other developers should step up and learn boolean which is one of the first things taught in programming.'   He said it a bit nicer than that but I agree completely.

 

Hi Michael,

 

You already know how I feel on this subject.  :-)


Anyway, Michael said it best.

Link to comment
Share on other sites

Boolean logic is used all the time as in naming a flag field 'isActive' which holds a '1' like:  If ( IsActive ; ... ).  We don't need to write:  If ( IsActive = 1 ; ... )  but rather it is clear that if there is not an operator, it is boolean.

 

Great example, LaRetta!  I totally agree with you on this example.  Your naming convention for Boolean fields — I use the same, under the influence, originally, of fmstandards.org — really shows how a good naming convention can make code immensely more readable.

 

It's great to end the day on a point of solid agreement . . . although I have to counter this:

 

As -Queue- (JT) once said here (paraphrased):  ' I do not plan to dumb down my code but rather other developers should step up and learn boolean which is one of the first things taught in programming.'   He said it a bit nicer than that but I agree completely.

 

…with this: "Always code as if the guy who ends up maintaining your code will be a violent psychopath who knows where you live." `John Woods

 

(Thanks to Stephen Wonfor over at TechNet/FM Community for that one.)

 

 

BTW, I'm not implying anyone who doesn't like to use boolean is dumb or wrong; absolutely NOT.  

 

 

It's all good.  I always take your input seriously and learn from it continually.

Link to comment
Share on other sites

 

If ( date ; ...

 

I do not need to ask what kind of date.  All dates are numbers so if there is ANY date it will be true.  

 

 

In this particular case though, if I had input -1 in the date field then the IF would still be true: -1 is a non-zero number and FM will cast is as the boolean True.

 

The point that I was trying to make is that by not being explicit we have to rely on FM's built-in rules on data type conversion:  Date --> Number --> Boolean

Which is perfectly fine as long as:

- we all understand the rules completely (I bet a lot of people would not have pegged -1 to return as True)

- FM does not change its rules (and it has in the past, not for numbers but for Text --> Boolean

If[ isValid( date ) ; ...

Would be my preference to see as readable code here because it very clearly reads: any valid date will do.

 

But I respect L's and Comment's preference not to do it.

Link to comment
Share on other sites

However, that is not so with numerical values (in this context: values that are obviously numerical). I cannot find any justification for writing =

If ( SomeNumber > 0 ; result1 ; result2 )

 when you actually mean =

If ( GetAsBoolean ( SomeNumber ) ; result1 ; result2 )

and - as I have stated at the beginning - the explicit GetAsBoolean ( ) adds nothing but redundant verbosity.

 

I'm not calling for adding GetAsBoolean() - as you say that is redundant and adds nothing.

 

As I've stated elsewhere in this thread, what I want to see is what the real intended test is against $someNumber.

 

if $someNumber is negative for instance, it will still resolve as True when treated as a boolean.  And very likely that is not what the coder meant, he probably did mean

if[ $someNumber > 0 ]

and not

if[ $someNumber <> 0]

But I can not determine that from reading:

if[ $someNumber ]

When I review code I do not know if the coder really meant that it should be ok with negative numbers.  Most people don't realize that negative numbers are true.

Link to comment
Share on other sites

if $someNumber is negative for instance, it will still resolve as True when treated as a boolean.  And very likely that is not what the coder meant,

 

 

I am not sure what the coder meant, but that is certainly what the coder wrote. Why should I presume they meant something else? And what would you expect the coder to write if that's exactly what they meant?

Link to comment
Share on other sites

In this particular case though, if I had input -1 in the date field then the IF would still be true: -1 is a non-zero number and FM will cast is as the boolean True.

-1 could not exist in a date field because that is not a valid date. Nonetheless, it is true that the person using boolean must understand that boolean is ANY non-zero number. As for FM changing its rules on boolean ... yes, FM dropped true/false, yes/no from meaning boolean but that is opposite of what we are discussing and it was bizarre they allowed that in the first place, just as allowing text in number fields is still bizarre to this day.

*Numbers have always been, and will always be (your friend). No wait, that's something else ... LOL. Numbers have always been and will always be boolean by their nature ... that is the basis for everything in programming, including FM. FM could not change its logic on boolean.

 

The point that I was trying to make is that by not being explicit we have to rely on FM's built-in rules on data type conversion: Date --> Number --> Boolean

Dates ARE numbers internally to FM, aren't they, no conversation needed? The conversion then to boolean takes no more resources than adding an operator and a test value as suggested:

If ( IsActive ; do this ) takes no more resources than your example of

If ( IsActive = 1 ; do this ) which is the example Michael provided similar to

If ( GetAsBoolean ( IsActive ) ; do this ) to show that FM automatically converts (first example) to boolean without wrapping it with GetAsBoolean()

I had to laugh a bit when FM added GetAsBoolean() - it is a wrapper for humans that are not clear on boolean logic. I would prefer the FM community be encouraged to step up their game and embrace boolean (taught in first year programming) rather than force unnecessary explicitly which adds clutter to a calculation (same with unnecessary parentheses) because someone at some time might not have known what they were writing or the person reading it might not know the author's intent.

 

If[ isValid( date ) ; ...
Would be my preference to see as readable code here because it very clearly reads: any valid date will do.

But Wim, this evaluates to true even if the field is empty.  Anyway, it is fine that we disagree. How boring if we all thought exactly the same about everything in the universe! :-)

* quote from Star Trek by Mr Spock to Captain Kirk (slightly twisted here for my own use)

edited: corrected typo

Edited by LaRetta
Link to comment
Share on other sites

Numbers have always been, and will always be (your friend). No wait, that's something else ... LOL. Numbers have always been and will always be boolean by their nature ... that is the basis for everything 

* quote from Star Trek by Mr Spock to Captain Kirk (slightly twisted here for my own use)

 

Theoretical physicist & string theorist Brian Green once speculated that maybe someday we'll come face to face with a much more advanced, inter-galactic- and time-travelling civilization, and will ask them about the great physical and cosmological mysteries:  the origins of the universe, time-travel and the "arrow of time," higher dimensional space, etc.  "We've been trying to answer those questions through math," we'll tell them.  They will reply "Oh, math!  We tried that.  It only got us so far, so we eventually abandoned it."

  • Like 1
Link to comment
Share on other sites

Numbers have always been and will always be boolean by their nature

 

I am not sure I would agree with such a broad statement. It's true that in Filemaker, there is no Boolean data type, so when you say Boolean, you must mean a numeric value - simply because there's nothing else. Even the constants True and False are just placeholders (labels) for 1 and 0. But that only means that Booleans are Numbers - not necessarily the opposite.

 

 

Dates ARE numbers internally to FM, aren't they, no [conversion] needed?

 

Actually, no - though it is convenient (and mostly harmless) to think so. But internally, the dates are stored "as entered".

 

 

]I had to laugh a bit when FM added GetAsBoolean() - it is a wrapper for humans that are not clear on boolean logic.

 

I cannot agree with this either. Before this function appeared, we had to use the somewhat awkward expression of =

 

not not Something

in order to reduce Something to 0 or 1. Which can be very handy if - for example - you want to replace the verbose =

SomeValue + Case ( SomeNumericValue ; 1 ; 0 )

with the neat =

SomeValue + GetAsBoolean ( SomeNumericValue )
Link to comment
Share on other sites

I liked not not.  :crazy2:   It is true, however, that I have used GetAsBoolean() twice since it came out instead of using not not because not not is a bit odd.  I got not not from JT when he provided a calculation of:  not not PatternCount() ...

 

Thank you for the correction on dates ... not sure where I got that concept that they are numbers.  They are the number of days from Jan 1, 1001 but still they are stored as date - depending upon OS setting!?  I completely believe you of course, but it would be more logical if it were number, wouldn't it? 

Link to comment
Share on other sites

I am not sure what the coder meant, but that is certainly what the coder wrote. Why should I presume they meant something else? And what would you expect the coder to write if that's exactly what they meant?

 

The coder = the person who wrote the code.

 

I would expect the coder to write

If[ $someNumber <> 0]

if he meant: all numbers are ok except 0

 

I do a lot of training and code reviews so for me it is crucial that what I read is exactly what the programmer intended to do.  It just takes 5 extra keystrokes including spaces = probably less than 1 second to type, and it saves us a few minutes in the code-review meeting, or likely more than 10 minutes if I have to get hold of the guy when we are not physically in the same space.

 

There is no ambiguity in the statement above, there is room for doubt when the "<> 0" is left off.

 

Anyway, I'm not trying to convert you; just pointing out what my perspective and preference is.  This is a good thread.

Link to comment
Share on other sites

There is no ambiguity in the statement above, there is room for doubt when the "<> 0" is left off.

 

There is no ambiguity in the statement =

If [ $someNumber ]

either. The doubt, if any, is introduced by you not trusting your coders to write what they actually mean - perhaps justifiably so. But this falls squarely under what LaRetta said earlier:

 

As -Queue- (JT) once said here (paraphrased):  ' I do not plan to dumb down my code
Link to comment
Share on other sites

Hmm  I type it out like Wim does.  The reason for that is because I often do long chains of conditionals and it is super-easy to just change the argument at the end.  My conditions use a False condition as the "true" argument as much of the time, if not more.  But to make it even a bit easier, I often express it like this wherever I can, and only change the equal sign.  That makes it easy to correct the multi-variable conditionals if I get them wrong at first or if they need tweaking.

 

$int = 0

$int <> 0

 

or

 

$str = ""

$str <> ""

 

 

P.S. the only time where I use just an "=" is when I am searching directly in a field on a layout, and I click on the magnifying glass button at the top left.  Then I type in either an "=" or a "*". (empty or non-empty)  The same often goes for a scripted search too.

Link to comment
Share on other sites

This topic is 3345 days old. Please don't post here. Open a new topic instead.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...

Important Information

By using this site, you agree to our Terms of Use.