NEWS, EDITORIALS, REFERENCE
In this post we're going to talk about mouse tracking and the difference between proportionality, speed and acceleration.
I'm a big fan of acceleration for reasons that we'll get into shortly, including a video demonstration. But I didn't realize until fairly recently, when I started doing research on the topic, that mouse acceleration is actually a very contentious issue, particularly amongst PC gamers.1 But it's also a sticking point for switchers from PC to Mac (or vice versa) because the default acceleration curves are different between the two operating systems. This can lead to your muscle memory making wrong predictions about how the mouse cursor will move on the screen based on how you move the mouse around on the table. It's such an annoyance for some people that there are numerous third party utilities for both platforms that allow you to override the system defaults and customize the mouse movement much more finely.
Most C64 users back in the day had a joystick, or two or ten. But only a small number of those same users also had a mouse. I was one of the former for at least several years. My first C64 was a second–hand C64c, with a 1541-II, an EPYX Fastload cartridge and an original copy of GEOS v1.2 included in (and advertised on) the box. I also had several joysticks and no mouse.
When I discovered GEOS, it was my first experience with a graphical user interface and it positively captivated me. It is probably the reason I am still obsessed with operating systems 28 years later. GEOS comes with loadable drivers for different input devices, so it supports either a joystick or a mouse.
What is a Directional Input Device?
A C64 joystick is a directional input device. It essentially consists of 5 digital (on/off) buttons. Up/down/left/right and fire. If you press the left-button and hold it down, then every 60th of a second the computer uses the same CIA chip it uses to scan the keyboard to notice that the button is depressed. But from scan to scan there is fundamentally no change of input, it just notices that the button is still held down. Given this unchanging, digitally ON state, how far should the computer move the on–screen cursor at each 60th of a second?
Naively you could just pick a speed, a fixed number of pixels for each second that the button is continuously depressed. But whatever fixed speed you choose, you end up with one of two problems: If you pick a relatively slow speed then it takes frustratingly long to have the cursor travel all the way from one side of the screen to the other. But if you choose a speed fast enough that you can zip from one side to the other satisfyingly quickly, then it becomes frustratingly difficult to make small accurate moves. You tap that joystick left for the briefest amount of time you can physically pull off, and the cursor shoots past the edge of the tiny rectangle you're trying to get it over.
The main problem is that the Joystick, with its digitally on or off buttons is not proportional. We'll get to that in a second, because there is still something you can do to improve life without a proportional input device. You need something more sophisticated than a fixed speed. What you really need are some controls on speed and acceleration. If you were ever a GEOS user, maybe you remember this settings panel?
This settings panel gives you three sliders. Acceleration, Max Velocity and Min Velocity. Minimum velocity is the the speed that the cursor starts moving at when you first push a directional button. Maximum velocity is the fastest that it can move, which is typically set at something higher than the minimum velocity. And acceleration is the length of time it takes to speed up from the minimum to the maximum velocity.
This helps. It certainly helps. The cursor can move slowly over short distances for better precision, but if you keep holding the button down it'll speed up to get you across the screen much faster.
What is a Proportional Input Device?
The Commodore 1351 mouse was first released in 1986, and is compatible with the C64 and c128.2 Commodore also released the very similar looking 1350 mouse. But don't be deceived, the 1350 is actually just a directional input device, much like a joystick only harder to use. I honestly have no idea why they bothered to make the 1350.3
The 1351, however, is a proportional input device. It uses analog features of the SID chip to be able to read an 8 bit number from each axis, X and Y, on every 60th of a second scan. The greater the distance traveled by the mouse between scans, the larger that 8 bit number will be. Proportionality was a revolution in input control. Even though the Mac had a proportional mouse two years before Commodore released one, who really cares? All we Commodore users needed to know was that once you'd used GEOS with a mouse, it was so good that you would never ever want to go back to using a joystick.
A true mouse is inherently proportional, whereas the speed and acceleration of a joystick have to be faked. But, what does proportional really mean?
It means that there is a relationship between the physical distance the mouse moves across the table, and the distance the cursor moves across the screen. Obviously, the distance across the screen, as a physical distance, depends on how big the screen is. On an SX-64's 5" screen, moving the whole way across the screen is just 5" of physical distance. While on a 13" monitor (like my beloved 1084S), moving across the screen means moving 13 physical inches, or however big they are after you account for the borders. For the simplicity of discussion, let's just pretend that the monitor is sized such that one inch on the table moves the cursor one inch on the screen.
What's so great about a proportional device is the following: If you want to move the cursor two inches on the screen, you need to move the mouse two inches on the table. But how fast you want to do that is up to you. You can get there in 1 second, by moving the mouse at 2 inches per second, or you can get there in half a second by moving the mouse at 4 inches per second. That's amazing.
It's so inherently great, that to my knowledge, the velocity and acceleration settings in GEOS do not apply to the mouse driver, but only to the joystick driver. You don't really need them for the mouse, right? How fast you want to go can already be set by how quickly you choose to move your hand. How quickly you want to accelerate is already determined by how quickly your hand accelerates. It's perfect, right? Well. Almost.
What is Tracking Speed?
In the examples above I said, let's specify that one inch on the table is one inch on the screen. I said that so the math would be easy. But let's think about what's really going on.
The C64's screen is roughly square. But its screen resolution is more rectangular, 320x200 is a ratio of 1.6, or 8/5. That means that from a pixel perspective the distance across the screen is further than the distance from top to bottom.
Next, the mouse driver, the software reading and interpreting the mouse hardware input, is able to get an 8-bit number for distance, along each axis, every 60th of a second. This number has to account for both directions, so the number is signed. A signed 8-bit value can range from -128 to +127. So the question is, what should the relationship be between the value the mouse reports and the pixels traversed? Should it be one–to–one? What would that mean?
If you move the mouse and the software reads the hardware and gets a number like 50, then we'd move the cursor 50 pixels across the screen (along that axis). And if you moved the mouse more slowly, and the software read a value of only 25, well then we'd move the cursor 25 pixels across the screen.
50 pixels is a quarter of the distance from the top of the screen to the bottom. (200/50 is 4.) So what happens if it turns out that you only have to move the mouse half an inch to get a number like 50? You barely move the mouse on the table, and the cursor has already moved a quarter of the way up the screen, it would be hard to get precision like that. But, what if the opposite happens? What if it turns out, you have to move the mouse 5 inches to get it to generate a number like 50? To move the mouse only a quarter of the way across the screen you've gotta practically push the mouse off the far edge of the table.
There is the additional problem that even though the screen appears square, it's horizontal resolution is higher, which means the mouse would move slower horizontally than vertically with exactly the same speed. If you traced a circle with your hand, you'd get an oval on the screen.
Instead, we can calibrate the number of pulses from the mouse to the number of pixels to move. This calibration is effectively just a multiplier. The distance traveled will remain exactly proportional to how far you push the mouse, but the ratio of mouse distance to on–screen distance can be increased or decreased using a multiplier (to slow it down, division is just a multiplier that's less than one.) Furthermore, you could have different multipliers for each axis to account for the difference in resolution along those axes.
People clearly have different opinions about what makes a good mouse.
As it turns out, this is the holy grail for PC gamers. They want the mouse to be precisely proportional. But they want to have control over the tracking speed, as a raw multiplier of the value provided by the mouse. On PCs having control over the multiplier matters a lot more because of the vaste variety of mice you could hook up. The internals of different mice will lead to a different raw pulse count for physical distance traveled. We'll return to this in a moment.
The C64 programs I tested, (Wheels and GoDot), use proportional input, with a fixed multiplier. This is less of an issue on a C64, because there are fewer choices of mouse. Every 1351 behaves the same way, although I really should test out different PS/2 mice hooked up via a MicroMys and other PS/2 mouse adapters. Additionally, arbitrary multiplication is a pain on a 6502, and an 8-bit number has a very small range, especially when you start introducing integer multiplication.
I based the mouse driver in C64 OS on the sample code printed at the back of the 1351 user manual. To my surprise, the mouse driver source code at codebase64.org is basically identical to that found in the 1351 manual. I suspect it's probably the same essential routine used in nearly every C64 program that supports the 1351.
Also, interestingly, it embeds a multiplier. Multiplying or dividing by orders of two are extremely cheap and easy in 6502. One merely shifts left or right respectively. That's what this standard routine does. It LSR's once to divide the value in half. If the mouse provides a change of 50, the cursor is moved 25 pixels on the screen.
This is speed. By default the tracking speed would be too high, so the driver hardcodes a speed multiplier of 0.5. Beyond the adjustment in speed, the motion of the cursor is always proportional to the motion of the mouse. But does the story end here? Actually, it doesn't.
What is Acceleration?
We already saw the word acceleration, in the context of a directional input device like a joystick. That was the acceleration of the speed of the cursor over a period of time during which it was non–proportionally instructed: move left. Proportional acceleration is a step beyond that.
Windows and macOS both provide proportional acceleration. It is incredibly useful on the desktop, in fact I argue that you'd never want to live without it. But PC gamers hate it! If you search the web today for "mouse acceleration", you find page after page where nearly every hit is someone asking how to turn mouse acceleration off. So, in order to understand what it is, let's look at how this Mac gamer describes it:
To understand what I mean by mouse acceleration, try this:
Senseful — StackExchange, January 2011
- Place your finger on the left most side of the trackpad.
- Very slowly, move your finger all the way to the right of the trackpad, and observe that the cursor doesn't move very much on the screen.
- Now try the same thing, but this time move your finger really fast from one side of the trackpad to the other. You should see that the cursor has moved a significant amount of distance more than it did previously, even though your finger traveled the same distance.
That, in a nutshell, is a acceleration. He explains it on a trackpad, but the principle is exactly the same with a mouse. If you move the mouse slowly, the speed multiplier is low. But as you move the mouse faster, not only does the cursor move faster because you're moving your hand faster, but a higher speed multiplier is also used. This is actually no longer merely proportional. It's accelerated proportional.
Here are the control panels in the latest versions of Windows and macOS, side–by–side, for mouse tracking.
They each provide a slider, and, in my opinion and most certainly in the opinion of PC gamers, they both mislabel what that slider does. In Windows it says "Select a pointer speed:" with a slider from slow to fast. In macOS, it's labeled "Tracking speed" also with a slider from slow to fast. Both of these sliders actually control the amount of acceleration. I haven't tested this out on Windows, but on macOS if you set the "Track speed" down as slow as possible, it minimizes the effects of acceleration. But, on the other hand, it's very slow! There is no separate control to allow you set the speed multiplier as described earlier, without also using acceleration.
My understanding is that the situation is very similar with that Windows control. What they call pointer speed is not the tracking speed multiplier, but affects the acceleration curve. Windows also includes that curious little checkbox that says, "Enhance pointer precision." I had to look up what that does. Apparently, if you turn that on, when you move the mouse slowly, it uses a multiplier less than 1.4 In other words, when moving slowly, the pointer tracks even slower, so you can get the pointer to move with even finer pixel precision, even though the acceleration might be quite pronounced. Neat.
What is the real world effect of acceleration?
Gamers have their own reason for not liking acceleration. Something to do with muscle memory and precision control of who you're shooting and where, in the latest mind–bendingly realistic 3D first person shooter. This is a world I have almost no experience with.
But on the desktop, I would argue, that acceleration is essential to the efficient and effective use of a mouse. This is surely why in both Windows and macOS, used by hundreds of millions of people around the world, there is no built–in way to even turn acceleration off. Acceleration is critical to the experience of a mouse being fast and efficient. Meanwhile, GEOS and Wheels, and GoDot and other C64 programs do not use acceleration. I asked around, and most modern computer users are not consciously aware that their mouse is accelerated. It just feels natural to them. They move the mouse with a goal in mind, and the pointer dances across the screen and gets there without any annoyance.
This is, of course, a hallmark of good design. It gets out of the way, the user doesn't notice it, but meanwhile it actually takes a lot more code and a lot more sophistication to accomplish what feels simpler, more natural, or even invisible.
C64 OS has got acceleration. I made this video to show the comparison between Wheels, GoDot and C64 OS. After the video, I'll go into some detail about how acceleration works.
It's not totally perfect. In the video I was having some issue getting up into the upper right corner of the screen. However, on the whole, the difference should be clear and pretty stark.
The converse of a modern user being unconscious of the fact that acceleration is taking place, is that when you don't have acceleration you are often not conscious of exactly what it is that feels wrong. All you get is the experience of: this is slow. For example, you sit down at a demo machine running GEOS or Wheels at a Commodore Expo, you try to use it for a second and you find, to move the mouse across the screen you have to pick up the mouse, reposition it and give another swipe to get it fully to the top, say. You're not quite sure what's wrong, it just feels sluggish. It's natural to assume that it's just inherently sluggish, because, what the hell, right? You're on a 35 year old machine with a 1Mhz CPU, it's gonna feel slow, right? What more do you expect?
This is a psychological illusion.
It's hard to put your finger on exactly why it feels slow, so it's easy to jump to the conclusion that an old computer, producing a slow experience, is a simple causal relationship.
These sorts of cognitive biases are well known. Steve Jobs once told a funny story about iTunes and random shuffling of the playback of songs. As it happens, random shuffling means that there is some probability that the same song will play twice in a row, and some slightly higher probability that you'll hear the same song twice just a few songs apart. But the probability that you'll get through all the songs in the list before you hear a repeat is very low, even though that's what people actually prefer. So, in order to improve shuffle mode, they had to intentionally make the whole process less random. This seems counter–intuitive, but is an example of the principle that to get a more natural outcome often requires more sophistication which means more code.
Your brain naturally expects mouse acceleration, and when it's strictly proportional, it feels sluggish, like you're dragging the pointer through molasses.
How does acceleration work?
It's hard to get a straight answer on how exactly acceleration is implemented. Partially because its implementation is different between operating system platforms like Windows, Linux and macOS, likely it's even different between versions of those operating systems. And furthermore, most of these implementations are closed source, leaving people guessing at how they work based on usage experiments.
Microsoft's tech documents, in my search experience, seem to be the most forthcoming, and I am left to imagine that Apple's approach is similar. Basically, the mouse driver references a series of perhaps 10 or more thresholds. These are physical mouse speed thresholds. Each threshold is like a breakpoint at which can be defined a multiplier. The break point of each threshold as well as the multiplier value at each of those thresholds can all be customized. Taken together with the points plotted on a graph, they define a curve. This is what is known as the acceleration curve.
When the mouse moves slowly, the system moves the cursor at a constant rate that is directly proportional to the rate at which the mouse moves. But if the mouse moves faster than the value of MouseThreshold1 or MouseThreshold2, the system can respond by accelerating the movement of the cursor, so that the cursor moves two or four times as fast as the mouse. MouseSpeed — docs.microsoft.com, September 2008
Let's imagine a generic mouse, for no system in particular. The mouse is scanned at a regular interval. On the C64, by the way, this is usually 60 times a second. But on PCs it is usually the mouse itself that reports its own updates. And different mice have different levels of precision. 120 times a second is common, but up to 500 times a second for high precision mice is not unheard of.
The user moves the mouse slowly, and slowly pushes it faster. On subsequent scans, the mouse reports: 4, 5, 8, 10. On each of those scans, the value falls below the first threshold set at say 12. And so the mouse is moved one–to–one, 4 pixels, then 5, then 8, then 10 pixels. But then the speed of the physical mouse crosses that first threshold and the mouse now reports the next several values as: 13, 18, 25, 29. Because these all fall in the second threshold, they are multiplied by the multipler for that zone, say 1.5. And so the cursor moves with each report: 19 pixels, 27 pixels, 37 pixels, and then 43 pixels. And so on.
This is a utility for macOS called ControllerMate. There are some limitations on which input drivers it's able to affect. However if you use a driver that it can influence, it allows you to visually customize the acceleration curve. Shown above is someone's attempt on the Mac to use ControllerMate to have their mouse simulate the curve used on Windows.
The horizontal X-Axis, is physical mouse speed. Each of the 12 black points represents a physical speed threshold. The vertical Y-Axis is the speed multiplier used on movement of the cursor. To be honest, I don't know what the scale is or what the units on those axes represent. But, you can get an idea of what this would accomplish.
How does acceleration in C64 OS work?
All of the above is interesting. It's neat to see how things have developed. But the C64 is a much simpler machine, and it doesn't need anywhere near this level of sophistication. Partially because we need to conserve memory and CPU cycles. But partially because we really just don't need it. The screen resolution is a fixed size, and it's relatively small. It's been 320x200 pixels for 35 years. And the mouse is mostly the same mouse, with some possible exceptions for some of the more recent adapters.
But the biggest constraint is working within a signed 8-bit range. If we stick to integer multipliers, and we don't want to overflow the value 127, then just think about how those thresholds and multipliers would get compressed. If there were 10 thresholds, and therefore 10 multipliers, at a bare minimum the 10th multiple would be just 10. (Otherwise, you've got multiple thresholds with the same multipler, in which case, there is no point in having that many thresholds.) But at a bare minimum of 10, a reported value of just 13 from the mouse would multiply out to 130, which overflows the signed 8-bit range!
In other words, the 8-bit range is so small, that 10 threshold points is completely useless. There is effectively no play room to actually shape a curve.
But, I'm still convinced that mouse acceleration is useful, despite these limitations.
So, here's what I've got in C64 OS:
- Two fixed multipliers, and
- One customizable threshold
And that's it. The two fixed multipliers are as follows: 0.5 and 1.0. And the customizable threshold is a value that comes out of the main system config file, and is accessed as an environment variable. Basically, you get to choose at what physical mouse speed the driver stops dividing the value by two. The division by two is done with an LSR, and it's already part of the most common C64 mouse routines, as discussed earlier. The LSR is used because without it the tracking speed just feels too fast.
In C64 OS, you set the threshold. If the speed exceeds that threshold then the LSR is skipped over, and the faster 1:1 speed is used, instead of the reduced 2:1. Believe it or not, such a simple addition makes the mouse feel significantly faster. After using C64 OS for a while and getting used to being able to zip the cursor across the screen with a quick flick of the hand, going back into Wheels and poking around feels unbearably slow, even before we get into opening any menus.
That was a lot of lead up to a very small change. But, I had a lot of fun learning about mouse acceleration. And hopefully others will get something out of the discussion.
A comparison of the menu system between C64 OS and Wheels/GEOS will be the subject of another post that I've got on my list to write up soon.
- When I say "PC gamer" I really mean Mac gamer too. Basically, by PC gamer I mean those gamers using modern computers, typically with a combination of mouse and keyboard controls. As opposed to a console gamer with a dedicated controller, or a retro computer gamer. [↩]
- And their related variations: SX-64, C64c, c128D, etc. Essentially all the machines that have a SID chip. [↩]
- Little known secret, you can put a 1351 into 1350 mode by holding down the button on the right while powering on the computer. Now you can use your 1351 with any game that supports a joystick, if you're a total masochist. [↩]
- Actually, don't quote me on that. I've read contradictory reports about exactly what that option does. But, at least some sites report that at slow mouse speeds, the cursor becomes exaggeratedly slow allowing you to move the cursor one pixel at a time. That sounds plausible to me. [↩]