Author Topic: First Run at a virtual, customized keyboard routine  (Read 2112 times)

0 Members and 1 Guest are viewing this topic.

Offline SMcNeill

  • QB64 Developer
  • Forum Resident
  • Posts: 3972
    • View Profile
    • Steve’s QB64 Archive Forum
First Run at a virtual, customized keyboard routine
« on: February 03, 2021, 09:17:29 pm »
Code: QB64: [Select]
  1. SCREEN _NEWIMAGE(640, 480, 32)
  2.  
  3. k = KB_Input(1, 30, 30, 100, 100)
  4. IF k > 0 AND k < 256 THEN PRINT CHR$(k)
  5.  
  6.  
  7.  
  8.  
  9.  
  10.  
  11. FUNCTION KB_Input (KB, Xsize, Ysize, Xpos, Ypos)
  12.  
  13.     restart:
  14.     IF keyboard_image THEN _FREEIMAGE keyboard_image
  15.  
  16.     SELECT CASE KB
  17.         CASE 1 'starting, caps keyboard 
  18.             REDIM KB(0 TO 3) AS STRING
  19.             KB(0) = "ABCDEFGH" + CHR$(0)
  20.             KB(1) = "IJKLMNOP" + CHR$(0)
  21.             KB(2) = "QRSTUVWX" + CHR$(0)
  22.             KB(3) = "YZ" + CHR$(0)
  23.         CASE 2 'lower case keyboard 
  24.             REDIM KB(0 TO 3) AS STRING
  25.             KB(0) = "abcdefgh" + CHR$(0)
  26.             KB(1) = "ijklmnop" + CHR$(0)
  27.             KB(2) = "qrstyvxx" + CHR$(0)
  28.             KB(3) = "yz" + CHR$(0)
  29.         CASE 3 'top row values
  30.             REDIM KB(0 TO 3) AS STRING
  31.             KB(0) = "12345678" + CHR$(0)
  32.             KB(1) = "90!@#$%^" + CHR$(0)
  33.             KB(2) = "&*()-=_+" + CHR$(0)
  34.             KB(3) = "`~" + CHR$(0)
  35.         CASE 4
  36.             REDIM KB(0 TO 3) AS STRING
  37.             KB(0) = "This" + CHR$(0)
  38.             KB(1) = "does not" + CHR$(0)
  39.             KB(2) = "yet work" + CHR$(0)
  40.             KB(3) = "" + CHR$(0)
  41.         CASE 5
  42.             REDIM KB(0 TO 3) AS STRING
  43.             KB(0) = "" + CHR$(0)
  44.             KB(1) = "" + CHR$(0)
  45.             KB(2) = "" + CHR$(0)
  46.             KB(3) = "" + CHR$(0)
  47.         CASE 6
  48.             REDIM KB(0 TO 1) AS STRING
  49.             KB(0) = "" + CHR$(0)
  50.             KB(1) = "" + CHR$(0)
  51.         CASE 7
  52.             REDIM KB(0) AS STRING
  53.             KB(0) = "" + CHR$(0)
  54.     END SELECT
  55.  
  56.     l = LBOUND(KB): u = UBOUND(KB)
  57.     FOR i = l TO u 'get longest line
  58.         IF LEN(KB(i)) > LL THEN LL = LEN(KB(i))
  59.     NEXT
  60.     LL = LL + 1
  61.     keyboard_image = _NEWIMAGE((Xsize + 2) * LL, (Ysize + 2) * (u - l + 1), 32)
  62.     'now build the keyboard
  63.     FOR i = l TO u
  64.         top = (i - l) * Ysize + Ypos
  65.         FOR j = 1 TO LEN(KB(i))
  66.             left = (j - 1) * Xsize + Xpos
  67.             LINE (left, top)-STEP(Xsize, Ysize), -1, B
  68.             IF j < LEN(KB(i)) AND i < 3 THEN
  69.                 c = ASC(KB(i), j)
  70.                 IF c < 32 THEN out$ = "KB" + _TRIM$(STR$(c)) ELSE out$ = CHR$(c)
  71.                 IF c = 0 THEN out$ = ""
  72.             ELSE
  73.                 IF j = LEN(KB(i)) THEN
  74.                     SELECT CASE i
  75.                         CASE 0: out$ = "BSP"
  76.                         CASE 1: out$ = "DEL"
  77.                         CASE 2: out$ = "RET"
  78.                         CASE 3: out$ = "SPC"
  79.                     END SELECT
  80.                 ELSE
  81.                     c = ASC(KB(i), j)
  82.                     IF c < 32 THEN out$ = "KB" + _TRIM$(STR$(c)) ELSE out$ = CHR$(c)
  83.                 END IF
  84.             END IF
  85.             _PRINTSTRING (left + (Xsize - _FONTWIDTH * LEN(out$)) / 2, top + (Ysize - _FONTHEIGHT) / 2), out$
  86.         NEXT
  87.     NEXT
  88.     Hardware_Keyboard_Image = _COPYIMAGE(keyboard_image, 33)
  89.     _FREEIMAGE keyboard_image
  90.  
  91.     oldmouse = -1
  92.     DO
  93.         _PUTIMAGE (Xpos, Ypos), Hardware_Keyboard_Image
  94.         WHILE _MOUSEINPUT: WEND
  95.         mb = _MOUSEBUTTON(1): mx = _MOUSEX: my = _MOUSEY
  96.  
  97.         Xon = INT((mx - Xpos) / Xsize) + 1
  98.         Yon = INT((my - Ypos) / Ysize) + l
  99.         'LOCATE 1, 1: PRINT Xon, Yon
  100.  
  101.  
  102.         IF mb AND NOT oldmouse THEN 'it's a click
  103.             IF Yon >= l AND Yon <= u THEN
  104.                 IF Xon > 0 AND Xon <= LEN(KB(Yon)) THEN
  105.                     k = ASC(KB(Yon), Xon)
  106.                     PCOPY 1, 0
  107.                     SELECT CASE k
  108.                         CASE 0 'we should only have a null value for the last row of special characters
  109.                             SELECT CASE Yon
  110.                                 CASE 0: KB_Input = 8: EXIT FUNCTION
  111.                                 CASE 1: KB_Input = 21248: EXIT FUNCTION
  112.                                 CASE 2: KB_Input = 13: EXIT FUNCTION
  113.                                 CASE 3: KB_Input = 13: EXIT FUNCTION
  114.                             END SELECT
  115.                         CASE 1 TO 31: KB = k: GOTO restart
  116.                         CASE ELSE
  117.                             KB_Input = k: EXIT FUNCTION
  118.                     END SELECT
  119.  
  120.                 END IF
  121.             END IF
  122.         END IF
  123.         _LIMIT 30
  124.         _DISPLAY
  125.         oldmouse = mb
  126.     LOOP

Much like Pete, I tend to sit down and just start coding, without really much thought  going into anything before I start working on it.  Unlike Pete, I try to make my code as modular as possible, and to only focus on one little thing at a time...

This is my first attempt at a virtual, customizable, pop-up keyboard.  At first, I was thinking that I might not need certain keys (and I won't, for all inputs, such as having a customer only enter a numeric entry for their phone number), but I still need to come up with some easy way to represent them, in case they are wanted (such as enter, space, and so on).

I want to keep the syntax simple enough that a new user could basically just sit down and write out what keys go where, like I've done above, but I need something a little more flexible and powerful as well.  For now, and for ease of testing/swapping, I'm using low ASCII codes as control characters to designate different keyboards, but I'll need to do them a little different as well...

Drawing the keyboard, making it a hardware image,  and reading it isn't really that hard to do.  Sorting out the proper data format in this case is a real head scratcher!!

Anyone with a good idea for a simple way to implement a string layout for a keyboard?

Right now, my thoughts are thinking of using CHR$(0) as a "Special character" and wrapping it around keys.  As far as I know, there's no easy/native way to insert a CHR$(0) character into the QB64 IDE (the ASCII chart doesn't insert 0 and neither does ALT-0 with the number keys, and you won't find a key on any keyboard for it), so it'd have to be manually placed and used, keeping if from being something that might accidently pop-up in a string, and if a person wants to print it, all they'd have to print is a normal CHR$(32) space...

So the next layout would tentatively look like:

KB(0) = "`1234567890-=" + CHR$(0) + "BSP" + CHR$(0)
KB(1) = CHR$(0) + "TAB" + CHR$(0) + "QWERTYUIOP[]\"

The bottom row would look like:
KB(5) = CHR$(0) + "CTR" + CHR$(0) + CHR$(0) + "WIN" + CHR$(0) + CHR$(0) + "ALT" + CHR$(0) + CHR$(0) + " " + ... (you get the point)

Which still seems relatively simple to me, and easy enough for others to learn...   Unless somebody has an idea for a better schematic?  I'm all ears, and willing to listen to all ideas and opinions.  :)
https://github.com/SteveMcNeill/Steve64 — A github collection of all things Steve!

Offline SMcNeill

  • QB64 Developer
  • Forum Resident
  • Posts: 3972
    • View Profile
    • Steve’s QB64 Archive Forum
Re: First Run at a virtual, customized keyboard routine
« Reply #1 on: February 03, 2021, 09:31:23 pm »
Maybe CHR$(0) + “(the ASCII code)”  + CHR$(0)

So Enter would be CHR$(0) + “13” + CHR$(0)... 

Then all I have to do is return that value back to the user, and have a set of labels to automagically go with them.

Edit:

Maybe a hybrid approach: Value + comma + Display

Example for enter: CHR$(0) + “13, RET” + CHR$(0)

Returns code 13, displays RET if you’re making a compact keyboard.
« Last Edit: February 03, 2021, 09:56:10 pm by SMcNeill »
https://github.com/SteveMcNeill/Steve64 — A github collection of all things Steve!

Offline SMcNeill

  • QB64 Developer
  • Forum Resident
  • Posts: 3972
    • View Profile
    • Steve’s QB64 Archive Forum
Re: First Run at a virtual, customized keyboard routine
« Reply #2 on: February 04, 2021, 05:04:28 am »
So here's what my a new, full-sized, virtual keyboard might look like under my new system:

Code: QB64: [Select]
  1. DIM My_Keyboard(5) AS STRING
  2. My_Keyboard(0) = CHR$(0) + "27,ESC" + STRING$(2,0) + "15104,F1" + STRING$(2,0) + "15360,F2" + _
  3.     STRING$(2,0) + "15616,F3" + STRING$(2,0) + "15872,F4" + STRING$(2,0) + "16128,F5" + _
  4.     STRING$(2,0) + "16384,F6" + STRING$(2,0) + "16640,F7" + STRING$(2,0) + "16896,F8" + _
  5.     STRING$(2,0) + "17152,F9" + STRING$(2,0) + "17408,F10" + STRING$(2,0) + "34048,F11" + _
  6.     STRING$(2,0) + "34304,F12" + CHR$(0)
  7. My_Keyboard(1) = "`1234567890-=" + CHR$(0) + "19200,BKSP" + CHR$(0)
  8. My_Keyboard(2) = CHR$(0) + "9,TAB" + CHR$(0) + "QWERTYUIOP[]\"
  9. My_Keyboard(3) = CHR$(0) + "100301,CAPS" + CHR$(0) + "ASDFGHJKL;'" + CHR$(0) + "13,ENTER" + CHR$(0)
  10. My_Keyboard(4) = CHR$(0) + "100304,SHIFT" + CHR$(0) + "ZXCVBNM,./" + CHR$(0) + "100303,SHIFT" + CHR$(0)
  11. My_Keyboard(5) = CHR$(0) + "100306,CTRL" + STRING$(2,0) + "0,WIN" + STRING$(2,0) + "100308,ALT" + _
  12.     STRING$(2,0) + "32,SPACE" + STRING$(2,0) + "100307,ALT" + STRING$(2,0) + "0,WIN" + STRING$(2,0) + "0,MENU" + _
  13.     STRING$(2,0) + "100305,CTRL" +  CHR$(0)
  14.  
  15. SCREEN _NEWIMAGE(800, 600, 32)
  16.  
  17. k = KB_Input(My_Keyboard(), 50, 30, 50, 100)
  18.  
  19.  
  20. FUNCTION KB_Input (KB() AS STRING, Xsize, Ysize, Xpos, Ypos)
  21.  
  22.     l = LBOUND(KB): u = UBOUND(KB)
  23.     DIM Keyboard_Values(l TO u, 0 TO 256)
  24.     FOR i = l TO u 'get longest line
  25.         IF LEN(KB(i)) > LL THEN LL = LEN(KB(i))
  26.     NEXT
  27.     LL = LL + 1
  28.     keyboard_image = _NEWIMAGE((Xsize + 2) * LL, (Ysize + 2) * (u - l + 1), 32)
  29.     'now build the keyboard
  30.     FOR i = l TO u
  31.         top = (i - l) * Ysize + Ypos
  32.         count = 0
  33.         FOR j = 1 TO LEN(KB(i))
  34.             left = (count) * Xsize + Xpos
  35.             count = count + 1
  36.             repeat = 1
  37.             c = ASC(KB(i), j): out$ = ""
  38.             IF c = 0 THEN
  39.                 'look for the comma
  40.                 comma_position = INSTR(j, KB(i), ",")
  41.                 IF comma_position THEN 'we have a value, label
  42.                     value$ = MID$(KB(i), j + 1, comma_position - j - 1)
  43.                     c = VAL(value$)
  44.                     j = comma_position + 1
  45.                 ELSE 'cry loud and hard so we can sort it out while programming our keyboard layout
  46.                     scream_and_die:
  47.                     SLEEP
  48.                     CLS
  49.                     PRINT "You have an invalid keyboard layout!"
  50.                     END
  51.                 END IF
  52.  
  53.                 end_position = INSTR(j, KB(i), CHR$(0))
  54.                 IF end_position THEN 'we're extracting the label
  55.                     out$ = MID$(KB(i), j, end_position - j)
  56.                     repeat = ASC(out$, LEN(out$))
  57.                     IF repeat > 0 AND repeat < 9 THEN
  58.                         out$ = LEFT$(out$, LEN(out$) - 1)
  59.                     ELSE
  60.                         repeat = 1
  61.                     END IF
  62.                     j = end_position
  63.                 ELSE
  64.                     GOTO scream_and_die
  65.                 END IF
  66.             END IF
  67.             LINE (left, top)-STEP(Xsize * repeat, Ysize), -1, B
  68.             DO UNTIL repeat = 1
  69.                 Keyboard_Values(i, count) = c
  70.                 count = count + 1
  71.                 repeat = repeat - 1
  72.             LOOP
  73.             Keyboard_Values(i, count) = c
  74.             IF c < 256 AND out$ = "" THEN out$ = CHR$(c)
  75.             _PRINTSTRING (left + (Xsize - _FONTWIDTH * LEN(out$)) / 2, top + (Ysize - _FONTHEIGHT) / 2), out$
  76.         NEXT
  77.     NEXT
  78.     Hardware_Keyboard_Image = _COPYIMAGE(keyboard_image, 33)
  79.     _FREEIMAGE keyboard_image
  80.  
  81.     oldmouse = -1
  82.     DO
  83.         _PUTIMAGE (Xpos, Ypos), Hardware_Keyboard_Image
  84.         WHILE _MOUSEINPUT: WEND
  85.         mb = _MOUSEBUTTON(1): mx = _MOUSEX: my = _MOUSEY
  86.  
  87.         Xon = INT((mx - Xpos) / Xsize) + 1
  88.         Yon = INT((my - Ypos) / Ysize) + l
  89.         'LOCATE 1, 1: PRINT Xon, Yon
  90.  
  91.  
  92.         _LIMIT 30
  93.         _DISPLAY
  94.         oldmouse = mb
  95.     LOOP

  [ You are not allowed to view this attachment ]  

That's actually not looking so bad, if I do say so myself!

And the whole thing builds itself from scratch, once you give it your chosen layout.  The one which made the keyboard in the screen shot is this one:

DIM My_Keyboard(5) AS STRING
My_Keyboard(0) = CHR$(0) + "27,ESC" + STRING$(2,0) + "15104,F1" + STRING$(2,0) + "15360,F2" + _
    STRING$(2,0) + "15616,F3" + STRING$(2,0) + "15872,F4" + STRING$(2,0) + "16128,F5" + _
    STRING$(2,0) + "16384,F6" + STRING$(2,0) + "16640,F7" + STRING$(2,0) + "16896,F8" + _
    STRING$(2,0) + "17152,F9" + STRING$(2,0) + "17408,F10" + STRING$(2,0) + "34048,F11" + _
    STRING$(2,0) + "34304,F12" + CHR$(0)
My_Keyboard(1) = "`1234567890-=" + CHR$(0) + "19200,BKSP" + CHR$(0)
My_Keyboard(2) = CHR$(0) + "9,TAB" + CHR$(0) + "QWERTYUIOP[]\"
My_Keyboard(3) = CHR$(0) + "100301,CAPS" + CHR$(0) + "ASDFGHJKL;'" + CHR$(0) + "13,ENTER" + CHR$(0)
My_Keyboard(4) = CHR$(0) + "100304,SHIFT" + CHR$(0) + "ZXCVBNM,./" + CHR$(0) + "100303,SHIFT" + CHR$(0)
My_Keyboard(5) = CHR$(0) + "100306,CTRL" + STRING$(2,0) + "0,WIN" + STRING$(2,0) + "100308,ALT" + _
    STRING$(2,0) + "32,SPACE" + STRING$(2,0) + "100307,ALT" + STRING$(2,0) + "0,WIN" + STRING$(2,0) + "0,MENU" + _
    STRING$(2,0) + "100305,CTRL" +  CHR$(0)


It looks a little complicated when you first take a glance at it, but it's not.  It's basically using the syntax which I was talking about above.
For normal keys, you just put them in quotes.  "QWERTYUIOP[]\"
For any special keys, you identify them with CHR$(0) + "code_value,LABEL" + CHR$(0).
So the TAB key, for instance is: CHR$(0) + "9,TAB" + CHR$(0).

So that whole row becomes CHR$(0) + "9,TAB" + CHR$(0) + "QWERTYUIOP[]\"

And with that, you can build a keyboard of any layout which you might want for your programs, and then use the mouse to interact with it.  (Or a touchscreen.)
https://github.com/SteveMcNeill/Steve64 — A github collection of all things Steve!

Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
    • View Profile
Re: First Run at a virtual, customized keyboard routine
« Reply #3 on: February 04, 2021, 12:54:21 pm »
Yes that looks better than my Keyboard!

For comparison on a HP laptop Keyboard several years out, I have a fn key and my Windows Logo key on Left of Spacebar: ctrl fn Logo alt.  On right of spacebar it's: alt  ctrl 4 arrow keys in the space of 3 buttons, the Up and Down arrows split a normal sized key space into 2, really bad for gaming.

Probably doesn't mean a hill of beans but I like to b...

Come to think, way, way, way back to VB 2, I made a graphic keyboard so when mousing inputs I didn't have move my hands off to type something like a single letter and then go back to mouse. Ergonomically that's huge savings.