Neo ist eine ergonomische Tastaturbelegung, welche für die deutsche Sprache optimiert ist. https://neo-layout.org
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

257 lines
5.3KB

  1. #!/usr/bin/perl -wT
  2. use strict;
  3. use warnings;
  4. use XML::Writer;
  5. use open ':encoding(utf8)';
  6. use utf8;
  7. sub start_svg;
  8. sub end_svg;
  9. sub create_defs;
  10. sub create_key;
  11. sub parse_ref;
  12. sub in2px;
  13. sub create_keys;
  14. sub round;
  15. my $dpi = 90;
  16. # a4 paper
  17. my $height = in2px(8.268);
  18. my $width = in2px(11.69);
  19. my $keywidth = in2px(0.75);
  20. my $keyheight = in2px(0.75);
  21. my $labelwidth = in2px(0.5);
  22. my $labelheight = in2px(0.55);
  23. my $posx = 0;
  24. my $posy = 0;
  25. my $row = 0;
  26. my %kp_mapping = ( # mapping for keypad, level 4
  27. 'Hom' => '⇱',
  28. 'KP↑' => '⇡',
  29. 'PgU' => '⇞',
  30. 'KP←' => '⇠',
  31. 'Beg' => '•',
  32. 'KP→' => '⇢',
  33. 'End' => '⇲',
  34. 'KP↓' => '⇣',
  35. 'PgD' => '⇟',
  36. 'Ins' => '⎀',
  37. 'Del' => '⌦',
  38. 'Ent' => '⏎',
  39. 'vec' => ' ⃗'
  40. );
  41. my $writer = new XML::Writer(ENCODING => 'utf-8',
  42. DATA_MODE => 1,
  43. DATA_INDENT => 2);
  44. start_svg;
  45. create_defs;
  46. create_keys(parse_ref);
  47. end_svg;
  48. exit;
  49. # parse reference and return multi-array
  50. sub parse_ref {
  51. my @letters;
  52. open REF, "../../A-REFERENZ-A/neo20.txt"
  53. or die 'Error opening reference: '.$!;
  54. while (<REF>) {
  55. my @layer;
  56. last if /^== Zeichenerläuterungen/;
  57. # layout blocks
  58. if(/Miniatur ===$/) {
  59. while(<REF>) {
  60. last if(/^$/); # empty line => end of current block
  61. next if($_ !~ /^│/); # skip horizontal dividers
  62. push @layer, split /│/;
  63. }
  64. push @letters, [ @layer ]; # push ref
  65. }
  66. }
  67. close REF;
  68. return @letters;
  69. }
  70. sub create_keys {
  71. my @letters = @_;
  72. for (0..$#{$letters[0]}) { # letters
  73. create_key
  74. $letters[0][$_],
  75. $letters[0][$_],
  76. $letters[1][$_],
  77. $letters[2][$_],
  78. $letters[3][$_];
  79. }
  80. for (0..$#{$letters[7]}) { # numbers
  81. create_key
  82. $letters[7][$_],
  83. $letters[7][$_],
  84. $letters[8][$_],
  85. $letters[9][$_],
  86. $letters[10][$_];
  87. }
  88. }
  89. sub in2px {
  90. return ($_[0]||0) * $dpi;
  91. }
  92. sub start_svg {
  93. $writer->xmlDecl('UTF-8');
  94. $writer->doctype('svg', '-//W3C//DTD SVG 20001102//EN',
  95. 'http://www.w3.org/TR/2000/CR-SVG-20001102/DTD/svg-20001102.dtd');
  96. $writer->startTag('svg', height => $height, width => $width,
  97. 'xmlns' => 'http://www.w3.org/2000/svg',
  98. 'xmlns:xlink' => 'http://www.w3.org/1999/xlink');
  99. }
  100. sub end_svg {
  101. $writer->endTag('svg');
  102. $writer->end();
  103. }
  104. # create the key template
  105. sub create_defs {
  106. $writer->startTag('defs');
  107. # style information
  108. $writer->dataElement('style', '
  109. text.common {
  110. font-family:Linux Biolinum O, Linux Biolinum;
  111. font-style:normal;
  112. font-variant:normal;
  113. font-stretch:normal;
  114. text-align:center;
  115. text-anchor:middle;
  116. stroke:none;
  117. }
  118. text.main {
  119. /*font-weight:bold;*/
  120. font-size:19px;
  121. fill:#eeeeee;
  122. stroke-width:4;
  123. }
  124. text.special {
  125. font-size:16px;
  126. stroke-width:3;
  127. }
  128. text.outline {
  129. stroke:#111111;
  130. stroke-linejoin:round;
  131. }
  132. rect#boundary {
  133. fill:none;
  134. stroke:#eeeeee;
  135. stroke-width:'.in2px(0.005).';
  136. }
  137. rect#border {
  138. fill:#333333;
  139. stroke:#eeeeee;
  140. stroke-width:'.in2px(0.025).';
  141. }
  142. text.level1 {
  143. }
  144. text.level2 {
  145. }
  146. text.level3 {
  147. fill:#99dd66;
  148. }
  149. text.level4 {
  150. fill:#6699dd;
  151. font-size:13px;
  152. }', type => 'text/css');
  153. # boundary of keys
  154. $writer->emptyTag('rect',
  155. id => 'boundary',
  156. width => $keywidth, height => $keyheight,
  157. rx => 5);
  158. # border for keys, actual key stickers
  159. $writer->emptyTag('rect',
  160. id => 'border',
  161. width => $labelwidth, height => $labelheight,
  162. rx => 10);
  163. $writer->endTag('defs');
  164. }
  165. # create a specific key (cloned from template)
  166. # first parameter (0) is first level, and is only used for line breaks in the graphic
  167. # param 1..4 are actual layers
  168. sub create_key {
  169. my @keys = @_;
  170. $keys[0] = '' unless defined($keys[0]);
  171. $keys[1] = '' unless defined($keys[1]);
  172. s/\s//g for @keys; # remove any space
  173. # map words to symbols for numblock
  174. foreach (keys %kp_mapping) {
  175. $keys[3] =~ s/\Q$_/\Q$kp_mapping{$_}/;
  176. $keys[4] =~ s/\Q$_/\Q$kp_mapping{$_}/;
  177. }
  178. return if length($keys[0]) != 1;
  179. $writer->startTag('g',
  180. transform => "translate($posx,$posy)",
  181. id => 'key_'.(join '', @keys));
  182. $writer->emptyTag('use', 'xlink:href' => '#boundary');
  183. $writer->startTag('g',
  184. transform => 'translate('.(($keywidth-$labelwidth)/2.5).', 2)');
  185. $writer->emptyTag('use', 'xlink:href' => '#border');
  186. # add text+outlines to sticker
  187. for(' outline', '') {
  188. $writer->dataElement('text', $keys[1],
  189. transform => 'translate(15,41)',
  190. class => "level1 common main$_")
  191. # do not show e1, if it's the same letter as e2
  192. # only use for latin letters
  193. unless(#$keys[1] =~ /[a-züöäß]/ &&
  194. $keys[1] =~ /\Q$keys[2]/i);
  195. $writer->dataElement('text', $keys[2]||'',
  196. transform => 'translate(15,19)',
  197. class => "level2 common main$_");
  198. $writer->dataElement('text', $keys[3]||'',
  199. transform => 'translate(32,18)',
  200. class => "level3 common special$_");
  201. $writer->dataElement('text', $keys[4]||'',
  202. transform => 'translate(32,42)',
  203. class => "level4 common special$_");
  204. # do not show e4 on keypad
  205. #unless($row > 4 && $keys[0] =~ /\d/i);
  206. }
  207. $writer->endTag('g');
  208. $writer->endTag('g');
  209. $posx += $keywidth;
  210. if($row < 3) {
  211. if($keys[0] =~ /[`´y]/) { # split keyboard rows, dirty way
  212. $posx = ++$row*$keywidth/2; # not really accurate, but works
  213. $posy += $keyheight;
  214. }
  215. } elsif($keys[0] =~ /[-93+j]/) { # keypad
  216. $posx = ++$row*0;
  217. $posy += $keyheight;
  218. }
  219. }
  220. sub round {
  221. return int($_[0]+.5*($_[0]<=>0));
  222. }