[comp.sys.mac.programmer] Problem setting KCHR resource

minow@thundr.dec.com (Fortran for Precedent) (10/15/88)

(This didn't seem to get out the first time: apologies if you see it twice)

I'm writing a VT200 terminal emulator that implements the Dec LK201 keyboard.
This means that my "option" character set is completely different from Apple's
(I use a private font), and I have to handle the Option overstrikes
differently.  Because of a bug in the operating system, this isn't possible
to do cleanly (<Option>e passes through deadkey processing before my event
handler sees it).  I thought I could fix this by creating my own KCHR
resource (following Tech Note 160).  My private resource is identical to
the system resource except that all <Option> handling points to the "standard" 
eyboard.

The code seems to run correctly, except for three problems:

-- KeyTrans doesn't put the SICN resource in the menu bar.
-- GetScript(... smScriptIcon) returns zero, not my resource id (however
   GetScript(... smScriptKeys) returns the correct value.
-- The keyboard action doesn't change.

I can live with the first two, but the last problem is driving me batty.
Any suggestions as to what I'm doing wrong would be greatly appreciated.

Martin Minow
minow%thundr.dec@decwrl.dec.com

/*
 * This hack is called at program startup.  It finds the current keyboard
 * mapping resource (KCHR) and creates a new KCHR that does not have any
 * deadkeys.  This allows our LK201 compose routine to work without
 * interference from the system keyboard translator.  I suppose creating a
 * proper KCHR resource (with our mapping) would be somewhat better, but it's
 * a pain. The associated SICN resource is in the resource file.
 */
void
setup_KCHR_resource()
{
	register int		i;
	int			KCHR_resource_id;
	Handle			kchr, new, sicn;
	union {
	    unsigned char	*c;
	    short int		*i;
	}			table;
	int			n_tables;
	long			size;
	OSErr			status;
	
	KCHR_resource_id = GetScript(smScriptKeys, GetEnvirons(smKeyScript));
	kchr = GetResource('KCHR', KCHR_resource_id);
	if (kchr == NIL) {
	    error_message("No KCHR?", ResError());
	    return;
	}
	HLock(kchr);
	table.c = (unsigned char *) *kchr;
	n_tables = table.i[1 + (256 / sizeof (short))];
	/*
	 * n_tables has the number of keyboard mapping tables (8 for US).
	 * Build a resource just big enough.
	 */
	size =
		  sizeof (short)		/* Version number	*/
		+ 256				/* Table indexes	*/
		+ sizeof (short)		/* number of tables	*/
		+ (n_tables * 128)		/* the actual tables	*/
		+ sizeof (short);		/* Number of deadkeys	*/
	new = NewHandle((long) size);		/* Get the resource	*/
	if (new == NIL) {
	    error_message("No room for KCHR?", (int) size);
	    HUnlock(kchr);
	    return;
	}
	HLock(new);
	BlockMove(*kchr, *new, size);
	HUnlock(kchr);				/* Done with kchr	*/
	table.c = (unsigned char *) *new;	/* table -> new KCHR	*/
	table.i[1 + 128 + 1 + (n_tables * 64)] = 0;	/* No deadkeys	*/ 
	table.c += sizeof (short);		/* -> table @ indexes	*/
	/*
	 * Walk through the table_index entries.  When we find one
	 * with optionKey set, change it to point to the table without
	 * option key (but with the same arrangements of shift/caps/control).
	 * Not that this will leave some dangling (unused) tables.  Can't
	 * win 'em all.
	 */
#define	OPT	(optionKey >> 8)
	for (i = 0; i < 256; i++) {
	    if ((i & OPT) != 0)
		table.c[i] = table.c[i & ~OPT];
	}
	HUnlock(new);
	AddResource(new, 'KCHR', KCHR_resource_id, "\pLK201 KCHR");
	if (ResError() != noErr) {
	    error_message("Can't add KCHR resource", ResError());
	    return;
	}
	SetResAttrs(new, 0);			/* Clear "changed" bit	*/
	if (GetResource('SICN', KCHR_id) == NIL) {
	    error_message("No SICN?", ResError());
	    return;
	}
	status = SetScript(smRoman, smScriptKeys, KCHR_id);
	if (status != noErr)
	    status = SetScript(smRoman, smScriptIcon, KCHR_id);
	if (status != noErr)
	    error_message("Can't SetScript", status);
	KeyScript(smRoman);
	Debugger();
	status = GetScript(GetEnvirons(smKeyScript), smScriptKeys);
	/* This returns the expected value (KCHR_id)			*/
	status = GetScript(GetEnvirons(smKeyScript), smScriptIcon);
	/* This returns zero and "my" keyboard isn't enabled and the	*/
	/* icon doesn't show						*/
}