Thread Rating:
  • 1 Vote(s) - 4 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Inkey for non-US keyboards (Cp1252 based languages)
#1
Lightbulb 
This is a alternative Inkey$ function, which takes the input from several local keyboard types and maps the keyhits to the DOS Cp437 as good  as possible without the need of _MAPUNICODE.

InkeyHit.bas
Code: (Select All)
'----------------------
'--- InkeyHit$ test ---
'----------------------
PRINT "start pressing keys..."
PRINT "- try single keys incl. arrows, Ins, Del etc."
PRINT "- use shift, ctrl, alt combos with keys"
PRINT "- if you have that key, check AltGr + key combos"
PRINT "- Enter will end the program": PRINT

DO
    i$ = ""
    WHILE i$ = ""
        _LIMIT 50
        i$ = InkeyHit$(1031) '1031 = german de-DE (look at top of the function for others)
    WEND
    IF LEN(i$) = 2 THEN
        PRINT "CHR$(0) +", ASC(i$, 2), RIGHT$(i$, 1)
    ELSE
        PRINT "-------->", ASC(i$, 1), i$
    END IF
    IF i$ = CHR$(27) THEN CLS
LOOP UNTIL i$ = CHR$(13)
END

'-----------------
'--- InkeyHit$ ---
'-----------------
' This alternative INKEY$ function is made for use with western european
' languages (Cp1252 based) and any QB64 versions >= 1.000. It will
' directly map the inputs to the chars available in Cp437, hence you don't
' need to setup a custom unicode font and _MAPUNICODE table, you can stay
' with QB64's built-in fonts and standard codepage 437.
' By this means it solves the INKEY$ issues introduced with the transition
' from using SDL to using OpenGL regarding special/international chars.
' However, it does not fix the regular INPUT, LINE INPUT and INPUT$ when
' used for keyboard input, here you should create your own functions,
' which use this function to get its inputs.
' This function is based on my old function made for Germany/Austria only,
' but now also implements support for other languages (keyboard layouts)
' based on the research work done by forum member moises1953.
'----------
' SYNTAX:
'  keypress$ = InkeyHit$ (kbl%)
'----------
' INPUTS:
'  --- kbl% ---
'    The keyboard layout/language ID (eg. 1031 for de-DE), which is in
'    effect on your system. Make sure your language is listed in the CONSTs
'    at the beginning of the function. If you use this function with any
'    unsupported language, then some keys might not work as expected
'    (eg. accents, umlauts or AltGr key triggered chars).
'----------
' RESULT:
'  --- keypress$ ---
'    Equivalent to the INKEY$ result (see Wiki).
'----------
' ACCENTS:
'  Note that the accents keys on most keyboards are so called
'  preselection keys, different from modifier keys (Shift/Ctrl/Alt)
'  you don't need to hold them while typing accented chars. You just
'  press it once followed by pressing the letter key once to get the
'  respective accented char (eg. ` + e = Š). To get the accent char
'  itself you either press the space bar after the accent preselection
'  or you press the accent preselection key twice.
'----------
' LIMITS:
'  Note that the following keys and key combos are not supported
'  for various reasons:
'
'    Two Byte Characters        Key                CHR$(0) + "?"
'  -------------------------------------------------------------
'  CHR$(0) + CHR$(16-50)      [Alt] + letter
'    rarely used, not in alphabetical order, KB layout dependent,
'    => returns the regular char instead (Alt modifier ignored)
'  CHR$(0) + CHR$(76)        [5 NumberPad]        "L" (NumLock off in QB64)
'    rarely used, almost useless for most applications,
'    => returns nothing
'  CHR$(0) + CHR$(120-129)    [Alt] + number
'    ignored in favor for alternative Alt + ASCII code input method,
'    => returns nothing, but collects numbers to built an ASCII code,
'      the respective char is returned when releasing the Alt-Key
'  CHR$(0) + CHR$(130 or 131) [Alt] + _/- or +/=  "‚" or "ƒ"
'    rarely used, KB layout dependent,
'    => returns the regular char instead (Alt modifier ignored)
'---------------------------------------------------------------------
FUNCTION InkeyHit$ (kbl%)
'--- option _explicit requirements ---
DIM charCode&, hitVal&, oPreKey&, modShift%, modCtrl%, modAltGr%, modAlt%, modNone%
DIM modShiftOnly%, modCtrlOnly%, modAltOnly%, modCtrlNoAlt%, inChar%, outChar%

'--- keyboard layouts supported by this routine ---
CONST kbDaDk% = 1030, kbDeDe% = 1031, kbEsEs% = 1034, kbFrFr% = 1036
CONST kbNlNl% = 1043, kbNbNo% = 1044, kbSvSe% = 1053
CONST kbDeCh% = 2055, kbEsMx% = 2058, kbFrBe% = 2060, kbPtPt% = 2070
'--- accent preselection key types ---
CONST pkAcute% = 1, pkGrave% = 2, pkUmlau% = 3, pkCircu% = 4

'--- variables init ---
STATIC lastKey&, preKey&, ascNum$
InkeyHit$ = "": charCode& = 0

'--- flush regular input buffer & get next key hit ---
DO: LOOP UNTIL INKEY$ = ""
hitVal& = _KEYHIT
IF hitVal& <> 0 THEN
    '--- get modifiers ---
    modShift% = _KEYDOWN(100303) OR _KEYDOWN(100304)
    modCtrl% = _KEYDOWN(100305) OR _KEYDOWN(100306)
    modAltGr% = _KEYDOWN(100307) AND _KEYDOWN(100306)
    modAlt% = (_KEYDOWN(100307) OR _KEYDOWN(100308)) AND NOT modAltGr%
    '--- special conditions ---
    modNone% = NOT modShift% AND NOT modCtrl% AND NOT modAlt% AND NOT modAltGr%
    modShiftOnly% = modShift% AND NOT modCtrl% AND NOT modAlt% AND NOT modAltGr%
    modCtrlOnly% = modCtrl% AND NOT modShift% AND NOT modAlt% AND NOT modAltGr%
    modAltOnly% = modAlt% AND NOT modShift% AND NOT modCtrl% 'not AltGr implied in Alt
    modCtrlNoAlt% = modCtrl% AND NOT modAlt% AND NOT modAltGr% 'shift allowed

    '--- start evaluation ---
    IF hitVal& > 0 THEN
        IF hitVal& <= 255 THEN lastKey& = hitVal& 'for later release detection
        '--- lookup preselected accent (if any) ---
        IF hitVal& >= 32 AND hitVal& <= 127 THEN
            SELECT CASE preKey&
                CASE pkAcute%
                    RESTORE InkeyHit_Acute
                    DO: READ inChar%, outChar%: LOOP UNTIL inChar% = hitVal& OR inChar% = 0
                    charCode& = outChar%
                CASE pkGrave%
                    RESTORE InkeyHit_Grave
                    DO: READ inChar%, outChar%: LOOP UNTIL inChar% = hitVal& OR inChar% = 0
                    charCode& = outChar%
                CASE pkUmlau%
                    RESTORE InkeyHit_Umlau
                    DO: READ inChar%, outChar%: LOOP UNTIL inChar% = hitVal& OR inChar% = 0
                    charCode& = outChar%
                CASE pkCircu%
                    RESTORE InkeyHit_Circu
                    DO: READ inChar%, outChar%: LOOP UNTIL inChar% = hitVal& OR inChar% = 0
                    charCode& = outChar%
            END SELECT
        END IF
        'Regardless of the lookup result, any non-modifier key press
        'has to properly cancel any pending preselection.
        IF hitVal& <= 65535 THEN preKey& = 0

        '--- if no accent was found or preselected, then move on ---
        IF charCode& = 0 THEN
            'take the regular key code as default
            charCode& = hitVal&
            'check shift/ctrl/alt conditions and special behavior
            SELECT CASE hitVal&
                CASE 9 'tab & reverse tab
                    IF modShiftOnly% THEN charCode& = 15 * 256
                CASE 48 TO 57 'numeric keys 0-9
                    IF NOT modNone% THEN charCode& = 0
                CASE 65 TO 90 'CTRL CAPS A-Z: 1-26
                    IF modCtrlNoAlt% THEN charCode& = hitVal& - 64
                CASE 97 TO 122 'CTRL a-z: 1-26
                    IF modCtrlNoAlt% THEN charCode& = hitVal& - 96
                CASE 128 TO 255 'Ext. ASCII (Cp1252 to Cp437 mapping, if available)
                    RESTORE InkeyHit_Regul
                    DO: READ inChar%, outChar%: LOOP UNTIL inChar% = hitVal& OR inChar% = 0
                    charCode& = outChar%
                CASE 256 TO 65535 'double char chr$(0) +
                    IF (hitVal& AND 255) = 0 THEN
                        hitVal& = hitVal& \ 256
                        SELECT CASE hitVal& 'Alt overrides Ctrl overrides Shift
                            CASE 59 TO 68 'F1-F10
                                IF modShift% THEN charCode& = (hitVal& + 25) * 256
                                IF modCtrl% THEN charCode& = (hitVal& + 35) * 256
                                IF modAlt% THEN charCode& = (hitVal& + 45) * 256
                            CASE 133, 134 'F11-F12
                                IF modShift% THEN charCode& = (hitVal& + 2) * 256
                                IF modCtrl% THEN charCode& = (hitVal& + 4) * 256
                                IF modAlt% THEN charCode& = (hitVal& + 6) * 256
                            CASE 71 'Home
                                IF modCtrl% THEN charCode& = 119 * 256
                                IF modAlt% THEN charCode& = 151 * 256
                            CASE 72 'ArrowUp
                                IF modCtrl% THEN charCode& = 141 * 256
                                IF modAlt% THEN charCode& = 152 * 256
                            CASE 73 'PageUp
                                IF modCtrl% THEN charCode& = 132 * 256
                                IF modAlt% THEN charCode& = 153 * 256
                            CASE 75 'ArrowLeft
                                IF modCtrl% THEN charCode& = 115 * 256
                                IF modAlt% THEN charCode& = 155 * 256
                            CASE 77 'ArrowRight
                                IF modCtrl% THEN charCode& = 116 * 256
                                IF modAlt% THEN charCode& = 157 * 256
                            CASE 79 'End
                                IF modCtrl% THEN charCode& = 117 * 256
                                IF modAlt% THEN charCode& = 159 * 256
                            CASE 80 'ArrowDown
                                IF modCtrl% THEN charCode& = 145 * 256
                                IF modAlt% THEN charCode& = 160 * 256
                            CASE 81 'PageDown
                                IF modCtrl% THEN charCode& = 118 * 256
                                IF modAlt% THEN charCode& = 161 * 256
                            CASE 82 'Insert
                                IF modCtrl% THEN charCode& = 146 * 256
                                IF modAlt% THEN charCode& = 162 * 256
                            CASE 83 'Delete
                                IF modCtrl% THEN charCode& = 147 * 256
                                IF modAlt% THEN charCode& = 163 * 256
                        END SELECT
                    END IF
            END SELECT
        END IF
    ELSE
        oPreKey& = preKey& 'save current preselection state
        SELECT CASE hitVal&
            CASE -57 TO -48 'collect numbers (Alt + char code input)
                IF modAltOnly% THEN ascNum$ = ascNum$ + CHR$(-hitVal&): _
                ELSE IF hitVal& = -50 AND modAltGr% AND kbl% = kbFrFr% THEN charCode& = 126 '~
            CASE -100308 'Alt released: build char from last 3 digits
                IF ascNum$ <> "" THEN
                    charCode& = VAL(RIGHT$(ascNum$, 3))
                    IF charCode& < 32 OR charCode& > 255 THEN charCode& = 0
                    lastKey& = 0: preKey& = 0: ascNum$ = "" 'cancel all
                END IF
            CASE -lastKey& 'cancel the last key
                lastKey& = 0
                'This case is just here to trap the releases of regular keys.
                'It is required to avoid the generation of false positives
                'for the following accent preselection cases, if the regular
                'key release would generate the same value as any accent key.
            CASE -186
                SELECT CASE kbl%
                    CASE kbPtPt% 'acute & grave
                        IF modNone% THEN preKey& = pkAcute%
                        IF modShiftOnly% THEN preKey& = pkGrave%
                    CASE kbEsEs% 'grave & circumflex
                        IF modNone% THEN preKey& = pkGrave%
                        IF modShiftOnly% THEN preKey& = pkCircu%
                    CASE kbDaDk%, kbSvSe%, kbNbNo% 'umlaut & circumflex
                        IF modNone% THEN preKey& = pkUmlau%
                        IF modShiftOnly% THEN preKey& = pkCircu%
                    CASE kbEsMx% 'acute & umlaut
                        IF modNone% THEN preKey& = pkAcute%
                        IF modShiftOnly% THEN preKey& = pkUmlau%
                END SELECT
            CASE -187
                SELECT CASE kbl%
                    CASE kbPtPt% 'umlaut
                        IF modNone% THEN preKey& = pkUmlau%
                END SELECT
            CASE -191
                SELECT CASE kbl%
                    CASE kbPtPt% 'circumflex
                        IF modNone% THEN preKey& = pkCircu%
                    CASE kbEsMx% 'grave
                        IF modNone% THEN preKey& = pkGrave%
                END SELECT
            CASE -192
                SELECT CASE kbl%
                    CASE kbNlNl% 'acute & grave
                        IF modNone% THEN preKey& = pkAcute%
                        IF modShiftOnly% THEN preKey& = pkGrave%
                    CASE kbDeCh% 'umlaut
                        IF modNone% THEN preKey& = pkUmlau%
                    CASE kbFrFr%, kbFrBe% 'acute
                        IF modNone% THEN preKey& = pkAcute%
                END SELECT
            CASE -219
                SELECT CASE kbl%
                    CASE kbDeCh% 'acute
                        IF modNone% THEN preKey& = pkAcute%
                    CASE kbDaDk%, kbSvSe%, kbNbNo% 'acute & grave
                        IF modNone% THEN preKey& = pkAcute%
                        IF modShiftOnly% THEN preKey& = pkGrave%
                END SELECT
            CASE -220
                SELECT CASE kbl%
                    CASE kbFrBe% 'grave
                        IF modNone% THEN preKey& = pkGrave%
                    CASE kbDeDe% 'circumflex
                        IF modNone% THEN preKey& = pkCircu%
                END SELECT
            CASE -221
                SELECT CASE kbl%
                    CASE kbFrFr%, kbFrBe% 'circumflex & umlaut
                        IF modNone% THEN preKey& = pkCircu%
                        IF modShiftOnly% THEN preKey& = pkUmlau%
                    CASE kbNlNl% 'umlaut & circumflex
                        IF modNone% THEN preKey& = pkUmlau%
                        IF modShiftOnly% THEN preKey& = pkCircu%
                    CASE kbDeCh% 'circumflex & grave
                        IF modNone% THEN preKey& = pkCircu%
                        IF modShiftOnly% THEN preKey& = pkGrave%
                    CASE kbDeDe% 'acute & grave
                        IF modNone% THEN preKey& = pkAcute%
                        IF modShiftOnly% THEN preKey& = pkGrave%
                END SELECT
            CASE -222
                SELECT CASE kbl%
                    CASE kbEsEs% 'acute & umlaut
                        IF modNone% THEN preKey& = pkAcute%
                        IF modShiftOnly% THEN preKey& = pkUmlau%
                    CASE kbEsMx% 'circumflex
                        IF modNone% THEN preKey& = pkCircu%
                END SELECT
            CASE -226
                SELECT CASE kbl%
                    CASE kbPtPt% '\
                        IF modNone% THEN charCode& = 92
                END SELECT
            CASE ELSE
                oPreKey& = 0 'no case did match, cancel saved state
        END SELECT
        '--- check double-preselection key press (if any) ---
        IF oPreKey& > 0 AND oPreKey& = preKey& THEN
            SELECT CASE preKey&
                CASE pkAcute%: charCode& = 39
                CASE pkGrave%: charCode& = 96
                CASE pkUmlau%: charCode& = 34
                CASE pkCircu%: charCode& = 94
            END SELECT
        END IF
    END IF
END IF
'--- finally encode the usual INKEY$ result ---
IF charCode& > 0 AND charCode& <= 65535 THEN
    IF charCode& <= 255 THEN InkeyHit$ = CHR$(charCode&)
    IF charCode& >= 256 AND charCode& <= 65535 AND (charCode& AND 255) = 0 THEN InkeyHit$ = CHR$(0) + CHR$(charCode& \ 256)
    lastKey& = 0: preKey& = 0
END IF
EXIT FUNCTION
'-----------------------------
'Char lookup tables:
'=> pairs of Input ASC (Cp1252), Output ASC (Cp437)
'=> lists must be double 0-terminated
InkeyHit_Regul:
DATA 128,238,161,173,162,155,163,156,164,15,165,157,166,124,167,21,170,166,171,174
DATA 172,170,176,248,177,241,178,253,179,252,181,230,182,20,183,250,186,167,187,175
DATA 188,172,189,171,191,168,196,142,197,143,198,146,199,128,201,144,209,165,214,153
DATA 220,154,223,225,224,133,225,160,226,131,228,132,229,134,230,145,231,135,232,138
DATA 233,130,234,136,235,137,236,141,237,161,238,140,239,139,241,164,242,149,243,162
DATA 244,147,246,148,247,246,248,232,249,151,250,163,251,150,252,129,255,152,0,0
InkeyHit_Acute:
DATA 32,39,97,160,101,130,105,161,111,162,117,163,69,144,0,0
InkeyHit_Grave:
DATA 32,96,97,133,101,138,105,141,111,149,117,151,0,0
InkeyHit_Umlau:
DATA 97,132,101,137,105,139,111,148,117,129,65,142,79,153,85,154,121,152,0,0
InkeyHit_Circu:
DATA 32,94,97,131,101,136,105,140,111,147,117,150,65,143,0,0
END FUNCTION
Reply




Users browsing this thread: 3 Guest(s)