Repairing Omron and Alps buttons

Recently I had occasion to repair a Logitech wireless mouse and the keyboard of an antique from the 80's, an Apple IIc.

Both devices use mechanical switches which can be opened by releasing side latches and repaired, which is what I did. Rather than duplicating the two tutorials that I used for my repairs, I reference them in this post, with some additional background information.

Logitech Mouse: Omron microswitches


Typical Omron micro switches used in mice

One of my mice, a ten year old Logitech MX 700, had a faulty left click button. Single clicks sporadically turned into double clicks, or click-holds. I took apart the mouse and saw the word "Omron" on the left click microbutton. In fact, all the buttons were Omron, and a quick search taught me that Omron switches are  the most popular microswitches used in mice and probably in consumer electronics in general. Over time (say after 50,000 actuations), the thin metal strip inside the switches can sometimes succumb to metal fatigue and the button starts misbehaving.

By opening the switch and flattening the metal strip within it, you can breathe new life into the microswitch. I used this excellent set of instructions on StackExchange as my guide.


Apple IIc: Alps "complicated" button switches


Alps key switches

Sometime later, I purchased a vintage Apple IIc on eBay which, when it arrived, checked out to be in perfect working order, except for apparently dead "o" and "u" buttons. Suspecting that I could repair those two keys like I did the Omron mouse buttons, I researched online to learn about the keys used on those Apple systems. That research revealed that the keyboard buttons in Apple IIc were Alps "complicated" switches. Alps buttons, like Omrons, are very popular and even sought after by collectors and keyboard enthusiasts who value Alps keys for their excellent mechanical feel (search for "Dell AT 101 Keyboard", and you'll see what I mean). The "complicated" part of their description refers to the internal mechanism for the buttons which is, well, more complicated than subsequent versions of the switches which were made more cheaply with simplified mechanical internals.

Similar to Omron switches, there is a metal actuator which is attached to the button's contact plate and can, over time, lose its spring and cause the button to no longer register keystrokes. Opening the button, removing the metal actuator and bending it is usually all that's needed to revive a non-functioning Alps "complicated" key.

This informative post on the 68k Macintosh Liberation Army forums served as my Alps button repair guide.




Practical uses for the modulo operator


I was introduced to the modulo operator in my first real programming job (longer ago than I care to admit). The problem I had was that I needed to generate a calendar as a simple HTML table (remember when all website layout was done with tables?) and needed to layout columns in multiples of 7.

I shared my dilemma with Felix, a more experienced and knowledgeable programmer at work who taught me about the modulus operator.

The modulus operator returns the remainder of a division of one number by another. In most programming languages, modulo is indicated with a percent sign. For example, "4 mod 2" or "4%2" returns 0, because 2 divides into 4 perfectly, without a remainder. "5%2", however, returns 1 because 1 is the remainder of 5 divided by 2 (2 divides into 5 2 times, with 1 left over).

That doesn't sound like much, but it turns out that knowing the remainder of a division is immensely useful in certain situations.


Example 1: Is a number even?

Since any even number divided by 2 has a remainder of 0, we can use modulo to determine the even-ess of a number. This can be used to make every other row in a table a certain color, for example.

for (x = 1; x < 11; x++) {

    if (x%2 == 0) {
        // Yes! this is an even row
        rowColor = #CCCCCC; // grey
    
    } else {
        // This is an odd row
        rowColor = #FFFFFF; // white
    }
}


Example 2: Do something every nth time.

If you have a for loop and want to report on the state of the loop, but not every cycle through, you can use modulo:

for (x=0; x <100000; x++) {

    // do regular stuff here
 
    // do something special every 9th time through
    // the loop
    if (x % 9 == 0) {
        // important stuff here
    }
}

Example 3: Prepare seconds for display as Hours, Minutes and seconds.

If you need to turn an elapsed number of seconds into Hours, Minutes and Seconds, modulo comes in handy.

hours:int   = seconds / 3600;
minutes:int = (seconds / 60) % 60;
seconds:int = seconds % 60;

starting with 582 seconds:

hours   = 582 / 3600 = 0 // integer would round this to 0
minutes = (582 / 60) % 60 = (9.7) % 60 = 9
seconds = 582 % 60 = 42

Thus, 582 seconds is 9 minutes, 42 seconds.


Example 4: Force a number to be a multiple of another number

Another way of thinking of this example is forcing a number to be evenly divisible by another number.

Let's say you need to have a number that is always a multiple of 10. You can use modulo in this way to accomplish it:

multipleOfTen = x - (x % 10);

By subtracting the remainder of a value x divided by 10 from x we get a value that is always divisible by 10. It's a neat mathematical trick.

For x=1 through x=9, for example, x%10 is always x. Thus:
multipleOfTen = 1 - (1 % 10) = 1 - (1) = 0;
multipleOfTen = 2 - (2 % 10) = 2 - (2) = 0;
multipleOfTen = 3 - (3 % 10) = 3 - (3) = 0;
...
multipleOfTen = 9 - (9 % 10) = 9 - (9) = 0;

once we hit 10, we get:
multipleOfTen = 10 - (10 % 10) = 10 - (0) = 10;

and once we hit 20 we get:
multipleOfTen = 20 - (20 % 10) = 20 - (0) = 20;


But...how is this useful? Well, imagine that you need to work with a data structure that is made up of values grouped in multiples. One such data structure is a ByteArray representing an audio file. Often times programming languages give you access to binary files as ByteArrays so that they are easy to operate upon (upload, write to the file system or perform data conversions).

Now, if you record 32-bit audio, you're capturing data 4 bytes at a time. That means that every audio sample, the smallest unit of data, is 4 bytes wide. Indexes 0 through 3 of the ByteArray would represent one sample.

If you were to split a byte array representing a 32-bit audio file in the middle of a 4-byte unit, you would "break" the audio file. When played back, you would either get an end of file error and/or it would sound like a screech.

In order to safely edit the audio ByteArray, you can only edit in multiples of 4, at the beginning or end of a 4 byte block, not in the middle.

So, let's say we want to trim some bytes from the start of the audio file. What's a safe starting index in the array?

Since the data is chunked in groups of 4, we can say:
safeStartIndex = startIndex - (startIndex%4)

A start index of 0 would yield a safeStartIndex of:
safeStartIndex = 0 - (0%4) = 0 - (0) = 0

A start index of 1 would yield:
safeStartIndex = 1 - (1%4) = 1 - (1) = 0

A start index of 2 would yield:
safeStartIndex = 2 - (2%4) = 2 - (2) = 0

A start index of 3 would yield:
safeStartIndex = 3 - (3%4) = 3 - (3) = 0

A start index of 4 would yield:
safeStartIndex = 4 - (4%4) = 4 - (0) = 4

Notice that by using modulo, we can automatically adjust non-safe ByteArray indexes to an index which is divisible by 4 and won't split the audio file represented by our array in the wrong place (ie. in the middle of a sample group).

Final Words

The WatchHogStories blog has another way of describing modulo which I really like. As Dotun, the author of the blog, says (with a slight modification):

* a is zero or a positive number.
* n is a positive number.
* if a / n equals a whole number then a % n  always equals 0
* if a is and less than n then a % n always equals a
* if a is greater than n then a % n always equals a value between 1 and n-1

HTML script tags can not be atomic/self-closing

Recently I completed a project where I converted an Actionscript form generation system I wrote for my wife's business into Javascript.

I've been writing Javascript on and off for the last, almost, 20 years. For easy coding, I started with all my code and css styles in the same html file, but eventually broke up everything into individual files.

I placed the stylesheet in its own file and loaded it using a standard <link> tag:

<link id="primaryStylesheet" rel="stylesheet" type="text/css" href="path/to/my/fancy/stylesheet.css" />

Notice how the I used the self-closing (atomic) version of the <link> tag (ends with "/>" rather than with a closing "</link>").

Then it was time to load in all the Javascript which was now in its own set of external files. I used a standard <script> tag for that:
<!-- DOESN'T WORK -->
<script type="text/JavaScript" src="/awesome/library.js" />

However, I was surprised to find that while my stylesheet loaded without a problem, my Javascript files did not. I knew this not because I got an error like "Javascript files did not load", but because the scripts that I knew to work and do something on screen no longer did anything. After a little investigation, I discovered they weren't in memory at all.

A little googling brought me to an entry on Siderite's Blog that explains he had the same problem and discovered that the W3C DOM recommendation states the following about the script tag:

Start tag: required, End tag: required

Thus, it can't be an atomic/self-closing tag. Browsers respect that, though they don't provide any error feedback, instead failing silently.
<!-- Works! -->
<script type="text/JavaScript" src="/awesome/library.js"></script>

So, thanks Siderite for reminding me that it pays to read specs. :-)