[comp.sys.sun] Dvorak keyboard software on a Sun

dewar@cpsc.ucalgary.ca (Alan Dewar) (02/28/89)

In article <890201-093010-10574@Xerox>, SBartlett.OsbuSouth@xerox.com writes:
> Does anyone out there in net-land know of a way I can configure a Sun to
> treat its standard keyboard as having a Dvorak layout?

I put together a Dvorak keyboard for the Sun 3 some time ago, mostly just
to see if it could be done.  What I wrote was actually a little more
general than that--it can be used to set any keyboard mapping you like.
The user interface is somewhat unfriendly, I'm afraid.  You have to edit
binary files by hand if you want anything new.  (I started with the
standard QWERTY mapping, obtained by my "getkbd.c", and edited it to get a
Dvorak layout.) In any event, it works, and I did get a Dvorak keyboard.
Any enhancements to the programs would be welcome.

The following programs, getkbd.c and setkbd.c, respectively get and set
the keyboard mapping, writing to stdout or reading from stdin.  Two
mappings (uuencoded) are also included:  qwerty.kbd and dvorak.kbd.

Alan Dewar	Computer Science Dept.	University of Calgary
dewar@cpsc.UCalgary.CA		..!alberta!calgary!dewar
- - - - - - - - - - - - - - - - - cut here - - - - - - - - - - - - - - - - -
/* getkbd.c								*/
/* write the current Sun 3 keyboard layout to stdout (for setkbd)	*/
/*									*/
/* Written:	88-04-20 Alan Dewar (dewar@cpsc.UCalgary.CA)		*/

#include <stdio.h>
#include <sys/file.h>
#include <sys/ioctl.h>
#include <sundev/kbd.h>
#include <sys/types.h>
#include <sundev/kbio.h>

static int	TABLEMASKS[] = {0, CAPSMASK, SHIFTMASK, CTRLMASK, UPMASK};
#define NMASKS	( sizeof(TABLEMASKS) / sizeof(int) )

main ()
{
    int			fd;
    struct kbd_data {
	struct keyboard	kbd;
	struct keymap	map[NMASKS];
	char		string[16][KTAB_STRLEN];
    }			data;
    struct kiockey	key;
    int			mask, station;
    int			m, n;
    int			err;

    fd = open ("/dev/kbd", O_RDWR);
    if (fd < 0) {
	fprintf (stderr, "Cannot open /dev/kbd\n");
	exit (-1);
    }
    for (m = 0; m < 16; m++) {
	for (n = 0; n < KTAB_STRLEN; n++) {
	    data.string[m][n] = '\0';
	}
    }

    for (mask = 0; mask < NMASKS; mask++) {
	((struct keymap **)(&data.kbd))[mask] = &data.map[mask];
	key.kio_tablemask = TABLEMASKS[mask];
	for (station = 0; station < 128; station++) {
	    key.kio_station = station;
	    err = ioctl (fd, KIOCGETKEY, &key);
	    if (err != 0) {
		fprintf ("Error %d encountered\n", err);
	    }
	    data.map[mask].keymap[station] = key.kio_entry;
	    if (key.kio_entry >= STRING && key.kio_entry < STRING+16) {
		m = key.kio_entry & 0x0F;
		for (n = 0; n < KTAB_STRLEN; n++) {
		    data.string[m][n] = key.kio_string[n];
		}
	    }
	}
    }
    key.kio_tablemask = -1;
    err = ioctl (fd, KIOCGETKEY, &key);
    if (err != 0) {
	fprintf ("Error %d encountered\n", err);
    }
    data.kbd.k_abort1 = key.kio_station;
    key.kio_tablemask = -2;
    err = ioctl (fd, KIOCGETKEY, &key);
    if (err != 0) {
	fprintf ("Error %d encountered\n", err);
    }
    data.kbd.k_abort2 = key.kio_station;

    for (mask = 0; mask < NMASKS; mask++) {
	(long) (((struct keymap **)(&data.kbd))[mask]) =
		(char *) (((struct keymap **)(&data.kbd))[mask])
		- (char *) (&data);
    }
    fwrite (&data, sizeof(data), 1, stdout);
}
- - - - - - - - - - - - - - - - - cut here - - - - - - - - - - - - - - - - -
/* setkbd.c								*/
/* set the Sun 3 keyboard layout as specified by stdin (from getkbd)	*/
/*									*/
/* Written:	88-04-20 Alan Dewar (dewar@cpsc.UCalgary.CA)		*/

#include <stdio.h>
#include <sys/file.h>
#include <sys/ioctl.h>
#include <sundev/kbd.h>
#include <sys/types.h>
#include <sundev/kbio.h>

static int	TABLEMASKS[] = {0, CAPSMASK, SHIFTMASK, CTRLMASK, UPMASK};
#define NMASKS	( sizeof(TABLEMASKS) / sizeof(int) )

main ()
{
    int			fd;
    struct kbd_data {
	struct keyboard	kbd;
	struct keymap	map[NMASKS];
	char		string[16][KTAB_STRLEN];
    }			data;
    struct kiockey	key;
    int			mask, station;
    int			m, n;
    int			err;

    fd = open ("/dev/kbd", O_RDWR);
    if (fd < 0) {
	fprintf (stderr, "Cannot open /dev/kbd\n");
	exit (-1);
    }
    if (fread (&data, sizeof(data), 1, stdin) != 1) {
	fprintf (stderr, "Cannot read keyboard data\n");
	exit (-2);
    }
    for (mask = 0; mask < NMASKS; mask++) {
	(char *) (((struct keymap **)(&data.kbd))[mask]) =
		(char *) (&data)
		+ (long) (((struct keymap **)(&data.kbd))[mask]);
    }

    for (mask = 0; mask < NMASKS; mask++) {
	key.kio_tablemask = TABLEMASKS[mask];
	for (station = 0; station < 128; station++) {
	    key.kio_station = station;
	    key.kio_entry = data.map[mask].keymap[station];
	    if (key.kio_entry >= STRING && key.kio_entry < STRING+16) {
		m = key.kio_entry & 0x0F;
		for (n = 0; n < KTAB_STRLEN; n++) {
		    key.kio_string[n] = data.string[m][n];
		}
	    }
	    err = ioctl (fd, KIOCSETKEY, &key);
	    if (err != 0) {
		fprintf ("Error %d encountered\n", err);
	    }
	}
    }
    key.kio_tablemask = -1;
    key.kio_station = data.kbd.k_abort1;
    err = ioctl (fd, KIOCSETKEY, &key);
    if (err != 0) {
	fprintf ("Error %d encountered\n", err);
    }
    key.kio_tablemask = -2;
    key.kio_station = data.kbd.k_abort2;
    err = ioctl (fd, KIOCSETKEY, &key);
    if (err != 0) {
	fprintf ("Error %d encountered\n", err);
    }
}
- - - - - - - - - - - - - - - - - cut here - - - - - - - - - - - - - - - - -
begin 644 qwerty.kbd
M    (@   *(   $B   !H@   B(           %-     **1HL&BX.&BXJ+C
MHN2BY:+FY^@&HM#1TJ+"PZ*B&S$R,S0U-C<X.3 M/6 (HM/4U:+$HL6B"7%W
M97)T>75I;W!;77^BUK'8HL;'S:*$87-D9F=H:FML.R=<#:*SVK2BR,[)HH)Z
M>&-V8FYM+"XO@PK<LMZBHJ*B@) @D**BHJ>HHI&BP:+@X:+BHN.BY*+EHN;G
MZ :BT-'2HL+#HJ(;,3(S-#4V-S@Y,"T]8 BBT]35HL2BQ:()45=%4E1954E/
M4%M=?Z+6L=BBQL>BHH1!4T1&1TA*2TP[)UP-HK/:M*+(SLFB@EI80U9"3DTL
M+B^#"MRRWJ*BHJ* D""0HJ*BIZBBD:+!HN#AHN*BXZ+DHN6BYN?H!J+0T=*B
MPL.BHALA0",D)5XF*B@I7RM^"*+3U-6BQ*+%H@E15T525%E524]0>WU_HM:Q
MV*+&QZ*BA$%31$9'2$I+3#HB? VBL]JTHLC.R:*"6EA#5D).33P^/X,*W++>
MHJ*BHH"0()"BHJ*GJ**1HL&BX.&BXJ+CHN2BY:+FY^@&HM#1TJ+"PZ*B&S$ 
M,S0U'C<X.3 ?/1X(HM/4U:+$HL6B"1$7!1(4&14)#Q ;'7^BUK'8HL;'HJ*$
M 1,$!@<("@L,.R<<#:*SVK2BR,[)HH(:& ,6 @X-+"X?@PK<LMZBHJ*B@)  
MD**BHJ>HHI&BH:*AH:*AHJ&BH:*AHJ&AH:&BH:&@HJ&AHJ*@H*"@H*"@H*"@
MH*"@H*"BH:&@HJ&BH:*@H*"@H*"@H*"@H*"@H**AH:"BH:&BHH2@H*"@H*"@
MH*"@H*"@HJ&AH**AH:&B@J"@H*"@H*"@H*"#H*&AH**BHJ*@D*"0HJ*BHJ8 
M            &UM!         !M;0@         ;6T0         &UM#    
M                                                            
M                                                            
8                                

end
- - - - - - - - - - - - - - - - - cut here - - - - - - - - - - - - - - - - -
begin 644 dvorak.kbd
M    (@   *(   $B   !H@   B(           %-     **1HL&BX.&BXJ+C
MHN2BY:+FY^@&HM#1TJ+"PZ*B&S$R,S0U-C<X.3!;76 (HM/4U:+$HL6B"2\L
M+G!Y9F=C<FPG/7^BUK'8HL;'S:*$86]E=6ED:'1N<RU<#:*SVK2BR,[)HH([
M<6IK>&)M=W9Z@PK<LMZBHJ*B@) @D**BHJ>HHI&BP:+@X:+BHN.BY*+EHN;G
MZ :BT-'2HL+#HJ(;,3(S-#4V-S@Y,%M=8 BBT]35HL2BQ:()+RPN4%E&1T-2
M3"<]?Z+6L=BBQL>BHH1!3T55241(5$Y3+5P-HK/:M*+(SLFB@CM12DM80DU7
M5EJ#"MRRWJ*BHJ* D""0HJ*BIZBBD:+!HN#AHN*BXZ+DHN6BYN?H!J+0T=*B
MPL.BHALA0",D)5XF*B@I>WU^"*+3U-6BQ*+%H@D_/#Y0649'0U),(BM_HM:Q
MV*+&QZ*BA$%/155)1$A43E-?? VBL]JTHLC.R:*".E%*2UA"35=66H,*W++>
MHJ*BHH"0()"BHJ*GJ**1HL&BX.&BXJ+CHN2BY:+FY^@&HM#1TJ+"PZ*B&S$ 
M,S0U'C<X.3 ;'1X(HM/4U:+$HL6B"1\L+A 9!@<#$@PG/7^BUK'8HL;'HJ*$
M 0\%%0D$"!0.$Q\<#:*SVK2BR,[)HH([$0H+& (-%Q8:@PK<LMZBHJ*B@)  
MD**BHJ>HHI&BH:*AH:*AHJ&BH:*AHJ&AH:&BH:&@HJ&AHJ*@H*"@H*"@H*"@
MH*"@H*"BH:&@HJ&BH:*@H*"@H*"@H*"@H*"@H**AH:"BH:&BHH2@H*"@H*"@
MH*"@H*"@HJ&AH**AH:&B@J"@H*"@H*"@H*"#H*&AH**BHJ*@D*"0HJ*BHJ8 
M            &UM!         !M;0@         ;6T0         &UM#    
M                                                            
M                                                            
8                                

end
- - - - - - - - - - - - - - - - - cut here - - - - - - - - - - - - - - - - -

kdo@lucid.com (Ken Olum) (03/01/89)

Here is a program I use to provide Dvorak emulation.

#include <sys/types.h>
#include <sys/file.h>
#include <sundev/kbio.h>
#include <sundev/kbd.h>
#include <stdio.h>


/* Places on the sun3 keyboard where the keys that we hack begin */
#define sun3_top_row 54
#define sun3_middle_row 77
#define sun3_bottom_row 100

/* Strings that describe what to do.  The 4 strings go into the normal, the
   shift, the all-caps and the control table.  In the control-table string only
   uppercase characters (@ through _) represent their control-character values.
   Other characters are unchanged */

char *normal_keys[4] = {
  "qwertyuiopasdfghjkl;zxcvbnm,./" , /* normal */
  "QWERTYUIOPASDFGHJKL:ZXCVBNM<>?" , /* shift */
  "QWERTYUIOPASDFGHJKL;ZXCVBNM,./" , /* caps */
  "QWERTYUIOPASDFGHJKL;ZXCVBNM,._"}; /* control */

char *dvorak_keys[4] = {
  "/,.pyfgcrlaoeuidhtns;qjkxbmwvz", /* normal */
  "?<>PYFGCRLAOEUIDHTNS:QJKXBMWVZ", /* shift */
  "/,.PYFGCRLAOEUIDHTNS;QJKXBMWVZ", /* caps */
  "_,.PYFGCRLAOEUIDHTNS QJKXBMWVZ"}; /* control */

/* Tell about how to use the program */
usage()
{
  printf("Usage: 'dvorak on' or 'dvorak off'\n");
  exit (1); }


main(argc,argv)
     int argc;
     char **argv;
{
  int fd,type;
  int dvorak;			/* true if going to dvorak */

  if (argc!=2) usage();
  if (strcmp(argv[1],"on") == 0) dvorak = 1;
  else if (strcmp(argv[1],"off") == 0) dvorak = 0;
  else usage();

  /* Open the keyboard device to hack on it */

  if ((fd = open("/dev/kbd",O_RDONLY,0)) < 0)
    xerror("Can't open /dev/kbd");

  /* Check that the keyboard is the right type.  They have different slots
     so we could lose badly if it isn't the right one */

  if (ioctl(fd, KIOCTYPE, &type) < 0)
    xerror("Can't determine keyboard type");
  if (type!=KB_SUN3) {
    printf("This only works if you have a Sun-3 keyboard\n");
    exit(1);}

  /* Now do the work */

  if (dvorak) set_key_set(fd, dvorak_keys);
  else set_key_set(fd, normal_keys);

  if (close(fd) < 0)
    xerror("Can't close /dev/kbd");
}

set_key_set(fd, set)
     char *set[4];
{
  set_key_table(fd, 0, set[0]);
  set_key_table(fd, SHIFTMASK, set[1]);
  set_key_table(fd, CAPSMASK, set[2]);	/* Caps is like shift */
  set_key_table(fd, CTRLMASK, set[3]);
}

/* Set 30 keys on 3 rows */

set_key_table(fd, table, string)
     int fd,table;
     char *string;
{
  set_key_row(fd, sun3_top_row, table, string);
  set_key_row(fd, sun3_middle_row, table, &string[10]);
  set_key_row(fd, sun3_bottom_row, table, &string[20]);
}

/* Set a row of 10 keys starting with START from string */

set_key_row(fd, start, table, string)
     int fd,table;
     char *string;
{
  char c;
  int i;

  for (i=0;i<10;i++) {
    c = string[i];		/* Get char from spec */
    if (table==CTRLMASK) {
      if ((c >= '@') && (c <= '_')) /* Chars that can be controlified */
	c = c&0x1F;		/* Do that, otherwise leave it alone */
    }
    do_set_key(fd, table, start++, c); }
}


do_set_key(fd, table, slot, value)
     int fd, table, slot, value;
{
  struct kiockey keyinfo;

  keyinfo.kio_tablemask = table;
  keyinfo.kio_station = slot;
  keyinfo.kio_entry = value;

  if (ioctl(fd, KIOCSETKEY, &keyinfo) < 0) {
    perror("Can't change key %d in table %d", slot, table);
    exit(1); }

  /* For debugging, check keys */
/*
  if (ioctl(fd, KIOCGETKEY, &keyinfo) < 0) {
    perror("Can't get key %d in table %d", slot, table);
    exit(1); }
  if (keyinfo.kio_entry == value)
    printf("%c", value);
  else printf("\n'%c' -> '%c'\n", keyinfo.kio_entry, value);
*/
}


xerror(str)
char *str;
{ perror(str);
  exit(1);}

dewar@cpsc.ucalgary.ca (Alan Dewar) (03/11/89)

My uuencoded keyboard-layout files seem to have escaped the mailers mostly
unscathed, with one exception.  The line immediately before the 'end' line
should not be empty, but should consist of a single SPACE character.
Otherwise, uudecode complains of a "Short file".  Make this change to the
uuencoded versions of qwerty.kbd and dvorak.kbd and things should work
fine.

Just in case any other mailers trimmed other trailing blanks, each line
after the 'begin' line and before the line beginning with '8' should have
enough trailing blanks to make all these lines the same length.  The line
which begins with '8' should have exactly 32 trailing blanks.

Alan Dewar	Computer Science Dept.	University of Calgary
dewar@cpsc.UCalgary.CA		..!alberta!calgary!dewar

dupuy@cs.columbia.edu (Alexander Dupuy) (03/11/89)

Under 4.0, there is a Defaults entry /Input/Keymap_Directory (by default,
/usr/lib/keymaps) which contains a number of .keydef files which should
seem to be something like the outpuy of your getkbd.c.  Ideally, these
should be used by input_from_defaults, but they don't seem to be.  There
doesn't seem to be any documentaion on their format.

Perhaps in 4.1, you will be able to set Input/Keymap_Directory
to ~/keymaps, and by running input_from_defaults, have a Dvorak keyboard
on any machine you use.

@alex

guy@uunet.uu.net (Guy Harris) (03/23/89)

>Perhaps in 4.1, you will be able to set Input/Keymap_Directory
>to ~/keymaps, and by running input_from_defaults, have a Dvorak keyboard
>on any machine you use.

I don't expect so, but I may be surprised.

However, I *do* expect you'll be able to use a new utility supplied with
4.1 to download the keyboard translation table so as to make it a Dvorak
keyboard (both in SunView and when talking to the "raw" console).  Of
course, with X11 and NeWS you'll have to use some other mechanism - e.g.,
changing the X11 server's keycode-to-keysym map so that it pretends you
have a Dvorak-labelled keyboard - since both X11 and NeWS servers (and,
probably, the X11/NeWS server when it comes out) run the keyboard in
untranslated mode, so that events read from "/dev/kbd" have keystation
codes, not ASCII or ISO 8859 characters, as event codes. 

pat@decwrl.dec.com (Pat Lashley) (03/30/89)

In article <8903010045.AA08334@cs.columbia.edu> dupuy@cs.columbia.edu (Alexander Dupuy) writes:
>    Under 4.0, there is a Defaults entry /Input/Keymap_Directory (by default,
>    /usr/lib/keymaps) which contains a number of .keydef files which should
>    seem to be something like the outpuy of your getkbd.c....

You might want to check out the loadkeys(1) and keytables(5) man pages,
and the files in /usr/share/lib/keytables.  I think that the various
layouts defined there are chosen with the /Input/Keyboard_Type defaults
entry.  The named files in /usr/share/lib/keytables appear to be hard
links to the layout_?? files.  It should be pretty easy for someone
familiar with the Dvorak layout to generate (and post <-- hint) an
appropriate table for a Type4 keyboard.

These man pages are marked as SunOS Release 4.0.1, they are not marked as
386i specific.  I think that the 386i is the only Sun currently available
with the type 4 keyboard referred to in loadkeys(1).  At least until
April... :-)

--- Reply to address below - DO NOT auto-route --- 
PMLashley	...{sun,megatest,sts,zygot}!cohesive!kla!pat
KLA Instruments	POBox 58016, 3901 Burton Drive
		Santa Clara, CA 95052		+1 408 988 6100