PS
# keyboardSVG.m4
 gen_init
 scale=25.4 # unit is mm

divert(-1)

define(`kbd_u',(11mm__))
define(`kbdrowsep',`movewid')
define(`kbdshadewid',`(kbd_u/9)')

                           `kbdkey(name|text=chars,keys)
                            chars: string or string string
                            keys: wdth=expr;  # base wid
                                  hght=expr;  # base ht
                                  rad=expr; # base rad
                                  shadewid=expr; # base shade wid
                                  base=attribs; # base attributes
                                  top=attribs;  # top attributes '
define(`kbdkey',
`pushkeys_(`$2',
  `wdth:kbd_u; hght:kbd_u*14/13+lthick; rad:kbd_u/10;
   shadewid:kbdshadewid; base:fill_(0.3):N; top:fill_(0.9):N')dnl
 [ Base: box wid m4wdth ht m4hght rad m4rad m4base
   Top:  box wid m4wdth-2*m4shadewid ht m4hght-m4shadewid-lthick \
     rad m4rad*(kbd_u-2*m4shadewid)/(kbd_u) with .n \
     at Base.n-(0,lthick) m4top
   move to Top.w
   ifelse(`$1',,,`pushkey_(`$1',text,,N)ifelse(m4text,,
    `"iflatex(\sf) `$1'" above ljust',
    `m4text');') `$3'
   popdef(`m4wdth', `m4hght', `m4shadewid', `m4rad', `m4base', `m4top') dnl
   popdef(`m4text') ] ')

define(`tsmall',
`iflatex(`"{\sf\scriptsize `$1'}"',
 ifelse(`$3',,")svg_fsize(`$1',ifelse(`$2',,75,`$2'))ifelse(`$3',,"))')

define(`stkbdkey',
`iflatex(`command "{\sf\scriptsize"',`m4tmp=textht
  textht = ifelse(`$1',,0.66*textht,`$1') ')
 kbdkey(shift($*))
 iflatex(`command "}%"',`textht = m4tmp')')

                           `enterkey(name|text=chars,keys)
                            chars: string or string string
                            keys: wdth=expr;  # base wid
                                  hght=expr;  # base ht
                                  bhght=expr;  # ht of bottom part
                                  rad=expr; # base rad
                                  shadewid=expr; # base shade wid
                                  base=attribs; # base attributes
                                  top=attribs;  # top attributes '
define(`enterkey',
`pushkeys_(`$2',
  `wdth:kbd_u*2.26;
   hght:kbd_u*14/13*2+kbdrowsep+linethick bp__;
   bhght: kbd_u*14/13;
   twdth: kbd_u*3/2;
   rad:kbd_u/10;
   shadewid:kbdshadewid;
   base:fill_(0.3):N;
   top:fill_(0.9):N')dnl
 [ ltx = lthick; r = m4rad*(kbd_u-2*m4shadewid)/(kbd_u)
# thick outer
   linethick = (m4shadewid+r)/(1bp__); lth2 = lthick/2
   NEx: Here; NE: NEx-(lth2,lth2); SE: NE-(0,m4hght-lth2*3-ltx*3/2)
   SW: SE-(m4wdth-lthick,0)
   W: SW+(0,m4bhght-lthick+ltx*3/2); NW: NE-(m4twdth-lthick,0); X: (NW,W)
   d = 0.3; ro = m4rad-lth2
   move to W; arcto(X,NW,m4rad+lth2,outlined graystring(d)); Tx:NW
   Loopover_(`PK',`arcto(Tx,PK,ro,outlined graystring(d));Tx:PK',NE,SE,SW,W,X)
   linethick = ltx
# outer outline
   NE: NEx; SE: NE-(0,m4hght+ltx); SW: SE-(m4wdth,0)
   W: SW+(0,m4bhght); NW: NE-(m4twdth,0); X: (NW,W)
   m4enteroutline(m4rad,,m4rad)
# thick inner
   linethick = m4shadewid/(1bp__)+linethick; lth2 = lthick/2
   NE: NEx-(m4shadewid+lth2,lth2+ltx); SE: (NE,SE)+(0,m4shadewid*3/2)
   SW: SE-(m4wdth-m4shadewid*3,0); W: SW+(0,m4bhght-m4shadewid*2-ltx*3/2);
   NW: NE-(m4twdth-m4shadewid*3,0); X: (NW,W)
   c = 0.9; ri = r-lth2
   move to W; arcto(X,NW,ri+lth2*2,outlined graystring(c)); Tx:NW
   Loopover_(`PK',`arcto(Tx,PK,ri,outlined graystring(c));Tx:PK',NE,SE,SW,W,X)
   N: 1/2 between NW and NE
   line from N to (N,SE) thick (NE.x-NW.x)/(1bp__) outlined graystring(c)
   SSW: 1/2 between SW and W
   line from SSW to (SE,SSW) thick (W.y-SW.y)/(1bp__) outlined graystring(c)
# inner outline
   NE: NE+(lth2,lth2); SE: SE+(lth2,-lth2); SW: SW-(lth2,lth2)
   W: W+(-lth2,lth2); NW: NW+(-lth2,lth2); X: (NW,W)
   linethick = ltx
   m4enteroutline(ri,,ri+lth2*2)
   move to (X,(1/2 between SW and W));
   ifelse(`$1',,,`pushkey_(`$1',text,,N)dnl
     ifelse(m4text,,`"iflatex(\sf) `$1'" above ljust',`m4text')')
   popdef(`m4wdth', `m4hght', `m4bhght', `m4twdth', `m4shadewid', `m4rad',
    `m4base', `m4top', `m4bhght' ) popdef(`m4text')dnl
   `$3' ] ')
define(`m4enteroutline',`move to W+(`$1',0); arcto(X,NW,`$3',`$2'); Tx: NW
 Loopover_(`PP',`arcto(Tx,PP,`$1',`$2'); Tx: PP',NE,SE,SW,W,X)')
define(`m4enterup',`[ u = ifelse(`$1',,kbd_u*0.3)
 line right u/4 then up u/2 then right u/6 then up u/2 left u/4+u/6 \
 then down u/2 left u/4+u/6 then right u/6 then down u/2 then right u/4
 ]')

define(`kbdsymb',`iflatex("\tt\char`$1'",`dsvg_symb(`$1')')')
define(`m4kbdarrow',`arrow thick 1.5 ht kbd_u/5 wid kbd_u/5')

divert(0)dnl

define dsvg_symb {"&#$1;"}

maxpswid = 25*kbd_u
movewid = kbd_u/11

define(`rshift',` at Here+(ifelse(`$1',,`kbd_u/8',`$1'),0) ')

iflatex(`command "{\small\sf"',
`ifsvg(svg_font(Arial,kbd_u*16/13/4,0bp__))
 textht=kbd_u/4 ')

Row2: [
 textoffset = kbd_u/8
 Loopover_(`KK',`kbdkey(text=KK); move',
   kbdsymb(126) ljust kbdsymb(96) ljust,
   Loopover_(`NN',`kbdsymb(NN) ljust "m4Lx" ljust,',33,64,35,36,37,94,38,42,40)
   kbdsymb(41) ljust "0" ljust,
   kbdsymb(95) ljust "-" ljust,
   kbdsymb(43) ljust "=" ljust,
   kbdsymb(124) ljust kbdsymb(92) ljust,
   "" )
   m4kbdarrow left kbd_u*0.5 at last [].Top
   ]
Row1: [
 kbdkey(tsmall(Esc,,N)); move right_ last [].wid+movewid*2
 Loopover_(`KK',`kbdkey(KK); move',F1,F2,F3,F4)
 move right_ last [].wid/2
 Loopover_(`KK',`kbdkey(KK); move',F5,F6,F7,F8)
 move right_ Row2.wid-Here.x-4*last [].wid-4*movewid
 Loopover_(`KK',`kbdkey(KK); move',F9,F10,F11,F12)
 ] with .sw at Row2.nw+(0,2*kbdrowsep)
Row3: [
# Uparrow: kbdkey(,,m4kbdarrow up kbd_u/2 at Top)
 Tab: kbdkey(text=tsmall(Tab) rshift ljust,wdth=kbd_u*1.6,
  [ A: m4kbdarrow left kbd_u/2; line thick A.thick up A.wid at A.end
    A: m4kbdarrow right A.len at A-(0,kbd_u/2)
    line thick A.thick up A.wid at A.end ] with .w at Top ); move
 Loopover_(`KK',`KK: kbdkey(KK); move',Q,W,E,R,T,Y,U,I,O,P)
 textoffset = kbd_u/8
 kbdkey(text=kbdsymb(123) ljust kbdsymb(91) ljust); move
 kbdkey(text=kbdsymb(125) ljust kbdsymb(93) ljust); move
 w = Row2.wid-Here.x
 R: box invis wid w-movewid ht last [].Base.ht
 ] with .nw at Row2.sw-(0,kbdrowsep)
Row4: [
 Capslock: kbdkey(text=tsmall(Caps Lock) rshift ljust,
  wdth=Row3.Tab.wid+Row3.Q.wid/3;); move
 Loopover_(`KK',`KK: kbdkey(KK); move',A,S,D,F,G,H,J,K,L)
 textoffset = kbd_u/8
 kbdkey(text=kbdsymb(58) ljust kbdsymb(59) ljust); move
 kbdkey(text=kbdsymb(34) ljust kbdsymb(39) ljust); move
 ] with .nw at Row3.sw-(0,kbdrowsep)
 Enter: enterkey(text=tsmall(Enter),,
   m4kbdarrow <- from last ""+(kbd_u/2,0) \
     right kbd_u/2 then up kbd_u/5 ) \
   with .ne at (Row2.e,Row3.n)-(movewid,0)
Row5: [
 ShiftL: kbdkey(text=tsmall(Shift) at 0.4 between Top.w and Top.e,
   wdth=kbd_u*2.4, m4enterup at 0.15 between Top.w and Top.e); move
 Loopover_(`KK',`KK: kbdkey(KK); move',Z,X,C,V,B,N,M)
 textoffset = kbd_u/8
 kbdkey(text=kbdsymb(60) ljust kbdsymb(44) ljust); move
 kbdkey(text=kbdsymb(62) ljust kbdsymb(46) ljust); move
 kbdkey(text=kbdsymb(63) ljust kbdsymb(47) ljust); move
 v = Row2.wid-Here.x-kbd_u-movewid*2
 ShiftR: kbdkey(text=tsmall(Shift) at 1/2 between Top.w and Top.e,wdth=v,
   m4enterup at 0.15 between Top.w and Top.e); move
 kbdkey(); move
 ] with .nw at Row4.sw+(0,-kbdrowsep)
Row6: [
 w = 22/18*kbd_u
 CtrlL: kbdkey(text=tsmall(Ctrl) rshift ljust,wdth=w); move
 kbdkey(,wdth=w); move
 kbdkey(text=tsmall(Alt) rshift ljust,wdth=w); move
 s = Row2.wid-(7*w+8*movewid)
 kbdkey(,wdth=s); move
 kbdkey(text=tsmall(Alt) rshift ljust,wdth=w); move
 kbdkey(,wdth=w); move
 kbdkey(,wdth=w); move
 CtrlR: kbdkey(text=tsmall(Ctrl) rshift ljust,wdth=w); move
 ] with .nw at Row5.sw+(0,-kbdrowsep)
Arrowkeys: [ iflatex(`command "{\sf\scriptsize"',`textht *=0.66')
Row1:[ textoffset = kbd_u/20
 kbdkey(text=`"Print" ljust "Screen" ljust "SysRQ" ljust'); move
 textoffset = kbd_u/12
 kbdkey(text="Scroll" ljust "Lock" ljust); move
 kbdkey(text="Pause" ljust "Break" ljust); move
 ]
Row2: [ textoffset = kbd_u/12
 kbdkey(text="Insert" ljust); move
 kbdkey(text=tsmall(Home) ljust); move
 kbdkey(text="Page" ljust "Up" ljust); move
 ] with .nw at Row1.sw-(0,2*kbdrowsep)
Row3: [ textoffset = kbd_u/12
 Delete: kbdkey(text="Delete" ljust); move
 End: kbdkey(text="End" ljust); move
 kbdkey(text="Page" ljust "Down" ljust); move
 ] with .nw at Row2.sw+(0,-kbdrowsep)
Row5: [
 move right Row3.End.w.x + movewid
 Uparrow: kbdkey(,,m4kbdarrow up kbd_u/2 at Top)
 ] with .nw at Row3.sw-(0,Row3.Delete.ht+2*kbdrowsep)
Row6: [
 kbdkey(,,m4kbdarrow left kbd_u/2 at Top); move
 kbdkey(,,m4kbdarrow down kbd_u/2 at Top); move
 kbdkey(,,m4kbdarrow right kbd_u/2 at Top); move
 ] with .nw at Row5.sw-(0,kbdrowsep)

 iflatex(`command "}%"',`textht *=(1/0.66)')
 ] with .nw at Row1.ne+(movewid,0)
Keypad: [ move down_ Arrowkeys.n.y-Arrowkeys.Row2.e.y; right_
 textoffset = kbd_u/8
Row2:[
 kbdkey(text=tsmall(Num) ljust tsmall(Lock) ljust); move
 iflatex(`command "{\large"',`textht *=1.5')
 kbdkey(text=kbdsymb(47) ljust); move
 kbdkey(text=kbdsymb(42) ljust); move
 kbdkey(text=kbdsymb(45) ljust); move
 iflatex(`command "}"')
 ]
Row3:[ textoffset = kbd_u/12
 kbdkey(text="7" ljust tsmall(Home) ljust); move
 kbdkey(text="8" ljust "" ljust,,m4kbdarrow up_ kbd_u/3 \
  at 3/4 between Top.ne and Top.sw); move
 kbdkey(text="9" ljust tsmall(PgUp) ljust); move
 ] with .nw at Row2.sw+(0,-kbdrowsep)
Row4:[ textoffset = kbd_u/12
 kbdkey(text="4" ljust "" ljust,,m4kbdarrow left kbd_u/3 \
  at 0.7 between Top.ne and Top.sw); move
 kbdkey(text="5" ljust "" ljust); move
 Six: kbdkey(text="6" ljust "" ljust,,m4kbdarrow right kbd_u/3 \
  at 0.7 between Top.ne and Top.sw); move
 ] with .nw at Row3.sw+(0,-kbdrowsep)
Row5:[ textoffset = kbd_u/12
 kbdkey(text="1" ljust tsmall(End) ljust); move
 kbdkey(text="2" ljust "" ljust,,m4kbdarrow down kbd_u/3 \
  at 0.7 between Top.ne and Top.sw); move
 kbdkey(text="3" ljust tsmall(PgDn) ljust); move
 ] with .nw at Row4.sw+(0,-kbdrowsep)
Row6:[ textoffset = kbd_u/12
 kbdkey(text="0" ljust tsmall(Ins) ljust,
   wdth=Row4.wid-Row4.Six.wid-2*movewid); move
 kbdkey(text=kbdsymb(46) ljust tsmall(Del) ljust); move
 ] with .nw at Row5.sw+(0,-kbdrowsep)
Col4: [ textoffset = kbd_u/12
 iflatex(`command "{\large"',`textht *=1.5')
 kbdkey(text="+" ljust,hght=Row3.n.y-Row4.s.y); move
 iflatex(`command "}"',`textht /=1.5')
 kbdkey(text=tsmall(Enter) ljust,hght=Row5.n.y-Row6.s.y) \
   with .nw at last [].sw - (0,kbdrowsep)
 ] with .ne at (Row2.e,Row3.n)

 ] with .nw at Arrowkeys.ne+(movewid,0)

iflatex(`command "}%"',
ifsvg(`command "</g>"'))
PE