Keys corresponding to Key Codes on US Apple Keyboard Pro

Full Key Codes is a very handy utility for finding the key code for any key on your keyboard that has one. When reading someone else’s script, however, it is not always easy to tell what key is meant by a key code instruction in the script. To solve that problem for my keyboard, I wrote two scripts. The first below prepares a list of all the key codes with values given an experimentally determined set, and the second then reveals the key corresponding to any code if there is one. In my preliminary testing the results seemed to be accurate, but I did not test every key.

If you have an American Apple Pro USB Keyboard, the second script can be used as is.


(* The nested list below was determined for the standard Apple Pro USB Keyboard delivered with a G5-2/2.3 tower. System Profiler describes it as follows:

	Apple Pro Keyboard:
	Version:	4.10
	Bus Power (mA):	250
	Speed:	Up to 12 Mb/sec
	Manufacturer:	Mitsumi Electric
	Product ID:	0x020b
	Vendor ID:	0x05ac  (Apple Computer, Inc.)
	
Using Full Key Codes found here [http://softwares.bajram.com/utilities/] the list below was determined by simply pressing every key and recording what the text on the key cap and the decimal key code that went with it. Note that neither F14 nor F15 produced a code on my machine, and that the volume softer, volume louder, mute volume and eject did not either - they simply did what they were supposed to do. Finally, although the modifier keys: Caps Lock, Shift, Control, Option, and Command have key codes in a standard ISO set, they are not displayed by Full Key Codes.
*)

set FullKeySet to {{"esc", 53}, {"F1", 122}, {"F2", 120}, {"F3", 99}, {"F4", 118}, {"F5", 96}, {"F6", 97}, {"F7", 98}, {"F8", 100}, {"F9", 101}, {"F10", 109}, {"F11", 103}, {"F12", 111}, {"F13", 105}, {"'~", 50}, {"1!", 18}, {"2@", 19}, {"3#", 20}, {"4$", 21}, {"5%", 23}, {"6^", 22}, {"7&", 26}, {"8*", 28}, {"9(", 25}, {"0)", 29}, {"-_", 27}, {"=+", 24}, {"Del", 51}, {"Tab", 48}, {"qQ", 12}, {"wW", 13}, {"eE", 14}, {"rR", 15}, {"tT", 17}, {"yY", 16}, {"uU", 32}, {"iI", 34}, {"oO", 31}, {"pP", 35}, {"[{", 33}, {"]}", 30}, {"\\|", 42}, {"aA", 0}, {"sS", 1}, {"dD", 2}, {"fF", 3}, {"gG", 5}, {"hH", 4}, {"jJ", 38}, {"kK", 40}, {"lL", 37}, {";:", 41}, {"'\"", 39}, {"Return", 36}, {"zZ", 6}, {"xX", 7}, {"cC", 8}, {"vV", 9}, {"bB", 11}, {"nN", 45}, {"mM", 46}, {",<", 43}, {".>", 47}, {"/?", 44}, {"Space", 49}, {"F16", 106}, {"Help", 114}, {"Home", 115}, {"page up", 116}, {"Fwd Del", 117}, {"end", 119}, {"page down", 121}, {"up arrow", 126}, {"left arrow", 123}, {"right arrow", 124}, {"down arrow", 125}, {"clear", 71}, {"N: =", 81}, {"N: /", 75}, {"N: *", 67}, {"N: -", 78}, {"N: +", 69}, {"Enter", 76}, {"N: .", 65}, {"N: 0", 82}, {"N:1", 83}, {"N: 2", 84}, {"N: 3", 85}, {"N: 4", 86}, {"N: 5", 87}, {"N: 6", 88}, {"N: 7", 89}, {"N: 8", 91}, {"N: 9", 92}}

-- split the entries into two corresponding lists
set KK to {}
set KN to {}
repeat with K in FullKeySet
	set end of KK to item 1 of K
	set end of KN to item 2 of K
end repeat
-- sort the entries in both lists into numerical order
sort_items(KN, KK)
-- find missing values and insert spaces in Key list KK
set missing to {}
repeat with j from 2 to 200 -- limit set high enough to make room for growth of list
	try
		if (1 + (item (j - 1) of KN)) ≠ (item j of KN) then
			set m to 1 + (item (j - 1) of KN)
			set KN to insertInList(KN, m, j - 1)
			set KK to insertInList(KK, missing value, j - 1)
			set end of missing to j
		end if
	on error -- no more values
		exit repeat
	end try
end repeat
missing (* By list position; one greater than the missing key code (list starts with 0): {11, 53, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 67, 69, 71, 73, 74, 75, 78, 80, 81, 91, 94, 95, 96, 103, 105, 108, 109, 111, 113, 114} *)

KK --> {"aA", "sS", "dD", "fF", "hH", "gG", "zZ", "xX", "cC", "vV", missing value, "bB", "qQ", "wW", "eE", "rR", "yY", "tT", "1!", "2@", "3#", "4$", "6^", "5%", "=+", "9(", "7&", "-_", "8*", "0)", "]}", "oO", "uU", "[{", "iI", "pP", "Return", "lL", "jJ", "'\"", "kK", ";:", "\\|", ",<", "/?", "nN", "mM", ".>", "Tab", "Space", "'~", "Del", missing value, "esc", missing value, missing value, missing value, missing value, missing value, missing value, missing value, missing value, missing value, missing value, missing value, "N: .", missing value, "N: *", missing value, "N: +", missing value, "clear", missing value, missing value, missing value, "N: /", "Enter", missing value, "N: -", missing value, missing value, "N: =", "N: 0", "N:1", "N: 2", "N: 3", "N: 4", "N: 5", "N: 6", "N: 7", missing value, "N: 8", "N: 9", missing value, missing value, missing value, "F5", "F6", "F7", "F3", "F8", "F9", missing value, "F11", missing value, "F13", "F16", missing value, missing value, "F10", missing value, "F12", missing value, missing value, "Help", "Home", "page up", "Fwd Del", "F4", "end", "F2", "page down", "F1", "left arrow", "right arrow", "down arrow", "up arrow"}  KK is now a full list of 127 entries for the integers between 0 and 126 in numerical order. Entries for which there is no corresponding key are missing values.

to sort_items(sortList, SecondList) -- handler by Kai
	-- sorts first list and keeps second list in correspondance with first
	script L
		property srt : sortList
		property sec : SecondList
		--property thd : thirdList
	end script
	tell (count L's srt) to repeat with i from (it - 1) to 1 by -1
		set s to (L's srt)'s item i
		set r to (L's sec)'s item i
		--set q to (L's thd)'s item i
		repeat with i from (i + 1) to it
			tell (L's srt)'s item i to if s > it then
				set (L's srt)'s item (i - 1) to it
				set (L's sec)'s item (i - 1) to (L's sec)'s item i
				--set (L's thd)'s item (i - 1) to (L's thd)'s item i
			else
				set (L's srt)'s item (i - 1) to s
				set (L's sec)'s item (i - 1) to r
				--set (L's thd)'s item (i - 1) to q
				exit repeat
			end if
		end repeat
		if it is i and s > (L's srt)'s end then
			set (L's srt)'s item it to s
			set (L's sec)'s item it to r
			--set (L's thd)'s item it to q
		end if
	end repeat
end sort_items

to insertInList(myList, Insertion, AfterNum) -- not mine, but no record of author
	if AfterNum ≥ (count of myList) then
		set end of myList to Insertion
		return myList
	end if
	tell myList
		set frontPart to items 1 thru AfterNum
		set backPart to items (AfterNum + 1) thru -1
	end tell
	set myList to frontPart & Insertion & backPart
	return myList
end insertInList

Then, copying the list KK in the script above to a new one yields:


set _Keys to {"aA", "sS", "dD", "fF", "hH", "gG", "zZ", "xX", "cC", "vV", missing value, "bB", "qQ", "wW", "eE", "rR", "yY", "tT", "1!", "2@", "3#", "4$", "6^", "5%", "=+", "9(", "7&", "-_", "8*", "0)", "]}", "oO", "uU", "[{", "iI", "pP", "Return", "lL", "jJ", "'\"", "kK", ";:", "\\|", ",<", "/?", "nN", "mM", ".>", "Tab", "Space", "'~", "Del", missing value, "esc", missing value, missing value, missing value, missing value, missing value, missing value, missing value, missing value, missing value, missing value, missing value, "N: .", missing value, "N: *", missing value, "N: +", missing value, "clear", missing value, missing value, missing value, "N: /", "Enter", missing value, "N: -", missing value, missing value, "N: =", "N: 0", "N:1", "N: 2", "N: 3", "N: 4", "N: 5", "N: 6", "N: 7", missing value, "N: 8", "N: 9", missing value, missing value, missing value, "F5", "F6", "F7", "F3", "F8", "F9", missing value, "F11", missing value, "F13", "F16", missing value, missing value, "F10", missing value, "F12", missing value, missing value, "Help", "Home", "page up", "Fwd Del", "F4", "end", "F2", "page down", "F1", "left arrow", "right arrow", "down arrow", "up arrow"}

set KC to (text returned of (display dialog "Enter the keyboard code" & return & "(a number between 0 and 126)" default answer "")) as integer
if KC < 0 or KC > 126 then
	display dialog "Number out of range"
	return
else if item (KC + 1) of _Keys is missing value then
	display dialog "There is no key for that code on this keyboard"
else
	display dialog "The key cap should say: " & (item (KC + 1) of _Keys)
end if

Hi, Adam.

Here’s a reworking of the script I offered yesterday in the “keyboard prefs buttons changing” thread in the OS X forum. That version only worked with (my) British version of the Keyboard Viewer and had a couple of errors anyway. I think this one may be more compatible with other varieties of English, provided that the system’s Tiger and the Keyboard Viewer’s displaying a Latin font. It beeps if the key code entered is out of range or isn’t on my keyboard (which is similar to yours, but with a Product ID of 0x020c) and simply marks time if the key legend isn’t recognised by the Keyboard Viewer. It’s still only intended as an exercise, but should be good enough in most cases on English-language systems.

on main()
	-- Quitting the Keyboard Viewer first ensures that there's a window when its activated.
	tell application "System Events" to set kvsOpen to (application process "KeyboardViewerServer" exists)
	if (kvsOpen) then tell application "KeyboardViewerServer" to quit
	
	-- The characters corresponding to the unmodified keys of a G5 keyboard in a British version of Tiger's Keyboard Viewer showing a Geneva font.
	-- Missing values mean no keys with those numbers. In the lists, the first item is 1 for alphanumeric keys, 2 for the number keypad.
	-- Unicode data values beginning with "F" are Keyboard Viewer's button names for the F keys. The others are various keyboard symbols.
	set l to {"a", "s", "d", "f", "h", "g", "z", "x", "c", "v", "§", "b", "q", "w", "e", "r", "y", "t", {1, "1"}, {1, "2"}, {1, "3"}, {1, "4"}, {1, "6"}, {1, "5"}, {1, "="}, {1, "9"}, {1, "7"}, {1, "-"}, {1, "8"}, {1, "0"}, "]", "o", "u", "[", "i", "p", «data utxt21A9», "l", "j", "'", "k", ";", "\\", ",", {1, "/"}, "n", "m", {1, "."}, «data utxt21E5», " ", "`", «data utxt232B», missing value, "esc", missing value, «data utxt2318», «data utxt21E7», «data utxt21EA», «data utxt2325», «data utxt2303», missing value, missing value, missing value, missing value, missing value, {2, "."}, missing value, "*", missing value, "+", missing value, «data utxt2327», missing value, missing value, missing value, {2, "/"}, «data utxt2324», missing value, {2, "-"}, missing value, missing value, {2, "="}, {2, "0"}, {2, "1"}, {2, "2"}, {2, "3"}, {2, "4"}, {2, "5"}, {2, "6"}, {2, "7"}, missing value, {2, "8"}, {2, "9"}, missing value, missing value, missing value, «data utxtF86000460035», «data utxtF86000460036», «data utxtF86000460037», «data utxtF86000460033», «data utxtF86000460038», «data utxtF86000460039», missing value, «data utxtF861004600310031», missing value, «data utxtF861004600310033», «data utxtF861004600310036», «data utxtF861004600310034», missing value, «data utxtF861004600310030», missing value, «data utxtF861004600310032», missing value, «data utxtF861004600310035», «data utxt003F20DD», «data utxt2196», «data utxt21DE», «data utxt2326», «data utxtF86000460034», «data utxt2198», «data utxtF86000460032», «data utxt21DF», «data utxtF86000460031», «data utxt21E0», «data utxt21E2», «data utxt21E3», «data utxt21E1»}
	
	set c to (count l)
	set k to (text returned of (display dialog "Enter a key code between 0 and " & (c - 1) & ":" default answer "")) + 1
	
	if (k < 0) or (k > c) or (item k of l is missing value) then
		beep 3
	else
		set buttonName to item k of l
		tell application "KeyboardViewerServer" to activate
		tell application "System Events"
			tell application process "KeyboardViewerServer"
				if (buttonName's class is list) then
					set {x, buttonName} to buttonName
					set target to a reference to (button x of front window whose name is buttonName)
				else
					set target to a reference to (buttons of front window whose name is buttonName)
				end if
				repeat 10 times
					perform target's action "AXPress"
					delay 0.2
				end repeat
			end tell
		end tell
	end if
end main

main()

Ahh - a clever way to manage that with a target name instead of button number. To the extent that I’ve tested it, it’s accurate on my keyboard, too. Character 10 doesn’t appear on my keyboard, but nothing bad happens.

I was about half way to building a table similar to your first submission (I stopped it to go on to some other things). Now I needn’t complete the job, I guess, although I probably will at some point. One of the points of confusion with buttons by number on MM is that they start at 4, with 1, 2, & 3 being the close, hide and grow buttons at the top of the keyboard window.

Hi, Adam.

Thanks for the feedback. Key 10, on my keyboard, is just below the Escape key, to the left of alphanumeric “1”. I see your script has a missing value for that slot, presumably indicating either that there’s no key there or that there’s one with a different key code. Interesting. I’d vaguely assumed that US keyboards would be physically the same as the equivalent British models, with perhaps just some different shift characters in the number row. (We have a “£” sign above “3” and use the Option key to get “#”. My G5 keyboard also has a Euro sign “€” next to the “@” above the “2”, but that’s also obtained by using the Option key.)

My PowerBook has an “fn” key, but since neither keyboardSee nor GUI Scripting will run on it, I can’t tell what the key code is for that.

Hi Nigel and Adam,

I expanded your script a bit for the capability to work on german keyboards too.
For this purpose I’ve added a property for the main system language (independent from International prefpane settings)
and also for the system code of the connected keyboard.
I’m not sure whether “en_US” and “en_UK” are correct.


property language : user locale of (system info)
property keyboard : system attribute "kbd " -- keyboard Version (not used yet)

(*
	31 = Pro Keyboard w/F16 key Domestic (ANSI) Keyboard
	32 = Pro Keyboard w/F16 key International (ISO) Keyboard
	33 = Pro Keyboard w/F16 key Japanese (JIS) Keyboard
	34 = USB Pro Keyboard w/ F16 key Domestic (ANSI) Keyboard
	35 = USB Pro Keyboard w/ F16 key International (ISO) Keyboard
	36 = USB Pro Keyboard w/ F16 key Japanese (JIS) Keyboard
*)


on main()
	-- Quitting the Keyboard Viewer first ensures that there's a window when its activated.
	tell application "System Events" to set kvsOpen to (application process "KeyboardViewerServer" exists)
	if (kvsOpen) then tell application "KeyboardViewerServer" to quit
	
	-- The characters corresponding to the unmodified keys of a G5 keyboard in a British version of Tiger's Keyboard Viewer showing a Geneva font.
	-- Missing values mean no keys with those numbers. In the lists, the first item is 1 for alphanumeric keys, 2 for the number keypad.
	-- Unicode data values beginning with "F" are Keyboard Viewer's button names for the F keys. The others are various keyboard symbols.

	if language is "en_US" or language is "en_UK" then
		set l to {"a", "s", "d", "f", "h", "g", "z", "x", "c", "v", "§", "b", "q", "w", "e", "r", "y", "t", {1, "1"}, {1, "2"}, {1, "3"}, {1, "4"}, {1, "6"}, {1, "5"}, {1, "="}, {1, "9"}, {1, "7"}, {1, "-"}, {1, "8"}, {1, "0"}, "]", "o", "u", "[", "i", "p", «data utxt21A9», "l", "j", "'", "k", ";", "\\", ",", {1, "/"}, "n", "m", {1, "."}, «data utxt21E5», " ", "`", «data utxt232B», missing value, "esc", missing value, «data utxt2318», «data utxt21E7», «data utxt21EA», «data utxt2325», «data utxt2303», missing value, missing value, missing value, missing value, missing value, {2, "."}, missing value, "*", missing value, "+", missing value, «data utxt2327», missing value, missing value, missing value, {2, "/"}, «data utxt2324», missing value, {2, "-"}, missing value, missing value, {2, "="}, {2, "0"}, {2, "1"}, {2, "2"}, {2, "3"}, {2, "4"}, {2, "5"}, {2, "6"}, {2, "7"}, missing value, {2, "8"}, {2, "9"}, missing value, missing value, missing value, «data utxtF86000460035», «data utxtF86000460036», «data utxtF86000460037», «data utxtF86000460033», «data utxtF86000460038», «data utxtF86000460039», missing value, «data utxtF861004600310031», missing value, «data utxtF861004600310033», «data utxtF861004600310036», «data utxtF861004600310034», missing value, «data utxtF861004600310030», missing value, «data utxtF861004600310032», missing value, «data utxtF861004600310035», «data utxt003F20DD», «data utxt2196», «data utxt21DE», «data utxt2326», «data utxtF86000460034», «data utxt2198», «data utxtF86000460032», «data utxt21DF», «data utxtF86000460031», «data utxt21E0», «data utxt21E2», «data utxt21E3», «data utxt21E1»}
	else if language is "de_DE" then
		set l to {"a", "s", "d", "f", "h", "g", "y", "x", "c", "v", "^", "b", "q", "w", "e", "r", "z", "t", {1, "1"}, {1, "2"}, {1, "3"}, {1, "4"}, {1, "6"}, {1, "5"}, {1, "´"}, {1, "9"}, {1, "7"}, {1, "ß"}, {1, "8"}, {1, "0"}, "+", "o", "u", "ü", "i", "p", «data utxt21A9», "l", "j", "ä", "k", "ö", "#", ",", {1, "-"}, "n", "m", {1, "."}, «data utxt21E5», " ", "<", «data utxt232B», missing value, "esc", missing value, «data utxt2318», «data utxt21E7», «data utxt21EA», «data utxt2325», «data utxt2303», missing value, missing value, missing value, missing value, missing value, {2, "."}, missing value, "*", missing value, "+", missing value, «data utxt2327», missing value, missing value, missing value, {2, "/"}, «data utxt2324», missing value, {2, "-"}, missing value, missing value, {2, "="}, {2, "0"}, {2, "1"}, {2, "2"}, {2, "3"}, {2, "4"}, {2, "5"}, {2, "6"}, {2, "7"}, missing value, {2, "8"}, {2, "9"}, missing value, missing value, missing value, «data utxtF86000460035», «data utxtF86000460036», «data utxtF86000460037», «data utxtF86000460033», «data utxtF86000460038», «data utxtF86000460039», missing value, «data utxtF861004600310031», missing value, «data utxtF861004600310033», «data utxtF861004600310036», «data utxtF861004600310034», missing value, «data utxtF861004600310030», missing value, «data utxtF861004600310032», missing value, «data utxtF861004600310035», «data utxt003F20DD», «data utxt2196», «data utxt21DE», «data utxt2326», «data utxtF86000460034», «data utxt2198», «data utxtF86000460032», «data utxt21DF», «data utxtF86000460031», «data utxt21E0», «data utxt21E2», «data utxt21E3», «data utxt21E1»}
	end if
	set c to (count l)
	set k to (text returned of (display dialog "Enter a key code between 0 and " & (c - 1) & ":" default answer "")) + 1
	
	if (k < 0) or (k > c) or (item k of l is missing value) then
		beep 3
	else
		set buttonName to item k of l
		tell application "KeyboardViewerServer" to activate
		tell application "System Events"
			tell application process "KeyboardViewerServer"
				if (buttonName's class is list) then
					set {x, buttonName} to buttonName
					set target to a reference to (button x of front window whose name is buttonName)
				else
					set target to a reference to (buttons of front window whose name is buttonName)
				end if
				repeat 10 times
					perform target's action "AXPress"
					delay 0.2
				end repeat
			end tell
		end tell
	end if
end main

main()

Hi, Stefan.

Thanks for that. I’m glad the script’s apparently adaptable for other languages. I expect there’s some easy way to read the machine’s current keyboard layout from the system, but I don’t know what that might be.

I hadn’t heard of system info before. It must be a relatively new addition to the StandardAdditions as it’s not on my Jaguar machine. (I love the fact that, in AppleScript, the ways to find out about the system on which the script’s running depend on the system! :wink: ) I’d personally use it at run-time rather than as a property, otherwise the result would only be true for the system on which the script was compiled.

On my machine, located in the UK, the user locale is returned as “en_GB”.

system info is new in Tiger, but

do shell script "defaults read .GlobalPreferences AppleLocale"

should do the same job at Pre-Tiger machines

You’re right, it’s stupid to use a property in this case

No. Sorry. On my Jaguar machine, it just throws an error that says: " The domain/default pair of (.GlobalPreferences, AppleLocale) does not exist."

By the way, thanks also for system attribute "kbd ". I was able to use that on my PowerBook and got the answer 195. Cross-checking that layout in keyboardSee on my G5, I was able to see that the “fn” key has a key code of 3F “ that is, 63 decimal. However, I haven’t changed the 64th entry in my list of button names, as of course I still can’t check what the button name is in the Keyboard Viewer. :slight_smile:

yes, I just booted my Jaguar partition, and found a domain named Country
in the .GlobalPreferences.plist of Library, try this:

do shell script "defaults read /Library/Preferences/.GlobalPreferences Country"

but it returns only a two letter Code.

The file /System/Library/Frameworks/CoreServices.framework/Versions/A/Frameworks/CarbonCore.framework/Versions/A/Headers/Gestalt.h
contains all information you can get with the “system attribute” command. All different keyboard codes are described in there

A country code is really less useful, however. Mine says “CA” which is Canada, but there are two official languages here. Similarly (although I don’t know), Belgian machines might have two forms and Swiss machines three.

I don’t know, Adam. There are actually only three different keyboard codes (Domestic, International and Japanese)
but a lot of different layouts. For example, Germany (de_DE) and the german part of Switzerland (de_CH) have not the same layout
but there is common one for the three main languages of Switzerland (de_CH, fr_CH, it_CH).