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+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