Encoding Hazzles

  • VB.NET
  • .NET (FX) 4.5–4.8

Es gibt 24 Antworten in diesem Thema. Der letzte Beitrag () ist von Peter329.

    Encoding Hazzles

    Hi,

    ein ganz einfaches Problem: weil mein Tischrechner nach vielen Jahren seinen Geist aufgeben hat, und ich mich so an ihn gewöhnt habe, möchte ich den in VB realisieren. Anbei ein picture.

    Man kann per Maus Eingaben machen. Oder man kann die Eingaben per Tastatur machen. In jedem Fall landen die Eingaben im oberen Eingabefenster.

    Natürlich möchte ich per Tastatur nur folgende Eingaben zulassen:

    Zahlen und Dezimalzeichen : 0, 1, 2, ... 9, . und ,

    Rechenoperationen: + - x / % =

    Alle anderen Tasten sollen einfach ignoriert werden.

    Das habe ich wie folgt vesucht:

    VB.NET-Quellcode

    1. Private Sub txtInput_KeyDown(sender As Object, e As KeyEventArgs) Handles txtInput.KeyDown
    2. Debug.Print("txtInput_KeyDown --> ProcessKey KeyCode=" & e.KeyCode.ToString)
    3. e.SuppressKeyPress = ProcessKey(e.KeyCode)
    4. End Sub
    5. Private Function ProcessKey(Keycode As Integer) As Boolean
    6. If Keycode <= 20 Then Return False 'Ignore CNTL, SHIFT, ALT etc.
    7. Dim workchr As Char = Convert.ToChar(Keycode)
    8. Debug.Print("ProcessKey --> Keycode=" & Keycode.ToString & " workchr=" & workchr.ToString)
    9. Select Case workchr
    10. Case "0"c To "9"c
    11. Return False 'Accept numerics
    12. Case "."c, ","c
    13. Return False 'Accept decimals
    14. Case "+"c, "-"c, "%"c, "="c
    15. ProcessCommand(workchr) 'Process operation codes
    16. Case "x"c, "X"c, "*"c
    17. ProcessCommand("x"c) 'Process operation codes
    18. Case "/"c, ":"c
    19. ProcessCommand("/"c) 'Process operation codes
    20. Case Else
    21. Return False
    22. End Select
    23. Return True 'Process key
    24. End Function


    Mit den Zahlen und Dezimalzeichen klappt das ja auch prima.

    Aber mit den Rechenoperationen klappt das überhaupt nicht. Das liegt daran, dass die Konvertierung nicht die richtigen Zeichen liefern. Wenn ich 5 eingebe, dann ist workint = 35 und workchr = "5"c , so wie es sein soll. Wenn ich aber ein ein '+' eingeben, dann kommt alles andere als workchr = "+"c heraus !

    Und was besonders blöde ist: wenn ich '=' eingebe, dann ist workchr = "0"c ... und das bringt mein Programmlogik dann vollends durcheinander.

    Diese Anweisung ist wohl nicht richtig:

    VB.NET-Quellcode

    1. Dim workchr As Char = Convert.ToChar(Keycode)


    Kann mir jemand (nachsichtig) erklären was ich falsch mache und wie ich das auf die Reihe kriegen kann ?

    LG
    Peter


    P.S.: Wieso hat denn mein Programmcode so viele Leerzeilen ? Ich habe den mit Cut&Paste eingefügt und in meinem Coding sind die Leerzeilen nicht enthalten.
    Bilder
    • s 2017-08-30 14-48-210.jpg

      46,89 kB, 915×461, 158 mal angesehen

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „Peter329“ ()

    @Peter329 Setz in die Prozedsur txtInput_KeyDown einen Haltepunkt und sieh Dir an, was bei der gewünschten Taste für ein Code ankommt, den kannste dann gleich online eintragen und weiter-debuggen. ;)
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    Na ja, den Debugger hab ich schon eingeschaltet, bevor ich es gewagt habe, hier im Forum aufzuschlagen. :)

    Wenn ich z.B. ein '+' eingebe, dann erhalte ich den Keycode = 187

    Die Anweisung:

    VB.NET-Quellcode

    1. Dim workchr As Char = Convert.ToChar(Keycode)


    LIefert dann workchr = ">>" c.

    Währende "+"c irgendwas von UTF-16 murmelt ... Und damit scheitert die Abfrage.

    Irgendwie konvertiere ich nicht richtig, das ist mir schon klar.

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „Peter329“ ()

    Peter329 schrieb:

    VB.NET-Quellcode

    1. Dim workchr As Char = Convert.ToChar(Keycode)
    Arbeite mit e.KeyData, nicht aber mit einem ggf. falsch konvertierten Char.

    VB.NET-Quellcode

    1. Select Case e.KeyData
    2. Case Keys.D0 To Keys.D9
    3. Label1.Text = e.KeyData.ToString
    4. End Select
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    ok, das mit "e.keydata" ist schon mal ein Wink in die richtige Richtung.

    keydata ist from Typ "Keys". Und es enthält wohl den KeyCode sowie Flags für SHIFT (UMSCHALT) und CTRL (STRG) etc. ... Aber wie man jetzt damit umgeht, da habe ich Probleme.

    Ich will beispielsweise abfragen ob die SHIFT Taste gedrückt ist. Im Debugger sehe ich, dass dann e.keydata = Keys.Shift Or Keys.Shiftkey ist.

    Wenn ich das so abfrage

    VB.NET-Quellcode

    1. If KeyData = Keys.Shift Or Keys.ShiftKey Then ...


    dann mosert der Compiler, dass Option "Strict On" die Konvertierungen Boolean nach Integer bzw. Integer nach Boolean nicht zulässt.

    Wie extrahiere ich denn KeyCode und Modifizierer aus den KeyData ?

    Peter329 schrieb:

    Modifizierer
    Genau das:

    VB.NET-Quellcode

    1. Label2.Text = e.Modifiers.ToString
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    Du musst bei den Keys auch drauf achten, dass es Plus und Minus zweimal gibt. Also Key.OemPlus und Key.OemMinus für die auf der normalen Tastatur und Key.Add bzw. Key.Subtract für die Numpad Tasten.

    Grüße
    Vainamo

    Peter329 schrieb:

    VB.NET-Quellcode

    1. If
    2. KeyData = Keys.Shift Or Keys.ShiftKey Then ...
    dann mosert der Compiler, dass Option "Strict On" die Konvertierungen Boolean nach
    Integer bzw. Integer nach Boolean nicht zulässt.
    Dann ist das wohl ein Operator-Vorrang-Problem. Folglich mit Klammerung die Vorrangigkeit selbst festlegen

    VB.NET-Quellcode

    1. If KeyData = (Keys.Shift Or Keys.ShiftKey) Then ...
    allerdings ist der Wert Keys.Shift Or Keys.ShiftKey nicht besonders sinnvoll abzufragen.
    Vlt. beschäftigst du dich mal mit BitOperationen, Bitmasken etc, und wie man das auf Enumerationen anwendet.
    Im Löffelmann-2005er-Buch ist ein ganz auszeichnetes Kapitel zu Enumerationen.
    Ah - hier habich auch was dazu gebastelt: Keys-Enumeration verstehen

    Vainamo schrieb:

    dass es Plus und Minus zweimal gibt

    @Peter329 Jou. Jetzt kommt auch die in Post #2 beschriebene Methode mit dem Haltepunkt und dem Online-Debug-Auswerten der gedrückten Taste zum Tragen. ;)
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    Erst mal recht herzlichen Dank an euch Drei ! Ihr habt mir sehr geholfen.

    @Vainamo

    Jau, das mit dem Nummern Block ist richtig. Nicht nur Add und Subtract haben andere Belegungen, sondern ALLE Tasten. Das muss man wissen.

    Wie kann ich denn abfragen, ob NUMLOCK aktiv ist oder nicht ?

    @EDR
    Ein Problem der "precedence of operators" ... Mann, da hätte ich selbst drauf kommen sollen. Intellisense war da nicht ganz so hilfreich. Aber jetzt klappt das mit dem Maskieren und Abfragen der Bits ganz hervorragen (wenn man noch beachtet, dass für die Bits-Strings im IF ein CBOOL() fällig ist). Danke, für dein Beispiel.

    Jetzt wäre ich fast happy ... aber es gibt leider noch ein Problem:

    Der Schrägstrich ("/") ist bei mir über SHIFT-D7 zu erreichen (weil ich ein deutsches Keyboard habe). Wenn ich das eingebe dann erhalte ich:

    VB.NET-Quellcode

    1. Private Sub txtInput_KeyDown(sender As Object, e As KeyEventArgs) Handles txtInput.KeyDown
    2. Debug.Print("txtInput_KeyDown --> KeyData=" & e.KeyData.ToString & " x'" & Hex(e.KeyData) &
    3. " Modifiers=" & e.Modifiers & " x'" & Hex(e.Modifiers) & " " & e.Modifiers.ToString &
    4. " KeyCode=" & e.KeyCode.ToString & " x'" & Hex(e.KeyCode) &
    5. " KeyValue=" & e.KeyValue.ToString & " x'" & Hex(e.KeyValue))
    6. txtInput_KeyDown --> KeyData=D7, Shift x'10037
    7. Modifiers=65536 x'10000 Shift
    8. KeyCode=D7 x'37
    9. KeyValue=55 x'37


    Sieht ja auch alles ganz easy aus. Im ersten Int-16 Wort ist Keys.Shift (x'0001') enthalten.
    Und im zweiten Int-16 Wort steht der Keycode D7 (x'37 = 55) drin.

    Aber wo zum Teufel kann ich herausfinden, dass dies ein SCHRÄGSTRICH ist ? Andere e. Properties habe ich nicht gefunden. Aber in die Textbox wird jedenfalls ein Schrägstrich eingefügt. Aber genau das will ich verhindern, weil der Schrägstrich "dividieren" bedeutet und nicht angezeigt, sondern ausgeführt werden soll.

    Dass SHIFT-D7 der Schrägstrich ist, kann ich nicht fest einprogrammieren, weil der Schrägstrich bei amerikanischen Keyboards ganz woanders liegt !

    Ich bin ratlos. Ich hoffe, ihr könnt mir helfen.

    LG
    Peter

    Dieser Beitrag wurde bereits 3 mal editiert, zuletzt von „Peter329“ ()

    Das klingt ja eigentlich sehr vielversprechend:

    VB.NET-Quellcode

    1. Dim myKey As String = KeysConverter.ConvertToString(e.KeyCode)
    2. Fehler BC30469 Der Verweis auf einen nicht freigegebenen Member erfordert einen Objektverweis.


    Das sagt mir jetzt leider nichts. Und Intellisense hilft auch nicht unbedingt weiter ...

    LG
    Peter
    Musst auch ein Objekt nehmen ;) Ist allerdings nicht ganz das Richtige wie ich gerade festgestellt habe. Du müsstest wahrscheinlich P/Invoke bemühen und MapVirtualKey + ToUnicodeEx. Davon mal abgesehen, was ist denn mit dem KeyPress-Event? Das gibt dir direkt n Char mit.
    was ist denn mit dem KeyPress-Event? Das gibt dir direkt n Char mit.


    ehem ... also, ich habe die angelieferten Properties und Functions von oben nach unten durchforstet:

    Properties:

    Alt
    Control
    Handled
    KeyCode
    KeyData
    KeyValue
    Modifiers
    Shift
    SuppressKeypress

    Functions:

    Equals
    GetHashCode
    GetType
    ToString

    Am ehesten wäre mir noch "ToString" aussichtsreich erschienen. Aber das hilft auch nicht weiter:

    e=System.Windows.Forms.KeyEventArgs

    Also ich sehe nicht, wie ich im an das generierte Zeichen heran komme.

    LG
    Peter
    Ok, für Eingaben, die innerhalb der Display Textbox erfolgen klappt das damit. Danke !

    Ich will aber auch alle Eingaben verarbeiten, selbst wenn die Display Textbox NICHT den Focus hat. Das mache ich wie folgt:

    VB.NET-Quellcode

    1. Const WM_KEYDOWN As Integer = &H100
    2. Protected Overrides Function ProcessCmdKey(ByRef msg As System.Windows.Forms.Message,
    3. ByVal keyData As System.Windows.Forms.Keys) As Boolean
    4. If msg.Msg = WM_KEYDOWN Then
    5. If txtInput.Focused Then
    6. Debug.Print("ProcessCmdKey --> ignored because txtInput is focussed")
    7. Return MyBase.ProcessCmdKey(msg, keyData) 'All keys are passed to txtInput
    8. End If
    9. Debug.Print("ProcessCmdKey --> KeyData=" & keyData.ToString)
    10. ProcessKeydata(keyData) 'Process key outside focus
    11. End If
    12. Return True 'All done
    13. End Function


    In dieser Umgebung habe ich nur keyData. Wie ich da Modifiers und keyCode extrahieren kann, habe ich Dank EDR ja gelernt.

    Die Frage ist, wie ich hier den "keyChar" heraus bekomme.

    Im dümmsten Fall werde ich kapitulieren und SHIFT+D7 hart einprogrammieren. Dann läuft das auf meinem PC, aber eben nicht unbedingt auf anderen PCs ...

    LG Peter
    Mach's dir leicht. Nimm das KeyPress-Event deines Fensters, zusätzlich musst du KeyPreview auf True setzen. Das Fenster registriert immer dann Tastendrücke wenn der Focus auf einem Control liegt, dass keine Texteingabe vorsieht. Ist der Focus in deiner TextBox, tippst du in die TextBox. Ist der Focus auf einem Button, erhält das Fenster den KeyPress.

    Peter329 schrieb:

    Wie kann ich denn abfragen, ob NUMLOCK aktiv ist oder nicht ?
    Soweit ich das verstanden habe ist das nicht erforderlich, das System schickt Dir die richtichen KeyCodes.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!

    Gonger96 schrieb:

    Mach's dir leicht.


    Na ja, also meine Form enthält mehr als ein Dutzend Controls! Und für die dann alle das KeyPress Event zu abonnieren, das gefällt mir dann nicht so richtig.

    Es muss doch möglich sein herauszufinden, welches Zeichen aufgrund von Modifiers und Keycode generiert wird.

    RFG schrieb:

    Soweit ich das verstanden habe ist das nicht erforderlich, das System schickt Dir die richtichen KeyCodes.


    Jau das ist richtig ... aber vielleicht möchte ich eine Meldung generieren: "Please, activate Numlock" ... aber wie du schon sagst, andernfalls werden halt einfach Keystrokes generiert, die ich ignoriere. Damit könnte ich dann auch leben.

    LG
    Peter

    Peter329 schrieb:

    "Please, activate Numlock"
    Das wäre keine gute Reklame, weil ich üblicherweise nicht mit NumLook arbeite, nur gelegentlich beim Taschenrechner.

    Peter329 schrieb:

    Es muss doch möglich sein herauszufinden, welches Zeichen aufgrund von Modifiers und Keycode generiert wird.
    Teste das mit einer separaten Form, ein paar Labels und KeyPreview = True, gib dann in den Labeln alles mögliche aus zum Testen Deiner Tastaturauswertung.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!