PackageDescription: MEMacOSXCommandKey

ME Mac OSX Command Key

Last published: September 1, 2012 by 'stevek'

Defines 0 Classes
Extends 5 Classes

This package is a workaround to make Command key modifiers work on Mac OS X Aqua VMs, and to show Ctrl+char in menus as Command+char (NB MEMacOSXLucidaGrande package is recommended to get the correct menu font).

Mac OS X Aqua VMs do not pass Command modifier keys to the image (tested in 7.7 and 7.9) - only the events when the Command key alone is depressed and released are passed, and the image ignores those. The image also does not support the Command key properly: menu items cannot specify it (at least not in the Menu Editor), and the text editor dispatch table cannot cope with it (it only has 16 slots, i.e. 4 modifier bits, and Command would be a fifth bit and require 32 slots).

This package uses the Mac OS X app menu from the top of the screen to receive Command+Char shortcuts, passes them to the image as MacOSXExtra menu item commands with tags 40-43 (Command+cursor keys) and 48-99 (Command+A-Z, Command+Shift+A-Z), then generates a KeyPressed and Released event for them. Command+cursor keys are translated to Home and End (Command+Left on a Mac goes to the start of the line). Command+char is translated as Ctrl+char, which can then be processed by VW menus and text editors. The display of menu item shortcuts shows Ctrl+char as Command+char, as Mac users expect, and thus matching what the key press is that invokes the command. For ease of use of users familiar with the same VW app on other platforms, menu items also still accept Ctrl+char on the Mac, even though the menu only shows Command+char.

You are responsible for building the Mac OS X app menu items for the Command shortcuts needed by your application. The menus are in MainMenu.nib, edited with XCode's Interface Builder - see packaging\mac and bin\macx\readme.txt. Note that you must have a menu with tag 10 (like the Edit menu in the VW MainMenu.nib), you want to avoid the tag values 11, 13, 14, 15 in that menu (if there, the VM maps these to Ctrl+Z/X/C/V, regardless of the shortcut key specified in them), and your menu items must be directly visible in the main menus (not submenus). OS X standard practice reserves Command + H (hide app windows), Q (quit app), W (close window) and M (minimize).

MacOSXExtra also assumes the following tags, which make reasonable sense for most apps - you just need have menu items with these tags and override the methods they run (see setMenuDispatchTable):
1 About [your app]
2 Preferences Command+,
3 Quit [your app] Command+Q
17 Select All Command+A (already overridden here, use tag 17 rather than 48 for Command+A - see #selectAll:eventMenu:)
32 Help Topics

Note that the shortcut key specified in Interface Builder determines what key press the user must make, the tag value determines which menu event VW sees, and this package translates that tag value into a key press (48 = Command+A, 48+26 = Command+Shift+A). So if you want a menu item for Advanced Find, Ctrl+Shift+F or Command+Shift+F on Macs, you make a Menu Item in VW for Ctrl+Shift+F, which VW will display on Macs as Command+Shift+F. You add an app menu item to MainMenu.nib for Command+Shift+F, and give it the tag value 48+26+($f asInteger - $a asInteger)=48+26+5=79. When Command+Shift+F is pressed, OS X triggers the app menu item, which is recognised by the VM (because tags 40-99 were activated by a call to primActivateMenuItem:state: primitive 778 at #returnFromSnapshot) and passed as event type 15 with tag 79 to the image. There it is looked up in MacOSXMenuDispatch, which calls commandKey:eventMenu:, which decodes the 79 back into (Command+)Shift+F, and then creates a key pressed and released event for Ctrl+Shift+F.

When the VM is corrected to pass the Command key modifier correctly, the following system changes may be necessary in the image:
- KeyboardEvent>>isShortcutKey - "or: [self hasCommand"
- KeyboardEvent>>shortcutModifierSymbols - "allow commandMask, also in menu building and editing"
- MenuItemAdornment>>shortcutModifierStringMac - "translateModifiers := false"
- dispatch table support for 5 bits / 32 slots