SD7-full crashed 2/23/2018

Mark, update 9:35 am pst, 2/23/18
The line in the loop that caused the problem is:

  • if (item ShiftKey of KeyFlags) then set Done to true

For some reason the value of KeyFlags is corrupted, even though I had done the same before many times. It works out of the loop but fails in the loop. Hopefully this will help you trace down the crash.

I’ll let you know if I discover anything else.

update 10:23 am pst, 2/23/18
I found the source of the bug. When not using a loop I was always holding a key when the script was run. But when using a loop I had no key pressed because the loop was supposed to wait until a key was pressed. But in the handler GetKeyFlags(IntegerNumber) since there was no keys pressed zero was passed in to GetKeyFlags.

Therefore the loop “repeat while IntegerNumber ≥ 1” never executed and the 3 lines later smashed the output form GetKeyFlags, the handler itself or both.

		set ListLength to length of TheBinaryNumber
		if (ListLength < 8) then
			set TheBinaryNumber to items 1 thru (8 - ListLength) of FalseList & TheBinaryNumber

I’m not sure if SD could handle an error like this one anymore gracefully then it did. That would make a mess in memory.

update 5:23 pm pst, 2/23/18
The script pretty is much impossible to finish because SD7-full just keeps crashing and Script Editor just keeps getting -1763 errors which are errors about ASObj-C pointers being saved in a script. However Script Editor is noticeably less prone to getting the -1763 errors then SD7-full is prone to to crashing. It’s pretty simple script but a bear to code.

update 6:53 am pst, 2/24/18
All the problems with this script were resolved in a post by Shane. See link below.


Mark,

I had worked with the script and tested it. Then I added the part listed below and it crashed the first time I ran it

set Done to false
repeat while (not Done)
	set KeyFlags to GetKeyFlags(TheFlags div 65536)
	return KeyFlags
	if (item ShiftKey of KeyFlags) then set Done to true
end repeat

So I don’t know if I messed something up in the new part. But apart form the new part the rest of the script seemed to be running really well. After sending this post I’ll work with script to see if I can figure out what’s going on. The repeat loop seemed pretty straight forward but I might have made a dumb mistake I haven’t noticed yet.

I just wanted report it now before I forgot details. If I discover anything new I’ll add it to the post.

I included 3 error reports

  • SD crash report.txt
  • Apple crash report.txt
  • Details of internal error.txt

I also zipped the actual script file that holds the script and included that in the post as well as included the actual script text at the end of this post.

use framework "Foundation"
use framework "AppKit"
use scripting additions

(*
This script finds out what modifier keys are pressed and returns a list of the keys that are pressed.
In order for this script to be effective it has to be fast so many choices in the design of this script were
made because they were the fastest.  If the script is modifed and it doesn't repond well afterwards check
the times to make sure something is slowing things down.
The 8 modifier keys that are processed by this script are:
	"caps lock" key
	shift key
	control key
	option key
	command key
	numericPad key
	help key
	function key

Note: The flag for the "caps lock" key will be "true" when "caps lock" is on, not necessarily when the "caps lock" key is pressed down.

There are 3 script lines below that have the comment at the end " -- This is only used to time how long the script takes".
These three are all that is needed to do a very precise time check. The GetKeyFlags handler on my Mac processes the
"key pressed" number in hundrerds of microseconds.  AppleScript's current date is too slow to time this script.
The commands that constitute the entire script timing system are:
	set StartTime to current application's NSDate's |date|()
	set EndTime to current application's NSDate's |date|()
	set RunTime to EndTime's timeIntervalSinceDate:StartTime
Since the modifier key check  will most often be used in a loop speed is very important.

A list of booleans was used to hold the boolean values created in GetKeyFlags instead of a string because the string
processing was slower.

The speed on my Mac were fast enough to be effective.  The speed was tested on 
a late 2015 27 inch iMac, processor 3.2 GHz Intel core i5.
*)

global FalseList

-- Initilize key flag constants
set CapsLockKey to 8
set ShiftKey to 7
set ControlKey to 6
set OptionKey to 5
set CommandKey to 4
set NumericPad to 3
set HelpKey to 2
set FunctionKey to 1

on GetKeyFlags(IntegerNumber)
	-- This handler takes the output of the property "modifierFlags" in the "NSEvent" class in "AppKit" and
	-- returns a list of 8 booleans showing which modifer keys are pressed.  
	script ReturnObj
		property Successful : false
		property BinaryNumber : {}
		property NumberOfBits : -1
	end script
	
	global FalseList
	
	try
		set TheBinaryNumber to {}
		repeat while IntegerNumber ≥ 1
			if (IntegerNumber mod 2) = 0 then
				set TheBinaryNumber to {false} & TheBinaryNumber
			else
				set TheBinaryNumber to {true} & TheBinaryNumber
			end if
			set IntegerNumber to IntegerNumber div 2
		end repeat
		
		set ListLength to length of TheBinaryNumber
		if (ListLength < 8) then
			set TheBinaryNumber to items 1 thru (8 - ListLength) of FalseList & TheBinaryNumber
		end if
		
		set (BinaryNumber of ReturnObj) to TheBinaryNumber
		set (NumberOfBits of ReturnObj) to count of TheBinaryNumber
		set (Successful of ReturnObj) to true
		return ReturnObj
	on error errMsg number errNum
		display dialog "Error " & (errNum as string) & " occured." & return & return & errMsg ¬
			buttons {"OK"} default button "OK" with title "Error"
		set (Successful of ReturnObj) to false
		return ReturnObj
	end try
end GetKeyFlags

-- The "delay 2" is at the start of the script is to create a delay once the script begins.  This is import in that
-- pressing command-R to start the script will return command key pressed down before you have any chance to press any other modifier keys.
delay 2

-- This is only used on the GetKeyFlags handler and it is declared globally so it only has to be created once.
set FalseList to {false, false, false, false, false, false, false, false}

set StartTime to current application's NSDate's |date|() -- This is only used to time how long the script takes

set TheFlags to current application's NSEvent's modifierFlags() as integer

-- The "div 65536" stips off the lower 16 bits that do not carry any information about keys pressed.
set TheKeysPressed to GetKeyFlags(TheFlags div 65536)

-- These 2 lines figure out how many seconds passed between StartingTime & EndTime
-- On my Mac this time is around 20 microseconds
set EndTime to current application's NSDate's |date|() -- This is only used to time how long the script takes
set RunTime to EndTime's timeIntervalSinceDate:StartTime -- This is only used to time how long the script takes

-- It is very easy to on any keys at any time
set TheResult to BinaryNumber of TheKeysPressed --> {true, false, false, true, true, true, true, true}
-- For all of the next 6 checks I tested with CapsLockKey on and the Shift, Control, Option, Command and Function keys all pressed
item CapsLockKey of TheResult --> true
item ShiftKey of TheResult --> true
item ControlKey of TheResult --> true
item OptionKey of TheResult --> true
item CommandKey of TheResult --> true
item FunctionKey of TheResult --> true
-- NumericPad and HelpKey were not tested because I don't have the right kind of keyboard to test that.

-- The "div 65536" stips off the lower 16 bits that do not carry any information about keys pressed.
set TheKeysPressed to GetKeyFlags(TheFlags div 65536)

-- For the next 6 checks I had only the "caps lock" on, no other keys were pressed
item CapsLockKey of TheResult -->true
item ShiftKey of TheResult --> false
item ControlKey of TheResult --> false
item OptionKey of TheResult --> false
item CommandKey of TheResult --> false
item FunctionKey of TheResult --> false

-- For the next 6 checks I had only the "control" key pressed
item CapsLockKey of TheResult -->false
item ShiftKey of TheResult --> false
item ControlKey of TheResult --> true
item OptionKey of TheResult --> false
item CommandKey of TheResult --> false
item FunctionKey of TheResult --> false

set Done to false
repeat while (not Done)
	set KeyFlags to GetKeyFlags(TheFlags div 65536)
	return KeyFlags
	if (item ShiftKey of KeyFlags) then set Done to true
end repeat

Reports.zip (56.9 KB)

key test 8.scptd.zip (18.6 KB)