PDA

View Full Version : Pound sterling (currency) missing from Teensyduino British (UK) keyboard



Nantonos
11-25-2012, 11:15 PM
Tested with the LayoutTest example, Teensy beta 8, Teensy 2.0++ on Windows7. A British keyboard
http://en.wikipedia.org/wiki/Keyboard_layouts#United_Kingdom
is the system default and is correctly detected by Teensyduino in the keyboard layout menu.

The results were initially surprising to me; letters with acute accents are printed (although UK English does not use them). Grave accents are not printed. But I discovered that this is correct (http://en.wikipedia.org/wiki/British_and_American_keyboards); the acute vowels are not printed on the keyboard but are typed with Alt-GR.

I then made a modified copy of the example, to add the three untested letters which are on a UK keyboard - the pound sterling (currency) symbol , the EBCIDIC negation and the EBCIDIC broiken pipe . Of those, the pound sterling was not generated. Here is the modified code (just additions, at the end):


/* USB Keyboard Layout Test

You must select Keyboard from the "Tools > USB Type" menu

Select the the correct layout from "Tools > Keyboard Layout"

If you discover incorrect results for your country's layout,
please email Paul Stoffregen <paul@pjrc.com> with the results
of this test and an explanation of which keys are wrong. If
your layout is not available, please find the layout which
is closest, and email Paul Stoffregen.

Modified to add UK keyboard symbols, Chris Lilley.
*/

const int ledPin = 6; // Teensy 2.0 = Pin 11, Teensy++ 2.0 = Pin 6

void setup() {
Serial.begin(9600);

// Blink the LED for 10 seconds, to give time to open
// a word processor or text editor to receive the test
pinMode(ledPin, OUTPUT);
for (int i=0; i < 10; i++) {
digitalWrite(ledPin, HIGH);
delay(500);
digitalWrite(ledPin, LOW);
delay(500);
}

// Type all possible characters. Many countries do not use all
// characters. Unsupported characters will be skipped
//
Keyboard.println("Teensy USB UK Keyboard Layout Test");
delay(100);
Keyboard.println("Lowercase: abcdefghijklmnopqrstuvwxyz");
delay(100);
Keyboard.println("Uppercase: ABCDEFGHIJKLMNOPQRSTUVWXYZ");
delay(100);
Keyboard.println("Numbers: 0123456789");
delay(100);
Keyboard.println("Symbols1: !\"#$%&'()*+,-./");
delay(100);
Keyboard.println("Symbols2: :;<=>?[\\]^_`{|}~");
delay(100);
Keyboard.println("Symbols3: *");
delay(100);
Keyboard.println("Symbols4: ");
delay(100);
Keyboard.println("Grave: ");
delay(100);
Keyboard.println("Acute: ");
delay(100);
Keyboard.println("Circumflex: ");
delay(100);
Keyboard.println("Tilde: ");
delay(100);
Keyboard.println("Diaeresis: ");
delay(100);
Keyboard.println("Cedilla: ");
delay(100);
Keyboard.println("Ring Above: ");
delay(100);
Keyboard.println("AE: ");
delay(100);
Keyboard.println("Thorn: ");
delay(100);
Keyboard.println("Sharp S: ");
delay(100);
Keyboard.println("O-Stroke: ");
delay(100);
Keyboard.println("Eth: ");
delay(100);
Keyboard.println("Euro: €");
delay(100);
// UK-specific additions
Keyboard.println("Sterling: ");
delay(100);
Keyboard.println("EBCEDIC negation: ");
delay(100);
Keyboard.println("EBCEDIC broken bar: ");
}

void loop() {
// Do nothing after the test
}


And the results:


Teensy USB UK Keyboard Layout Test
Lowercase: abcdefghijklmnopqrstuvwxyz
Uppercase: ABCDEFGHIJKLMNOPQRSTUVWXYZ
Numbers: 0123456789
Symbols1: !$%&'()*+,-./
Symbols2: :;<=>?[\]^_`{|}~
Symbols3:
Symbols4:
Grave:
Acute:
Circumflex:
Tilde:
Diaeresis:
Cedilla:
Ring Above:
AE:
Thorn:
Sharp S:
O-Stroke:
Eth:
Euro: €
Sterling:
EBCEDIC negation:
EBCEDIC broken bar:

Experimentalist
11-27-2012, 06:18 AM
The sign (GBP Sterling) lives in the high ANSI characters, 0x00A3, for reference and this is the root of the problem. One thing to note is that this makes it a good character to use in your passwords due to the issues you are having in outputting it.

http://www.unicode.org/charts/PDF/U0000.pdf
http://www.unicode.org/charts/PDF/U0080.pdf

A work around for this that I use is as follows:

Keyboard.set_modifier(MODIFIERKEY_SHIFT);
Keyboard.send_now();
delay(10);
Keyboard.set_key1(KEY_3);
Keyboard.send_now();
delay(10);
Keyboard.set_modifier(0);
Keyboard.set_key1(0);
Keyboard.send_now();

Also worth noting, on Windows not sure about others, to print any high ANSI character not available from the keyboard e.g. hold the ALT key and use the numeric keypad to enter the Unicode in decimal is 0x00A9, 0169 decimal:

Keyboard.set_modifier(MODIFIERKEY_ALT);
Keyboard.send_now();
Keyboard.set_key1(KEYPAD_0);
Keyboard.send_now();
Keyboard.set_key1(0);
Keyboard.send_now();
Keyboard.set_key1(KEYPAD_1);
Keyboard.send_now();
Keyboard.set_key1(0);
Keyboard.send_now();
Keyboard.set_key1(KEYPAD_6);
Keyboard.send_now();
Keyboard.set_key1(0);
Keyboard.send_now();
Keyboard.set_key1(KEYPAD_9);
Keyboard.send_now();
Keyboard.set_key1(0);
Keyboard.send_now();
Keyboard.set_modifier(0);
Keyboard.set_key1(0);
Keyboard.send_now();

Obviously not much effort to write a method to send any Unicode character.

Hope it helps

Nantonos
11-27-2012, 05:59 PM
The sign (GBP Sterling) lives in the high ANSI characters, 0x00A3, for reference and this is the root of the problem.
I doubt it. Any modern system is working in Unicode (unfortunately modern system excludes Arduino and the like, which are resolutely stuck in the mid-1980s with 8-bit code pages, but I mean any version of Windows from NT/2000/XP on up, any MacOS X, any Linux of FreeBSD from the last decade).

Your comment would apply to something like Win95, which mostly used 8-bit 'code pages'. If 'high ansi' (8 bit characters with the high bit set) were the issue then € would also be a problem along with .



One thing to note is that this makes it a good character to use in your passwords due to the issues you are having in outputting it.
I have no trouble outputting it. It is printed right on my keyboard (above the '3' is '', so shift-3) and I typed it in right there.

Thanks for your comments, but I don't think they are the root of the problem. Its just a small flaw in the Teensy keyboard emulation, which was probably not noticed because the example test program doesn't expose it.

PaulStoffregen
11-27-2012, 07:28 PM
Are you using Teensy 2.0 or 3.0 ?

PaulStoffregen
11-27-2012, 07:32 PM
Also, does this image match your keyboard's actual layout? I don't have a UK keyboard, so I depend on these images for making the layout mapping.

http://en.wikipedia.org/wiki/File:KB_United_Kingdom.svg

Please confirm and I'll look at the code....

Experimentalist
11-27-2012, 08:23 PM
Paul, yep that is a UK keyboard.

The UK mods in Keylayouts.h are wrong for the sign:

#define ISO_8859_1_A3 KEY_3 + ALTGR_MASK // 163 Pound Sign

Should be a SHIFT_MASK

Nantonos the solution above works then since Shift-3 was exactly what the code I posted does, I was just trying to help. We had a pen tester in recently and all the passwords with a sign took a little longer to crack than those of similar complexity without. Regarding the other characters € , those are the only high chars you can enter directly using modifiers physically from the UK keyboard emulation and therefore are the only ones Paul has mapped in the UK keyboard layout. I simply provide a solution for people who want to send the others.

Take a look in "\arduino-1.0.x\hardware\teensy\cores\teensy\Keylayouts.h" to understand further.

Nantonos
11-27-2012, 09:03 PM
Tested with the LayoutTest example, Teensy beta 8, Teensy 2.0++ on Windows7.


Are you using Teensy 2.0 or 3.0 ?

Test was with Teensy ++ 2.0. I have Teensy 2.0 and 3.0 available also.

Nantonos
11-27-2012, 09:05 PM
Also, does this image match your keyboard's actual layout? I don't have a UK keyboard, so I depend on these images for making the layout mapping.

http://en.wikipedia.org/wiki/File:KB_United_Kingdom.svg

Please confirm and I'll look at the code....

Yes, exactly. Black letters in that diagram are printed on the keyboard; blue letters are not, but can be generated with alt-gr.

Pound stering is printed on the '3' key, where '#' is on US layout.

Nantonos
11-27-2012, 09:08 PM
The UK mods in Keylayouts.h are wrong for the sign:

#define ISO_8859_1_A3 KEY_3 + ALTGR_MASK // 163 Pound Sign

Should be a SHIFT_MASK

Good catch, yes that looks like it.


Nantonos the solution above works then since Shift-3 was exactly what the code I posted does, I was just trying to help.
Thanks, appreciated. I was more interested in reporting a bug and having it fixed, rather than using a workaround.

Nantonos
11-27-2012, 09:09 PM
OK, I will go test French keyboards now, I think we have one in the house unused somewhere.

Paul, would it help if I retest on Teensy 3.0 and beta 8? I assume the same bug will be copied over there.

PaulStoffregen
11-27-2012, 10:47 PM
I've put the fix in. It'll be in the next release.

Testing on 3.0 would be awesome. The keylayouts.h file is identical, so any layout definition bugs should be the same on 2.0 and 3.0. But 3.0's code international keyboard hasn't been tested much, because it's so new. I made that character test example because I only have US keyboards and I depend on people testing on actual machines configured for these other keyboards.

Experimentalist
11-27-2012, 11:14 PM
Thanks, appreciated . . .

No problem, just nice to get some thanks for your time, ta

PaulStoffregen
11-27-2012, 11:55 PM
Here an updated core library with the fixed keylayouts.h.

http://www.pjrc.com/teensy/beta/teensy3_27nov12.zip

Nantonos
11-28-2012, 03:37 AM
French AZERTY keyboards have some bugs too. I compared the layout on Wikipedia (http://en.wikipedia.org/wiki/File:KB_France.svg) to an actual French keyboard, just to be sure it was correct.

The LayoutTest example gave incorrect results

I then modified the LayoutTest to

- check for additional characters
- check that French quotation marks aren't produced by a standard French keyboard (I kid you not (http://en.wikipedia.org/wiki/AZERTY#Missing_elements))
- briefly check that the 'dead keys' used to create accents work.

Here is the modified code

/* USB French Keyboard Layout Test

You must select Keyboard from the "Tools > USB Type" menu

Select the the correct layout from "Tools > Keyboard Layout"

If you discover incorrect results for your country's layout,
please email Paul Stoffregen <paul@pjrc.com> with the results
of this test and an explanation of which keys are wrong. If
your layout is not available, please find the layout which
is closest, and email Paul Stoffregen.

Modified by Chris Lilley to fully test French AZERTY keyboard
*/

const int ledPin = 6; // Teensy 2.0 = Pin 11, Teensy++ 2.0 = Pin 6

void setup() {
Serial.begin(9600);

// Blink the LED for 10 seconds, to give time to open
// a word processor or text editor to receive the test
pinMode(ledPin, OUTPUT);
for (int i=0; i < 10; i++) {
digitalWrite(ledPin, HIGH);
delay(500);
digitalWrite(ledPin, LOW);
delay(500);
}

// Type all possible characters. Many countries do not use all
// characters. Unsupported characters will be skipped
//
Keyboard.println("Teensy USB French AZERTY Keyboard Layout Test");
delay(100);
Keyboard.println("Lowercase: abcdefghijklmnopqrstuvwxyz");
delay(100);
Keyboard.println("Uppercase: ABCDEFGHIJKLMNOPQRSTUVWXYZ");
delay(100);
Keyboard.println("Numbers: 0123456789");
delay(100);
Keyboard.println("Symbols1: !\"#$%&'()*+,-./");
delay(100);
Keyboard.println("Symbols2: :;<=>?[\\]^_`{|}~");
delay(100);
Keyboard.println("Symbols3: *");
delay(100);
Keyboard.println("Symbols4: ");
delay(100);
Keyboard.println("Grave: ");
delay(100);
Keyboard.println("Acute: ");
delay(100);
Keyboard.println("Circumflex: ");
delay(100);
Keyboard.println("Tilde: ");
delay(100);
Keyboard.println("Diaeresis: ");
delay(100);
Keyboard.println("Cedilla: ");
delay(100);
Keyboard.println("Ring Above: ");
delay(100);
Keyboard.println("AE: ");
delay(100);
Keyboard.println("Thorn: ");
delay(100);
Keyboard.println("Sharp S: ");
delay(100);
Keyboard.println("O-Stroke: ");
delay(100);
Keyboard.println("Eth: ");
delay(100);
Keyboard.println("Euro: €");
// additions for Azerty French layout, see
// http://en.wikipedia.org/wiki/File:KB_France.svg
// http://en.wikipedia.org/wiki/AZERTY
delay(100);
Keyboard.println("French additional characters");
delay(100);
Keyboard.println("Superscript 2: ");
delay(100);
Keyboard.println("Broken pipe: ");
delay(100);
Keyboard.println("Pound sterling: ");
delay(100);
Keyboard.println("Currency sign: ");
delay(100);
Keyboard.println("French quotation marks NOT on French AZERTY keyboard!");
delay(100);
//These won't be output
Keyboard.println("Guillemets: ");
delay(100);
Keyboard.print("Combining diaresis: ");
// Test 'dead key' combining diaresis plus vowels
delay(100);
Keyboard.set_modifier(MODIFIERKEY_SHIFT);
Keyboard.set_key1(KEY_LEFT_BRACE); // This is actually the diaresis and circumflex key
Keyboard.set_key2(0);
Keyboard.set_key3(0);
Keyboard.set_key4(0);
Keyboard.set_key5(0);
Keyboard.set_key6(0);
Keyboard.send_now();
Keyboard.set_modifier(0);
Keyboard.set_key1(KEY_E);
Keyboard.send_now();
Keyboard.set_key1(0);
Keyboard.send_now();
}

void loop() {
// Do nothing after the test
}

and here are the results which are not as expected:


Teensy USB French AZERTY Keyboard Layout Test
Lowercase: abcdefghijklmnopqrstuvwxyz
Uppercase: ABCDEFGHIJKLMNOPQRSTUVWXYZ
Numbers: 0123456789
Symbols1: !"#$%&'()*+,-./
Symbols2: :;<=>?[\]^_`{|}~
Symbols3:
Symbols4:
Grave: `Q;
Acute:
Circumflex: ^Q^q
Tilde: ~Q~q
Diaeresis: Qq
Cedilla:
Ring Above:
AE:
Thorn:
Sharp S:
O-Stroke:
Eth:
Euro: €
French additional characters
Superscript 2:
Broken pipe:
Pound sterling:
Currency sign:
French quotation marks NOT on French AZERTY keyboard!
Guillemets:
Combining diaresis:

Nantonos
11-28-2012, 03:50 AM
So the incorrect things are:

- while A and Q are correct (they are swapped on the French keyboard layout, compared to US) the accented forms of the letter A are mostly replaced by accented letter Q instead! (except is correct) Edit: corrected by code posted below
- broken pipe symbol is missing (but in practice French keyboards seem to output | instead) Edit: known Windows bug, apparently.
- Edit: was missing Edit: corrected by code posted below

Nantonos
11-28-2012, 04:41 AM
Corrected French AZERTY section


#ifdef LAYOUT_FRENCH

#define SHIFT_MASK 0x0040
#define ALTGR_MASK 0x0080
#define DEADKEYS_MASK 0x0700
#define CIRCUMFLEX_BITS 0x0100
#define GRAVE_ACCENT_BITS 0x0200
#define DIAERESIS_BITS 0x0300
#define TILDE_BITS 0x0400
#define KEYCODE_TYPE uint16_t
#define DEADKEY_CIRCUMFLEX KEY_LEFT_BRACE
#define DEADKEY_GRAVE_ACCENT KEY_7 + ALTGR_MASK
#define DEADKEY_DIAERESIS KEY_LEFT_BRACE + SHIFT_MASK
#define DEADKEY_TILDE KEY_2 + ALTGR_MASK
#define KEY_NON_US_100 63

#define ASCII_20 KEY_SPACE // 32
#define ASCII_21 KEY_SLASH // 33 !
#define ASCII_22 KEY_3 // 34 "
#define ASCII_23 KEY_3 + ALTGR_MASK // 35 #
#define ASCII_24 KEY_RIGHT_BRACE // 36 $
#define ASCII_25 KEY_QUOTE + SHIFT_MASK // 37 %
#define ASCII_26 KEY_1 // 38 &
#define ASCII_27 KEY_4 // 39 '
#define ASCII_28 KEY_5 // 40 (
#define ASCII_29 KEY_MINUS // 41 )
#define ASCII_2A KEY_BACKSLASH // 42 *
#define ASCII_2B KEY_EQUAL + SHIFT_MASK // 43 +
#define ASCII_2C KEY_M // 44 ,
#define ASCII_2D KEY_6 // 45 -
#define ASCII_2E KEY_COMMA + SHIFT_MASK // 46 .
#define ASCII_2F KEY_PERIOD + SHIFT_MASK // 47 /
#define ASCII_30 KEY_0 + SHIFT_MASK // 48 0
#define ASCII_31 KEY_1 + SHIFT_MASK // 49 1
#define ASCII_32 KEY_2 + SHIFT_MASK // 50 2
#define ASCII_33 KEY_3 + SHIFT_MASK // 51 3
#define ASCII_34 KEY_4 + SHIFT_MASK // 52 4
#define ASCII_35 KEY_5 + SHIFT_MASK // 53 5
#define ASCII_36 KEY_6 + SHIFT_MASK // 54 6
#define ASCII_37 KEY_7 + SHIFT_MASK // 55 7
#define ASCII_38 KEY_8 + SHIFT_MASK // 55 8
#define ASCII_39 KEY_9 + SHIFT_MASK // 57 9
#define ASCII_3A KEY_PERIOD // 58 :
#define ASCII_3B KEY_COMMA // 59 ;
#define ASCII_3C KEY_NON_US_100 // 60 <
#define ASCII_3D KEY_EQUAL // 61 =
#define ASCII_3E KEY_NON_US_100 + SHIFT_MASK // 62 >
#define ASCII_3F KEY_M + SHIFT_MASK // 63 ?
#define ASCII_40 KEY_0 + ALTGR_MASK // 64 @
#define ASCII_41 KEY_Q + SHIFT_MASK // 65 A
#define ASCII_42 KEY_B + SHIFT_MASK // 66 B
#define ASCII_43 KEY_C + SHIFT_MASK // 67 C
#define ASCII_44 KEY_D + SHIFT_MASK // 68 D
#define ASCII_45 KEY_E + SHIFT_MASK // 69 E
#define ASCII_46 KEY_F + SHIFT_MASK // 70 F
#define ASCII_47 KEY_G + SHIFT_MASK // 71 G
#define ASCII_48 KEY_H + SHIFT_MASK // 72 H
#define ASCII_49 KEY_I + SHIFT_MASK // 73 I
#define ASCII_4A KEY_J + SHIFT_MASK // 74 J
#define ASCII_4B KEY_K + SHIFT_MASK // 75 K
#define ASCII_4C KEY_L + SHIFT_MASK // 76 L
#define ASCII_4D KEY_SEMICOLON + SHIFT_MASK // 77 M
#define ASCII_4E KEY_N + SHIFT_MASK // 78 N
#define ASCII_4F KEY_O + SHIFT_MASK // 79 O
#define ASCII_50 KEY_P + SHIFT_MASK // 80 P
#define ASCII_51 KEY_A + SHIFT_MASK // 81 Q
#define ASCII_52 KEY_R + SHIFT_MASK // 82 R
#define ASCII_53 KEY_S + SHIFT_MASK // 83 S
#define ASCII_54 KEY_T + SHIFT_MASK // 84 T
#define ASCII_55 KEY_U + SHIFT_MASK // 85 U
#define ASCII_56 KEY_V + SHIFT_MASK // 86 V
#define ASCII_57 KEY_Z + SHIFT_MASK // 87 W
#define ASCII_58 KEY_X + SHIFT_MASK // 88 X
#define ASCII_59 KEY_Y + SHIFT_MASK // 89 Y
#define ASCII_5A KEY_W + SHIFT_MASK // 90 Z
#define ASCII_5B KEY_5 + ALTGR_MASK // 91 [
#define ASCII_5C KEY_8 + ALTGR_MASK // 92
#define ASCII_5D KEY_MINUS + ALTGR_MASK // 93 ]
#define ASCII_5E KEY_9 + ALTGR_MASK // 94 ^
#define ASCII_5F KEY_8 // 95 _
#define ASCII_60 GRAVE_ACCENT_BITS + KEY_SPACE // 96 `
#define ASCII_61 KEY_Q // 97 a
#define ASCII_62 KEY_B // 98 b
#define ASCII_63 KEY_C // 99 c
#define ASCII_64 KEY_D // 100 d
#define ASCII_65 KEY_E // 101 e
#define ASCII_66 KEY_F // 102 f
#define ASCII_67 KEY_G // 103 g
#define ASCII_68 KEY_H // 104 h
#define ASCII_69 KEY_I // 105 i
#define ASCII_6A KEY_J // 106 j
#define ASCII_6B KEY_K // 107 k
#define ASCII_6C KEY_L // 108 l
#define ASCII_6D KEY_SEMICOLON // 109 m
#define ASCII_6E KEY_N // 110 n
#define ASCII_6F KEY_O // 111 o
#define ASCII_70 KEY_P // 112 p
#define ASCII_71 KEY_A // 113 q
#define ASCII_72 KEY_R // 114 r
#define ASCII_73 KEY_S // 115 s
#define ASCII_74 KEY_T // 116 t
#define ASCII_75 KEY_U // 117 u
#define ASCII_76 KEY_V // 118 v
#define ASCII_77 KEY_Z // 119 w
#define ASCII_78 KEY_X // 120 x
#define ASCII_79 KEY_Y // 121 y
#define ASCII_7A KEY_W // 122 z
#define ASCII_7B KEY_4 + ALTGR_MASK // 123 {
#define ASCII_7C KEY_6 + ALTGR_MASK // 124 |
#define ASCII_7D KEY_EQUAL + ALTGR_MASK // 125 }
#define ASCII_7E TILDE_BITS + KEY_SPACE // 126 ~
#define ASCII_7F KEY_BACKSPACE // 127


second half in following post (forum limit)

Nantonos
11-28-2012, 04:42 AM
#define ISO_8859_1_A0 KEY_SPACE // 160 Nonbreakng Space
#define ISO_8859_1_A1 0 // 161 Inverted Exclamation
#define ISO_8859_1_A2 0 // 162 Cent SIGN
#define ISO_8859_1_A3 KEY_RIGHT_BRACE + SHIFT_MASK // 163 Pound Sign
#define ISO_8859_1_A4 KEY_RIGHT_BRACE + ALTGR_MASK // 164 Currency or Euro Sign
#define ISO_8859_1_A5 0 // 165 YEN SIGN
#define ISO_8859_1_A6 0 // 166 BROKEN BAR
#define ISO_8859_1_A7 KEY_SLASH + SHIFT_MASK // 167 SECTION SIGN
#define ISO_8859_1_A8 DIAERESIS_BITS + KEY_SPACE // 168 DIAERESIS
#define ISO_8859_1_A9 0 // 169 COPYRIGHT SIGN
#define ISO_8859_1_AA 0 // 170 FEMININE ORDINAL
#define ISO_8859_1_AB 0 // 171 LEFT DOUBLE ANGLE QUOTE
#define ISO_8859_1_AC 0 // 172 NOT SIGN
#define ISO_8859_1_AD 0 // 173 SOFT HYPHEN
#define ISO_8859_1_AE 0 // 174 REGISTERED SIGN
#define ISO_8859_1_AF 0 // 175 MACRON
#define ISO_8859_1_B0 KEY_MINUS + SHIFT_MASK // 176 DEGREE SIGN
#define ISO_8859_1_B1 0 // 177 PLUS-MINUS SIGN
#define ISO_8859_1_B2 KEY_TILDE // 178 SUPERSCRIPT TWO
#define ISO_8859_1_B3 0 // 179 SUPERSCRIPT THREE
#define ISO_8859_1_B4 0 // 180 ACUTE ACCENT
#define ISO_8859_1_B5 KEY_BACKSLASH + SHIFT_MASK // 181 MICRO SIGN
#define ISO_8859_1_B6 0 // 182 PILCROW SIGN
#define ISO_8859_1_B7 0 // 183 MIDDLE DOT
#define ISO_8859_1_B8 0 // 184 CEDILLA
#define ISO_8859_1_B9 0 // 185 SUPERSCRIPT ONE
#define ISO_8859_1_BA 0 // 186 MASCULINE ORDINAL
#define ISO_8859_1_BB 0 // 187 RIGHT DOUBLE ANGLE QUOTE
#define ISO_8859_1_BC 0 // 188 FRACTION ONE QUARTER
#define ISO_8859_1_BD 0 // 189 FRACTION ONE HALF
#define ISO_8859_1_BE 0 // 190 FRACTION THREE QUARTERS
#define ISO_8859_1_BF 0 // 191 INVERTED QUESTION MARK
#define ISO_8859_1_C0 GRAVE_ACCENT_BITS + KEY_Q + SHIFT_MASK // 192 A GRAVE
#define ISO_8859_1_C1 0 // 193 A ACUTE
#define ISO_8859_1_C2 CIRCUMFLEX_BITS + KEY_Q + SHIFT_MASK // 194 A CIRCUMFLEX
#define ISO_8859_1_C3 TILDE_BITS + KEY_Q + SHIFT_MASK // 195 A TILDE
#define ISO_8859_1_C4 DIAERESIS_BITS + KEY_Q + SHIFT_MASK // 196 A DIAERESIS
#define ISO_8859_1_C5 0 // 197 A RING ABOVE
#define ISO_8859_1_C6 0 // 198 AE
#define ISO_8859_1_C7 0 // 199 C CEDILLA
#define ISO_8859_1_C8 GRAVE_ACCENT_BITS + KEY_E + SHIFT_MASK // 200 E GRAVE
#define ISO_8859_1_C9 0 // 201 E ACUTE
#define ISO_8859_1_CA CIRCUMFLEX_BITS + KEY_E + SHIFT_MASK // 202 E CIRCUMFLEX
#define ISO_8859_1_CB DIAERESIS_BITS + KEY_E + SHIFT_MASK // 203 E DIAERESIS
#define ISO_8859_1_CC GRAVE_ACCENT_BITS + KEY_I + SHIFT_MASK // 204 I GRAVE
#define ISO_8859_1_CD 0 // 205 I ACUTE
#define ISO_8859_1_CE CIRCUMFLEX_BITS + KEY_I + SHIFT_MASK // 206 I CIRCUMFLEX
#define ISO_8859_1_CF DIAERESIS_BITS + KEY_I + SHIFT_MASK // 207 I DIAERESIS
#define ISO_8859_1_D0 0 // 208 ETH
#define ISO_8859_1_D1 TILDE_BITS + KEY_N + SHIFT_MASK // 209 N TILDE
#define ISO_8859_1_D2 GRAVE_ACCENT_BITS + KEY_O + SHIFT_MASK // 210 O GRAVE
#define ISO_8859_1_D3 0 // 211 O ACUTE
#define ISO_8859_1_D4 CIRCUMFLEX_BITS + KEY_O + SHIFT_MASK // 212 O CIRCUMFLEX
#define ISO_8859_1_D5 TILDE_BITS + KEY_O + SHIFT_MASK // 213 O TILDE
#define ISO_8859_1_D6 DIAERESIS_BITS + KEY_O + SHIFT_MASK // 214 O DIAERESIS
#define ISO_8859_1_D7 0 // 215 MULTIPLICATION
#define ISO_8859_1_D8 0 // 216 O STROKE
#define ISO_8859_1_D9 GRAVE_ACCENT_BITS + KEY_U + SHIFT_MASK // 217 U GRAVE
#define ISO_8859_1_DA 0 // 218 U ACUTE
#define ISO_8859_1_DB CIRCUMFLEX_BITS + KEY_U + SHIFT_MASK // 219 U CIRCUMFLEX
#define ISO_8859_1_DC DIAERESIS_BITS + KEY_U // 220 U DIAERESIS
#define ISO_8859_1_DD 0 // 221 Y ACUTE
#define ISO_8859_1_DE 0 // 222 THORN
#define ISO_8859_1_DF 0 // 223 SHARP S
#define ISO_8859_1_E0 KEY_0 // 224 a GRAVE
#define ISO_8859_1_E1 0 // 225 a ACUTE
#define ISO_8859_1_E2 CIRCUMFLEX_BITS + KEY_Q // 226 a CIRCUMFLEX
#define ISO_8859_1_E3 TILDE_BITS + KEY_Q // 227 a TILDE
#define ISO_8859_1_E4 DIAERESIS_BITS + KEY_Q // 228 a DIAERESIS
#define ISO_8859_1_E5 0 // 229 a RING ABOVE
#define ISO_8859_1_E6 0 // 230 ae
#define ISO_8859_1_E7 KEY_9 // 231 c CEDILLA
#define ISO_8859_1_E8 KEY_7 // 232 e GRAVE
#define ISO_8859_1_E9 KEY_2 // 233 e ACUTE
#define ISO_8859_1_EA CIRCUMFLEX_BITS + KEY_E // 234 e CIRCUMFLEX
#define ISO_8859_1_EB DIAERESIS_BITS + KEY_E // 235 e DIAERESIS
#define ISO_8859_1_EC GRAVE_ACCENT_BITS + KEY_I // 236 i GRAVE
#define ISO_8859_1_ED 0 // 237 i ACUTE
#define ISO_8859_1_EE CIRCUMFLEX_BITS + KEY_I // 238 i CIRCUMFLEX
#define ISO_8859_1_EF DIAERESIS_BITS + KEY_I // 239 i DIAERESIS
#define ISO_8859_1_F0 0 // 240 ETH
#define ISO_8859_1_F1 TILDE_BITS + KEY_N // 241 n TILDE
#define ISO_8859_1_F2 GRAVE_ACCENT_BITS + KEY_O // 242 o GRAVE
#define ISO_8859_1_F3 0 // 243 o ACUTE
#define ISO_8859_1_F4 CIRCUMFLEX_BITS + KEY_O // 244 o CIRCUMFLEX
#define ISO_8859_1_F5 TILDE_BITS + KEY_O // 245 o TILDE
#define ISO_8859_1_F6 DIAERESIS_BITS + KEY_O // 246 o DIAERESIS
#define ISO_8859_1_F7 0 // 247 DIVISION
#define ISO_8859_1_F8 0 // 248 o STROKE
#define ISO_8859_1_F9 KEY_SEMICOLON // 249 u GRAVE
#define ISO_8859_1_FA 0 // 250 u ACUTE
#define ISO_8859_1_FB CIRCUMFLEX_BITS + KEY_U // 251 u CIRCUMFLEX
#define ISO_8859_1_FC DIAERESIS_BITS + KEY_U // 252 u DIAERESIS
#define ISO_8859_1_FD 0 // 253 y ACUTE
#define ISO_8859_1_FE 0 // 254 THORN
#define ISO_8859_1_FF DIAERESIS_BITS + KEY_Y // 255 y DIAERESIS
#define UNICODE_20AC KEY_E + ALTGR_MASK // Euro Sign

#endif // LAYOUT_FRENCH

Nantonos
11-28-2012, 04:44 AM
Correct output from test program


Teensy USB French AZERTY Keyboard Layout Test
Lowercase: abcdefghijklmnopqrstuvwxyz
Uppercase: ABCDEFGHIJKLMNOPQRSTUVWXYZ
Numbers: 0123456789
Symbols1: !"#$%&'()*+,-./
Symbols2: :;<=>?[\]^_`{|}~
Symbols3:
Symbols4:
Grave: m
Acute:
Circumflex:
Tilde:
Diaeresis:
Cedilla:
Ring Above:
AE:
Thorn:
Sharp S:
O-Stroke:
Eth:
Euro:
French additional characters
Superscript 2:
Broken pipe:
Pound sterling:
Currency sign:
French quotation marks NOT on French AZERTY keyboard!
Guillemets:
Combining diaresis:

Experimentalist
11-28-2012, 06:07 AM
Also worth noting, on Windows not sure about others, to print any high ANSI character not available from the keyboard e.g. hold the ALT key and use the numeric keypad to enter the Unicode in decimal is 0x00A9, 0169 decimal:

Keyboard.set_modifier(MODIFIERKEY_ALT);
. . .


You now have me wondering is there an easier/better way of outputting the characters in this http://www.unicode.org/charts/PDF/U0080.pdf code table ???

Nantonos
11-28-2012, 09:06 AM
You now have me wondering is there an easier/better way of outputting the characters in this http://www.unicode.org/charts/PDF/U0080.pdf code table ???

The part of keylayouts.h that converts keycodes to characters seems to output to ASCII, ISO-8859-1, and Unicode. It is really not clear to me why it does that, since ASCII corresponds exactly to the codes 32..127 of Unicode and 8859-1 corresponds exactly to codes 32...127 and 160..255 of Unicode. In other words, while there are many and varied character encodings worldwide, the only two used in that header file are code for code exactly the same as Unicode, for the characters they cover.

Anyway it would seem both useful and easy to define some sort of 'virtual Unicode' keyboard which would be impossible to construct in practice but is straightforward to code; it can output any Unicode character. Perhaps the USB HID keyboard prevents that.

But Keyboard.println("any Unicode string you want"); has a certain attraction.

PaulStoffregen
12-01-2012, 08:39 PM
Thanks for testing the French layout. I'm incorporating your fixes right now!



The part of keylayouts.h that converts keycodes to characters seems to output to ASCII, ISO-8859-1, and Unicode. It is really not clear to me why it does that, since ASCII corresponds exactly to the codes 32..127 of Unicode and 8859-1 corresponds exactly to codes 32...127 and 160..255 of Unicode.

USB keyboards do not transmit in ascii or unicode. They use the codes defined in the HID usage tables. Here's the official document:

http://www.usb.org/developers/devclass_docs/Hut1_12v2.pdf

The codes for keyboard keys are in chapter 10, starting on page 53.

The Arduino IDE encodes all string constants as UTF8. So the keyboard support for Serial.print(string) has to decode UTF8 to Unicode. Then it uses those lookup tables to translate Unicode into specific HID usage table codes. The tables are populated with a 6 bit field for the HID usage code, and other bits indicate which modifier keys to use, and/or which dead key sequence to execute before sending the main hid code. I tried to make as much as possible compile-time configured, so it's efficient, but it still ends up as quite a bit of code to do the various translations and execute the dead key sequences.

It would have been awesome if the usb keyboards sent unicode. It also would have been nice if usb keyboard were required to provide the actual layout in their descriptor. Then the PC could know which keyboard layout is used and automatically translate the hid usage codes into they unicode they represent. That would have made it possible to simple plug in any keyboard with any layout and have it automatically work.

Unfortunately, that's not the way things were standardized. Apparently the keyboard manufacturers were involved in the early talks (early 90s) to create the usb standards. It was known that usb could never become adopted without support from keyboards. I've been told the keyboard manufacturers insisted on these codes, because they wanted to manufacture exactly the same electronics and simple populate international keyboards with different plastic keys (or different pad printing on the same plastic keys). They were not willing to even change 1 bit of actual electronic data between different layouts.

So the very unfortunate long-term result is all usb keybords send these very arbitrary codes that indicate which physical location was pressed, but encode absolutely nothing about the meaning of that location... not even a single fixed byte in the usb descriptors indicating the keyboard's layout which could be used. Every user then is responsible for configuring their PC for their keyboard's actual layout (Microsoft and Apple sell localized copies which default to that nation's most common layout), because it can't be automatically detected. And when emulating a keyboard, all this extra complexity is needed to support the many different international layouts, because the PC is configured for a specific layout and you can't tell anything else.

On the plus side, usb keyboards are very cheap!

hoosieree
03-31-2016, 05:47 PM
Thanks for testing the French layout. I'm incorporating your fixes right now!

So the very unfortunate long-term result is all usb keybords send these very arbitrary codes that indicate which physical location was pressed, but encode absolutely nothing about the meaning of that location... not even a single fixed byte in the usb descriptors indicating the keyboard's layout which could be used. Every user then is responsible for configuring their PC for their keyboard's actual layout (Microsoft and Apple sell localized copies which default to that nation's most common layout), because it can't be automatically detected. And when emulating a keyboard, all this extra complexity is needed to support the many different international layouts, because the PC is configured for a specific layout and you can't tell anything else.

On the plus side, usb keyboards are very cheap!

Thanks for that bit of history. Wouldn't be surprised if it's a similar story behind the other USB peripherals.