From b57ca7c38bad70b70f166f0eefa1f15c5aba42cf Mon Sep 17 00:00:00 2001 From: FellippeHeitor Date: Sun, 14 Apr 2019 16:42:04 -0300 Subject: [PATCH] Removes virtual keyboard references (1/2) --- programs/android/template/located_files.txt | 4 - programs/android/template/notes.txt | 178 -- .../android/template/untitled/.idea/.name | 1 - .../template/untitled/.idea/compiler.xml | 23 - .../.idea/copyright/profiles_settings.xml | 3 - .../template/untitled/.idea/encodings.xml | 5 - .../template/untitled/.idea/gradle.xml | 19 - .../android/template/untitled/.idea/misc.xml | 10 - .../template/untitled/.idea/modules.xml | 10 - .../untitled/.idea/scopes/scope_settings.xml | 5 - .../android/template/untitled/.idea/vcs.xml | 7 - .../android/template/untitled/app/app.iml | 89 - .../template/untitled/app/build.gradle | 40 - .../untitled/app/src/main/AndroidManifest.xml | 34 - .../template/untitled/app/src/main/Thumbs.db | Bin 64000 -> 0 bytes .../untitled/app/src/main/assets/Thumbs.db | Bin 17408 -> 0 bytes .../app/src/main/assets/emptyfolder.bin | 0 .../untitled/app/src/main/jni/Android.mk | 199 -- .../untitled/app/src/main/jni/Application.mk | 38 - .../app/src/main/jni/c/emptyfolder.bin | 0 .../untitled/app/src/main/jni/main.cpp | 19 - .../app/src/main/jni/temp/emptyfolder.bin | 0 .../app/src/main/res/values/strings.xml | 4 - .../android/template/untitled/build.gradle | 15 - .../template/untitled/gradle.properties | 1 - .../gradle/wrapper/gradle-wrapper.jar | Bin 49896 -> 0 bytes .../gradle/wrapper/gradle-wrapper.properties | 6 - programs/android/template/untitled/gradlew | 164 - .../android/template/untitled/gradlew.bat | 90 - .../template/untitled/local.properties | 8 - .../android/template/untitled/settings.gradle | 1 - .../android/template/untitled/untitled.iml | 19 - source/embed/footer_stub.bas | 2 + source/embed/header_stub.bas | 3 + source/qb64.bas | 67 +- source/qb_framework/qb_framework_global.bas | 172 - source/qb_framework/qb_framework_methods.bas | 1968 ------------ source/virtual_keyboard/embed/footer.bas | 2 - source/virtual_keyboard/embed/header.bas | 7 - .../virtual_keyboard_layout_default.txt | 1 - .../virtual_keyboard_global.bas | 177 -- .../virtual_keyboard_keycodes.bas | 207 -- .../virtual_keyboard_keypush.bas | 11 - .../virtual_keyboard_methods.bas | 2811 ----------------- 44 files changed, 11 insertions(+), 6409 deletions(-) delete mode 100644 programs/android/template/located_files.txt delete mode 100644 programs/android/template/notes.txt delete mode 100644 programs/android/template/untitled/.idea/.name delete mode 100644 programs/android/template/untitled/.idea/compiler.xml delete mode 100644 programs/android/template/untitled/.idea/copyright/profiles_settings.xml delete mode 100644 programs/android/template/untitled/.idea/encodings.xml delete mode 100644 programs/android/template/untitled/.idea/gradle.xml delete mode 100644 programs/android/template/untitled/.idea/misc.xml delete mode 100644 programs/android/template/untitled/.idea/modules.xml delete mode 100644 programs/android/template/untitled/.idea/scopes/scope_settings.xml delete mode 100644 programs/android/template/untitled/.idea/vcs.xml delete mode 100644 programs/android/template/untitled/app/app.iml delete mode 100644 programs/android/template/untitled/app/build.gradle delete mode 100644 programs/android/template/untitled/app/src/main/AndroidManifest.xml delete mode 100644 programs/android/template/untitled/app/src/main/Thumbs.db delete mode 100644 programs/android/template/untitled/app/src/main/assets/Thumbs.db delete mode 100644 programs/android/template/untitled/app/src/main/assets/emptyfolder.bin delete mode 100644 programs/android/template/untitled/app/src/main/jni/Android.mk delete mode 100644 programs/android/template/untitled/app/src/main/jni/Application.mk delete mode 100644 programs/android/template/untitled/app/src/main/jni/c/emptyfolder.bin delete mode 100644 programs/android/template/untitled/app/src/main/jni/main.cpp delete mode 100644 programs/android/template/untitled/app/src/main/jni/temp/emptyfolder.bin delete mode 100644 programs/android/template/untitled/app/src/main/res/values/strings.xml delete mode 100644 programs/android/template/untitled/build.gradle delete mode 100644 programs/android/template/untitled/gradle.properties delete mode 100644 programs/android/template/untitled/gradle/wrapper/gradle-wrapper.jar delete mode 100644 programs/android/template/untitled/gradle/wrapper/gradle-wrapper.properties delete mode 100644 programs/android/template/untitled/gradlew delete mode 100644 programs/android/template/untitled/gradlew.bat delete mode 100644 programs/android/template/untitled/local.properties delete mode 100644 programs/android/template/untitled/settings.gradle delete mode 100644 programs/android/template/untitled/untitled.iml create mode 100644 source/embed/footer_stub.bas create mode 100644 source/embed/header_stub.bas delete mode 100644 source/qb_framework/qb_framework_global.bas delete mode 100644 source/qb_framework/qb_framework_methods.bas delete mode 100644 source/virtual_keyboard/embed/footer.bas delete mode 100644 source/virtual_keyboard/embed/header.bas delete mode 100644 source/virtual_keyboard/layouts/virtual_keyboard_layout_default.txt delete mode 100644 source/virtual_keyboard/virtual_keyboard_global.bas delete mode 100644 source/virtual_keyboard/virtual_keyboard_keycodes.bas delete mode 100644 source/virtual_keyboard/virtual_keyboard_keypush.bas delete mode 100644 source/virtual_keyboard/virtual_keyboard_methods.bas diff --git a/programs/android/template/located_files.txt b/programs/android/template/located_files.txt deleted file mode 100644 index 346a6abe1..000000000 --- a/programs/android/template/located_files.txt +++ /dev/null @@ -1,4 +0,0 @@ -c:\ndk\ndk-build -c:\Program Files\Android\Android Studio\gradle\gradle-2.2.1\bin\gradle.bat -c:\Users\Robert\AppData\Local\Android\sdk1\AVD Manager.exe -c:\Program Files\Android\Android Studio\gradle\gradle-2.4\bin\gradle.bat diff --git a/programs/android/template/notes.txt b/programs/android/template/notes.txt deleted file mode 100644 index 9d80f19a9..000000000 --- a/programs/android/template/notes.txt +++ /dev/null @@ -1,178 +0,0 @@ -This is a template for creating an Android NDK project for Android Studio - -The following steps are performed on this template: - --Copy/Rename 'untitled' folder to new location - -[root] - local.properties: - -replace path references to SDK & NDK - untitled.iml - -rename file - (no other changes for root) - - [.idea] - modules.xml - -untitled - gradle.xml - -path to gradle "gradleHome" - .name - -replace content with new program name - (no other changes for .idea) - - [scopes] - (no changes required) - - [copyright] - (no changes required) - - [gradle] - (no changes required) - - [app] - app.iml - -untitled - build.gradle - -com.example.untitled - -commandLine 'c:\\ndk\\ndk-build.cmd','-C', file('src/main').absolutePath - (no other changes required) - - [src/main] - AndroidManifest.xml - -com.example.untitled - (no other changes required) - - [assets] - (no other changes required) - - [res/values] - strings.xml - -untitled - (no other changes required) - - [jni] - [temp] - -replace with a copy of everything in the temp folder - [c] - -replace with a copy of everything from the c folder - (with selective restrictions) - FILTER: - *.h - *.c - *.cpp - *.mm - EXCLUDE: - [c_compiler/*] - [*/os/*] - Application.mk - -# - #Flags for image dependency - APP_CFLAGS += -D DEPENDENCY_IMAGE_CODEC - #Flags for font dependency - APP_CFLAGS += -D DEPENDENCY_LOADFONT - #Flags for audio dependency - APP_CFLAGS += -D DEPENDENCY_AUDIO_OUT - APP_CFLAGS += -D DEPENDENCY_AUDIO_CONVERSION - APP_CFLAGS += -D DEPENDENCY_AUDIO_DECODE - - Android.mk - -# - ------------------------------------------------------------------------------------------------------------------ -include $(CLEAR_VARS) - -OPENAL_DIR := c/parts/audio/out/android/OpenAL - -AL_SOURCES := \ - $(OPENAL_DIR)/Alc/android.c \ - $(OPENAL_DIR)/OpenAL32/alAuxEffectSlot.c \ - $(OPENAL_DIR)/OpenAL32/alBuffer.c \ - $(OPENAL_DIR)/OpenAL32/alDatabuffer.c \ - $(OPENAL_DIR)/OpenAL32/alEffect.c \ - $(OPENAL_DIR)/OpenAL32/alError.c \ - $(OPENAL_DIR)/OpenAL32/alExtension.c \ - $(OPENAL_DIR)/OpenAL32/alFilter.c \ - $(OPENAL_DIR)/OpenAL32/alListener.c \ - $(OPENAL_DIR)/OpenAL32/alSource.c \ - $(OPENAL_DIR)/OpenAL32/alState.c \ - $(OPENAL_DIR)/OpenAL32/alThunk.c \ - $(OPENAL_DIR)/Alc/ALc.c \ - $(OPENAL_DIR)/Alc/alcConfig.c \ - $(OPENAL_DIR)/Alc/alcEcho.c \ - $(OPENAL_DIR)/Alc/alcModulator.c \ - $(OPENAL_DIR)/Alc/alcReverb.c \ - $(OPENAL_DIR)/Alc/alcRing.c \ - $(OPENAL_DIR)/Alc/alcThread.c \ - $(OPENAL_DIR)/Alc/ALu.c \ - $(OPENAL_DIR)/Alc/bs2b.c \ - $(OPENAL_DIR)/Alc/null.c \ - $(OPENAL_DIR)/Alc/panning.c \ - $(OPENAL_DIR)/Alc/mixer.c \ - $(OPENAL_DIR)/Alc/audiotrack.c \ - $(OPENAL_DIR)/Alc/opensles.c - - -LOCAL_MODULE := parts_audio_out -LOCAL_SRC_FILES := $(AL_SOURCES) - -LOCAL_C_INCLUDES := \ - $(HOME)/src/openal-soft/jni/OpenAL \ - $(HOME)/src/openal-soft/jni/OpenAL/include \ - $(HOME)/src/openal-soft/jni/OpenAL/OpenAL32/Include \ - c/parts/audio/out/android/OpenAL/OpenAL32/Include - -LOCAL_CFLAGS += \ - -DAL_ALEXT_PROTOTYPES \ - -MAX_SOURCES_LOW ?= 4 -MAX_SOURCES_START ?= 8 -MAX_SOURCES_HIGH ?= 64 - -LOCAL_CFLAGS += -DMAX_SOURCES_LOW=$(MAX_SOURCES_LOW) -DMAX_SOURCES_START=$(MAX_SOURCES_START) -DMAX_SOURCES_HIGH=$(MAX_SOURCES_HIGH) -LOCAL_CFLAGS += -DPOST_FROYO - -include $(BUILD_STATIC_LIBRARY) - - - - - -# PARTS/AUDIO/CONVERSION -include $(CLEAR_VARS) -LOCAL_MODULE := parts_audio_conversion -LOCAL_SRC_FILES := c/parts/audio/conversion/src/samplerate.c -LOCAL_SRC_FILES += c/parts/audio/conversion/src/src_linear.c -LOCAL_SRC_FILES += c/parts/audio/conversion/src/src_sinc.c -LOCAL_SRC_FILES += c/parts/audio/conversion/src/src_zoh.c -#LOCAL_CFLAGS := -#LOCAL_C_INCLUDES := -include $(BUILD_STATIC_LIBRARY) -#include $(PREBUILT_STATIC_LIBRARY) - -# PARTS/AUDIO/CONVERSION -include $(CLEAR_VARS) -LOCAL_MODULE := parts_audio_decode_mp3 -LOCAL_SRC_FILES := c/parts/audio/decode/mp3_mini/src/minimp3.c -#LOCAL_CFLAGS := -#LOCAL_C_INCLUDES := -include $(BUILD_STATIC_LIBRARY) -#include $(PREBUILT_STATIC_LIBRARY) - - -# PARTS/VIDEO/FONT/TTF -include $(CLEAR_VARS) -LOCAL_MODULE := parts_video_font_ttf -LOCAL_SRC_FILES := c/parts/video/font/ttf/src/freetypeamalgam.c -#LOCAL_CFLAGS := -#LOCAL_C_INCLUDES := -include $(BUILD_STATIC_LIBRARY) -#include $(PREBUILT_STATIC_LIBRARY) ------------------------------------------------------------------------------------------------------------------ - - -# - LOCAL_STATIC_LIBRARIES += parts_video_font_ttf - LOCAL_STATIC_LIBRARIES += parts_audio_out - LOCAL_STATIC_LIBRARIES += parts_audio_conversion - LOCAL_STATIC_LIBRARIES += parts_audio_decode_mp3 - - (no other changes required) diff --git a/programs/android/template/untitled/.idea/.name b/programs/android/template/untitled/.idea/.name deleted file mode 100644 index 64f7f1b5b..000000000 --- a/programs/android/template/untitled/.idea/.name +++ /dev/null @@ -1 +0,0 @@ -untitled \ No newline at end of file diff --git a/programs/android/template/untitled/.idea/compiler.xml b/programs/android/template/untitled/.idea/compiler.xml deleted file mode 100644 index 217af471a..000000000 --- a/programs/android/template/untitled/.idea/compiler.xml +++ /dev/null @@ -1,23 +0,0 @@ - - - - - - diff --git a/programs/android/template/untitled/.idea/copyright/profiles_settings.xml b/programs/android/template/untitled/.idea/copyright/profiles_settings.xml deleted file mode 100644 index e7bedf337..000000000 --- a/programs/android/template/untitled/.idea/copyright/profiles_settings.xml +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/programs/android/template/untitled/.idea/encodings.xml b/programs/android/template/untitled/.idea/encodings.xml deleted file mode 100644 index e206d70d8..000000000 --- a/programs/android/template/untitled/.idea/encodings.xml +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/programs/android/template/untitled/.idea/gradle.xml b/programs/android/template/untitled/.idea/gradle.xml deleted file mode 100644 index dffab7afd..000000000 --- a/programs/android/template/untitled/.idea/gradle.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - - diff --git a/programs/android/template/untitled/.idea/misc.xml b/programs/android/template/untitled/.idea/misc.xml deleted file mode 100644 index 9076de565..000000000 --- a/programs/android/template/untitled/.idea/misc.xml +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - - diff --git a/programs/android/template/untitled/.idea/modules.xml b/programs/android/template/untitled/.idea/modules.xml deleted file mode 100644 index e7542c636..000000000 --- a/programs/android/template/untitled/.idea/modules.xml +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - - diff --git a/programs/android/template/untitled/.idea/scopes/scope_settings.xml b/programs/android/template/untitled/.idea/scopes/scope_settings.xml deleted file mode 100644 index 922003b84..000000000 --- a/programs/android/template/untitled/.idea/scopes/scope_settings.xml +++ /dev/null @@ -1,5 +0,0 @@ - - - - \ No newline at end of file diff --git a/programs/android/template/untitled/.idea/vcs.xml b/programs/android/template/untitled/.idea/vcs.xml deleted file mode 100644 index def6a6a18..000000000 --- a/programs/android/template/untitled/.idea/vcs.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - diff --git a/programs/android/template/untitled/app/app.iml b/programs/android/template/untitled/app/app.iml deleted file mode 100644 index d82d1de57..000000000 --- a/programs/android/template/untitled/app/app.iml +++ /dev/null @@ -1,89 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/programs/android/template/untitled/app/build.gradle b/programs/android/template/untitled/app/build.gradle deleted file mode 100644 index 4c7d72451..000000000 --- a/programs/android/template/untitled/app/build.gradle +++ /dev/null @@ -1,40 +0,0 @@ -apply plugin: 'com.android.application' - -android { - compileSdkVersion 21 - buildToolsVersion "21.1.2" - - - sourceSets.main { - jni.srcDirs = [] - jniLibs.srcDir 'src/main/libs' - } - - defaultConfig { - applicationId "com.example.untitled" - minSdkVersion 11 - targetSdkVersion 11 - - ndk { - //moduleName "native-activity" - stl "stlport_static" - } - } - - buildTypes { - release { - minifyEnabled false - proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt' - } - } - - // call regular ndk-build(.cmd) script from app directory - task ndkBuild(type: Exec) { - commandLine '$QB64_NDK_BUILD_CMD_FILE$','-C', file('src/main').absolutePath - } - - tasks.withType(JavaCompile) { - compileTask -> compileTask.dependsOn ndkBuild - } - -} diff --git a/programs/android/template/untitled/app/src/main/AndroidManifest.xml b/programs/android/template/untitled/app/src/main/AndroidManifest.xml deleted file mode 100644 index cbce140ac..000000000 --- a/programs/android/template/untitled/app/src/main/AndroidManifest.xml +++ /dev/null @@ -1,34 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/programs/android/template/untitled/app/src/main/Thumbs.db b/programs/android/template/untitled/app/src/main/Thumbs.db deleted file mode 100644 index 73bb945d001e40f347d6b7a7bc800c1c23f31b71..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 64000 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 - - -include $(CLEAR_VARS) - -OPENAL_DIR := c/parts/audio/out/android/OpenAL - -AL_SOURCES := \ - $(OPENAL_DIR)/Alc/android.c \ - $(OPENAL_DIR)/OpenAL32/alAuxEffectSlot.c \ - $(OPENAL_DIR)/OpenAL32/alBuffer.c \ - $(OPENAL_DIR)/OpenAL32/alDatabuffer.c \ - $(OPENAL_DIR)/OpenAL32/alEffect.c \ - $(OPENAL_DIR)/OpenAL32/alError.c \ - $(OPENAL_DIR)/OpenAL32/alExtension.c \ - $(OPENAL_DIR)/OpenAL32/alFilter.c \ - $(OPENAL_DIR)/OpenAL32/alListener.c \ - $(OPENAL_DIR)/OpenAL32/alSource.c \ - $(OPENAL_DIR)/OpenAL32/alState.c \ - $(OPENAL_DIR)/OpenAL32/alThunk.c \ - $(OPENAL_DIR)/Alc/ALc.c \ - $(OPENAL_DIR)/Alc/alcConfig.c \ - $(OPENAL_DIR)/Alc/alcEcho.c \ - $(OPENAL_DIR)/Alc/alcModulator.c \ - $(OPENAL_DIR)/Alc/alcReverb.c \ - $(OPENAL_DIR)/Alc/alcRing.c \ - $(OPENAL_DIR)/Alc/alcThread.c \ - $(OPENAL_DIR)/Alc/ALu.c \ - $(OPENAL_DIR)/Alc/bs2b.c \ - $(OPENAL_DIR)/Alc/null.c \ - $(OPENAL_DIR)/Alc/panning.c \ - $(OPENAL_DIR)/Alc/mixer.c \ - $(OPENAL_DIR)/Alc/audiotrack.c \ - $(OPENAL_DIR)/Alc/opensles.c - - -LOCAL_MODULE := parts_audio_out -LOCAL_SRC_FILES := $(AL_SOURCES) - -LOCAL_C_INCLUDES := \ - $(HOME)/src/openal-soft/jni/OpenAL \ - $(HOME)/src/openal-soft/jni/OpenAL/include \ - $(HOME)/src/openal-soft/jni/OpenAL/OpenAL32/Include \ - c/parts/audio/out/android/OpenAL/OpenAL32/Include - -LOCAL_CFLAGS += \ - -DAL_ALEXT_PROTOTYPES \ - -MAX_SOURCES_LOW ?= 4 -MAX_SOURCES_START ?= 8 -MAX_SOURCES_HIGH ?= 64 - -LOCAL_CFLAGS += -DMAX_SOURCES_LOW=$(MAX_SOURCES_LOW) -DMAX_SOURCES_START=$(MAX_SOURCES_START) -DMAX_SOURCES_HIGH=$(MAX_SOURCES_HIGH) -LOCAL_CFLAGS += -DPOST_FROYO - -include $(BUILD_STATIC_LIBRARY) - -# PARTS/AUDIO/CONVERSION -include $(CLEAR_VARS) -LOCAL_MODULE := parts_audio_conversion -LOCAL_SRC_FILES := c/parts/audio/conversion/src/resample.c -#LOCAL_CFLAGS := -#LOCAL_C_INCLUDES := -include $(BUILD_STATIC_LIBRARY) -#include $(PREBUILT_STATIC_LIBRARY) - -# PARTS/AUDIO/DECODE/MP3 -include $(CLEAR_VARS) -LOCAL_MODULE := parts_audio_decode_mp3 -LOCAL_SRC_FILES := c/parts/audio/decode/mp3_mini/src/minimp3.c -#LOCAL_CFLAGS := -#LOCAL_C_INCLUDES := -include $(BUILD_STATIC_LIBRARY) -#include $(PREBUILT_STATIC_LIBRARY) - -# PARTS/AUDIO/DECODE/OGG -include $(CLEAR_VARS) -LOCAL_MODULE := parts_audio_decode_ogg -LOCAL_SRC_FILES := c/parts/audio/decode/ogg/src/stb_vorbis.c -#LOCAL_CFLAGS := -#LOCAL_C_INCLUDES := -include $(BUILD_STATIC_LIBRARY) -#include $(PREBUILT_STATIC_LIBRARY) - -# PARTS/VIDEO/FONT/TTF -include $(CLEAR_VARS) -LOCAL_MODULE := parts_video_font_ttf -LOCAL_SRC_FILES := c/parts/video/font/ttf/src/freetypeamalgam.c -#LOCAL_CFLAGS := -#LOCAL_C_INCLUDES := -include $(BUILD_STATIC_LIBRARY) -#include $(PREBUILT_STATIC_LIBRARY) - - -include $(CLEAR_VARS) - - - -LOCAL_MODULE := native-activity - -LOCAL_SRC_FILES := main.cpp c/qbx.cpp -#LOCAL_SRC_FILES := main.c GL/glew.c tut.cpp - -#GLU ES -LOCAL_C_INCLUDES += $(LOCAL_PATH)/c/parts/core/glues/src -LOCAL_SRC_FILES += c/parts/core/glues/src/glues_error.c -LOCAL_SRC_FILES += c/parts/core/glues/src/glues_mipmap.c -LOCAL_SRC_FILES += c/parts/core/glues/src/glues_project.c -LOCAL_SRC_FILES += c/parts/core/glues/src/glues_quad.c -LOCAL_SRC_FILES += c/parts/core/glues/src/glues_registry.c -#(libtess folder not added, probably not required) - -#FreeGlut -LOCAL_C_INCLUDES += $(LOCAL_PATH)/c/parts/core/android_core/include -LOCAL_C_INCLUDES += $(LOCAL_PATH)/c/parts/core/android_core/src - -LOCAL_SRC_FILES += c/parts/core/android_core/src/fg_callbacks.c -#LOCAL_SRC_FILES += c/parts/core/android_core/src/fg_cursor.c -LOCAL_SRC_FILES += c/parts/core/android_core/src/fg_display.c -#LOCAL_SRC_FILES += c/parts/core/android_core/src/fg_ext.c -LOCAL_SRC_FILES += c/parts/core/android_core/src/fg_font_data.c -LOCAL_SRC_FILES += c/parts/core/android_core/src/fg_gamemode.c -LOCAL_SRC_FILES += c/parts/core/android_core/src/fg_init.c -LOCAL_SRC_FILES += c/parts/core/android_core/src/fg_internal.h -LOCAL_SRC_FILES += c/parts/core/android_core/src/fg_input_devices.c -LOCAL_SRC_FILES += c/parts/core/android_core/src/fg_joystick.c -LOCAL_SRC_FILES += c/parts/core/android_core/src/fg_main.c -LOCAL_SRC_FILES += c/parts/core/android_core/src/fg_misc.c -LOCAL_SRC_FILES += c/parts/core/android_core/src/fg_overlay.c -LOCAL_SRC_FILES += c/parts/core/android_core/src/fg_spaceball.c -LOCAL_SRC_FILES += c/parts/core/android_core/src/fg_state.c -LOCAL_SRC_FILES += c/parts/core/android_core/src/fg_stroke_mono_roman.c -LOCAL_SRC_FILES += c/parts/core/android_core/src/fg_stroke_roman.c -LOCAL_SRC_FILES += c/parts/core/android_core/src/fg_structure.c -LOCAL_SRC_FILES += c/parts/core/android_core/src/fg_videoresize.c -LOCAL_SRC_FILES += c/parts/core/android_core/src/fg_window.c - -#LOCAL_SRC_FILES += c/parts/core/android_core/src/fg_menu.c - -LOCAL_SRC_FILES += c/parts/core/android_core/src/util/xparsegeometry_repl.c - - -#===ANDROID SPECIFIC FILES (also required) -LOCAL_SRC_FILES += c/parts/core/android_core/src/egl/fg_internal_egl.h -LOCAL_SRC_FILES += c/parts/core/android_core/src/egl/fg_display_egl.c -LOCAL_SRC_FILES += c/parts/core/android_core/src/egl/fg_init_egl.c -LOCAL_SRC_FILES += c/parts/core/android_core/src/egl/fg_structure_egl.c -LOCAL_SRC_FILES += c/parts/core/android_core/src/egl/fg_window_egl.c -LOCAL_SRC_FILES += c/parts/core/android_core/src/android/native_app_glue/android_native_app_glue.c -LOCAL_SRC_FILES += c/parts/core/android_core/src/android/native_app_glue/android_native_app_glue.h -LOCAL_SRC_FILES += c/parts/core/android_core/src/android/fg_runtime_android.c -LOCAL_SRC_FILES += c/parts/core/android_core/src/android/fg_gamemode_android.c -LOCAL_SRC_FILES += c/parts/core/android_core/src/android/fg_input_devices_android.c -LOCAL_SRC_FILES += c/parts/core/android_core/src/android/fg_joystick_android.c -LOCAL_SRC_FILES += c/parts/core/android_core/src/android/fg_main_android.c -LOCAL_SRC_FILES += c/parts/core/android_core/src/android/fg_spaceball_android.c -LOCAL_SRC_FILES += c/parts/core/android_core/src/android/fg_state_android.c -LOCAL_SRC_FILES += c/parts/core/android_core/src/android/fg_window_android.c -LOCAL_SRC_FILES += c/parts/core/android_core/src/android/opengles_stubs.c -LOCAL_SRC_FILES += c/parts/core/android_core/src/android/fg_internal_android.h - - - -LOCAL_LDLIBS := -llog -landroid -lEGL -lGLESv1_CM -lOpenSLES - - -#LOCAL_LDLIBS := -llog -landroid -lEGL -lGLESv2 - - - -LOCAL_STATIC_LIBRARIES := android_native_app_glue -LOCAL_CFLAGS := -w - -# -LOCAL_STATIC_LIBRARIES += parts_video_font_ttf -LOCAL_STATIC_LIBRARIES += parts_audio_out -LOCAL_STATIC_LIBRARIES += parts_audio_conversion -LOCAL_STATIC_LIBRARIES += parts_audio_decode_mp3 -LOCAL_STATIC_LIBRARIES += parts_audio_decode_ogg -include $(BUILD_SHARED_LIBRARY) - -$(call import-module,android/native_app_glue) diff --git a/programs/android/template/untitled/app/src/main/jni/Application.mk b/programs/android/template/untitled/app/src/main/jni/Application.mk deleted file mode 100644 index b35c97cf3..000000000 --- a/programs/android/template/untitled/app/src/main/jni/Application.mk +++ /dev/null @@ -1,38 +0,0 @@ -APP_PLATFORM := android-10 -#APP_PLATFORM := android-9 - -#APP_ABI := armeabi -# Android 4+ (Ice Cream Sandwich) requires an ARMv7 processor. (Some custom versions of Android 4+ have been made for ARMv6) -# Therefore, there isn't much point producing armeabi binaries - -APP_ABI := armeabi-v7a -APP_ABI += x86 - -APP_STL := gnustl_static - -APP_CFLAGS := -DANDROID -APP_CFLAGS += -DHAVE_STDBOOL_H -APP_CFLAGS += -DNEED_XPARSEGEOMETRY_IMPL -APP_CFLAGS += -DHAVE_XPARSEGEOMETRY -APP_CFLAGS += -DEGL_VERSION_1_0 -APP_CFLAGS += -D GL_GLEXT_PROTOTYPES - - -APP_CFLAGS += -DVERSION_MAJOR=3 -APP_CFLAGS += -DVERSION_MINOR=0 -APP_CFLAGS += -DVERSION_PATCH=0 - - -# - -#Flags for image dependency -APP_CFLAGS += -D DEPENDENCY_IMAGE_CODEC - -#Flags for font dependency -APP_CFLAGS += -D DEPENDENCY_LOADFONT - -#Flags for audio dependency -APP_CFLAGS += -D DEPENDENCY_AUDIO_OUT -APP_CFLAGS += -D DEPENDENCY_AUDIO_CONVERSION -APP_CFLAGS += -D DEPENDENCY_AUDIO_DECODE - diff --git a/programs/android/template/untitled/app/src/main/jni/c/emptyfolder.bin b/programs/android/template/untitled/app/src/main/jni/c/emptyfolder.bin deleted file mode 100644 index e69de29bb..000000000 diff --git a/programs/android/template/untitled/app/src/main/jni/main.cpp b/programs/android/template/untitled/app/src/main/jni/main.cpp deleted file mode 100644 index 32d79ea15..000000000 --- a/programs/android/template/untitled/app/src/main/jni/main.cpp +++ /dev/null @@ -1,19 +0,0 @@ -#include -#include - -#include -#include - -#include -#include - - -#define LOGI(...) ((void)__android_log_print(ANDROID_LOG_INFO, "FreeGLUT", __VA_ARGS__)) - -/* -#include -#include -#include -*/ -#include "c/libqb.cpp" - \ No newline at end of file diff --git a/programs/android/template/untitled/app/src/main/jni/temp/emptyfolder.bin b/programs/android/template/untitled/app/src/main/jni/temp/emptyfolder.bin deleted file mode 100644 index e69de29bb..000000000 diff --git a/programs/android/template/untitled/app/src/main/res/values/strings.xml b/programs/android/template/untitled/app/src/main/res/values/strings.xml deleted file mode 100644 index cdeb37251..000000000 --- a/programs/android/template/untitled/app/src/main/res/values/strings.xml +++ /dev/null @@ -1,4 +0,0 @@ - - - untitled - diff --git a/programs/android/template/untitled/build.gradle b/programs/android/template/untitled/build.gradle deleted file mode 100644 index 6a5c233c5..000000000 --- a/programs/android/template/untitled/build.gradle +++ /dev/null @@ -1,15 +0,0 @@ -// Top-level build file where you can add configuration options common to all sub-projects/modules. -buildscript { - repositories { - jcenter() - } - dependencies { - classpath 'com.android.tools.build:gradle:1.3.0' - } -} - -allprojects { - repositories { - jcenter() - } -} diff --git a/programs/android/template/untitled/gradle.properties b/programs/android/template/untitled/gradle.properties deleted file mode 100644 index d72861d28..000000000 --- a/programs/android/template/untitled/gradle.properties +++ /dev/null @@ -1 +0,0 @@ -android.useDeprecatedNdk=true \ No newline at end of file diff --git a/programs/android/template/untitled/gradle/wrapper/gradle-wrapper.jar b/programs/android/template/untitled/gradle/wrapper/gradle-wrapper.jar deleted file mode 100644 index 8c0fb64a8698b08ecc4158d828ca593c4928e9dd..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 49896 zcmagFb986H(k`5d^NVfUwr$(C?M#x1ZQHiZiEVpg+jrjgoQrerx!>1o_ul)D>ebz~ zs=Mmxr&>W81QY-S1PKWQ%N-;H^tS;2*XwVA`dej1RRn1z<;3VgfE4~kaG`A%QSPsR z#ovnZe+tS9%1MfeDyz`RirvdjPRK~p(#^q2(^5@O&NM19EHdvN-A&StN>0g6QA^VN z0Gx%Gq#PD$QMRFzmK+utjS^Y1F0e8&u&^=w5K<;4Rz|i3A=o|IKLY+g`iK6vfr9?+ z-`>gmU&i?FGSL5&F?TXFu`&Js6h;15QFkXp2M1H9|Eq~bpov-GU(uz%mH0n55wUl- zv#~ccAz`F5wlQ>e_KlJS3@{)B?^v*EQM=IxLa&76^y51a((wq|2-`qON>+4dLc{Oo z51}}o^Zen(oAjxDK7b++9_Yg`67p$bPo3~BCpGM7uAWmvIhWc5Gi+gQZ|Pwa-Gll@<1xmcPy z|NZmu6m)g5Ftu~BG&Xdxclw7Cij{xbBMBn-LMII#Slp`AElb&2^Hw+w>(3crLH!;I zN+Vk$D+wP1#^!MDCiad@vM>H#6+`Ct#~6VHL4lzmy;lSdk>`z6)=>Wh15Q2)dQtGqvn0vJU@+(B5{MUc*qs4!T+V=q=wy)<6$~ z!G>e_4dN@lGeF_$q9`Ju6Ncb*x?O7=l{anm7Eahuj_6lA{*#Gv*TaJclevPVbbVYu z(NY?5q+xxbO6%g1xF0r@Ix8fJ~u)VRUp`S%&rN$&e!Od`~s+64J z5*)*WSi*i{k%JjMSIN#X;jC{HG$-^iX+5f5BGOIHWAl*%15Z#!xntpk($-EGKCzKa zT7{siZ9;4TICsWQ$pu&wKZQTCvpI$Xvzwxoi+XkkpeE&&kFb!B?h2hi%^YlXt|-@5 zHJ~%AN!g_^tmn1?HSm^|gCE#!GRtK2(L{9pL#hp0xh zME}|DB>(5)`iE7CM)&_+S}-Bslc#@B5W4_+k4Cp$l>iVyg$KP>CN?SVGZ(&02>iZK zB<^HP$g$Lq*L$BWd?2(F?-MUbNWTJVQdW7$#8a|k_30#vHAD1Z{c#p;bETk0VnU5A zBgLe2HFJ3032$G<`m*OB!KM$*sdM20jm)It5OSru@tXpK5LT>#8)N!*skNu1$TpIw zufjjdp#lyH5bZ%|Iuo|iu9vG1HrIVWLH>278xo>aVBkPN3V$~!=KnlXQ4eDqS7%E% zQ!z^$Q$b^6Q)g#cLpwur(|<0gWHo6A6jc;n`t(V9T;LzTAU{IAu*uEQ%Ort1k+Kn+f_N`9|bxYC+~Z1 zCC1UCWv*Orx$_@ydv9mIe(liLfOr7mhbV@tKw{6)q^1DH1nmvZ0cj215R<~&I<4S| zgnr;9Cdjqpz#o8i0CQjtl`}{c*P)aSdH|abxGdrR)-3z+02-eX(k*B)Uqv6~^nh** z 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 \(.*\)$'` - if expr "$link" : '/.*' > /dev/null; then - PRG="$link" - else - PRG=`dirname "$PRG"`"/$link" - fi -done -SAVED="`pwd`" -cd "`dirname \"$PRG\"`/" >&- -APP_HOME="`pwd -P`" -cd "$SAVED" >&- - -CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar - -# Determine the Java command to use to start the JVM. -if [ -n "$JAVA_HOME" ] ; then - if [ -x "$JAVA_HOME/jre/sh/java" ] ; then - # IBM's JDK on AIX uses strange locations for the executables - JAVACMD="$JAVA_HOME/jre/sh/java" - else - JAVACMD="$JAVA_HOME/bin/java" - fi - if [ ! -x "$JAVACMD" ] ; then - die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." - fi -else - JAVACMD="java" - which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." -fi - -# Increase the maximum file descriptors if we can. -if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then - MAX_FD_LIMIT=`ulimit -H -n` - if [ $? -eq 0 ] ; then - if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then - MAX_FD="$MAX_FD_LIMIT" - fi - ulimit -n $MAX_FD - if [ $? -ne 0 ] ; then - warn "Could not set maximum file descriptor limit: $MAX_FD" - fi - else - warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" - fi -fi - -# For Darwin, add options to specify how the application appears in the dock -if $darwin; then - GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" -fi - -# For Cygwin, switch paths to Windows format before running java -if $cygwin ; then - APP_HOME=`cygpath --path --mixed "$APP_HOME"` - CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` - - # We build the pattern for arguments to be converted via cygpath - ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` - SEP="" - for dir in $ROOTDIRSRAW ; do - ROOTDIRS="$ROOTDIRS$SEP$dir" - SEP="|" - done - OURCYGPATTERN="(^($ROOTDIRS))" - # Add a user-defined pattern to the cygpath arguments - if [ "$GRADLE_CYGPATTERN" != "" ] ; then - OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" - fi - # Now convert the arguments - kludge to limit ourselves to /bin/sh - i=0 - for arg in "$@" ; do - CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` - CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option - - if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition - eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` - else - eval `echo args$i`="\"$arg\"" - fi - i=$((i+1)) - done - case $i in - (0) set -- ;; - (1) set -- "$args0" ;; - (2) set -- "$args0" "$args1" ;; - (3) set -- "$args0" "$args1" "$args2" ;; - (4) set -- "$args0" "$args1" "$args2" "$args3" ;; - (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; - (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; - (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; - (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; - (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; - esac -fi - -# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules -function splitJvmOpts() { - JVM_OPTS=("$@") -} -eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS -JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" - -exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" diff --git a/programs/android/template/untitled/gradlew.bat b/programs/android/template/untitled/gradlew.bat deleted file mode 100644 index 8a0b282aa..000000000 --- a/programs/android/template/untitled/gradlew.bat +++ /dev/null @@ -1,90 +0,0 @@ -@if "%DEBUG%" == "" @echo off -@rem ########################################################################## -@rem -@rem Gradle startup script for Windows -@rem -@rem ########################################################################## - -@rem Set local scope for the variables with windows NT shell -if "%OS%"=="Windows_NT" setlocal - -@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS= - -set DIRNAME=%~dp0 -if "%DIRNAME%" == "" set DIRNAME=. -set APP_BASE_NAME=%~n0 -set APP_HOME=%DIRNAME% - -@rem Find java.exe -if defined JAVA_HOME goto findJavaFromJavaHome - -set JAVA_EXE=java.exe -%JAVA_EXE% -version >NUL 2>&1 -if "%ERRORLEVEL%" == "0" goto init - -echo. -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:findJavaFromJavaHome -set JAVA_HOME=%JAVA_HOME:"=% -set JAVA_EXE=%JAVA_HOME%/bin/java.exe - -if exist "%JAVA_EXE%" goto init - -echo. -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:init -@rem Get command-line arguments, handling Windowz variants - -if not "%OS%" == "Windows_NT" goto win9xME_args -if "%@eval[2+2]" == "4" goto 4NT_args - -:win9xME_args -@rem Slurp the command line arguments. -set CMD_LINE_ARGS= -set _SKIP=2 - -:win9xME_args_slurp -if "x%~1" == "x" goto execute - -set CMD_LINE_ARGS=%* -goto execute - -:4NT_args -@rem Get arguments from the 4NT Shell from JP Software -set CMD_LINE_ARGS=%$ - -:execute -@rem Setup the command line - -set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar - -@rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% - -:end -@rem End local scope for the variables with windows NT shell -if "%ERRORLEVEL%"=="0" goto mainEnd - -:fail -rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of -rem the _cmd.exe /c_ return code! -if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 -exit /b 1 - -:mainEnd -if "%OS%"=="Windows_NT" endlocal - -:omega diff --git a/programs/android/template/untitled/local.properties b/programs/android/template/untitled/local.properties deleted file mode 100644 index f2e7798e8..000000000 --- a/programs/android/template/untitled/local.properties +++ /dev/null @@ -1,8 +0,0 @@ -## This file must *NOT* be checked into Version Control Systems, -# as it contains information specific to your local configuration. -# -# Location of the SDK. This is only used by Gradle. -# -#Sun Apr 05 17:45:27 AEST 2015 -sdk.dir=C\:\\Users\\Robert\\AppData\\Local\\Android\\sdk1 -ndk.dir=C\:\\ndk \ No newline at end of file diff --git a/programs/android/template/untitled/settings.gradle b/programs/android/template/untitled/settings.gradle deleted file mode 100644 index e7b4def49..000000000 --- a/programs/android/template/untitled/settings.gradle +++ /dev/null @@ -1 +0,0 @@ -include ':app' diff --git a/programs/android/template/untitled/untitled.iml b/programs/android/template/untitled/untitled.iml deleted file mode 100644 index 0bb6048ae..000000000 --- a/programs/android/template/untitled/untitled.iml +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - - - - - - - - - - - - - diff --git a/source/embed/footer_stub.bas b/source/embed/footer_stub.bas new file mode 100644 index 000000000..6d8004f6d --- /dev/null +++ b/source/embed/footer_stub.bas @@ -0,0 +1,2 @@ +SUB VkUpdate +END SUB diff --git a/source/embed/header_stub.bas b/source/embed/header_stub.bas new file mode 100644 index 000000000..fb300439a --- /dev/null +++ b/source/embed/header_stub.bas @@ -0,0 +1,3 @@ +'blank line +CONST TRUE = -1 +CONST FALSE = 0 diff --git a/source/qb64.bas b/source/qb64.bas index 3023639af..654905f7e 100644 --- a/source/qb64.bas +++ b/source/qb64.bas @@ -18,9 +18,6 @@ $SCREENHIDE 'INCLUDE:'qb_framework\qb_framework_global.bas' DEFLNG A-Z -'INCLUDE:'virtual_keyboard\virtual_keyboard_global.bas' -DEFLNG A-Z - '-------- Optional IDE Component (1/2) -------- '$INCLUDE:'ide\ide_global.bas' @@ -29,10 +26,6 @@ REDIM SHARED PL(0) AS INTEGER 'Priority Level DIM SHARED QuickReturn AS INTEGER Set_OrderOfOperations 'This will also make certain our directories are valid, and if not make them. -DIM SHARED VirtualKeyboardState -DIM SHARED DesiredVirtualKeyboardState -DIM SHARED RecompileAttemptsForVirtualKeyboardState - REDIM EveryCaseSet(100), SelectCaseCounter AS _UNSIGNED LONG DIM ExecLevel(255), ExecCounter AS INTEGER REDIM SHARED UserDefine(1, 100) AS STRING '0 element is the name, 1 element is the string value @@ -1192,14 +1185,8 @@ sflistn = -1 'no entries SubNameLabels = sp 'QB64 will perform a repass to resolve sub names used as labels -DesiredVirtualKeyboardState = 0 -RecompileAttemptsForVirtualKeyboardState = 0 - recompile: -'move desired state into active state -VirtualKeyboardState = DesiredVirtualKeyboardState - lastLineReturn = 0 lastLine = 0 firstLine = 1 @@ -1572,13 +1559,8 @@ DO IF lastLine <> 0 OR firstLine <> 0 THEN lineBackup$ = wholeline$ 'backup the real line (will be blank when lastline is set) - IF VirtualKeyboardState THEN - IF firstLine <> 0 THEN forceIncludeFromRoot$ = "source\virtual_keyboard\embed\header.bas" - IF lastLine <> 0 THEN forceIncludeFromRoot$ = "source\virtual_keyboard\embed\footer.bas" - ELSE - IF firstLine <> 0 THEN forceIncludeFromRoot$ = "source\virtual_keyboard\embed\header_stub.bas" - IF lastLine <> 0 THEN forceIncludeFromRoot$ = "source\virtual_keyboard\embed\footer_stub.bas" - END IF + IF firstLine <> 0 THEN forceIncludeFromRoot$ = "source\embed\header_stub.bas" + IF lastLine <> 0 THEN forceIncludeFromRoot$ = "source\embed\footer_stub.bas" firstLine = 0: lastLine = 0 GOTO forceInclude_prepass forceIncludeCompleted_prepass: @@ -1605,32 +1587,6 @@ DO temp$ = LTRIM$(RTRIM$(UCASE$(wholestv$))) - IF temp$ = "$VIRTUALKEYBOARD:ON" THEN - DesiredVirtualKeyboardState = 1 - IF VirtualKeyboardState = 0 THEN - IF RecompileAttemptsForVirtualKeyboardState = 0 THEN - 'this is the first time a conflict has occurred, so react immediately with a full recompilation using the desired state - RecompileAttemptsForVirtualKeyboardState = RecompileAttemptsForVirtualKeyboardState + 1 - GOTO do_recompile - ELSE - 'continue compilation to retrieve the final state requested and act on that as required - END IF - END IF - END IF - - IF temp$ = "$VIRTUALKEYBOARD:OFF" THEN - DesiredVirtualKeyboardState = 0 - IF VirtualKeyboardState <> 0 THEN - IF RecompileAttemptsForVirtualKeyboardState = 0 THEN - 'this is the first time a conflict has occurred, so react immediately with a full recompilation using the desired state - RecompileAttemptsForVirtualKeyboardState = RecompileAttemptsForVirtualKeyboardState + 1 - GOTO do_recompile - ELSE - 'continue compilation to retrieve the final state requested and act on that as required - END IF - END IF - END IF - IF LEFT$(temp$, 4) = "$IF " THEN IF RIGHT$(temp$, 5) <> " THEN" THEN a$ = "$IF without THEN": GOTO errmes temp$ = LTRIM$(MID$(temp$, 4)) 'strip off the $IF and extra spaces @@ -2929,13 +2885,8 @@ DO IF lastLine <> 0 OR firstLine <> 0 THEN lineBackup$ = a3$ 'backup the real first line (will be blank when lastline is set) - IF VirtualKeyboardState THEN - IF firstLine <> 0 THEN forceIncludeFromRoot$ = "source\virtual_keyboard\embed\header.bas" - IF lastLine <> 0 THEN forceIncludeFromRoot$ = "source\virtual_keyboard\embed\footer.bas" - ELSE - IF firstLine <> 0 THEN forceIncludeFromRoot$ = "source\virtual_keyboard\embed\header_stub.bas" - IF lastLine <> 0 THEN forceIncludeFromRoot$ = "source\virtual_keyboard\embed\footer_stub.bas" - END IF + IF firstLine <> 0 THEN forceIncludeFromRoot$ = "source\embed\header_stub.bas" + IF lastLine <> 0 THEN forceIncludeFromRoot$ = "source\embed\footer_stub.bas" firstLine = 0: lastLine = 0 GOTO forceInclude forceIncludeCompleted: @@ -3126,11 +3077,13 @@ DO END IF IF a3u$ = "$VIRTUALKEYBOARD:ON" THEN + 'Deprecated; does nothing. layout$ = "$VIRTUALKEYBOARD:ON" GOTO finishednonexec END IF IF a3u$ = "$VIRTUALKEYBOARD:OFF" THEN + 'Deprecated; does nothing. layout$ = "$VIRTUALKEYBOARD:OFF" GOTO finishednonexec END IF @@ -10988,11 +10941,6 @@ FOR x = 1 TO commonarraylistn NEXT IF Debug THEN PRINT #9, "Finished COMMON array list check!" -IF DesiredVirtualKeyboardState <> VirtualKeyboardState THEN - RecompileAttemptsForVirtualKeyboardState = RecompileAttemptsForVirtualKeyboardState + 1 - recompile = 1 -END IF - IF recompile THEN do_recompile: IF Debug THEN PRINT #9, "Recompile required!" @@ -24888,8 +24836,5 @@ END SUB 'INCLUDE:'qb_framework\qb_framework_methods.bas' DEFLNG A-Z -'INCLUDE:'virtual_keyboard\virtual_keyboard_methods.bas' -DEFLNG A-Z - '-------- Optional IDE Component (2/2) -------- '$INCLUDE:'ide\ide_methods.bas' diff --git a/source/qb_framework/qb_framework_global.bas b/source/qb_framework/qb_framework_global.bas deleted file mode 100644 index 1ac2adccd..000000000 --- a/source/qb_framework/qb_framework_global.bas +++ /dev/null @@ -1,172 +0,0 @@ -'#################### QB-FRAMEWORK: Environment #################### -DEFLNG A-Z -'DEFLNG A-Z isn't required, but certain functions require LONG type variables -'as their parameters and return data in them, for example QB_NODE_each(...) -'################################################## - -'#################### QB-FRAMEWORK: Global #################### -DIM SHARED QB_DEBUG AS LONG '1 or 0 -DIM SHARED QB_DEBUG_VERBOSE AS LONG '1 or 0 -QB_DEBUG = 0 -QB_DEBUG_VERBOSE = 0 'set in conjunction with QB_DEBUG for more detailed debug infromation -IF QB_DEBUG_VERBOSE THEN QB_DEBUG = 1 -'Quick copy-paste references: -' QB_DEBUG_VERBOSE = 1: QB_DEBUG = 1 -' QB_DEBUG_VERBOSE = 0: QB_DEBUG = 0 -'################################################## - -'#################### EACH: Global #################### -'Handle Handlers (used to manage a set of handles) -CONST QB_EACH_NO_BLANK& = 0 'the default, blank entries will not be returned -CONST QB_EACH_ALLOW_BLANK& = 1 'captures implied blanks in adjacent, leading & trailing separators -CONST QB_EACH_ALLOW_ALL_BLANK& = 2 'also captures blank if entire parent is blank (not captured by default) - -'#################### HANDLE: Global #################### -'Handle Handlers (used to manage a set of handles) -TYPE __QB_HANDLE_HANDLER - lastFreedListIndex AS LONG '0=none - lastHandle AS LONG - count AS LONG -END TYPE -REDIM SHARED __QB_HANDLE_handler(1 + 0) AS __QB_HANDLE_HANDLER -'manually setup the first handle handler to maintain handles to our handle handlers -__QB_HANDLE_handler(1).lastHandle = 1 -__QB_HANDLE_handler(1).lastFreedListIndex = 0 -'Freed List -TYPE __QB_HANDLE_FREEDLIST - handle AS LONG - prevFreedListIndex AS LONG 'of same owner -END TYPE -REDIM SHARED __QB_HANDLE_freedList(1 + 0) AS __QB_HANDLE_FREEDLIST -DIM SHARED __QB_HANDLE_freedList_Last AS LONG: __QB_HANDLE_freedList_Last = 1 -DIM SHARED __QB_HANDLE_freedList_Next AS LONG: __QB_HANDLE_freedList_Next = 1 -'Freed-Freed List -REDIM SHARED __QB_HANDLE_freedFreedList(1 + 0) AS LONG -DIM SHARED __QB_HANDLE_freedFreedList_Last AS LONG: __QB_HANDLE_freedFreedList_Last = 1 -DIM SHARED __QB_HANDLE_freedFreedList_Next AS LONG: __QB_HANDLE_freedFreedList_Next = 1 -'################################################## - -'#################### DATETIME: Global #################### -CONST QB_DATETIME_TYPE_LOCAL = 1 'local time -CONST QB_DATETIME_TYPE_OFFSET = 3 -CONST QB_DATETIME_TYPE_DURATION = 4 -'For duration: -' 1 day=24 hours regardless of timezone -' 1 year=366 days regardless of year -' 1 month=31 days regardless of month -TYPE QB_DATETIME - reserved AS LONG - days AS LONG '1-31 - months AS LONG '1-12 - years AS LONG 'eg. 2015 - hours AS LONG '0-23 - minutes AS LONG '0-59 - seconds AS LONG '0-59 - milliseconds AS LONG '0-999 - microseconds AS LONG '0-999 (a microsecond is 1/1000th of a millisecond) - type AS LONG -END TYPE -DIM SHARED __QB_DATETIME_TYPE_EMPTY AS QB_DATETIME -REDIM SHARED __QB_DATETIME(0 + 1) AS QB_DATETIME -DIM SHARED __QB_DATETIME_ubound AS LONG: __QB_DATETIME_ubound = 1 -DIM SHARED __QB_DATETIME_handleSet AS LONG: __QB_DATETIME_handleSet = QB_HANDLE_newSet -'################################################## - -'#################### STRING: Global #################### -REDIM SHARED __QB_STR_string(1 + 0) AS STRING -REDIM SHARED __QB_STR_stringValid(1 + 0) AS LONG -DIM SHARED __QB_STR_stringUbound AS LONG: __QB_STR_stringUbound = 1 -DIM SHARED __QB_STR_handleSet AS LONG: __QB_STR_handleSet = QB_HANDLE_newSet -DIM SHARED QB_STR_QUOTE AS STRING: QB_STR_QUOTE = CHR$(34) -'################################################## - -'#################### NODE: Global #################### -CONST QB_NODE_TYPE_HASHSET& = 1 -CONST QB_NODE_TYPE_LIST& = 2 -CONST QB_NODE_TYPE_DICTIONARY& = 4 -CONST QB_NODE_TYPE_VALUE& = 8 'a simple value, optionally with a label - -CONST QB_NODE_ALLOW_DUPLICATE_KEYS& = 256 -CONST QB_NODE_CASE_SENSITIVE& = 512 -CONST QB_NODE_AVOID_DUPLICATE_VALUES_PER_KEY& = 1024 'new entries will not be added to a key if it already contains the value unless nTh is specified -CONST QB_NODE_DUPLICATE_VALUES_CASE_SENSITIVE& = 2048 'duplicate values check is case sensitive -CONST QB_NODE_DESTROY_ORPHANED_CHILDNODES& = 4096 - -CONST QB_NODE_FORMAT_LONG& = 1 -CONST QB_NODE_FORMAT_STR& = 2 -CONST QB_NODE_FORMAT_BOOL& = 4 -CONST QB_NODE_FORMAT_NULL& = 8 - -CONST QB_TRUE& = -1 -CONST QB_FALSE& = 0 -CONST QB_NULL& = -2 - -TYPE QB_NODE_TYPE - valid AS LONG - type AS LONG - flags AS LONG - 'linkage - parent AS LONG - firstChild AS LONG - lastChild AS LONG - count AS LONG - next AS LONG - prev AS LONG - owner AS LONG 'optional - 'label & value - label AS LONG - labelFormat AS LONG 'eg. QB_NODE_FORMAT_STR - value AS LONG - valueFormat AS LONG - 'hashsets & dictionaries - hashOffset AS LONG 'added to all keys to increase the chance of uniqueness against other KVP sets with different owners - hashReference AS LONG 'handle/value of the hashtable reference which points to this node -END TYPE - -DIM SHARED QB_NODE_TYPE_EMPTY AS QB_NODE_TYPE -QB_NODE_TYPE_EMPTY.labelFormat = QB_NODE_FORMAT_NULL -QB_NODE_TYPE_EMPTY.valueFormat = QB_NODE_FORMAT_NULL -REDIM SHARED __QB_NODE(0 + 1) AS QB_NODE_TYPE -REDIM SHARED __QB_NODE_hashLists(0 + 16777215) AS LONG -DIM SHARED __QB_NODE_ubound: __QB_NODE_ubound = 1 -DIM SHARED __QB_NODE_handleSet AS LONG: __QB_NODE_handleSet = QB_HANDLE_newSet - -'################################################## - -'#################### __JSON: Global #################### -CONST QB_JSON_STRING& = 1 -CONST QB_JSON_NUMBER& = 2 -CONST QB_JSON_BOOL& = 3 -CONST QB_JSON_NULL& = 4 -'http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-404.pdf -'\b Backspace CHR$(8) -'\f Form feed CHR$(12) -'\n New line CHR$(10) -'\r Carriage return CHR$(13) -'\t Tab CHR$(9) -'\" Double quote CHR$(34) -'\\ Backslash caracter CHR$(92) -DIM SHARED __QB_JSON_escape_lookup(255) AS LONG -__QB_JSON_escape_lookup(8) = ASC("b") -__QB_JSON_escape_lookup(12) = ASC("f") -__QB_JSON_escape_lookup(10) = ASC("n") -__QB_JSON_escape_lookup(13) = ASC("r") -__QB_JSON_escape_lookup(9) = ASC("t") -__QB_JSON_escape_lookup(34) = 34 -__QB_JSON_escape_lookup(92) = ASC("\") -DIM SHARED __QB_JSON_escape_lookup_reversed(255) AS LONG -__QB_JSON_escape_lookup_reversed(ASC("b")) = 8 -__QB_JSON_escape_lookup_reversed(ASC("f")) = 12 -__QB_JSON_escape_lookup_reversed(ASC("n")) = 10 -__QB_JSON_escape_lookup_reversed(ASC("r")) = 13 -__QB_JSON_escape_lookup_reversed(ASC("t")) = 9 -__QB_JSON_escape_lookup_reversed(34) = 34 -__QB_JSON_escape_lookup_reversed(ASC("\")) = 92 -__QB_JSON_escape_lookup_reversed(ASC("B")) = 8 -__QB_JSON_escape_lookup_reversed(ASC("F")) = 12 -__QB_JSON_escape_lookup_reversed(ASC("N")) = 10 -__QB_JSON_escape_lookup_reversed(ASC("R")) = 13 -__QB_JSON_escape_lookup_reversed(ASC("T")) = 9 -__QB_JSON_escape_lookup_reversed(ASC("'")) = 39 'allow for escaping single quotes \' -_MAPUNICODE &H00A0~& TO 255 -'################################################## diff --git a/source/qb_framework/qb_framework_methods.bas b/source/qb_framework/qb_framework_methods.bas deleted file mode 100644 index cc471fb5b..000000000 --- a/source/qb_framework/qb_framework_methods.bas +++ /dev/null @@ -1,1968 +0,0 @@ -DEFLNG A-Z - -'#################### NODESET: Methods #################### - -FUNCTION QB_FRAMEWORK_leakInfo$ -DIM QB__handlesets AS LONG -QB__handlesets = QB_HANDLE_count(1) -DIM QB__nodes AS LONG -QB__nodes = QB_HANDLE_count(__QB_NODE_handleSet) -DIM QB__datetimes AS LONG -QB__datetimes = QB_HANDLE_count(__QB_DATETIME_handleSet) -DIM QB__strings AS LONG -QB__strings = QB_HANDLE_count(__QB_STR_handleSet) -DIM QB__leakInfo AS LONG -QB__leakInfo = QB_NODE_newDictionary -QB_NODE_assign QB__leakInfo, QB_NODE_newValueWithLabel_long("HANDLE_set_count", QB__handlesets) -QB_NODE_assign QB__leakInfo, QB_NODE_newValueWithLabel_long("STR_count", QB__strings) -QB_NODE_assign QB__leakInfo, QB_NODE_newValueWithLabel_long("NODE_count", QB__nodes) -QB_NODE_assign QB__leakInfo, QB_NODE_newValueWithLabel_long("DATETIME_count", QB__datetimes) -QB_NODE_assign QB__leakInfo, QB_NODE_newValueWithLabel_long("global_hash_table_size", (UBOUND(__QB_NODE_hashLists) + 1) * 4) -QB_FRAMEWORK_leakInfo$ = QB_NODESET_serialize(QB__leakInfo, "json") -QB_NODE_destroy QB__leakInfo -END FUNCTION - -SUB QB_NODESET_free (QB__selIn AS LONG) -IF QB__selIn < 0 THEN - QB_NODE_destroy -QB__selIn 'destroy this list/hashset of nodes -END IF -END SUB - -FUNCTION QB_NODESET_count& (QB__selIn AS LONG) -QB_NODESET_count& = QB_NODESET_count_PRESERVE&(QB__selIn) -QB_NODESET_free QB__selIn -END FUNCTION -FUNCTION QB_NODESET_count_PRESERVE& (QB__selIn AS LONG) -IF QB__selIn < 0 THEN - QB_NODESET_count_PRESERVE& = __QB_NODE(-QB__selIn).count -ELSE - IF QB__selIn <> 0 THEN - QB_NODESET_count_PRESERVE& = 1 - ELSE - QB_NODESET_count_PRESERVE& = 0 - END IF -END IF -END FUNCTION - -FUNCTION QB_NODESET_equal& (QB__selIn AS LONG, value AS STRING) -DIM QB__selOut AS LONG: QB__selOut = QB_NODE_new(QB_NODE_TYPE_HASHSET, 0) -DIM QB__SelInI AS LONG: DIM QB__SelInIterator AS LONG -DIM QB__sel AS LONG -DIM QB__newSel AS LONG -IF QB__selIn < 0 THEN - DO WHILE QB_NODE_each(QB__SelInI, -QB__selIn, QB__SelInIterator) - QB__sel = __QB_NODE(QB__SelInI).label - IF __QB_NODE(QB__sel).valueFormat = QB_NODE_FORMAT_STR THEN - IF QB_STR_get(__QB_NODE(QB__sel).value) = value THEN - QB__newSel = QB_NODE_newLabel_long(QB__sel) - QB_NODE_assign QB__selOut, QB__newSel - END IF - END IF - LOOP -ELSE - QB__sel = QB__selIn - IF __QB_NODE(QB__sel).valueFormat = QB_NODE_FORMAT_STR THEN - IF QB_STR_get(__QB_NODE(QB__sel).value) = value THEN - QB__newSel = QB_NODE_newLabel_long(QB__sel) - QB_NODE_assign QB__selOut, QB__newSel - END IF - END IF -END IF -QB_NODESET_equal& = -QB__selOut -QB_NODESET_free QB__selIn -END FUNCTION - -FUNCTION QB_NODESET_label_equal& (QB__selIn AS LONG, value AS STRING) -DIM QB__selOut AS LONG: QB__selOut = QB_NODE_new(QB_NODE_TYPE_HASHSET, 0) -DIM QB__SelInI AS LONG: DIM QB__SelInIterator AS LONG -DIM QB__sel AS LONG -DIM QB__newSel AS LONG -IF QB__selIn < 0 THEN - DO WHILE QB_NODE_each(QB__SelInI, -QB__selIn, QB__SelInIterator) - QB__sel = __QB_NODE(QB__SelInI).label - IF __QB_NODE(QB__sel).labelFormat = QB_NODE_FORMAT_STR THEN - IF QB_STR_get(__QB_NODE(QB__sel).label) = value THEN - QB__newSel = QB_NODE_newLabel_long(QB__sel) - QB_NODE_assign QB__selOut, QB__newSel - END IF - END IF - LOOP -ELSE - QB__sel = QB__selIn - IF __QB_NODE(QB__sel).labelFormat = QB_NODE_FORMAT_STR THEN - IF QB_STR_get(__QB_NODE(QB__sel).label) = value THEN - QB__newSel = QB_NODE_newLabel_long(QB__sel) - QB_NODE_assign QB__selOut, QB__newSel - END IF - END IF -END IF -QB_NODESET_label_equal& = -QB__selOut -QB_NODESET_free QB__selIn -END FUNCTION - -FUNCTION QB_NODESET_allChildren& (QB__selIn AS LONG) 'all decendants, all depths -DIM QB__selOut AS LONG: QB__selOut = QB_NODE_new(QB_NODE_TYPE_HASHSET, 0) -DIM QB__SelInI AS LONG: DIM QB__SelInIterator AS LONG -DIM QB__sel AS LONG -IF QB__selIn < 0 THEN - DO WHILE QB_NODE_each(QB__SelInI, -QB__selIn, QB__SelInIterator) - QB__sel = __QB_NODE(QB__SelInI).label - IF __QB_NODE(QB__sel).count THEN - __QB_NODESET_addChildren QB__sel, QB__selOut - END IF - LOOP -ELSE - QB__sel = QB__selIn - IF __QB_NODE(QB__sel).count THEN - __QB_NODESET_addChildren QB__sel, QB__selOut - END IF -END IF -QB_NODESET_allChildren& = -QB__selOut -QB_NODESET_free QB__selIn -END FUNCTION - -FUNCTION QB_NODESET_children& (QB__selIn AS LONG) 'only 1st level decendants -DIM QB__selOut AS LONG: QB__selOut = QB_NODE_new(QB_NODE_TYPE_HASHSET, 0) -DIM QB__SelInI AS LONG: DIM QB__SelInIterator AS LONG -DIM QB__sel AS LONG -IF QB__selIn < 0 THEN - DO WHILE QB_NODE_each(QB__SelInI, -QB__selIn, QB__SelInIterator) - QB__sel = __QB_NODE(QB__SelInI).label - IF __QB_NODE(QB__sel).count THEN - __QB_NODESET_addChildrenWithDepth QB__sel, QB__selOut, 1, 1, 1 - END IF - LOOP -ELSE - QB__sel = QB__selIn - IF __QB_NODE(QB__sel).count THEN - __QB_NODESET_addChildrenWithDepth QB__sel, QB__selOut, 1, 1, 1 - END IF -END IF -QB_NODESET_children& = -QB__selOut -QB_NODESET_free QB__selIn -END FUNCTION - -FUNCTION QB_NODESET_parent& (QB__selIn AS LONG) -DIM QB__selOut AS LONG: QB__selOut = QB_NODE_new(QB_NODE_TYPE_HASHSET, 0) -DIM QB__SelInI AS LONG: DIM QB__SelInIterator AS LONG -DIM QB__sel AS LONG -DIM QB__newSel AS LONG -IF QB__selIn < 0 THEN - DO WHILE QB_NODE_each(QB__SelInI, -QB__selIn, QB__SelInIterator) - QB__sel = __QB_NODE(QB__SelInI).label - IF __QB_NODE(QB__sel).parent THEN - QB__newSel = QB_NODE_newLabel_long(__QB_NODE(QB__sel).parent) - QB_NODE_assign QB__selOut, QB__newSel - END IF - LOOP -ELSE - QB__sel = QB__selIn - IF __QB_NODE(QB__sel).parent THEN - QB__newSel = QB_NODE_newLabel_long(__QB_NODE(QB__sel).parent) - QB_NODE_assign QB__selOut, QB__newSel - END IF -END IF -QB_NODESET_parent& = -QB__selOut -QB_NODESET_free QB__selIn -END FUNCTION - -FUNCTION QB_NODESET_node& (QB__selIn AS LONG) -IF QB__selIn >= 0 THEN - QB_NODESET_node& = QB__selIn - 'note: not a nodeset, no need to call nodeset free - EXIT FUNCTION -END IF -DIM QB__sel AS LONG -QB__sel = __QB_NODE(-QB__selIn).firstChild -IF QB__sel <> 0 THEN - QB__sel = __QB_NODE(QB__sel).label -END IF -QB_NODESET_node& = QB__sel -QB_NODESET_free QB__selIn -END FUNCTION - -FUNCTION QB_NODESET_parents& (QB__selIn AS LONG) -DIM QB__selOut AS LONG: QB__selOut = QB_NODE_new(QB_NODE_TYPE_HASHSET, 0) -DIM QB__SelInI AS LONG: DIM QB__SelInIterator AS LONG -DIM QB__sel AS LONG -DIM QB__newSel AS LONG -IF QB__selIn < 0 THEN - DO WHILE QB_NODE_each(QB__SelInI, -QB__selIn, QB__SelInIterator) - QB__sel = __QB_NODE(QB__SelInI).label - QB__sel = __QB_NODE(QB__sel).parent - DO WHILE QB__sel - QB__newSel = QB_NODE_newLabel_long(QB__sel) - QB_NODE_assign QB__selOut, QB__newSel - QB__sel = __QB_NODE(QB__sel).parent - LOOP - LOOP -ELSE - QB__sel = QB__selIn - QB__sel = __QB_NODE(QB__sel).parent - DO WHILE QB__sel - QB__newSel = QB_NODE_newLabel_long(QB__sel) - QB_NODE_assign QB__selOut, QB__newSel - QB__sel = __QB_NODE(QB__sel).parent - LOOP -END IF -QB_NODESET_parents& = -QB__selOut -QB_NODESET_free QB__selIn -END FUNCTION - -FUNCTION QB_NODESET_each& (QB__SelInI AS LONG, QB__selIn AS LONG, QB__selInIterator AS LONG) -DIM QB__ret AS LONG -QB__ret = QB_NODESET_each_PRESERVE(QB__SelInI, QB__selIn, QB__selInIterator) -IF QB__ret = 0 THEN QB_NODESET_free QB__selIn -QB_NODESET_each& = QB__ret -END FUNCTION -FUNCTION QB_NODESET_each_PRESERVE& (QB__SelInI AS LONG, QB__selIn AS LONG, QB__selInIterator AS LONG) -IF QB__selIn > 0 THEN - IF QB__selInIterator = 0 THEN - QB_NODESET_each_PRESERVE& = -1 - QB__SelInI = QB__selIn - ELSE - QB__selInIterator = 1 - QB_NODESET_each_PRESERVE& = 0 - QB__SelInI = 0 - END IF -ELSE - DIM QB__ret AS LONG - QB_NODESET_each_PRESERVE = QB_NODE_each(QB__SelInI, -QB__selIn, QB__selInIterator) - IF QB__SelInI <> 0 THEN QB__SelInI = __QB_NODE(QB__SelInI).label -END IF -END FUNCTION - -FUNCTION QB_NODESET_deserialize& (json AS STRING, format AS STRING) 'only "json" is supported -'prepass to make deserializing by scanning (INSTR) for : { } [ ] , work -DIM json2 AS STRING -json2 = SPACE$(LEN(json) * 6) 'the maximum size preparsed content can grow is 6x -i2 = 0 -inblock = 0 -lastA = 0 -lastLastA = 0 -FOR i1 = 1 TO LEN(json) - a = ASC(json, i1) - IF inblock THEN - IF a = 58 OR a = 123 OR a = 125 OR a = 91 OR a = 93 OR a = 44 THEN 'escape... : { } [ ] , - IF a = 58 THEN i2 = i2 + 6: MID$(json2, i2 - 5, 6) = "\u003A" - IF a = 123 THEN i2 = i2 + 6: MID$(json2, i2 - 5, 6) = "\u007B" - IF a = 125 THEN i2 = i2 + 6: MID$(json2, i2 - 5, 6) = "\u007D" - IF a = 91 THEN i2 = i2 + 6: MID$(json2, i2 - 5, 6) = "\u005B" - IF a = 93 THEN i2 = i2 + 6: MID$(json2, i2 - 5, 6) = "\u005D" - IF a = 44 THEN i2 = i2 + 6: MID$(json2, i2 - 5, 6) = "\u002C" - ELSE - i2 = i2 + 1: ASC(json2, i2) = a - END IF - IF a = inblock AND ((lastA <> 92) OR (lastA = 92 AND lastLastA = 92)) THEN inblock = 0 'note: we allow \' - ELSE - IF a = 34 THEN inblock = 34 - IF a = 39 THEN inblock = 39 - i2 = i2 + 1: ASC(json2, i2) = a - END IF - lastLastA = lastA - lastA = a -NEXT -json2 = LEFT$(json2, i2) -json2 = LTRIM$(RTRIM$(json2)) -DIM QB__index AS LONG -QB__index = 1 -QB_NODESET_deserialize& = __QB_JSON_deserialize(json2, QB__index, 0) -END FUNCTION - -FUNCTION QB_NODESET_serialize$ (QB__selIn AS LONG, format AS STRING) 'only "json" is supported -QB_NODESET_serialize$ = QB_NODESET_serialize_PRESERVE$(QB__selIn, format) -QB_NODESET_free QB__selIn -END FUNCTION -FUNCTION QB_NODESET_serialize_PRESERVE$ (QB__selIn AS LONG, format AS STRING) 'only "json" is supported -DIM QB__ret AS STRING -DIM QB__SelInI AS LONG: DIM QB__SelInIterator AS LONG -DIM QB__sel AS LONG -IF QB__selIn < 0 THEN - DIM QB__n AS LONG - DO WHILE QB_NODE_each(QB__SelInI, -QB__selIn, QB__SelInIterator) - QB__sel = __QB_NODE(QB__SelInI).label - QB__n = QB__n + 1 - __QB_JSON_serialize QB__ret, QB__sel, 0 - IF __QB_NODE(-QB__selIn).count <> QB__n THEN QB__ret = QB__ret + "," - LOOP -ELSE - QB__sel = QB__selIn - __QB_JSON_serialize QB__ret, QB__sel, 0 -END IF -QB_NODESET_serialize_PRESERVE$ = QB__ret -END FUNCTION - -'######################################## - -'#################### DATETIME: Methods #################### -FUNCTION QB_DATETIME_new (dateTimeType AS LONG) -DIM QB__handle AS LONG -QB__handle = QB_HANDLE_new(__QB_DATETIME_handleSet) -IF QB__handle > __QB_DATETIME_ubound THEN - __QB_DATETIME_ubound = QB__handle * 2 - REDIM _PRESERVE __QB_DATETIME(__QB_DATETIME_ubound) AS QB_DATETIME -END IF -__QB_DATETIME(QB__handle) = __QB_DATETIME_TYPE_EMPTY -__QB_DATETIME(QB__handle).reserved = 1 -__QB_DATETIME(QB__handle).type = dateTimeType -QB_DATETIME_new& = QB__handle -END FUNCTION - -SUB QB_DATETIME_get (QB__handle AS LONG, dateTimeToPopulate AS QB_DATETIME) -dateTimeToPopulate = __QB_DATETIME(QB__handle) -END SUB - -SUB QB_DATETIME_set (QB__handle AS LONG, dateTimeToPopulate AS QB_DATETIME) -__QB_DATETIME(QB__handle) = dateTimeToPopulate -END SUB - -SUB QB_DATETIME_free (QB__handle AS LONG) -IF QB__handle > __QB_DATETIME_ubound OR QB__handle <= 0 THEN ERROR 258: EXIT SUB 'invalid handle -IF __QB_DATETIME(QB__handle).reserved = 0 THEN ERROR 258: EXIT SUB -__QB_DATETIME(QB__handle).reserved = 0 -QB_HANDLE_free QB__handle, __QB_DATETIME_handleSet -END SUB - -FUNCTION QB_DATETIME_now -DIM QB__handle AS LONG -QB__handle = QB_DATETIME_new(QB_DATETIME_TYPE_LOCAL) -DIM QB__date AS STRING -QB__date = DATE$ 'mm-dd-yyyy -DIM QB__time AS STRING -QB__time = TIME$ 'hh:mm:ss -DIM QB__timer AS DOUBLE -QB__timer = TIMER(0.001) -__QB_DATETIME(QB__handle).months = VAL(MID$(QB__date, 1, 2)) -__QB_DATETIME(QB__handle).days = VAL(MID$(QB__date, 4, 2)) -__QB_DATETIME(QB__handle).years = VAL(MID$(QB__date, 7, 4)) -__QB_DATETIME(QB__handle).hours = VAL(MID$(QB__time, 1, 2)) -__QB_DATETIME(QB__handle).minutes = VAL(MID$(QB__time, 4, 2)) -__QB_DATETIME(QB__handle).seconds = VAL(MID$(QB__time, 7, 2)) -DIM QB__msStr AS STRING -DIM QB__ms AS LONG -QB__msStr = LTRIM$(STR$(QB__timer - INT(QB__timer))) -IF LEN(QB__msStr) > 4 THEN QB__msStr = LEFT$(QB__msStr, 4) -QB__ms = VAL(QB__msStr) * 1000 -IF QB__ms >= 1000 THEN QB__ms = 0 -__QB_DATETIME(QB__handle).milliseconds = QB__ms -QB_DATETIME_now& = QB__handle -END FUNCTION - -FUNCTION QB_DATETIME_format$ (QB__handle AS LONG, format AS STRING) -'Example: -' PRINT QB_DATETIME_format(myDateHandle, "D/M/YYYY H:mm:ss {AM}") 'could print "31/3/2012 5:02:05 PM" -' -'YYYY - 4 digit year -'YY - 2 digit year -'MM - 2 digit month -'M - 1 or 2 digit month -'DD - 2 digit day -'D - 1 or 2 digit day -'{TH},{Th},{th} -'{JAN},{jan},{Jan} -'{JANUARY},{january},{January} -'{MONDAY},{Monday},{monday} -'hh - 2 digit hour (24 hour time) -'HH - 2 digit hour (12 hour time) -'h - 1 or 2 digit hour (24 hour time) -'H - 1 or 2 digit hour (12 hour time) -'mm - 2 digit minutes -'m - 1 or 2 digit minutes -'ss - 2 digit seconds -'s - 1 or 2 digit seconds -'zzz - 3 digit milliseconds -'z - 1, 2 or 3 digit milliseconds -'{AM},{am} -DIM QB__out AS STRING -QB__out = "" -DIM QB__i AS LONG -DIM QB__fi AS LONG -DIM QB__s AS STRING -DIM QB__i1 AS LONG - -DIM QB__minDigits AS LONG -DIM QB__value AS STRING - -DIM QB__rhs AS STRING - -DIM QB__n AS LONG -DIM QB__x AS LONG - -DIM QB__smartCase AS LONG - -FOR QB__fi = 1 TO LEN(format) - - FOR QB__i = 1 TO 100 - - QB__minDigits = -1 'N/A - QB__smartCase = 0 'match case exactly - - QB__s = "" - - QB__n = 0 - - QB__n = QB__n + 1: IF QB__i = QB__n THEN - QB__s = "{am}" - QB__smartCase = 1 - IF __QB_DATETIME(QB__handle).hours > 11 THEN QB__value = "pm" ELSE QB__value = "am" - END IF - - QB__n = QB__n + 1: IF QB__i = QB__n THEN - QB__s = "{th}" - QB__smartCase = 1 - QB__value = "th" - IF __QB_DATETIME(QB__handle).days MOD 10 = 1 THEN QB__value = "st" - IF __QB_DATETIME(QB__handle).days MOD 10 = 2 THEN QB__value = "nd" - IF __QB_DATETIME(QB__handle).days MOD 10 = 3 THEN QB__value = "rd" - IF __QB_DATETIME(QB__handle).days > 10 AND __QB_DATETIME(QB__handle).days < 14 THEN QB__value = "th" - END IF - - QB__n = QB__n + 1: IF QB__i = QB__n THEN - QB__s = "{monday}" - QB__smartCase = 1 - DIM QB__month AS LONG - DIM QB__year AS LONG - DIM QB__day AS LONG - DIM QB__newYear AS STRING - DIM QB__century AS LONG - DIM QB__dmy AS LONG - 'http://brisray.com/qbasic/qdate.htm - QB__day = __QB_DATETIME(QB__handle).days - QB__month = __QB_DATETIME(QB__handle).months - QB__year = __QB_DATETIME(QB__handle).years - IF QB__month < 3 THEN - QB__month = QB__month + 12 - QB__year = QB__year - 1 - END IF - '*** Add 1 to the month and multiply by 2.61 - '*** Drop the fraction (not round) afterwards - QB__month = QB__month + 1 - QB__month = FIX(QB__month * 2.61) - '*** Add Day, Month and the last two digits of the year - QB__newYear = LTRIM$(STR$(QB__year)) - QB__year = VAL(RIGHT$(QB__newYear, 2)) - QB__dmy = QB__day + QB__month + QB__year - QB__century = VAL(LEFT$(QB__newYear, 2)) - '*** Add a quarter of the last two digits of the year - '*** (truncated not rounded) - QB__year = FIX(QB__year / 4) - QB__dmy = QB__dmy + QB__year - '*** Add the following factors for the year - IF QB__century = 18 THEN QB__century = 2 - IF QB__century = 19 THEN QB__century = 0 - IF QB__century = 20 THEN QB__century = 6 - IF QB__century = 21 THEN QB__century = 4 - QB__dmy = QB__dmy + QB__century - '*** The day of the week is the modulus of DMY divided by 7 - QB__dmy = QB__dmy MOD 7 - IF QB__dmy = 0 THEN QB__value = "sunday" - IF QB__dmy = 1 THEN QB__value = "monday" - IF QB__dmy = 2 THEN QB__value = "tuesday" - IF QB__dmy = 3 THEN QB__value = "wednesday" - IF QB__dmy = 4 THEN QB__value = "thursday" - IF QB__dmy = 5 THEN QB__value = "friday" - IF QB__dmy = 6 THEN QB__value = "saturday" - END IF - - QB__n = QB__n + 1: IF QB__i = QB__n THEN - QB__s = "{mon}" - QB__smartCase = 1 - 'http://brisray.com/qbasic/qdate.htm - QB__day = __QB_DATETIME(QB__handle).days - QB__month = __QB_DATETIME(QB__handle).months - QB__year = __QB_DATETIME(QB__handle).years - IF QB__month < 3 THEN - QB__month = QB__month + 12 - QB__year = QB__year - 1 - END IF - '*** Add 1 to the month and multiply by 2.61 - '*** Drop the fraction (not round) afterwards - QB__month = QB__month + 1 - QB__month = FIX(QB__month * 2.61) - '*** Add Day, Month and the last two digits of the year - QB__newYear = LTRIM$(STR$(QB__year)) - QB__year = VAL(RIGHT$(QB__newYear, 2)) - QB__dmy = QB__day + QB__month + QB__year - QB__century = VAL(LEFT$(QB__newYear, 2)) - '*** Add a quarter of the last two digits of the year - '*** (truncated not rounded) - QB__year = FIX(QB__year / 4) - QB__dmy = QB__dmy + QB__year - '*** Add the following factors for the year - IF QB__century = 18 THEN QB__century = 2 - IF QB__century = 19 THEN QB__century = 0 - IF QB__century = 20 THEN QB__century = 6 - IF QB__century = 21 THEN QB__century = 4 - QB__dmy = QB__dmy + QB__century - '*** The day of the week is the modulus of DMY divided by 7 - QB__dmy = QB__dmy MOD 7 - IF QB__dmy = 0 THEN QB__value = "sun" - IF QB__dmy = 1 THEN QB__value = "mon" - IF QB__dmy = 2 THEN QB__value = "tue" - IF QB__dmy = 3 THEN QB__value = "wed" - IF QB__dmy = 4 THEN QB__value = "thu" - IF QB__dmy = 5 THEN QB__value = "fri" - IF QB__dmy = 6 THEN QB__value = "sat" - END IF - - QB__n = QB__n + 1: IF QB__i = QB__n THEN - QB__s = "{jan}" - QB__smartCase = 1 - IF __QB_DATETIME(QB__handle).months = 1 THEN QB__value = "jan" - IF __QB_DATETIME(QB__handle).months = 2 THEN QB__value = "feb" - IF __QB_DATETIME(QB__handle).months = 3 THEN QB__value = "mar" - IF __QB_DATETIME(QB__handle).months = 4 THEN QB__value = "apr" - IF __QB_DATETIME(QB__handle).months = 5 THEN QB__value = "may" - IF __QB_DATETIME(QB__handle).months = 6 THEN QB__value = "jun" - IF __QB_DATETIME(QB__handle).months = 7 THEN QB__value = "jul" - IF __QB_DATETIME(QB__handle).months = 8 THEN QB__value = "aug" - IF __QB_DATETIME(QB__handle).months = 9 THEN QB__value = "sep" - IF __QB_DATETIME(QB__handle).months = 10 THEN QB__value = "oct" - IF __QB_DATETIME(QB__handle).months = 11 THEN QB__value = "nov" - IF __QB_DATETIME(QB__handle).months = 12 THEN QB__value = "dec" - END IF - - - - - QB__n = QB__n + 1: IF QB__i = QB__n THEN - QB__s = "{january}" - QB__smartCase = 1 - IF __QB_DATETIME(QB__handle).months = 1 THEN QB__value = "january" - IF __QB_DATETIME(QB__handle).months = 2 THEN QB__value = "february" - IF __QB_DATETIME(QB__handle).months = 3 THEN QB__value = "march" - IF __QB_DATETIME(QB__handle).months = 4 THEN QB__value = "april" - IF __QB_DATETIME(QB__handle).months = 5 THEN QB__value = "may" - IF __QB_DATETIME(QB__handle).months = 6 THEN QB__value = "june" - IF __QB_DATETIME(QB__handle).months = 7 THEN QB__value = "july" - IF __QB_DATETIME(QB__handle).months = 8 THEN QB__value = "august" - IF __QB_DATETIME(QB__handle).months = 9 THEN QB__value = "september" - IF __QB_DATETIME(QB__handle).months = 10 THEN QB__value = "october" - IF __QB_DATETIME(QB__handle).months = 11 THEN QB__value = "november" - IF __QB_DATETIME(QB__handle).months = 12 THEN QB__value = "december" - END IF - - QB__n = QB__n + 1: IF QB__i = QB__n THEN QB__s = "YYYY": QB__minDigits = 4: QB__value = QB_STR_long(__QB_DATETIME(QB__handle).years) - QB__n = QB__n + 1: IF QB__i = QB__n THEN QB__s = "YY": QB__minDigits = 2: QB__value = QB_STR_long(__QB_DATETIME(QB__handle).years MOD 100) - - QB__n = QB__n + 1: IF QB__i = QB__n THEN QB__s = "MM": QB__minDigits = 2: QB__value = QB_STR_long(__QB_DATETIME(QB__handle).months) - QB__n = QB__n + 1: IF QB__i = QB__n THEN QB__s = "M": QB__minDigits = 1: QB__value = QB_STR_long(__QB_DATETIME(QB__handle).months) - - QB__n = QB__n + 1: IF QB__i = QB__n THEN QB__s = "DD": QB__minDigits = 2: QB__value = QB_STR_long(__QB_DATETIME(QB__handle).days) - QB__n = QB__n + 1: IF QB__i = QB__n THEN QB__s = "D": QB__minDigits = 1: QB__value = QB_STR_long(__QB_DATETIME(QB__handle).days) - - QB__n = QB__n + 1: IF QB__i = QB__n THEN QB__s = "hh": QB__minDigits = 2: QB__value = QB_STR_long(__QB_DATETIME(QB__handle).hours) - QB__n = QB__n + 1: IF QB__i = QB__n THEN QB__s = "h": QB__minDigits = 1: QB__value = QB_STR_long(__QB_DATETIME(QB__handle).hours) - - QB__n = QB__n + 1: IF QB__i = QB__n THEN - QB__s = "HH": QB__minDigits = 2: - QB__x = __QB_DATETIME(QB__handle).hours - IF QB__x > 12 THEN QB__x = QB__x - 12 - IF QB__x = 0 THEN QB__x = 12 - QB__value = QB_STR_long(QB__x) - END IF - QB__n = QB__n + 1: IF QB__i = QB__n THEN - QB__s = "H": QB__minDigits = 1 - QB__x = __QB_DATETIME(QB__handle).hours - IF QB__x > 12 THEN QB__x = QB__x - 12 - IF QB__x = 0 THEN QB__x = 12 - QB__value = QB_STR_long(QB__x) - END IF - - QB__n = QB__n + 1: IF QB__i = QB__n THEN QB__s = "mm": QB__minDigits = 2: QB__value = QB_STR_long(__QB_DATETIME(QB__handle).minutes) - QB__n = QB__n + 1: IF QB__i = QB__n THEN QB__s = "m": QB__minDigits = 1: QB__value = QB_STR_long(__QB_DATETIME(QB__handle).minutes) - - QB__n = QB__n + 1: IF QB__i = QB__n THEN QB__s = "ss": QB__minDigits = 2: QB__value = QB_STR_long(__QB_DATETIME(QB__handle).seconds) - QB__n = QB__n + 1: IF QB__i = QB__n THEN QB__s = "s": QB__minDigits = 1: QB__value = QB_STR_long(__QB_DATETIME(QB__handle).seconds) - - QB__n = QB__n + 1: IF QB__i = QB__n THEN QB__s = "zzz": QB__minDigits = 3: QB__value = QB_STR_long(__QB_DATETIME(QB__handle).milliseconds) - QB__n = QB__n + 1: IF QB__i = QB__n THEN QB__s = "z": QB__minDigits = 1: QB__value = QB_STR_long(__QB_DATETIME(QB__handle).milliseconds) - - - IF QB__s <> "" THEN - - IF QB__smartCase THEN - QB__rhs = LCASE$(RIGHT$(format, LEN(format) - QB__fi + 1)) + " " - ELSE - QB__rhs = RIGHT$(format, LEN(format) - QB__fi + 1) + " " - END IF - - IF LEFT$(QB__rhs, LEN(QB__s)) = QB__s THEN - IF QB__minDigits <> -1 THEN - IF LEN(QB__value) < QB__minDigits THEN - QB__value = STRING$(QB__minDigits - LEN(QB__value), "0") + QB__value - END IF - END IF - IF QB__smartCase THEN - QB__rhs = RIGHT$(format, LEN(format) - QB__fi + 1) + " " - QB__value = __QB_DATETIME_format_smartCase$(QB__rhs, QB__value) - END IF - - QB__out = QB__out + QB__value - QB__fi = QB__fi + LEN(QB__s) - 1 - EXIT FOR - END IF - END IF - NEXT - IF QB__i = 101 THEN QB__out = QB__out + MID$(format, QB__fi, 1) -NEXT -QB_DATETIME_format$ = QB__out -END FUNCTION - -'######################################## - - -'#################### STRING: Methods #################### - -FUNCTION QB_STR_empty& -DIM QB__handle AS LONG -QB__handle = QB_HANDLE_new(__QB_STR_handleSet) -IF QB__handle > __QB_STR_stringUbound THEN - __QB_STR_stringUbound = QB__handle * 2 - REDIM _PRESERVE __QB_STR_string(__QB_STR_stringUbound) AS STRING - REDIM _PRESERVE __QB_STR_stringValid(__QB_STR_stringUbound) AS LONG -END IF -__QB_STR_stringValid(QB__handle) = 1 -IF LEN(__QB_STR_string(QB__handle)) <> 0 THEN __QB_STR_string(QB__handle) = "" -QB_STR_empty& = QB__handle -END FUNCTION - -FUNCTION QB_STR_new& (Value AS STRING) -DIM QB__handle AS LONG -QB__handle = QB_HANDLE_new(__QB_STR_handleSet) -IF QB__handle > __QB_STR_stringUbound THEN - __QB_STR_stringUbound = QB__handle * 2 - REDIM _PRESERVE __QB_STR_string(__QB_STR_stringUbound) AS STRING - REDIM _PRESERVE __QB_STR_stringValid(__QB_STR_stringUbound) AS LONG -END IF -__QB_STR_stringValid(QB__handle) = 1 -__QB_STR_string(QB__handle) = Value -QB_STR_new& = QB__handle -END FUNCTION - -FUNCTION QB_STR_get$ (handle AS LONG) -IF handle > __QB_STR_stringUbound OR handle <= 0 THEN - $CHECKING:OFF - ERROR 258 'invalid handle - EXIT SUB - $CHECKING:ON -END IF -IF __QB_STR_stringValid(handle) = 0 THEN - $CHECKING:OFF - ERROR 258 'invalid handle - EXIT SUB - $CHECKING:ON -END IF -QB_STR_get$ = __QB_STR_string(handle) -END FUNCTION - -SUB QB_STR_set (handle AS LONG, value AS STRING) -IF handle > __QB_STR_stringUbound OR handle <= 0 THEN ERROR 258: EXIT SUB 'invalid handle -IF __QB_STR_stringValid(handle) = 0 THEN ERROR 258: EXIT SUB -__QB_STR_string(handle) = value -END SUB - -SUB QB_STR_free (handle AS LONG) -IF handle > __QB_STR_stringUbound OR handle <= 0 THEN ERROR 258: EXIT SUB 'invalid handle -IF __QB_STR_stringValid(handle) = 0 THEN ERROR 258: EXIT SUB -__QB_STR_stringValid(handle) = 0 -QB_HANDLE_free handle, __QB_STR_handleSet -END SUB - -FUNCTION QB_STR_long$ (value AS LONG) 'returns a string representation of a long value -QB_STR_long$ = LTRIM$(STR$(value)) -END FUNCTION - -'################################################## - - -'#################### HANDLE: Methods #################### - -FUNCTION QB_HANDLE_newSet& -DIM QB__context AS LONG -QB__context = QB_HANDLE_new(1) -IF UBOUND(__QB_HANDLE_handler) < QB__context THEN - REDIM _PRESERVE __QB_HANDLE_handler(QB__context * 2) AS __QB_HANDLE_HANDLER -END IF -__QB_HANDLE_handler(QB__context).lastFreedListIndex = 0 -__QB_HANDLE_handler(QB__context).lastHandle = 0 -__QB_HANDLE_handler(QB__context).count = 0 -QB_HANDLE_newSet& = QB__context -END FUNCTION - -SUB QB_HANDLE_freeSet (context AS LONG) -QB_HANDLE_free context, 1 -END SUB - -FUNCTION QB_HANDLE_count& (context AS LONG) -QB_HANDLE_count& = __QB_HANDLE_handler(context).count -END FUNCTION - -FUNCTION QB_HANDLE_new& (context AS LONG) -__QB_HANDLE_handler(context).count = __QB_HANDLE_handler(context).count + 1 -DIM QB__handle AS LONG -IF __QB_HANDLE_handler(context).lastFreedListIndex = 0 THEN - QB__handle = __QB_HANDLE_handler(context).lastHandle + 1 - __QB_HANDLE_handler(context).lastHandle = QB__handle - QB_HANDLE_new& = QB__handle - EXIT FUNCTION -END IF -DIM __QB_HANDLE_lastIndex AS LONG -__QB_HANDLE_lastIndex = __QB_HANDLE_handler(context).lastFreedListIndex -QB__handle = __QB_HANDLE_freedList(__QB_HANDLE_lastIndex).handle -__QB_HANDLE_handler(context).lastFreedListIndex = __QB_HANDLE_freedList(__QB_HANDLE_lastIndex).prevFreedListIndex -'add to freed-freed list so the freed structure can be reused -IF __QB_HANDLE_freedFreedList_Next > __QB_HANDLE_freedFreedList_Last THEN - __QB_HANDLE_freedFreedList_Last = __QB_HANDLE_freedFreedList_Next * 2 - REDIM _PRESERVE __QB_HANDLE_freedFreedList(__QB_HANDLE_freedFreedList_Last) AS LONG -END IF -__QB_HANDLE_freedFreedList(__QB_HANDLE_freedFreedList_Next) = __QB_HANDLE_lastIndex -__QB_HANDLE_freedFreedList_Next = __QB_HANDLE_freedFreedList_Next + 1 -QB_HANDLE_new& = QB__handle -END FUNCTION - -SUB QB_HANDLE_free (handle AS LONG, context AS LONG) 'MUST pass a valid handle -__QB_HANDLE_handler(context).count = __QB_HANDLE_handler(context).count - 1 -'add handle to freed list -DIM QB__index AS LONG -IF __QB_HANDLE_freedFreedList_Next > 1 THEN 'recover from freed-freed list? - __QB_HANDLE_freedFreedList_Next = __QB_HANDLE_freedFreedList_Next - 1 - QB__index = __QB_HANDLE_freedFreedList(__QB_HANDLE_freedFreedList_Next) -ELSE - IF __QB_HANDLE_freedList_Next > __QB_HANDLE_freedList_Last THEN - __QB_HANDLE_freedList_Last = __QB_HANDLE_freedList_Next * 2 - REDIM _PRESERVE __QB_HANDLE_freedList(__QB_HANDLE_freedList_Last) AS __QB_HANDLE_FREEDLIST - END IF - QB__index = __QB_HANDLE_freedList_Next - __QB_HANDLE_freedList_Next = __QB_HANDLE_freedList_Next + 1 -END IF -__QB_HANDLE_freedList(QB__index).prevFreedListIndex = __QB_HANDLE_handler(context).lastFreedListIndex -__QB_HANDLE_freedList(QB__index).handle = handle -__QB_HANDLE_handler(context).lastFreedListIndex = QB__index -END SUB - -'################################################## - - -'#################### EACH: Methods #################### - -FUNCTION QB_EACH_str_in_str& (value AS STRING, parent AS STRING, separator AS STRING, flags AS LONG, i AS LONG) -'requirements: -' iterator must be a LONG, initially set to 0 -'notes: -' refer to constants for available flags (0 is default) -DIM QB__byteValue AS LONG -DIM QB__parentLen AS LONG -DIM QB__sepValue AS LONG -DIM QB__i1 AS LONG -DIM QB__retry AS LONG -QB__sepValue = ASC(separator) -QB__parentLen = LEN(parent) -DO - i = i + 1 - IF i > QB__parentLen THEN - value = "" - IF i = QB__parentLen + 1 THEN - IF QB__parentLen <> 0 THEN - IF ASC(parent, i - 1) = QB__sepValue THEN - IF (flags AND (QB_EACH_ALLOW_BLANK OR QB_EACH_ALLOW_ALL_BLANK)) <> 0 THEN QB_EACH_str_in_str& = -1 - END IF - ELSE - IF (flags AND QB_EACH_ALLOW_ALL_BLANK) <> 0 THEN QB_EACH_str_in_str& = -1 - END IF - END IF - EXIT FUNCTION - END IF - QB__i1 = i - byteValue = ASC(parent, i) - $CHECKING:OFF - DO WHILE byteValue <> QB__sepValue - i = i + 1 - IF i > QB__parentLen THEN EXIT DO - byteValue = ASC(parent, i) - LOOP - $CHECKING:ON - value = MID$(parent, QB__i1, i - QB__i1) - IF LEN(value) = 0 AND (flags AND (QB_EACH_ALLOW_BLANK OR QB_EACH_ALLOW_ALL_BLANK)) = 0 THEN - QB__retry = 1 - ELSE - QB__retry = 0 - END IF -LOOP WHILE QB__retry -QB_EACH_str_in_str& = -1 -END FUNCTION - -FUNCTION QB_EACH_long_in_str& (value AS LONG, parent AS STRING, separator AS STRING, i AS LONG) -'requirements: -' a comma separated list of valid LONG values -' no whitespace -' no leading, trailing or adjacent commas -' iterator must be a LONG -' value must be a LONG -DIM QB__byteValue AS LONG -DIM QB__parentLen AS LONG -DIM QB__negate AS LONG -DIM QB__sepValue AS LONG -QB__sepValue = ASC(separator) -QB__parentLen = LEN(parent) -value = 0 'reset value (avoids undefined results) -i = i + 1 -IF i > QB__parentLen THEN EXIT FUNCTION -QB__byteValue = ASC(parent, i) -IF QB__byteValue = 45 THEN - QB__negate = 1 - i = i + 1 - QB__byteValue = ASC(parent, i) -END IF -DO WHILE QB__byteValue <> QB__sepValue - value = value * 10 + QB__byteValue - 48 - i = i + 1 - IF i > QB__parentLen THEN EXIT DO - QB__byteValue = ASC(parent, i) -LOOP -IF QB__negate THEN value = -value -QB_EACH_long_in_str& = -1 -END FUNCTION - -'################################################## - - -'#################### Key Value Pair Dictionary Look-Ups: Methods #################### - - - -FUNCTION QB_NODE_newValueWithLabel& (label AS STRING, value AS STRING) 'assume str_str -DIM QB__handle AS LONG -QB__handle = __QB_NODE_new&(QB_NODE_TYPE_VALUE) -__QB_NODE(QB__handle).labelFormat = QB_NODE_FORMAT_STR -__QB_NODE(QB__handle).label = QB_STR_new(label) -__QB_NODE(QB__handle).valueFormat = QB_NODE_FORMAT_STR -__QB_NODE(QB__handle).value = QB_STR_new(value) -QB_NODE_newValueWithLabel& = QB__handle -END FUNCTION - - -FUNCTION QB_NODE_newValueWithLabel_long& (label AS STRING, value AS LONG) 'assume str_long -DIM QB__handle AS LONG -QB__handle = __QB_NODE_new&(QB_NODE_TYPE_VALUE) -__QB_NODE(QB__handle).labelFormat = QB_NODE_FORMAT_STR -__QB_NODE(QB__handle).label = QB_STR_new(label) -__QB_NODE(QB__handle).valueFormat = QB_NODE_FORMAT_LONG -__QB_NODE(QB__handle).value = value -QB_NODE_newValueWithLabel_long& = QB__handle -END FUNCTION - -FUNCTION QB_NODE_newValueWithLabel_bool& (label AS STRING, value AS LONG) 'assume str_bool -DIM QB__handle AS LONG -QB__handle = __QB_NODE_new&(QB_NODE_TYPE_VALUE) -__QB_NODE(QB__handle).labelFormat = QB_NODE_FORMAT_STR -__QB_NODE(QB__handle).label = QB_STR_new(label) -__QB_NODE(QB__handle).valueFormat = QB_NODE_FORMAT_BOOL -IF value = 0 THEN - __QB_NODE(QB__handle).value = QB_FALSE -ELSE - __QB_NODE(QB__handle).value = QB_TRUE -END IF -QB_NODE_newValueWithLabel_bool& = QB__handle -END FUNCTION - -FUNCTION QB_NODE_newLabel& (label AS STRING) 'assume str -DIM QB__handle AS LONG -QB__handle = __QB_NODE_new&(QB_NODE_TYPE_VALUE) -__QB_NODE(QB__handle).labelFormat = QB_NODE_FORMAT_STR -__QB_NODE(QB__handle).label = QB_STR_new(label) -QB_NODE_newLabel& = QB__handle -END FUNCTION - -FUNCTION QB_NODE_newValue& (value AS STRING) 'assume str -DIM QB__handle AS LONG -QB__handle = __QB_NODE_new&(QB_NODE_TYPE_VALUE) -__QB_NODE(QB__handle).valueFormat = QB_NODE_FORMAT_STR -__QB_NODE(QB__handle).value = QB_STR_new(value) -QB_NODE_newValue& = QB__handle -END FUNCTION - -FUNCTION QB_NODE_newLabel_long& (label AS LONG) -DIM QB__handle AS LONG -QB__handle = __QB_NODE_new&(QB_NODE_TYPE_VALUE) -__QB_NODE(QB__handle).labelFormat = QB_NODE_FORMAT_LONG -__QB_NODE(QB__handle).label = label -QB_NODE_newLabel_long& = QB__handle -END FUNCTION - -FUNCTION QB_NODE_typeName$ (nodeType AS LONG) -IF nodeType = 1 THEN QB_NODE_typeName$ = "HASHSET" -IF nodeType = 2 THEN QB_NODE_typeName$ = "LIST" -IF nodeType = 4 THEN QB_NODE_typeName$ = "DICTIONARY" -IF nodeType = 8 THEN QB_NODE_typeName$ = "VALUE" -END FUNCTION - -FUNCTION QB_NODE_new& (nodeType AS LONG, flags AS LONG) -IF QB_DEBUG_VERBOSE THEN PRINT "QB_NODE_new()" -DIM QB__handle AS LONG -QB__handle = QB_HANDLE_new(__QB_NODE_handleSet) -IF QB__handle > __QB_NODE_ubound THEN - __QB_NODE_ubound = QB__handle * 2 - REDIM _PRESERVE __QB_NODE(__QB_NODE_ubound) AS QB_NODE_TYPE -END IF -__QB_NODE(QB__handle) = QB_NODE_TYPE_EMPTY -__QB_NODE(QB__handle).valid = 1 -__QB_NODE(QB__handle).type = nodeType -__QB_NODE(QB__handle).flags = flags -IF nodeType AND (QB_NODE_TYPE_HASHSET + QB_NODE_TYPE_DICTIONARY) THEN - __QB_NODE(QB__handle).hashOffset = INT(RND * 16777215) -END IF -IF QB_DEBUG THEN PRINT "Created node type"; nodeType -QB_NODE_new& = QB__handle -END FUNCTION - - -FUNCTION QB_NODE_newDictionary& -QB_NODE_newDictionary& = QB_NODE_new(QB_NODE_TYPE_DICTIONARY, 0) -END FUNCTION - -FUNCTION QB_NODE_newList& -QB_NODE_newList& = QB_NODE_new(QB_NODE_TYPE_LIST, 0) -END FUNCTION - -FUNCTION QB_NODE_newHashSet& -QB_NODE_newHashSet& = QB_NODE_new(QB_NODE_TYPE_HASHSET, 0) -END FUNCTION - -SUB QB_NODE_setValue_format (QB__handle AS LONG, value AS LONG, format AS LONG) -$CHECKING:OFF -IF __QB_NODE_validateHandle(QB__handle, QB_NODE_TYPE_VALUE) = -1 THEN EXIT FUNCTION -$CHECKING:ON -'format-specific validation here -__QB_NODE(QB__handle).value = value -__QB_NODE(QB__handle).valueFormat = format -END SUB - -SUB QB_NODE_setLabel_format (QB__handle AS LONG, label AS LONG, format AS LONG) -$CHECKING:OFF -IF __QB_NODE_validateHandle(QB__handle, QB_NODE_TYPE_VALUE + QB_NODE_TYPE_HASHSET + QB_NODE_TYPE_LIST + QB_NODE_TYPE_DICTIONARY) = -1 THEN EXIT FUNCTION -$CHECKING:ON -'format-specific validation here -__QB_NODE(QB__handle).label = label -__QB_NODE(QB__handle).labelFormat = format -END SUB - -SUB QB_NODE_setValue (QB__handle AS LONG, value AS STRING) 'assume str -$CHECKING:OFF -IF __QB_NODE_validateHandle(QB__handle, QB_NODE_TYPE_VALUE) = -1 THEN EXIT FUNCTION -$CHECKING:ON -__QB_NODE(QB__handle).value = QB_STR_new(value) -__QB_NODE(QB__handle).valueFormat = QB_NODE_FORMAT_STR -END SUB - -SUB QB_NODE_setLabel (QB__handle AS LONG, label AS STRING) 'assume str -$CHECKING:OFF -IF __QB_NODE_validateHandle(QB__handle, QB_NODE_TYPE_VALUE + QB_NODE_TYPE_HASHSET + QB_NODE_TYPE_LIST + QB_NODE_TYPE_DICTIONARY) = -1 THEN EXIT FUNCTION -$CHECKING:ON -'TODO: If parent is a dictionary/hashset detach then reattach -__QB_NODE(QB__handle).label = QB_STR_new(label) -__QB_NODE(QB__handle).labelFormat = QB_NODE_FORMAT_STR -END SUB - -FUNCTION QB_NODE_value$ (QB__handle AS LONG) 'assume str -$CHECKING:OFF -IF __QB_NODE_validateHandle(QB__handle, QB_NODE_TYPE_VALUE) = -1 THEN EXIT FUNCTION -$CHECKING:ON -'format-specific validation here -IF __QB_NODE(QB__handle).valueFormat = QB_NODE_FORMAT_STR THEN - QB_NODE_value$ = QB_STR_get(__QB_NODE(QB__handle).value) - EXIT FUNCTION -END IF -IF __QB_NODE(QB__handle).valueFormat = QB_NODE_FORMAT_LONG THEN - QB_NODE_value$ = QB_STR_long(__QB_NODE(QB__handle).value) - EXIT FUNCTION -END IF -IF __QB_NODE(QB__handle).valueFormat = QB_NODE_FORMAT_NULL THEN - QB_NODE_value$ = "null" - EXIT FUNCTION -END IF -IF __QB_NODE(QB__handle).valueFormat = QB_NODE_FORMAT_BOOL THEN - IF __QB_NODE(QB__handle).value <> 0 THEN - QB_NODE_value$ = "true" - ELSE - QB_NODE_value$ = "false" - END IF - EXIT FUNCTION -END IF -QB_NODE_value$ = "undefined" -END SUB - -FUNCTION QB_NODE_label$ (QB__handle AS LONG) 'assume str -$CHECKING:OFF -IF __QB_NODE_validateHandle(QB__handle, QB_NODE_TYPE_VALUE) = -1 THEN EXIT FUNCTION -$CHECKING:ON -'format-specific validation here -IF __QB_NODE(QB__handle).labelFormat = QB_NODE_FORMAT_STR THEN - QB_NODE_label$ = QB_STR_get(__QB_NODE(QB__handle).label) - EXIT FUNCTION -END IF -IF __QB_NODE(QB__handle).labelFormat = QB_NODE_FORMAT_LONG THEN - QB_NODE_label$ = QB_STR_long(__QB_NODE(QB__handle).label) - EXIT FUNCTION -END IF -IF __QB_NODE(QB__handle).labelFormat = QB_NODE_FORMAT_NULL THEN - QB_NODE_label$ = "null" - EXIT FUNCTION -END IF -IF __QB_NODE(QB__handle).labelFormat = QB_NODE_FORMAT_BOOL THEN - IF __QB_NODE(QB__handle).label <> 0 THEN - QB_NODE_label$ = "true" - ELSE - QB_NODE_label$ = "false" - END IF - EXIT FUNCTION -END IF -QB_NODE_label$ = "undefined" -END SUB - -FUNCTION QB_NODE_count& (QB__handle AS LONG) -$CHECKING:OFF -IF __QB_NODE_validateHandle(QB__handle, QB_NODE_TYPE_HASHSET + QB_NODE_TYPE_DICTIONARY + QB_NODE_TYPE_LIST) = -1 THEN EXIT FUNCTION -$CHECKING:ON -QB_NODE_count& = __QB_NODE(QB__handle).count -END FUNCTION - -FUNCTION QB_NODE_each& (child AS LONG, parent AS LONG, i AS LONG) -$CHECKING:OFF -IF i = 0 THEN - IF __QB_NODE_validateHandle(parent, QB_NODE_TYPE_LIST + QB_NODE_TYPE_HASHSET + QB_NODE_TYPE_DICTIONARY) = -1 THEN EXIT FUNCTION -END IF -$CHECKING:ON -'i is either 0(on first call), -1(end of set reached) or the NEXT node -IF i = -1 THEN - child = 0 - EXIT FUNCTION -END IF -IF i = 0 THEN - child = __QB_NODE(parent).firstChild -ELSE - child = i -END IF -IF child = 0 THEN 'node does not exist - i = -1 - EXIT FUNCTION -END IF -i = __QB_NODE(child).next -IF i = 0 THEN - i = -1 -END IF -QB_NODE_each& = -1 -END FUNCTION - -FUNCTION QB_NODE_eachWithLabel_format& (child AS LONG, parent AS LONG, label AS LONG, labelFormat AS LONG, i AS LONG) -$CHECKING:OFF -IF i = 0 THEN - IF __QB_NODE_validateHandle(parent, QB_NODE_TYPE_DICTIONARY + QB_NODE_TYPE_HASHSET) = -1 THEN EXIT FUNCTION -END IF -$CHECKING:ON -IF __QB_NODE(parent).type AND (QB_NODE_TYPE_DICTIONARY + QB_NODE_TYPE_HASHSET) THEN - 'i is either 0(on first call), -1(end of set reached) or the NEXT node - IF i = -1 THEN - child = 0 - EXIT FUNCTION - END IF - DIM QB__label AS STRING - IF i = 0 THEN - DIM QB__hashValue AS LONG - IF labelFormat = QB_NODE_FORMAT_LONG THEN - QB__hashValue = __QB_NODE_hashLong(label, __QB_NODE(parent).hashOffset) - ELSE - IF labelFormat = QB_NODE_FORMAT_STR THEN - QB__label = QB_STR_get(label) - IF (__QB_NODE(parent).flags AND QB_NODE_CASE_SENSITIVE) = 0 THEN - QB__label = LCASE$(QB__label) - END IF - QB__hashValue = __QB_NODE_hashStr(QB__label, __QB_NODE(parent).hashOffset) - END IF - END IF - DIM QB__hashList AS LONG - QB__hashList = __QB_NODE_hashLists(QB__hashValue) - IF QB__hashList = 0 THEN - 'no hash list exists - i = -1 - EXIT FUNCTION - END IF - i = __QB_NODE(QB__hashList).firstChild - ELSE - IF labelFormat = QB_NODE_FORMAT_STR THEN - QB__label = QB_STR_get(label) - IF (__QB_NODE(parent).flags AND QB_NODE_CASE_SENSITIVE) = 0 THEN - QB__label = LCASE$(QB__label) - END IF - END IF - END IF - DO - IF i = 0 THEN - i = -1 - EXIT FUNCTION - END IF - 'check if current node matches label - IF __QB_NODE(i).owner = parent THEN 'same owner - IF __QB_NODE(i).labelFormat = labelFormat THEN 'same label format - DIM QB__same AS LONG - QB__same = 0 - IF labelFormat = QB_NODE_FORMAT_LONG THEN - IF __QB_NODE(i).label = label THEN QB__same = 1 - ELSE - IF QB_STR_get(__QB_NODE(i).label) = QB__label THEN QB__same = 1 - END IF - IF QB__same THEN 'same label - child = __QB_NODE(i).value - i = __QB_NODE(i).next - IF i = 0 THEN - i = -1 - END IF - QB_NODE_eachWithLabel_format& = -1 - EXIT FUNCTION - END IF - END IF - END IF - i = __QB_NODE(i).next - LOOP -END IF 'DICTIONARY -END FUNCTION - -FUNCTION QB_NODE_withLabel_format& (parent AS LONG, label AS LONG, labelFormat AS LONG) -$CHECKING:OFF -IF __QB_NODE_validateHandle(parent, QB_NODE_TYPE_DICTIONARY + QB_NODE_TYPE_HASHSET) = -1 THEN EXIT FUNCTION -$CHECKING:ON -IF __QB_NODE(parent).type AND (QB_NODE_TYPE_DICTIONARY + QB_NODE_TYPE_HASHSET) THEN - DIM QB__label AS STRING - DIM QB__hashValue AS LONG - IF labelFormat = QB_NODE_FORMAT_LONG THEN - QB__hashValue = __QB_NODE_hashLong(label, __QB_NODE(parent).hashOffset) - ELSE - IF labelFormat = QB_NODE_FORMAT_STR THEN - QB__label = QB_STR_get(label) - IF (__QB_NODE(parent).flags AND QB_NODE_CASE_SENSITIVE) = 0 THEN - QB__label = LCASE$(QB__label) - END IF - QB__hashValue = __QB_NODE_hashStr(QB__label, __QB_NODE(parent).hashOffset) - END IF - END IF - DIM QB__hashList AS LONG - QB__hashList = __QB_NODE_hashLists(QB__hashValue) - IF QB__hashList = 0 THEN EXIT FUNCTION - DIM QB__i AS LONG - QB__i = __QB_NODE(QB__hashList).firstChild - DO WHILE QB__i <> 0 - IF __QB_NODE(QB__i).owner = parent THEN 'same owner - IF __QB_NODE(QB__i).labelFormat = labelFormat THEN 'same label format - DIM QB__same AS LONG - QB__same = 0 - IF labelFormat = QB_NODE_FORMAT_LONG THEN - IF __QB_NODE(QB__i).label = label THEN QB__same = 1 - ELSE - IF QB_STR_get(__QB_NODE(QB__i).label) = QB__label THEN QB__same = 1 - END IF - IF QB__same THEN 'same label - QB_NODE_withLabel_format& = __QB_NODE(QB__i).value - EXIT FUNCTION - END IF - END IF - END IF - QB__i = __QB_NODE(QB__i).next - LOOP - EXIT FUNCTION 'not found -END IF 'DICTIONARY -END FUNCTION - -FUNCTION QB_NODE_valueOfLabel$ (parent AS LONG, label AS STRING) 'assume str-label, str-value -DIM QB__i AS LONG -QB__i = QB_NODE_withLabel&(parent, label) -IF QB__i THEN - QB_NODE_valueOfLabel$ = QB_NODE_value(QB__i) -END IF -END FUNCTION - -FUNCTION QB_NODE_valueOfLabel_long& (parent AS LONG, label AS STRING) 'assume str-label -DIM QB__i AS LONG -QB__i = QB_NODE_withLabel&(parent, label) -IF QB__i THEN - QB_NODE_valueOfLabel_long& = __QB_NODE(QB__i).value -END IF -END FUNCTION - -FUNCTION QB_NODE_valueOfLabel_bool& (parent AS LONG, label AS STRING) 'assume str-label -DIM QB__i AS LONG -QB__i = QB_NODE_withLabel&(parent, label) -IF QB__i THEN - QB_NODE_valueOfLabel_bool& = __QB_NODE(QB__i).value -END IF -END FUNCTION - -FUNCTION QB_NODE_withLabel& (parent AS LONG, label AS STRING) -$CHECKING:OFF -IF __QB_NODE_validateHandle(parent, QB_NODE_TYPE_DICTIONARY + QB_NODE_TYPE_HASHSET) = -1 THEN EXIT FUNCTION -$CHECKING:ON -IF __QB_NODE(parent).type AND (QB_NODE_TYPE_DICTIONARY + QB_NODE_TYPE_HASHSET) THEN - DIM QB__label AS STRING - DIM QB__hashValue AS LONG - QB__label = label - IF (__QB_NODE(parent).flags AND QB_NODE_CASE_SENSITIVE) = 0 THEN - QB__label = LCASE$(QB__label) - END IF - QB__hashValue = __QB_NODE_hashStr(QB__label, __QB_NODE(parent).hashOffset) - DIM QB__hashList AS LONG - QB__hashList = __QB_NODE_hashLists(QB__hashValue) - IF QB__hashList = 0 THEN EXIT FUNCTION - DIM QB__i AS LONG - QB__i = __QB_NODE(QB__hashList).firstChild - DO WHILE QB__i <> 0 - IF __QB_NODE(QB__i).owner = parent THEN 'same owner - IF __QB_NODE(QB__i).labelFormat = QB_NODE_FORMAT_STR THEN 'same label format - DIM QB__same AS LONG - QB__same = 0 - IF QB_STR_get(__QB_NODE(QB__i).label) = QB__label THEN QB__same = 1 - IF QB__same THEN 'same label - QB_NODE_withLabel& = __QB_NODE(QB__i).value - EXIT FUNCTION - END IF - END IF - END IF - QB__i = __QB_NODE(QB__i).next - LOOP - EXIT FUNCTION 'not found -END IF 'DICTIONARY -END FUNCTION - - -SUB QB_NODE_assign (parent AS LONG, child AS LONG) -$CHECKING:OFF -IF __QB_NODE_validateHandle(child, QB_NODE_TYPE_VALUE + QB_NODE_TYPE_HASHSET + QB_NODE_TYPE_LIST + QB_NODE_TYPE_DICTIONARY) = -1 THEN EXIT FUNCTION -IF __QB_NODE_validateHandle(parent, QB_NODE_TYPE_HASHSET + QB_NODE_TYPE_LIST + QB_NODE_TYPE_DICTIONARY) = -1 THEN EXIT FUNCTION -$CHECKING:ON - -IF __QB_NODE(parent).type AND (QB_NODE_TYPE_LIST) THEN - QB_NODE_detach child - __QB_NODE_append parent, child -END IF - -IF __QB_NODE(parent).type AND (QB_NODE_TYPE_DICTIONARY + QB_NODE_TYPE_HASHSET) THEN - QB_NODE_detach child - - DIM QB__label AS STRING - DIM QB__hashValue AS LONG - - IF __QB_NODE(child).labelFormat = QB_NODE_FORMAT_LONG THEN - QB__hashValue = __QB_NODE_hashLong(__QB_NODE(child).label, __QB_NODE(parent).hashOffset) - ELSE - IF __QB_NODE(child).labelFormat = QB_NODE_FORMAT_STR THEN - QB__label = QB_STR_get(__QB_NODE(child).label) - IF (__QB_NODE(parent).flags AND QB_NODE_CASE_SENSITIVE) = 0 THEN - QB__label = LCASE$(QB__label) - END IF - QB__hashValue = __QB_NODE_hashStr(QB__label, __QB_NODE(parent).hashOffset) - END IF - END IF - DIM QB__hashList AS LONG - QB__hashList = __QB_NODE_hashLists(QB__hashValue) - DIM QB__canReplace AS LONG - QB__canReplace = 1 - IF (__QB_NODE(parent).flags AND QB_NODE_ALLOW_DUPLICATE_KEYS) <> 0 THEN - QB__canReplace = 0 - IF (__QB_NODE(parent).flags AND QB_NODE_AVOID_DUPLICATE_VALUES_PER_KEY) <> 0 THEN QB__canReplace = 1 - END IF - - DIM QB__childValue AS STRING - IF (__QB_NODE(parent).flags AND QB_NODE_AVOID_DUPLICATE_VALUES_PER_KEY) <> 0 AND __QB_NODE(child).labelFormat = QB_NODE_FORMAT_STR THEN - QB__childValue = QB_STR_get(__QB_NODE(child).value) - IF (__QB_NODE(parent).flags AND QB_NODE_DUPLICATE_VALUES_CASE_SENSITIVE) = 0 THEN QB__childValue = LCASE$(QB__childValue) - END IF - - IF QB__hashList = 0 OR QB__canReplace = 0 THEN - IF QB__hashList = 0 THEN - QB__hashList = QB_NODE_new(QB_NODE_TYPE_LIST, 0) - __QB_NODE_hashLists(QB__hashValue) = QB__hashList - __QB_NODE(QB__hashList).hashReference = QB__hashValue - END IF - ELSE - DIM QB__this AS LONG - DIM QB__i AS LONG - DO WHILE QB_NODE_each(QB__this, QB__hashList, QB__i) - IF __QB_NODE(QB__this).owner = parent THEN 'same owner - IF __QB_NODE(QB__this).labelFormat = __QB_NODE(child).labelFormat THEN 'same label format - DIM QB__same AS LONG - QB__same = 0 - IF __QB_NODE(child).labelFormat = QB_NODE_FORMAT_LONG THEN - IF __QB_NODE(QB__this).label = __QB_NODE(child).label THEN QB__same = 1 - ELSE - IF QB_STR_get(__QB_NODE(QB__this).label) = QB__label THEN QB__same = 1 - END IF - IF QB__same THEN 'same label - IF (__QB_NODE(parent).flags AND QB_NODE_ALLOW_DUPLICATE_KEYS) <> 0 THEN - IF (__QB_NODE(parent).flags AND QB_NODE_AVOID_DUPLICATE_VALUES_PER_KEY) <> 0 THEN - IF __QB_NODE(QB__this).valueFormat = __QB_NODE(child).valueFormat THEN 'same value format - IF __QB_NODE(child).labelFormat = QB_NODE_FORMAT_LONG THEN - IF __QB_NODE(child).value = __QB_NODE(QB__this).value THEN - 'optionally, destroy this child - IF __QB_NODE(parent).flags AND QB_NODE_DESTROY_ORPHANED_CHILDNODES THEN - QB_NODE_destroy child - END IF - EXIT SUB 'entry already exists - END IF - ELSE - IF (__QB_NODE(parent).flags AND QB_NODE_DUPLICATE_VALUES_CASE_SENSITIVE) <> 0 THEN - IF QB_STR_get(__QB_NODE(QB__this).value) = QB__childValue THEN - 'optionally, destroy this child - IF __QB_NODE(parent).flags AND QB_NODE_DESTROY_ORPHANED_CHILDNODES THEN - QB_NODE_destroy child - END IF - EXIT SUB 'entry already exists - END IF - ELSE - IF LCASE$(QB_STR_get(__QB_NODE(QB__this).value)) = QB__childValue THEN - 'optionally, destroy this child - IF __QB_NODE(parent).flags AND QB_NODE_DESTROY_ORPHANED_CHILDNODES THEN - QB_NODE_destroy child - END IF - EXIT SUB 'entry already exists - END IF - END IF - END IF - END IF - END IF - ELSE - 'duplicate keys not allowed - __QB_NODE_append parent, child - 'update existing reference to child - DIM QB__oldChild AS LONG - QB__oldChild = __QB_NODE(QB__this).value - __QB_NODE_detach QB__oldChild 'generic detach must be used (reference will be re-used) - 'optionally, destroy old child - IF __QB_NODE(parent).flags AND QB_NODE_DESTROY_ORPHANED_CHILDNODES THEN - QB_NODE_destroy QB__oldChild - END IF - __QB_NODE(QB__this).value = child - __QB_NODE(child).hashReference = QB__this - EXIT SUB - END IF - END IF - END IF - END IF - LOOP - END IF - 'create new reference to child - __QB_NODE_append parent, child - DIM QB__ref AS LONG - QB__ref = QB_NODE_new(QB_NODE_TYPE_VALUE, 0) - IF __QB_NODE(child).labelFormat = QB_NODE_FORMAT_LONG THEN - QB_NODE_setLabel_format QB__ref, __QB_NODE(child).label, QB_NODE_FORMAT_LONG - ELSE - QB_NODE_setLabel_format QB__ref, QB_STR_new(QB__label), QB_NODE_FORMAT_STR - END IF - QB_NODE_setValue_format QB__ref, child, QB_NODE_FORMAT_LONG - __QB_NODE(QB__ref).owner = parent 'owner allows searching elimination of conflicting hash entries from other sets - 'add reference to list - __QB_NODE_append QB__hashList, QB__ref - __QB_NODE(child).hashReference = QB__ref -END IF 'dictionary - - - - - - - - -END SUB 'assign - -SUB QB_NODE_detach (QB__handle AS LONG) -IF QB_DEBUG_VERBOSE THEN - PRINT "QB_NODE_detach: Node"; QB__handle; "of type: " + QB_NODE_typeName(__QB_NODE(QB__handle).type) -END IF -$CHECKING:OFF -IF __QB_NODE_validateHandle(QB__handle, 0) = -1 THEN EXIT FUNCTION -$CHECKING:ON -DIM QB__parent AS LONG -DIM QB__ref AS LONG -DIM QB__ref_parent AS LONG -'dictionaries & hashsets require removal of their hash table reference link -QB__parent = __QB_NODE(QB__handle).parent -IF QB__parent THEN 'has parent - IF __QB_NODE(QB__parent).type AND (QB_NODE_TYPE_HASHSET + QB_NODE_TYPE_DICTIONARY) THEN - QB__ref = __QB_NODE(QB__handle).hashReference - QB__ref_parent = __QB_NODE(QB__ref).parent - IF __QB_NODE(QB__ref_parent).count = 1 THEN - 'last reference - IF QB_DEBUG_VERBOSE THEN - PRINT "QB_NODE_detach: Calling destroy on parent hashreference-list node"; QB__ref_parent; "of type: " + QB_NODE_typeName(__QB_NODE(QB__ref_parent).type) + " (no more entries)" - END IF - 'clear the hash entry pointing to this list - __QB_NODE_hashLists(__QB_NODE(QB__ref_parent).hashReference) = 0 'step 1 (must happen before step 2) - __QB_NODE_destroy QB__ref_parent 'step 2 - ELSE - __QB_NODE_destroy QB__ref - END IF - IF __QB_NODE(QB__parent).flags AND QB_NODE_DESTROY_ORPHANED_CHILDNODES THEN - __QB_NODE_detach QB__handle 'perform generic detach - __QB_NODE_destroy QB__handle - EXIT FUNCTION - END IF - __QB_NODE_detach QB__handle 'perform generic detach - EXIT FUNCTION - END IF -END IF -__QB_NODE_detach QB__handle 'perform generic detach -END SUB - -SUB QB_NODE_destroy (QB__handle AS LONG) -$CHECKING:OFF -IF __QB_NODE_validateHandle(QB__handle, 0) = -1 THEN EXIT FUNCTION -$CHECKING:ON -'destroy this node and all its children recursively -__QB_NODE_destroy QB__handle -END SUB - -SUB __QB_NODE_destroy (QB__handle AS LONG) - -IF QB_DEBUG_VERBOSE THEN - PRINT "__QB_NODE_destroy: Will destroy node"; QB__handle; "of type: " + QB_NODE_typeName(__QB_NODE(QB__handle).type) -END IF - -'when a collection is being destroyed, prevent QB_NODE_DESTROY_ORPHANED_CHILDNODES from firing a delete operation twice -IF __QB_NODE(QB__handle).flags AND QB_NODE_DESTROY_ORPHANED_CHILDNODES THEN - __QB_NODE(QB__handle).flags = __QB_NODE(QB__handle).flags - QB_NODE_DESTROY_ORPHANED_CHILDNODES -END IF - -'before any node can be destroyed it must be detached -QB_NODE_detach QB__handle -'destroy this node's children (if any) -DIM QB__child AS LONG -DIM QB__next AS LONG -QB__child = __QB_NODE(QB__handle).firstChild -DO WHILE QB__child - QB__next = __QB_NODE(QB__child).next - IF QB_DEBUG_VERBOSE THEN - PRINT "__QB_NODE_destroy: Calling destroy on child node"; QB__child; "of type: " + QB_NODE_typeName(__QB_NODE(QB__child).type) - END IF - __QB_NODE_destroy QB__child - QB__child = QB__next -LOOP -'destroy this object -IF QB_DEBUG_VERBOSE THEN - PRINT "__QB_NODE_destroy: Destroying node"; QB__handle; "of type: " + QB_NODE_typeName(__QB_NODE(QB__handle).type) -END IF -$CHECKING:OFF -IF __QB_NODE_validateHandle(QB__handle, 0) = -1 THEN EXIT FUNCTION -$CHECKING:ON -__QB_NODE(QB__handle).valid = 0 -'cleanup string references -IF __QB_NODE(QB__handle).valueFormat = QB_NODE_FORMAT_STR THEN - QB_STR_free __QB_NODE(QB__handle).value -END IF -IF __QB_NODE(QB__handle).labelFormat = QB_NODE_FORMAT_STR THEN - QB_STR_free __QB_NODE(QB__handle).label -END IF -QB_HANDLE_free QB__handle, __QB_NODE_handleSet -END SUB - -FUNCTION __QB_NODE_new& (nodeType AS LONG) -IF QB_DEBUG_VERBOSE THEN PRINT "__QB_NODE_new()" -DIM QB__handle AS LONG -QB__handle = QB_HANDLE_new(__QB_NODE_handleSet) -IF QB__handle > __QB_NODE_ubound THEN - __QB_NODE_ubound = QB__handle * 2 - REDIM _PRESERVE __QB_NODE(__QB_NODE_ubound) AS QB_NODE_TYPE -END IF -__QB_NODE(QB__handle) = QB_NODE_TYPE_EMPTY -__QB_NODE(QB__handle).valid = 1 -__QB_NODE(QB__handle).type = nodeType -IF QB_DEBUG_VERBOSE THEN PRINT "Created node type"; nodeType -__QB_NODE_new& = QB__handle -END FUNCTION - -SUB __QB_NODE_append (parent AS LONG, child AS LONG) -'generic append to end of parent list -'assumes child is detached -__QB_NODE(child).parent = parent -IF __QB_NODE(parent).firstChild = 0 THEN - 'is first entry in list - __QB_NODE(parent).count = 1 - __QB_NODE(parent).firstChild = child - __QB_NODE(parent).lastChild = child -ELSE - 'add to existing list - DIM QB__i AS LONG - QB__i = __QB_NODE(parent).lastChild - __QB_NODE(parent).count = __QB_NODE(parent).count + 1 - __QB_NODE(parent).lastChild = child - __QB_NODE(QB__i).next = child - __QB_NODE(child).prev = QB__i -END IF -END SUB - -FUNCTION __QB_NODE_hashLong (value AS LONG, baseOffset AS LONG) -__QB_NODE_hashLong = (value + baseOffset) AND &HFFFFFF~& -END FUNCTION - -FUNCTION __QB_NODE_hashStr (value AS STRING, baseOffset AS LONG) -DIM QB__keyNameLen AS LONG -DIM QB__i AS LONG -DIM QB__hashValue AS LONG -QB__keyNameLen = LEN(value) -QB__i = 1 -DO WHILE QB__i <= QB__keyNameLen - QB__hashValue = QB__hashValue + ASC(value, QB__i) * QB__i * 15 - QB__i = QB__i + 1 -LOOP -__QB_NODE_hashStr = (QB__hashValue + baseOffset) AND &HFFFFFF~& -END FUNCTION - -FUNCTION __QB_NODE_validateHandle (handle AS LONG, optionalRequiredType AS LONG) -$CHECKING:OFF -IF handle > __QB_NODE_ubound OR handle <= 0 THEN ERROR 258: EXIT FUNCTION 'invalid handle -IF __QB_NODE(handle).valid = 0 THEN ERROR 258: EXIT FUNCTION -IF optionalRequiredType <> 0 THEN - IF (optionalRequiredType AND __QB_NODE(handle).type) = 0 THEN - ERROR 258 - __QB_NODE_validateHandle = -1 - EXIT FUNCTION - END IF -END IF -$CHECKING:ON -END FUNCTION - -SUB __QB_NODE_detach (handle AS LONG) -IF QB_DEBUG_VERBOSE THEN - PRINT "__QB_NODE_detach: Node"; handle; "of type: " + QB_NODE_typeName(__QB_NODE(handle).type) -END IF -'generic detach method (regardless of parent type) -DIM QB__i -QB__i = __QB_NODE(handle).next -IF QB__i THEN - __QB_NODE(QB__i).prev = __QB_NODE(handle).prev -END IF -QB__i = __QB_NODE(handle).prev -IF QB__i THEN - __QB_NODE(QB__i).next = __QB_NODE(handle).next -END IF -QB__i = __QB_NODE(handle).parent -IF QB__i THEN - IF __QB_NODE(QB__i).firstChild = handle THEN __QB_NODE(QB__i).firstChild = __QB_NODE(handle).next - IF __QB_NODE(QB__i).lastChild = handle THEN __QB_NODE(QB__i).lastChild = __QB_NODE(handle).prev - __QB_NODE(QB__i).count = __QB_NODE(QB__i).count - 1 - __QB_NODE(handle).parent = 0 -END IF -__QB_NODE(handle).next = 0 -__QB_NODE(handle).prev = 0 -__QB_NODE(handle).hashReference = 0 -END SUB - -'################################################## - - - -SUB __QB_NODESET_addChildren (QB__parent AS LONG, QB__selOut AS LONG) -DIM QB__child AS LONG -DIM QB__newSel AS LONG -QB__child = __QB_NODE(QB__parent).firstChild -DO WHILE QB__child - QB__newSel = QB_NODE_newLabel_long(QB__child) - QB_NODE_assign QB__selOut, QB__newSel - IF __QB_NODE(QB__child).firstChild THEN __QB_NODESET_addChildren QB__child, QB__selOut - QB__child = __QB_NODE(QB__child).next -LOOP -END SUB - -SUB __QB_NODESET_addChildrenWithDepth (QB__parent AS LONG, QB__selOut AS LONG, currentDepth AS LONG, minDepth AS LONG, maxDepth AS LONG) -DIM QB__child AS LONG -DIM QB__newSel AS LONG -QB__child = __QB_NODE(QB__parent).firstChild -DO WHILE QB__child - IF currentDepth >= minDepth THEN - QB__newSel = QB_NODE_newLabel_long(QB__child) - QB_NODE_assign QB__selOut, QB__newSel - END IF - IF currentDepth < maxDepth THEN - IF __QB_NODE(QB__child).firstChild THEN - __QB_NODESET_addChildrenWithDepth QB__child, QB__selOut, currentDepth + 1, minDepth, maxDepth - END IF - END IF - QB__child = __QB_NODE(QB__child).next -LOOP -END SUB - - - -SUB __QB_NODE_debugInfo (QB__i AS LONG) -PRINT "-------- __QB_NODE_debugInfo:"; QB__i; "--------" -'type -DIM QB__type AS LONG -QB__type = __QB_NODE(QB__i).type -PRINT "TYPE: " + QB_NODE_typeName(QB__type) -'label -IF __QB_NODE(QB__i).labelFormat = QB_NODE_FORMAT_STR THEN - PRINT "LABEL: " + QB_STR_get(__QB_NODE(QB__i).label) -END IF -'value -IF __QB_NODE(QB__i).valueFormat = QB_NODE_FORMAT_STR THEN - PRINT "VALUE: " + QB_STR_get(__QB_NODE(QB__i).value) -END IF -IF __QB_NODE(QB__i).parent THEN - PRINT "Has parent of type " + QB_NODE_typeName(__QB_NODE(__QB_NODE(QB__i).parent).type) + " ["; __QB_NODE(QB__i).parent; "]" -ELSE - PRINT "This is a root element" -END IF -IF __QB_NODE(QB__i).firstChild THEN - PRINT "Has child of type " + QB_NODE_typeName(__QB_NODE(__QB_NODE(QB__i).firstChild).type) + " ["; __QB_NODE(QB__i).firstChild; "]" -END IF -IF __QB_NODE(QB__i).next THEN - PRINT "Has next sibling of type " + QB_NODE_typeName(__QB_NODE(__QB_NODE(QB__i).next).type) + " ["; __QB_NODE(QB__i).next; "]" -END IF -IF __QB_NODE(QB__i).prev THEN - PRINT "Has previous sibling of type " + QB_NODE_typeName(__QB_NODE(__QB_NODE(QB__i).prev).type) + " ["; __QB_NODE(QB__i).prev; "]" -END IF -PRINT "----------------" -END SUB - -'################################################## - - -'#################### JSON: Private Methods #################### - -FUNCTION __QB_JSON_unescape$ (QB__in AS STRING, QB__detectedFormat AS LONG, QB__detectedFormatValue AS LONG) -'-unescapes string -'-strips paired single or double quotes -'-detects data type (string, number, bool, null) -'-very permissive -QB__detectedFormat = 0 -QB__detectedFormatValue = 0 -DIM QB__out AS STRING -DIM QB__i1 AS LONG -DIM QB__i2 AS LONG -DIM QB__i3 AS LONG -DIM QB__in_len AS LONG -DIM QB__a AS LONG -DIM QB__a2 AS LONG -DIM QB__hex AS STRING -DIM QB__hex_len AS LONG -DIM QB__quoted AS LONG -QB__in_len = LEN(QB__in) -QB__out = SPACE$(QB__in_len) 'output is never longer than input -QB__i1 = 1 -QB__i2 = 0 -QB__i = 0 -'trim -QB__in = LTRIM$(RTRIM$(QB__in)) -QB__in_len = LEN(QB__in) -'strip quotes -IF ASC(QB__in) = 34 OR ASC(QB__in) = 39 THEN - IF ASC(QB__in, QB__in_len) = ASC(QB__in) AND QB__in_len > 1 THEN - QB__quoted = ASC(QB__in) - QB__detectedFormat = QB_NODE_FORMAT_STR - QB__in_len = QB__in_len - 2 - QB__in = MID$(QB__in, 2, QB__in_len) - END IF -END IF -'detect type if not quoted -IF QB__quoted = 0 THEN - IF QB__in_len = 4 THEN - IF LCASE$(QB__in) = "true" THEN QB__in = "true": QB__detectedFormat = QB_NODE_FORMAT_BOOL: QB__detectedFormatValue = QB_TRUE - IF LCASE$(QB__in) = "null" THEN QB__in = "null": QB__detectedFormat = QB_NODE_FORMAT_NULL: QB__detectedFormatValue = QB_NULL - END IF - IF QB__in_len = 5 THEN - IF LCASE$(QB__in) = "false" THEN QB__in = "false": QB__detectedFormat = QB_NODE_FORMAT_BOOL: QB__detectedFormatValue = QB_FALSE - END IF - IF QB__detectedFormat = 0 THEN - QB__a = ASC(QB__in) - IF QB__a >= 48 AND QB__a <= 57 THEN '0-9 - IF INSTR(QB__in, ".") = 0 THEN - QB__detectedFormat = QB_NODE_FORMAT_LONG: QB__detectedFormatValue = VAL(QB__in) - END IF - ELSE - IF QB__a = 45 THEN '- - IF INSTR(QB__in, ".") = 0 THEN - QB__detectedFormat = QB_NODE_FORMAT_LONG: QB__detectedFormatValue = VAL(QB__in) - END IF - END IF - IF QB__a = 46 THEN '. - 'TODO: decimal support - END IF - END IF - IF QB__detectedFormat = 0 THEN QB__detectedFormat = QB_NODE_FORMAT_STR - END IF -END IF -'if a string, parse to convert escaped content -IF QB__detectedFormat = QB_NODE_FORMAT_STR THEN - DO WHILE QB__i1 <= QB__in_len - QB__a = ASC(QB__in, QB__i1) - IF QB__a <> 92 OR QB__i1 = QB__in_len THEN 'not \ or at end - QB__i2 = QB__i2 + 1: ASC(QB__out, QB__i2) = QB__a - ELSE - QB__i1 = QB__i1 + 1: QB__a = ASC(QB__in, QB__i1) - QB__a2 = __QB_JSON_escape_lookup_reversed(QB__a) - IF QB__a2 THEN - QB__i2 = QB__i2 + 1: ASC(QB__out, QB__i2) = QB__a2 - ELSE - IF QB__a = 117 OR QB__a = 85 AND QB__i1 + 4 <= QB__in_len THEN 'u or U - QB__a2 = VAL("&H" + MID$(QB__in, QB__i1 + 1, 4) + "~&") 'unicode code point - QB__i1 = QB__i1 + 4 - QB__a = 0 - IF QB__a2 = 0 THEN - QB__i2 = QB__i2 + 1: ASC(QB__out, QB__i2) = 0 - ELSE - 'todo: replace with dictionary lookup - FOR QB__i3 = 1 TO 255 - IF QB__a2 = _MAPUNICODE(QB__i3) THEN - QB__a = QB__i3 - QB__i2 = QB__i2 + 1: ASC(QB__out, QB__i2) = QB__a - EXIT FOR - END IF - NEXT - IF QB__i3 = 256 THEN 'could not locate a match for the character, show a question mark - QB__i2 = QB__i2 + 1: ASC(QB__out, QB__i2) = 63 '? - END IF - END IF - ELSE - 'unknown \??? combination (add as is) - QB__i2 = QB__i2 + 1: ASC(QB__out, QB__i2) = 92 '\ - QB__i2 = QB__i2 + 1: ASC(QB__out, QB__i2) = QB__a '2nd character - END IF - END IF - END IF - QB__i1 = QB__i1 + 1 - LOOP - __QB_JSON_unescape$ = LEFT$(QB__out, QB__i2) -ELSE - __QB_JSON_unescape$ = QB__in -END IF -END FUNCTION - -FUNCTION __QB_JSON_escape$ (QB__in AS STRING) -DIM QB__out AS STRING -DIM QB__i1 AS LONG -DIM QB__i2 AS LONG -DIM QB__in_len AS LONG -DIM QB__a AS LONG -DIM QB__a2 AS LONG -DIM QB__hex AS STRING -DIM QB__hex_len AS LONG -QB__in_len = LEN(QB__in) -QB__out = SPACE$(QB__in_len * 6) 'worst possible case is double size (\uXXXX) -QB__i1 = 1 -QB__i2 = 0 -QB__i = 0 -DO WHILE QB__i1 <= QB__in_len - QB__a = ASC(QB__in, QB__i1) - IF QB__a <> 92 AND QB__a <> 34 AND (QB__a >= 32 AND QB__a <= 126) THEN 'not \ or " and valid standard ASCII - QB__i2 = QB__i2 + 1: ASC(QB__out, QB__i2) = QB__a - ELSE - QB__i2 = QB__i2 + 1: ASC(QB__out, QB__i2) = 92 '\ - QB__a2 = __QB_JSON_escape_lookup(QB__a) - IF QB__a2 THEN - QB__i2 = QB__i2 + 1: ASC(QB__out, QB__i2) = QB__a2 - ELSE - QB__i2 = QB__i2 + 1: ASC(QB__out, QB__i2) = 117 'u - IF QB__a = 0 THEN - QB__hex = "0" - ELSE - QB__hex = HEX$(_MAPUNICODE(QB__a)) - END IF - QB__hex_len = LEN(QB__hex) - QB__a2 = 48 - FOR QB__i = 1 TO 4 - IF 5 - QB__i <= QB__hex_len THEN - QB__a2 = ASC(QB__hex, QB__i - (4 - QB__hex_len)) - END IF - QB__i2 = QB__i2 + 1: ASC(QB__out, QB__i2) = QB__a2 - NEXT - END IF - END IF - QB__i1 = QB__i1 + 1 -LOOP -__QB_JSON_escape$ = LEFT$(QB__out, QB__i2) -END FUNCTION - -FUNCTION __QB_JSON_output_string$ (QB__in AS STRING) -__QB_JSON_output_string$ = QB_STR_QUOTE + __QB_JSON_escape$(QB__in) + QB_STR_QUOTE -END FUNCTION - -SUB __QB_JSON_serialize (json AS STRING, first AS LONG, addSiblings AS LONG) -DIM QB__i AS LONG -QB__i = first -DO WHILE QB__i - IF QB__i <> first THEN - json = json + "," - END IF - IF __QB_NODE(QB__i).type = QB_NODE_TYPE_DICTIONARY THEN - IF __QB_NODE(QB__i).labelFormat = QB_NODE_FORMAT_STR THEN - json = json + __QB_JSON_output_string(QB_STR_get(__QB_NODE(QB__i).label)) + ":" - END IF - json = json + "{" - __QB_JSON_serialize json, __QB_NODE(QB__i).firstChild, 1 - json = json + "}" - END IF - IF __QB_NODE(QB__i).type = QB_NODE_TYPE_LIST THEN - IF __QB_NODE(QB__i).labelFormat = QB_NODE_FORMAT_STR THEN - json = json + __QB_JSON_output_string(QB_STR_get(__QB_NODE(QB__i).label)) + ":" - END IF - json = json + "[" - __QB_JSON_serialize json, __QB_NODE(QB__i).firstChild, 1 - json = json + "]" - END IF - IF __QB_NODE(QB__i).type = QB_NODE_TYPE_VALUE THEN - IF __QB_NODE(QB__i).labelFormat = QB_NODE_FORMAT_STR THEN - json = json + __QB_JSON_output_string(QB_STR_get(__QB_NODE(QB__i).label)) + ":" - END IF - IF __QB_NODE(QB__i).valueFormat <> QB_NODE_FORMAT_STR THEN - json = json + QB_NODE_value(QB__i) - ELSE - json = json + __QB_JSON_output_string(QB_NODE_value(QB__i)) - END IF - END IF - IF addSiblings THEN - QB__i = __QB_NODE(QB__i).next - ELSE - QB__i = 0 - END IF -LOOP -END SUB - - -FUNCTION __QB_JSON_deserialize (QB__json AS STRING, QB__index AS LONG, QB__parent AS LONG) -'returns the first node created - -DIM QB__firstNodeCreated AS LONG -DIM QB__ignore AS LONG - -DIM QB__index1 AS LONG -QB__index1 = QB__index - -DIM QB__asc AS LONG -DIM QB__labelIndex AS LONG -DIM QB__label AS STRING -DIM QB__value AS STRING -DIM QB__obj AS LONG -DIM QB__objAdded AS LONG -DIM QB__final AS LONG -DIM QB__detectedFormat AS LONG -DIM QB__detectedFormatValue AS LONG -DIM QB__contentExists AS LONG -DO WHILE QB__index <= LEN(QB__json) + 1 - IF QB__index = LEN(QB__json) + 1 THEN - QB__final = 1 - QB__asc = 32 'whitespace - ELSE - QB__asc = ASC(QB__json, QB__index) - END IF - - IF QB__asc = 44 OR QB__asc = 125 OR QB__asc = 93 OR QB__final <> 0 THEN ', } ] final - IF QB__objAdded = 0 AND QB__contentExists <> 0 THEN - QB__value = MID$(QB__json, QB__index1, (QB__index - QB__index1)) - 'TODO: derive value format here - QB__obj = QB_NODE_new(QB_NODE_TYPE_VALUE, 0) - IF QB__firstNodeCreated = 0 THEN QB__firstNodeCreated = QB__obj - IF QB__label <> "" THEN - QB_NODE_setLabel QB__obj, __QB_JSON_unescape$(QB__label, 0, 0) - QB__label = "" - END IF - QB__value = __QB_JSON_unescape$(QB__value, QB__detectedFormat, QB__detectedFormatValue) - IF QB__detectedFormat = QB_NODE_FORMAT_STR THEN - QB_NODE_setValue_format QB__obj, QB_STR_new(QB__value), QB__detectedFormat - ELSE - QB_NODE_setValue_format QB__obj, QB__detectedFormatValue, QB__detectedFormat - END IF - IF QB__parent <> 0 THEN QB_NODE_assign QB__parent, QB__obj - END IF - 'end of block encountered? - IF QB__asc = 125 OR QB__asc = 93 OR QB__final <> 0 THEN '} ] final - __QB_JSON_deserialize = QB__firstNodeCreated - EXIT FUNCTION - END IF - QB__index1 = QB__index + 1 - QB__objAdded = 0 - QB__contentExists = 0 - END IF - - IF QB__asc <> 44 AND QB__asc <> 32 AND QB__asc <> 9 THEN QB__contentExists = 1 - - IF QB__asc = 58 THEN ': - IF LEN(QB__label) THEN - 'already has label - PRINT "Invalid label separator encountered ':'" - END - END IF - QB__label = MID$(QB__json, QB__index1, (QB__index - QB__index1)) - QB__index1 = QB__index + 1 'move start location - QB__contentExists = 0 - END IF - - IF QB__asc = 123 THEN '{ - IF QB__objAdded <> 0 THEN - PRINT "Expected ," - END - END IF - QB__obj = QB_NODE_newDictionary - IF QB__firstNodeCreated = 0 THEN QB__firstNodeCreated = QB__obj - IF QB__label <> "" THEN - QB_NODE_setLabel QB__obj, __QB_JSON_unescape$(QB__label, 0, 0) - QB__label = "" - END IF - QB__index = QB__index + 1 - QB__ignore = __QB_JSON_deserialize(QB__json, QB__index, QB__obj) - IF ASC(QB__json, QB__index) <> 125 THEN '} - PRINT "Expected }" - END - END IF - IF QB__parent <> 0 THEN QB_NODE_assign QB__parent, QB__obj - QB__objAdded = 1 - QB__contentExists = 0 - END IF - - IF QB__asc = 91 THEN '[ - IF QB__objAdded <> 0 THEN - PRINT "Expected ," - END IF - QB__obj = QB_NODE_newList - IF QB__firstNodeCreated = 0 THEN QB__firstNodeCreated = QB__obj - IF QB__label <> "" THEN - QB_NODE_setLabel QB__obj, __QB_JSON_unescape$(QB__label, 0, 0) - QB__label = "" - END IF - QB__index = QB__index + 1 - QB__ignore = __QB_JSON_deserialize(QB__json, QB__index, QB__obj) - IF ASC(QB__json, QB__index) <> 93 THEN '] - PRINT "Expected ]" - END - END IF - IF QB__parent <> 0 THEN QB_NODE_assign QB__parent, QB__obj - QB__objAdded = 1 - QB__contentExists = 0 - END IF - - QB__index = QB__index + 1 -LOOP -PRINT "Unexpected end of loop encountered" -END - -END FUNCTION - -'################################################## - -'#################### DATETIME: Private Methods #################### - -FUNCTION __QB_DATETIME_format_smartCase$ (format AS STRING, value AS STRING) -DIM QB__type AS LONG -DIM QB__a AS LONG -DIM QB__a2 AS LONG -QB__a = ASC(format, 2) -QB__a2 = ASC(format, 3) -IF QB__a >= 65 AND QB__a <= 90 THEN - IF QB__a2 >= 65 AND QB__a2 <= 90 THEN - value = UCASE$(value) - ELSE - value = UCASE$(LEFT$(value, 1)) + LCASE$(MID$(value, 2)) - END IF -ELSE - value = LCASE$(value) -END IF -__QB_DATETIME_format_smartCase$ = value -END FUNCTION - -'################################################## \ No newline at end of file diff --git a/source/virtual_keyboard/embed/footer.bas b/source/virtual_keyboard/embed/footer.bas deleted file mode 100644 index b319e5b7d..000000000 --- a/source/virtual_keyboard/embed/footer.bas +++ /dev/null @@ -1,2 +0,0 @@ -'$include:'..\..\qb_framework\qb_framework_methods.bas' -'$include:'..\virtual_keyboard_methods.bas' diff --git a/source/virtual_keyboard/embed/header.bas b/source/virtual_keyboard/embed/header.bas deleted file mode 100644 index 129b2516e..000000000 --- a/source/virtual_keyboard/embed/header.bas +++ /dev/null @@ -1,7 +0,0 @@ -'$include:'..\..\qb_framework\qb_framework_global.bas' -'$include:'..\virtual_keyboard_global.bas' -DEFSNG A-Z -$INSTALLFILES "..\..\..\cyberbit.ttf" -$INSTALLFILES "..\layouts\virtual_keyboard_layout_default.txt" -dim shared appRootPath as string -appRootPath$=_CWD$+"\" '_CWD$ is the application root when the program launches, preserve this value for later use before client program changes the path diff --git a/source/virtual_keyboard/layouts/virtual_keyboard_layout_default.txt b/source/virtual_keyboard/layouts/virtual_keyboard_layout_default.txt deleted file mode 100644 index c2a9399a0..000000000 --- a/source/virtual_keyboard/layouts/virtual_keyboard_layout_default.txt +++ /dev/null @@ -1 +0,0 @@ -{"width":90,"keys":[{"type":"keySet","x":0,"y":30,"width":6,"height":3,"label":"\u2261","childKeys":[{"type":"key","offsetX":25,"offsetY":-30,"width":34,"height":6,"label":"","locks":false,"lockIsTemporary":false,"events":{"keydown":{"keyCode":"KEY_SPACE"}}},{"type":"key","offsetX":86,"offsetY":-30,"width":4,"height":6,"label":"Esc","locks":false,"lockIsTemporary":false,"events":{"keydown":{"keyCode":"KEY_ESCAPE"}}},{"type":"key","offsetX":0,"offsetY":-24,"width":14,"height":6,"label":"Shift","locks":true,"lockIsTemporary":true,"events":{"keydown":{"keyCode":"KEY_LSHIFT"}}},{"type":"key","offsetX":0,"offsetY":-18,"width":11,"height":6,"label":"Caps Lock","locks":true,"lockIsTemporary":false,"events":{"keydown":{"keyCode":"KEY_CAPSLOCK"}}},{"type":"key","offsetX":0,"offsetY":-12,"width":9,"height":6,"label":"Tab","locks":false,"lockIsTemporary":false,"events":{"keydown":{"keyCode":"KEY_TAB"}}},{"type":"key","offsetX":78,"offsetY":-6,"width":12,"height":6,"label":"Back Space","locks":false,"lockIsTemporary":false,"events":{"keydown":{"keyCode":"KEY_BACKSPACE"}}},{"type":"key","offsetX":72,"offsetY":-6,"width":6,"height":6,"label":"=","locks":false,"lockIsTemporary":false,"events":{"keydown":{"keyCode":"KEY_EQUAL"},"keydownWithShift":{"keyCode":"KEY_PLUS","label":"+"}}},{"type":"key","offsetX":66,"offsetY":-6,"width":6,"height":6,"label":"-","locks":false,"lockIsTemporary":false,"events":{"keydown":{"keyCode":"KEY_MINUS"},"keydownWithShift":{"keyCode":"KEY_UNDERSCORE","label":"_"}}},{"type":"key","offsetX":60,"offsetY":-6,"width":6,"height":6,"label":"0","locks":false,"lockIsTemporary":false,"events":{"keydown":{"keyCode":"KEY_0"},"keydownWithShift":{"keyCode":"KEY_CLOSE_BRACKET","label":")"}}},{"type":"key","offsetX":54,"offsetY":-6,"width":6,"height":6,"label":"9","locks":false,"lockIsTemporary":false,"events":{"keydown":{"keyCode":"KEY_9"},"keydownWithShift":{"keyCode":"KEY_OPEN_BRACKET","label":"("}}},{"type":"key","offsetX":48,"offsetY":-6,"width":6,"height":6,"label":"8","locks":false,"lockIsTemporary":false,"events":{"keydown":{"keyCode":"KEY_8"},"keydownWithShift":{"keyCode":"KEY_STAR","label":"*"}}},{"type":"key","offsetX":42,"offsetY":-6,"width":6,"height":6,"label":"7","locks":false,"lockIsTemporary":false,"events":{"keydown":{"keyCode":"KEY_7"},"keydownWithShift":{"keyCode":"KEY_AND","label":"&"}}},{"type":"key","offsetX":36,"offsetY":-6,"width":6,"height":6,"label":"6","locks":false,"lockIsTemporary":false,"events":{"keydown":{"keyCode":"KEY_6"},"keydownWithShift":{"keyCode":"KEY_CARET","label":"^"}}},{"type":"key","offsetX":30,"offsetY":-6,"width":6,"height":6,"label":"5","locks":false,"lockIsTemporary":false,"events":{"keydown":{"keyCode":"KEY_5"},"keydownWithShift":{"keyCode":"KEY_PERCENT","label":"%"}}},{"type":"key","offsetX":18,"offsetY":-6,"width":6,"height":6,"label":"3","locks":false,"lockIsTemporary":false,"events":{"keydown":{"keyCode":"KEY_3"},"keydownWithShift":{"keyCode":"KEY_HASH","label":"#"}}},{"type":"key","offsetX":24,"offsetY":-6,"width":6,"height":6,"label":"4","locks":false,"lockIsTemporary":false,"events":{"keydown":{"keyCode":"KEY_4"},"keydownWithShift":{"keyCode":"KEY_DOLLAR","label":"$"}}},{"type":"key","offsetX":0,"offsetY":-30,"width":9,"height":6,"label":"Ctrl","locks":true,"lockIsTemporary":true,"events":{"keydown":{"keyCode":"KEY_LCTRL"}}},{"type":"key","offsetX":9,"offsetY":-30,"width":8,"height":6,"label":"\u2302","locks":false,"lockIsTemporary":false,"events":{"keydown":{"keyCode":"KEY_LSUPER"}}},{"type":"key","offsetX":17,"offsetY":-30,"width":8,"height":6,"label":"Alt","locks":true,"lockIsTemporary":true,"events":{"keydown":{"keyCode":"KEY_LALT"}}},{"type":"key","offsetX":59,"offsetY":-30,"width":9,"height":6,"label":"Alt","locks":true,"lockIsTemporary":true,"events":{"keydown":{"keyCode":"KEY_RALT"}}},{"type":"key","offsetX":80,"offsetY":-24,"width":10,"height":6,"label":"Shift","locks":true,"lockIsTemporary":true,"events":{"keydown":{"keyCode":"KEY_RSHIFT"}}},{"type":"key","offsetX":74,"offsetY":-30,"width":6,"height":6,"label":"\u2193","locks":false,"lockIsTemporary":false,"events":{"keydown":{"keyCode":"KEY_DOWN"}}},{"type":"key","offsetX":68,"offsetY":-30,"width":6,"height":6,"label":"\u2190","locks":false,"lockIsTemporary":false,"events":{"keydown":{"keyCode":"KEY_LEFT"}}},{"type":"key","offsetX":80,"offsetY":-30,"width":6,"height":6,"label":"\u2192","locks":false,"lockIsTemporary":false,"events":{"keydown":{"keyCode":"KEY_RIGHT"}}},{"type":"key","offsetX":74,"offsetY":-24,"width":6,"height":6,"label":"\u2191","locks":false,"lockIsTemporary":false,"events":{"keydown":{"keyCode":"KEY_UP"}}},{"type":"key","offsetX":68,"offsetY":-24,"width":6,"height":6,"label":"/","locks":false,"lockIsTemporary":false,"events":{"keydown":{"keyCode":"KEY_FORWARD_SLASH"},"keydownWithShift":{"keyCode":"KEY_QUESTION","label":"?"}}},{"type":"key","offsetX":62,"offsetY":-24,"width":6,"height":6,"label":".","locks":false,"lockIsTemporary":false,"events":{"keydown":{"keyCode":"KEY_DOT"},"keydownWithShift":{"keyCode":"KEY_GREATER_THAN","label":">"}}},{"type":"key","offsetX":56,"offsetY":-24,"width":6,"height":6,"label":",","locks":false,"lockIsTemporary":false,"events":{"keydown":{"keyCode":"KEY_COMMA"},"keydownWithShift":{"keyCode":"KEY_LESS_THAN","label":"<"}}},{"type":"key","offsetX":50,"offsetY":-24,"width":6,"height":6,"label":"m","locks":false,"lockIsTemporary":false,"events":{"keydown":{"keyCode":"KEY_LCASE_M"},"keydownWithShift":{"keyCode":"KEY_UCASE_M","label":"M"}}},{"type":"key","offsetX":44,"offsetY":-24,"width":6,"height":6,"label":"n","locks":false,"lockIsTemporary":false,"events":{"keydown":{"keyCode":"KEY_LCASE_N"},"keydownWithShift":{"keyCode":"KEY_UCASE_N","label":"N"}}},{"type":"key","offsetX":38,"offsetY":-24,"width":6,"height":6,"label":"b","locks":false,"lockIsTemporary":false,"events":{"keydown":{"keyCode":"KEY_LCASE_B"},"keydownWithShift":{"keyCode":"KEY_UCASE_B","label":"B"}}},{"type":"key","offsetX":32,"offsetY":-24,"width":6,"height":6,"label":"v","locks":false,"lockIsTemporary":false,"events":{"keydown":{"keyCode":"KEY_LCASE_V"},"keydownWithShift":{"keyCode":"KEY_UCASE_V","label":"V"}}},{"type":"key","offsetX":26,"offsetY":-24,"width":6,"height":6,"label":"c","locks":false,"lockIsTemporary":false,"events":{"keydown":{"keyCode":"KEY_LCASE_C"},"keydownWithShift":{"keyCode":"KEY_UCASE_C","label":"C"}}},{"type":"key","offsetX":20,"offsetY":-24,"width":6,"height":6,"label":"x","locks":false,"lockIsTemporary":false,"events":{"keydown":{"keyCode":"KEY_LCASE_X"},"keydownWithShift":{"keyCode":"KEY_UCASE_X","label":"X"}}},{"type":"key","offsetX":14,"offsetY":-24,"width":6,"height":6,"label":"z","locks":false,"lockIsTemporary":false,"events":{"keydown":{"keyCode":"KEY_LCASE_Z"},"keydownWithShift":{"keyCode":"KEY_UCASE_Z","label":"Z"}}},{"type":"key","offsetX":77,"offsetY":-18,"width":13,"height":6,"label":"Enter","locks":false,"lockIsTemporary":false,"events":{"keydown":{"keyCode":"KEY_ENTER"}}},{"type":"key","offsetX":81,"offsetY":-12,"width":9,"height":6,"label":"\\","locks":false,"lockIsTemporary":false,"events":{"keydown":{"keyCode":"KEY_BACK_SLASH"},"keydownWithShift":{"keyCode":"KEY_VERTICAL_BAR","label":"|"}}},{"type":"key","offsetX":71,"offsetY":-18,"width":6,"height":6,"label":"'","locks":false,"lockIsTemporary":false,"events":{"keydown":{"keyCode":"KEY_APOSTROPHE"},"keydownWithShift":{"keyCode":"KEY_QUOTE","label":"\""}}},{"type":"key","offsetX":65,"offsetY":-18,"width":6,"height":6,"label":";","locks":false,"lockIsTemporary":false,"events":{"keydown":{"keyCode":"KEY_SEMICOLON"},"keydownWithShift":{"keyCode":"KEY_COLON","label":":"}}},{"type":"key","offsetX":59,"offsetY":-18,"width":6,"height":6,"label":"l","locks":false,"lockIsTemporary":false,"events":{"keydown":{"keyCode":"KEY_LCASE_L"},"keydownWithShift":{"keyCode":"KEY_UCASE_L","label":"L"}}},{"type":"key","offsetX":53,"offsetY":-18,"width":6,"height":6,"label":"k","locks":false,"lockIsTemporary":false,"events":{"keydown":{"keyCode":"KEY_LCASE_K"},"keydownWithShift":{"keyCode":"KEY_UCASE_K","label":"K"}}},{"type":"key","offsetX":47,"offsetY":-18,"width":6,"height":6,"label":"j","locks":false,"lockIsTemporary":false,"events":{"keydown":{"keyCode":"KEY_LCASE_J"},"keydownWithShift":{"keyCode":"KEY_UCASE_J","label":"J"}}},{"type":"key","offsetX":41,"offsetY":-18,"width":6,"height":6,"label":"h","locks":false,"lockIsTemporary":false,"events":{"keydown":{"keyCode":"KEY_LCASE_H"},"keydownWithShift":{"keyCode":"KEY_UCASE_H","label":"H"}}},{"type":"key","offsetX":35,"offsetY":-18,"width":6,"height":6,"label":"g","locks":false,"lockIsTemporary":false,"events":{"keydown":{"keyCode":"KEY_LCASE_G"},"keydownWithShift":{"keyCode":"KEY_UCASE_G","label":"G"}}},{"type":"key","offsetX":29,"offsetY":-18,"width":6,"height":6,"label":"f","locks":false,"lockIsTemporary":false,"events":{"keydown":{"keyCode":"KEY_LCASE_F"},"keydownWithShift":{"keyCode":"KEY_UCASE_F","label":"F"}}},{"type":"key","offsetX":23,"offsetY":-18,"width":6,"height":6,"label":"d","locks":false,"lockIsTemporary":false,"events":{"keydown":{"keyCode":"KEY_LCASE_D"},"keydownWithShift":{"keyCode":"KEY_UCASE_D","label":"D"}}},{"type":"key","offsetX":17,"offsetY":-18,"width":6,"height":6,"label":"s","locks":false,"lockIsTemporary":false,"events":{"keydown":{"keyCode":"KEY_LCASE_S"},"keydownWithShift":{"keyCode":"KEY_UCASE_S","label":"S"}}},{"type":"key","offsetX":11,"offsetY":-18,"width":6,"height":6,"label":"a","locks":false,"lockIsTemporary":false,"events":{"keydown":{"keyCode":"KEY_LCASE_A"},"keydownWithShift":{"keyCode":"KEY_UCASE_A","label":"A"}}},{"type":"key","offsetX":12,"offsetY":-6,"width":6,"height":6,"label":"2","locks":false,"lockIsTemporary":false,"events":{"keydown":{"keyCode":"KEY_2"},"keydownWithShift":{"keyCode":"KEY_AT","label":"@"}}},{"type":"key","offsetX":75,"offsetY":-12,"width":6,"height":6,"label":"]","locks":false,"lockIsTemporary":false,"events":{"keydown":{"keyCode":"KEY_CLOSE_BRACKET_SQUARE"},"keydownWithShift":{"keyCode":"KEY_CLOSE_BRACKET_CURLY","label":"}"}}},{"type":"key","offsetX":69,"offsetY":-12,"width":6,"height":6,"label":"[","locks":false,"lockIsTemporary":false,"events":{"keydown":{"keyCode":"KEY_OPEN_BRACKET_SQUARE"},"keydownWithShift":{"keyCode":"KEY_OPEN_BRACKET_CURLY","label":"{"}}},{"type":"key","offsetX":63,"offsetY":-12,"width":6,"height":6,"label":"p","locks":false,"lockIsTemporary":false,"events":{"keydown":{"keyCode":"KEY_LCASE_P"},"keydownWithShift":{"keyCode":"KEY_UCASE_P","label":"P"}}},{"type":"key","offsetX":57,"offsetY":-12,"width":6,"height":6,"label":"o","locks":false,"lockIsTemporary":false,"events":{"keydown":{"keyCode":"KEY_LCASE_O"},"keydownWithShift":{"keyCode":"KEY_UCASE_O","label":"O"}}},{"type":"key","offsetX":51,"offsetY":-12,"width":6,"height":6,"label":"i","locks":false,"lockIsTemporary":false,"events":{"keydown":{"keyCode":"KEY_LCASE_I"},"keydownWithShift":{"keyCode":"KEY_UCASE_I","label":"I"}}},{"type":"key","offsetX":45,"offsetY":-12,"width":6,"height":6,"label":"u","locks":false,"lockIsTemporary":false,"events":{"keydown":{"keyCode":"KEY_LCASE_U"},"keydownWithShift":{"keyCode":"KEY_UCASE_U","label":"U"}}},{"type":"key","offsetX":39,"offsetY":-12,"width":6,"height":6,"label":"y","locks":false,"lockIsTemporary":false,"events":{"keydown":{"keyCode":"KEY_LCASE_Y"},"keydownWithShift":{"keyCode":"KEY_UCASE_Y","label":"Y"}}},{"type":"key","offsetX":33,"offsetY":-12,"width":6,"height":6,"label":"t","locks":false,"lockIsTemporary":false,"events":{"keydown":{"keyCode":"KEY_LCASE_T"},"keydownWithShift":{"keyCode":"KEY_UCASE_T","label":"T"}}},{"type":"key","offsetX":27,"offsetY":-12,"width":6,"height":6,"label":"r","locks":false,"lockIsTemporary":false,"events":{"keydown":{"keyCode":"KEY_LCASE_R"},"keydownWithShift":{"keyCode":"KEY_UCASE_R","label":"R"}}},{"type":"key","offsetX":21,"offsetY":-12,"width":6,"height":6,"label":"e","locks":false,"lockIsTemporary":false,"events":{"keydown":{"keyCode":"KEY_LCASE_E"},"keydownWithShift":{"keyCode":"KEY_UCASE_E","label":"E"}}},{"type":"key","offsetX":15,"offsetY":-12,"width":6,"height":6,"label":"w","locks":false,"lockIsTemporary":false,"events":{"keydown":{"keyCode":"KEY_LCASE_W"},"keydownWithShift":{"keyCode":"KEY_UCASE_W","label":"W"}}},{"type":"key","offsetX":9,"offsetY":-12,"width":6,"height":6,"label":"q","locks":false,"lockIsTemporary":false,"events":{"keydown":{"keyCode":"KEY_LCASE_Q"},"keydownWithShift":{"keyCode":"KEY_UCASE_Q","label":"Q"}}},{"type":"key","offsetX":6,"offsetY":-6,"width":6,"height":6,"label":"1","locks":false,"lockIsTemporary":false,"events":{"keydown":{"keyCode":"KEY_1"},"keydownWithShift":{"keyCode":"KEY_EXCLAMATION","label":"!"}}},{"type":"key","offsetX":0,"offsetY":-6,"width":6,"height":6,"label":"`","locks":false,"lockIsTemporary":false,"events":{"keydown":{"keyCode":"KEY_REVERSE_APOSTROPHE"},"keydownWithShift":{"keyCode":"KEY_TILDE","label":"~"}}}]}]} diff --git a/source/virtual_keyboard/virtual_keyboard_global.bas b/source/virtual_keyboard/virtual_keyboard_global.bas deleted file mode 100644 index c317326bf..000000000 --- a/source/virtual_keyboard/virtual_keyboard_global.bas +++ /dev/null @@ -1,177 +0,0 @@ -DEFSNG A-Z - -DECLARE LIBRARY - SUB requestKeyboardOverlayImage (BYVAL handle AS LONG) - SUB mouseinput_mode (BYVAL exclusive AS LONG) - FUNCTION func__mouseinput_exclusive& -END DECLARE - -'VK Constants -'$include:'virtual_keyboard_keycodes.bas' -'$include:'virtual_keyboard_keypush.bas' - -'VK Types -TYPE VKEY_EVENT - keydown AS LONG -END TYPE - -TYPE VKEY_DPAD - up AS VKEY_EVENT - down AS VKEY_EVENT - left AS VKEY_EVENT - right AS VKEY_EVENT - x AS SINGLE '-1 to 1 - y AS SINGLE '-1 to 1 - dx AS LONG '-1, 0, 1 - dy AS LONG '-1, 0, 1 - lastKeyDx AS LONG '-1, 0, 1 - lastKeyDy AS LONG '-1, 0, 1 -END TYPE - -TYPE VKEY_TYPE - active AS LONG '1=in use - internal AS LONG - role AS STRING * 4 - state AS LONG - label AS STRING * 100 - x AS LONG 'left hand side - y AS LONG 'from base of screen - w AS LONG 'width - h AS LONG 'height (default is 10) - parent AS LONG - offsetX AS LONG - offsetY AS LONG - held AS LONG - event AS VKEY_EVENT - - hasShiftedEvent AS LONG - shiftedEvent AS VKEY_EVENT 'eg. when shifted or caps lock is on - shiftedLabel AS STRING * 100 - - locks AS LONG '1 or 0 eg. num lock, scroll lock, caps lock - lockIsTemporary AS LONG 'eg shift key, locks till next press - locked AS LONG - dpad AS VKEY_DPAD - - - subImage AS LONG - - image AS LONG - highlightImage AS LONG - selectedImage AS LONG - shiftedImage AS LONG - shiftedHighlightImage AS LONG - shiftedSelectedImage AS LONG - - reDraw AS LONG - - 'key repeat - lastKeydownTime AS SINGLE - keyRepeatCount AS LONG - keyRepeatKeyCode AS LONG - -END TYPE - -'VK Global Variables -DIM SHARED VK(1000) AS VKEY_TYPE -DIM SHARED VkLast - -DIM SHARED VkEmpty AS VKEY_TYPE -VkEmpty.label = "" - -DIM SHARED VkHide: VkHide = 1 - -DIM SHARED VkUnitStepY: VkUnitStepY = 6 -DIM SHARED VkNewKeySize: VkNewKeySize = 6 -DIM SHARED VkDefaultWidth: VkDefaultWidth = 6 -DIM SHARED VkLastSelectionPage: VkLastSelectionPage = 1 -DIM SHARED VkUnitSize 'size of a unit in pixels (floating point) - -DIM SHARED VkDefaultSelectKeyPage: VkDefaultSelectKeyPage = 1 -DIM SHARED VkFont -DIM SHARED VkFontSmall -DIM SHARED VkKeyNameLookup AS LONG -DIM SHARED VkKeyCodeLookup AS LONG -VkAddKeyNames - -'fonts are loaded on startup, not all sizes are available and the system will -'find/use the best match -DIM SHARED vkFonts(1000) AS LONG -DIM SHARED vkFontAllow(1000) AS LONG -vkFontAllow(8)=1 -vkFontAllow(9)=1 -vkFontAllow(10)=1 -vkFontAllow(11)=1 -vkFontAllow(12)=1 -vkFontAllow(14)=1 -vkFontAllow(16)=1 -vkFontAllow(18)=1 -vkFontAllow(20)=1 -vkFontAllow(24)=1 -vkFontAllow(28)=1 -vkFontAllow(32)=1 -vkFontAllow(36)=1 -vkFontAllow(48)=1 -vkFontAllow(72)=1 -vkFontAllow(100)=1 - -DIM SHARED VkBgTex -DIM SHARED VkBorderTex -DIM SHARED VkInternalBgTex -DIM SHARED VkInternalBorderTex -DIM SHARED VkClearTex - -DIM SHARED VkSelectedKey -DIM SHARED VkAddShiftedKey - -DIM SHARED VkWinX -DIM SHARED VkWinY -DIM SHARED VkOverlay 'an image overlayed over the other content -DIM SHARED VkBackbuffer 'backbuffer of overlay - -DIM SHARED VkExiting -DIM SHARED VkExited - -DIM SHARED VkReset - -DIM SHARED VkDelayStartTime AS DOUBLE -DIM SHARED VkDelay AS DOUBLE -VkDelayStartTime=TIMER(0.001) -VkDelay=1 'programs typically set their screen resolution on start, so wait a second before trying to build a keyboard which matches that resolution -DIM SHARED VkDelayedReset - -DIM SHARED VkWidthInUnits - -DIM SHARED VkTimer -VkTimer = _FREETIMER - -DIM SHARED VkReDraw AS LONG: VkReDraw = 1 - -DIM SHARED VkDelayUntilFirstRepeat AS SINGLE: VkDelayUntilFirstRepeat = 0.75 -DIM SHARED VkDelayUntilFollowingRepeats AS SINGLE: VkDelayUntilFollowingRepeats = 0.025 '40 per sec - -TYPE VkRegTypeX - ax AS INTEGER - bx AS INTEGER - cx AS INTEGER - dx AS INTEGER - bp AS INTEGER - si AS INTEGER - di AS INTEGER - flags AS INTEGER - ds AS INTEGER - es AS INTEGER -END TYPE -DIM SHARED VkReg AS VkRegTypeX - -DIM SHARED VkSharedMouseMx AS LONG -DIM SHARED VkSharedMouseMy AS LONG -DIM SHARED VkSharedMouseMb AS LONG - -DIM SHARED VkSharedInputMode AS LONG: VkSharedInputMode = -1 - -ON TIMER(VkTimer, .01) VkUpdate -TIMER(VkTimer) ON - -DIM SHARED VkMousePipe AS LONG -DIM SHARED VkMousePipeCapture AS LONG \ No newline at end of file diff --git a/source/virtual_keyboard/virtual_keyboard_keycodes.bas b/source/virtual_keyboard/virtual_keyboard_keycodes.bas deleted file mode 100644 index eb4bd2132..000000000 --- a/source/virtual_keyboard/virtual_keyboard_keycodes.bas +++ /dev/null @@ -1,207 +0,0 @@ -CONST VK_KEY_PAUSE& = 100019 -CONST VK_KEY_NUMLOCK& = 100300 -CONST VK_KEY_CAPSLOCK& = 100301 -CONST VK_KEY_SCROLLOCK& = 100302 -CONST VK_KEY_RSHIFT& = 100303 -CONST VK_KEY_LSHIFT& = 100304 -CONST VK_KEY_RCTRL& = 100305 -CONST VK_KEY_LCTRL& = 100306 -CONST VK_KEY_RALT& = 100307 -CONST VK_KEY_LALT& = 100308 -CONST VK_KEY_RMETA& = 100309 'Left 'Apple' key (MacOSX) -CONST VK_KEY_LMETA& = 100310 'Right 'Apple' key (MacOSX) -CONST VK_KEY_LSUPER& = 100311 'Left "Windows" key -CONST VK_KEY_RSUPER& = 100312 'Right "Windows"key -CONST VK_KEY_MODE& = 100313 '"AltGr" key -CONST VK_KEY_COMPOSE& = 100314 -CONST VK_KEY_HELP& = 100315 -CONST VK_KEY_PRINT& = 100316 -CONST VK_KEY_SYSREQ& = 100317 -CONST VK_KEY_BREAK& = 100318 -CONST VK_KEY_MENU& = 100319 -CONST VK_KEY_POWER& = 100320 -CONST VK_KEY_EURO& = 100321 -CONST VK_KEY_UNDO& = 100322 -CONST VK_KEY_KP0& = 100256 -CONST VK_KEY_KP1& = 100257 -CONST VK_KEY_KP2& = 100258 -CONST VK_KEY_KP3& = 100259 -CONST VK_KEY_KP4& = 100260 -CONST VK_KEY_KP5& = 100261 -CONST VK_KEY_KP6& = 100262 -CONST VK_KEY_KP7& = 100263 -CONST VK_KEY_KP8& = 100264 -CONST VK_KEY_KP9& = 100265 -CONST VK_KEY_KP_PERIOD& = 100266 -CONST VK_KEY_KP_DIVIDE& = 100267 -CONST VK_KEY_KP_MULTIPLY& = 100268 -CONST VK_KEY_KP_MINUS& = 100269 -CONST VK_KEY_KP_PLUS& = 100270 -CONST VK_KEY_KP_ENTER& = 100271 -CONST VK_KEY_KP_INSERT& = 200000 -CONST VK_KEY_KP_END& = 200001 -CONST VK_KEY_KP_DOWN& = 200002 -CONST VK_KEY_KP_PAGE_DOWN& = 200003 -CONST VK_KEY_KP_LEFT& = 200004 -CONST VK_KEY_KP_MIDDLE& = 200005 -CONST VK_KEY_KP_RIGHT& = 200006 -CONST VK_KEY_KP_HOME& = 200007 -CONST VK_KEY_KP_UP& = 200008 -CONST VK_KEY_KP_PAGE_UP& = 200009 -CONST VK_KEY_KP_DELETE& = 200010 -CONST VK_KEY_SCROLL_LOCK_MODE& = 200011 -CONST VK_KEY_INSERT_MODE& = 200012 - -CONST VK_KEY_F1& = 15104 -CONST VK_KEY_F2& = 15360 -CONST VK_KEY_F3& = 15616 -CONST VK_KEY_F4& = 15872 -CONST VK_KEY_F5& = 16128 -CONST VK_KEY_F6& = 16384 -CONST VK_KEY_F7& = 16640 -CONST VK_KEY_F8& = 16896 -CONST VK_KEY_F9& = 17152 -CONST VK_KEY_F10& = 17408 -CONST VK_KEY_F11& = 34048 -CONST VK_KEY_F12& = 34304 - -CONST VK_KEY_INSERT& = 20992 -CONST VK_KEY_DELETE& = 21248 -CONST VK_KEY_HOME& = 18176 -CONST VK_KEY_END& = 20224 -CONST VK_KEY_PAGE_UP& = 18688 -CONST VK_KEY_PAGE_DOWN& = 20736 - -CONST VK_KEY_UP& = 18432 -CONST VK_KEY_DOWN& = 20480 -CONST VK_KEY_LEFT& = 19200 -CONST VK_KEY_RIGHT& = 19712 - -CONST VK_KEY_BACKSPACE& = 8 -CONST VK_KEY_TAB& = 9 - -CONST VK_KEY_ENTER& = 13 -CONST VK_KEY_ESCAPE& = 27 - -CONST VK_KEY_SPACE& = 32 -CONST VK_KEY_EXCLAMATION& = 33 -CONST VK_KEY_QUOTE& = 34 -CONST VK_KEY_HASH& = 35 -CONST VK_KEY_DOLLAR& = 36 -CONST VK_KEY_PERCENT& = 37 -CONST VK_KEY_AND& = 38 -CONST VK_KEY_APOSTROPHE& = 39 -CONST VK_KEY_OPEN_BRACKET& = 40 -CONST VK_KEY_CLOSE_BRACKET& = 41 -CONST VK_KEY_STAR& = 42 -CONST VK_KEY_PLUS& = 43 -CONST VK_KEY_COMMA& = 44 -CONST VK_KEY_MINUS& = 45 -CONST VK_KEY_DOT& = 46 -CONST VK_KEY_FORWARD_SLASH& = 47 -CONST VK_KEY_0& = 48 -CONST VK_KEY_1& = 49 -CONST VK_KEY_2& = 50 -CONST VK_KEY_3& = 51 -CONST VK_KEY_4& = 52 -CONST VK_KEY_5& = 53 -CONST VK_KEY_6& = 54 -CONST VK_KEY_7& = 55 -CONST VK_KEY_8& = 56 -CONST VK_KEY_9& = 57 -CONST VK_KEY_COLON& = 58 -CONST VK_KEY_SEMICOLON& = 59 -CONST VK_KEY_LESS_THAN& = 60 -CONST VK_KEY_EQUAL& = 61 -CONST VK_KEY_GREATER_THAN& = 62 -CONST VK_KEY_QUESTION& = 63 -CONST VK_KEY_AT& = 64 -CONST VK_KEY_A& = 65 -CONST VK_KEY_B& = 66 -CONST VK_KEY_C& = 67 -CONST VK_KEY_D& = 68 -CONST VK_KEY_E& = 69 -CONST VK_KEY_F& = 70 -CONST VK_KEY_G& = 71 -CONST VK_KEY_H& = 72 -CONST VK_KEY_I& = 73 -CONST VK_KEY_J& = 74 -CONST VK_KEY_K& = 75 -CONST VK_KEY_L& = 76 -CONST VK_KEY_M& = 77 -CONST VK_KEY_N& = 78 -CONST VK_KEY_O& = 79 -CONST VK_KEY_P& = 80 -CONST VK_KEY_Q& = 81 -CONST VK_KEY_R& = 82 -CONST VK_KEY_S& = 83 -CONST VK_KEY_T& = 84 -CONST VK_KEY_U& = 85 -CONST VK_KEY_V& = 86 -CONST VK_KEY_W& = 87 -CONST VK_KEY_X& = 88 -CONST VK_KEY_Y& = 89 -CONST VK_KEY_Z& = 90 -CONST VK_KEY_UCASE_A& = 65 -CONST VK_KEY_UCASE_B& = 66 -CONST VK_KEY_UCASE_C& = 67 -CONST VK_KEY_UCASE_D& = 68 -CONST VK_KEY_UCASE_E& = 69 -CONST VK_KEY_UCASE_F& = 70 -CONST VK_KEY_UCASE_G& = 71 -CONST VK_KEY_UCASE_H& = 72 -CONST VK_KEY_UCASE_I& = 73 -CONST VK_KEY_UCASE_J& = 74 -CONST VK_KEY_UCASE_K& = 75 -CONST VK_KEY_UCASE_L& = 76 -CONST VK_KEY_UCASE_M& = 77 -CONST VK_KEY_UCASE_N& = 78 -CONST VK_KEY_UCASE_O& = 79 -CONST VK_KEY_UCASE_P& = 80 -CONST VK_KEY_UCASE_Q& = 81 -CONST VK_KEY_UCASE_R& = 82 -CONST VK_KEY_UCASE_S& = 83 -CONST VK_KEY_UCASE_T& = 84 -CONST VK_KEY_UCASE_U& = 85 -CONST VK_KEY_UCASE_V& = 86 -CONST VK_KEY_UCASE_W& = 87 -CONST VK_KEY_UCASE_X& = 88 -CONST VK_KEY_UCASE_Y& = 89 -CONST VK_KEY_UCASE_Z& = 90 -CONST VK_KEY_OPEN_BRACKET_SQUARE& = 91 -CONST VK_KEY_BACK_SLASH& = 92 -CONST VK_KEY_CLOSE_BRACKET_SQUARE& = 93 -CONST VK_KEY_CARET& = 94 -CONST VK_KEY_UNDERSCORE& = 95 -CONST VK_KEY_REVERSE_APOSTROPHE& = 96 -CONST VK_KEY_LCASE_A& = 97 -CONST VK_KEY_LCASE_B& = 98 -CONST VK_KEY_LCASE_C& = 99 -CONST VK_KEY_LCASE_D& = 100 -CONST VK_KEY_LCASE_E& = 101 -CONST VK_KEY_LCASE_F& = 102 -CONST VK_KEY_LCASE_G& = 103 -CONST VK_KEY_LCASE_H& = 104 -CONST VK_KEY_LCASE_I& = 105 -CONST VK_KEY_LCASE_J& = 106 -CONST VK_KEY_LCASE_K& = 107 -CONST VK_KEY_LCASE_L& = 108 -CONST VK_KEY_LCASE_M& = 109 -CONST VK_KEY_LCASE_N& = 110 -CONST VK_KEY_LCASE_O& = 111 -CONST VK_KEY_LCASE_P& = 112 -CONST VK_KEY_LCASE_Q& = 113 -CONST VK_KEY_LCASE_R& = 114 -CONST VK_KEY_LCASE_S& = 115 -CONST VK_KEY_LCASE_T& = 116 -CONST VK_KEY_LCASE_U& = 117 -CONST VK_KEY_LCASE_V& = 118 -CONST VK_KEY_LCASE_W& = 119 -CONST VK_KEY_LCASE_X& = 120 -CONST VK_KEY_LCASE_Y& = 121 -CONST VK_KEY_LCASE_Z& = 122 -CONST VK_KEY_OPEN_BRACKET_CURLY& = 123 -CONST VK_KEY_VERTICAL_BAR& = 124 -CONST VK_KEY_CLOSE_BRACKET_CURLY& = 125 -CONST VK_KEY_TILDE& = 126 -CONST VK_KEY_BACKSPACE_ALTERNATE& = 127 diff --git a/source/virtual_keyboard/virtual_keyboard_keypush.bas b/source/virtual_keyboard/virtual_keyboard_keypush.bas deleted file mode 100644 index e6267e503..000000000 --- a/source/virtual_keyboard/virtual_keyboard_keypush.bas +++ /dev/null @@ -1,11 +0,0 @@ -DECLARE LIBRARY "" - SUB keydown_ascii (BYVAL keycode~&) - SUB keyup_ascii (BYVAL keycode~&) - SUB keydown_unicode (BYVAL keycode~&) - SUB keyup_unicode (BYVAL keycode~&) - SUB keydown_vk (BYVAL keycode~&) - SUB keyup_vk (BYVAL keycode~&) - 'these map directly to keydown/keyup except for unicode which remaps extended CP437 & double-width - SUB keydown (BYVAL keycode~&) - SUB keyup (BYVAL keycode~&) -END DECLARE \ No newline at end of file diff --git a/source/virtual_keyboard/virtual_keyboard_methods.bas b/source/virtual_keyboard/virtual_keyboard_methods.bas deleted file mode 100644 index 89518fe29..000000000 --- a/source/virtual_keyboard/virtual_keyboard_methods.bas +++ /dev/null @@ -1,2811 +0,0 @@ -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