Caps lock breaking keyboard shortcuts handling in Adobe Air

Hello everybody, I’m Florian and currently the newest member of the balsamiq team. So what is my job here? I hunt bugs and add automated tests so once bugs are eradicated we do not run into them again.

Today I would like to discuss an ancient bug. Certain keyboard shortcuts were disabled when caps lock was activated. Instead of saving or exporting your mockups as png nothing happened at all. The bug occured on Windows and Linux even though Windows and Mac are handled in the same way and Linux had its own solution.

So what did we do and what did we do wrong?

At this point I want to dig a bit deeper into technical details of the Flex API of the KeyboardEvent. The KeyboardEvent has several nice public properties which are set on the basis of the keys you press. These are:
• keyCode which is the numeric value of the key pressed
• shiftKey is a Boolean which tells us if shift is pressed, likewise
• altKey for alt
• controlKey for control by Linux and Windows
• commandKey by Mac
• and now the bad bad charCode which is the computed charCode by the all the keys pressed above.

So why is the charCode the baddy? Because it is affected by caps lock on Linux and Windows! So if your key handler works on the basis of the charCode and checks if a key modifier has been pressed you might end up either in a keyboard shortcut which should not be triggered, or with no result at all.

Windows and Mac

For Windows and Mac OS we used the nice NativeMenu from Flex.

We use the NativeMenu and the NativeMenuItems to add all the entries you see in the menu. NativeMenuItem is an entry e.g. “Save As” and in our case it should listen to the key combination "ctrl + shift + s". To create this "Save As" item we use following code sniplet:
var item:NativeMenuItem = new NativeMenuItem(“Save As”);
item.name = “saveas”;
item.keyEquivalent = “S”;
item.mnemonicIndex = 5;

This works great on Windows until we hit caps lock. Before I tell you why I want to refer to a blog post of Brooks Andrus. He added another line to the item above:
item.keyEquivalentModifiers = Keyboard.SHIFT
This meant that he had to have caps lock on to trigger the shortcut.

The reason is the that the NativeMenu and the NativeMenuItems work with the charCode. As we know the charCode is affected by caps lock on Windows. Though it is interesting that the charCode stays unaffected by Mac, so we do not need a special handling here.

Now how do we solve this issue on Windows? The NativeMenu only bubbles the event up if a listener triggers and even if it would still bubble it up the select event has absolutely no knowledge any more of which keys were pressed.

This is how we solved it:
We added a listener in the creation of the menu for a KeyboardEvent.KEY_UP.
And this is the function we call:
protected var _capsLockOn:String;
//Only used on Windows
protected function onKeyUp(p_evt:KeyboardEvent = null):void
{
trace("onKeyUp "+Keyboard.capsLock);
var newCapsLock:String = (Keyboard.capsLock) ? "ON" : "OFF"
if (_capsLockOn == null || newCapsLock != _capsLockOn) {
_capsLockOn = newCapsLock;
Application.application.stage.removeEventListener(KeyboardEvent.KEY_DOWN, onKeyDown);
if (_capsLockOn == "ON") {
Application.application.stage.addEventListener(KeyboardEvent.KEY_DOWN, onKeyDown);
}
}
}

In onKeyDown we again handle all the events that should have been handled in the NativeMenu.

Linux

For Linux we wrote our own menu. We designed it as we wanted, added all the items and added event listeners to handle keyboard events for specific item. The event handler worked with the charCode.

So for Linux the solution is straightforward. Instead of mapping just to the charCode we map to the lower case of the charCode and check if shift is pressed. It would probably be even better to map to the keyCode and the key modifiers.

So the mystery is solved why caps lock disables shortcuts. We have learned our lesson here.

I hope this helps a lot of you to solve the problem of shortcut issues vanishing when caps lock is pressed.

(P.S. If anybody knows how to simulate a keyboard event so the NativeMenu triggers please share this information with me. I want to add some Unit Tests for this. (Yes, I know that is no longer unit level!))

Better Adobe AIR Beta 2 Package for Ubuntu 64-bit Jaunty

UPDATE:  Package for AIR 2.5.0.  Remember you still need to follow the instructions below and your mileage may vary !!!

adobeair_2.5.0.16600balsamiq1.deb

We ran into a number of issues with installing Adobe AIR Beta 2 on our hosting infrastructure for myBalsamiq.com last week, so I wanted to share a trick I found that made the process a lot smoother and that hopefully is not too big of a hack while we wait for real 64-bit debian packages from Adobe.

So first of all a note of warning, the debian package that you can download here does not constitute a way to install a 64-bit package for Adobe AIR!  Adobe has announced an official 64-bit distribution but at least as concerns beta 2, we are still talking about using workarounds to get a 32-bit AIR to run on a 64-bit distribution through downloading and installing the appropriate 32-bit dependencies.

Our use case for installing Adobe AIR on some of our servers is a simple feature that was missing from previous myBalsamiq beta releases.  What happens is that when you upload a BMML file to a myBalsamiq project we call Balsamiq Mockups Desktop through the command line interface and produce a PNG of the uploaded mockup using the export command.  This allows us to create a new myBalsamiq Mockup page for the upload complete with a mockup image without having to launch the Mockups editor first.

Now Adobe has a very detailed procedure that is important to get acquainted with to install Adobe AIR 2 on 64-bit Ubuntu 9.04 because you still have to go through it, at least up to the step where it asks you to run AdobeAirInstaller.bin (which didn't work for us at all). Actually, I found there was no need to extract libs from the two debs (steps 4 & 5) as everything was setup right by the ia32_libs package.  I also did have to run an extra getlibs to grab libxstl1.1 as follows

sudo getlibs -l libxslt.so.1

Now  once the official deb package installed, because of a current bug in apt referenced here on Launchpad and here on the debian bug tracker, installing an AIR app through the AIR App Installer would work, but would create a broken package for the app rendering apt unusable for further installations.

So...  now for the big hack which allowed us to both install Adobe AIR using a deb package and not break apt.  What I did was use the following steps to extract, amend, and repackage the official Adobe AIR deb package to produce a patched version that lies to apt by saying its a 64-bit package!

First I extracted the deb package contents and debian meta-data into a folder:

dpkg-deb -x adobeair-2.0.0.11670.deb adobeair-2.0.0.11670balsamiq1
dpkg-deb -e adobeair-2.0.0.11670.deb adobeair-2.0.0.11670balsamiq1/DEBIAN

Then I updated the DEBIAN/control file switching the i386 architecture to amd64 and the version to 2.0.0.11670balsamiq1.

I then rebuilt the package using:

dpkg -b adobeair-2.0.0.11670balsamiq1

which produced the adobeair-2.0.0.11670balsamiq1.deb package which you can download here.

Here's a trace of installing it on one of our machines where you can see that aptitude picks up the presence of the adobe air package (which won't work if you use the official one)

luis@mockupshq:~$ sudo dpkg -i adobeair-2.0.0.11670balsamiq1.deb
Selecting previously deselected package adobeair.
(Reading database ... 63964 files and directories currently installed.)
Unpacking adobeair (from adobeair-2.0.0.11670balsamiq1.deb) ...

Running 32-bit AIR on 64-bit systems has not been fully tested. However, 32-bit AIR is expected to run on 64-bit systems if they have the required 32-bit libraries and packages installed.
 The following links describe how to install or update AIR 2.0 on 64-bit versions of Ubuntu 9.04, Fedora 11 and OpenSuse 11.1.
 Installing Adobe AIR 2.0 on 64-bit Linux visit http://kb2.adobe.com/cps/521/cpsid_52132.html
 Updating to Adobe AIR 2.0 on 64-bit Linux visit http://kb2.adobe.com/cps/521/cpsid_52132.html
Setting up adobeair (2.0.0.11670balsamiq1) ...

luis@mockupshq:~$ aptitude show adobeair
Package: adobeair
New: yes
State: installed
Automatically installed: no
Version: 2.0.0.11670balsamiq1
Priority: extra
Section: Development
Maintainer: Adobe Systems, Incorporated
Uncompressed Size: 44.9M
Depends: libgtk2.0-0 (>= 2.4), libxslt1.1, libxml2
PreDepends: lzma
Conflicts: adobeair1.0
Description: Adobe AIR

Now remember, your mileage with our deb is not guaranteed (although I actually also use this package on my laptop which is running karmic 64-bit)! So please don't get angry if something terrible happens with your installation, but I do encourage you to post your experience with it in the comments here, especially if something bad happens so that others may avoid going through your misery.

Oh and if you're interested in our myBalsamiq webapp, then definitely check out Peldi's awesome sneak peak screencast on the company blog.

Error creating AIR file: Could not BER decode the CRL.

Today, out of the blue, our Mockups for Desktop build started failing with the cryptic error above.

A Google search didn't turn up much, while a Bing search returned this seemingly abandoned Flex bug (#FB-16236).

Signs pointed to an issue with our code signing certificate. I contacted the TC TrustCenter support (who issued the cert) via phone, which was totally useless. The guy didn't even ask what happened, he just opened a ticket and 6 hours later I haven't heard back.

Until we get this fixed we cannot ship updates to Mockups, so you can imagine how I felt all afternoon.

I posted on the Adobe Air pre-release forums but heard nothing there either.

I did eventually find a solution though: I went here: http://www.chosensecurity.com/adobe-air-certificates and since the links on the page were broken I reluctantly clicked on "Chat Now", at least to tell them about their broken websites.

To my surprise, the person that answered my chat was extremely knowledgeable and was able to tell me exactly what the deal was.

So I'm sharing it now for those of you in the future who hit this rare issue. Do not panic, your pain is temporary.

So here's the deal: when you sign your Air application with a certificate, it turns out that adt goes out to the interwebs and checks a Certificate Revocation List, i.e. a server that keeps a list of expired or blocked certificates.

Makes sense, except that today ChosenSecurity/TC TrustCenter has had an outage of some sorts that took down their CRL server. They're working on it, and it should all go back to normal tomorrow.

In the meantime, a workaround is to DISCONNECT FROM THE INTERNET and sign your application then. In this case adt falls back to a cached version of the CRL, et voila'! I tried it and it works.

Hurray!

This reminds me of something my "Distributed Systems" professor taught us back in college: "a rigorous, well accepted definition of a distributed system is one in which someone, somewhere, does something...which prevents you from getting your work done".

Yup, check! :)

Peldi

People from the future: If this article helped you, put a w00t in the comments! :)