1
1
Fork 0
mirror of https://github.com/QB64-Phoenix-Edition/QB64pe.git synced 2024-07-03 11:11:20 +00:00
QB64-PE/source/virtual_keyboard/virtual_keyboard_methods.bas

2812 lines
125 KiB
QBasic

DEFSNG A-Z
SUB VkResetMenu 'clears internal keys and rebuilds primary menu
VkRemoveInternal
i = VkByRole("ROOT")
c = 0
'add menu
IF VkHide <> 0 THEN
c = c + 1
i2 = VkNew
VkReLabel i2, "Show"
VK(i2).parent = i
VK(i2).offsetX = VkDefaultWidth * c
VK(i2).internal = 1
VK(i2).role = "SHOW"
VK(i2).w = VkNewKeySize
ELSE
c = c + 1
i2 = VkNew
VkReLabel i2, "Hide"
VK(i2).parent = i
VK(i2).offsetX = VkDefaultWidth * c
VK(i2).internal = 1
VK(i2).role = "HIDE"
VK(i2).w = VkNewKeySize
END IF
c = c + 1
i2 = VkNew
VkReLabel i2, "File"
VK(i2).parent = i
VK(i2).offsetX = VkDefaultWidth * c
VK(i2).internal = 1
VK(i2).role = "FILE"
VK(i2).w = VkNewKeySize
VK(i2).locks = 1
c = c + 1
i2 = VkNew
VkReLabel i2, "Edit"
VK(i2).parent = i
VK(i2).offsetX = VkDefaultWidth * c
VK(i2).internal = 1
VK(i2).role = "EDIT"
VK(i2).w = VkNewKeySize
VK(i2).locks = 1
c = c + 1
i2 = VkNew
VkReLabel i2, "Size"
VK(i2).parent = i
VK(i2).offsetX = VkDefaultWidth * c
VK(i2).internal = 1
VK(i2).role = "SIZE"
VK(i2).w = VkNewKeySize
VK(i2).locks = 1
c = c + 1
i2 = VkNew
VkReLabel i2, "Abc.."
VK(i2).parent = i
VK(i2).offsetX = VkDefaultWidth * c
VK(i2).internal = 1
VK(i2).role = "ABC."
VK(i2).w = VkNewKeySize
VK(i2).locks = 1
'POSTPONED UNTIL 2ND RELEASE
'c = c + 1
'i2 = VkNew
'VkReLabel i2, "Type"
'VK(i2).parent = i
'VK(i2).offsetX = VkDefaultWidth * c
'VK(i2).internal = 1
'VK(i2).role = "TYPE"
'VK(i2).w = VkNewKeySize
'VK(i2).locks = 1
'DEPRECATED (MOUSE PIPES REMOVED THE REQUIREMENT FOR INPUT MODE SELECTION)
'c = c + 1
'i2 = VkNew
'VkReLabel i2, "Input Mode"
'VK(i2).parent = i
'VK(i2).offsetX = VkDefaultWidth * c
'VK(i2).internal = 1
'VK(i2).role = "IMOD"
'VK(i2).w = VkNewKeySize
'VK(i2).locks = 1
END SUB
SUB VkSelectKey (page)
VkDefaultSelectKeyPage = page
VkRemoveInternal
rt = VkByRole("ROOT")
i2 = VkNew
VK(i2).offsetX = 0
VK(i2).offsetY = -1 * VkUnitStepY
VK(i2).parent = rt
VkReLabel i2, CHR$(26)
VK(i2).internal = 1
VK(i2).role = "NSET"
p = page + 1
VK(i2).state = p
i2 = VkNew
VK(i2).offsetX = 0
VK(i2).offsetY = -2 * VkUnitStepY
VK(i2).parent = rt
VkReLabel i2, CHR$(27)
VK(i2).internal = 1
VK(i2).role = "PSET"
p = page - 1
IF p < 1 THEN p = 1
VK(i2).state = p
'a = -1000
DIM range(100, 1 TO 2) AS LONG
r = 0
'key groups (first because they are more useful than individual keys)
r = r + 1: range(r, 1) = -1001: range(r, 2) = range(r, 1) 'Set: Full KB
r = r + 1: range(r, 1) = -1000: range(r, 2) = range(r, 1) 'Set: F1-F12
r = r + 1: range(r, 1) = -1002: range(r, 2) = range(r, 1) 'Set: Game Controller
r = r + 1: range(r, 1) = -1003: range(r, 2) = range(r, 1) 'Set: Arrow Pad
r = r + 1: range(r, 1) = -1004: range(r, 2) = range(r, 1) 'Set: WASD Pad
r = r + 1: range(r, 1) = -1005: range(r, 2) = range(r, 1) 'Set: Ins-Home-PageUp Del-End-PageDown
r = r + 1: range(r, 1) = -1006: range(r, 2) = range(r, 1) 'Set: Num Pad
'D-Pad
r = r + 1: range(r, 1) = 1000: range(r, 2) = 1004 'D-Pad
'"safe"/essential ASCII (reordered for convenience)
r = r + 1: range(r, 1) = 97: range(r, 2) = 122 'a-z
r = r + 1: range(r, 1) = 48: range(r, 2) = 57 '0-9
r = r + 1: range(r, 1) = 65: range(r, 2) = 90 'A-Z
r = r + 1: range(r, 1) = 32: range(r, 2) = 32 'SPACE
r = r + 1: range(r, 1) = 13: range(r, 2) = 13 'ENTER
r = r + 1: range(r, 1) = 8: range(r, 2) = 8 'BACKSPACE
r = r + 1: range(r, 1) = 9: range(r, 2) = 9 'TAB
r = r + 1: range(r, 1) = 33: range(r, 2) = 47 '" "-"/"
r = r + 1: range(r, 1) = 58: range(r, 2) = 64 '":"-"@"
r = r + 1: range(r, 1) = 91: range(r, 2) = 96 '"["-"`"
r = r + 1: range(r, 1) = 123: range(r, 2) = 126 '"{"-"~"
r = r + 1: range(r, 1) = 27: range(r, 2) = 27 'ESCAPE
r = r + 1: range(r, 1) = 1005: range(r, 2) = 1035 '(see below)
'arrow keys
'INSERT, etc
'F1-F12
'standard modifier keys (SHIFT, ALT, etc)
'other special keys (Windows key, ...)
'extended ASCII
r = r + 1: range(r, 1) = 127: range(r, 2) = 255
'"unsafe" ASCII (placed after all content to avoid confusion with arrows)
r = r + 1: range(r, 1) = 1: range(r, 2) = 7
r = r + 1: range(r, 1) = 10: range(r, 2) = 12
r = r + 1: range(r, 1) = 14: range(r, 2) = 26
'r = r + 1: range(r, 1) = 28: range(r, 2) = 31-4
ranges = r
a = range(1, 1)
FOR cpage = 1 TO page
FOR y = 0 TO -3 STEP -1
FOR x = 1 TO 7
IF cpage = page THEN
i2 = VkNew
VK(i2).offsetX = x * VkDefaultWidth + 1
VK(i2).offsetY = y * VkUnitStepY
VK(i2).parent = rt
END IF
IF a <= 255 AND a >= 0 THEN
IF cpage = page THEN
VkReLabel i2, CHR$(a)
IF a = 32 THEN VkReLabel i2, "Space"
IF a = 13 THEN VkReLabel i2, "Enter"
IF a = 8 THEN VkReLabel i2, "Back Space"
IF a = 9 THEN VkReLabel i2, "Tab"
IF a = 0 THEN VkReLabel i2, "Null"
IF a = 7 THEN VkReLabel i2, "Bell"
IF a = 10 THEN VkReLabel i2, "Line Feed"
IF a = 11 THEN VkReLabel i2, "Vert Tab"
IF a = 12 THEN VkReLabel i2, "Form Feed"
IF a = 27 THEN VkReLabel i2, "Esc"
IF a = 255 THEN VkReLabel i2, "Nbsp"
VK(i2).event.keydown = a
END IF
ELSE
label$ = "?"
code = 63
lockIsTemporary = 0
locks = 0
'key sets
IF a = -1000 THEN label$ = "F1-F12": code = a
IF a = -1001 THEN label$ = "Full KB": code = a
IF a = -1002 THEN label$ = "Game Controller": code = a
IF a = -1003 THEN label$ = "Arrow Pad": code = a
IF a = -1004 THEN label$ = "WASD Pad": code = a
IF a = -1005 THEN label$ = "Ins-Home-PageUp Del-End-PageDown": code = a
IF a = -1006 THEN label$ = "Num Pad": code = a
n = 1000 - 1
n = n + 1: IF a = n THEN label$ = "Virtual Joystick": code = -1
'n = n + 1: IF a = n THEN label$ = CHR$(24) + "[UP-ARROW]": code = VK_KEY_UP
'n = n + 1: IF a = n THEN label$ = CHR$(25) + "[DOWN-ARROW]": code = VK_KEY_DOWN
'n = n + 1: IF a = n THEN label$ = CHR$(27) + "[LEFT-ARROW]": code = VK_KEY_LEFT
'n = n + 1: IF a = n THEN label$ = CHR$(26) + "[RIGHT-ARROW]": code = VK_KEY_RIGHT
n = n + 1: IF a = n THEN label$ = CHR$(24): code = VK_KEY_UP
n = n + 1: IF a = n THEN label$ = CHR$(25): code = VK_KEY_DOWN
n = n + 1: IF a = n THEN label$ = CHR$(27): code = VK_KEY_LEFT
n = n + 1: IF a = n THEN label$ = CHR$(26): code = VK_KEY_RIGHT
n = n + 1: IF a = n THEN label$ = "Ins": code = VK_KEY_INSERT
n = n + 1: IF a = n THEN label$ = "Del": code = VK_KEY_DELETE
n = n + 1: IF a = n THEN label$ = "Home": code = VK_KEY_HOME
n = n + 1: IF a = n THEN label$ = "End": code = VK_KEY_END
n = n + 1: IF a = n THEN label$ = "Page Up": code = VK_KEY_PAGE_UP
n = n + 1: IF a = n THEN label$ = "Page Down": code = VK_KEY_PAGE_DOWN
n = n + 1: IF a = n THEN label$ = "F1": code = VK_KEY_F1
n = n + 1: IF a = n THEN label$ = "F2": code = VK_KEY_F2
n = n + 1: IF a = n THEN label$ = "F3": code = VK_KEY_F3
n = n + 1: IF a = n THEN label$ = "F4": code = VK_KEY_F4
n = n + 1: IF a = n THEN label$ = "F5": code = VK_KEY_F5
n = n + 1: IF a = n THEN label$ = "F6": code = VK_KEY_F6
n = n + 1: IF a = n THEN label$ = "F7": code = VK_KEY_F7
n = n + 1: IF a = n THEN label$ = "F8": code = VK_KEY_F8
n = n + 1: IF a = n THEN label$ = "F9": code = VK_KEY_F9
n = n + 1: IF a = n THEN label$ = "F10": code = VK_KEY_F10
n = n + 1: IF a = n THEN label$ = "F11": code = VK_KEY_F11
n = n + 1: IF a = n THEN label$ = "F12": code = VK_KEY_F12
n = n + 1
IF a = n THEN
label$ = "Shift (Left)"
code = VK_KEY_LSHIFT
locks = 1: lockIsTemporary = 1
END IF
n = n + 1
IF a = n THEN
label$ = "Shift (Right)"
code = VK_KEY_RSHIFT
locks = 1: lockIsTemporary = 1
END IF
n = n + 1
IF a = n THEN
label$ = "Ctrl (Left)"
code = VK_KEY_LCTRL
locks = 1: lockIsTemporary = 1
END IF
n = n + 1
IF a = n THEN
label$ = "Ctrl (Right)"
code = VK_KEY_RCTRL
locks = 1: lockIsTemporary = 1
END IF
n = n + 1
IF a = n THEN
label$ = "Alt (Left)"
code = VK_KEY_LALT
locks = 1: lockIsTemporary = 1
END IF
n = n + 1
IF a = n THEN
label$ = "Alt (Right)"
code = VK_KEY_RALT
locks = 1: lockIsTemporary = 1
END IF
n = n + 1
IF a = n THEN
label$ = "Caps Lock"
code = VK_KEY_CAPSLOCK
locks = 1
END IF
n = n + 1
IF a = n THEN
label$ = "Num Lock"
code = VK_KEY_NUMLOCK
locks = 1
END IF
n = n + 1
IF a = n THEN
label$ = "Scr Lock"
code = VK_KEY_SCROLLOCK
locks = 1
END IF
n = n + 1: IF a = n THEN label$ = "Win (Left)": code = VK_KEY_LSUPER
n = n + 1: IF a = n THEN label$ = "Win (Right)": code = VK_KEY_RSUPER
n = n + 1: IF a = n THEN label$ = "Apple (Left)": code = VK_KEY_LMETA
n = n + 1: IF a = n THEN label$ = "Apple (Right)": code = VK_KEY_RMETA
'SCREEN 2
'PRINT n-1
'CONST KEY_KP0& = 100256
'CONST KEY_KP1& = 100257
'CONST KEY_KP2& = 100258
'CONST KEY_KP3& = 100259
'CONST KEY_KP4& = 100260
'CONST KEY_KP5& = 100261
'CONST KEY_KP6& = 100262
'CONST KEY_KP7& = 100263
'CONST KEY_KP8& = 100264
'CONST KEY_KP9& = 100265
'CONST KEY_KP_PERIOD& = 100266
'CONST KEY_KP_DIVIDE& = 100267
'CONST KEY_KP_MULTIPLY& = 100268
'CONST KEY_KP_MINUS& = 100269
'CONST KEY_KP_PLUS& = 100270
'CONST KEY_KP_ENTER& = 100271
'CONST KEY_KP_INSERT& = 200000
'CONST KEY_KP_END& = 200001
'CONST KEY_KP_DOWN& = 200002
'CONST KEY_KP_PAGE_DOWN& = 200003
'CONST KEY_KP_LEFT& = 200004
'CONST KEY_KP_MIDDLE& = 200005
'CONST KEY_KP_RIGHT& = 200006
'CONST KEY_KP_HOME& = 200007
'CONST KEY_KP_UP& = 200008
'CONST KEY_KP_PAGE_UP& = 200009
'CONST KEY_KP_DELETE& = 200010
size = LEN(label$)
text$ = label$
IF INSTR(text$, " ") THEN
text2$ = RIGHT$(text$, LEN(text$) - INSTR(text$, " "))
text$ = LEFT$(text$, INSTR(text$, " ") - 1)
IF LEN(text2$) > LEN(text$) THEN size = LEN(text2$) ELSE size = LEN(text$)
END IF
IF size > 5 THEN
x = x + (size - 5) \ 5 + 1
IF cpage = page THEN VK(i2).w = VkDefaultWidth + ((size - 5) \ 5 + 1) * VkDefaultWidth
END IF
IF cpage = page THEN
VkReLabel i2, label$
VK(i2).event.keydown = code
VK(i2).lockIsTemporary = lockIsTemporary
VK(i2).locks = locks
END IF
END IF
IF cpage = page THEN
VK(i2).internal = 1
VK(i2).role = "VALU"
END IF
'END IF
a = a + 1
FOR r = 0 TO ranges
IF range(r, 2) + 1 = a THEN
IF r = ranges THEN noMore = 1 ELSE a = range(r + 1, 1)
EXIT FOR
END IF
NEXT
IF noMore THEN EXIT SUB
NEXT
NEXT
NEXT
END SUB
SUB VkPress (i)
role$ = VK(i).role
IF role$ = "ROOT" THEN
VkAddShiftedKey = 0
IF VK(i).locked = 0 THEN
VK(i).held = 1
VK(i).locked = 1
VkResetMenu
ELSE
'remove all internal keys
VkRemoveInternal
VK(i).locked = 0
END IF
EXIT SUB
END IF
IF role$ = "AA.." THEN
IF VkSelectedKey <> 0 THEN
IF VK(VkSelectedKey).event.keydown >= 0 THEN
VkAddShiftedKey = 0
VkSelectKey VkDefaultSelectKeyPage
END IF
END IF
EXIT SUB
END IF
IF role$ = "^AA." THEN
IF VkSelectedKey <> 0 THEN
IF VK(VkSelectedKey).event.keydown >= 0 THEN
VkAddShiftedKey = 1
VkSelectKey VkDefaultSelectKeyPage
END IF
END IF
EXIT SUB
END IF
IF role$ = "ADDK" THEN
VkSelectedKey = 0
VkAddShiftedKey = 0
VkSelectKey VkDefaultSelectKeyPage
EXIT SUB
END IF
IF role$ = "DELK" THEN
i2 = VkSelectedKey
IF i2 <> 0 THEN
'if this is a parent handle, all children need to be detached first
IF VK(i2).event.keydown = -2 THEN 'keyset handle
FOR i3 = 1 TO VkLast
IF VK(i3).active THEN
IF VK(i3).parent = i2 THEN
VK(i3).parent = 0
VK(i3).offsetX = 0
VK(i3).offsetY = 0
END IF
END IF
NEXT
END IF
VkRemove i2
VkSelectedKey = 0
VkResetMenu
END IF
EXIT SUB
END IF
IF role$ = "DSET" THEN
i2 = VkSelectedKey
hasChildren = 0
IF i2 <> 0 THEN
'if this is a parent handle, all children need to be deleted first
IF VK(i2).event.keydown = -2 THEN 'keyset handle
FOR i3 = 1 TO VkLast
IF VK(i3).active THEN
IF VK(i3).parent = i2 THEN
VkRemove i3
hasChildren = 1
END IF
END IF
NEXT
END IF
IF hasChildren THEN
VkRemove i2
VkSelectedKey = 0
VkResetMenu
END IF
END IF
EXIT SUB
END IF
IF role$ = "DALL" THEN
FOR i3 = 1 TO VkLast
IF VK(i3).active THEN
IF VK(i3).internal = 0 THEN
VkRemove i3
END IF
END IF
NEXT
VkSelectedKey = 0
VkResetMenu
EXIT SUB
END IF
IF role$ = "EDIT" THEN
IF VK(i).locked = 1 THEN
VkResetMenu
ELSE
VkHide = 0 'do not hide keybaord when editing
VkResetMenu
i = VkByRole(role$)
VK(i).locked = 1
ox = VK(i).offsetX
oy = 0
oy = oy + 1
i2 = VkNew
VkReLabel i2, "Add Keys"
VK(i2).parent = VK(i).parent
VK(i2).offsetX = ox
VK(i2).offsetY = -oy * VkUnitStepY
VK(i2).internal = 1
VK(i2).role = "ADDK"
VK(i2).w = VkNewKeySize
oy = oy + 1
i2 = VkNew
VkReLabel i2, "Del Key"
VK(i2).parent = VK(i).parent
VK(i2).offsetX = ox
VK(i2).offsetY = -oy * VkUnitStepY
VK(i2).internal = 1
VK(i2).role = "DELK"
VK(i2).w = VkNewKeySize
oy = oy + 1
i2 = VkNew
VkReLabel i2, "Del Set"
VK(i2).parent = VK(i).parent
VK(i2).offsetX = ox
VK(i2).offsetY = -oy * VkUnitStepY
VK(i2).internal = 1
VK(i2).role = "DSET"
VK(i2).w = VkNewKeySize
oy = oy + 1
i2 = VkNew
VkReLabel i2, "Del All"
VK(i2).parent = VK(i).parent
VK(i2).offsetX = ox
VK(i2).offsetY = -oy * VkUnitStepY
VK(i2).internal = 1
VK(i2).role = "DALL"
VK(i2).w = VkNewKeySize
END IF
VkReDraw = 1
EXIT SUB
END IF 'edit
IF role$ = "HIDE" THEN
VkHide = -1
VkResetMenu
VkPress VkByRole("ROOT")
EXIT SUB
END IF
IF role$ = "SHOW" THEN
VkHide = 0
VkResetMenu
VkPress VkByRole("ROOT")
EXIT SUB
END IF
IF role$ = "SAVE" THEN
VkSave
VkResetMenu
END IF
IF role$ = "FILE" THEN
IF VK(i).locked = 1 THEN
VkResetMenu
ELSE
VkHide = 0 'do not hide keybaord when editing
VkResetMenu
i = VkByRole(role$)
VK(i).locked = 1
ox = VK(i).offsetX
oy = 0
oy = oy + 1
i2 = VkNew
VkReLabel i2, "Save"
VK(i2).parent = VK(i).parent
VK(i2).offsetX = ox
VK(i2).offsetY = -oy * VkUnitStepY
VK(i2).internal = 1
VK(i2).role = "SAVE"
VK(i2).w = VkNewKeySize
oy = oy + 1
i2 = VkNew
VkReLabel i2, "Reset"
VK(i2).parent = VK(i).parent
VK(i2).offsetX = ox
VK(i2).offsetY = -oy * VkUnitStepY
VK(i2).internal = 1
VK(i2).role = "RSET"
VK(i2).w = VkNewKeySize
oy = oy + 1
i2 = VkNew
VkReLabel i2, "Exit"
VK(i2).parent = VK(i).parent
VK(i2).offsetX = ox
VK(i2).offsetY = -oy * VkUnitStepY
VK(i2).internal = 1
VK(i2).role = "EXIT"
VK(i2).w = VkNewKeySize
END IF
VkReDraw = 1
EXIT SUB
END IF 'FILE
IF role$ = "EXIT" THEN
'remove ALL keys, even root keys
FOR i3 = 1 TO VkLast
IF VK(i3).active THEN
VkRemove i3
END IF
NEXT
VkSelectedKey = 0
VkExiting=1
EXIT SUB
END IF
IF role$ = "RSET" THEN
'remove all keys
FOR i3 = 1 TO VkLast
IF VK(i3).active THEN
IF VK(i3).internal = 0 THEN
VkRemove i3
END IF
END IF
NEXT
VkSelectedKey = 0
'load default layout (if one exists)
VkFile$=""
if _FILEEXISTS(appRootPath$+"virtual_keyboard_layout_default.txt") then VkFile$=appRootPath$+"virtual_keyboard_layout_default.txt"
if VkFile$<>"" then
fh = FREEFILE
OPEN VkFile$ FOR INPUT AS #fh
LINE INPUT #fh, json$
CLOSE #fh
root = QB_NODESET_deserialize(json$, "json")
DIM oldVkWidthInUnits AS LONG
oldVkWidthInUnits=VkWidthInUnits
VkWidthInUnits=90
DIM rootValueNode AS LONG
rootValueNode=QB_NODE_withLabel(root, "width")
if rootValueNode then VkWidthInUnits=QB_NODE_valueOfLabel_long(root, "width")
if VkWidthInUnits<>oldVkWidthInUnits then
FOR i3 = 1 TO VkLast
IF VK(i3).active THEN
VK(i3).reDraw = 1
END IF
NEXT
VkReset = 1
END IF
VkLoadKeys QB_NODESET_node(QB_NODESET_label_equal(QB_NODESET_children(root), "keys")), 0
QB_NODE_destroy root
end if
VkResetMenu
EXIT SUB
END IF
IF role$ = "SCUP" THEN
VkWidthInUnits=VkWidthInUnits-6
if VkWidthInUnits<90-6*7 then VkWidthInUnits=90-6*7
'force all keys to be redrawn
FOR i3 = 1 TO VkLast
IF VK(i3).active THEN
VK(i3).reDraw = 1
END IF
NEXT
VkReset = 1
EXIT SUB
END IF
IF role$ = "SCDN" THEN
VkWidthInUnits=VkWidthInUnits+6
if VkWidthInUnits>90+6*20 then VkWidthInUnits=90+6*20
'force all keys to be redrawn
FOR i3 = 1 TO VkLast
IF VK(i3).active THEN
VK(i3).reDraw = 1
END IF
NEXT
VkReset = 1
EXIT SUB
END IF
IF role$ = "BIGR" THEN
i2 = VkSelectedKey
IF i2 <> 0 THEN
IF VK(i2).event.keydown >= 0 THEN
VK(i2).w = VK(i2).w + 1
VK(i2).reDraw = 1
END IF
END IF
EXIT SUB
END IF
IF role$ = "SMLR" THEN
i2 = VkSelectedKey
IF i2 <> 0 THEN
IF VK(i2).event.keydown >= 0 THEN
VK(i2).w = VK(i2).w - 1
IF VK(i2).w < 2 THEN VK(i2).w = 2
VK(i2).reDraw = 1
END IF
END IF
EXIT SUB
END IF
IF role$ = "SIZE" THEN
IF VK(i).locked = 1 THEN
VkResetMenu
ELSE
VkHide = 0 'do not hide keybaord when editing
VkResetMenu
i = VkByRole(role$)
VK(i).locked = 1
ox = VK(i).offsetX
oy = 0
oy = oy + 1
i2 = VkNew
VkReLabel i2, chr$(17) + chr$(196) + chr$(196) + chr$(16)
VK(i2).parent = VK(i).parent
VK(i2).offsetX = ox
VK(i2).offsetY = -oy * VkUnitStepY
VK(i2).internal = 1
VK(i2).role = "BIGR"
VK(i2).w = VkNewKeySize
oy = oy + 1
i2 = VkNew
VkReLabel i2, chr$(196) + chr$(16) + chr$(17) + chr$(196)
VK(i2).parent = VK(i).parent
VK(i2).offsetX = ox
VK(i2).offsetY = -oy * VkUnitStepY
VK(i2).internal = 1
VK(i2).role = "SMLR"
VK(i2).w = VkNewKeySize
oy = oy + 1
i2 = VkNew
VkReLabel i2, "Scale Up"
VK(i2).parent = VK(i).parent
VK(i2).offsetX = ox
VK(i2).offsetY = -oy * VkUnitStepY
VK(i2).internal = 1
VK(i2).role = "SCUP"
VK(i2).w = VkNewKeySize
oy = oy + 1
i2 = VkNew
VkReLabel i2, "Scale Down"
VK(i2).parent = VK(i).parent
VK(i2).offsetX = ox
VK(i2).offsetY = -oy * VkUnitStepY
VK(i2).internal = 1
VK(i2).role = "SCDN"
VK(i2).w = VkNewKeySize
END IF
VkReDraw = 1
EXIT SUB
END IF 'SIZE
IF role$ = "ABC." THEN
IF VK(i).locked = 1 THEN
VkResetMenu
ELSE
VkHide = 0 'do not hide keybaord when editing
VkResetMenu
i = VkByRole(role$)
VK(i).locked = 1
ox = VK(i).offsetX
oy = 0
oy = oy + 1
i2 = VkNew
VkReLabel i2, "Aa..."
VK(i2).parent = VK(i).parent
VK(i2).offsetX = ox
VK(i2).offsetY = -oy * VkUnitStepY
VK(i2).internal = 1
VK(i2).role = "AA.."
VK(i2).w = VkNewKeySize
oy = oy + 1
i2 = VkNew
VkReLabel i2, "Aa... ^^"
VK(i2).parent = VK(i).parent
VK(i2).offsetX = ox
VK(i2).offsetY = -oy * VkUnitStepY
VK(i2).internal = 1
VK(i2).role = "^AA."
VK(i2).w = VkNewKeySize
END IF
VkReDraw = 1
EXIT SUB
END IF 'ABC.
IF role$ = "TYPE" THEN
IF VK(i).locked = 1 THEN
VkResetMenu
ELSE
VkHide = 0 'do not hide keybaord when editing
VkResetMenu
i = VkByRole(role$)
VK(i).locked = 1
ox = VK(i).offsetX
oy = 0
oy = oy + 1
i2 = VkNew
VkReLabel i2, "Locks"
VK(i2).parent = VK(i).parent
VK(i2).offsetX = ox
VK(i2).offsetY = -oy * VkUnitStepY
VK(i2).internal = 1
VK(i2).role = "LOCK"
VK(i2).w = VkNewKeySize
oy = oy + 1
i2 = VkNew
VkReLabel i2, "Waits Press"
VK(i2).parent = VK(i).parent
VK(i2).offsetX = ox
VK(i2).offsetY = -oy * VkUnitStepY
VK(i2).internal = 1
VK(i2).role = "STKY"
VK(i2).w = VkNewKeySize
END IF
VkReDraw = 1
EXIT SUB
END IF 'TYPE
'IF role$ = "IMOD" THEN
' IF VK(i).locked = 1 THEN
' VkResetMenu
' ELSE
' VkResetMenu
' i = VkByRole(role$)
' VK(i).locked = 1
' ox = VK(i).offsetX
' oy = 0
'
' oy = oy + 1
' i2 = VkNew
' VkReLabel i2, "Share Input"
' VK(i2).parent = VK(i).parent
' VK(i2).offsetX = ox
' VK(i2).offsetY = -oy * VkUnitStepY
' VK(i2).internal = 1
' VK(i2).locks = 1
' IF VkSharedInputMode <> 0 THEN VK(i2).locked = 1
' VK(i2).role = "IMSH"
' VK(i2).w = VkNewKeySize
'
' oy = oy + 1
' i2 = VkNew
' VkReLabel i2, "Excl- usive"
' VK(i2).parent = VK(i).parent
' VK(i2).offsetX = ox
' VK(i2).offsetY = -oy * VkUnitStepY
' VK(i2).internal = 1
' VK(i2).locks = 1
' IF VkSharedInputMode = 0 THEN VK(i2).locked = 1
' VK(i2).role = "IMEX"
' VK(i2).w = VkNewKeySize
'
' END IF
' VkReDraw = 1
' EXIT SUB
'END IF 'TYPE
'IF role$ = "IMSH" THEN
' i3 = VkByRole("IMSH")
' VK(i3).locked = 1
' i3 = VkByRole("IMEX")
' VK(i3).locked = 0
' VkSharedInputMode = -1
' VkReDraw = 1
' DO WHILE func__mouseinput_exclusive: LOOP
' DO WHILE _MOUSEINPUT: LOOP
' mouseinput_mode 0
' EXIT SUB
'END IF
'IF role$ = "IMEX" THEN
' i3 = VkByRole("IMSH")
' VK(i3).locked = 0
' i3 = VkByRole("IMEX")
' VK(i3).locked = 1
' VkSharedInputMode = 0
' VkReDraw = 1
' DO WHILE func__mouseinput_exclusive: LOOP
' DO WHILE _MOUSEINPUT: LOOP
' mouseinput_mode 1
' EXIT SUB
'END IF
IF VK(i).role = "NSET" OR VK(i).role = "PSET" THEN
page = VK(i).state
VkSelectKey page
EXIT SUB
END IF
IF VK(i).role = "USER" THEN
rt = VkByRole("ROOT")
IF VK(rt).locked <> 0 THEN
'select key
VkSelectedKey = i
VkReDraw = 1
EXIT SUB
END IF
EXIT SUB
END IF
IF VK(i).role = "VALU" THEN
i3 = VkByRole("ROOT")
IF VK(i).event.keydown <= -1000 THEN 'Full KB
'add parent (handle) key
i2 = VkNew
VK(i2).x = VK(i3).x + VkDefaultWidth * 0 + 1
VK(i2).y = VK(i3).y - VkDefaultWidth * 1
VkReLabel i2, CHR$(240)
VK(i2).role = "USER"
VK(i2).h = CINT(VkUnitStepY / 2)
VK(i2).event.keydown = -2 'a "keySet"
END IF
IF VK(i).event.keydown = -1004 THEN 'WASD Pad
json$ = "{\qkeys\q:[{\qtype\q:\qkey\q,\qoffsetX\q:0,\qoffsetY\q:0,\qwidth\q:6,\qheight\q:6,\qlabel\q:\qa\q,\qlocks\q:false,\qlockIsTemporary\q:false,\qevents\q:{\qkeydown\q:{\qkeyCode\q:\qKEY_LCASE_A\q}}},{\qtype\q:\qkey\q,\qoffsetX\q:12,\qoffsetY\q:0,\qwidth\q:6,\qheight\q:6,\qlabel\q:\qd\q,\qlocks\q:false,\qlockIsTemporary\q:false,\qevents\q:{\qkeydown\q:{\qkeyCode\q:\qKEY_LCASE_D\q}}},{\qtype\q:\qkey\q,\qoffsetX\q:6,\qoffsetY\q:6,\qwidth\q:6,\qheight\q:6,\qlabel\q:\qw\q,\qlocks\q:false,\qlockIsTemporary\q:false,\qevents\q:{\qkeydown\q:{\qkeyCode\q:\qKEY_LCASE_W\q}}},{\qtype\q:\qkey\q,\qoffsetX\q:6,\qoffsetY\q:0,\qwidth\q:6,\qheight\q:6,\qlabel\q:\qs\q,\qlocks\q:false,\qlockIsTemporary\q:false,\qevents\q:{\qkeydown\q:{\qkeyCode\q:\qKEY_LCASE_S\q}}}]}"
keyset = QB_NODESET_deserialize(VkGetQuotedString(json$), "json")
VkLoadKeys QB_NODESET_node(QB_NODESET_label_equal(QB_NODESET_children(keyset), "keys")), i2
FOR i3 = 1 TO VkLast
IF VK(i2).active THEN
IF VK(i3).parent = i2 THEN
VK(i3).offsetY = VK(i3).offsetY - VkDefaultWidth * 1
END IF
END IF
NEXT
VkPress (VkByRole("ROOT"))
VkPress (VkByRole("ROOT"))
VkSelectedKey = i2
EXIT SUB
END IF
IF VK(i).event.keydown = -1003 THEN 'Arrow Pad
json$ = "{\qkeys\q:[{\qtype\q:\qkey\q,\qoffsetX\q:12,\qoffsetY\q:0,\qwidth\q:6,\qheight\q:6,\qlabel\q:\q\u2192\q,\qlocks\q:false,\qlockIsTemporary\q:false,\qevents\q:{\qkeydown\q:{\qkeyCode\q:\qKEY_RIGHT\q}}},{\qtype\q:\qkey\q,\qoffsetX\q:0,\qoffsetY\q:0,\qwidth\q:6,\qheight\q:6,\qlabel\q:\q\u2190\q,\qlocks\q:false,\qlockIsTemporary\q:false,\qevents\q:{\qkeydown\q:{\qkeyCode\q:\qKEY_LEFT\q}}},{\qtype\q:\qkey\q,\qoffsetX\q:6,\qoffsetY\q:0,\qwidth\q:6,\qheight\q:6,\qlabel\q:\q\u2193\q,\qlocks\q:false,\qlockIsTemporary\q:false,\qevents\q:{\qkeydown\q:{\qkeyCode\q:\qKEY_DOWN\q}}},{\qtype\q:\qkey\q,\qoffsetX\q:6,\qoffsetY\q:6,\qwidth\q:6,\qheight\q:6,\qlabel\q:\q\u2191\q,\qlocks\q:false,\qlockIsTemporary\q:false,\qevents\q:{\qkeydown\q:{\qkeyCode\q:\qKEY_UP\q}}}]}"
keyset = QB_NODESET_deserialize(VkGetQuotedString(json$), "json")
VkLoadKeys QB_NODESET_node(QB_NODESET_label_equal(QB_NODESET_children(keyset), "keys")), i2
FOR i3 = 1 TO VkLast
IF VK(i2).active THEN
IF VK(i3).parent = i2 THEN
VK(i3).offsetY = VK(i3).offsetY - VkDefaultWidth * 1
END IF
END IF
NEXT
VkPress (VkByRole("ROOT"))
VkPress (VkByRole("ROOT"))
VkSelectedKey = i2
EXIT SUB
END IF
'Ins-Home-PageUp Del-End-PageDown
IF VK(i).event.keydown = -1005 THEN 'Ins-Home-PageUp Del-End-PageDown
json$ = "{\qkeys\q:[{\qtype\q:\qkey\q,\qoffsetX\q:12,\qoffsetY\q:0,\qwidth\q:6,\qheight\q:6,\qlabel\q:\qPage Down\q,\qlocks\q:false,\qlockIsTemporary\q:false,\qevents\q:{\qkeydown\q:{\qkeyCode\q:\qKEY_PAGE_DOWN\q}}},{\qtype\q:\qkey\q,\qoffsetX\q:12,\qoffsetY\q:6,\qwidth\q:6,\qheight\q:6,\qlabel\q:\qPage Up\q,\qlocks\q:false,\qlockIsTemporary\q:false,\qevents\q:{\qkeydown\q:{\qkeyCode\q:\qKEY_PAGE_UP\q}}},{\qtype\q:\qkey\q,\qoffsetX\q:6,\qoffsetY\q:0,\qwidth\q:6,\qheight\q:6,\qlabel\q:\qEnd\q,\qlocks\q:false,\qlockIsTemporary\q:false,\qevents\q:{\qkeydown\q:{\qkeyCode\q:\qKEY_END\q}}},{\qtype\q:\qkey\q,\qoffsetX\q:6,\qoffsetY\q:6,\qwidth\q:6,\qheight\q:6,\qlabel\q:\qHome\q,\qlocks\q:false,\qlockIsTemporary\q:false,\qevents\q:{\qkeydown\q:{\qkeyCode\q:\qKEY_HOME\q}}},{\qtype\q:\qkey\q,\qoffsetX\q:0,\qoffsetY\q:0,\qwidth\q:6,\qheight\q:6,\qlabel\q:\qDel\q,\qlocks\q:false,\qlockIsTemporary\q:false,\qevents\q:{\qkeydown\q:{\qkeyCode\q:\qKEY_DELETE\q}}},{\qtype\q:\qkey\q,\qoffsetX\q:0,\qoffsetY\q:6,\qwidth\q:6,\qheight\q:6,\qlabel\q:\qIns\q,\qlocks\q:false,\qlockIsTemporary\q:false,\qevents\q:{\qkeydown\q:{\qkeyCode\q:\qKEY_INSERT\q}}}]}"
keyset = QB_NODESET_deserialize(VkGetQuotedString(json$), "json")
VkLoadKeys QB_NODESET_node(QB_NODESET_label_equal(QB_NODESET_children(keyset), "keys")), i2
FOR i3 = 1 TO VkLast
IF VK(i2).active THEN
IF VK(i3).parent = i2 THEN
VK(i3).offsetY = VK(i3).offsetY - VkDefaultWidth * 2
END IF
END IF
NEXT
VkPress (VkByRole("ROOT"))
VkPress (VkByRole("ROOT"))
VkSelectedKey = i2
EXIT SUB
END IF
IF VK(i).event.keydown = -1006 THEN 'Num Pad
json$ = "{\qkeys\q:[{\qtype\q:\qkey\q,\qoffsetX\q:6,\qoffsetY\q:12,\qwidth\q:6,\qheight\q:6,\qlabel\q:\q5\q,\qlocks\q:false,\qlockIsTemporary\q:false,\qevents\q:{\qkeydown\q:{\qkeyCode\q:\qKEY_5\q}}},{\qtype\q:\qkey\q,\qoffsetX\q:0,\qoffsetY\q:12,\qwidth\q:6,\qheight\q:6,\qlabel\q:\q4\q,\qlocks\q:false,\qlockIsTemporary\q:false,\qevents\q:{\qkeydown\q:{\qkeyCode\q:\qKEY_4\q}}},{\qtype\q:\qkey\q,\qoffsetX\q:12,\qoffsetY\q:6,\qwidth\q:6,\qheight\q:6,\qlabel\q:\q3\q,\qlocks\q:false,\qlockIsTemporary\q:false,\qevents\q:{\qkeydown\q:{\qkeyCode\q:\qKEY_3\q}}},{\qtype\q:\qkey\q,\qoffsetX\q:6,\qoffsetY\q:6,\qwidth\q:6,\qheight\q:6,\qlabel\q:\q2\q,\qlocks\q:false,\qlockIsTemporary\q:false,\qevents\q:{\qkeydown\q:{\qkeyCode\q:\qKEY_2\q}}},{\qtype\q:\qkey\q,\qoffsetX\q:0,\qoffsetY\q:6,\qwidth\q:6,\qheight\q:6,\qlabel\q:\q1\q,\qlocks\q:false,\qlockIsTemporary\q:false,\qevents\q:{\qkeydown\q:{\qkeyCode\q:\qKEY_1\q}}},{\qtype\q:\qkey\q,\qoffsetX\q:0,\qoffsetY\q:0,\qwidth\q:12,\qheight\q:6,\qlabel\q:\q0\q,\qlocks\q:false,\qlockIsTemporary\q:false,\qevents\q:{\qkeydown\q:{\qkeyCode\q:\qKEY_0\q}}},{\qtype\q:\qkey\q,\qoffsetX\q:12,\qoffsetY\q:12,\qwidth\q:6,\qheight\q:6,\qlabel\q:\q6\q,\qlocks\q:false,\qlockIsTemporary\q:false,\qevents\q:{\qkeydown\q:{\qkeyCode\q:\qKEY_6\q}}},{\qtype\q:\qkey\q,\qoffsetX\q:0,\qoffsetY\q:18,\qwidth\q:6,\qheight\q:6,\qlabel\q:\q7\q,\qlocks\q:false,\qlockIsTemporary\q:false,\qevents\q:{\qkeydown\q:{\qkeyCode\q:\qKEY_7\q}}},{\qtype\q:\qkey\q,\qoffsetX\q:6,\qoffsetY\q:18,\qwidth\q:6,\qheight\q:6,\qlabel\q:\q8\q,\qlocks\q:false,\qlockIsTemporary\q:false,\qevents\q:{\qkeydown\q:{\qkeyCode\q:\qKEY_8\q}}},{\qtype\q:\qkey\q,\qoffsetX\q:6,\qoffsetY\q:24,\qwidth\q:6,\qheight\q:6,\qlabel\q:\q/\q,\qlocks\q:false,\qlockIsTemporary\q:false,\qevents\q:{\qkeydown\q:{\qkeyCode\q:\qKEY_FORWARD_SLASH\q}}},{\qtype\q:\qkey\q,\qoffsetX\q:12,\qoffsetY\q:24,\qwidth\q:6,\qheight\q:6,\qlabel\q:\q*\q,\qlocks\q:false,\qlockIsTemporary\q:false,\qevents\q:{\qkeydown\q:{\qkeyCode\q:\qKEY_STAR\q}}},{\qtype\q:\qkey\q,\qoffsetX\q:18,\qoffsetY\q:12,\qwidth\q:6,\qheight\q:12,\qlabel\q:\q+\q,\qlocks\q:false,\qlockIsTemporary\q:false,\qevents\q:{\qkeydown\q:{\qkeyCode\q:\qKEY_PLUS\q}}},{\qtype\q:\qkey\q,\qoffsetX\q:18,\qoffsetY\q:24,\qwidth\q:6,\qheight\q:6,\qlabel\q:\q-\q,\qlocks\q:false,\qlockIsTemporary\q:false,\qevents\q:{\qkeydown\q:{\qkeyCode\q:\qKEY_MINUS\q}}},{\qtype\q:\qkey\q,\qoffsetX\q:0,\qoffsetY\q:24,\qwidth\q:6,\qheight\q:6,\qlabel\q:\qBack Space\q,\qlocks\q:false,\qlockIsTemporary\q:false,\qevents\q:{\qkeydown\q:{\qkeyCode\q:\qKEY_BACKSPACE\q}}},{\qtype\q:\qkey\q,\qoffsetX\q:18,\qoffsetY\q:0,\qwidth\q:6,\qheight\q:12,\qlabel\q:\qEnter\q,\qlocks\q:false,\qlockIsTemporary\q:false,\qevents\q:{\qkeydown\q:{\qkeyCode\q:\qKEY_ENTER\q}}},{\qtype\q:\qkey\q,\qoffsetX\q:12,\qoffsetY\q:18,\qwidth\q:6,\qheight\q:6,\qlabel\q:\q9\q,\qlocks\q:false,\qlockIsTemporary\q:false,\qevents\q:{\qkeydown\q:{\qkeyCode\q:\qKEY_9\q}}},{\qtype\q:\qkey\q,\qoffsetX\q:12,\qoffsetY\q:0,\qwidth\q:6,\qheight\q:6,\qlabel\q:\q.\q,\qlocks\q:false,\qlockIsTemporary\q:false,\qevents\q:{\qkeydown\q:{\qkeyCode\q:\qKEY_DOT\q}}}]}"
keyset = QB_NODESET_deserialize(VkGetQuotedString(json$), "json")
VkLoadKeys QB_NODESET_node(QB_NODESET_label_equal(QB_NODESET_children(keyset), "keys")), i2
FOR i3 = 1 TO VkLast
IF VK(i2).active THEN
IF VK(i3).parent = i2 THEN
VK(i3).offsetY = VK(i3).offsetY - VkDefaultWidth * 5
END IF
END IF
NEXT
VkPress (VkByRole("ROOT"))
VkPress (VkByRole("ROOT"))
VkSelectedKey = i2
EXIT SUB
END IF
IF VK(i).event.keydown = -1002 THEN 'Game Controller
json$ = "{\qkeys\q:[{\qtype\q:\qkey\q,\qoffsetX\q:70,\qoffsetY\q:18,\qwidth\q:20,\qheight\q:6,\qlabel\q:\qR\q,\qlocks\q:false,\qlockIsTemporary\q:false,\qevents\q:{\qkeydown\q:{\qkeyCode\q:\qKEY_UCASE_R\q}}},{\qtype\q:\qkey\q,\qoffsetX\q:0,\qoffsetY\q:18,\qwidth\q:20,\qheight\q:6,\qlabel\q:\qL\q,\qlocks\q:false,\qlockIsTemporary\q:false,\qevents\q:{\qkeydown\q:{\qkeyCode\q:\qKEY_UCASE_L\q}}},{\qtype\q:\qkey\q,\qoffsetX\q:75,\qoffsetY\q:0,\qwidth\q:10,\qheight\q:6,\qlabel\q:\qB\q,\qlocks\q:false,\qlockIsTemporary\q:false,\qevents\q:{\qkeydown\q:{\qkeyCode\q:\qKEY_UCASE_B\q}}},{\qtype\q:\qkey\q,\qoffsetX\q:80,\qoffsetY\q:6,\qwidth\q:10,\qheight\q:6,\qlabel\q:\qA\q,\qlocks\q:false,\qlockIsTemporary\q:false,\qevents\q:{\qkeydown\q:{\qkeyCode\q:\qKEY_UCASE_A\q}}},{\qtype\q:\qkey\q,\qoffsetX\q:75,\qoffsetY\q:12,\qwidth\q:10,\qheight\q:6,\qlabel\q:\qX\q,\qlocks\q:false,\qlockIsTemporary\q:false,\qevents\q:{\qkeydown\q:{\qkeyCode\q:\qKEY_UCASE_X\q}}},{\qtype\q:\qkey\q,\qoffsetX\q:70,\qoffsetY\q:6,\qwidth\q:10,\qheight\q:6,\qlabel\q:\qY\q,\qlocks\q:false,\qlockIsTemporary\q:false,\qevents\q:{\qkeydown\q:{\qkeyCode\q:\qKEY_UCASE_Y\q}}},{\qtype\q:\qjoystick\q,\qoffsetX\q:6,\qoffsetY\q:6,\qwidth\q:6,\qheight\q:6,\qlabel\q:\qVirtual Joystick\q,\qevents\q:{\qup\q:{\qkeyCode\q:\qKEY_UP\q},\qdown\q:{\qkeyCode\q:\qKEY_DOWN\q},\qleft\q:{\qkeyCode\q:\qKEY_LEFT\q},\qright\q:{\qkeyCode\q:\qKEY_RIGHT\q}}},{\qtype\q:\qkey\q,\qoffsetX\q:33,\qoffsetY\q:6,\qwidth\q:10,\qheight\q:6,\qlabel\q:\qSpace\q,\qlocks\q:false,\qlockIsTemporary\q:false,\qevents\q:{\qkeydown\q:{\qkeyCode\q:\qKEY_SPACE\q}}},{\qtype\q:\qkey\q,\qoffsetX\q:48,\qoffsetY\q:6,\qwidth\q:10,\qheight\q:6,\qlabel\q:\qEnter\q,\qlocks\q:false,\qlockIsTemporary\q:false,\qevents\q:{\qkeydown\q:{\qkeyCode\q:\qKEY_ENTER\q}}}]}"
keyset = QB_NODESET_deserialize(VkGetQuotedString(json$), "json")
VkLoadKeys QB_NODESET_node(QB_NODESET_label_equal(QB_NODESET_children(keyset), "keys")), i2
FOR i3 = 1 TO VkLast
IF VK(i2).active THEN
IF VK(i3).parent = i2 THEN
VK(i3).offsetY = VK(i3).offsetY - VkDefaultWidth * 4
END IF
END IF
NEXT
VkPress (VkByRole("ROOT"))
VkPress (VkByRole("ROOT"))
VkSelectedKey = i2
EXIT SUB
END IF
IF VK(i).event.keydown = -1001 THEN 'Full KB
'no shifted characters:
'json$ = "{\qkeys\q:[{\qtype\q:\qkey\q,\qoffsetX\q:0,\qoffsetY\q:24,\qwidth\q:6,\qheight\q:6,\qlabel\q:\q`\q,\qlocks\q:false,\qlockIsTemporary\q:false,\qevents\q:{\qkeydown\q:{\qkeyCode\q:\qKEY_REVERSE_APOSTROPHE\q}}},{\qtype\q:\qkey\q,\qoffsetX\q:6,\qoffsetY\q:24,\qwidth\q:6,\qheight\q:6,\qlabel\q:\q1\q,\qlocks\q:false,\qlockIsTemporary\q:false,\qevents\q:{\qkeydown\q:{\qkeyCode\q:\qKEY_1\q}}},{\qtype\q:\qkey\q,\qoffsetX\q:9,\qoffsetY\q:18,\qwidth\q:6,\qheight\q:6,\qlabel\q:\qq\q,\qlocks\q:false,\qlockIsTemporary\q:false,\qevents\q:{\qkeydown\q:{\qkeyCode\q:\qKEY_LCASE_Q\q}}},{\qtype\q:\qkey\q,\qoffsetX\q:15,\qoffsetY\q:18,\qwidth\q:6,\qheight\q:6,\qlabel\q:\qw\q,\qlocks\q:false,\qlockIsTemporary\q:false,\qevents\q:{\qkeydown\q:{\qkeyCode\q:\qKEY_LCASE_W\q}}},{\qtype\q:\qkey\q,\qoffsetX\q:21,\qoffsetY\q:18,\qwidth\q:6,\qheight\q:6,\qlabel\q:\qe\q,\qlocks\q:false,\qlockIsTemporary\q:false,\qevents\q:{\qkeydown\q:{\qkeyCode\q:\qKEY_LCASE_E\q}}},{\qtype\q:\qkey\q,\qoffsetX\q:27,\qoffsetY\q:18,\qwidth\q:6,\qheight\q:6,\qlabel\q:\qr\q,\qlocks\q:false,\qlockIsTemporary\q:false,\qevents\q:{\qkeydown\q:{\qkeyCode\q:\qKEY_LCASE_R\q}}},{\qtype\q:\qkey\q,\qoffsetX\q:33,\qoffsetY\q:18,\qwidth\q:6,\qheight\q:6,\qlabel\q:\qt\q,\qlocks\q:false,\qlockIsTemporary\q:false,\qevents\q:{\qkeydown\q:{\qkeyCode\q:\qKEY_LCASE_T\q}}},{\qtype\q:\qkey\q,\qoffsetX\q:39,\qoffsetY\q:18,\qwidth\q:6,\qheight\q:6,\qlabel\q:\qy\q,\qlocks\q:false,\qlockIsTemporary\q:false,\qevents\q:{\qkeydown\q:{\qkeyCode\q:\qKEY_LCASE_Y\q}}},{\qtype\q:\qkey\q,\qoffsetX\q:45,\qoffsetY\q:18,\qwidth\q:6,\qheight\q:6,\qlabel\q:\qu\q,\qlocks\q:false,\qlockIsTemporary\q:false,\qevents\q:{\qkeydown\q:{\qkeyCode\q:\qKEY_LCASE_U\q}}},{\qtype\q:\qkey\q,\qoffsetX\q:51,\qoffsetY\q:18,\qwidth\q:6,\qheight\q:6,\qlabel\q:\qi\q,\qlocks\q:false,\qlockIsTemporary\q:false,\qevents\q:{\qkeydown\q:{\qkeyCode\q:\qKEY_LCASE_I\q}}},{\qtype\q:\qkey\q,\qoffsetX\q:57,\qoffsetY\q:18,\qwidth\q:6,\qheight\q:6,\qlabel\q:\qo\q,\qlocks\q:false,\qlockIsTemporary\q:false,\qevents\q:{\qkeydown\q:{\qkeyCode\q:\qKEY_LCASE_O\q}}},{\qtype\q:\qkey\q,\qoffsetX\q:63,\qoffsetY\q:18,\qwidth\q:6,\qheight\q:6,\qlabel\q:\qp\q,\qlocks\q:false,\qlockIsTemporary\q:false,\qevents\q:{\qkeydown\q:{\qkeyCode\q:\qKEY_LCASE_P\q}}},{\qtype\q:\qkey\q,\qoffsetX\q:69,\qoffsetY\q:18,\qwidth\q:6,\qheight\q:6,\qlabel\q:\q[\q,\qlocks\q:false,\qlockIsTemporary\q:false,\qevents\q:{\qkeydown\q:{\qkeyCode\q:\qKEY_OPEN_BRACKET_SQUARE\q}}},{\qtype\q:\qkey\q,\qoffsetX\q:75,\qoffsetY\q:18,\qwidth\q:6,\qheight\q:6,\qlabel\q:\q]\q,\qlocks\q:false,\qlockIsTemporary\q:false,\qevents\q:{\qkeydown\q:{\qkeyCode\q:\qKEY_CLOSE_BRACKET_SQUARE\q}}},{\qtype\q:\qkey\q,\qoffsetX\q:12,\qoffsetY\q:24,\qwidth\q:6,\qheight\q:6,\qlabel\q:\q2\q,\qlocks\q:false,\qlockIsTemporary\q:false,\qevents\q:{\qkeydown\q:{\qkeyCode\q:\qKEY_2\q}}},{\qtype\q:\qkey\q,\qoffsetX\q:11,\qoffsetY\q:12,\qwidth\q:6,\qheight\q:6,\qlabel\q:\qa\q,\qlocks\q:false,\qlockIsTemporary\q:false,\qevents\q:{\qkeydown\q:{\qkeyCode\q:\qKEY_LCASE_A\q}}},{\qtype\q:\qkey\q,\qoffsetX\q:17,\qoffsetY\q:12,\qwidth\q:6,\qheight\q:6,\qlabel\q:\qs\q,\qlocks\q:false,\qlockIsTemporary\q:false,\qevents\q:{\qkeydown\q:{\qkeyCode\q:\qKEY_LCASE_S\q}}},{\qtype\q:\qkey\q,\qoffsetX\q:23,\qoffsetY\q:12,\qwidth\q:6,\qheight\q:6,\qlabel\q:\qd\q,\qlocks\q:false,\qlockIsTemporary\q:false,\qevents\q:{\qkeydown\q:{\qkeyCode\q:\qKEY_LCASE_D\q}}},{\qtype\q:\qkey\q,\qoffsetX\q:29,\qoffsetY\q:12,\qwidth\q:6,\qheight\q:6,\qlabel\q:\qf\q,\qlocks\q:false,\qlockIsTemporary\q:false,\qevents\q:{\qkeydown\q:{\qkeyCode\q:\qKEY_LCASE_F\q}}},{\qtype\q:\qkey\q,\qoffsetX\q:35,\qoffsetY\q:12,\qwidth\q:6,\qheight\q:6,\qlabel\q:\qg\q,\qlocks\q:false,\qlockIsTemporary\q:false,\qevents\q:{\qkeydown\q:{\qkeyCode\q:\qKEY_LCASE_G\q}}},{\qtype\q:\qkey\q,\qoffsetX\q:41,\qoffsetY\q:12,\qwidth\q:6,\qheight\q:6,\qlabel\q:\qh\q,\qlocks\q:false,\qlockIsTemporary\q:false,\qevents\q:{\qkeydown\q:{\qkeyCode\q:\qKEY_LCASE_H\q}}},{\qtype\q:\qkey\q,\qoffsetX\q:47,\qoffsetY\q:12,\qwidth\q:6,\qheight\q:6,\qlabel\q:\qj\q,\qlocks\q:false,\qlockIsTemporary\q:false,\qevents\q:{\qkeydown\q:{\qkeyCode\q:\qKEY_LCASE_J\q}}},{\qtype\q:\qkey\q,\qoffsetX\q:53,\qoffsetY\q:12,\qwidth\q:6,\qheight\q:6,\qlabel\q:\qk\q,\qlocks\q:false,\qlockIsTemporary\q:false,\qevents\q:{\qkeydown\q:{\qkeyCode\q:\qKEY_LCASE_K\q}}},{\qtype\q:\qkey\q,\qoffsetX\q:59,\qoffsetY\q:12,\qwidth\q:6,\qheight\q:6,\qlabel\q:\ql\q,\qlocks\q:false,\qlockIsTemporary\q:false,\qevents\q:{\qkeydown\q:{\qkeyCode\q:\qKEY_LCASE_L\q}}},{\qtype\q:\qkey\q,\qoffsetX\q:65,\qoffsetY\q:12,\qwidth\q:6,\qheight\q:6,\qlabel\q:\q;\q,\qlocks\q:false,\qlockIsTemporary\q:false,\qevents\q:{\qkeydown\q:{\qkeyCode\q:\qKEY_SEMICOLON\q}}},{\qtype\q:\qkey\q,\qoffsetX\q:71,\qoffsetY\q:12,\qwidth\q:6,\qheight\q:6,\qlabel\q:\q'\q,\qlocks\q:false,\qlockIsTemporary\q:false,\qevents\q:{\qkeydown\q:{\qkeyCode\q:\qKEY_APOSTROPHE\q}}},{\qtype\q:\qkey\q,\qoffsetX\q:81,\qoffsetY\q:18,\qwidth\q:9,\qheight\q:6,\qlabel\q:\q\\\q,\qlocks\q:false,\qlockIsTemporary\q:false,\qevents\q:{\qkeydown\q:{\qkeyCode\q:\qKEY_BACK_SLASH\q}}},{\qtype\q:\qkey\q,\qoffsetX\q:77,\qoffsetY\q:12,\qwidth\q:13,\qheight\q:6,\qlabel\q:\qEnter\q,\qlocks\q:false,\qlockIsTemporary\q:false,\qevents\q:{\qkeydown\q:{\qkeyCode\q:\qKEY_ENTER\q}}},{\qtype\q:\qkey\q,\qoffsetX\q:14,\qoffsetY\q:6,\qwidth\q:6,\qheight\q:6,\qlabel\q:\qz\q,\qlocks\q:false,\qlockIsTemporary\q:false,\qevents\q:{\qkeydown\q:{\qkeyCode\q:\qKEY_LCASE_Z\q}}},{\qtype\q:\qkey\q,\qoffsetX\q:20,\qoffsetY\q:6,\qwidth\q:6,\qheight\q:6,\qlabel\q:\qx\q,\qlocks\q:false,\qlockIsTemporary\q:false,\qevents\q:{\qkeydown\q:{\qkeyCode\q:\qKEY_LCASE_X\q}}},{\qtype\q:\qkey\q,\qoffsetX\q:26,\qoffsetY\q:6,\qwidth\q:6,\qheight\q:6,\qlabel\q:\qc\q,\qlocks\q:false,\qlockIsTemporary\q:false,\qevents\q:{\qkeydown\q:{\qkeyCode\q:\qKEY_LCASE_C\q}}},{\qtype\q:\qkey\q,\qoffsetX\q:32,\qoffsetY\q:6,\qwidth\q:6,\qheight\q:6,\qlabel\q:\qv\q,\qlocks\q:false,\qlockIsTemporary\q:false,\qevents\q:{\qkeydown\q:{\qkeyCode\q:\qKEY_LCASE_V\q}}},{\qtype\q:\qkey\q,\qoffsetX\q:38,\qoffsetY\q:6,\qwidth\q:6,\qheight\q:6,\qlabel\q:\qb\q,\qlocks\q:false,\qlockIsTemporary\q:false,\qevents\q:{\qkeydown\q:{\qkeyCode\q:\qKEY_LCASE_B\q}}},{\qtype\q:\qkey\q,\qoffsetX\q:44,\qoffsetY\q:6,\qwidth\q:6,\qheight\q:6,\qlabel\q:\qn\q,\qlocks\q:false,\qlockIsTemporary\q:false,\qevents\q:{\qkeydown\q:{\qkeyCode\q:\qKEY_LCASE_N\q}}},{\qtype\q:\qkey\q,\qoffsetX\q:50,\qoffsetY\q:6,\qwidth\q:6,\qheight\q:6,\qlabel\q:\qm\q,\qlocks\q:false,\qlockIsTemporary\q:false,\qevents\q:{\qkeydown\q:{\qkeyCode\q:\qKEY_LCASE_M\q}}},{\qtype\q:\qkey\q,\qoffsetX\q:56,\qoffsetY\q:6,\qwidth\q:6,\qheight\q:6,\qlabel\q:\q,\q,\qlocks\q:false,\qlockIsTemporary\q:false,\qevents\q:{\qkeydown\q:{\qkeyCode\q:\qKEY_COMMA\q}}},{\qtype\q:\qkey\q,\qoffsetX\q:62,\qoffsetY\q:6,\qwidth\q:6,\qheight\q:6,\qlabel\q:\q.\q,\qlocks\q:false,\qlockIsTemporary\q:false,\qevents\q:{\qkeydown\q:{\qkeyCode\q:\qKEY_DOT\q}}},{\qtype\q:\qkey\q,\qoffsetX\q:68,\qoffsetY\q:6,\qwidth\q:6,\qheight\q:6,\qlabel\q:\q/\q,\qlocks\q:false,\qlockIsTemporary\q:false,\qevents\q:{\qkeydown\q:{\qkeyCode\q:\qKEY_FORWARD_SLASH\q}}},{\qtype\q:\qkey\q,\qoffsetX\q:74,\qoffsetY\q:6,\qwidth\q:6,\qheight\q:6,\qlabel\q:\q\u2191\q,\qlocks\q:false,\qlockIsTemporary\q:false,\qevents\q:{\qkeydown\q:{\qkeyCode\q:\qKEY_UP\q}}},{\qtype\q:\qkey\q,\qoffsetX\q:80,\qoffsetY\q:0,\qwidth\q:6,\qheight\q:6,\qlabel\q:\q\u2192\q,\qlocks\q:false,\qlockIsTemporary\q:false,\qevents\q:{\qkeydown\q:{\qkeyCode\q:\qKEY_RIGHT\q}}},{\qtype\q:\qkey\q,\qoffsetX\q:68,\qoffsetY\q:0,\qwidth\q:6,\qheight\q:6,\qlabel\q:\q\u2190\q,\qlocks\q:false,\qlockIsTemporary\q:false,\qevents\q:{\qkeydown\q:{\qkeyCode\q:\qKEY_LEFT\q}}},{\qtype\q:\qkey\q,\qoffsetX\q:74,\qoffsetY\q:0,\qwidth\q:6,\qheight\q:6,\qlabel\q:\q\u2193\q,\qlocks\q:false,\qlockIsTemporary\q:false,\qevents\q:{\qkeydown\q:{\qkeyCode\q:\qKEY_DOWN\q}}},{\qtype\q:\qkey\q,\qoffsetX\q:80,\qoffsetY\q:6,\qwidth\q:10,\qheight\q:6,\qlabel\q:\qShift\q,\qlocks\q:true,\qlockIsTemporary\q:true,\qevents\q:{\qkeydown\q:{\qkeyCode\q:\qKEY_RSHIFT\q}}},{\qtype\q:\qkey\q,\qoffsetX\q:59,\qoffsetY\q:0,\qwidth\q:9,\qheight\q:6,\qlabel\q:\qAlt\q,\qlocks\q:true,\qlockIsTemporary\q:true,\qevents\q:{\qkeydown\q:{\qkeyCode\q:\qKEY_RALT\q}}},{\qtype\q:\qkey\q,\qoffsetX\q:17,\qoffsetY\q:0,\qwidth\q:8,\qheight\q:6,\qlabel\q:\qAlt\q,\qlocks\q:true,\qlockIsTemporary\q:true,\qevents\q:{\qkeydown\q:{\qkeyCode\q:\qKEY_LALT\q}}},{\qtype\q:\qkey\q,\qoffsetX\q:9,\qoffsetY\q:0,\qwidth\q:8,\qheight\q:6,\qlabel\q:\q\u2302\q,\qlocks\q:false,\qlockIsTemporary\q:false,\qevents\q:{\qkeydown\q:{\qkeyCode\q:\qKEY_LSUPER\q}}},{\qtype\q:\qkey\q,\qoffsetX\q:0,\qoffsetY\q:0,\qwidth\q:9,\qheight\q:6,\qlabel\q:\qCtrl\q,\qlocks\q:true,\qlockIsTemporary\q:true,\qevents\q:{\qkeydown\q:{\qkeyCode\q:\qKEY_LCTRL\q}}},{\qtype\q:\qkey\q,\qoffsetX\q:24,\qoffsetY\q:24,\qwidth\q:6,\qheight\q:6,\qlabel\q:\q4\q,\qlocks\q:false,\qlockIsTemporary\q:false,\qevents\q:{\qkeydown\q:{\qkeyCode\q:\qKEY_4\q}}},{\qtype\q:\qkey\q,\qoffsetX\q:18,\qoffsetY\q:24,\qwidth\q:6,\qheight\q:6,\qlabel\q:\q3\q,\qlocks\q:false,\qlockIsTemporary\q:false,\qevents\q:{\qkeydown\q:{\qkeyCode\q:\qKEY_3\q}}},{\qtype\q:\qkey\q,\qoffsetX\q:30,\qoffsetY\q:24,\qwidth\q:6,\qheight\q:6,\qlabel\q:\q5\q,\qlocks\q:false,\qlockIsTemporary\q:false,\qevents\q:{\qkeydown\q:{\qkeyCode\q:\qKEY_5\q}}},{\qtype\q:\qkey\q,\qoffsetX\q:36,\qoffsetY\q:24,\qwidth\q:6,\qheight\q:6,\qlabel\q:\q6\q,\qlocks\q:false,\qlockIsTemporary\q:false,\qevents\q:{\qkeydown\q:{\qkeyCode\q:\qKEY_6\q}}},{\qtype\q:\qkey\q,\qoffsetX\q:42,\qoffsetY\q:24,\qwidth\q:6,\qheight\q:6,\qlabel\q:\q7\q,\qlocks\q:false,\qlockIsTemporary\q:false,\qevents\q:{\qkeydown\q:{\qkeyCode\q:\qKEY_7\q}}},{\qtype\q:\qkey\q,\qoffsetX\q:48,\qoffsetY\q:24,\qwidth\q:6,\qheight\q:6,\qlabel\q:\q8\q,\qlocks\q:false,\qlockIsTemporary\q:false,\qevents\q:{\qkeydown\q:{\qkeyCode\q:\qKEY_8\q}}},{\qtype\q:\qkey\q,\qoffsetX\q:54,\qoffsetY\q:24,\qwidth\q:6,\qheight\q:6,\qlabel\q:\q9\q,\qlocks\q:false,\qlockIsTemporary\q:false,\qevents\q:{\qkeydown\q:{\qkeyCode\q:\qKEY_9\q}}},{\qtype\q:\qkey\q,\qoffsetX\q:60,\qoffsetY\q:24,\qwidth\q:6,\qheight\q:6,\qlabel\q:\q0\q,\qlocks\q:false,\qlockIsTemporary\q:false,\qevents\q:{\qkeydown\q:{\qkeyCode\q:\qKEY_0\q}}},{\qtype\q:\qkey\q,\qoffsetX\q:66,\qoffsetY\q:24,\qwidth\q:6,\qheight\q:6,\qlabel\q:\q-\q,\qlocks\q:false,\qlockIsTemporary\q:false,\qevents\q:{\qkeydown\q:{\qkeyCode\q:\qKEY_MINUS\q}}},{\qtype\q:\qkey\q,\qoffsetX\q:72,\qoffsetY\q:24,\qwidth\q:6,\qheight\q:6,\qlabel\q:\q=\q,\qlocks\q:false,\qlockIsTemporary\q:false,\qevents\q:{\qkeydown\q:{\qkeyCode\q:\qKEY_EQUAL\q}}},{\qtype\q:\qkey\q,\qoffsetX\q:84,\qoffsetY\q:24,\qwidth\q:6,\qheight\q:6,\qlabel\q:\qBack Space\q,\qlocks\q:false,\qlockIsTemporary\q:false,\qevents\q:{\qkeydown\q:{\qkeyCode\q:\qKEY_BACKSPACE\q}}},{\qtype\q:\qkey\q,\qoffsetX\q:78,\qoffsetY\q:24,\qwidth\q:6,\qheight\q:6,\qlabel\q:\q+\q,\qlocks\q:false,\qlockIsTemporary\q:false,\qevents\q:{\qkeydown\q:{\qkeyCode\q:\qKEY_PLUS\q}}},{\qtype\q:\qkey\q,\qoffsetX\q:0,\qoffsetY\q:18,\qwidth\q:9,\qheight\q:6,\qlabel\q:\qTab\q,\qlocks\q:false,\qlockIsTemporary\q:false,\qevents\q:{\qkeydown\q:{\qkeyCode\q:\qKEY_TAB\q}}},{\qtype\q:\qkey\q,\qoffsetX\q:0,\qoffsetY\q:12,\qwidth\q:11,\qheight\q:6,\qlabel\q:\qCaps Lock\q,\qlocks\q:true,\qlockIsTemporary\q:false,\qevents\q:{\qkeydown\q:{\qkeyCode\q:\qKEY_CAPSLOCK\q}}},{\qtype\q:\qkey\q,\qoffsetX\q:0,\qoffsetY\q:6,\qwidth\q:14,\qheight\q:6,\qlabel\q:\qShift\q,\qlocks\q:true,\qlockIsTemporary\q:true,\qevents\q:{\qkeydown\q:{\qkeyCode\q:\qKEY_LSHIFT\q}}},{\qtype\q:\qkey\q,\qoffsetX\q:86,\qoffsetY\q:0,\qwidth\q:4,\qheight\q:6,\qlabel\q:\qEsc\q,\qlocks\q:false,\qlockIsTemporary\q:false,\qevents\q:{\qkeydown\q:{\qkeyCode\q:\qKEY_ESCAPE\q}}},{\qtype\q:\qkey\q,\qoffsetX\q:25,\qoffsetY\q:0,\qwidth\q:34,\qheight\q:6,\qlabel\q:\q\q,\qlocks\q:false,\qlockIsTemporary\q:false,\qevents\q:{\qkeydown\q:{\qkeyCode\q:\qKEY_SPACE\q}}}]}"
'with shifted characters:
json$ = "{\qkeys\q:[{\qtype\q:\qkey\q,\qoffsetX\q:0,\qoffsetY\q:24,\qwidth\q:6,\qheight\q:6,\qlabel\q:\q`\q,\qlocks\q:false,\qlockIsTemporary\q:false,\qevents\q:{\qkeydown\q:{\qkeyCode\q:\qKEY_REVERSE_APOSTROPHE\q},\qkeydownWithShift\q:{\qkeyCode\q:\qKEY_TILDE\q,\qlabel\q:\q~\q}}},{\qtype\q:\qkey\q,\qoffsetX\q:6,\qoffsetY\q:24,\qwidth\q:6,\qheight\q:6,\qlabel\q:\q1\q,\qlocks\q:false,\qlockIsTemporary\q:false,\qevents\q:{\qkeydown\q:{\qkeyCode\q:\qKEY_1\q},\qkeydownWithShift\q:{\qkeyCode\q:\qKEY_EXCLAMATION\q,\qlabel\q:\q!\q}}},{\qtype\q:\qkey\q,\qoffsetX\q:9,\qoffsetY\q:18,\qwidth\q:6,\qheight\q:6,\qlabel\q:\qq\q,\qlocks\q:false,\qlockIsTemporary\q:false,\qevents\q:{\qkeydown\q:{\qkeyCode\q:\qKEY_LCASE_Q\q},\qkeydownWithShift\q:{\qkeyCode\q:\qKEY_UCASE_Q\q,\qlabel\q:\qQ\q}}},{\qtype\q:\qkey\q,\qoffsetX\q:15,\qoffsetY\q:18,\qwidth\q:6,\qheight\q:6,\qlabel\q:\qw\q,\qlocks\q:false,\qlockIsTemporary\q:false,\qevents\q:{\qkeydown\q:{\qkeyCode\q:\qKEY_LCASE_W\q},\qkeydownWithShift\q:{\qkeyCode\q:\qKEY_UCASE_W\q,\qlabel\q:\qW\q}}},{\qtype\q:\qkey\q,\qoffsetX\q:21,\qoffsetY\q:18,\qwidth\q:6,\qheight\q:6,\qlabel\q:\qe\q,\qlocks\q:false,\qlockIsTemporary\q:false,\qevents\q:{\qkeydown\q:{\qkeyCode\q:\qKEY_LCASE_E\q},\qkeydownWithShift\q:{\qkeyCode\q:\qKEY_UCASE_E\q,\qlabel\q:\qE\q}}},{\qtype\q:\qkey\q,\qoffsetX\q:27,\qoffsetY\q:18,\qwidth\q:6,\qheight\q:6,\qlabel\q:\qr\q,\qlocks\q:false,\qlockIsTemporary\q:false,\qevents\q:{\qkeydown\q:{\qkeyCode\q:\qKEY_LCASE_R\q},\qkeydownWithShift\q:{\qkeyCode\q:\qKEY_UCASE_R\q,\qlabel\q:\qR\q}}},{\qtype\q:\qkey\q,\qoffsetX\q:33,\qoffsetY\q:18,\qwidth\q:6,\qheight\q:6,\qlabel\q:\qt\q,\qlocks\q:false,\qlockIsTemporary\q:false,\qevents\q:{\qkeydown\q:{\qkeyCode\q:\qKEY_LCASE_T\q},\qkeydownWithShift\q:{\qkeyCode\q:\qKEY_UCASE_T\q,\qlabel\q:\qT\q}}},{\qtype\q:\qkey\q,\qoffsetX\q:39,\qoffsetY\q:18,\qwidth\q:6,\qheight\q:6,\qlabel\q:\qy\q,\qlocks\q:false,\qlockIsTemporary\q:false,\qevents\q:{\qkeydown\q:{\qkeyCode\q:\qKEY_LCASE_Y\q},\qkeydownWithShift\q:{\qkeyCode\q:\qKEY_UCASE_Y\q,\qlabel\q:\qY\q}}},{\qtype\q:\qkey\q,\qoffsetX\q:45,\qoffsetY\q:18,\qwidth\q:6,\qheight\q:6,\qlabel\q:\qu\q,\qlocks\q:false,\qlockIsTemporary\q:false,\qevents\q:{\qkeydown\q:{\qkeyCode\q:\qKEY_LCASE_U\q},\qkeydownWithShift\q:{\qkeyCode\q:\qKEY_UCASE_U\q,\qlabel\q:\qU\q}}},{\qtype\q:\qkey\q,\qoffsetX\q:51,\qoffsetY\q:18,\qwidth\q:6,\qheight\q:6,\qlabel\q:\qi\q,\qlocks\q:false,\qlockIsTemporary\q:false,\qevents\q:{\qkeydown\q:{\qkeyCode\q:\qKEY_LCASE_I\q},\qkeydownWithShift\q:{\qkeyCode\q:\qKEY_UCASE_I\q,\qlabel\q:\qI\q}}},{\qtype\q:\qkey\q,\qoffsetX\q:57,\qoffsetY\q:18,\qwidth\q:6,\qheight\q:6,\qlabel\q:\qo\q,\qlocks\q:false,\qlockIsTemporary\q:false,\qevents\q:{\qkeydown\q:{\qkeyCode\q:\qKEY_LCASE_O\q},\qkeydownWithShift\q:{\qkeyCode\q:\qKEY_UCASE_O\q,\qlabel\q:\qO\q}}},{\qtype\q:\qkey\q,\qoffsetX\q:63,\qoffsetY\q:18,\qwidth\q:6,\qheight\q:6,\qlabel\q:\qp\q,\qlocks\q:false,\qlockIsTemporary\q:false,\qevents\q:{\qkeydown\q:{\qkeyCode\q:\qKEY_LCASE_P\q},\qkeydownWithShift\q:{\qkeyCode\q:\qKEY_UCASE_P\q,\qlabel\q:\qP\q}}},{\qtype\q:\qkey\q,\qoffsetX\q:69,\qoffsetY\q:18,\qwidth\q:6,\qheight\q:6,\qlabel\q:\q[\q,\qlocks\q:false,\qlockIsTemporary\q:false,\qevents\q:{\qkeydown\q:{\qkeyCode\q:\qKEY_OPEN_BRACKET_SQUARE\q},\qkeydownWithShift\q:{\qkeyCode\q:\qKEY_OPEN_BRACKET_CURLY\q,\qlabel\q:\q{\q}}},{\qtype\q:\qkey\q,\qoffsetX\q:75,\qoffsetY\q:18,\qwidth\q:6,\qheight\q:6,\qlabel\q:\q]\q,\qlocks\q:false,\qlockIsTemporary\q:false,\qevents\q:{\qkeydown\q:{\qkeyCode\q:\qKEY_CLOSE_BRACKET_SQUARE\q},\qkeydownWithShift\q:{\qkeyCode\q:\qKEY_CLOSE_BRACKET_CURLY\q,\qlabel\q:\q}\q}}},{\qtype\q:\qkey\q,\qoffsetX\q:12,\qoffsetY\q:24,\qwidth\q:6,\qheight\q:6,\qlabel\q:\q2\q,\qlocks\q:false,\qlockIsTemporary\q:false,\qevents\q:{\qkeydown\q:{\qkeyCode\q:\qKEY_2\q},\qkeydownWithShift\q:{\qkeyCode\q:\qKEY_AT\q,\qlabel\q:\q@\q}}},{\qtype\q:\qkey\q,\qoffsetX\q:11,\qoffsetY\q:12,\qwidth\q:6,\qheight\q:6,\qlabel\q:\qa\q,\qlocks\q:false,\qlockIsTemporary\q:false,\qevents\q:{\qkeydown\q:{\qkeyCode\q:\qKEY_LCASE_A\q},\qkeydownWithShift\q:{\qkeyCode\q:\qKEY_UCASE_A\q,\qlabel\q:\qA\q}}},{\qtype\q:\qkey\q,\qoffsetX\q:17,\qoffsetY\q:12,\qwidth\q:6,\qheight\q:6,\qlabel\q:\qs\q,\qlocks\q:false,\qlockIsTemporary\q:false,\qevents\q:{\qkeydown\q:{\qkeyCode\q:\qKEY_LCASE_S\q},\qkeydownWithShift\q:{\qkeyCode\q:\qKEY_UCASE_S\q,\qlabel\q:\qS\q}}},{\qtype\q:\qkey\q,\qoffsetX\q:23,\qoffsetY\q:12,\qwidth\q:6,\qheight\q:6,\qlabel\q:\qd\q,\qlocks\q:false,\qlockIsTemporary\q:false,\qevents\q:{\qkeydown\q:{\qkeyCode\q:\qKEY_LCASE_D\q},\qkeydownWithShift\q:{\qkeyCode\q:\qKEY_UCASE_D\q,\qlabel\q:\qD\q}}},{\qtype\q:\qkey\q,\qoffsetX\q:29,\qoffsetY\q:12,\qwidth\q:6,\qheight\q:6,\qlabel\q:\qf\q,\qlocks\q:false,\qlockIsTemporary\q:false,\qevents\q:{\qkeydown\q:{\qkeyCode\q:\qKEY_LCASE_F\q},\qkeydownWithShift\q:{\qkeyCode\q:\qKEY_UCASE_F\q,\qlabel\q:\qF\q}}},{\qtype\q:\qkey\q,\qoffsetX\q:35,\qoffsetY\q:12,\qwidth\q:6,\qheight\q:6,\qlabel\q:\qg\q,\qlocks\q:false,\qlockIsTemporary\q:false,\qevents\q:{\qkeydown\q:{\qkeyCode\q:\qKEY_LCASE_G\q},\qkeydownWithShift\q:{\qkeyCode\q:\qKEY_UCASE_G\q,\qlabel\q:\qG\q}}},{\qtype\q:\qkey\q,\qoffsetX\q:41,\qoffsetY\q:12,\qwidth\q:6,\qheight\q:6,\qlabel\q:\qh\q,\qlocks\q:false,\qlockIsTemporary\q:false,\qevents\q:{\qkeydown\q:{\qkeyCode\q:\qKEY_LCASE_H\q},\qkeydownWithShift\q:{\qkeyCode\q:\qKEY_UCASE_H\q,\qlabel\q:\qH\q}}},{\qtype\q:\qkey\q,\qoffsetX\q:47,\qoffsetY\q:12,\qwidth\q:6,\qheight\q:6,\qlabel\q:\qj\q,\qlocks\q:false,\qlockIsTemporary\q:false,\qevents\q:{\qkeydown\q:{\qkeyCode\q:\qKEY_LCASE_J\q},\qkeydownWithShift\q:{\qkeyCode\q:\qKEY_UCASE_J\q,\qlabel\q:\qJ\q}}},{\qtype\q:\qkey\q,\qoffsetX\q:53,\qoffsetY\q:12,\qwidth\q:6,\qheight\q:6,\qlabel\q:\qk\q,\qlocks\q:false,\qlockIsTemporary\q:false,\qevents\q:{\qkeydown\q:{\qkeyCode\q:\qKEY_LCASE_K\q},\qkeydownWithShift\q:{\qkeyCode\q:\qKEY_UCASE_K\q,\qlabel\q:\qK\q}}},{\qtype\q:\qkey\q,\qoffsetX\q:59,\qoffsetY\q:12,\qwidth\q:6,\qheight\q:6,\qlabel\q:\ql\q,\qlocks\q:false,\qlockIsTemporary\q:false,\qevents\q:{\qkeydown\q:{\qkeyCode\q:\qKEY_LCASE_L\q},\qkeydownWithShift\q:{\qkeyCode\q:\qKEY_UCASE_L\q,\qlabel\q:\qL\q}}},{\qtype\q:\qkey\q,\qoffsetX\q:65,\qoffsetY\q:12,\qwidth\q:6,\qheight\q:6,\qlabel\q:\q;\q,\qlocks\q:false,\qlockIsTemporary\q:false,\qevents\q:{\qkeydown\q:{\qkeyCode\q:\qKEY_SEMICOLON\q},\qkeydownWithShift\q:{\qkeyCode\q:\qKEY_COLON\q,\qlabel\q:\q:\q}}},{\qtype\q:\qkey\q,\qoffsetX\q:71,\qoffsetY\q:12,\qwidth\q:6,\qheight\q:6,\qlabel\q:\q'\q,\qlocks\q:false,\qlockIsTemporary\q:false,\qevents\q:{\qkeydown\q:{\qkeyCode\q:\qKEY_APOSTROPHE\q},\qkeydownWithShift\q:{\qkeyCode\q:\qKEY_QUOTE\q,\qlabel\q:\q\\q\q}}},{\qtype\q:\qkey\q,\qoffsetX\q:81,\qoffsetY\q:18,\qwidth\q:9,\qheight\q:6,\qlabel\q:\q\\\q,\qlocks\q:false,\qlockIsTemporary\q:false,\qevents\q:{\qkeydown\q:{\qkeyCode\q:\qKEY_BACK_SLASH\q},\qkeydownWithShift\q:{\qkeyCode\q:\qKEY_VERTICAL_BAR\q,\qlabel\q:\q|\q}}},{\qtype\q:\qkey\q,\qoffsetX\q:77,\qoffsetY\q:12,\qwidth\q:13,\qheight\q:6,\qlabel\q:\qEnter\q,\qlocks\q:false,\qlockIsTemporary\q:false,\qevents\q:{\qkeydown\q:{\qkeyCode\q:\qKEY_ENTER\q}}},{\qtype\q:\qkey\q,\qoffsetX\q:14,\qoffsetY\q:6,\qwidth\q:6,\qheight\q:6,\qlabel\q:\qz\q,\qlocks\q:false,\qlockIsTemporary\q:false,\qevents\q:{\qkeydown\q:{\qkeyCode\q:\qKEY_LCASE_Z\q},\qkeydownWithShift\q:{\qkeyCode\q:\qKEY_UCASE_Z\q,\qlabel\q:\qZ\q}}},{\qtype\q:\qkey\q,\qoffsetX\q:20,\qoffsetY\q:6,\qwidth\q:6,\qheight\q:6,\qlabel\q:\qx\q,\qlocks\q:false,\qlockIsTemporary\q:false,\qevents\q:{\qkeydown\q:{\qkeyCode\q:\qKEY_LCASE_X\q},\qkeydownWithShift\q:{\qkeyCode\q:\qKEY_UCASE_X\q,\qlabel\q:\qX\q}}},{\qtype\q:\qkey\q,\qoffsetX\q:26,\qoffsetY\q:6,\qwidth\q:6,\qheight\q:6,\qlabel\q:\qc\q,\qlocks\q:false,\qlockIsTemporary\q:false,\qevents\q:{\qkeydown\q:{\qkeyCode\q:\qKEY_LCASE_C\q},\qkeydownWithShift\q:{\qkeyCode\q:\qKEY_UCASE_C\q,\qlabel\q:\qC\q}}},{\qtype\q:\qkey\q,\qoffsetX\q:32,\qoffsetY\q:6,\qwidth\q:6,\qheight\q:6,\qlabel\q:\qv\q,\qlocks\q:false,\qlockIsTemporary\q:false,\qevents\q:{\qkeydown\q:{\qkeyCode\q:\qKEY_LCASE_V\q},\qkeydownWithShift\q:{\qkeyCode\q:\qKEY_UCASE_V\q,\qlabel\q:\qV\q}}},{\qtype\q:\qkey\q,\qoffsetX\q:38,\qoffsetY\q:6,\qwidth\q:6,\qheight\q:6,\qlabel\q:\qb\q,\qlocks\q:false,\qlockIsTemporary\q:false,\qevents\q:{\qkeydown\q:{\qkeyCode\q:\qKEY_LCASE_B\q},\qkeydownWithShift\q:{\qkeyCode\q:\qKEY_UCASE_B\q,\qlabel\q:\qB\q}}},{\qtype\q:\qkey\q,\qoffsetX\q:44,\qoffsetY\q:6,\qwidth\q:6,\qheight\q:6,\qlabel\q:\qn\q,\qlocks\q:false,\qlockIsTemporary\q:false,\qevents\q:{\qkeydown\q:{\qkeyCode\q:\qKEY_LCASE_N\q},\qkeydownWithShift\q:{\qkeyCode\q:\qKEY_UCASE_N\q,\qlabel\q:\qN\q}}},{\qtype\q:\qkey\q,\qoffsetX\q:50,\qoffsetY\q:6,\qwidth\q:6,\qheight\q:6,\qlabel\q:\qm\q,\qlocks\q:false,\qlockIsTemporary\q:false,\qevents\q:{\qkeydown\q:{\qkeyCode\q:\qKEY_LCASE_M\q},\qkeydownWithShift\q:{\qkeyCode\q:\qKEY_UCASE_M\q,\qlabel\q:\qM\q}}},{\qtype\q:\qkey\q,\qoffsetX\q:56,\qoffsetY\q:6,\qwidth\q:6,\qheight\q:6,\qlabel\q:\q,\q,\qlocks\q:false,\qlockIsTemporary\q:false,\qevents\q:{\qkeydown\q:{\qkeyCode\q:\qKEY_COMMA\q},\qkeydownWithShift\q:{\qkeyCode\q:\qKEY_LESS_THAN\q,\qlabel\q:\q<\q}}},{\qtype\q:\qkey\q,\qoffsetX\q:62,\qoffsetY\q:6,\qwidth\q:6,\qheight\q:6,\qlabel\q:\q.\q,\qlocks\q:false,\qlockIsTemporary\q:false,\qevents\q:{\qkeydown\q:{\qkeyCode\q:\qKEY_DOT\q},\qkeydownWithShift\q:{\qkeyCode\q:\qKEY_GREATER_THAN\q,\qlabel\q:\q>\q}}},{\qtype\q:\qkey\q,\qoffsetX\q:68,\qoffsetY\q:6,\qwidth\q:6,\qheight\q:6,\qlabel\q:\q/\q,\qlocks\q:false,\qlockIsTemporary\q:false,\qevents\q:{\qkeydown\q:{\qkeyCode\q:\qKEY_FORWARD_SLASH\q},\qkeydownWithShift\q:{\qkeyCode\q:\qKEY_QUESTION\q,\qlabel\q:\q?\q}}},{\qtype\q:\qkey\q,\qoffsetX\q:74,\qoffsetY\q:6,\qwidth\q:6,\qheight\q:6,\qlabel\q:\q\u2191\q,\qlocks\q:false,\qlockIsTemporary\q:false,\qevents\q:{\qkeydown\q:{\qkeyCode\q:\qKEY_UP\q}}},{\qtype\q:\qkey\q,\qoffsetX\q:80,\qoffsetY\q:0,\qwidth\q:6,\qheight\q:6,\qlabel\q:\q\u2192\q,\qlocks\q:false,\qlockIsTemporary\q:false,\qevents\q:{\qkeydown\q:{\qkeyCode\q:\qKEY_RIGHT\q}}},{\qtype\q:\qkey\q,\qoffsetX\q:68,\qoffsetY\q:0,\qwidth\q:6,\qheight\q:6,\qlabel\q:\q\u2190\q,\qlocks\q:false,\qlockIsTemporary\q:false,\qevents\q:{\qkeydown\q:{\qkeyCode\q:\qKEY_LEFT\q}}},{\qtype\q:\qkey\q,\qoffsetX\q:74,\qoffsetY\q:0,\qwidth\q:6,\qheight\q:6,\qlabel\q:\q\u2193\q,\qlocks\q:false,\qlockIsTemporary\q:false,\qevents\q:{\qkeydown\q:{\qkeyCode\q:\qKEY_DOWN\q}}},{\qtype\q:\qkey\q,\qoffsetX\q:80,\qoffsetY\q:6,\qwidth\q:10,\qheight\q:6,\qlabel\q:\qShift\q,\qlocks\q:true,\qlockIsTemporary\q:true,\qevents\q:{\qkeydown\q:{\qkeyCode\q:\qKEY_RSHIFT\q}}},{\qtype\q:\qkey\q,\qoffsetX\q:59,\qoffsetY\q:0,\qwidth\q:9,\qheight\q:6,\qlabel\q:\qAlt\q,\qlocks\q:true,\qlockIsTemporary\q:true,\qevents\q:{\qkeydown\q:{\qkeyCode\q:\qKEY_RALT\q}}},{\qtype\q:\qkey\q,\qoffsetX\q:17,\qoffsetY\q:0,\qwidth\q:8,\qheight\q:6,\qlabel\q:\qAlt\q,\qlocks\q:true,\qlockIsTemporary\q:true,\qevents\q:{\qkeydown\q:{\qkeyCode\q:\qKEY_LALT\q}}},{\qtype\q:\qkey\q,\qoffsetX\q:9,\qoffsetY\q:0,\qwidth\q:8,\qheight\q:6,\qlabel\q:\q\u2302\q,\qlocks\q:false,\qlockIsTemporary\q:false,\qevents\q:{\qkeydown\q:{\qkeyCode\q:\qKEY_LSUPER\q}}},{\qtype\q:\qkey\q,\qoffsetX\q:0,\qoffsetY\q:0,\qwidth\q:9,\qheight\q:6,\qlabel\q:\qCtrl\q,\qlocks\q:true,\qlockIsTemporary\q:true,\qevents\q:{\qkeydown\q:{\qkeyCode\q:\qKEY_LCTRL\q}}},{\qtype\q:\qkey\q,\qoffsetX\q:24,\qoffsetY\q:24,\qwidth\q:6,\qheight\q:6,\qlabel\q:\q4\q,\qlocks\q:false,\qlockIsTemporary\q:false,\qevents\q:{\qkeydown\q:{\qkeyCode\q:\qKEY_4\q},\qkeydownWithShift\q:{\qkeyCode\q:\qKEY_DOLLAR\q,\qlabel\q:\q$\q}}},{\qtype\q:\qkey\q,\qoffsetX\q:18,\qoffsetY\q:24,\qwidth\q:6,\qheight\q:6,\qlabel\q:\q3\q,\qlocks\q:false,\qlockIsTemporary\q:false,\qevents\q:{\qkeydown\q:{\qkeyCode\q:\qKEY_3\q},\qkeydownWithShift\q:{\qkeyCode\q:\qKEY_HASH\q,\qlabel\q:\q#\q}}},{\qtype\q:\qkey\q,\qoffsetX\q:30,\qoffsetY\q:24,\qwidth\q:6,\qheight\q:6,\qlabel\q:\q5\q,\qlocks\q:false,\qlockIsTemporary\q:false,\qevents\q:{\qkeydown\q:{\qkeyCode\q:\qKEY_5\q},\qkeydownWithShift\q:{\qkeyCode\q:\qKEY_PERCENT\q,\qlabel\q:\q%\q}}},{\qtype\q:\qkey\q,\qoffsetX\q:36,\qoffsetY\q:24,\qwidth\q:6,\qheight\q:6,\qlabel\q:\q6\q,\qlocks\q:false,\qlockIsTemporary\q:false,\qevents\q:{\qkeydown\q:{\qkeyCode\q:\qKEY_6\q},\qkeydownWithShift\q:{\qkeyCode\q:\qKEY_CARET\q,\qlabel\q:\q^\q}}},{\qtype\q:\qkey\q,\qoffsetX\q:42,\qoffsetY\q:24,\qwidth\q:6,\qheight\q:6,\qlabel\q:\q7\q,\qlocks\q:false,\qlockIsTemporary\q:false,\qevents\q:{\qkeydown\q:{\qkeyCode\q:\qKEY_7\q},\qkeydownWithShift\q:{\qkeyCode\q:\qKEY_AND\q,\qlabel\q:\q&\q}}},{\qtype\q:\qkey\q,\qoffsetX\q:48,\qoffsetY\q:24,\qwidth\q:6,\qheight\q:6,\qlabel\q:\q8\q,\qlocks\q:false,\qlockIsTemporary\q:false,\qevents\q:{\qkeydown\q:{\qkeyCode\q:\qKEY_8\q},\qkeydownWithShift\q:{\qkeyCode\q:\qKEY_STAR\q,\qlabel\q:\q*\q}}},{\qtype\q:\qkey\q,\qoffsetX\q:54,\qoffsetY\q:24,\qwidth\q:6,\qheight\q:6,\qlabel\q:\q9\q,\qlocks\q:false,\qlockIsTemporary\q:false,\qevents\q:{\qkeydown\q:{\qkeyCode\q:\qKEY_9\q},\qkeydownWithShift\q:{\qkeyCode\q:\qKEY_OPEN_BRACKET\q,\qlabel\q:\q(\q}}},{\qtype\q:\qkey\q,\qoffsetX\q:60,\qoffsetY\q:24,\qwidth\q:6,\qheight\q:6,\qlabel\q:\q0\q,\qlocks\q:false,\qlockIsTemporary\q:false,\qevents\q:{\qkeydown\q:{\qkeyCode\q:\qKEY_0\q},\qkeydownWithShift\q:{\qkeyCode\q:\qKEY_CLOSE_BRACKET\q,\qlabel\q:\q)\q}}},{\qtype\q:\qkey\q,\qoffsetX\q:66,\qoffsetY\q:24,\qwidth\q:6,\qheight\q:6,\qlabel\q:\q-\q,\qlocks\q:false,\qlockIsTemporary\q:false,\qevents\q:{\qkeydown\q:{\qkeyCode\q:\qKEY_MINUS\q},\qkeydownWithShift\q:{\qkeyCode\q:\qKEY_UNDERSCORE\q,\qlabel\q:\q_\q}}},{\qtype\q:\qkey\q,\qoffsetX\q:72,\qoffsetY\q:24,\qwidth\q:6,\qheight\q:6,\qlabel\q:\q=\q,\qlocks\q:false,\qlockIsTemporary\q:false,\qevents\q:{\qkeydown\q:{\qkeyCode\q:\qKEY_EQUAL\q},\qkeydownWithShift\q:{\qkeyCode\q:\qKEY_PLUS\q,\qlabel\q:\q+\q}}},{\qtype\q:\qkey\q,\qoffsetX\q:78,\qoffsetY\q:24,\qwidth\q:12,\qheight\q:6,\qlabel\q:\qBack Space\q,\qlocks\q:false,\qlockIsTemporary\q:false,\qevents\q:{\qkeydown\q:{\qkeyCode\q:\qKEY_BACKSPACE\q}}},{\qtype\q:\qkey\q,\qoffsetX\q:0,\qoffsetY\q:18,\qwidth\q:9,\qheight\q:6,\qlabel\q:\qTab\q,\qlocks\q:false,\qlockIsTemporary\q:false,\qevents\q:{\qkeydown\q:{\qkeyCode\q:\qKEY_TAB\q}}},{\qtype\q:\qkey\q,\qoffsetX\q:0,\qoffsetY\q:12,\qwidth\q:11,\qheight\q:6,\qlabel\q:\qCaps Lock\q,\qlocks\q:true,\qlockIsTemporary\q:false,\qevents\q:{\qkeydown\q:{\qkeyCode\q:\qKEY_CAPSLOCK\q}}},{\qtype\q:\qkey\q,\qoffsetX\q:0,\qoffsetY\q:6,\qwidth\q:14,\qheight\q:6,\qlabel\q:\qShift\q,\qlocks\q:true,\qlockIsTemporary\q:true,\qevents\q:{\qkeydown\q:{\qkeyCode\q:\qKEY_LSHIFT\q}}},{\qtype\q:\qkey\q,\qoffsetX\q:86,\qoffsetY\q:0,\qwidth\q:4,\qheight\q:6,\qlabel\q:\qEsc\q,\qlocks\q:false,\qlockIsTemporary\q:false,\qevents\q:{\qkeydown\q:{\qkeyCode\q:\qKEY_ESCAPE\q}}},{\qtype\q:\qkey\q,\qoffsetX\q:25,\qoffsetY\q:0,\qwidth\q:34,\qheight\q:6,\qlabel\q:\q\q,\qlocks\q:false,\qlockIsTemporary\q:false,\qevents\q:{\qkeydown\q:{\qkeyCode\q:\qKEY_SPACE\q}}}]}"
keyset = QB_NODESET_deserialize(VkGetQuotedString(json$), "json")
VkLoadKeys QB_NODESET_node(QB_NODESET_label_equal(QB_NODESET_children(keyset), "keys")), i2
FOR i3 = 1 TO VkLast
IF VK(i2).active THEN
IF VK(i3).parent = i2 THEN
VK(i3).offsetY = VK(i3).offsetY - VkDefaultWidth * 5
END IF
END IF
NEXT
VkPress (VkByRole("ROOT"))
VkPress (VkByRole("ROOT"))
VkSelectedKey = i2
EXIT SUB
END IF
IF VK(i).event.keydown = -1000 THEN 'F1-F12
json$ = "{\qkeys\q:[{\qtype\q:\qkey\q,\qoffsetX\q:66,\qoffsetY\q:0,\qwidth\q:6,\qheight\q:6,\qlabel\q:\qF12\q,\qlocks\q:false,\qlockIsTemporary\q:false,\qevents\q:{\qkeydown\q:{\qkeyCode\q:\qKEY_F12\q}}},{\qtype\q:\qkey\q,\qoffsetX\q:60,\qoffsetY\q:0,\qwidth\q:6,\qheight\q:6,\qlabel\q:\qF11\q,\qlocks\q:false,\qlockIsTemporary\q:false,\qevents\q:{\qkeydown\q:{\qkeyCode\q:\qKEY_F11\q}}},{\qtype\q:\qkey\q,\qoffsetX\q:54,\qoffsetY\q:0,\qwidth\q:6,\qheight\q:6,\qlabel\q:\qF10\q,\qlocks\q:false,\qlockIsTemporary\q:false,\qevents\q:{\qkeydown\q:{\qkeyCode\q:\qKEY_F10\q}}},{\qtype\q:\qkey\q,\qoffsetX\q:48,\qoffsetY\q:0,\qwidth\q:6,\qheight\q:6,\qlabel\q:\qF9\q,\qlocks\q:false,\qlockIsTemporary\q:false,\qevents\q:{\qkeydown\q:{\qkeyCode\q:\qKEY_F9\q}}},{\qtype\q:\qkey\q,\qoffsetX\q:42,\qoffsetY\q:0,\qwidth\q:6,\qheight\q:6,\qlabel\q:\qF8\q,\qlocks\q:false,\qlockIsTemporary\q:false,\qevents\q:{\qkeydown\q:{\qkeyCode\q:\qKEY_F8\q}}},{\qtype\q:\qkey\q,\qoffsetX\q:36,\qoffsetY\q:0,\qwidth\q:6,\qheight\q:6,\qlabel\q:\qF7\q,\qlocks\q:false,\qlockIsTemporary\q:false,\qevents\q:{\qkeydown\q:{\qkeyCode\q:\qKEY_F7\q}}},{\qtype\q:\qkey\q,\qoffsetX\q:30,\qoffsetY\q:0,\qwidth\q:6,\qheight\q:6,\qlabel\q:\qF6\q,\qlocks\q:false,\qlockIsTemporary\q:false,\qevents\q:{\qkeydown\q:{\qkeyCode\q:\qKEY_F6\q}}},{\qtype\q:\qkey\q,\qoffsetX\q:24,\qoffsetY\q:0,\qwidth\q:6,\qheight\q:6,\qlabel\q:\qF5\q,\qlocks\q:false,\qlockIsTemporary\q:false,\qevents\q:{\qkeydown\q:{\qkeyCode\q:\qKEY_F5\q}}},{\qtype\q:\qkey\q,\qoffsetX\q:18,\qoffsetY\q:0,\qwidth\q:6,\qheight\q:6,\qlabel\q:\qF4\q,\qlocks\q:false,\qlockIsTemporary\q:false,\qevents\q:{\qkeydown\q:{\qkeyCode\q:\qKEY_F4\q}}},{\qtype\q:\qkey\q,\qoffsetX\q:12,\qoffsetY\q:0,\qwidth\q:6,\qheight\q:6,\qlabel\q:\qF3\q,\qlocks\q:false,\qlockIsTemporary\q:false,\qevents\q:{\qkeydown\q:{\qkeyCode\q:\qKEY_F3\q}}},{\qtype\q:\qkey\q,\qoffsetX\q:6,\qoffsetY\q:0,\qwidth\q:6,\qheight\q:6,\qlabel\q:\qF2\q,\qlocks\q:false,\qlockIsTemporary\q:false,\qevents\q:{\qkeydown\q:{\qkeyCode\q:\qKEY_F2\q}}},{\qtype\q:\qkey\q,\qoffsetX\q:0,\qoffsetY\q:0,\qwidth\q:6,\qheight\q:6,\qlabel\q:\qF1\q,\qlocks\q:false,\qlockIsTemporary\q:false,\qevents\q:{\qkeydown\q:{\qkeyCode\q:\qKEY_F1\q}}}]}"
keyset = QB_NODESET_deserialize(VkGetQuotedString(json$), "json")
VkLoadKeys QB_NODESET_node(QB_NODESET_label_equal(QB_NODESET_children(keyset), "keys")), i2
FOR i3 = 1 TO VkLast
IF VK(i2).active THEN
IF VK(i3).parent = i2 THEN
VK(i3).offsetY = VK(i3).offsetY - VkDefaultWidth * 1
END IF
END IF
NEXT
VkPress (VkByRole("ROOT"))
VkPress (VkByRole("ROOT"))
VkSelectedKey = i2
EXIT SUB
END IF
addingNewKey = 0
IF VkSelectedKey <> 0 THEN
i2 = VkSelectedKey
ELSE
addingNewKey = 1
i2 = VkNew
VK(i2).x = VK(i3).x + VkDefaultWidth * 0 + 1
VK(i2).y = VK(i3).y - VkDefaultWidth * 1
END IF
' hasShiftedEvent AS LONG
' shiftedEvent AS VKEY_EVENT 'eg. when shifted or caps lock is on
' shiftedLabel AS STRING * 100
'VkAddShiftedKey
label$ = RTRIM$(VK(i).label)
IF INSTR(label$, " (") > 1 AND INSTR(label$, ")") > 1 THEN
'strip meta info
label$ = LEFT$(label$, INSTR(label$, " (") - 1)
END IF
IF VkAddShiftedKey THEN
VkAddShiftedKey = 0
VK(i2).hasShiftedEvent = 1
VkReLabelShifted i2, label$
VK(i2).shiftedEvent.keydown = VK(i).event.keydown
ELSE
VkReLabel i2, label$
VK(i2).event.keydown = VK(i).event.keydown
VK(i2).locks = VK(i).locks
VK(i2).lockIsTemporary = VK(i).lockIsTemporary
END IF
'for a-z & A-Z automatically add their shifted key codes
IF addingNewKey <> 0 AND VkAddShiftedKey = 0 THEN
keyCode = VK(i).event.keydown
shiftedKeyCode = keyCode
IF keyCode >= 97 AND keyCode <= 122 THEN shiftedKeyCode = keyCode - 32
IF keyCode >= 65 AND keyCode <= 90 THEN shiftedKeyCode = keyCode + 32
IF shiftedKeyCode <> keyCode THEN
VK(i2).hasShiftedEvent = 1
VK(i2).shiftedEvent.keydown = shiftedKeyCode
VK(i2).shiftedLabel = CHR$(shiftedKeyCode)
END IF
END IF
VK(i2).role = "USER"
VkPress (VkByRole("ROOT"))
VkPress (VkByRole("ROOT"))
VkSelectedKey = i2
EXIT SUB
END IF
END SUB
FUNCTION VkNew
VkReDraw = 1
i2 = 0
FOR i = 1 TO VkLast
IF VK(i).active = 0 THEN
i2 = i
END IF
NEXT
IF i2 = 0 THEN i2 = i: VkLast = i
i = i2
VK(i) = VkEmpty
VK(i).active = 1
VK(i).x = 0
VK(i).y = 0
VK(i).w = VkDefaultWidth
VK(i).h = VkUnitStepY
VK(i).role = "UNKN"
VkNew = i
END FUNCTION
SUB VkRemove (i)
VkReDraw = 1
VK(i).active = 0
IF VK(i).image THEN _FREEIMAGE VK(i).image
IF VK(i).subImage THEN _FREEIMAGE VK(i).subImage
IF VK(i).highlightImage THEN _FREEIMAGE VK(i).highlightImage
IF VK(i).selectedImage THEN _FREEIMAGE VK(i).selectedImage
END SUB
SUB VkRemoveInternal
FOR i = 1 TO VkLast
IF VK(i).active THEN
IF VK(i).internal THEN
IF VK(i).role <> "ROOT" THEN
VkRemove i
END IF
END IF
END IF
NEXT
END SUB
FUNCTION VkByRole (role$)
FOR i = 1 TO VkLast
IF VK(i).active = 1 THEN
IF VK(i).role = role$ THEN VkByRole = i: EXIT FUNCTION
END IF
NEXT
END FUNCTION
SUB VkLongPress (i)
'avoid using long press for now because Windows delays MOUSEDOWN to MOUSEUP on touch
VkPress i
END SUB
SUB VkKeyRepeat (i)
keydown VK(i).keyRepeatKeyCode
VK(i).lastKeydownTime = TIMER
VK(i).keyRepeatCount = VK(i).keyRepeatCount + 1
END SUB
SUB VkKeyDown (i)
VkReDraw = 1
'called whenever user key down
IF VK(i).internal = 0 THEN
rt = VkByRole("ROOT")
IF VK(rt).locked = 0 THEN 'not in edit mode
keydownvalue = VK(i).event.keydown
IF VK(i).hasShiftedEvent THEN
IF VkShiftInEffect THEN keydownvalue = VK(i).shiftedEvent.keydown
END IF
IF keydownvalue <> 0 THEN
IF VK(i).locks <> 0 OR VK(i).lockIsTemporary <> 0 THEN
IF VK(i).locked <> 0 THEN
keyup keydownvalue
VK(i).locked = 0
VK(i).held = 0
ELSE
keydown keydownvalue
VK(i).locked = 1
VK(i).held = 1
END IF
ELSE
VK(i).held = 1
keydown keydownvalue
VK(i).lastKeydownTime = TIMER
VK(i).keyRepeatKeyCode = keydownvalue
VK(i).keyRepeatCount = 0
END IF
END IF
END IF
IF VK(i).locks = 0 THEN
FOR i2 = 1 TO VkLast
IF VK(i2).active THEN
IF VK(i2).internal = 0 THEN
IF i <> i2 THEN
IF VK(i2).locks THEN
IF VK(i2).locked THEN
IF VK(i2).lockIsTemporary THEN
VkKeyDown i2
END IF
END IF
END IF
END IF
END IF
END IF
NEXT
END IF
ELSE
VK(i).held = 1
END IF
END SUB
SUB VkKeyUp (i)
VkReDraw = 1
'called whenever user key down
IF VK(i).internal = 0 THEN
rt = VkByRole("ROOT")
IF VK(rt).locked = 0 THEN 'not in edit mode
keydownvalue = VK(i).event.keydown
IF VK(i).hasShiftedEvent THEN
IF VkShiftInEffect THEN keydownvalue = VK(i).shiftedEvent.keydown
END IF
IF keydownvalue <> 0 THEN
IF VK(i).locks <> 0 OR VK(i).lockIsTemporary <> 0 THEN
'do nothing
ELSE
keyup keydownvalue
VK(i).held = 0
END IF
END IF
END IF
ELSE
VK(i).held = 0
END IF
END SUB
SUB VkUpdate
if VkDelay>0 then
VkTimeNow#=TIMER(0.001)
if VkTimeNow#<VkDelayStartTime OR VkTimeNow#>=VkDelayStartTime+VkDelay THEN VkDelay=0
exit sub
end if
if vkExited then
DO WHILE _MOUSEINPUT(VkMousePipe)
_MOUSEINPUTPIPE VkMousePipe
LOOP
exit sub
end if
if VkExiting=1 then VkExiting=2
subOldDest = _DEST
subOldSource = _SOURCE
reDraw = VkReDraw
VkReDraw = 0
IF reDraw THEN
'SOUND 1000, .1
END IF
STATIC VkI
STATIC VKoldX
STATIC VKoldY
STATIC VKdragging
STATIC VKstart
STATIC mDownX
STATIC mDownY
STATIC omb
STATIC mb, mx, my
STATIC sx, sy
STATIC VkInit
'theme colors
'for user keys:
textCol& = _RGBA32(255, 255, 255, 192)
borderCol& = _RGBA32(32, 32, 32, 192)
borderSelectedCol& = _RGBA32(255, 255, 255, 192)
bgCol& = _RGBA32(96, 96, 96, 128)
bgHighlightCol& = _RGBA32(128, 128, 128, 128)
'for customization:
InternalTextCol& = _RGBA32(255, 255, 255, 255)
InternalBorderCol& = _RGBA32(255, 255, 255, 192)
InternalBgCol& = _RGBA32(0, 0, 0, 192)
InternalBgHighlightCol& = _RGBA32(128, 128, 128, 128)
'Init is done once
IF VkInit = 0 THEN
VkWidthInUnits = 90 'default width in units (may be changed by loading a layout)
VkReset = 1
END IF
winX = _SCALEDWIDTH
winY = _SCALEDHEIGHT
IF winX <> VkWinX OR winY <> VkWinY THEN
'store new resolution
VkWinX = winX
VkWinY = winY
'clear overlay image (if one exists yet)
if VkOverlay then
_PUTIMAGE , VkClearTex, VkOverlay
end if
'beging a delay (wait until screen has fully repositioned)
VkDelayStartTime=TIMER(0.001)
VkDelay=1
VkDelayedReset=1
exit sub
END IF
if VkDelayedReset=1 then
VkDelayedReset=0
VkReset = 1
end if
'Reset occurs whenever the screen size changes
IF VkReset = 1 THEN
VkReset = 0
'get new dimensions
VkWinX = winX
VkWinY = winY
'PRINT winX, winY
' END
sx = VkWinX: sy = VkWinY 'shortcuts
'we need to free the old overlay & backbuffer, but because they might be
'in use we cannot do it immediately
VkOverlay32 = _NEWIMAGE(VkWinX, VkWinY, 32)
VkOverlay = _COPYIMAGE(VkOverlay32, 33)
VkBackbuffer = _COPYIMAGE(VkOverlay32, 33)
_FREEIMAGE VkOverlay32
VkUnitSize = sx / VkWidthInUnits
h = CINT(VkUnitStepY * VkUnitSize * 0.5)
'VkFont = _LOADFONT("c:\windows\fonts\lucon.ttf", CINT(h))
'VkFontSmall = _LOADFONT("c:\windows\fonts\lucon.ttf", CINT(h * 0.5))
'generic textures
VkReDraw = 1
FOR i = 1 TO VkLast
IF VK(i).active THEN
VK(i).reDraw = 1
END IF
NEXT
END IF 'reset
IF VkInit = 0 THEN
VkClearTex = VkColTex(_RGBA32(0, 0, 0, 0)): _DONTBLEND VkClearTex
i = VkNew
VK(i).x = 0 'VkDefaultWidth
VK(i).y = VkUnitStepY * 4 '*** do not modify or scaled up keybaord will be off screen***
VK(i).w = VkDefaultWidth
VK(i).h = VkUnitStepY
VK(i).role = "ROOT"
VK(i).internal = 1
VK(i).locks = 1
VkReLabel i, "KB" 'CHR$(15)
VkLoad
END IF
VkInit = 1
IF reDraw THEN
'clear backbuffer
_DONTBLEND VkBackbuffer
_PUTIMAGE , VkClearTex, VkBackbuffer
_BLEND VkBackbuffer
'correct offsets of keys relative to parents
FOR i = 1 TO VkLast
IF VK(i).active THEN
p = VK(i).parent
IF p THEN
VK(i).x = VK(p).x + VK(i).offsetX
VK(i).y = VK(p).y + VK(i).offsetY
END IF
END IF
NEXT
rt = VkByRole("ROOT")
shiftInEffect = VkShiftInEffect
'render keys
FOR internal = 0 TO 1
FOR i = 1 TO VkLast
IF VK(i).active THEN
IF VK(i).internal = internal AND (VK(i).event.keydown <> -2 OR VK(rt).locked <> 0) and (internal=1 or vkHide=0) THEN
x = VK(i).x * VkUnitSize
y = VK(i).y * VkUnitSize
w = VK(i).w
h = VK(i).h
x1 = INT(x)
x2 = INT(x + VkUnitSize * w) - 1
y1 = sy - 1 - INT(y)
y2 = sy - 1 - INT(y + VkUnitSize * h) + 1
w2 = x2 - x1 + 1 'pixel metrics
h2 = y1 - y2 + 1
'get key colors
cText& = textCol&
cBorder& = borderCol&
cBg& = bgCol&
cBgHighlight& = bgHighlightCol&
IF VK(i).internal THEN
cText& = InternalTextCol&
cBorder& = InternalBorderCol&
cBg& = InternalBgCol&
cBgHighlight& = InternalBgHighlightCol&
END IF
IF VK(i).event.keydown = -1 AND VK(i).internal = 0 THEN 'D-PAD
're-calculate dimensions
x = (VK(i).x - VkDefaultWidth) * VkUnitSize
y = (VK(i).y - VkUnitStepY) * VkUnitSize
w = VK(i).w * 3
h = VK(i).h * 3
x1 = INT(x)
x2 = INT(x + VkUnitSize * w) - 1
y1 = sy - 1 - INT(y)
y2 = sy - 1 - INT(y + VkUnitSize * h) + 1
w2 = x2 - x1 + 1 'pixel metrics
h2 = y1 - y2 + 1
create = 0
IF VK(i).image <> 0 AND create = 0 THEN
'has required size changed?
iw = _WIDTH(VK(i).image)
ih = _HEIGHT(VK(i).image)
IF iw <> w2 OR ih <> h2 THEN
create = 1
END IF
END IF
IF VK(i).reDraw THEN VK(i).reDraw = 0: create = 1
IF create THEN
'invalidate
IF VK(i).image <> 0 THEN _FREEIMAGE VK(i).image: VK(i).image = 0
IF VK(i).subImage <> 0 THEN _FREEIMAGE VK(i).subImage: VK(i).subImage = 0
END IF
IF VK(i).image = 0 THEN
'soft render base
defKey = _NEWIMAGE(w2, h2, 32)
_DEST defKey
_DONTBLEND
dpcx = w2 \ 2: dpcy = h2 \ 2
dprad = w2 \ 2 - 3
CIRCLE (dpcx, dpcy), dprad, _RGBA32(255, 255, 255, 255)
PAINT (dpcx, dpcy), cBg&, _RGBA32(255, 255, 255, 255)
'CIRCLE (dpcx, dpcy), dprad, _RGBA32(_RED32(cBg&), _GREEN32(cBg&), _BLUE32(cBg&), _ALPHA32(cBg&) * 0.75)
a = _ALPHA32(cBg&)
FOR r = dprad TO dprad + 10 STEP 0.15
a = a - 10
IF a < 0 THEN EXIT FOR
CIRCLE (dpcx, dpcy), r, _RGBA32(_RED32(cBg&), _GREEN32(cBg&), _BLUE32(cBg&), a)
NEXT
_BLEND
'conv to hw
VK(i).image = _COPYIMAGE(defKey, 33)
_FREEIMAGE defKey
'soft render stick
defKey = _NEWIMAGE(w2, h2, 32)
_DEST defKey
_DONTBLEND
dprad = dprad / 2.5
CIRCLE (dpcx, dpcy), dprad, _RGBA32(255, 255, 255, 255)
PAINT (dpcx, dpcy), _RGBA32(255, 255, 255, 128), _RGBA32(255, 255, 255, 255)
a = 128
FOR r = dprad TO dprad + 10 STEP 0.15
a = a - 10
IF a < 0 THEN EXIT FOR
CIRCLE (dpcx, dpcy), r, _RGBA32(255, 255, 255, a)
NEXT
_BLEND
'conv to hw
VK(i).subImage = _COPYIMAGE(defKey, 33)
_FREEIMAGE defKey
END IF
dpadx = VK(i).dpad.x: dpady = VK(i).dpad.y
IF VkHide = 0 OR VK(i).internal <> 0 THEN
_PUTIMAGE (x1, y2), VK(i).image, VkBackbuffer
_PUTIMAGE (x1 + dpadx * VkUnitSize * VkDefaultWidth * 0.89, y2 + dpady * VkUnitSize * VkDefaultWidth * 0.89), VK(i).subImage, VkBackbuffer
END IF
GOTO special_key
END IF
'standard key
create = 0
IF VK(i).image <> 0 AND create = 0 THEN
'has required size changed?
iw = _WIDTH(VK(i).image)
ih = _HEIGHT(VK(i).image)
IF iw <> w2 OR ih <> h2 THEN
create = 1
END IF
END IF
IF VK(i).reDraw THEN VK(i).reDraw = 0: create = 1
IF create THEN
'invalidate
IF VK(i).image <> 0 THEN _FREEIMAGE VK(i).image: VK(i).image = 0
IF VK(i).highlightImage <> 0 THEN _FREEIMAGE VK(i).highlightImage: VK(i).highlightImage = 0
IF VK(i).selectedImage <> 0 THEN _FREEIMAGE VK(i).selectedImage: VK(i).selectedImage = 0
END IF
IF VK(i).image = 0 THEN
'soft render default key
FOR shiftedPass = 0 TO 1
IF shiftedPass = 0 OR (shiftedPass = 1 AND VK(i).hasShiftedEvent <> 0) THEN
FOR pass = 1 TO 3
defKey = _NEWIMAGE(w2, h2, 32)
_DEST defKey
_DONTBLEND
IF pass <> 2 THEN LINE (0, 0)-(w2 - 1, h2 - 1), cBg&, BF
IF pass = 2 THEN LINE (0, 0)-(w2 - 1, h2 - 1), cBgHighlight&, BF
IF pass <> 3 THEN
LINE (0, 0)-(w2 - 1, h2 - 1), cBorder&, B
ELSE
LINE (0, 0)-(w2 - 1, h2 - 1), borderSelectedCol&, B
END IF
_BLEND
'add text
'convert label to image
text$ = RTRIM$(VK(i).label)
IF shiftedPass THEN text$ = RTRIM$(VK(i).shiftedLabel)
text2$ = ""
IF text$ <> "" THEN
lines = 1
IF INSTR(text$, " ") THEN
lines = 2
text2$ = RIGHT$(text$, LEN(text$) - INSTR(text$, " "))
text$ = LEFT$(text$, INSTR(text$, " ") - 1)
END IF
defKeyHeightInPixels = VkUnitStepY * VkUnitSize
'42.6 for screen 0 80x25
font = VkFindFont(INT(defKeyHeightInPixels / 2)) 'ideally 20 for 80x25
IF lines = 2 OR LEN(text$) >= 2 AND text$ <> "KB" THEN
font = VkFindFont(INT(defKeyHeightInPixels / 3.5)) 'ideally 12 for 80x25
END IF
_FONT font
cw = _PRINTWIDTH(text$)
IF lines = 2 THEN
cw2 = _PRINTWIDTH(text2$)
IF cw2 > cw THEN cw = cw2
END IF
ch = _FONTHEIGHT
IF cw <> 0 AND ch <> 0 THEN
ox = w2 \ 2 - cw \ 2
oy = h2 \ 2 - (ch * lines) \ 2
' _PUTIMAGE ((x1 + x2) / 2 - cw / 2, (y1 + y2) / 2 - ch / 2), ci33, VkBackbuffer
_PRINTMODE _KEEPBACKGROUND
COLOR cText&
_CONTROLCHR OFF
_PRINTSTRING (ox, oy), text$
IF text2$ <> "" THEN _PRINTSTRING (ox, oy + ch), text2$
_CONTROLCHR ON
END IF 'cw <> 0 AND ch <> 0
END IF 'text$<>""
' _FONT font
' cw = _PRINTWIDTH(text$)
' IF lines = 2 THEN
' cw2 = _PRINTWIDTH(text2$)
' IF cw2 > cw THEN cw = cw2
' END IF
' ch = _FONTHEIGHT
' ' GOTO 1
' IF cw = 0 OR ch = 0 THEN GOTO 1
' ci = _NEWIMAGE(cw, ch * lines, 32)
' _DEST ci
' _FONT font
' _PRINTMODE _KEEPBACKGROUND
' COLOR textCol&
' _CONTROLCHR OFF
' _PRINTSTRING (0, 0), text$
' _PRINTSTRING (0, ch), text2$
' _CONTROLCHR ON
'IF VK(i).held THEN
' cBg& = cBgHighlight&
'END IF
'bgTex = VkColTex(bgCol&)
'borderTex = VkColTex(borderCol&)
''PRINT x1, y1, x2, y2
'_PUTIMAGE (x1 + 1, y2 + 1)-(x2 - 1, y1 - 1), bgTex, VkBackbuffer
'_PUTIMAGE (x1, y2)-(x2, y2), borderTex, VkBackbuffer
'_PUTIMAGE (x1, y2 + 1)-(x1, y1), borderTex, VkBackbuffer
'_PUTIMAGE (x2, y2 + 1)-(x2, y1), borderTex, VkBackbuffer
'_PUTIMAGE (x1 + 1, y1)-(x2 - 1, y1), borderTex, VkBackbuffer
''LINE (x1, y1)-(x2, y2), borderCol&, B
'' _BLEND
'' _BLEND bgTex
'IF g = 0 THEN
' g = 1
' ' _PUTIMAGE (0, 0)-(100, 100), bgTex
' ' _PUTIMAGE (50, 50)-(150, 150), borderTex
'END IF
'_FREEIMAGE bgTex
'_FREEIMAGE borderTex
'conv to hw
IF shiftedPass = 0 THEN
IF pass = 1 THEN VK(i).image = _COPYIMAGE(defKey, 33)
IF pass = 2 THEN VK(i).highlightImage = _COPYIMAGE(defKey, 33)
IF pass = 3 THEN VK(i).selectedImage = _COPYIMAGE(defKey, 33)
ELSE
IF pass = 1 THEN VK(i).shiftedImage = _COPYIMAGE(defKey, 33)
IF pass = 2 THEN VK(i).shiftedHighlightImage = _COPYIMAGE(defKey, 33)
IF pass = 3 THEN VK(i).shiftedSelectedImage = _COPYIMAGE(defKey, 33)
END IF
_FREEIMAGE defKey
NEXT 'pass
END IF
NEXT 'shiftedPass
'SOUND 1000, 0.1
END IF
'assume shift in effect
shifted = 0
IF VK(i).hasShiftedEvent THEN
IF shiftInEffect THEN
shifted = 1
END IF
END IF
IF VkHide = 0 OR VK(i).internal <> 0 THEN
IF shifted THEN
IF VkSelectedKey = i AND VK(rt).locked <> 0 THEN
_PUTIMAGE (x1, y2), VK(i).shiftedSelectedImage, VkBackbuffer
ELSE
IF VK(i).locks THEN
IF VK(i).locked THEN
_PUTIMAGE (x1, y2), VK(i).shiftedHighlightImage, VkBackbuffer
ELSE
_PUTIMAGE (x1, y2), VK(i).shiftedImage, VkBackbuffer
END IF
ELSE
IF VK(i).held THEN
_PUTIMAGE (x1, y2), VK(i).shiftedHighlightImage, VkBackbuffer
ELSE
_PUTIMAGE (x1, y2), VK(i).shiftedImage, VkBackbuffer
END IF
END IF
END IF
ELSE
IF VkSelectedKey = i AND VK(rt).locked <> 0 THEN
_PUTIMAGE (x1, y2), VK(i).selectedImage, VkBackbuffer
ELSE
IF VK(i).locks THEN
IF VK(i).locked THEN
_PUTIMAGE (x1, y2), VK(i).highlightImage, VkBackbuffer
ELSE
_PUTIMAGE (x1, y2), VK(i).image, VkBackbuffer
END IF
ELSE
IF VK(i).held THEN
_PUTIMAGE (x1, y2), VK(i).highlightImage, VkBackbuffer
ELSE
_PUTIMAGE (x1, y2), VK(i).image, VkBackbuffer
END IF
END IF
END IF
END IF
END IF
''convert label to image
'text$ = RTRIM$(VK(i).label)
'IF text$ <> "" THEN
' lines = 1
' IF INSTR(text$, " ") THEN
' lines = 2
' text2$ = RIGHT$(text$, LEN(text$) - INSTR(text$, " "))
' text$ = LEFT$(text$, INSTR(text$, " ") - 1)
' END IF
' font = VkFont
' IF lines = 2 OR LEN(text$) > 1 THEN
' font = VkFontSmall
' END IF
' STATIC dummy32
' IF dummy32 = 0 THEN
' dummy32 = _NEWIMAGE(1, 1, 32)
' END IF
' olddest = _DEST
' _DEST dummy32
' _FONT font
' cw = _PRINTWIDTH(text$)
' IF lines = 2 THEN
' cw2 = _PRINTWIDTH(text2$)
' IF cw2 > cw THEN cw = cw2
' END IF
' ch = _FONTHEIGHT
' ' GOTO 1
' IF cw = 0 OR ch = 0 THEN GOTO 1
' ci = _NEWIMAGE(cw, ch * lines, 32)
' _DEST ci
' _FONT font
' _PRINTMODE _KEEPBACKGROUND
' COLOR textCol&
' _CONTROLCHR OFF
' _PRINTSTRING (0, 0), text$
' _PRINTSTRING (0, ch), text2$
' _CONTROLCHR ON
' ch = ch * lines
' ci33 = _COPYIMAGE(ci, 33)
' _FREEIMAGE ci
' 'IF VkFontScale = 1 THEN
' _PUTIMAGE ((x1 + x2) / 2 - cw / 2, (y1 + y2) / 2 - ch / 2), ci33, VkBackbuffer
' 'ELSE
' 'cw = cw / VkFontScale
' 'ch = ch / VkFontScale
' '_PUTIMAGE ((x1 + x2) / 2 - cw / 2, (y1 + y2) / 2 - ch / 2)-((x1 + x2) / 2 + cw / 2 - 1, (y1 + y2) / 2 + ch / 2 - 1), ci33, VkBackbuffer, , _SMOOTH
' 'END IF
' _FREEIMAGE ci33
' 1
' _DEST olddest
special_key:
' _DEST olddest
' END IF
END IF
END IF
NEXT
NEXT
'_PUTIMAGE (mx, my)-(mx + 100, my + 100), borderTex, VkBackbuffer
'_PUTIMAGE , VkBackbuffer, VkOverlay
_DONTBLEND VkBackbuffer
_PUTIMAGE , VkBackbuffer, VkOverlay
'_PUTIMAGE (0, 0)-(639, 399), VkOverlay
requestKeyboardOverlayImage VkOverlay
_BLEND VkBackbuffer
END IF 'reDraw
'key repeat
timeNow! = TIMER
FOR i = 1 TO VkLast
IF VK(i).active THEN
IF VK(i).internal = 0 THEN
IF VK(i).lastKeydownTime <> 0 THEN 'only keys which can repeat will have this set
IF VK(i).held THEN
IF VK(i).keyRepeatCount = 0 THEN
IF ABS(VK(i).lastKeydownTime - timeNow!) > VkDelayUntilFirstRepeat THEN
VkKeyRepeat i
END IF
ELSE
IF ABS(VK(i).lastKeydownTime - timeNow!) > VkDelayUntilFollowingRepeats THEN
VkKeyRepeat i
END IF
END IF
END IF
END IF
END IF
END IF
NEXT
DO
mDown = 0
mUp = 0
mEvent = 0
if VkMousePipe=0 then
VkMousePipe=_MOUSEPIPEOPEN 'create new pipe
end if
' IF VkSharedInputMode THEN
' VkGetMouse VkSharedMouseMx, VkSharedMouseMy, VkSharedMouseMb
' mb = VkSharedMouseMb
' mb = mb AND 1
' IF mb <> 0 THEN mb = -1
' mx = VkSharedMouseMx
' my = VkSharedMouseMy
' 'CALL INTERRUPT is a problem...
' 'if ((display_page->compatible_mode==1)||(display_page->compatible_mode==7)||(display_page->compatible_mode==13)) cpu.cx*=2;
' 'if (display_page->text){
' ' //note: a range from 0 to columns*8-1 is returned regardless of the number of actual pixels
' ' cpu.cx=(mx-0.5)*8.0;
' ' if (cpu.cx>=(display_page->width*8)) cpu.cx=(display_page->width*8)-1;
' ' //note: a range from 0 to rows*8-1 is returned regardless of the number of actual pixels
' ' //obselete line of code: cpu.dx=(((float)cpu.dx)/((float)(display_page->height*fontheight[display_page->font])))*((float)(display_page->height*8));//(mouse_y/height_in_pixels)*(rows*8)
' ' cpu.dx=(my-0.5)*8.0;
' ' if (cpu.dx>=(display_page->height*8)) cpu.dx=(display_page->height*8)-1;
' '}
' 'reverse adjustments made by CALL INTERRUPT
' IF _PIXELSIZE = 1 THEN 'legacy modes adjustment
' mx = mx \ 2
' END IF
' IF _PIXELSIZE = 0 THEN 'screen 0 adjustment
' mx = (mx / 8) + 0.5
' my = (my / 8) + 0.5
' END IF
' 'apply new adjustments
' IF _PIXELSIZE = 0 THEN 'screen 0 adjustment
' mx = mx * 8 - 4
' my = my * 16 - 8
' END IF
' IF mb = -1 AND omb = 0 THEN mDown = -1: mEvent = 1
' IF mb = 0 AND omb = -1 THEN mUp = -1: mEvent = 1
' omb = mb
' ELSE
DO WHILE _MOUSEINPUT(VkMousePipe)
mb = _MOUSEBUTTON(1, VkMousePipe)
mx = _MOUSEX(VkMousePipe)
my = _MOUSEY(VkMousePipe)
sw=_width(0)
sh=_height(0)
IF _PIXELSIZE = 0 THEN 'screen 0 adjustment
mx = mx * 8 - 4
my = my * 16 - 8
sw=sw*8
sh=sh*16
END IF
mx = CINT(mx*(_SCALEDWIDTH/sw))
my = CINT(my*(_SCALEDHEIGHT/sh))
IF mb = -1 AND omb = 0 THEN mDown = -1: mEvent = 1: EXIT DO
if VkMousePipeCapture=0 then
_MOUSEINPUTPIPE VkMousePipe
end if
IF mb = 0 AND omb = -1 THEN
VkMousePipeCapture=0
mUp = -1
mEvent = 1
EXIT DO
end if
LOOP
omb = mb
' END IF
rootId = VkByRole("ROOT")
editMode = VK(rootId).locked
IF mDown THEN
mDownX = mx
mDownY = my
i2 = 0
FOR internal = 1 TO 0 STEP -1
FOR i = VkLast TO 1 STEP -1
IF VK(i).active THEN
IF VK(i).internal = internal THEN
if internal=1 or VkHide=0 then
x = VK(i).x * VkUnitSize
y = VK(i).y * VkUnitSize
w = VK(i).w
h = VK(i).h
x1 = INT(x)
x2 = INT(x + VkUnitSize * w) - 1
y1 = sy - 1 - INT(y)
y2 = sy - 1 - INT(y + VkUnitSize * h) + 1
IF mx >= x1 AND mx <= x2 AND my >= y2 AND my <= y1 THEN
i2 = i
EXIT FOR
END IF
end if
END IF
END IF
NEXT
IF i2 THEN EXIT FOR
NEXT
IF i2 THEN
VkI = i2
VKoldX = VK(i2).x
VKoldY = VK(i2).y
VKdragging = 0
VKstart = TIMER(0.001)
'VK(i2).held = -1
VkKeyDown i2
VkMousePipeCapture=1
END IF
if VkMousePipeCapture=0 then _MOUSEINPUTPIPE VkMousePipe
END IF
IF mUp THEN
IF VkI THEN
IF VK(VkI).event.keydown = -1 THEN
IF editMode = 0 THEN
VkUpdateDPAD VkI, 0, 0
END IF
END IF
VkKeyUp VkI
IF VKdragging = 0 THEN
VKend = TIMER(0.001)
duration = VKend - VKstart
IF duration > 0.5 THEN
VkLongPress (VkI)
ELSE
VkPress (VkI)
END IF
END IF
'VK(VKi).held = 0
VkI = 0
END IF
END IF
rt = VkByRole("ROOT")
IF mb THEN
IF VkI THEN
canMove = 0
IF VK(rt).locked <> 0 OR VK(VkI).internal = 1 THEN canMove = 1
IF canMove = 1 THEN
'calculate distance in units from mouse down location to current location
nx = VKoldX + CINT((mx - mDownX) / VkUnitSize)
ny = VKoldY - CINT((my - mDownY) / VkUnitSize / VkUnitStepY) * VkUnitStepY
distX = ABS(VKoldX - nx)
distY = ABS(VKoldY - ny)
IF distY > distX THEN dist = distY ELSE dist = distX
IF dist >= VkUnitStepY THEN
IF VK(rt).locked <> 0 OR VK(VkI).internal = 1 THEN
VKdragging = -1
'VK(VKi).held = 0
IF VK(VkI).parent <> 0 AND VK(VkI).internal <> 0 THEN
p = VK(VkI).parent
mDownX = mDownX + (VK(VkI).x - VK(p).x) * VkUnitSize
mDownY = mDownY + (VK(p).y - VK(VkI).y) * VkUnitSize
VkI = p
END IF
END IF
END IF
END IF 'canmove=1
'dpad
IF canMove = 0 THEN
IF VK(rt).locked = 0 AND VK(VkI).event.keydown = -1 THEN
'dpad
VKdragging = -1
END IF
END IF
IF VKdragging THEN
IF VK(rt).locked = 0 AND VK(VkI).event.keydown = -1 THEN
dpadx = mx - mDownX '(VK(VkI).x * VkUnitSize + VkUnitSize / 2)
dpady = my - mDownY ' (sy - VK(VkI).y * VkUnitSize - VkUnitSize / 2)
dpadx = dpadx / (VkUnitSize * VkDefaultWidth * 0.9)
dpady = dpady / (VkUnitSize * VkDefaultWidth * 0.9)
'normalize if greater than 1 unit
l = SQR(dpadx * dpadx + dpady * dpady)
IF l > 1 THEN
dpadx = dpadx / l
dpady = dpady / l
END IF
VkUpdateDPAD VkI, dpadx, dpady
'convert dpad value relative to 1/0
ELSE
'prevent off-screen drag
IF nx < 0 THEN nx = 0
IF ny < 0 THEN ny = 0
'prevent covering of other (non-internal) keys
ox = VK(VkI).x
oy = VK(VkI).y
oldOffsetX = VK(VkI).offsetX
oldOffsetY = VK(VkI).offsetY
IF ox <> nx OR oy <> ny THEN
sgnx = SGN(nx - ox): IF sgnx = 0 THEN sgnx = 1
sgny = SGN(ny - oy) * VkUnitStepY: IF sgny = 0 THEN sgny = VkUnitStepY
bestDist = 10000
FOR ix = ox TO nx STEP sgnx
FOR iy = oy TO ny STEP sgny
blocked = 0
IF VK(VkI).event.keydown <> -2 AND VK(VkI).internal = 0 THEN
nw = VK(VkI).w
FOR i = 1 TO VkLast
IF VK(i).internal = 0 AND VK(i).active AND i <> VkI AND VK(i).event.keydown <> -2 THEN
y = VK(i).y: x = VK(i).x: w = VK(i).w
IF iy = y THEN 'same row
ok = 0
IF ix >= x + w THEN ok = 1
IF ix + nw <= x THEN ok = 1
IF ok = 0 THEN blocked = 1
END IF
END IF
NEXT
END IF
IF blocked = 0 THEN
dist = ABS(nx - ix) + ABS(ny - iy)
IF dist < bestDist THEN
bestDist = dist
IF VK(VkI).parent THEN
VK(VkI).offsetX = oldOffsetX + (ix - ox)
VK(VkI).offsetY = oldOffsetY + (iy - oy)
END IF
VK(VkI).x = ix
VK(VkI).y = iy
VkReDraw = 1
END IF
END IF
NEXT
NEXT
END IF
END IF
END IF
END IF
END IF
LOOP UNTIL mEvent = 0
'_DISPLAY
'_LIMIT 30
'k$ = inkey$
'k$ = ""
_DEST subOldDest
_SOURCE subOldSource
if VkExiting=2 then
VkExiting=0
VkExited=1
end if
END SUB
FUNCTION VkColTex& (col&)
i& = _NEWIMAGE(1, 1, 32)
oldDest& = _DEST
_DEST i&
_DONTBLEND
CLS , col&
_BLEND
_DEST oldDest&
VkColTex& = _COPYIMAGE(i&, 33)
_FREEIMAGE i&
END FUNCTION
SUB VkUpdateDPAD (i, x, y)
VkReDraw = 1
ox = VK(i).dpad.x
oy = VK(i).dpad.y
minDist = 0.35 'diagonal max. dist is ~7
odx = VK(i).dpad.dx
ody = VK(i).dpad.dy
dx = 0
IF x <= -minDist THEN dx = -1
IF x >= minDist THEN dx = 1
dy = 0
IF y <= -minDist THEN dy = -1
IF y >= minDist THEN dy = 1
'hardcoded dpad keys
VK(i).dpad.left.keydown = VK_KEY_LEFT
VK(i).dpad.right.keydown = VK_KEY_RIGHT
VK(i).dpad.up.keydown = VK_KEY_UP
VK(i).dpad.down.keydown = VK_KEY_DOWN
IF dx <> odx THEN
IF odx = -1 THEN keyup VK(i).dpad.left.keydown
IF odx = 1 THEN keyup VK(i).dpad.right.keydown
IF dx = -1 THEN keydown VK(i).dpad.left.keydown: VK(i).dpad.lastKeyDx = dx: VK(i).dpad.lastKeyDy = 0
IF dx = 1 THEN keydown VK(i).dpad.right.keydown: VK(i).dpad.lastKeyDx = dx: VK(i).dpad.lastKeyDy = 0
END IF
IF dy <> ody THEN
IF ody = -1 THEN keyup VK(i).dpad.up.keydown
IF ody = 1 THEN keyup VK(i).dpad.down.keydown
IF dy = -1 THEN keydown VK(i).dpad.up.keydown: VK(i).dpad.lastKeyDy = dy: VK(i).dpad.lastKeyDx = 0
IF dy = 1 THEN keydown VK(i).dpad.down.keydown: VK(i).dpad.lastKeyDy = dy: VK(i).dpad.lastKeyDx = 0
END IF
'strongest direction must have been represented by last known keydown event fired by dpad
IF dx <> 0 OR dy <> 0 THEN 'has direction
bestDx = 0: bestDy = 0
IF ABS(x) > ABS(y) THEN
bestDx = SGN(x)
ELSE
bestDy = SGN(y)
END IF
IF bestDx <> VK(i).dpad.lastKeyDx AND bestDx <> 0 THEN
dx = bestDx
IF dx = -1 THEN keydown VK(i).dpad.left.keydown: VK(i).dpad.lastKeyDx = dx: VK(i).dpad.lastKeyDy = 0
IF dx = 1 THEN keydown VK(i).dpad.right.keydown: VK(i).dpad.lastKeyDx = dx: VK(i).dpad.lastKeyDy = 0
ELSE
IF bestDy <> VK(i).dpad.lastKeyDy AND bestDy <> 0 THEN
dy = bestDy
IF dy = -1 THEN keydown VK(i).dpad.up.keydown: VK(i).dpad.lastKeyDy = dy: VK(i).dpad.lastKeyDx = 0
IF dy = 1 THEN keydown VK(i).dpad.down.keydown: VK(i).dpad.lastKeyDy = dy: VK(i).dpad.lastKeyDx = 0
END IF
END IF
END IF
VK(i).dpad.dx = dx
VK(i).dpad.dy = dy
VK(i).dpad.x = x
VK(i).dpad.y = y
END SUB
SUB VkReLabel (i, label$)
VkReDraw = 1
VK(i).label = label$
VK(i).reDraw = 1
END SUB
SUB VkReLabelShifted (i, label$)
VkReDraw = 1
VK(i).shiftedLabel = label$
VK(i).reDraw = 1
END SUB
SUB VkAddKeyName (keyName AS STRING, keyCode AS LONG)
value = QB_NODE_new(QB_NODE_TYPE_VALUE, 0)
QB_NODE_setLabel_format value, QB_STR_new(keyName), QB_NODE_FORMAT_STR
QB_NODE_setValue_format value, keyCode, QB_NODE_FORMAT_LONG
QB_NODE_assign VkKeyCodeLookup, value
value = QB_NODE_new(QB_NODE_TYPE_VALUE, 0)
QB_NODE_setLabel_format value, keyCode, QB_NODE_FORMAT_LONG
QB_NODE_setValue_format value, QB_STR_new(keyName), QB_NODE_FORMAT_STR
QB_NODE_assign VkKeyNameLookup, value
END SUB
SUB VkAddKeyNames
VkKeyNameLookup = QB_NODE_newDictionary
VkKeyCodeLookup = QB_NODE_newDictionary
VkAddKeyName "KEY_PAUSE", 100019
VkAddKeyName "KEY_NUMLOCK", 100300
VkAddKeyName "KEY_CAPSLOCK", 100301
VkAddKeyName "KEY_SCROLLOCK", 100302
VkAddKeyName "KEY_RSHIFT", 100303
VkAddKeyName "KEY_LSHIFT", 100304
VkAddKeyName "KEY_RCTRL", 100305
VkAddKeyName "KEY_LCTRL", 100306
VkAddKeyName "KEY_RALT", 100307
VkAddKeyName "KEY_LALT", 100308
VkAddKeyName "KEY_RMETA", 100309
VkAddKeyName "KEY_LMETA", 100310
VkAddKeyName "KEY_LSUPER", 100311
VkAddKeyName "KEY_RSUPER", 100312
VkAddKeyName "KEY_MODE", 100313
VkAddKeyName "KEY_COMPOSE", 100314
VkAddKeyName "KEY_HELP", 100315
VkAddKeyName "KEY_PRINT", 100316
VkAddKeyName "KEY_SYSREQ", 100317
VkAddKeyName "KEY_BREAK", 100318
VkAddKeyName "KEY_MENU", 100319
VkAddKeyName "KEY_POWER", 100320
VkAddKeyName "KEY_EURO", 100321
VkAddKeyName "KEY_UNDO", 100322
VkAddKeyName "KEY_KP0", 100256
VkAddKeyName "KEY_KP1", 100257
VkAddKeyName "KEY_KP2", 100258
VkAddKeyName "KEY_KP3", 100259
VkAddKeyName "KEY_KP4", 100260
VkAddKeyName "KEY_KP5", 100261
VkAddKeyName "KEY_KP6", 100262
VkAddKeyName "KEY_KP7", 100263
VkAddKeyName "KEY_KP8", 100264
VkAddKeyName "KEY_KP9", 100265
VkAddKeyName "KEY_KP_PERIOD", 100266
VkAddKeyName "KEY_KP_DIVIDE", 100267
VkAddKeyName "KEY_KP_MULTIPLY", 100268
VkAddKeyName "KEY_KP_MINUS", 100269
VkAddKeyName "KEY_KP_PLUS", 100270
VkAddKeyName "KEY_KP_ENTER", 100271
VkAddKeyName "KEY_KP_INSERT", 200000
VkAddKeyName "KEY_KP_END", 200001
VkAddKeyName "KEY_KP_DOWN", 200002
VkAddKeyName "KEY_KP_PAGE_DOWN", 200003
VkAddKeyName "KEY_KP_LEFT", 200004
VkAddKeyName "KEY_KP_MIDDLE", 200005
VkAddKeyName "KEY_KP_RIGHT", 200006
VkAddKeyName "KEY_KP_HOME", 200007
VkAddKeyName "KEY_KP_UP", 200008
VkAddKeyName "KEY_KP_PAGE_UP", 200009
VkAddKeyName "KEY_KP_DELETE", 200010
VkAddKeyName "KEY_SCROLL_LOCK_MODE", 200011
VkAddKeyName "KEY_INSERT_MODE", 200012
VkAddKeyName "KEY_F1", 15104
VkAddKeyName "KEY_F2", 15360
VkAddKeyName "KEY_F3", 15616
VkAddKeyName "KEY_F4", 15872
VkAddKeyName "KEY_F5", 16128
VkAddKeyName "KEY_F6", 16384
VkAddKeyName "KEY_F7", 16640
VkAddKeyName "KEY_F8", 16896
VkAddKeyName "KEY_F9", 17152
VkAddKeyName "KEY_F10", 17408
VkAddKeyName "KEY_F11", 34048
VkAddKeyName "KEY_F12", 34304
VkAddKeyName "KEY_INSERT", 20992
VkAddKeyName "KEY_DELETE", 21248
VkAddKeyName "KEY_HOME", 18176
VkAddKeyName "KEY_END", 20224
VkAddKeyName "KEY_PAGE_UP", 18688
VkAddKeyName "KEY_PAGE_DOWN", 20736
VkAddKeyName "KEY_UP", 18432
VkAddKeyName "KEY_DOWN", 20480
VkAddKeyName "KEY_LEFT", 19200
VkAddKeyName "KEY_RIGHT", 19712
VkAddKeyName "KEY_BACKSPACE", 8
VkAddKeyName "KEY_TAB", 9
VkAddKeyName "KEY_ENTER", 13
VkAddKeyName "KEY_ESCAPE", 27
VkAddKeyName "KEY_SPACE", 32
VkAddKeyName "KEY_EXCLAMATION", 33
VkAddKeyName "KEY_QUOTE", 34
VkAddKeyName "KEY_HASH", 35
VkAddKeyName "KEY_DOLLAR", 36
VkAddKeyName "KEY_PERCENT", 37
VkAddKeyName "KEY_AND", 38
VkAddKeyName "KEY_APOSTROPHE", 39
VkAddKeyName "KEY_OPEN_BRACKET", 40
VkAddKeyName "KEY_CLOSE_BRACKET", 41
VkAddKeyName "KEY_STAR", 42
VkAddKeyName "KEY_PLUS", 43
VkAddKeyName "KEY_COMMA", 44
VkAddKeyName "KEY_MINUS", 45
VkAddKeyName "KEY_DOT", 46
VkAddKeyName "KEY_FORWARD_SLASH", 47
VkAddKeyName "KEY_0", 48
VkAddKeyName "KEY_1", 49
VkAddKeyName "KEY_2", 50
VkAddKeyName "KEY_3", 51
VkAddKeyName "KEY_4", 52
VkAddKeyName "KEY_5", 53
VkAddKeyName "KEY_6", 54
VkAddKeyName "KEY_7", 55
VkAddKeyName "KEY_8", 56
VkAddKeyName "KEY_9", 57
VkAddKeyName "KEY_COLON", 58
VkAddKeyName "KEY_SEMICOLON", 59
VkAddKeyName "KEY_LESS_THAN", 60
VkAddKeyName "KEY_EQUAL", 61
VkAddKeyName "KEY_GREATER_THAN", 62
VkAddKeyName "KEY_QUESTION", 63
VkAddKeyName "KEY_AT", 64
VkAddKeyName "KEY_A", 65
VkAddKeyName "KEY_B", 66
VkAddKeyName "KEY_C", 67
VkAddKeyName "KEY_D", 68
VkAddKeyName "KEY_E", 69
VkAddKeyName "KEY_F", 70
VkAddKeyName "KEY_G", 71
VkAddKeyName "KEY_H", 72
VkAddKeyName "KEY_I", 73
VkAddKeyName "KEY_J", 74
VkAddKeyName "KEY_K", 75
VkAddKeyName "KEY_L", 76
VkAddKeyName "KEY_M", 77
VkAddKeyName "KEY_N", 78
VkAddKeyName "KEY_O", 79
VkAddKeyName "KEY_P", 80
VkAddKeyName "KEY_Q", 81
VkAddKeyName "KEY_R", 82
VkAddKeyName "KEY_S", 83
VkAddKeyName "KEY_T", 84
VkAddKeyName "KEY_U", 85
VkAddKeyName "KEY_V", 86
VkAddKeyName "KEY_W", 87
VkAddKeyName "KEY_X", 88
VkAddKeyName "KEY_Y", 89
VkAddKeyName "KEY_Z", 90
VkAddKeyName "KEY_UCASE_A", 65
VkAddKeyName "KEY_UCASE_B", 66
VkAddKeyName "KEY_UCASE_C", 67
VkAddKeyName "KEY_UCASE_D", 68
VkAddKeyName "KEY_UCASE_E", 69
VkAddKeyName "KEY_UCASE_F", 70
VkAddKeyName "KEY_UCASE_G", 71
VkAddKeyName "KEY_UCASE_H", 72
VkAddKeyName "KEY_UCASE_I", 73
VkAddKeyName "KEY_UCASE_J", 74
VkAddKeyName "KEY_UCASE_K", 75
VkAddKeyName "KEY_UCASE_L", 76
VkAddKeyName "KEY_UCASE_M", 77
VkAddKeyName "KEY_UCASE_N", 78
VkAddKeyName "KEY_UCASE_O", 79
VkAddKeyName "KEY_UCASE_P", 80
VkAddKeyName "KEY_UCASE_Q", 81
VkAddKeyName "KEY_UCASE_R", 82
VkAddKeyName "KEY_UCASE_S", 83
VkAddKeyName "KEY_UCASE_T", 84
VkAddKeyName "KEY_UCASE_U", 85
VkAddKeyName "KEY_UCASE_V", 86
VkAddKeyName "KEY_UCASE_W", 87
VkAddKeyName "KEY_UCASE_X", 88
VkAddKeyName "KEY_UCASE_Y", 89
VkAddKeyName "KEY_UCASE_Z", 90
VkAddKeyName "KEY_OPEN_BRACKET_SQUARE", 91
VkAddKeyName "KEY_BACK_SLASH", 92
VkAddKeyName "KEY_CLOSE_BRACKET_SQUARE", 93
VkAddKeyName "KEY_CARET", 94
VkAddKeyName "KEY_UNDERSCORE", 95
VkAddKeyName "KEY_REVERSE_APOSTROPHE", 96
VkAddKeyName "KEY_LCASE_A", 97
VkAddKeyName "KEY_LCASE_B", 98
VkAddKeyName "KEY_LCASE_C", 99
VkAddKeyName "KEY_LCASE_D", 100
VkAddKeyName "KEY_LCASE_E", 101
VkAddKeyName "KEY_LCASE_F", 102
VkAddKeyName "KEY_LCASE_G", 103
VkAddKeyName "KEY_LCASE_H", 104
VkAddKeyName "KEY_LCASE_I", 105
VkAddKeyName "KEY_LCASE_J", 106
VkAddKeyName "KEY_LCASE_K", 107
VkAddKeyName "KEY_LCASE_L", 108
VkAddKeyName "KEY_LCASE_M", 109
VkAddKeyName "KEY_LCASE_N", 110
VkAddKeyName "KEY_LCASE_O", 111
VkAddKeyName "KEY_LCASE_P", 112
VkAddKeyName "KEY_LCASE_Q", 113
VkAddKeyName "KEY_LCASE_R", 114
VkAddKeyName "KEY_LCASE_S", 115
VkAddKeyName "KEY_LCASE_T", 116
VkAddKeyName "KEY_LCASE_U", 117
VkAddKeyName "KEY_LCASE_V", 118
VkAddKeyName "KEY_LCASE_W", 119
VkAddKeyName "KEY_LCASE_X", 120
VkAddKeyName "KEY_LCASE_Y", 121
VkAddKeyName "KEY_LCASE_Z", 122
VkAddKeyName "KEY_OPEN_BRACKET_CURLY", 123
VkAddKeyName "KEY_VERTICAL_BAR", 124
VkAddKeyName "KEY_CLOSE_BRACKET_CURLY", 125
VkAddKeyName "KEY_TILDE", 126
VkAddKeyName "KEY_BACKSPACE_ALTERNATE", 127
END SUB
FUNCTION VkGetKeyName$ (keyCode AS LONG)
VkGetKeyName$ = QB_STR_long(keyCode)
DIM VkChild AS LONG
DIM VkI AS LONG
DO WHILE QB_NODE_eachWithLabel_format(VkChild, VkKeyNameLookup, keyCode, QB_NODE_FORMAT_LONG, VkI)
VkGetKeyName$ = QB_NODE_value(VkChild)
EXIT FUNCTION
LOOP
END FUNCTION
FUNCTION VkGetKeyCode& (keyName AS STRING)
DIM i AS LONG
i = QB_NODE_withLabel(VkKeyCodeLookup, keyName)
IF i THEN
VkGetKeyCode& = VAL(QB_NODE_value(i))
ELSE
VkGetKeyCode& = VAL(keyName)
END IF
END FUNCTION
SUB VkSaveKeys (parentNode AS LONG, parentKey AS LONG)
FOR i = 1 TO VkLast
IF VK(i).internal = 0 AND VK(i).active <> 0 AND VK(i).parent = parentKey THEN
thisKey = QB_NODE_newDictionary
QB_NODE_assign parentNode, thisKey
'get type
keyType$ = "key"
IF VK(i).event.keydown = -1 THEN
keyType$ = "joystick"
END IF
IF VK(i).event.keydown = -2 THEN
keyType$ = "keySet"
END IF
QB_NODE_assign thisKey, QB_NODE_newValueWithLabel("type", keyType$)
IF parentKey = 0 THEN
QB_NODE_assign thisKey, QB_NODE_newValueWithLabel_long("x", VK(i).x)
QB_NODE_assign thisKey, QB_NODE_newValueWithLabel_long("y", VK(i).y)
ELSE
QB_NODE_assign thisKey, QB_NODE_newValueWithLabel_long("offsetX", VK(i).offsetX)
QB_NODE_assign thisKey, QB_NODE_newValueWithLabel_long("offsetY", VK(i).offsetY)
END IF
QB_NODE_assign thisKey, QB_NODE_newValueWithLabel_long("width", VK(i).w)
QB_NODE_assign thisKey, QB_NODE_newValueWithLabel_long("height", VK(i).h)
QB_NODE_assign thisKey, QB_NODE_newValueWithLabel("label", RTRIM$(VK(i).label))
events = QB_NODE_newDictionary: QB_NODE_setLabel events, "events"
IF keyType$ = "key" THEN
QB_NODE_assign thisKey, QB_NODE_newValueWithLabel_bool("locks", VK(i).locks)
QB_NODE_assign thisKey, QB_NODE_newValueWithLabel_bool("lockIsTemporary", VK(i).lockIsTemporary)
event = QB_NODE_newDictionary: QB_NODE_setLabel event, "keydown": QB_NODE_assign events, event
QB_NODE_assign event, QB_NODE_newValueWithLabel("keyCode", VkGetKeyName(VK(i).event.keydown))
IF VK(i).hasShiftedEvent THEN
event = QB_NODE_newDictionary: QB_NODE_setLabel event, "keydownWithShift": QB_NODE_assign events, event
QB_NODE_assign event, QB_NODE_newValueWithLabel("keyCode", VkGetKeyName(VK(i).shiftedEvent.keydown))
QB_NODE_assign event, QB_NODE_newValueWithLabel("label", RTRIM$(VK(i).shiftedLabel))
END IF
END IF
IF keyType$ = "joystick" THEN
'hardcode keys
VK(i).dpad.left.keydown = VK_KEY_LEFT
VK(i).dpad.right.keydown = VK_KEY_RIGHT
VK(i).dpad.up.keydown = VK_KEY_UP
VK(i).dpad.down.keydown = VK_KEY_DOWN
event = QB_NODE_newDictionary: QB_NODE_setLabel event, "up": QB_NODE_assign events, event
QB_NODE_assign event, QB_NODE_newValueWithLabel("keyCode", VkGetKeyName(VK(i).dpad.up.keydown))
event = QB_NODE_newDictionary: QB_NODE_setLabel event, "down": QB_NODE_assign events, event
QB_NODE_assign event, QB_NODE_newValueWithLabel("keyCode", VkGetKeyName(VK(i).dpad.down.keydown))
event = QB_NODE_newDictionary: QB_NODE_setLabel event, "left": QB_NODE_assign events, event
QB_NODE_assign event, QB_NODE_newValueWithLabel("keyCode", VkGetKeyName(VK(i).dpad.left.keydown))
event = QB_NODE_newDictionary: QB_NODE_setLabel event, "right": QB_NODE_assign events, event
QB_NODE_assign event, QB_NODE_newValueWithLabel("keyCode", VkGetKeyName(VK(i).dpad.right.keydown))
END IF
IF keyType$ = "keySet" THEN
END IF
IF QB_NODE_count(events) > 0 THEN
QB_NODE_assign thisKey, events
ELSE
QB_NODE_destroy events
END IF
childKeys = QB_NODE_newList: QB_NODE_setLabel childKeys, "childKeys"
VkSaveKeys childKeys, i
IF QB_NODE_count(childKeys) > 0 THEN
QB_NODE_assign thisKey, childKeys
ELSE
QB_NODE_destroy childKeys
END IF
END IF
NEXT
END SUB
SUB VkSave
root = QB_NODE_newDictionary
QB_NODE_assign root, QB_NODE_newValueWithLabel_long("width", VkWidthInUnits)
keys = QB_NODE_newList: QB_NODE_setLabel keys, "keys": QB_NODE_assign root, keys
VkSaveKeys keys, 0
json$ = QB_NODESET_serialize(root, "json")
QB_NODE_destroy root
fh = FREEFILE
OPEN appRootPath$+"virtual_keyboard_layout_current.txt" FOR OUTPUT AS #fh
PRINT #fh, json$
CLOSE #fh
END SUB
SUB VkLoadKeys (parentNode AS LONG, parentKey AS LONG)
DIM iterator AS LONG
DIM keyNode AS LONG
DO WHILE QB_NODE_each(keyNode, parentNode, iterator)
DIM events AS LONG
DIM event AS LONG
events = QB_NODE_withLabel(keyNode, "events")
keyType$ = QB_NODE_valueOfLabel(keyNode, "type")
i = VkNew
VK(i).role = "USER"
VK(i).parent = parentKey
IF parentKey THEN
VK(i).offsetX = QB_NODE_valueOfLabel_long(keyNode, "offsetX")
VK(i).offsetY = QB_NODE_valueOfLabel_long(keyNode, "offsetY")
ELSE
VK(i).x = QB_NODE_valueOfLabel_long(keyNode, "x")
VK(i).y = QB_NODE_valueOfLabel_long(keyNode, "y")
END IF
VK(i).w = QB_NODE_valueOfLabel_long(keyNode, "width")
VK(i).h = QB_NODE_valueOfLabel_long(keyNode, "height")
VK(i).label = QB_NODE_valueOfLabel(keyNode, "label")
IF keyType$ = "key" THEN
VK(i).locks = QB_NODE_valueOfLabel_bool(keyNode, "locks")
VK(i).lockIsTemporary = QB_NODE_valueOfLabel_bool(keyNode, "lockIsTemporary")
VK(i).event.keydown = VkGetKeyCode&(QB_NODE_valueOfLabel(QB_NODE_withLabel(events, "keydown"), "keyCode"))
shiftedEvent = QB_NODE_withLabel(events, "keydownWithShift")
IF shiftedEvent THEN
VK(i).hasShiftedEvent = 1
VK(i).shiftedEvent.keydown = VkGetKeyCode&(QB_NODE_valueOfLabel(shiftedEvent, "keyCode"))
VK(i).shiftedLabel = QB_NODE_valueOfLabel(shiftedEvent, "label")
END IF
END IF
IF keyType$ = "keySet" THEN
VK(i).event.keydown = -2
VkLoadKeys QB_NODE_withLabel(keyNode, "childKeys"), i
END IF
IF keyType$ = "joystick" THEN
VK(i).event.keydown = -1
VK(i).dpad.left.keydown = VkGetKeyCode&(QB_NODE_valueOfLabel(QB_NODE_withLabel(events, "left"), "keyCode"))
VK(i).dpad.right.keydown = VkGetKeyCode&(QB_NODE_valueOfLabel(QB_NODE_withLabel(events, "right"), "keyCode"))
VK(i).dpad.up.keydown = VkGetKeyCode&(QB_NODE_valueOfLabel(QB_NODE_withLabel(events, "up"), "keyCode"))
VK(i).dpad.down.keydown = VkGetKeyCode&(QB_NODE_valueOfLabel(QB_NODE_withLabel(events, "down"), "keyCode"))
END IF
LOOP
END SUB
FUNCTION VkGetQuotedString$ (a$)
a2$ = SPACE$(LEN(a$))
i2 = 0
FOR i = 1 TO LEN(a$)
a2 = a
a = ASC(a$, i)
IF a2 = 92 AND a = 113 THEN
ASC(a2$, i2) = 34
ELSE
i2 = i2 + 1
ASC(a2$, i2) = a
END IF
NEXT
a2$ = LEFT$(a2$, i2)
VkGetQuotedString$ = a2$
END FUNCTION
SUB VkLoad
VkFile$=""
if _FILEEXISTS(appRootPath$+"virtual_keyboard_layout_default.txt") then VkFile$=appRootPath$+"virtual_keyboard_layout_default.txt"
if _FILEEXISTS(appRootPath$+"virtual_keyboard_layout_current.txt") then VkFile$=appRootPath$+"virtual_keyboard_layout_current.txt"
if VkFile$<>"" then
fh = FREEFILE
OPEN VkFile$ FOR INPUT AS #fh
LINE INPUT #fh, json$
CLOSE #fh
root = QB_NODESET_deserialize(json$, "json")
DIM oldVkWidthInUnits AS LONG
oldVkWidthInUnits=VkWidthInUnits
VkWidthInUnits=90
DIM rootValueNode AS LONG
rootValueNode=QB_NODE_withLabel(root, "width")
if rootValueNode then VkWidthInUnits=QB_NODE_valueOfLabel_long(root, "width")
if VkWidthInUnits<>oldVkWidthInUnits then
FOR i3 = 1 TO VkLast
IF VK(i3).active THEN
VK(i3).reDraw = 1
END IF
NEXT
VkReset = 1
END IF
VkLoadKeys QB_NODESET_node(QB_NODESET_label_equal(QB_NODESET_children(root), "keys")), 0
QB_NODE_destroy root
end if
END SUB
FUNCTION VkShiftInEffect
shiftInEffect = 0
'IF _KEYDOWN(VK_KEY_LSHIFT) OR _KEYDOWN(VK_KEY_RSHIFT) THEN
' shiftInEffect = 1
'END IF
shiftLockInEffect = 0
FOR i = 1 TO VkLast
IF VK(i).active THEN
IF VK(i).internal = 0 THEN
'is this a caps lock or shift key?
'is it active?
IF VK(i).event.keydown = VK_KEY_CAPSLOCK THEN
IF VK(i).held <> 0 THEN
shiftLockInEffect = 1
END IF
END IF
END IF
END IF
NEXT
shiftKeyHeld = 0
FOR i = 1 TO VkLast
IF VK(i).active THEN
IF VK(i).internal = 0 THEN
'is this a caps lock or shift key?
'is it active?
IF VK(i).event.keydown = VK_KEY_LSHIFT OR VK(i).event.keydown = VK_KEY_RSHIFT THEN
IF VK(i).held <> 0 THEN
shiftKeyHeld = 1
END IF
END IF
END IF
END IF
NEXT
IF shiftLockInEffect + shiftKeyHeld = 1 THEN shiftInEffect = 1
IF VkAddShiftedKey = 1 THEN shiftInEffect = 1
VkShiftInEffect = shiftInEffect
END FUNCTION
SUB VkGetMouse (mx AS LONG, my AS LONG, mb AS LONG)
'DIM SHARED VkReg AS VkRegTypeX
VkReg.ax = 3
CALL INTERRUPT(&H33, VkReg, VkReg)
mb = VkReg.bx AND 1
mx = VkReg.cx
my = VkReg.dx
END SUB
FUNCTION VkFindFont& (idealSize AS LONG)
FOR diff = 0 TO 1000
FOR negative = 0 TO 1
IF negative THEN
size = idealSize - diff
ELSE
size = idealSize + diff \ 2 'increase of size is less desirable that decrease of size
END IF
IF size >= 0 AND size <= UBOUND(vkfontAllow) THEN
IF vkFontAllow(size) THEN
if vkFonts(size)=0 then vkFonts(size)=_LOADFONT(appRootPath$+"cyberbit.ttf", size)
if vkFonts(size)=0 then 'font failed to load, so use inbuilt font instead
vkFonts(size)=16
if size<16 then vkFonts(size)=8
end if
VkFindFont& = vkFonts(size)
EXIT FUNCTION
END IF
END IF
NEXT
NEXT
END FUNCTION