diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000000..1ba19987d4 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,12 @@ +# Editor configuration, see https://editorconfig.org +root = true + +[*] +charset = utf-8 +indent_style = space +indent_size = 2 +insert_final_newline = true +trim_trailing_whitespace = true + +[*.md] +max_line_length = off diff --git a/android/KMEA/app/src/main/java/com/tavultesoft/kmea/KeyboardListActivity.java b/android/KMEA/app/src/main/java/com/tavultesoft/kmea/KeyboardListActivity.java index 18c85627e5..7f0f2c463c 100644 --- a/android/KMEA/app/src/main/java/com/tavultesoft/kmea/KeyboardListActivity.java +++ b/android/KMEA/app/src/main/java/com/tavultesoft/kmea/KeyboardListActivity.java @@ -21,6 +21,7 @@ import androidx.appcompat.widget.Toolbar; import android.content.Context; import android.content.Intent; +import android.database.DataSetObserver; import android.os.Bundle; import android.util.Log; import android.view.LayoutInflater; @@ -30,6 +31,7 @@ import android.view.Window; import android.widget.AdapterView; import android.widget.ImageView; import android.widget.ListView; +import android.widget.RelativeLayout; import android.widget.TextView; import android.widget.Toast; @@ -40,13 +42,16 @@ public final class KeyboardListActivity extends AppCompatActivity implements OnK private static ListView listView = null; private static final String TAG = "KeyboardListActivity"; + private DataSetObserver repoObserver; + private Dataset repo; + @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); supportRequestWindowFeature(Window.FEATURE_NO_TITLE); final Context context = this; - setContentView(R.layout.activity_list_layout); + setContentView(R.layout.activity_list_with_progress_layout); toolbar = (Toolbar) findViewById(R.id.list_toolbar); setSupportActionBar(toolbar); getSupportActionBar().setDisplayHomeAsUpEnabled(true); @@ -61,7 +66,20 @@ public final class KeyboardListActivity extends AppCompatActivity implements OnK String langID = getIntent().getStringExtra("languageCode"); String langName = getIntent().getStringExtra("languageName"); - Dataset repo = CloudRepository.shared.fetchDataset(this); + repo = CloudRepository.shared.fetchDataset(this); + + // add listener to dataset to get event for catalog update. + repoObserver = new DataSetObserver() { + @Override + public void onChanged() { + updateProgressBar(); + } + }; + repo.registerDataSetObserver(repoObserver); + + // init progress bar state + updateProgressBar(); + final FilteredKeyboardsAdapter adapter = new FilteredKeyboardsAdapter(this, repo, langID); textView.setText(langName); @@ -103,6 +121,25 @@ public final class KeyboardListActivity extends AppCompatActivity implements OnK }); } + /** + * switch between progress and listview. + */ + private void updateProgressBar() + { + RelativeLayout _progress = findViewById(R.id.progress); + boolean _updaterunning= CloudRepository.shared.updateIsRunning(); + ListView _list = findViewById(R.id.listView); + if(_updaterunning) + { + _progress.setVisibility(View.VISIBLE); + _list.setVisibility(View.GONE); + } + else { + _progress.setVisibility(View.GONE); + _list.setVisibility(View.VISIBLE); + } + } + @Override protected void onResume() { super.onResume(); @@ -117,6 +154,14 @@ public final class KeyboardListActivity extends AppCompatActivity implements OnK // ensure onKeyboardDownloadFinished() gets called } + @Override + protected void onDestroy() { + super.onDestroy(); + // remove listener from dataset. + repo.unregisterDataSetObserver(repoObserver); + } + + @Override public boolean onSupportNavigateUp() { onBackPressed(); diff --git a/android/KMEA/app/src/main/java/com/tavultesoft/kmea/LanguageListActivity.java b/android/KMEA/app/src/main/java/com/tavultesoft/kmea/LanguageListActivity.java index 5bbc6974d8..77ea176364 100644 --- a/android/KMEA/app/src/main/java/com/tavultesoft/kmea/LanguageListActivity.java +++ b/android/KMEA/app/src/main/java/com/tavultesoft/kmea/LanguageListActivity.java @@ -26,6 +26,7 @@ import androidx.appcompat.app.AlertDialog; import androidx.appcompat.app.AppCompatActivity; import android.content.Context; import android.content.Intent; +import android.database.DataSetObserver; import android.os.Bundle; import androidx.appcompat.widget.Toolbar; import android.util.Log; @@ -36,6 +37,7 @@ import android.view.Window; import android.widget.AdapterView; import android.widget.ImageView; import android.widget.ListView; +import android.widget.RelativeLayout; import android.widget.TextView; import android.widget.Toast; @@ -56,6 +58,8 @@ public final class LanguageListActivity extends AppCompatActivity implements OnK // These two JSON objects and their getters are still used by legacy metadata functions. private static JSONArray languages = null; + private DataSetObserver repoObserver; + private Dataset repo; protected static JSONArray languages() { return languages; @@ -78,7 +82,7 @@ public final class LanguageListActivity extends AppCompatActivity implements OnK super.onCreate(savedInstanceState); supportRequestWindowFeature(Window.FEATURE_NO_TITLE); context = this; - setContentView(R.layout.activity_list_layout); + setContentView(R.layout.activity_list_with_progress_layout); toolbar = (Toolbar) findViewById(R.id.list_toolbar); setSupportActionBar(toolbar); @@ -88,11 +92,24 @@ public final class LanguageListActivity extends AppCompatActivity implements OnK TextView textView = (TextView) findViewById(R.id.bar_title); textView.setText(getString(R.string.title_add_language)); - listView = (ListView) findViewById(R.id.listView); + listView = findViewById(R.id.listView); listView.setFastScrollEnabled(true); // Establish the list view based on the CloudRepository's Dataset. - Dataset repo = CloudRepository.shared.fetchDataset(this); + repo = CloudRepository.shared.fetchDataset(this); + + // add listener to dataset to get event for catalog update. + repoObserver = new DataSetObserver() { + @Override + public void onChanged() { + updateProgressBar(); + } + }; + + repo.registerDataSetObserver(repoObserver); + + // init progress bar state + updateProgressBar(); listView.setAdapter(new LanguagesAdapter(this, repo)); listView.setOnItemClickListener(new AdapterView.OnItemClickListener() { @@ -157,6 +174,25 @@ public final class LanguageListActivity extends AppCompatActivity implements OnK listView.setSelectionFromTop(i.getIntExtra("listPosition", 0), i.getIntExtra("offsetY", 0)); } + /** + * switch between progress and listview. + */ + private void updateProgressBar() + { + RelativeLayout _progress = findViewById(R.id.progress); + boolean _updaterunning= CloudRepository.shared.updateIsRunning(); + ListView _list = findViewById(R.id.listView); + if(_updaterunning) + { + _progress.setVisibility(View.VISIBLE); + _list.setVisibility(View.GONE); + } + else { + _progress.setVisibility(View.GONE); + _list.setVisibility(View.VISIBLE); + } + } + @Override protected void onResume() { super.onResume(); @@ -405,4 +441,11 @@ public final class LanguageListActivity extends AppCompatActivity implements OnK return !KeyboardPickerActivity.containsKeyboard(context, kbKey); } } + + @Override + protected void onDestroy() { + super.onDestroy(); + // remove listener from dataset. + repo.unregisterDataSetObserver(repoObserver); + } } \ No newline at end of file diff --git a/android/KMEA/app/src/main/java/com/tavultesoft/kmea/cloud/impl/CloudCatalogDownloadCallback.java b/android/KMEA/app/src/main/java/com/tavultesoft/kmea/cloud/impl/CloudCatalogDownloadCallback.java index e9706b7c44..09c9c91e44 100644 --- a/android/KMEA/app/src/main/java/com/tavultesoft/kmea/cloud/impl/CloudCatalogDownloadCallback.java +++ b/android/KMEA/app/src/main/java/com/tavultesoft/kmea/cloud/impl/CloudCatalogDownloadCallback.java @@ -135,6 +135,7 @@ public class CloudCatalogDownloadCallback implements ICloudDownloadCallback= 1) { + appVersion = matcher.group(1); + } + // Retrieves the cloud-based keyboard catalog in Android's preferred format. String keyboardURL = String.format("%s?version=%s&device=%s&languageidtype=bcp47", - KMKeyboardDownloaderActivity.kKeymanApiBaseURL, BuildConfig.VERSION_NAME, deviceType); + KMKeyboardDownloaderActivity.kKeymanApiBaseURL, appVersion, deviceType); //cloudQueries[cloudQueryEntries++] = new CloudApiParam(ApiTarget.Keyboards, keyboardURL, JSONType.Object); return new CloudApiTypes.CloudApiParam( @@ -361,6 +375,7 @@ public class CloudRepository { String msg = context.getString(R.string.catalog_download_is_running_in_background); Toast.makeText(context, msg, Toast.LENGTH_SHORT).show(); } else { + updateIsRunning = true; String msg = context.getString(R.string.catalog_download_start_in_background); Toast.makeText(context, msg, Toast.LENGTH_SHORT).show(); CloudDownloadMgr.getInstance().executeAsDownload( @@ -382,11 +397,12 @@ public class CloudRepository { } + public void updateFinished() + { + updateIsRunning=false; + } - - - - - - + public boolean updateIsRunning() { + return updateIsRunning; + } } diff --git a/android/KMEA/app/src/main/res/layout/activity_list_with_progress_layout.xml b/android/KMEA/app/src/main/res/layout/activity_list_with_progress_layout.xml new file mode 100644 index 0000000000..278be5f8fe --- /dev/null +++ b/android/KMEA/app/src/main/res/layout/activity_list_with_progress_layout.xml @@ -0,0 +1,15 @@ + + + + + + + + + + diff --git a/android/KMEA/app/src/main/res/layout/progress_layout.xml b/android/KMEA/app/src/main/res/layout/progress_layout.xml new file mode 100644 index 0000000000..927f0e2f7c --- /dev/null +++ b/android/KMEA/app/src/main/res/layout/progress_layout.xml @@ -0,0 +1,24 @@ + + + + + + + diff --git a/android/KMEA/app/src/main/res/values/strings.xml b/android/KMEA/app/src/main/res/values/strings.xml index 8cd41cbe44..11f639cd06 100644 --- a/android/KMEA/app/src/main/res/values/strings.xml +++ b/android/KMEA/app/src/main/res/values/strings.xml @@ -66,6 +66,7 @@ Catalog update started in background.\n The catalog is still downloading; please try again in a moment!\n + The catalog is still downloading!\n Downloading keyboard started in Background The selected keyboard is already downloading; please try again in a moment! Keyboard download is finished! diff --git a/android/history.md b/android/history.md index ad8d92d7ec..0c22db30cc 100644 --- a/android/history.md +++ b/android/history.md @@ -4,14 +4,15 @@ * Start version 13.0 * New Features: * Adding a download manager to execute downloads in background and cleanup the existing implementation (#2247, #2275, #2308) + * Show spinner (without blocking UI), if user wants to add a language/keyboard and catalog download is in progress (#2313) * Improve custom package installation: Show readme.htm before starting installation process (#2286) * Update target Android SDK version to 29 (#2279) * Add linting to Debug builds and resolve lint errors (#2305) + * Sanitize the app version to `#.#.#` for the API cloud query (#2319) * Check for keyboard updates during keyman startup (#2335) * Show available keyboard updates as android system notifications (#2335) * Add update indicator icon to inform user about updates and install updates in keyman app (#2335) - ## 2019-10-30 12.0.4206 stable * Bug fix: * Disable suggestions when system keyboard entering password field (#2255) diff --git a/linux/Jenkinsfile b/linux/Jenkinsfile index 3b2adcdb1c..bf7ad63347 100644 --- a/linux/Jenkinsfile +++ b/linux/Jenkinsfile @@ -4,4 +4,7 @@ @Library('lsdev-pipeline-library') _ -keymanPackaging +keymanPackaging { + distributionsToPackage = 'xenial bionic' + arches = 'amd64 i386' +} diff --git a/linux/build/agent/dependencies.config b/linux/build/agent/dependencies.config index bf070fd82e..83c5e48313 100644 --- a/linux/build/agent/dependencies.config +++ b/linux/build/agent/dependencies.config @@ -20,10 +20,10 @@ # any=@precise.any [common] -any=git autotools-dev build-essential dh-autoreconf libibus-1.0-dev flex bison +any=git autotools-dev build-essential dh-autoreconf libibus-1.0-dev flex bison meson [xenial] any=libx11-dev -[bionix] +[bionic] any=@xenial.any diff --git a/linux/scripts/.editorconfig b/linux/scripts/.editorconfig new file mode 100644 index 0000000000..020438e0c6 --- /dev/null +++ b/linux/scripts/.editorconfig @@ -0,0 +1,4 @@ +# Editor configuration, see https://editorconfig.org +[*] +indent_style = space +indent_size = 4 diff --git a/linux/scripts/reconf.sh b/linux/scripts/reconf.sh index d783a9db35..a8b3ea127a 100755 --- a/linux/scripts/reconf.sh +++ b/linux/scripts/reconf.sh @@ -15,32 +15,37 @@ extra_projects="keyboardprocessor keyman-config" if [ "$1" != "" ]; then if [ "$1" == "keyboardprocessor" ]; then - echo "reconfiguring only keyboardprocessor" + echo "reconfiguring only keyboardprocessor" extra_projects="keyboardprocessor" autotool_projects="" elif [ ! -d "$1" ]; then echo "project $1 does not exist" exit 1 elif [ "$1" == "keyman-config" ]; then - echo "reconfiguring only keyman-config" + echo "reconfiguring only keyman-config" extra_projects="keyman-config" autotool_projects="" else - echo "reconfiguring only $1" + echo "reconfiguring only $1" autotool_projects="$1" extra_projects="" fi fi -JENKINS=${JENKINS:="no"} -oldvers=`cat VERSION` +if [ -n "$SKIPVERSION" -a -f OLDVERSION ]; then + oldvers=$(cat OLDVERSION) + newvers=$(cat VERSION) +else + JENKINS=${JENKINS:="no"} + oldvers=`cat VERSION` -. $(dirname "$0")/version.sh + . $(dirname "$0")/version.sh -version + version -echo "version: ${newvers}" -echo "${newvers}" > VERSION + echo "version: ${newvers}" + echo "${newvers}" > VERSION +fi # autoreconf the projects for proj in ${autotool_projects}; do diff --git a/web/history.md b/web/history.md index 021fd33d8f..ececec1c82 100644 --- a/web/history.md +++ b/web/history.md @@ -2,10 +2,17 @@ ## 13.0 alpha * Start version 13.0 -* Testing for upcoming patch to stable: - * Fixes issue with mnemonic keyboard handling of backspace and delete keys (#2288) - * Fix for iOS Safari's "Request Desktop Website" option disabling touch interactivity (#2283) - * Fix for keyboards using rules with the `nul` statement that replace the full context (#2284) + +## 2019-11-13 12.0.102 stable +* Fixes issue with mnemonic keyboard handling of backspace and delete keys (#2288) +* Fix for iOS Safari's "Request Desktop Website" option disabling touch interactivity (#2283) +* Fix for keyboards using rules with the `nul` statement that replace the full context (#2284) + +## 2019-10-10 12.0.101 stable +* Fixes issue with keyboards requiring special state notifications, such as the CJK picker keyboards (#2194) + +## 2019-10-07 12.0.100 stable +* Release 12.0 ## 2019-10-04 12.0.90 beta * Fixes next-layer management complications with predictive correction data computation (#2172) diff --git a/web/package-lock.json b/web/package-lock.json index 027a9b9997..1c76459b5d 100644 --- a/web/package-lock.json +++ b/web/package-lock.json @@ -2314,9 +2314,9 @@ } }, "typescript": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.2.2.tgz", - "integrity": "sha512-VCj5UiSyHBjwfYacmDuc/NOk4QQixbE+Wn7MFJuS0nRuPQbof132Pw4u53dm264O8LPc2MVsc7RJNml5szurkg==", + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.7.2.tgz", + "integrity": "sha512-ml7V7JfiN2Xwvcer+XAf2csGO1bPBdRbFCkYBczNZggrBZ9c7G3riSUeJmqEU5uOtXNPMhE3n+R4FA/3YOAWOQ==", "dev": true }, "uc.micro": { diff --git a/web/package.json b/web/package.json index fe57e635c7..c8e684ad7a 100644 --- a/web/package.json +++ b/web/package.json @@ -37,7 +37,7 @@ "karma-teamcity-reporter": "^1.1.0", "mocha": "^5.2.0", "modernizr": "^3.7.1", - "typescript": "^3.2.2" + "typescript": "^3.7.2" }, "scripts": { "tsc": "tsc", diff --git a/web/source/kmwdevice.ts b/web/source/kmwdevice.ts index e08eab92f4..209587c65e 100644 --- a/web/source/kmwdevice.ts +++ b/web/source/kmwdevice.ts @@ -1,3 +1,6 @@ +// Includes version-related functionality +/// + // The Device object definition ------------------------------------------------- namespace com.keyman { diff --git a/web/source/kmwexthtml.ts b/web/source/kmwexthtml.ts index d298110958..dede010fc0 100644 --- a/web/source/kmwexthtml.ts +++ b/web/source/kmwexthtml.ts @@ -23,8 +23,6 @@ interface Element { kmwInput: boolean, _kmwResizeHandler: (e: any) => void, - onselectstart: any, - // Used by our util.wait / util.alert system dismiss: () => void } diff --git a/web/source/osk/visualKeyboard.ts b/web/source/osk/visualKeyboard.ts index 663f1e9d71..d282ba1d4a 100644 --- a/web/source/osk/visualKeyboard.ts +++ b/web/source/osk/visualKeyboard.ts @@ -204,7 +204,7 @@ namespace com.keyman.osk { ts.fontFamily=spec['font']; } - if(typeof spec['fontsize'] == 'string' && spec['fontsize'] != 0) { + if(typeof spec['fontsize'] == 'string' && spec['fontsize'] != '') { ts.fontSize=spec['fontsize']; } @@ -564,12 +564,12 @@ namespace com.keyman.osk { // Function fields (fleshed out by kmwnative.ts and/or kmwembedded.ts) touchHold: (key: KeyElement) => void; optionKey: (e: KeyElement, keyName: string, keyDown: boolean) => void; - highlightSubKeys: (key: KeyElement, x: number, y: number) => void = this.highlightSubKeys || function(k,x,y) {}; + highlightSubKeys: (key: KeyElement, x: number, y: number) => void; showKeyTip: (key: KeyElement, on: boolean) => void; - drawPreview: (canvas: HTMLCanvasElement, w: number, h: number, edge: number) => void = this.drawPreview || function(c,w,h,e) {}; + drawPreview: (canvas: HTMLCanvasElement, w: number, h: number, edge: number) => void; createKeyTip: () => void; - addCallout: (key: KeyElement) => HTMLDivElement = this.addCallout || function(key) {return null}; - waitForFonts: (kfd,ofd) => boolean = this.waitForFonts || function(kfd,ofd){return true;}; // Default is used by embedded. + addCallout: (key: KeyElement) => HTMLDivElement; + waitForFonts: (kfd,ofd) => boolean; //#region OSK constructor and helpers @@ -581,6 +581,14 @@ namespace com.keyman.osk { * Description Generates the base visual keyboard element, prepping for attachment to KMW */ constructor(PVK, Lhelp, layout0: LayoutFormFactor, kbdBitmask: number) { + // Add handler stubs if not otherwise defined. (We can no longer in-line default-define with the declaration.) + this.highlightSubKeys = this.highlightSubKeys || function(k,x,y) {}; + this.drawPreview = this.drawPreview || function(c,w,h,e) {}; + this.addCallout = this.addCallout || function(key) {return null}; + this.waitForFonts = this.waitForFonts || function(kfd,ofd){return true;}; // Default is used by embedded. + + // Do normal constructor stuff. + let keyman = com.keyman.singleton; let util = keyman.util; @@ -617,7 +625,12 @@ namespace com.keyman.osk { } // Set flag to add default (US English) key label if specified by keyboard - layout.keyLabels = activeKeyboard && ((typeof(activeKeyboard['KDU']) != 'undefined') && activeKeyboard['KDU']); + if(typeof layout['displayUnderlying'] != 'undefined') { + layout.keyLabels = layout['displayUnderlying'] == true; // force bool + } else { + layout.keyLabels = activeKeyboard && ((typeof(activeKeyboard['KDU']) != 'undefined') && activeKeyboard['KDU']); + } + let divLayerContainer = this.deviceDependentLayout(layout, util.device.formFactor); this.ddOSK = true; @@ -2126,7 +2139,11 @@ namespace com.keyman.osk { // Cannot create an OSK if no layout defined, just return empty DIV if(layout != null) { - layout.keyLabels=((typeof(PKbd['KDU']) != 'undefined') && PKbd['KDU']); + if(typeof layout['displayUnderlying'] != 'undefined') { + layout.keyLabels = layout['displayUnderlying'] == true; // force bool + } else { + layout.keyLabels = typeof(PKbd['KDU']) != 'undefined' && PKbd['KDU']; + } } // TODO: Fix this method's link! diff --git a/web/source/utils/version.ts b/web/source/utils/version.ts index 7b64b37e53..de364dc71c 100644 --- a/web/source/utils/version.ts +++ b/web/source/utils/version.ts @@ -1,3 +1,6 @@ +// Ensure that this class contains no reference into core KMW code - it is referenced +// by components intended to be modular and possible to separate from core KMW. + namespace com.keyman.utils { // Dotted-decimal version export class Version { diff --git a/windows/src/desktop/history.md b/windows/src/desktop/history.md index 74e7f90de9..7a93845e62 100644 --- a/windows/src/desktop/history.md +++ b/windows/src/desktop/history.md @@ -3,6 +3,19 @@ ## 13.0 alpha * Start version 13.0 +## 2019-11-15 12.0.54 stable +* Bug Fix: On Screen Keyboard restored to wrong screen and position when reloading (#2330) + +## 2019-11-12 12.0.53 stable +* Bug Fix: Address instability when exiting Keyman on some systems (#2324) +* Bug Fix: Keyman was not working with Skype, Windows Search on some systems (#2324) + +## 2019-10-20 12.0.52 stable +* Upgrades from 11.0 and 12.0 were losing installed keyboards and settings (#2214) + +## 2019-10-07 12.0.50 stable +* Release 12.0 + ## 2019-10-03 12.0.42 beta * Bug Fix: Additional shutdown issues that sporadically occurred (#2157) * Fix issues starting debug logging for non-administrative users (#2153) diff --git a/windows/src/developer/TIKE/compile/MergeKeyboardInfo.pas b/windows/src/developer/TIKE/compile/MergeKeyboardInfo.pas index 4cefbe964c..86f1fe6501 100644 --- a/windows/src/developer/TIKE/compile/MergeKeyboardInfo.pas +++ b/windows/src/developer/TIKE/compile/MergeKeyboardInfo.pas @@ -327,9 +327,11 @@ begin SetLength(FPackageJSFileInfos, Length(FPackageJSFileInfos)+1); FPackageJSFileInfos[High(FPackageJSFileInfos)].Filename := Zip.FileNames[j]; - // For now, apply JS keyboard to all web and mobile targets + // Apply JS keyboard only to mobile targets, because web is not supported + // in a package. If a package does not support mobile, it should not include + // the .js. // Not using GetKeyboardInfo because that only handles kmx files - FPackageJSFileInfos[High(FPackageJSFileInfos)].Info.Targets := 'web mobile'; + FPackageJSFileInfos[High(FPackageJSFileInfos)].Info.Targets := 'mobile'; end; end; end; @@ -976,8 +978,6 @@ begin AddNewPair('windows', 'full'); AddNewPair('macos', 'full'); AddNewPair('linux', 'full'); - AddNewPair('desktopWeb', 'full'); - AddNewPair('mobileWeb', 'full'); AddNewPair('android', 'full'); AddNewPair('ios', 'full'); end @@ -1008,11 +1008,6 @@ begin // FPackageKMXFileInfos can contain target information for web/mobile targets. // This is a current limitation of FPackageJSFileInfos if there's no kmx files - if target = ktWeb then - begin - AddNewPair('desktopWeb', 'full'); - AddNewPair('mobileWeb', 'full'); - end; if (target = ktMobile) then begin AddNewPair('android', 'full'); @@ -1035,11 +1030,6 @@ begin targets := StringToKeymanTargets(keyboardFile.Info.Targets); for target in targets do begin - if (target = ktWeb) then - begin - AddNewPair('desktopWeb', 'full'); - AddNewPair('mobileWeb', 'full'); - end; if (target = ktMobile) then begin AddNewPair('android', 'full'); @@ -1056,16 +1046,17 @@ begin end; end; - // Handle JS file not in kmp - if FJsFile <> '' then + // Handle JS file not in kmp. Because it is isolated, we cannot detect + // whether it supports mobile vs desktop web because that is not included + // in the .js. So, for now we assume both. + // + // We no longer assume that the presence of a .js means support for + // native mobile apps. These apps now work on the basis of having a + // .kmp file available + if (FJsFile <> '') then begin AddNewPair('desktopWeb', 'full'); AddNewPair('mobileWeb', 'full'); - - // TODO: Don't add Android and iOS when we complete the addition of all .js keyboards - // to packages in the repository (including legacy keyboards) - AddNewPair('android', 'full'); - AddNewPair('ios', 'full'); end; json.AddPair('platformSupport', v); diff --git a/windows/src/developer/TIKE/main/Keyman.Developer.UI.UframeCEFHost.dfm b/windows/src/developer/TIKE/main/Keyman.Developer.UI.UframeCEFHost.dfm index bdbacd30c4..b326cf9e21 100644 --- a/windows/src/developer/TIKE/main/Keyman.Developer.UI.UframeCEFHost.dfm +++ b/windows/src/developer/TIKE/main/Keyman.Developer.UI.UframeCEFHost.dfm @@ -34,7 +34,6 @@ inherited frameCEFHost: TframeCEFHost Top = 208 end object cef: TChromium - OnWidgetCompMsg = cefWidgetCompMsg OnLoadEnd = cefLoadEnd OnSetFocus = cefSetFocus OnRunContextMenu = cefRunContextMenu diff --git a/windows/src/developer/TIKE/main/Keyman.Developer.UI.UframeCEFHost.pas b/windows/src/developer/TIKE/main/Keyman.Developer.UI.UframeCEFHost.pas index 818205d189..63d0138cfb 100644 --- a/windows/src/developer/TIKE/main/Keyman.Developer.UI.UframeCEFHost.pas +++ b/windows/src/developer/TIKE/main/Keyman.Developer.UI.UframeCEFHost.pas @@ -35,7 +35,6 @@ const CEF_AFTERCREATE = WM_USER + 302; CEF_SHOW = WM_USER + 303; CEF_LOADEND = WM_USER + 304; - CEF_SETFOCUS = WM_USER + 305; CEF_KEYEVENT = WM_USER + 306; CEF_BEFOREBROWSE = WM_USER + 307; CEF_CONSOLEMESSAGE = WM_USER + 308; @@ -106,7 +105,6 @@ type var settings: TCefBrowserSettings; var noJavascriptAccess: Boolean; var Result: Boolean); - procedure cefWidgetCompMsg(var aMessage: TMessage; var aHandled: Boolean); procedure cefSetFocus(Sender: TObject; const browser: ICefBrowser; source: TCefFocusSource; out Result: Boolean); private @@ -134,7 +132,6 @@ type procedure Handle_CEF_AFTERCREATE(var Message: TMessage); procedure Handle_CEF_SHOW(var message: TMessage); procedure Handle_CEF_LOADEND(var message: TMessage); - procedure Handle_CEF_SETFOCUS(var message: TMessage); procedure Handle_CEF_KEYEVENT(var message: TMessage); procedure Handle_CEF_BEFOREBROWSE(var message: TMessage); procedure Handle_CEF_CONSOLEMESSAGE(var message: TMessage); @@ -268,14 +265,6 @@ begin CreateBrowser; end; -procedure TframeCEFHost.cefWidgetCompMsg(var aMessage: TMessage; - var aHandled: Boolean); -begin - AssertCefThread; - if aMessage.Msg = WM_SETFOCUS then - PostMessage(FCallbackWnd, CEF_SETFOCUS, 0, 0); -end; - procedure TframeCEFHost.CreateBrowser; begin AssertVclThread; @@ -308,9 +297,11 @@ end; procedure TframeCEFHost.SetFocus; begin AssertVclThread; - inherited; - if not FIsClosing and cefwp.CanFocus then - cefwp.SetFocus; + if not FIsClosing and cefwp.CanFocus and Assigned(cef) then + begin + GetParentForm(Self).ActiveControl := Self; + cef.SetFocus(True); + end; end; procedure TframeCEFHost.CallbackWndProc(var Message: TMessage); @@ -322,7 +313,6 @@ begin CEF_AFTERCREATE: Handle_CEF_AFTERCREATE(Message); CEF_SHOW: Handle_CEF_SHOW(Message); CEF_LOADEND: Handle_CEF_LOADEND(Message); - CEF_SETFOCUS: Handle_CEF_SETFOCUS(Message); CEF_KEYEVENT: Handle_CEF_KEYEVENT(Message); CEF_BEFOREBROWSE: Handle_CEF_BEFOREBROWSE(Message); CEF_CONSOLEMESSAGE: Handle_CEF_CONSOLEMESSAGE(Message); @@ -534,13 +524,6 @@ begin FOnLoadEnd(Self); end; -procedure TframeCEFHost.Handle_CEF_SETFOCUS(var message: TMessage); -begin - AssertVclThread; - if Assigned(cefwp) and cefwp.Visible and cefwp.CanFocus then - GetParentForm(cefwp).ActiveControl := cefwp; -end; - procedure TframeCEFHost.cefPreKeyEvent(Sender: TObject; const browser: ICefBrowser; const event: PCefKeyEvent; osEvent: PMsg; out isKeyboardShortcut, Result: Boolean); @@ -614,7 +597,7 @@ end; procedure TframeCEFHost.cefSetFocus(Sender: TObject; const browser: ICefBrowser; source: TCefFocusSource; out Result: Boolean); begin - Result := source <> FOCUS_SOURCE_NAVIGATION; + Result := source = FOCUS_SOURCE_NAVIGATION; end; procedure TframeCEFHost.WMEnterMenuLoop(var aMessage: TMessage); diff --git a/windows/src/developer/TIKE/main/UframeTextEditor.pas b/windows/src/developer/TIKE/main/UframeTextEditor.pas index 5b97d4b8f3..fca4d88760 100644 --- a/windows/src/developer/TIKE/main/UframeTextEditor.pas +++ b/windows/src/developer/TIKE/main/UframeTextEditor.pas @@ -656,7 +656,6 @@ end; procedure TframeTextEditor.SetFocus; begin - inherited; cef.SetFocus; end; diff --git a/windows/src/developer/history.md b/windows/src/developer/history.md index 380d0457d8..69c69d909a 100644 --- a/windows/src/developer/history.md +++ b/windows/src/developer/history.md @@ -3,6 +3,12 @@ ## 13.0 alpha * Start version 13.0 +## 2019-11-15 12.0.54 stable +* Bug Fix: Text editor and other controls did not receive focus correctly (#2331) + +## 2019-10-07 12.0.50 stable +* Release 12.0 + ## 2019-10-05 12.0.45 beta * Touch Layout Editor: Make default padding in touch layout editor match default padding in KeymanWeb. (#2170) diff --git a/windows/src/engine/keyman/UfrmKeyman7Main.pas b/windows/src/engine/keyman/UfrmKeyman7Main.pas index 8c198f699f..c37b73fb95 100644 --- a/windows/src/engine/keyman/UfrmKeyman7Main.pas +++ b/windows/src/engine/keyman/UfrmKeyman7Main.pas @@ -442,6 +442,10 @@ begin begin olestrm := TOLEStream.Create(istrm); try + // In some situations, launching the app multiple times rapidly can + // cause the icon to be loaded multiple times. Make sure we reset the + // stream position before we try and read. + olestrm.Position := 0; Application.Icon.LoadFromStream(olestrm); finally olestrm.Free; diff --git a/windows/src/engine/keyman/keyman.dpr b/windows/src/engine/keyman/keyman.dpr index b2352c3a7e..2f9bed1197 100644 --- a/windows/src/engine/keyman/keyman.dpr +++ b/windows/src/engine/keyman/keyman.dpr @@ -1,7 +1,5 @@ program keyman; - - uses Forms, Dialogs, @@ -148,6 +146,11 @@ uses {$R VERSION.RES} {$R MANIFEST.RES} +// +// PEOPTFLAGS $140 turns on Data Execution Prevention +// +{$SETPEOPTFLAGS $140} + begin //InitTntEnvironment; //ShowMessage('Start'); diff --git a/windows/src/engine/keyman/viskbd/UfrmVisualKeyboard.pas b/windows/src/engine/keyman/viskbd/UfrmVisualKeyboard.pas index 9417d4597c..5205cc0b54 100644 --- a/windows/src/engine/keyman/viskbd/UfrmVisualKeyboard.pas +++ b/windows/src/engine/keyman/viskbd/UfrmVisualKeyboard.pas @@ -280,6 +280,8 @@ type implementation uses + System.Types, + CommCtrl, GraphUtil, KeymanHints, @@ -303,7 +305,7 @@ uses VistaMessages, MessageIdentifierConsts, messageidentifiers, - BitmapIPicture, Types; + BitmapIPicture; {$R *.DFM} @@ -1331,12 +1333,62 @@ begin end; procedure TfrmVisualKeyboard.LoadSettings; - procedure MoveBounds(R: TRect); + function FitRectInBounds(R, BR: TRect): TRect; begin - if (R.Left < R.Right) and (R.Top < R.Bottom) and (R.Left >= 0) and (R.Top >= 0) and - (R.Bottom <= Screen.Height) and (R.Right <= Screen.Width) then - BoundsRect := R; + if R.Width > BR.Width then + R.Width := BR.Width; + + if R.Height > BR.Height then + R.Height := BR.Height; + + if R.Left < BR.Left then + R.Offset(BR.Left-R.Left, 0); + + if R.Right > BR.Right then + R.Offset(BR.Right-R.Right, 0); + + if R.Top < BR.Top then + R.Offset(0, BR.Top-R.Top); + + if R.Bottom > BR.Bottom then + R.Offset(0, BR.Bottom-R.Bottom); + + Result := R; end; + + procedure MoveBounds(R: TRect); + var + area, i: Integer; + m: Integer; + BR, RI: TRect; + begin + // Adjust the rectangle to ensure TopLeft <= BottomRight + R.NormalizeRect; + + // Move the rect onto the screen (e.g. when monitor is disconnected, + // we don't want to show the OSK off the screen). It is valid for the window + // rect to go negative, if for example primary monitor is not left-most. + + // If the OSK is partially on-screen, move it onto the monitor where it has + // the most real-estate. + m := 0; area := 0; + for i := 0 to Screen.MonitorCount - 1 do + begin + if System.Types.IntersectRect(RI, R, Screen.Monitors[i].BoundsRect) then + begin + if RI.Width * RI.Height > area then + begin + area := RI.Width * RI.Height; + m := i; + end; + end; + end; + + BR := Screen.Monitors[m].WorkareaRect; + + Self.BoundsRect := FitRectInBounds(R, BR); + end; + procedure MoveDefault; begin SetBounds(Screen.WorkAreaRect.Right - Width, Screen.WorkAreaRect.Bottom - Height, Width, Height); diff --git a/windows/src/engine/keyman32/Keyman32.cpp b/windows/src/engine/keyman32/Keyman32.cpp index 9f4948f35b..f146f3eae0 100644 --- a/windows/src/engine/keyman32/Keyman32.cpp +++ b/windows/src/engine/keyman32/Keyman32.cpp @@ -157,11 +157,13 @@ BOOL __stdcall DllMain(HINSTANCE hinstDll, DWORD fdwReason, LPVOID reserved) case DLL_PROCESS_ATTACH: //if(!TestDebugProcess()) return FALSE; //if(!ShouldAttachToProcess()) return FALSE; + OutputThreadDebugString("DLL_PROCESS_ATTACH"); if(!Globals_InitProcess()) return FALSE; break; case DLL_PROCESS_DETACH: //if(!TestDebugProcess()) return FALSE; if (reserved == NULL) { + OutputThreadDebugString("DLL_PROCESS_DETACH not terminating"); // If reserved == NULL, that means the library is being unloaded, but // the process is not terminating. // @@ -180,15 +182,20 @@ BOOL __stdcall DllMain(HINSTANCE hinstDll, DWORD fdwReason, LPVOID reserved) // CloseTSF from here. This needs further investigation... UninitialiseProcess(FALSE); Globals_UninitProcess(); + } + else { + OutputThreadDebugString("DLL_PROCESS_DETACH terminating"); } break; case DLL_THREAD_ATTACH: //if(!TestDebugProcess()) return FALSE; + OutputThreadDebugString("DLL_THREAD_ATTACH"); Globals_InitThread(); break; case DLL_THREAD_DETACH: //if(!TestDebugProcess()) return FALSE; - UninitialiseProcess(FALSE); + OutputThreadDebugString("DLL_THREAD_DETACH"); + UninitialiseProcess(FALSE); Globals_UninitThread(); break; } @@ -214,8 +221,13 @@ BOOL UninitialiseProcess(BOOL Lock) if(_td->IndexStack) delete _td->IndexStack; _td->IndexStack = NULL; - } + if (_td->miniContext) delete _td->miniContext; + _td->miniContext = NULL; + + if (_td->msgbuf) delete _td->msgbuf; + _td->msgbuf = NULL; + } return TRUE; } @@ -512,6 +524,10 @@ extern "C" BOOL _declspec(dllexport) WINAPI Keyman_Exit(void) return FALSE; } +#ifndef _WIN64 + Hotkeys::Unload(); +#endif + *Globals::InitialisingThread() = 0; BOOL RetVal = TRUE; @@ -801,6 +817,7 @@ void LoadBaseLayoutSettings() { // I4552 // I4583 void RefreshKeyboards(BOOL Initialising) { + OutputThreadDebugString("RefreshKeyboards"); char sz[_MAX_FNAME]; char oldname[_MAX_FNAME]; RegistryReadOnly *reg2; @@ -828,7 +845,7 @@ void RefreshKeyboards(BOOL Initialising) _td->ActiveKeymanID = KEYMANID_NONKEYMAN; } - ReleaseKeyboards(TRUE); + ReleaseKeyboards(TRUE); /* Read the "keyboard off hotkey", simulate Alt+Gr, Hotkeys-Toggle flags */ @@ -938,13 +955,14 @@ void RefreshKeyboards(BOOL Initialising) _td->FInRefreshKeyboards = FALSE; } - void ReleaseKeyboards(BOOL Lock) { + OutputThreadDebugString("ReleaseKeyboards"); PKEYMAN64THREADDATA _td = ThreadGlobals(); - if(!_td || _td->lpKeyboards) return; + if(!_td || !_td->lpKeyboards) return; - if(Lock) if(_td->lpActiveKeyboard && !_td->ForceFileName[0]) DeactivateDLLs(_td->lpActiveKeyboard); + + if(Lock) if(_td->lpActiveKeyboard && !_td->ForceFileName[0]) DeactivateDLLs(_td->lpActiveKeyboard); for(int i = 0; i < _td->nKeyboards; i++) { diff --git a/windows/src/engine/keyman32/hookutils.cpp b/windows/src/engine/keyman32/hookutils.cpp index 15c24283b9..6ccccae719 100644 --- a/windows/src/engine/keyman32/hookutils.cpp +++ b/windows/src/engine/keyman32/hookutils.cpp @@ -15,45 +15,48 @@ typedef BOOL IN CONST PMINIDUMP_CALLBACK_INFORMATION CallbackParam OPTIONAL ); +DWORD ExceptionMessage(LPSTR Proc, LPEXCEPTION_POINTERS ep) { +#ifndef _DEBUG + UNREFERENCED_PARAMETER(Proc); +#endif -DWORD ExceptionMessage(LPSTR Proc, LPEXCEPTION_POINTERS ep) -{ MINIDUMP_EXCEPTION_INFORMATION mei; char filename[MAX_PATH], temppath[MAX_PATH]; - if(GetTempPath(MAX_PATH, temppath) == 0 || - GetTempFileName(temppath, "kmc", 0, filename) == 0) - SendDebugMessageFormat(0, sdmGlobal, 0, "Minidump failed to generate temp file name"); - else - { + if (GetTempPath(MAX_PATH, temppath) == 0 || + GetTempFileName(temppath, "kmc", 0, filename) == 0) { + OutputThreadDebugString("Minidump failed to generate temp file name\n"); + } + else { HANDLE hFile = CreateFile(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL); - if(!hFile) - SendDebugMessageFormat(0, sdmGlobal, 0, "Minidump failed to create file %s", filename); - else - { + if (!hFile) { + OutputThreadDebugString("Minidump failed to create file "); + OutputThreadDebugString(filename); + } + else { mei.ClientPointers = TRUE; mei.ExceptionPointers = ep; mei.ThreadId = GetCurrentThreadId(); HMODULE hDbgHelp = LoadLibrary("dbghelp.dll"); - if(!hDbgHelp) - SendDebugMessage(0, sdmGlobal, 0, "dbghelp.dll not available"); - else - { + if (!hDbgHelp) { + OutputThreadDebugString("dbghelp.dll not available"); + } + else { PMiniDumpWriteDump mdwd = (PMiniDumpWriteDump) GetProcAddress(hDbgHelp, "MiniDumpWriteDump"); - if(!mdwd) - SendDebugMessage(0, sdmGlobal, 0, "MiniDumpWriteDump not available"); - else - { + if (!mdwd) { + OutputThreadDebugString("MiniDumpWriteDump not available"); + } + else { if (!(*mdwd)(GetCurrentProcess(), GetCurrentProcessId(), hFile, - (MINIDUMP_TYPE)(MiniDumpWithDataSegs | MiniDumpWithHandleData), - &mei, NULL, NULL)) + (MINIDUMP_TYPE)(MiniDumpWithDataSegs | MiniDumpWithHandleData), + &mei, NULL, NULL)) { DebugLastError("MiniDumpWriteDump"); - else - { - SendDebugMessageFormat(0, sdmGlobal, 0, "Minidump written to %s", filename); + } + else { + OutputThreadDebugString("Minidump written to "); + OutputThreadDebugString(filename); HKEY hkey; if(RegCreateKeyEx(HKEY_CURRENT_USER, REGSZ_KeymanEngineDiag, 0, NULL, 0, KEY_ALL_ACCESS, - NULL, &hkey, NULL) == ERROR_SUCCESS) - { + NULL, &hkey, NULL) == ERROR_SUCCESS) { DWORD v = 0; RegSetValueEx(hkey, filename, 0, REG_DWORD, (PBYTE)&v, sizeof(DWORD)); RegCloseKey(hkey); @@ -66,23 +69,26 @@ DWORD ExceptionMessage(LPSTR Proc, LPEXCEPTION_POINTERS ep) } } - if(!ep || !ep->ExceptionRecord) - { - SendDebugMessageFormat(0, sdmGlobal, 0, "CAUGHT UNKNOWN EXCEPTION"); + if(!ep || !ep->ExceptionRecord) { + OutputThreadDebugString("CAUGHT UNKNOWN EXCEPTION"); return EXCEPTION_CONTINUE_SEARCH; } LPEXCEPTION_RECORD er = ep->ExceptionRecord; - while(er != NULL) - { - if(er->ExceptionCode == EXCEPTION_ACCESS_VIOLATION) - SendDebugMessageFormat(0, sdmGlobal, 0, "CAUGHT EXCEPTION %d (ACCESS VIOLATION) IN %s AT %x; attempted to %s %x", - er->ExceptionCode, Proc, er->ExceptionAddress, - er->ExceptionInformation[0] == 0 ? "read from" : "write to", - er->ExceptionInformation[1]); - else - SendDebugMessageFormat(0, sdmGlobal, 0, "CAUGHT EXCEPTION %d IN %s AT %x", - er->ExceptionCode, Proc, er->ExceptionAddress); + while(er != NULL) { + if (er->ExceptionCode == EXCEPTION_ACCESS_VIOLATION) { + OutputThreadDebugString("EXCEPTION_ACCESS_VIOLATION in "); + OutputThreadDebugString(Proc); + /*SendDebugMessageFormat(0, sdmGlobal, 0, "CAUGHT EXCEPTION %d (ACCESS VIOLATION) IN %s AT %x; attempted to %s %x", + er->ExceptionCode, Proc, er->ExceptionAddress, + er->ExceptionInformation[0] == 0 ? "read from" : "write to", + er->ExceptionInformation[1]);*/ + } + else { + OutputThreadDebugString("CAUGHT EXCEPTION"); + /*SendDebugMessageFormat(0, sdmGlobal, 0, "CAUGHT EXCEPTION %d IN %s AT %x", + er->ExceptionCode, Proc, er->ExceptionAddress);*/ + } er = er->ExceptionRecord; } diff --git a/windows/src/engine/keyman32/hotkeys.cpp b/windows/src/engine/keyman32/hotkeys.cpp index a3363c49cc..cead296f8d 100644 --- a/windows/src/engine/keyman32/hotkeys.cpp +++ b/windows/src/engine/keyman32/hotkeys.cpp @@ -45,6 +45,18 @@ Hotkeys *Hotkeys::Instance() { // I4326 return g_Hotkeys; } +void Hotkeys::Unload() { + if (GetCurrentThreadId() != Globals::get_InitialisingThread()) { + OutputThreadDebugString("Unexpected: no other thread should be attempting to unload hotkeys"); + return; + } + + if (g_Hotkeys != NULL) { + delete g_Hotkeys; + g_Hotkeys = NULL; + } +} + void Hotkeys::Reload() { // I4326 // I4390 Hotkeys *hotkeys = Hotkeys::Instance(); // I4641 if(hotkeys == NULL) { diff --git a/windows/src/engine/keyman32/hotkeys.h b/windows/src/engine/keyman32/hotkeys.h index b011d20547..863be3636c 100644 --- a/windows/src/engine/keyman32/hotkeys.h +++ b/windows/src/engine/keyman32/hotkeys.h @@ -43,4 +43,5 @@ public: Hotkey *GetHotkey(DWORD hotkey); static void Reload(); // I4326 static Hotkeys *Instance(); // I4326 -}; + static void Unload(); + }; diff --git a/windows/src/engine/keyman32/K32_DBG.CPP b/windows/src/engine/keyman32/k32_dbg.cpp similarity index 98% rename from windows/src/engine/keyman32/K32_DBG.CPP rename to windows/src/engine/keyman32/k32_dbg.cpp index 7fcc025762..f78eb737fa 100644 --- a/windows/src/engine/keyman32/K32_DBG.CPP +++ b/windows/src/engine/keyman32/k32_dbg.cpp @@ -304,4 +304,12 @@ char *Debug_UnicodeString(PWSTR s, int x) { } //WideCharToMultiByte(CP_ACP, 0, buf, -1, bufout, 128, NULL, NULL); return bufout[x]; -} \ No newline at end of file +} + +#ifdef _DEBUG +void _OutputThreadDebugString(char *s) { + char buf[256]; + sprintf_s(buf, "[%d]: %s\n", GetCurrentThreadId(), s); + OutputDebugString(buf); +} +#endif diff --git a/windows/src/engine/keyman32/k32_globals.cpp b/windows/src/engine/keyman32/k32_globals.cpp index af59056a15..2a08e6c293 100644 --- a/windows/src/engine/keyman32/k32_globals.cpp +++ b/windows/src/engine/keyman32/k32_globals.cpp @@ -138,7 +138,11 @@ PKEYMAN64THREADDATA Globals_InitThread() void Globals_UninitThread() { - if(!Globals_ProcessInitialised()) return; + OutputThreadDebugString("Globals_UninitThread"); + if (!Globals_ProcessInitialised()) { + OutputThreadDebugString("Globals_UninitThread aborted without cleanup"); + return; + } CloseTSF(); // I3933 @@ -185,6 +189,7 @@ void Globals_UninitProcess() TlsFree(dwTlsIndex); dwTlsIndex = TLS_OUT_OF_INDEXES; LeaveCriticalSection(&csGlobals); + DeleteCriticalSection(&csGlobals); } PKEYMAN64THREADDATA ThreadGlobals() diff --git a/windows/src/engine/keyman32/k32_lowlevelkeyboardhook.cpp b/windows/src/engine/keyman32/k32_lowlevelkeyboardhook.cpp index b50e0486e4..fee747f486 100644 --- a/windows/src/engine/keyman32/k32_lowlevelkeyboardhook.cpp +++ b/windows/src/engine/keyman32/k32_lowlevelkeyboardhook.cpp @@ -53,7 +53,7 @@ LRESULT CALLBACK kmnLowLevelKeyboardProc( __except(ExceptionMessage("kmnLowLevelKeyboardProc", GetExceptionInformation())) { } #endif - return res; + return res; } BOOL KeyLanguageSwitchPress(WPARAM wParam, BOOL extended, BOOL isUp, DWORD ShiftState); diff --git a/windows/src/engine/keyman32/keyboardoptions.cpp b/windows/src/engine/keyman32/keyboardoptions.cpp index 2e907c6460..1e0e0a8511 100644 --- a/windows/src/engine/keyman32/keyboardoptions.cpp +++ b/windows/src/engine/keyman32/keyboardoptions.cpp @@ -41,9 +41,10 @@ void LoadSharedKeyboardOptions(LPINTKEYBOARDINFO kp) void FreeKeyboardOptions(LPINTKEYBOARDINFO kp) { - assert(kp != NULL); - assert(kp->Keyboard != NULL); - assert(kp->KeyboardOptions != NULL); + // This is a cleanup routine; we don't want to precondition all calls to it + // so we do not assert + if (kp == NULL || kp->Keyboard == NULL || kp->KeyboardOptions == NULL) + return; for(DWORD i = 0; i < kp->Keyboard->cxStoreArray; i++) if(kp->KeyboardOptions[i].Value) diff --git a/windows/src/engine/keyman32/kmhook_callwndproc.cpp b/windows/src/engine/keyman32/kmhook_callwndproc.cpp index 4b72ab7bd6..7178ed5fea 100644 --- a/windows/src/engine/keyman32/kmhook_callwndproc.cpp +++ b/windows/src/engine/keyman32/kmhook_callwndproc.cpp @@ -66,6 +66,7 @@ LRESULT _kmnCallWndProc(int nCode, WPARAM wParam, LPARAM lParam); LRESULT CALLBACK kmnCallWndProc(int nCode, WPARAM wParam, LPARAM lParam) { LRESULT res = 0; + #ifdef _DEBUG_EXCEPTION res = _kmnCallWndProc(nCode,wParam,lParam); #else @@ -77,7 +78,7 @@ LRESULT CALLBACK kmnCallWndProc(int nCode, WPARAM wParam, LPARAM lParam) { } #endif - return res; + return res; } // I3617 BOOL IsSysTrayWindow(HWND hwnd); diff --git a/windows/src/engine/keyman32/serialkeyeventclient.cpp b/windows/src/engine/keyman32/serialkeyeventclient.cpp index 3719b9409a..722903e6c3 100644 --- a/windows/src/engine/keyman32/serialkeyeventclient.cpp +++ b/windows/src/engine/keyman32/serialkeyeventclient.cpp @@ -149,6 +149,7 @@ public: }; void ISerialKeyEventClient::Startup() { + OutputThreadDebugString("ISerialKeyEventClient::Startup"); PKEYMAN64THREADDATA _td = ThreadGlobals(); if (_td) { _td->pSerialKeyEventClient = new SerialKeyEventClient(); @@ -156,6 +157,7 @@ void ISerialKeyEventClient::Startup() { } void ISerialKeyEventClient::Shutdown() { + OutputThreadDebugString("ISerialKeyEventClient::Shutdown"); PKEYMAN64THREADDATA _td = ThreadGlobals(); if (_td && _td->pSerialKeyEventClient) { delete _td->pSerialKeyEventClient; diff --git a/windows/src/global/delphi/general/klog.pas b/windows/src/global/delphi/general/klog.pas index 8f8198bf31..0915696743 100644 --- a/windows/src/global/delphi/general/klog.pas +++ b/windows/src/global/delphi/general/klog.pas @@ -133,7 +133,7 @@ begin end; writeln(FLogFile, Format('%12.12d ', [GetTickCount()])+FormatDateTime('yyyy-mm-dd hh:nn:ss.zzz', Now) + ': ' + StringOfChar(' ', FMethodStack.Count*2) + msg); flush(FLogFile); - OutputDebugString(PChar(msg)); + OutputDebugString(PChar('KLog:' + msg + #13#10)); {$ENDIF} end; diff --git a/windows/src/global/inc/keyman64.h b/windows/src/global/inc/keyman64.h index ca8961501e..65e17b6db9 100644 --- a/windows/src/global/inc/keyman64.h +++ b/windows/src/global/inc/keyman64.h @@ -347,6 +347,13 @@ BOOL ShouldDebug_1(); // TSDMState state); #endif +#ifdef _DEBUG +#define OutputThreadDebugString(s) _OutputThreadDebugString(s) +void _OutputThreadDebugString(char *s); +#else +#define OutputThreadDebugString(s) +#endif + /* Keyboard selection functions */ void HandleRefresh(int code, LONG tag);