TweetFollow Us on Twitter

Key Mapper
Volume Number:2
Issue Number:10
Column Tag:Forth Forum

Keyboard Re-Mapper Utility

By Jörg Langowski, MacTutor Editorial Board

Keyboard configuration and reconfiguration

This time I'd like to address a problem that is rather neglected in Inside Macintosh, but not by MacTutor, and that is the configuration of the Mac keyboard. [As background, you may wish to refer to the August issue for an article by Joel West and David Smith on the Keyboard Sleuth.] The section on international resources mentions the different existing keyboards, their layouts and the keycodes; but it is nowhere said explicitly how the keycode that is sent out when a key is pressed is mapped to an ASCII character and where the tables are kept that are used for that assignment.

There is one program, the Localizer, that is generally used to change the keyboard configuration from one layout to another. This works well for the standard keyboards that come for the different countries in which the Mac is sold. It would be very convenient, though, to be able to change the keyboard mapping according to one's taste. That way one could layout a Dvorak keyboard or make simple changes just to have some different symbols available, without changing the whole keyboard arrangement. As an example, I prefer to have a decimal point instead of a comma on my (German) Mac+ numeric keypad, without changing the rest of the layout so that all the symbols stay where they are. There is no 'canned' configuration in the localizer that provides for this change. So, here's a nice chance to write a small application in Forth that does something useful and at the same time show some instructive details about how the keyboard is configured.

The INIT 0 and INIT 1 resources

Doing so requires some NOSYing around in the routines that translate keycodes into ASCII characters. These routines are built at system initialization time through the INIT resources ID=0 and ID=1. [One can find this out easily by looking at the Localizer, which contains quite a few INIT resources that all look very much the same except for some tables that contain the actual keyboard mapping]. Disassembly reveals how a keycode is translated into an ASCII character by the INIT routines. See Listing 1. The modifier bits (Shift, Option, Caps Lock) are taken as an index into a small offset table, from which the beginning of the actual translation table is obtained. The keycode then serves as an index into that table. Two different translation tables exist for the old Mac and the Mac+ keyboards. The keyboard type is read from the system global KybdType at $21E, which is continually being updated by the background routine that checks for the presence of a keyboard. A hex $B here means we have a Mac+ keyboard plugged in, other numbers so far refer to the old keyboard, and keypad, optionally. [A zero means, there is no keyboard... but in that case, we'll never get to this routine anyway...]

A very simple way to change the translation table to our preferences is to emulate the table lookup process in Forth, starting with the keycode. Mach1 (also the new version Mach2) contains the word ?TERMINAL which returns the character code, keycode and modifier flags if a key has been pressed.

Fig. 1 Our Keyboard Remapper in Mach2

Listing 2 defines a couple of words that will return the absolute address of the translation table entry from the keycode and modifiers. keycode and modifiers return the respective fields. keyaddress, given a modifier / keycode input on the stack, determines which INIT resource to use (INIT 0 for the main keyboard and INIT 1 for the numeric keypad), leaves a handle to that resource on the stack and the table entry's address on top of it. This address can then be used by the remapping routine to put a new entry into the table. The handle will be used to call _ChangedResource to mark the INIT resource as changed so that it is rewritten when _UpdateResource is called at the end.

get.key1.data and get.key2.data are words that are used by keyaddress to determine the beginning of the translation tables for the main and numeric keyboards. They are somewhat kludgy as they make use of the internal structure of the INIT 0 and INIT1 resource codes, reading the table addresses out of the LEA <data>,A0 instructions at the beginning of the code. When a system is released where those instructions occur in different positions, my program will get completely lost. In that case, it would either have to be modified to accommodate the new addresses or the kludge would have to be generalized, using a routine that looks for a LEA <data>,A0 instruction. All this is embarassingly bad programming style, but it was the simplest way that I could think up to find the table addresses.

The INIT resources are read once at the beginning of the main word remap and stored in two variables hand0 and hand1. remap itself is an endless loop which comprises the user dialog for remapping of the keys. When the user hits the go-away box, the loop is exited through a vector which is installed in the task's goaway-hook; the resource file is updated (file id=0 indicates the System file), and control is returned to the Finder.

The program can be compiled into a standalone application through the normal turnkey process built into Mach1; a turnkeyed version can be found on the MacTutor source disk.

While the remapper is being used, the INIT resources already in memory from boot-up will of course stay as they are. Only the copies of INIT 0 and INIT 1 in the present System file are changed and rewritten. This means that your keyboard will stay in its old configuration until you reboot with the disk that contains the changed System file.

Mach2, assembler bug, etc.

The new version of Mach - Mach2 - has been released a long time ago as you read this. As I write this, however, I have just taken a short look at the changes and improvements that have been made. The main change for execution speed is that the DO...LOOP index and limit have been moved from the loop stack into registers (only the innermost loop). This speeds up loop execution tremendously, so that the famous Sieve now executes in just about seven and one half seconds, which is only one second slower than TML Pascal code. Another benchmark I wrote that does 50 screen inversions (explicitly, without calling InvertRect) also executes only about 15% slower than Pascal code.

The disadvantage is that many more registers are now being internally used by the Mach2 system. In fact, Palo Alto Shipping warned me not to use any registers in CODE definitions without saving and restoring them. Therefore, if you try to use the floating point routines or many of the other examples that you could find here with Mach2, you're likely to be disappointed. Inserting MOVEM.L A0-A4/D0-D7,-(A7) and MOVEM.L (A7)+, A0-A4/D0-D7 in strategic places will help tremendously to fight frustration in that case.

The assembler bug which caused faulty coding of some instructions (seeV2#8) has been fixed, and they even promised that the Forth debugger would work Real Soon Now. Meanwhile, TMON is still the best way to debug with Mach2.

Where did the $%&§ output go...

A multitasking system like Mach has its peculiarities, which have to be learned. Somebody from the local developer's group had problems getting Quickdraw calls drawing into a window he had set up in Mach1. When he would turnkey the program, however, everything would work fine. It seemed like under some circumstances, with the Mach1 system window open, the system would use a different grafPort from what he thought.

There is a rather simple explanation to this problem. Mach1 keeps a flashing cursor going in any window in which QUIT, the interpreter main loop, is running, which causes the current port to be reset to that window's grafPort. It is the programmer's responsibility to make sure that the currently active grafPort is the one that one wants to use. Since any task keeps a pointer to its associated window in a user variable, this is easy to achieve by doing a _setPort to this window. (One could argue that the task scheduler should automatically reset the current port to the task's own window. In my opinion, that would not be a good idea, since it would create a lot of overhead on switching tasks. Furthermore, the task actually might want to use another grafPort, this would make the initial resetting unnecessary anyway.)

Listing 1: excerpts from the INIT0 and INIT1 key translation routines
;
; alphanumeric keyboard translator, Apple System File
;
INIT0  BRA     com_1 ; setup jump vector

proc2    BRA.S   lac_2
data1    DC.W    $FFFF,$4B45,$5943,1,$301,0

proc3    LEA     data8,A0    ; Mac+ translate table
 CMPI.B  #11,KybdType ; 11 = Mac+
 BEQ.S   lac_1
  LEA     data9,A0    ; old Mac translate table
lac_1    MOVEQ   #7,D0
 AND     D1,D0
 ADD     D0,D0 ; modifier byte*2
 MOVE    0(A0,D0.W),D0 ; offset for modifiers 
 ADD     D2,D0
 MOVE.B  0(A0,D0.W),D0 ; table entry
 RTS     

lac_2    CMPI    #52,D2 ; main entry point, D2 contains keycode
 BHI.S   lac_3  ; was modifier key pressed?
 BSR     proc3  ; if not, translate through table
 TST.B   KeyMap+6
 BPL.S   lac_4 ; if no control key
 BTST    #0,D1 ; shift pressed?
 BEQ.S   lac_4
 BTST    #2,D1 ; option pressed?
 BNE.S   lac_4
 BCLR    #0,D1 ; clear shift bit
 BSR     proc3  ; and retranslate
 CMPI.B  #48,D0 ; is it
 BCS.S   lac_4 ; a number key?
   CMPI.B  #57,D0
 BHI.S   lac_4
 TST.B   D3
 BMI.S   lac_4
 TST.B   ScrDmpEnb ; deal with FKEYs
 BEQ.S   lac_4
 SUBI.B  #48,D0
 MOVE.B  D0,ScrDmpType
lac_3    MOVEQ   #0,D0
lac_4    .
 .
 . ( code that deals with diacritical marks,
 .  etc. etc. )
 .
 RTS
 .

data8    ; Mac+ key translate table (German keyboard)
 DC.W    $10,$45,$7A,$45,$AF,$E4,$119,$E4
 ; ( offsets for modifier keys)
  DC.W    $6173,$6466,$6867,$7978,$6376,$62,$7177,$6572

  DC.W    $AEC6,$CEB2,$B0D0,$7EB5,$C909,$CAD4,$800

data9    ; Old Mac key translate table (German keyboard)
 DC.W    $10,$45,$7A,$45,$AF,$E4,$119,$E4
 ; ( offsets for modifier keys)
  DC.W  $6173,$6466,$6867,$3C79,$7863,$2D76,$7177, $6572
 .
 . ( DC.W offsets for modifiers etc.)
 .
  
  DC.W    $AEF1,$CE0D,$F7C9,$F5F6,$F809,$3D4,$8CA
                                         
com_1    LEA     proc2,A0
 MOVE.L  A0,Key1Trans  ; $29E
 RTS 
;    
; numeric keypad translator
;
INIT1  BRA     com_1 ; setup jump vector
proc2    LEA     data1,A0    ; translate table
 CMPI.B  #11,KybdType ; 11 = Mac+
 BEQ.S   lac_1
 ADDA.W  #64,A0 ; offset for old Mac
lac_1    LSR     #1,D1
 BCC.S   lac_2
 ADDA.W  #32,A0 ; offset for shift key
lac_2    ANDI.B  #$1F,D2
 MOVE.B  0(A0,D2.W),D0 ; get table entry
 RTS                                             
data1    DC.W    $2C,$1D00,0,$1C1B,$1F00,0,$31E,$2D00
  DC.W    0,$3031,$3233,$3435,$3637,$38,$3900,0
  DC.W    $2E,$2A00,0,$2B1B,$3D00,0,$32F,$2D00
  DC.W    0,$3031,$3233,$3435,$3637,$38,$3900,0
  DC.W    $2C,$1D00,0,$1C1B,$1F00,0,$31E,$2D00
  DC.W    0,$3031,$3233,$3435,$3637,$38,$3900,0
  DC.W    $2C,$2A00,0,$2B1B,$2E00,0,$32F,$2D00
  DC.W    0,$3031,$3233,$3435,$3637,$38,$3900,0
                                         
com_1    LEA     proc2,A0
 MOVE.L  A0,Key2Trans
 RTS                                          
 END     
Listing 2: Reconfiguring the Keyboard routines INIT 0 and INIT 1
( Keyboard reconfigurator, c 1986 J. Langowski / MacTutor )
( For reconfiguration of individual keys without using the Localizer 
)

only forth also assembler also mac

hex
494e4954 constant "init
21e constant keyb.type  ( B: Mac+ )
variable hand0  variable hand1

: get.handles
 "init 0 call getresource hand0 !
 "init 1 call getresource hand1 !
;
: get.key1.data ( | handle start.of.data )
 hand0 @ dup @ 7fffff and 14 + 
 keyb.type c@ B <> if C + then  dup w@ +
;
: get.key2.data ( | handle start.of.data )
 hand1 @ dup @ 7fffff and 6 + dup w@ +
 keyb.type c@ B <> if 40 + then  
;
: keyin
 begin 2d emit 8 emit ?terminal ?dup until
;
: keycode ( extracts keycode out of keyinfo )
 100 / ff and ;

: modifiers ( extracts modifiers from keyinfo )
 1000000 / ff and ;

: keyaddress { | mods keyc -- handle offset }
 dup  modifiers -> mods  keycode -> keyc
 keyc 41 < if get.key1.data 
 dup mods E and + w@ + keyc + 
   else get.key2.data 
 mods 2 and
 if ( shift key down) 20 + then
 keyc 1f and +
   then
;
: keytest
 begin keyin keyaddress c@ emit key drop drop again 
;
: get&show ( | handle offset )
 keyin dup key emit ."  - Keycode = " 
 dup modifiers swap keycode . 
 ." , Modifiers = " binary 
 <# # # # # #> type decimal 
 keyaddress dup c@ 
 ." , actual mapping - " emit cr
;
: keynum cr 
 begin get&show drop drop again
;
decimal

: hello 
 cls
 ." Macintosh Keyboard Remapper" cr
 ." © 1986 J.Langowski / MacTutor" cr cr
 ." Closing the window will update the resource file." cr cr
;
: yesno begin key dup emit 
 case 
 89 of 1 1 endof  121 of 1 1 endof
 78 of 0 1 endof  110 of 0 1 endof
 cr ." y or n - " 0 swap
 endcase
   until
;
: on.goaway 0 call updateresfile bye ;
 
: remap
 hello 
 get.handles
 begin
 ." Type the key you'd like to change - " cr
 get&show ( | handle offset )
 ." Do you want to remap this key (y/n) - " yesno cr
 if 
 ." Enter the character to map this key to - "
 key dup emit cr 
 swap c! 
     ( store in mapping table of INIT resource)
 call changedresource
 else 2drop
 then cr
 again
;
 
164 user goaway-hook

NEW.WINDOW remapper
" Keyboard Configuration Editor" remapper TITLE
50 20 316 496 remapper BOUNDS
ROUNDED VISIBLE CLOSEBOX NOGROWBOX 
 remapper ITEMS
600 5000 terminal mapper

: go.map activate remap ;

: start
 remapper add
 remapper mapper build
 ['] on.goaway goaway-hook task-> mapper !
 remapper dup call selectwindow call setport
 mapper go.map
; 
 

Community Search:
MacTech Search:

Software Updates via MacUpdate

Firetask Pro 4.2.2 - Innovative task man...
Firetask Pro uniquely combines the advantages of classical priority-and-due-date-based task management with GTD. Stay focused and on top of your commitments - Firetask Pro's "Today" view shows all... Read more
Bookends 13.4.3 - Reference management a...
Bookends is a full-featured bibliography/reference and information-management system for students and professionals. Bookends uses the cloud to sync reference libraries on all the Macs you use.... Read more
LibreOffice 6.4.5.2 - Free, open-source...
LibreOffice is an office suite (word processor, spreadsheet, presentations, drawing tool) compatible with other major office suites. The Document Foundation is coordinating development and... Read more
Thunderbird 68.10.0 - Email client from...
As of July 2012, Thunderbird has transitioned to a new governance model, with new features being developed by the broader free software and open source community, and security fixes and improvements... Read more
Firefox 78.0.1 - Fast, safe Web browser.
Firefox offers a fast, safe Web browsing experience. Browse quickly, securely, and effortlessly. With its industry-leading features, Firefox is the choice of Web development professionals and casual... Read more
BetterTouchTool 3.389 - Customize multi-...
BetterTouchTool adds many new, fully customizable gestures to the Magic Mouse, Multi-Touch MacBook trackpad, and Magic Trackpad. These gestures are customizable: Magic Mouse: Pinch in / out (zoom)... Read more
Slack 4.7.0 - Collaborative communicatio...
Slack brings team communication and collaboration into one place so you can get more work done, whether you belong to a large enterprise or a small business. Check off your to-do list and move your... Read more
OsiriX Lite 11.0.3 - 3D medical image pr...
OsiriX Lite is an image processing software dedicated to DICOM images (".dcm" / ".DCM" extension) produced by medical equipment (MRI, CT, PET, PET-CT, ...) and confocal microscopy (LSM and BioRAD-PIC... Read more
Wireshark 3.2.5 - Network protocol analy...
Wireshark is one of the world's foremost network protocol analyzers, and is the standard in many parts of the industry. It is the continuation of a project that started in 1998. Hundreds of... Read more
Dabble 1.6.1 - Organize your manuscript,...
Dabble organizes your manuscript, story notes, and plot. Dabble simplifies the story, leaving more room in your brain to create, which is what being a writer is really about. Organize your story.... Read more

Latest Forum Discussions

See All

Pokemon Go's July Community Day wil...
Pokemon Go developers have announced the details concerning the upcoming Gastly Community Day. This particular event was selected by the players of the game after the Gas Pokemon came in second place after a poll that decided which Pokemon would... | Read more »
Clash Royale: The Road to Legendary Aren...
Supercell recently celebrated its 10th anniversary and their best title, Clash Royale, is as good as it's ever been. Even for lapsed players, returning to the game is as easy as can be. If you want to join us in picking the game back up, we've put... | Read more »
Detective Di is a point-and-click murder...
Detective Di is a point-and-click murder mystery set in Tang Dynasty-era China. You'll take on the role of China's best-known investigator, Di Renjie, as he solves a series of grisly murders that will ultimately lead him on a collision course with... | Read more »
Dissidia Final Fantasy Opera Omnia is se...
Dissidia Final Fantasy Opera Omnia, one of Square Enix's many popular mobile RPGs, has announced a plethora of in-game events that are set to take place over the summer. This will include several rewards, Free Multi Draws and more. [Read more] | Read more »
Sphaze is a neat-looking puzzler where y...
Sphaze is a neat-looking puzzler where you'll work to guide robots through increasingly elaborate mazes. It's set in a visually distinct world that's equal parts fantasy and sci-fi, and it's finally launched today for iOS and Android devices. [... | Read more »
Apple Arcade is in trouble
Yesterday, Bloomberg reported that Apple is disappointed in the performance of Apple Arcade and will be shifting their approach to the service by focusing on games that can retain subscribers and canceling other upcoming releases that don't fit... | Read more »
Pixel Petz, an inventive platform for de...
Pixel Petz has built up a sizeable player base thanks to its layered, easy-to-understand creative tools and friendly social experience. It revolves around designing, trading, and playing with a unique collection of pixel art pets, and it's out now... | Read more »
The King of Fighters Allstar's late...
The King of Fighters ALLSTAR, Netmarble's popular action RPG, has once again been updated with a plethora of new content. This includes battle cards, events and 21 new fighters, which increases the already sizeable roster even more. [Read more] | Read more »
Romancing SaGa Re;univerSe, the mobile s...
Square Enix latest mobile spin-off Romancing SaGa Re;univerSe is available now globally for both iOS and Android. It initially launched in Japan back in 2018 where it's proven to be incredibly popular, so now folks in the West can finally see what... | Read more »
Away: Journey to the Unexpected is a sto...
Away: Journey to the Unexpected looks really quite lovely. Stylish, cute, and clearly heavily inspired by Japanese animation, it's amongst the best-looking mobile games on the horizon. Developed by a two-person team, this story-driven rogue-lite... | Read more »

Price Scanner via MacPrices.net

July 4th Sale: Woot offers wide range of Macs...
Amazon-owned Woot is blowing out a wide range of Apple Macs and iPads for July 4th staring at $279 and ranging up to just over $1000. Models vary from older iPads and 11″ MacBook Airs to some newer... Read more
Apple Pro Display XDR with Nano-Texture Glass...
Abt Electronics has Apple’s new 32″ Pro Display XDR model with the nano-texture glass in stock and on sale today for up to $144 off MSRP. Shipping is free: – Pro Display XDR (nano-texture glass): $... Read more
New 2020 Mac mini on sale for up to $100 off...
Amazon has Apple’s new 2020 Mac minis on sale today for $40-$100 off MSRP with prices starting at $759. Shipping is free: – 2020 4-Core Mac mini: $759 $40 off MSRP – 2020 6-Core Mac mini: $998.99 $... Read more
July 4th Sale: $100 off every 2020 13″ MacBoo...
Apple resellers have new 2020 13″ MacBook Airs on sale for $100 off Apple’s MSRP as part of their July 4th sales. Starting at $899, these are the cheapest new 2020 MacBooks for sale anywhere: (1) B... Read more
This hidden deal on Apple’s site can save you...
Are you a local, state, or federal government employee? If so, Apple offers special government pricing on their products, including AirPods, for you as well as immediate family members. Here’s how... Read more
Apple Watch Series 3 models on sale for new l...
Amazon has Apple Watch Series 3 GPS models on sale for $30 off MSRP, starting at only $169. Their prices are the lowest available for these models from any Apple reseller. Choose Amazon as the seller... Read more
Deal Alert! Get these refurbished 2018 13″ Ma...
Apple has restocked and lowered prices on select Certified Refurbished 2018 13″ MacBook Airs, starting at only $679. Each MacBook features a new outer case, comes with a standard Apple one-year... Read more
July 4th Sale: 13″ 2.0GHz MacBook Pros for $2...
B&H Photo has new 2020 13″ 2.0GHz MacBook Pros on sale for $200 off Apple’s MSRP as part of their July 4th sale. Prices start at $1599. These are the same MacBook Pros sold by Apple in their... Read more
July 1 only: $100 off Apple iPhone 11, 11 Pro...
Boost Mobile is offering Apple iPhone 11, 11 Pro, and iPhone 11 Pro Max models for $100 off MSRP with service. Their discount reduces the cost of an iPhone 11/64GB to $599, iPhone 11 Pro to $899 for... Read more
Apple offers $50-$100 Education discount on i...
Purchase a new 12.9″ or 11″ iPad Pro at Apple using your Education discount, and Apple will take $50-$100 off their MSRP. All teachers, students, and staff of any educational institution with a .edu... Read more

Jobs Board

Operating Room Assistant, *Apple* Hill Surg...
Operating Room Assistant, Apple Hill Surgical Center - Full Time, Day Shift, Monday - Saturday availability required Tracking Code 62363 Job Description Operating Read more
Perioperative RN - ( *Apple* Hill Surgical C...
Perioperative RN - ( Apple Hill Surgical Center) Tracking Code 60593 Job Description Monday - Friday - Full Time Days Possible Saturdays General Summary: Under the Read more
Product Manager, *Apple* Commercial Sales -...
Product Manager, Apple Commercial Sales Austin, TX, US Requisition Number:77652 As an Apple Product Manager for the Commercial Sales team at Insight, you Read more
*Apple* Mac Product Engineer - Barclays (Uni...
Apple Mac EngineerWhippany, NJ Support the development and delivery of solutions, products, and capabilities into the Barclays environment working across technical Read more
Blue *Apple* Cafe Student Worker - Pennsylv...
…enhance your work experience. Student positions are available at the Blue Apple Cafe. Employee meal discount during working hours. Duties include food preparation, Read more
All contents are Copyright 1984-2011 by Xplain Corporation. All rights reserved. Theme designed by Icreon.