mirror of
https://github.com/keymanapp/keyman.git
synced 2026-08-05 08:25:32 +00:00
Merge branch 'master' into android-update-catalog-on-startup
This commit is contained in:
commit
20bc90e7b2
41 changed files with 461 additions and 149 deletions
12
.editorconfig
Normal file
12
.editorconfig
Normal file
|
|
@ -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
|
||||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
@ -135,6 +135,7 @@ public class CloudCatalogDownloadCallback implements ICloudDownloadCallback<Data
|
|||
// Only empty if no queries returned data - we're offline.
|
||||
if (jsonTuple.isEmpty()) {
|
||||
this.failure.run(); // Signal failure to download to our failure callback.
|
||||
CloudRepository.shared.updateFinished();
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -245,6 +246,9 @@ public class CloudCatalogDownloadCallback implements ICloudDownloadCallback<Data
|
|||
ensureInitCloudReturn(aContext,aDataSet,aCloudResult);
|
||||
|
||||
processCloudReturns(aDataSet, aCloudResult,true);
|
||||
|
||||
CloudRepository.shared.updateFinished();
|
||||
aDataSet.notifyDataSetChanged();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -28,6 +28,8 @@ import java.util.ArrayList;
|
|||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.regex.Matcher;
|
||||
|
||||
public class CloudRepository {
|
||||
static public final CloudRepository shared = new CloudRepository();
|
||||
|
|
@ -42,6 +44,9 @@ public class CloudRepository {
|
|||
// DEBUG: Never allow these to be `true` in production.
|
||||
private static final boolean DEBUG_DISABLE_CACHE = false;
|
||||
|
||||
private boolean updateIsRunning = false;
|
||||
|
||||
|
||||
|
||||
private CloudRepository() {
|
||||
// Tracks the time of the most recent cache. We start at null to indicate that we haven't
|
||||
|
|
@ -123,9 +128,18 @@ public class CloudRepository {
|
|||
{
|
||||
String deviceType = CloudDataJsonUtil.getDeviceTypeForCloudQuery(aContext);
|
||||
|
||||
// Sanitize appVersion to #.#.# to match the API spec
|
||||
// Regex needs to match the entire string
|
||||
String appVersion = BuildConfig.VERSION_NAME;
|
||||
Pattern pattern = Pattern.compile("^(\\d+\\.\\d+\\.\\d+).*");
|
||||
Matcher matcher = pattern.matcher(appVersion);
|
||||
if (matcher.matches() && matcher.groupCount() >= 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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,15 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
|
||||
<include layout="@layout/list_toolbar" />
|
||||
|
||||
<include layout="@layout/progress_layout" />
|
||||
|
||||
<include layout="@layout/list_layout" />
|
||||
|
||||
</LinearLayout>
|
||||
24
android/KMEA/app/src/main/res/layout/progress_layout.xml
Normal file
24
android/KMEA/app/src/main/res/layout/progress_layout.xml
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/progress"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_marginTop="@dimen/fab_margin"
|
||||
>
|
||||
|
||||
<ProgressBar
|
||||
android:id="@+id/progressbar"
|
||||
style="?android:attr/progressBarStyleLarge"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:visibility="visible"/>
|
||||
<TextView
|
||||
android:id="@+id/progressbarmessage"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/progress_message_catalog_download_is_running"
|
||||
android:layout_centerInParent="true"
|
||||
android:layout_below="@+id/progressbar" />
|
||||
|
||||
</RelativeLayout>
|
||||
|
|
@ -66,6 +66,7 @@
|
|||
<!-- Background download messages-->
|
||||
<string name="catalog_download_start_in_background" translatable="false">Catalog update started in background.\n</string>
|
||||
<string name="catalog_download_is_running_in_background" translatable="false">The catalog is still downloading; please try again in a moment!\n</string>
|
||||
<string name="progress_message_catalog_download_is_running" translatable="false">The catalog is still downloading!\n</string>
|
||||
<string name="keyboard_download_start_in_background" translatable="false">Downloading keyboard started in Background</string>
|
||||
<string name="keyboard_download_is_running_in_background" translatable="false">The selected keyboard is already downloading; please try again in a moment!</string>
|
||||
<string name="keyboard_download_finished" translatable="false">Keyboard download is finished!</string>
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
5
linux/Jenkinsfile
vendored
5
linux/Jenkinsfile
vendored
|
|
@ -4,4 +4,7 @@
|
|||
|
||||
@Library('lsdev-pipeline-library') _
|
||||
|
||||
keymanPackaging
|
||||
keymanPackaging {
|
||||
distributionsToPackage = 'xenial bionic'
|
||||
arches = 'amd64 i386'
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
4
linux/scripts/.editorconfig
Normal file
4
linux/scripts/.editorconfig
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
# Editor configuration, see https://editorconfig.org
|
||||
[*]
|
||||
indent_style = space
|
||||
indent_size = 4
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
6
web/package-lock.json
generated
6
web/package-lock.json
generated
|
|
@ -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": {
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -1,3 +1,6 @@
|
|||
// Includes version-related functionality
|
||||
///<reference path="utils/version.ts"/>
|
||||
|
||||
// The Device object definition -------------------------------------------------
|
||||
|
||||
namespace com.keyman {
|
||||
|
|
|
|||
|
|
@ -23,8 +23,6 @@ interface Element {
|
|||
kmwInput: boolean,
|
||||
_kmwResizeHandler: (e: any) => void,
|
||||
|
||||
onselectstart: any,
|
||||
|
||||
// Used by our util.wait / util.alert system
|
||||
dismiss: () => void
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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!
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -34,7 +34,6 @@ inherited frameCEFHost: TframeCEFHost
|
|||
Top = 208
|
||||
end
|
||||
object cef: TChromium
|
||||
OnWidgetCompMsg = cefWidgetCompMsg
|
||||
OnLoadEnd = cefLoadEnd
|
||||
OnSetFocus = cefSetFocus
|
||||
OnRunContextMenu = cefRunContextMenu
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -656,7 +656,6 @@ end;
|
|||
|
||||
procedure TframeTextEditor.SetFocus;
|
||||
begin
|
||||
inherited;
|
||||
cef.SetFocus;
|
||||
end;
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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');
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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++)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -43,4 +43,5 @@ public:
|
|||
Hotkey *GetHotkey(DWORD hotkey);
|
||||
static void Reload(); // I4326
|
||||
static Hotkeys *Instance(); // I4326
|
||||
};
|
||||
static void Unload();
|
||||
};
|
||||
|
|
|
|||
|
|
@ -304,4 +304,12 @@ char *Debug_UnicodeString(PWSTR s, int x) {
|
|||
}
|
||||
//WideCharToMultiByte(CP_ACP, 0, buf, -1, bufout, 128, NULL, NULL);
|
||||
return bufout[x];
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef _DEBUG
|
||||
void _OutputThreadDebugString(char *s) {
|
||||
char buf[256];
|
||||
sprintf_s(buf, "[%d]: %s\n", GetCurrentThreadId(), s);
|
||||
OutputDebugString(buf);
|
||||
}
|
||||
#endif
|
||||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue