Author Topic: BUGS: display of special characters and keyboard mapping  (Read 2891 times)

0 Members and 1 Guest are viewing this topic.

Offline moises1953

  • Newbie
  • Posts: 55
    • View Profile
BUGS: display of special characters and keyboard mapping
« on: June 05, 2020, 05:25:26 am »
Display of special characters and keyboard mapping are a pending subject in QB64. It applies to both the IDE and the INKEY $, KEYHIT, INPUT ... functions.
Regardless of the IDE language that is selected, the screen output uses the CP437. So if you configure Windows CP1250, you can see what you write, but when you run the program it will show the character corresponding to the extended ASCII code represented by CP437. Therefore, the page chosen for the IDE is not taken into account to generate the text outputs of the compiled program, therefore it is useless to choose another one than CP437. And so it should be to preserve compatibility.
Regarding the presentation, let's take an extended character from page CP437, for example º has the code 167, however when typing º on a Spanish keyboard you receive, both in the IDE and in the executables, with the code 186 that represents as ║, and therefore should be mapped to  167 to show º.
As for the keyboard, some [AltGr] keys, like {} [] work well in the IDE, but not in the INPUT, and in neither case can you type accented letters, which requires a KEYHIT process.
I am attaching an example for a Spanish keyboard.
Code: QB64 $NOPREFIX: [Select]
  1. DEFLNG H-P
  2. 'CONST Phor = 1366, Pver = 768 ' WXGA
  3. CONST Phor = 1600, Pver = 900 ' HD+
  4.  
  5. TITLE "Inkeyhit" 'Version 1.0
  6. hscr = NEWIMAGE(Phor, Pver, 256)
  7. SCREEN hscr
  8. 'Permite comprobar el mapeado del teclado.
  9.  
  10. PuedeFull = (Pver = DESKTOPHEIGHT)
  11. 'Para poner a pantalla completa basta pulsar <Alt><Intro> un par de veces.
  12.  
  13. fontpath$ = "Lucon.ttf": fontsize% = 24 'Windows lucida console 24x14
  14. style$ = "MONOSPACE"
  15. hfont = LOADFONT(fontpath$, fontsize%, style$)
  16. IF hfont THEN FONT hfont
  17.  
  18. LOCATE , , 1 'mostrar cursor solo funciona en modo texto
  19. PRINT "Inkeyhit & display (128-175): €‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯"
  20. PRINT "                   (176-223): °±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖ×ØÙÚÛÜÝÞß"
  21. PRINT "CP437 extended     (224-254): àáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþ"
  22. PRINT "Puede comprobar si el mapeado del teclado es correcto"
  23. PRINT CHR$(254);
  24. LOCATE , 1
  25.   in$ = Inkeyhit$ 'emulates quickbasic INKEY$
  26.   IF LEN(in$) THEN
  27.     PRINT in$;
  28.     pcol = POS(0)
  29.     PRINT CHR$(254);
  30.     LOCATE , pcol
  31.   END IF
  32. LOOP UNTIL in$ = CHR$(27)
  33.  
  34. FUNCTION Inkeyhit$ STATIC 'Emulates INKEY$ for spanish keyboard
  35.   DIM i, iaccent AS INTEGER, car AS UNSIGNED BYTE, doblecar AS STRING * 2
  36.   i = KEYHIT
  37.   IF i THEN
  38.     car = 0
  39.     keyalt = KEYDOWN(100307) OR KEYDOWN(100308)
  40.     keyctrl = KEYDOWN(100305) OR KEYDOWN(100306)
  41.     keyshift = KEYDOWN(100303) OR KEYDOWN(100304)
  42.     IF iaccent THEN
  43.       SELECT CASE iaccent
  44.         CASE 1
  45.           SELECT CASE i
  46.             CASE 97: car = 160 '
  47.             CASE 101: car = 130 '‚
  48.             CASE 105: car = 161
  49.             CASE 111: car = 162
  50.             CASE 117: car = 163
  51.             CASE 69: car = 144
  52.           END SELECT
  53.         CASE 2
  54.           SELECT CASE i
  55.             CASE 97: car = 133 '…
  56.             CASE 101: car = 138
  57.             CASE 105: car = 141
  58.             CASE 111: car = 149 '•
  59.             CASE 117: car = 151 '—
  60.           END SELECT
  61.         CASE 3
  62.           SELECT CASE i
  63.             CASE 97: car = 132 '„
  64.             CASE 101: car = 137 '‰
  65.             CASE 105: car = 139 '‹
  66.             CASE 111: car = 148 '”
  67.             CASE 117: car = 129
  68.             CASE 65: car = 142
  69.             CASE 79: car = 153 '™
  70.             CASE 85: car = 154
  71.           END SELECT
  72.         CASE 4
  73.           SELECT CASE i
  74.             CASE 97: car = 131
  75.             CASE 101: car = 136
  76.             CASE 105: car = 140
  77.             CASE 111: car = 147 '“
  78.             CASE 117: car = 150 '–
  79.           END SELECT
  80.       END SELECT
  81.     END IF
  82.  
  83.     IF car = 0 THEN
  84.       SELECT CASE i
  85.         CASE 48 TO 57 'numeric heys 0-9
  86.           IF keyalt = 0 THEN car = i
  87.         CASE 97 TO 122 'CTRL a-z: 1-26
  88.           car = i
  89.           IF keyctrl THEN car = car - 96
  90.         CASE 128: car = 238 '€î   'spanish keyboard keys maping
  91.         CASE 161: car = 173 '¡­
  92.         CASE 170: car = 166 'ª¦
  93.         CASE 183: car = 249 '·ù
  94.         CASE 186: car = 167 'º§
  95.         CASE 191: car = 168 '¿¨
  96.         CASE 199: car = 128 'ç€
  97.         CASE 209: car = 165 'Ñ¥
  98.         CASE 231: car = 135 'ç‡
  99.         CASE 241: car = 164 'ñ¤
  100.         CASE 1 TO 255
  101.           car = i
  102.         CASE 256 TO 65535 'double byte chr$(0)+
  103.           doblecar = MKI$(i&)
  104.           car = ASC(doblecar, 2)
  105.           IF keyalt THEN
  106.             SELECT CASE car
  107.               CASE 59 TO 68 'F1-F10: ;-D
  108.                 MID$(doblecar, 2) = CHR$(car + 45)
  109.               CASE 133, 134 'F11,F12; …,†
  110.                 MID$(doblecar, 2) = CHR$(car + 6)
  111.               CASE ELSE
  112.                 MID$(doblecar, 2) = CHR$(0)
  113.             END SELECT
  114.           ELSEIF keyctrl THEN
  115.             SELECT CASE car
  116.               CASE 59 TO 68 'F1-F10: ^-g
  117.                 MID$(doblecar, 2) = CHR$(car + 35)
  118.               CASE 71 'Home
  119.                 MID$(doblecar, 2) = CHR$(119)
  120.               CASE 73 'RePag
  121.                 MID$(doblecar, 2) = CHR$(132)
  122.               CASE 75 'Left
  123.                 MID$(doblecar, 2) = CHR$(115)
  124.               CASE 77 'Right
  125.                 MID$(doblecar, 2) = CHR$(116)
  126.               CASE 79 'End
  127.                 MID$(doblecar, 2) = CHR$(117)
  128.               CASE 81 'AvPag
  129.                 MID$(doblecar, 2) = CHR$(118)
  130.               CASE 133, 134 'F11,F12
  131.                 MID$(doblecar, 2) = CHR$(car + 4)
  132.               CASE ELSE
  133.                 MID$(doblecar, 2) = CHR$(0)
  134.             END SELECT
  135.           ELSEIF keyshift THEN
  136.             SELECT CASE car
  137.               CASE 59 TO 68 'F1-F10
  138.                 MID$(doblecar, 2) = CHR$(car + 25)
  139.               CASE 71 TO 81
  140.               CASE 133, 134 'F11,F12
  141.                 MID$(doblecar, 2) = CHR$(car + 2)
  142.               CASE ELSE
  143.                 MID$(doblecar, 2) = CHR$(0)
  144.             END SELECT
  145.           END IF
  146.           IF CVI(doblecar) THEN
  147.             Inkeyhit$ = doblecar
  148.             iaccent = 0
  149.           END IF
  150.           car = 0
  151.         CASE -100308 'Alt up
  152.           IF LEN(buf$) THEN
  153.             car = VAL(buf$)
  154.             buf$ = ""
  155.           END IF
  156.         CASE -222 'accent and dieresis
  157.           IF keyshift THEN
  158.             iaccent = 3
  159.           ELSE
  160.             iaccent = 1
  161.           END IF
  162.         CASE -186 'backaccent and circumflex
  163.           IF keyshift THEN
  164.             iaccent = 4
  165.           ELSE
  166.             iaccent = 2
  167.           END IF
  168.         CASE -57 TO -48 'numeric keys, also numeric keypad with numlock
  169.           IF keyalt THEN
  170.             IF LEN(buf$) > 2 THEN buf$ = RIGHT$(buf$, 2)
  171.             buf$ = buf$ + CHR$(ABS(i&))
  172.           END IF
  173.       END SELECT
  174.     END IF
  175.     IF car THEN
  176.       Inkeyhit$ = CHR$(car)
  177.       iaccent = 0
  178.     END IF
  179.   END IF
  180.  
« Last Edit: June 05, 2020, 05:27:06 am by moises1953 »

Offline RhoSigma

  • QB64 Developer
  • Forum Resident
  • Posts: 565
    • View Profile
Re: BUGS: display of special characters and keyboard mapping
« Reply #1 on: June 05, 2020, 05:37:28 am »
Try using Steve's "Programmable Keyboard Input" to setup the input for yor needs:
https://www.qb64.org/forum/index.php?topic=2042.0

Or my falcon.h based unicode printing routines:
https://www.qb64.org/forum/index.php?topic=2248.0
« Last Edit: June 05, 2020, 05:39:55 am by RhoSigma »
My Projects:   https://qb64forum.alephc.xyz/index.php?topic=809
GuiTools - A graphic UI framework (can do multiple UI forms/windows in one program)
Libraries - ImageProcess, StringBuffers (virt. files), MD5/SHA2-Hash, LZW etc.
Bonus - Blankers, QB64/Notepad++ setup pack

Offline moises1953

  • Newbie
  • Posts: 55
    • View Profile
Re: BUGS: display of special characters and keyboard mapping
« Reply #2 on: June 05, 2020, 03:13:55 pm »
Thank's a lot RhoSigma, but none of this solves the problem of keyboard capture:
1. ¿Can you write an accented vowel on the IDE?, ¿or capture trought inkey$ function?
2. Think your keyboard has a ß letter. When you press goes to screen of the IDE?, or captures in KEYHIT function?
3. When you press [AltGr]+€, works OK.

In the case of the IDE , this is a bug, but in the case of keyboard capture and display, the InkeyHit funtion, wich emulates de inkey$, solves the problem in 146 lines of code, but needs a lot of maping,  por each keyboard. My example if for Spanish keyboard.

Offline RhoSigma

  • QB64 Developer
  • Forum Resident
  • Posts: 565
    • View Profile
Re: BUGS: display of special characters and keyboard mapping
« Reply #3 on: June 05, 2020, 06:32:50 pm »
Display of special characters and keyboard mapping are a pending subject in QB64. It applies to both the IDE and the INKEY $, KEYHIT, INPUT ... functions.

It's a known problem and will probably remain as is at least for the foreseeable future. A complete overhaul of the input system would be required, which is not an easy task, as it is not just a single function, but several interdependent functions.

When I was adding the input support for &B prefixed numbers for QB64 v1.4 I got a slight idea of how confusing the input system is. You might think adding support for &B is a small change here to recognize the prefix itself and adding a small algorithm there to process the following zeros and ones to get the  final number. But the reality is, that I had to do changes in more than a dozen different places in internal\c\libqb.cpp to catch really all INPUT variants.

In fact, don't expect that this problem will go away soon.

Regardless of the IDE language that is selected, the screen output uses the CP437. So if you configure Windows CP1250, you can see what you write, but when you run the program it will show the character corresponding to the extended ASCII code represented by CP437. Therefore, the page chosen for the IDE is not taken into account to generate the text outputs of the compiled program, therefore it is useless to choose another one than CP437.

It's not useless to use another codepage in the IDE, you just must make your program using the same one to get the correct output. See http://www.qb64.org/wiki/MAPUNICODE and the given example. You can also use the SUB SetAnsiCodepage() from my falcon toolkit mentioned in my first reply. Note that your program must use a unicode font, just as the IDE needs to with another codepage than 437.

Regarding the presentation, let's take an extended character from page CP437, for example º has the code 167, however when typing º on a Spanish keyboard you receive, both in the IDE and in the executables, with the code 186 that represents as ║, and therefore should be mapped to  167 to show º.
As for the keyboard, some [AltGr] keys, like {} [] work well in the IDE, but not in the INPUT, and in neither case can you type accented letters, which requires a KEYHIT process.

As said above, the input system is a pain. Using _MAPUNICODE does only change the text output, so that the strings used in your program will show up correct (if your program CP is mapped to the same CP you've used in the IDE). However, INPUT, INPUT$, INKEY$ etc. will not change by using another codepage, but if it's the same as your system codepage at least the regular letters should work (when using a unicode font in your program). I guess the special AltGr chars will still be wrong or not working at all.

Conclusion, if your InkeyHit function works for you, then be happy and use it. I made a similar function for german keyboards here: https://www.qb64.org/forum/index.php?topic=1385.0
My Projects:   https://qb64forum.alephc.xyz/index.php?topic=809
GuiTools - A graphic UI framework (can do multiple UI forms/windows in one program)
Libraries - ImageProcess, StringBuffers (virt. files), MD5/SHA2-Hash, LZW etc.
Bonus - Blankers, QB64/Notepad++ setup pack

Offline moises1953

  • Newbie
  • Posts: 55
    • View Profile
Re: BUGS: display of special characters and keyboard mapping
« Reply #4 on: June 06, 2020, 02:05:03 am »
Thank's a lot RhoSigma.
Most people who migrate an application from DOS only need consistency, which in the case of the keyboard means that if you touch a key it appears in the IDE, is written the same in the output, and is captured the same in the inputs. Agree?
Could that happen by using the translation function of the windows API?

https://docs.microsoft.com/en-us/windows/win32/inputdev/using-keyboard-input
....
Any thread that receives character input from the user must include the TranslateMessage function in its message loop. This function examines the virtual-key code of a keystroke message and, if the code corresponds to a character, places a character message into the message queue. The character message is removed and dispatched on the next iteration of the message loop; the wParam parameter of the message contains the character code.

In general, a thread's message loop should use the TranslateMessage function to translate every message, not just virtual-key messages. Although TranslateMessage has no effect on other types of messages, it guarantees that keyboard input is translated correctly. The following example shows how to include the TranslateMessage function in a typical thread message loop.
...