NEWS, EDITORIALS, REFERENCE

Subscribe to C64OS.com with your favorite RSS Reader
March 2, 2018#56 Reference

Key Map to Screen Editor

Post Archive Icon

The question driving the creation of this reference table is simple: If I press a key, or a key combined with one of the modifier keys (Shift, C=, or Control) what is going to appear on the screen?

Surprisingly, the answer is not straightforward. The keycaps of the Commodore 8-Bit family are famous for including a series of foreign-looking graphical symbols, sometimes on the key surface, sometimes printed on the front vertical face of the key. If you've ever used a C64, 128 or VIC-20, you know that in the mode immediately after turning the machine on, pressing a letter key will give you an uppercase letter, pressing shift and a letter will give you the right symbol of the two graphic symbols that appear on the key. Pressing C=Key and a letter will give you the left graphic symbol on the key.

But this is only the beginning. Many of the non-letter keys also have symbols, but not every symbol that you can generate with modifier combinations is represented on every key. And to make matters more complicated, switching the character set to uppercase/lowercase introduces other symbols that are not visible on the keycaps.

The tables below show what glyph will be produced on the screen (and every PETSCII control code that will be interpreted by the screen editor) for every key on the keyboard, in each of four possible modifications (Unmodified, Shift, C=, Control), in both character sets. See below for a full discussion.

Row 1 Uppercase / Graphics Lowercase / Uppercase
KeyCap Unmodified Shift Commodore Control Unmodified Shift Commodore Control
left arrow left arrow left arrow $06 left arrow left arrow left arrow $06
1 1 ! orange black 1 ! orange black
2 2 " brown white 2 " brown white
3 3 # lt.red red 3 # lt.red red
4 4 $ dk.grey cyan 4 $ dk.grey cyan
5 5 % md.grey purple 5 % md.grey purple
6 6 & lt.green green 6 & lt.green green
7 7 ' lt.blue blue 7 ' lt.blue blue
8 8 ( lt.grey yellow 8 ( lt.grey yellow
9 9 ) ) reverse on 9 ) ) reverse on
0 0 0 0 reverse off 0 0 0 reverse off
+ + nothing + nothing
- - nothing - nothing
£ pound $1C, red pound $1C, red
HOME home clear clear nothing home clear clear nothing
DEL delete insert insert nothing delete insert insert nothing
Row 2 Uppercase / Graphics Lowercase / Uppercase
KeyCap Unmodified Shift Commodore Control Unmodified Shift Commodore Control
CONTROL modifier key modifier key modifier key modifier key modifier key modifier key modifier key modifier key
Q Q $11, cursor down q Q $11, cursor down
W W $17 w W $17
E E $05, white e E $05, white
R R $12, reverse r R $12, reverse
T T $14, delete t T $14, delete
Y Y $19 y Y $19
U U $15 u U $15
I I $09, unlock i I $09, unlock
O O $0F o O $0F
P P $10 p P $10
@ @ $00 @ $00
* * nothing * nothing
up arrow $1E, green up arrow $1E, green
RESTORE NMI* NMI* NMI* NMI* NMI* NMI* NMI* NMI*

* RESTORE generates a hardware NMI signal direct to the CPU.

 
Row 3 Uppercase / Graphics Lowercase / Uppercase
KeyCap Unmodified Shift Commodore Control Unmodified Shift Commodore Control
STOP stop run run nothing stop run run nothing
SHIFT LOCK modifier key modifier key modifier key modifier key modifier key modifier key modifier key modifier key
A A $01 a A $01
S S $13, home s S $13, home
D D $04 d D $04
F F $06 f F $06
G G $07 g G $07
H H $08, lock h H $08, lock
J J $0A j J $0A
K K $0B k K $0B
L L $0B l L $0B
: : [ [ $1B : [ [ $1B
; ; ] ] $1D, cursor right ; ] ] $1D, cursor right
= = = = $1F, blue = = = $1F, blue
RETURN carriage return shifted-return* shifted-return* nothing carriage return shifted-return* shifted-return* nothing

* Shifted-return is PETSCII value $8D.

Row 4 Uppercase / Graphics Lowercase / Uppercase
KeyCap Unmodified Shift Commodore Control Unmodified Shift Commodore Control
C= modifier key modifier key modifier key modifier key modifier key modifier key modifier key modifier key
SHIFT modifier key modifier key modifier key modifier key modifier key modifier key modifier key modifier key
Z Z $1A z Z
X X $18 x X $18
C C $03, stop c C $03, stop
V V $16 v V $16
B B $02 b B $02
N N $0E, text n N $0E, text
M M $0D, carriage return m M $0D, carriage return
, , < < nothing , < < nothing
. . > > nothing . > > nothing
/ / ? ? nothing / ? ? nothing
SHIFT modifier key modifier key modifier key modifier key modifier key modifier key modifier key modifier key
↓CRSR↑ cursor down cursor up cursor up nothing cursor down cursor up cursor up nothing
←CRSR→ cursor right cursor left cursor left nothing cursor right cursor left cursor left nothing
Row 5 Uppercase / Graphics Lowercase / Uppercase
KeyCap Unmodified Shift Commodore Control Unmodified Shift Commodore Control
SPACE space shifted-space* shifted-space* nothing space shifted-space* shifted-space* nothing

* Shifted-space is PETSCII value $A0.

Right Side Uppercase / Graphics Lowercase / Uppercase
KeyCap Unmodified Shift Commodore Control Unmodified Shift Commodore Control
F1 F1 F2 F2 nothing F1 F2 F2 nothing
F3 F3 F4 F4 nothing F3 F4 F4 nothing
F5 F5 F6 F6 nothing F5 F6 F6 nothing
F7 F7 F8 F8 nothing F7 F8 F8 nothing
 

Discussion

The first thing to notice is that some key combinations do not cause a glyph to be rendered to the screen. These combinations are represented in the table above with italic text. Many control key combinations are filled in as nothing. That's because those combinations do not get decoded into anything by the KERNAL's key scanning routines. So, if you press Control and the Plus key, nothing at all will be put into the keyboard buffer. The interesting side effect of this is that if your program uses the standard routine for getting a character from the keyboard, (aka, GETIN, $FFE4) your program will have absolutely no idea that the user has depressed any keys at all.

This harkens back to one of my early posts, Why PETSCII anyway? GETIN merely returns you the next byte in the keyboard buffer. And the keyboard buffer only ever contains PETSCII values. And so if there are two or more key combinations that decode to the same PETSCII value, the program actually cannot determine which physical keys were used arrive at that PETSCII value. But, where is that relevant?

In the tables above, with the exception of nothing, all italicized text represents a non-glyph value that will be put in the keyboard buffer. Any glyph image shown in the tables are what will be produced, (in each character set), if the value from the keyboard buffer is output to the screen via the CHROUT ($FFD2) kernal call.

Many keys on the keyboard will put a non-glyph PETSCII value in the buffer, with or without a modifier key. Namely:

  • RUN/STOP
  • HOME/CLEAR
  • DEL/INS
  • CRSR LF/RT
  • CRSR UP/DN
  • RETURN
  • SPACE1, and
  • the F-keys

In every one of these cases they follow the same pattern. Unmodified the key results in the corresponding PETSCII value with bit7 low. The key combined with SHIFT produces the same nearly the same PETSCII value, but with bit7 flipped high.2 In all of these cases, combining the key with the Commodore key does exactly the same thing as combining with SHIFT. The oddity here is SPACE and RETURN, when shifted, also result in the PETSCII value with bit7 high. A regular RETURN is $0d, but SHIFT-RETURN results in $8d. A regular SPACE is $20, but SHIFT-SPACE is $a0. This strikes me as an odd decision.

Meanwhile, combining any of these keys with Control results in a nothing.

Close up of an older breadbin C64 keyboard.

Symbols and Alphabetic Keys

The alphabetic keys, A-Z, work consistently. In the Uppercase/Graphics character set, unmodified gives you an uppercase letter, with SHIFT you get the right-side graphic printed on the key and with the Commodore key you get the left-side graphic on the key. In the Lowercase/Uppercase character set you get the lowercase letter when unmodified, the uppercase letter with SHIFT and you continue to get the same left-side graphic when using the Commodore key. We'll discuss the Control key with alphabetic keys in a moment.

Things become less consistent when looking at the symbolic keys. Aka, those that are non-number and non-alphabetic but which still produce a glyph. These consist of (thematically grouped):

  • left pointing arrow, up pointing arrow
  • plus, minus, equals
  • colon, semi-colon, comma, period
  • British pound, @, asterisk and front slash.

These keys are a bit of a gong show. Unmodified you get the main symbol printed on the key surface, regardless of character set. So, you just push the plus key, and you get a plus symbol regardless whether you're in Uppercase/Graphics or Lowercase/Uppercase.

But some of these keys have two symbols printed on the top surface of the key. These keys behave the same way as each other, these form a special group that are the only ones which behave like they do. These keys are: comma, period, front slash, colon and semi-colon. For each of these keys with SHIFT you get the upper symbol on the key surface, but you also get the upper symbol when used with the Commodore key, and you get exactly these same symbols regardless of which character set you use.

The others are real oddballs. The equals key, for example, unmodified, SHIFT or Commodore key and in both character sets, you get the same equals-sign glyph. Weird. It gets weirder though. You have the same situation with the left-pointing arrow. Unmodified, SHIFT or Commodore key you get a left-pointing arrow glyph in both character sets. Meanwhile, the up-pointing arrow unmodified gives you the up-pointing arrow glyph in both character sets, SHIFT and Commodore key result in the same alternative glyph... but they're different between the character sets. In Uppercase/Graphics you get the PI symbol, which is the only symbol printed on the front face of the key, but in Lowercase/Uppercase you get an inverse full-hash!! It's a mystery.

The plus and minus keys behave like each other, but not like any of the others. They both have three possible glyph outputs: Unmodified, SHIFT, and Commodore key. And all three of these glyphs that are the same across both character sets.

The asterisk key has got its own idiosyncracy. The unmodified press of the key produces an asterisk glyph in both character sets. But this key with SHIFT produces a PETSCII graphic symbol, the same one in both character sets. And when modified with the Commodore key we get a different graphic symbol, but which is different in each character set. This is like a key unto its own.

The @ key and the Britsh pound key are equally odd as the asterisk key, but different again. Unmodified you get the standard glyph in both character sets (@ and £). But, only in the Uppercase/Graphics character set do you get the right- and left-side graphics, printed on the key cap, with SHIFT and Commodore key respectively. When you flip into the Lowercase/Uppercase set, the SHIFTED version of @ changes to a squareroot symbol, and similarly on the £ key, the graphic changes to something not represented on the key. At first glance you might think these behave like the alphabetic keys, but not quite. With the alphabetic keys switching character sets changes the unmodified version of the key. But not with these keys, you get the @ and £ symbols in both sets. The squareroot symbol comes out of the blue. It's not obvious that squareroot should be a shifted version of @, but nor is it represented on key cap itself. These keys are a lot like the asterisk key, but which modifier results in a glyph that stays the same between the character sets is different.

As I said, it's a gong show. The only way to figure out what any given key is going to do when modified is to see it in the tables above.

The Control Key

The Control key is the most strange and mysterious key. There is at least one consistent thing to say about it. It never causes visual glyphs to appear on the screen. It always produces either no effect whatsoever, or it puts a non-rendering PETSCII code into the keyboard buffer. And because of this, the character set doesn't make any difference, because the character set is only relevant for how to render a character that will be rendered.

The most common use of the Control key is to modify the 1 through 0 keys (10 keys in the first row.) Commodore key plus 1 through 8 sets the current color to the color words printed on those key caps. With the Control key then, 1 through 8 sets the current color to the other 8 possible colors. And on the SX-64 and C128 keyboard, these additional 8 color words are also printed on the key.

The 9 key and 0 key have RVS ON and RVS OFF printed on them. Control is used as the modifier to access these functions. And remember, selecting a current color, and turning reverse on or off, these are all done with single byte PETSCII codes.

With many keys on the keyboard, if you hold down Control and press them, nothing happens. And your BASIC program has no ability to (short of PEEKing into the KERNAL somewhere, maybe) know that you're even holding down the Control key. These include, but are not limited to: The F-keys, SPACE, the cursor keys, period, comma, front slash, RUN/STOP, and others.

Now, here's the weird thing. There is a whole series of keys that produce a byte value that's equal to their screen code, and put that in the keyboard buffer. How does this work exactly, well, every key that produces the character in PETSCII's Block 3, puts the corresponding byte from Block 1 into the buffer. You might want to refer to the PETSCII Table for this. So these keys put these values: @ puts $00, A puts $01, B $02, C $03, etc. all the way and including those that follow z in PETSCII: [ puts $5B, £ puts $5C, ] $5D and lastly the up-pointing arrow puts $5E.

But, of course, this is Commodore we're talking about here, so we need an exception. The left-pointing arrow is the last character of PETSCII Block 3. And pressing it modified with Control does indeed put a value into the keyboard buffer. Following the pattern it should put $5F. It does not. Instead it puts $06, the same value as Control F. Why? Who the hell knows.

On the one hand, this can be pretty nifty and useful in some bizarre cases. For example, if you need to send specific low byte values (from Block 1, so $00 to $30) to a serial bus device, from BASIC, you can start a string with a quote, then press Control H to drop in a $08 byte, then close the string. Believe it or not, this is exactly what I was helpfully told to do by Glenn Holmer (aka ShadowM or Cenbe on IRC) for sending some special commands to the uIEC/SD.

But, on the other hand, this has a rather odd side effect. Because many, but not all, of those low byte values are PETSCII control codes, these Control combinations collide seemingly at random other more sensible ways of inputting the same codes. In the tables above, for these Control combinations I've listed both the raw byte value as well as the PETSCII control code it corresponds with. Here are some examples, do these really make sense?

Control £Changes current color to red
Control QMoves cursor down
Control TDeletes a character
Control SMoves cursor home
Control ;Moves cursor right
Control MCarriage Return

There are many others. Seriously, try these! Who knew that Control M does a carriage return? And it's a true carriage return. Type load "$",8 and then hit Control M, the command will be execute just as surely as if you'd pressed the RETURN key. In fact, there is no way for your program to know, when it pulls a $0D byte from the keyboard buffer, whether that byte was put there with by pressing RETURN or pressing Control M. Very bizarre. Most of them just don't make sense.

UPDATE: November 11, 2021

When I first made this post, I didn't realize the history of the Control key. You can read more about it here: https://en.wikipedia.org/wiki/Control_key#History.

The standard behavior of the Control key, going back to the days of the Teletype machine, is to clear the high two bits of 7-bit ASCII, specifically with the intention of allowing the user to produce characters in ASCII Block 0 (codes 0 to 31) from the keyboard. This is not merely a weird Commodore thing.

I don't know how I never noticed this before, but even on a modern Mac, in UNIX-y applications like the Terminal, CTRL-M produces a carriage return. Here's another interesting one: CTRL-G produces an alert. That's the ASCII code for bell, which—when it was received and processed—was supposed to ding a physical bell to draw the attention of the operator.

Although, there are actually others that do kinda make sense. And I'm not sure whether it's intentional or just a happy accident. Control C puts a $03 in the buffer, because it's the 3rd letter in the alphabet. But $03 is the PETSCII control code for STOP. It's what gets put in there when you press the dedicated STOP key. But, this is also the control sequence for interrupting a command line program in UNIX, ^c. So, maybe Commodore assigned $03 to mean STOP intentionally because it would correspond with Control C. Who knows. Another one is Control R turns Reverse on. If that's not intentional, then it is a very happy coincidence. There is however no Control combination that can subsequently turn Reverse off.

UPDATE: December 6, 2018

Control C, under normal circumstances, such as at the READY prompt, does indeed put the PETSCII STOP value into the keyboard buffer. But I now believe it's entirely coincidental. The reason is because despite this happy correspondence, you cannot actually use Control C as a substitute for the STOP key in most of the cases where stop is useful.

For example, you cannot use Control C to stop the execution of a BASIC program, even though this is the most obvious and common use case. Nor can you use it to stop loading a file from disk. The reason is because during these circumstances the KERNAL does not do a full keyboard scan. It does the minimum scan necessary to detect if the physical STOP key's matrix switch is closed. The process is interrupted, but the STOP PETSCII value doesn't get buffered.

It is not possible therefore to remap the position of the STOP key simply by moving the STOP PETSCII value ($03) to a different place in the KERNAL's key map tables. You'd have to change the key scanning routines themselves. This all considered, Control C being STOP is probably just a coincidence.

Where does this come from?

You might wonder, where do all these key and modified key values come from? Everything described explicitly in the tables above derive from the four tables below.

These tables are found in the standard C64 KERNAL ROM, the addresses of each row of 8-bytes is included with each table. The key scanning routines decode which modifier you're pressing and use that to select one of the 4 tables. The other key you are pressing is used as an index into the selected table. This is why it is impossible to combine two or more modifier keys. Commodore plus Control together doesn't make any sense, together they don't select for some mythical 5th table.3

Anywhere in the tables above where the value produced by using SHIFT is the same as the value produced by using the Commodore key, that is because the value at certain indexes is the same between the Shifted and C=Key tables. Ie.

Row 0, Column 0, is 94 in both tables, that's INSERT.
Row 5, Column 7, is 3C in both tables, that's Less Than.

Meanwhile, anywhere where you see the same glyph in both character sets for a given key-with-modifer, that's just because that at that index in the character set in ROM, the same glyph appears in both character sets.



Standard Keyboard Table            Shifted Keyboard Table

.:EB81 14 0D 1D 88 85 86 87 11     .:EBC2 94 8D 9D 8C 89 8A 8B 91
.:EB89 33 57 41 34 5A 53 45 01     .:EBCA 23 D7 C1 24 DA D3 C5 01
.:EB91 35 52 44 36 43 46 54 58     .:EBD2 25 D2 C4 26 C3 C6 D4 D8
.:EB99 37 59 47 38 42 48 55 56     .:EBDA 27 D9 C7 28 C2 C8 D5 D6
.:EBA1 39 49 4A 30 4D 4B 4F 4E     .:EBE2 29 C9 CA 30 CD CB CF CE
.:EBA9 2B 50 4C 2D 2E 3A 40 2C     .:EBEA DB D0 CC DD 3E 5B BA 3C
.:EBB1 5C 2A 3B 13 01 3D 5E 2F     .:EBF2 A9 C0 5D 93 01 3D DE 3F
.:EBB9 31 5F 04 32 20 02 51 03     .:EBFA 21 5F 04 22 A0 02 D1 83
.:EBC1 FF                          .:EC02 FF


C=Key Keyboard Table               Control Keyboard Table

.:EC03 94 8D 9D 8C 89 8A 8B 91     .:EC78 FF FF FF FF FF FF FF FF
.:EC0B 96 B3 B0 97 AD AE B1 01     .:EC80 1C 17 01 9F 1A 13 05 FF
.:EC13 98 B2 AC 99 BC BB A3 BD     .:EC88 9C 12 04 1E 03 06 14 18
.:EC1B 9A B7 A5 9B BF B4 B8 BE     .:EC90 1F 19 07 9E 02 08 15 16
.:EC23 29 A2 B5 30 A7 A1 B9 AA     .:EC98 12 09 0A 92 0D 0B 0F 0E
.:EC2B A6 AF B6 DC 3E 5B A4 3C     .:ECA0 FF 10 0C FF FF 1B 00 FF
.:EC33 A8 DF 5D 93 01 3D DE 3F     .:ECA8 1C FF 1D FF FF 1F 1E FF
.:EC3B 81 5F 04 95 A0 02 AB 83     .:ECB0 90 06 FF 05 FF FF 11 FF
.:EC43 FF                          .:ECB8 FF


Lowercase Uppercase Character Set @2X Uppercase Graphics Character Set @2X

Lowercase/Uppercase Character Set, and Uppercase/Graphics Character Set.


I hope someone out there finds these tables, and the discussion, useful in his or her adventures with the Commodore 64.

For a full and interactive reference to all of this stuff, be sure to checkout:
https://www.pagetable.com/c64ref/charset/

  1. SPACE is sort of a pseudo-non-glyph kinda character. It technically results in a glyph that has no visual appearance, but it feels a bit like a cursor manipulation control, like RETURN or the cursor keys. Plus, its shifted version is much like RETURN's. []
  2. If you want to know why it works this way, refer to my other programming reference post on PETSCII Codes. []
  3. Just to note, keyboard handling is done entirely differently in C64 OS. How C64 OS does things is not entirely modern, mostly for reasons of lack of memory, but it is significantly closer to the way things are today than the way they were done in the KERNAL ROM. []

Do you like what you see?

You've just read one of my high-quality, long-form, weblog posts, for free! First, thank you for your interest, it makes producing this content feel worthwhile. I love to hear your input and feedback in the forums below. And I do my best to answer every question.

I'm creating C64 OS and documenting my progress along the way, to give something to you and contribute to the Commodore community. Please consider purchasing one of the items I am currently offering or making a small donation, to help me continue to bring you updates, in-depth technical discussions and programming reference. Your generous support is greatly appreciated.

Greg Naçu — C64OS.com

Want to support my hard work? Here's how!