From 00e58c13ec8afb2eb0b9f72ab55929f5b0716a97 Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Fri, 27 Mar 2020 17:50:51 +1100 Subject: [PATCH 1/3] feat(windows): user control for upload to sentry --- windows/src/desktop/kmshell/kmshell.dproj | 12 +- windows/src/desktop/kmshell/kmshell.res | Bin 7036 -> 7036 bytes .../main/UImportOlderVersionSettings.pas | 6 +- windows/src/desktop/kmshell/main/initprog.pas | 3 +- windows/src/desktop/kmshell/xml/locale.xml | 65 ++++++----- windows/src/desktop/setup/RunTools.pas | 24 +++- windows/src/desktop/setup/SetupStrings.pas | 6 +- .../src/desktop/setup/UfrmInstallOptions.dfm | 14 ++- .../src/desktop/setup/UfrmInstallOptions.pas | 15 +++ windows/src/desktop/setup/UfrmRunDesktop.pas | 6 +- .../developer/TIKE/dialogs/UfrmOptions.dfm | 24 ++++ .../developer/TIKE/dialogs/UfrmOptions.pas | 9 ++ .../TIKE/main/KeymanDeveloperOptions.pas | 11 ++ windows/src/developer/TIKE/main/UfrmMain.pas | 3 + windows/src/developer/kmcomp/kmcomp.dproj | 2 +- windows/src/engine/kmcomapi/Makefile | 2 +- .../engine/kmcomapi/util/utilkeymanoption.pas | 7 +- .../tsysinfo/UfrmRemoteExceptionHandler.pas | 29 +++++ windows/src/engine/tsysinfox64/Makefile | 2 +- .../src/ext/sentry/Sentry.Client.Console.pas | 4 +- windows/src/ext/sentry/Sentry.Client.Vcl.pas | 8 +- windows/src/ext/sentry/Sentry.Client.pas | 107 +++++++++++------- .../Keyman.System.KeymanSentryClient.pas | 45 +++++++- .../delphi/general/KeymanOptionNames.pas | 4 +- .../global/delphi/general/RegistryKeys.pas | 5 + windows/src/global/inc/registry.h | 7 ++ windows/src/global/vc/keymansentry.cpp | 96 ++++++++++------ 27 files changed, 374 insertions(+), 142 deletions(-) diff --git a/windows/src/desktop/kmshell/kmshell.dproj b/windows/src/desktop/kmshell/kmshell.dproj index c8b286254f..499f0bd9bf 100644 --- a/windows/src/desktop/kmshell/kmshell.dproj +++ b/windows/src/desktop/kmshell/kmshell.dproj @@ -394,18 +394,18 @@ true - - - kmshell.exe - true - - .\ true + + + kmshell.exe + true + + 1 diff --git a/windows/src/desktop/kmshell/kmshell.res b/windows/src/desktop/kmshell/kmshell.res index a4ee2686e621424b32df1e8be3326501f0222aa1..b40caabf45fce9a6717c6dbd98614de3cad72882 100644 GIT binary patch delta 13 Ucmexk_Qz~O2~+B&jb&`o058-9>Hq)$ delta 13 Ucmexk_Qz~O36tgYjb&`o04=2jg8%>k diff --git a/windows/src/desktop/kmshell/main/UImportOlderVersionSettings.pas b/windows/src/desktop/kmshell/main/UImportOlderVersionSettings.pas index 4cfd1992a0..44396a9f7c 100644 --- a/windows/src/desktop/kmshell/main/UImportOlderVersionSettings.pas +++ b/windows/src/desktop/kmshell/main/UImportOlderVersionSettings.pas @@ -24,7 +24,7 @@ unit UImportOlderVersionSettings; interface -function FirstRunInstallDefaults(DoDefaults,DoStartWithWindows,DoCheckForUpdates: Boolean; FDisablePackages: string): Boolean; // I2753 +function FirstRunInstallDefaults(DoDefaults,DoStartWithWindows,DoCheckForUpdates: Boolean; FDisablePackages: string; DoAutomaticallyReportUsage: Boolean): Boolean; // I2753 implementation @@ -42,7 +42,7 @@ uses RegistryKeys, UImportOlderKeyboardUtils; -function FirstRunInstallDefaults(DoDefaults,DoStartWithWindows,DoCheckForUpdates: Boolean; FDisablePackages: string): Boolean; // I2753 +function FirstRunInstallDefaults(DoDefaults,DoStartWithWindows,DoCheckForUpdates: Boolean; FDisablePackages: string; DoAutomaticallyReportUsage: Boolean): Boolean; // I2753 var n, I: Integer; v: Integer; @@ -129,6 +129,8 @@ begin if DoStartWithWindows then kmcom.Options['koStartWithWindows'].Value := True; // I2753 if DoCheckForUpdates then kmcom.Options['koCheckForUpdates'].Value := True; // I2753 + if DoAutomaticallyReportUsage then kmcom.Options['koAutomaticallyReportUsage'].Value := True; + if DoDefaults then begin diff --git a/windows/src/desktop/kmshell/main/initprog.pas b/windows/src/desktop/kmshell/main/initprog.pas index a1c4f58f12..8bbc5a0d6f 100644 --- a/windows/src/desktop/kmshell/main/initprog.pas +++ b/windows/src/desktop/kmshell/main/initprog.pas @@ -546,7 +546,8 @@ begin Pos('installdefaults', FQuery) > 0, Pos('startwithwindows', FQuery) > 0, Pos('checkforupdates', FQuery) > 0, - FDisablePackages); // I2651, I2753 + FDisablePackages, + Pos('automaticallyreportusage', FQuery) > 0); // I2651, I2753 end; UpdateAllLocaleDoctypes; // I2605 diff --git a/windows/src/desktop/kmshell/xml/locale.xml b/windows/src/desktop/kmshell/xml/locale.xml index 0c2d02c19a..7889880678 100644 --- a/windows/src/desktop/kmshell/xml/locale.xml +++ b/windows/src/desktop/kmshell/xml/locale.xml @@ -2,7 +2,7 @@ - + Keyman - + Segoe UI 9 @@ -43,7 +43,7 @@ Create a user interface translation for Keyman Desktop at http://www.tavultesoft Click this icon to select a keyboard &Name; is still running. Click this icon to use your language keyboard at any time - + @@ -58,7 +58,7 @@ Create a user interface translation for Keyman Desktop at http://www.tavultesoft Help - + Keyboard Layouts K Options O @@ -94,7 +94,7 @@ Create a user interface translation for Keyman Desktop at http://www.tavultesoft Languages: ✕ Add language - + On Screen Keyboard: Custom Installed @@ -103,7 +103,7 @@ Create a user interface translation for Keyman Desktop at http://www.tavultesoft Documentation: Installed Not installed - + Message: Copyright: @@ -143,6 +143,9 @@ Create a user interface translation for Keyman Desktop at http://www.tavultesoft Treat hardware deadkeys as plain keys Show hint messages +Automatically report errors to keyman.com +Share anonymous usage statistics with keyman.com + Start when Windows starts Show splash screen Show welcome screen @@ -163,7 +166,7 @@ Create a user interface translation for Keyman Desktop at http://www.tavultesoft User interface language... Base Keyboard... - + @@ -184,10 +187,10 @@ Create a user interface translation for Keyman Desktop at http://www.tavultesoft Open Text Editor Open Language Switcher - + General Hotkeys Keyboard Layouts - + Installed Language @@ -236,7 +239,7 @@ Create a user interface translation for Keyman Desktop at http://www.tavultesoft - + Install Keyboard/Package @@ -290,22 +293,22 @@ keyboard that you use in Windows. Keyman keyboards will adapt automatically to Select Keyboards to Install You cannot install all the keyboards in this package. You can install a maximum of %0:d additional keyboards. Please select the keyboards you wish to install from this package. - + - + Updated &Name; Components Available Updates for &Name_CN; are now available Please select the updates you wish to install: - + Do you want to download and install this patch now? You can download the new version from: Do you want to visit the website now? - + Install Now Cancel @@ -323,7 +326,7 @@ keyboard that you use in Windows. Keyman keyboards will adapt automatically to Click this icon to download and install updates View and &install &Name; updates E&xit online update check - + @@ -336,12 +339,12 @@ keyboard that you use in Windows. Keyman keyboards will adapt automatically to Start Keyman Exit - + Other tasks Configuration Show this screen at startup Hide this screen at startup - + @@ -367,7 +370,7 @@ keyboard that you use in Windows. Keyman keyboards will adapt automatically to - + Language Configuration Tasks Configure your computer to work with @@ -429,7 +432,7 @@ keyboard that you use in Windows. Keyman keyboards will adapt automatically to -Switch &Name; &Off +Switch &Name; &Off On Screen &Keyboard Keyboard &Usage &Font Helper @@ -441,7 +444,7 @@ keyboard that you use in Windows. Keyman keyboards will adapt automatically to E&xit No keyboard layouts are installed. -Choose "Configuration" to install a +Choose "Configuration" to install a keyboard layout for your language. Fade When Inactive @@ -461,7 +464,7 @@ keyboard layout for your language. Click the buttons below to view additional documentation and/or On Screen Keyboard. No keyboard layout is currently selected in &Name;. Click on any of the keyboard icons in the toolbar above to choose a keyboard layout. No keyboard layouts are currently installed or loaded. Use &Name; Configuration to install a keyboard layout. - + @@ -471,7 +474,7 @@ keyboard layout for your language. &Name_CN; @@ -483,10 +486,10 @@ keyboard layout for your language. -A package with the name %0:s is already installed. Do you want to uninstall it and install the new one? A keyboard with the name '%0:s' is already installed. If you continue, it will be uninstalled before the new one is installed. Continue? @@ -502,8 +505,8 @@ keyboard layout for your language. Codepage Unicode Downloading File - - + + Are you sure you want to remove the on screen keyboard installed for %0:s? @@ -552,7 +555,7 @@ PRIVACY WARNING: Please note that the debug logfile records all keystrokes that Install language %0:s and link to Keyman keyboard %1:s - + Please wait while &Name; finds the fonts that will work with keyboard. @@ -569,10 +572,10 @@ PRIVACY WARNING: Please note that the debug logfile records all keystrokes that No fonts were found on your system that work with . Please check the documentation to find fonts for this keyboard. - + No keyboard layouts are currently installed or loaded. Use &Name; Configuration to install a keyboard layout. Please choose a &Name; keyboard to find the fonts that will work with it. - + Hint: @@ -590,5 +593,5 @@ PRIVACY WARNING: Please note that the debug logfile records all keystrokes that Text Editor - &Name; - + diff --git a/windows/src/desktop/setup/RunTools.pas b/windows/src/desktop/setup/RunTools.pas index 1580257aeb..9b2651b9fe 100644 --- a/windows/src/desktop/setup/RunTools.pas +++ b/windows/src/desktop/setup/RunTools.pas @@ -91,7 +91,9 @@ type InstallSuccess: Boolean); procedure CheckInstalledVersion; function InstallMSI: Boolean; - procedure InstallPackages(StartKeyman,StartWithWindows,CheckForUpdates,StartDisabled,StartWithConfiguration: Boolean); + procedure InstallPackages(StartKeyman,StartWithWindows, + CheckForUpdates,StartDisabled,StartWithConfiguration, + AutomaticallyReportUsage: Boolean); procedure PrepareForReboot(res: Cardinal); function RestartWindows: Boolean; procedure RunVersion6Upgrade(const kmshellpath: WideString); @@ -106,7 +108,9 @@ type destructor Destroy; override; procedure CheckInternetConnectedState; function DownloadFile(ADownloadURL, ADownloadFilename: WideString): Boolean; - function DoInstall(Handle: THandle; PackagesOnly, CheckForUpdatesInstall, StartAfterInstall, StartWithWindows, CheckForUpdates, StartDisabled, StartWithConfiguration: Boolean): Boolean; + function DoInstall(Handle: THandle; PackagesOnly, CheckForUpdatesInstall, + StartAfterInstall, StartWithWindows, CheckForUpdates, StartDisabled, + StartWithConfiguration, AutomaticallyReportUsage: Boolean): Boolean; procedure LogError(const msg: WideString; ShowDialogIfNotSilent: Boolean = True); property Silent: Boolean read FSilent write FSilent; property PromptForReboot: Boolean read FPromptForReboot write FPromptForReboot; // I3355 // I3500 @@ -183,7 +187,9 @@ begin inherited; end; -function TRunTools.DoInstall(Handle: THandle; PackagesOnly, CheckForUpdatesInstall, StartAfterInstall, StartWithWindows, CheckForUpdates, StartDisabled, StartWithConfiguration: Boolean): Boolean; +function TRunTools.DoInstall(Handle: THandle; PackagesOnly, CheckForUpdatesInstall, + StartAfterInstall, StartWithWindows, CheckForUpdates, StartDisabled, + StartWithConfiguration, AutomaticallyReportUsage: Boolean): Boolean; begin Result := False; @@ -211,14 +217,17 @@ begin if InstallMSI then begin - InstallPackages(StartAfterInstall,StartWithWindows,CheckForUpdates,StartDisabled,StartWithConfiguration); + InstallPackages(StartAfterInstall,StartWithWindows,CheckForUpdates, + StartDisabled,StartWithConfiguration,AutomaticallyReportUsage); Result := True; end end else begin CheckInstalledVersion; - InstallPackages(StartAfterInstall,StartWithWindows,CheckForUpdates,FInstallInfo.StartDisabled, FInstallInfo.StartWithConfiguration); + InstallPackages(StartAfterInstall,StartWithWindows,CheckForUpdates, + FInstallInfo.StartDisabled, FInstallInfo.StartWithConfiguration, + AutomaticallyReportUsage); Result := True; end; end; @@ -686,7 +695,8 @@ begin end; end; -procedure TRunTools.InstallPackages(StartKeyman,StartWithWindows,CheckForUpdates,StartDisabled,StartWithConfiguration: Boolean); +procedure TRunTools.InstallPackages(StartKeyman,StartWithWindows,CheckForUpdates, + StartDisabled,StartWithConfiguration,AutomaticallyReportUsage: Boolean); var i: Integer; s: WideString; @@ -715,6 +725,8 @@ begin if StartWithWindows then s := s + 'StartWithWindows,'; if CheckForUpdates then s := s + 'CheckForUpdates,'; + if AutomaticallyReportUsage then s := s + 'AutomaticallyReportUsage,'; + if (FInstalledVersion.Version = '') or (FInstalledVersion.ProductCode <> FInstallerVersion.ProductCode) then s := s + 'InstallDefaults,'; // I2651 diff --git a/windows/src/desktop/setup/SetupStrings.pas b/windows/src/desktop/setup/SetupStrings.pas index d3e3a9ba9b..43530d17b2 100644 --- a/windows/src/desktop/setup/SetupStrings.pas +++ b/windows/src/desktop/setup/SetupStrings.pas @@ -84,7 +84,8 @@ type ssOptionsStartAfterInstall, ssOptionsCheckForUpdates, ssOptionsCheckForUpdatesBeforeInstall, - ssOptionsUpgradeKeyboards + ssOptionsUpgradeKeyboards, + ssOptionsAutomaticallyReportUsage ); const @@ -155,7 +156,8 @@ const {ssOptionsStartAfterInstall} 'Start $APPNAME when installation completes', {ssOptionsCheckForUpdates} 'Check for updates online periodically', {ssOptionsCheckForUpdatesBeforeInstall} 'Check for updates before installing', - {ssOptionsUpgradeKeyboards} 'Upgrade keyboards installed with older versions to version $VERSION' + {ssOptionsUpgradeKeyboards} 'Upgrade keyboards installed with older versions to version $VERSION', + {ssOptionsAutomaticallyReportUsage} 'Share anonymous usage statistics with keyman.com' ); implementation diff --git a/windows/src/desktop/setup/UfrmInstallOptions.dfm b/windows/src/desktop/setup/UfrmInstallOptions.dfm index b50708a084..d2e937641c 100644 --- a/windows/src/desktop/setup/UfrmInstallOptions.dfm +++ b/windows/src/desktop/setup/UfrmInstallOptions.dfm @@ -4,7 +4,7 @@ object frmInstallOptions: TfrmInstallOptions BorderIcons = [biSystemMenu] BorderStyle = bsDialog Caption = 'ssOptionsTitle' - ClientHeight = 213 + ClientHeight = 222 ClientWidth = 505 Color = clBtnFace Font.Charset = DEFAULT_CHARSET @@ -59,7 +59,7 @@ object frmInstallOptions: TfrmInstallOptions end object cmdOK: TButton Left = 172 - Top = 172 + Top = 183 Width = 73 Height = 25 Caption = 'OK' @@ -69,7 +69,7 @@ object frmInstallOptions: TfrmInstallOptions end object cmdCancel: TButton Left = 260 - Top = 172 + Top = 183 Width = 73 Height = 25 Cancel = True @@ -77,4 +77,12 @@ object frmInstallOptions: TfrmInstallOptions ModalResult = 2 TabOrder = 6 end + object chkAutomaticallyReportUsage: TCheckBox + Left = 16 + Top = 153 + Width = 473 + Height = 17 + Caption = 'ssOptionsAutomaticallyReportUsage' + TabOrder = 7 + end end diff --git a/windows/src/desktop/setup/UfrmInstallOptions.pas b/windows/src/desktop/setup/UfrmInstallOptions.pas index 3c72646cf4..121161d4c3 100644 --- a/windows/src/desktop/setup/UfrmInstallOptions.pas +++ b/windows/src/desktop/setup/UfrmInstallOptions.pas @@ -32,6 +32,7 @@ type chkUpgradeKeyman7: TCheckBox; cmdOK: TButton; cmdCancel: TButton; + chkAutomaticallyReportUsage: TCheckBox; procedure FormCreate(Sender: TObject); private function GetCanUpgradeKeyman7: Boolean; @@ -46,6 +47,8 @@ type procedure SetStartAfterInstall(const Value: Boolean); procedure SetStartWithWindows(const Value: Boolean); procedure SetUpgradeKeyman7(const Value: Boolean); + function GetAutomaticallyReportUsage: Boolean; + procedure SetAutomaticallyReportUsage(const Value: Boolean); { Private declarations } public { Public declarations } @@ -55,6 +58,7 @@ type property CheckForUpdatesInstall: Boolean read GetCheckForUpdatesInstall write SetCheckForUpdatesInstall; property UpgradeKeyman: Boolean read GetUpgradeKeyman7 write SetUpgradeKeyman7; property CanUpgradeKeyman: Boolean read GetCanUpgradeKeyman7 write SetCanUpgradeKeyman7; + property AutomaticallyReportUsage: Boolean read GetAutomaticallyReportUsage write SetAutomaticallyReportUsage; end; implementation @@ -76,6 +80,12 @@ begin chkCheckForUpdatesInstall.Caption := FInstallInfo.Text(ssOptionsCheckForUpdatesBeforeInstall); // Keyman 11 and later version keyboards will always automatically update chkUpgradeKeyman7.Caption := FInstallInfo.Text(ssOptionsUpgradeKeyboards); + chkAutomaticallyReportUsage.Caption := FInstallInfo.Text(ssOptionsAutomaticallyReportUsage); +end; + +function TfrmInstallOptions.GetAutomaticallyReportUsage: Boolean; +begin + Result := chkAutomaticallyReportUsage.Checked; end; function TfrmInstallOptions.GetCanUpgradeKeyman7: Boolean; @@ -108,6 +118,11 @@ begin Result := chkUpgradeKeyman7.Checked; end; +procedure TfrmInstallOptions.SetAutomaticallyReportUsage(const Value: Boolean); +begin + chkAutomaticallyReportUsage.Checked := Value; +end; + procedure TfrmInstallOptions.SetCanUpgradeKeyman7(const Value: Boolean); begin chkUpgradeKeyman7.Enabled := Value; diff --git a/windows/src/desktop/setup/UfrmRunDesktop.pas b/windows/src/desktop/setup/UfrmRunDesktop.pas index b0f5bbc330..f5acff8d0e 100644 --- a/windows/src/desktop/setup/UfrmRunDesktop.pas +++ b/windows/src/desktop/setup/UfrmRunDesktop.pas @@ -91,6 +91,7 @@ type FCheckForUpdatesInstall: Boolean; FStartAfterInstall: Boolean; FStartWithWindows: Boolean; + FAutomaticallyReportUsage: Boolean; FDisableUpgradeFrom6Or7Or8: Boolean; // I2847 // I4293 procedure SetOfflineByRequest(const Value: Boolean); procedure Rewrap; @@ -494,7 +495,7 @@ begin SetupMSI; // I2644 if GetRunTools.DoInstall(Handle, PackagesOnly, FCheckForUpdatesInstall, FStartAfterInstall, FStartWithWindows, FCheckForUpdates, - FInstallInfo.StartDisabled, FInstallInfo.StartWithConfiguration) then + FInstallInfo.StartDisabled, FInstallInfo.StartWithConfiguration, FAutomaticallyReportUsage) then begin if not Silent and not FStartAfterInstall then // I2610 ShowMessage(FInstallInfo.Text(ssInstallSuccess)); @@ -519,6 +520,8 @@ var oldHeight: Integer; begin + FAutomaticallyReportUsage := True; + Application.Title := FInstallInfo.Text(ssApplicationTitle); Caption := FInstallInfo.Text(ssTitle); cmdInstall.Caption := FInstallInfo.Text(ssInstallButton); @@ -599,6 +602,7 @@ procedure TfrmRunDesktop.lblOptionsClick(Sender: TObject); begin with TfrmInstallOptions.Create(Self) do try + AutomaticallyReportUsage := FAutomaticallyReportUsage; StartWithWindows := FStartWithWindows; StartAfterInstall := FStartAfterInstall; CheckForUpdates := FCheckForUpdates; diff --git a/windows/src/developer/TIKE/dialogs/UfrmOptions.dfm b/windows/src/developer/TIKE/dialogs/UfrmOptions.dfm index 6b59d066e5..6254b90ce4 100644 --- a/windows/src/developer/TIKE/dialogs/UfrmOptions.dfm +++ b/windows/src/developer/TIKE/dialogs/UfrmOptions.dfm @@ -130,6 +130,30 @@ inherited frmOptions: TfrmOptions Caption = '&Automatically save before importing OSK' TabOrder = 8 end + object gbPrivacy: TGroupBox + Left = 8 + Top = 280 + Width = 401 + Height = 73 + Caption = 'Privacy' + TabOrder = 9 + object chkReportUsage: TCheckBox + Left = 8 + Top = 44 + Width = 311 + Height = 17 + Caption = '&Share anonymous usage statistics with keyman.com' + TabOrder = 0 + end + object chkReportErrors: TCheckBox + Left = 8 + Top = 21 + Width = 311 + Height = 17 + Caption = 'Automatically report &errors to keyman.com' + TabOrder = 1 + end + end end object tabEditor: TTabSheet Caption = 'Editor' diff --git a/windows/src/developer/TIKE/dialogs/UfrmOptions.pas b/windows/src/developer/TIKE/dialogs/UfrmOptions.pas index cea5040614..f85325a33e 100644 --- a/windows/src/developer/TIKE/dialogs/UfrmOptions.pas +++ b/windows/src/developer/TIKE/dialogs/UfrmOptions.pas @@ -101,6 +101,9 @@ type chkAutoSaveBeforeCompiling: TCheckBox; chkOSKAutoSaveBeforeImporting: TCheckBox; chkDebuggerAutoResetBeforeCompiling: TCheckBox; + gbPrivacy: TGroupBox; + chkReportUsage: TCheckBox; + chkReportErrors: TCheckBox; procedure FormCreate(Sender: TObject); procedure cmdOKClick(Sender: TObject); procedure cmdDefaultFontClick(Sender: TObject); @@ -199,6 +202,9 @@ begin editWebHostDefaultPort.Text := IntToStr(WebHostDefaultPort); // I4021 + chkReportUsage.Checked := ReportUsage; + chkReportErrors.Checked := ReportErrors; + lblEditorCustomTheme.Caption := ''; if EditorTheme = '' then cbEditorTheme.ItemIndex := 0 @@ -295,6 +301,9 @@ begin ExternalEditorPath := editExternalEditorPath.Text; DefaultProjectPath := IncludeTrailingPathDelimiter(editDefaultProjectPath.Text); + ReportUsage := chkReportUsage.Checked; + ReportErrors := chkReportErrors.Checked; + Write; end; diff --git a/windows/src/developer/TIKE/main/KeymanDeveloperOptions.pas b/windows/src/developer/TIKE/main/KeymanDeveloperOptions.pas index 20e6fb8a50..83a85f4a79 100644 --- a/windows/src/developer/TIKE/main/KeymanDeveloperOptions.pas +++ b/windows/src/developer/TIKE/main/KeymanDeveloperOptions.pas @@ -62,6 +62,8 @@ type FDebuggerAutoResetBeforeCompiling: Boolean; FAutoSaveBeforeCompiling: Boolean; FOSKAutoSaveBeforeImporting: Boolean; + FReportErrors: Boolean; + FReportUsage: Boolean; procedure CloseRegistry; procedure OpenRegistry; function regReadString(const nm, def: string): string; @@ -95,6 +97,9 @@ type property AutoSaveBeforeCompiling: Boolean read FAutoSaveBeforeCompiling write FAutoSaveBeforeCompiling; property OSKAutoSaveBeforeImporting: Boolean read FOSKAutoSaveBeforeImporting write FOSKAutoSaveBeforeImporting; + property ReportErrors: Boolean read FReportErrors write FReportErrors; + property ReportUsage: Boolean read FReportUsage write FReportUsage; + property WebHostDefaultPort: Integer read FWebHostDefaultPort write FWebHostDefaultPort; // I4021 property AllowMultipleInstances: Boolean read FAllowMultipleInstances write FAllowMultipleInstances; @@ -213,6 +218,9 @@ begin FFix183_LadderLength := regReadInt(SRegValue_IDEOpt_WebLadderLength, CRegValue_IDEOpt_WebLadderLength_Default); FDefaultProjectPath := IncludeTrailingPathDelimiter(regReadString(SRegValue_IDEOpt_DefaultProjectPath, GetFolderPath(CSIDL_PERSONAL) + CDefaultProjectPath)); + + FReportErrors := regReadBool(SRegValue_AutomaticallyReportErrors, True); + FReportUsage := regReadBool(SRegValue_AutomaticallyReportUsage, True); finally CloseRegistry; end; @@ -257,6 +265,9 @@ begin regWriteInt(SRegValue_IDEOpt_WebLadderLength, FFix183_LadderLength); regWriteString(SRegValue_IDEOpt_DefaultProjectPath, FDefaultProjectPath); + + regWriteBool(SRegValue_AutomaticallyReportErrors, FReportErrors); + regWriteBool(SRegValue_AutomaticallyReportUsage, FReportUsage); finally CloseRegistry; end; diff --git a/windows/src/developer/TIKE/main/UfrmMain.pas b/windows/src/developer/TIKE/main/UfrmMain.pas index 7c7cc5bc52..13fe682c9b 100644 --- a/windows/src/developer/TIKE/main/UfrmMain.pas +++ b/windows/src/developer/TIKE/main/UfrmMain.pas @@ -430,6 +430,7 @@ uses keymanapi_TLB, KeymanVersion, OnlineConstants, + Keyman.System.KeymanSentryClient, Keyman.Developer.UI.TikeOnlineUpdateCheck, GlobalProxySettings, Keyman.Developer.System.Project.ProjectFile, @@ -481,6 +482,8 @@ var begin inherited; + TKeymanSentryClient.Client.MessageEvent(SENTRY_LEVEL_INFO, TKeymanSentryClient.LOGGER_DEVELOPER_IDE, 'Started Keyman Developer'); + if not ForceDirectories(FKeymanDeveloperOptions.DefaultProjectPath) then begin // Fall back to Documents folder if we cannot create the default project path diff --git a/windows/src/developer/kmcomp/kmcomp.dproj b/windows/src/developer/kmcomp/kmcomp.dproj index a8d9aa9f1f..ab8fa18e88 100644 --- a/windows/src/developer/kmcomp/kmcomp.dproj +++ b/windows/src/developer/kmcomp/kmcomp.dproj @@ -8,7 +8,7 @@ Console None 18.8 - Win64 + Win32 true diff --git a/windows/src/engine/kmcomapi/Makefile b/windows/src/engine/kmcomapi/Makefile index 9358d1fd47..3885fed722 100644 --- a/windows/src/engine/kmcomapi/Makefile +++ b/windows/src/engine/kmcomapi/Makefile @@ -18,7 +18,7 @@ build: version.res manifest.res kbd_noicon.res dirs if exist $(WIN64_TARGET_PATH)\kmcomapi.x64.dll del $(WIN64_TARGET_PATH)\kmcomapi.x64.dll # Delphi does not allow us to build to a different target filename so we rename after build ren $(WIN64_TARGET_PATH)\kmcomapi.dll kmcomapi.x64.dll - $(SENTRYTOOL_DELPHIPREP) $(WIN64_TARGET_PATH)\kmcomapi.x64.dll -dpr kmcomapi.dpr + # Not yet supported: $(SENTRYTOOL_DELPHIPREP) $(WIN64_TARGET_PATH)\kmcomapi.x64.dll -dpr kmcomapi.dpr $(COPY) $(WIN64_TARGET_PATH)\kmcomapi.x64.dll $(PROGRAM)\engine\kmcomapi.x64.dll if exist $(WIN64_TARGET_PATH)\kmcomapi.dbg $(COPY) $(WIN64_TARGET_PATH)\kmcomapi.dbg $(DEBUGPATH)\engine\kmcomapi.x64.dbg diff --git a/windows/src/engine/kmcomapi/util/utilkeymanoption.pas b/windows/src/engine/kmcomapi/util/utilkeymanoption.pas index 973f1bd5b3..1f3a6e2718 100644 --- a/windows/src/engine/kmcomapi/util/utilkeymanoption.pas +++ b/windows/src/engine/kmcomapi/util/utilkeymanoption.pas @@ -121,7 +121,7 @@ type GroupName: string; end; -const KeymanOptionInfo: array[0..13] of TKeymanOptionInfo = ( // I3331 // I3620 // I4552 +const KeymanOptionInfo: array[0..15] of TKeymanOptionInfo = ( // I3331 // I3620 // I4552 // Global options (opt: koKeyboardHotkeysAreToggle; RegistryName: SRegValue_KeyboardHotkeysAreToggle; OptionType: kotBool; BoolValue: False; GroupName: 'kogGeneral'), @@ -130,6 +130,9 @@ const KeymanOptionInfo: array[0..13] of TKeymanOptionInfo = ( // I3331 // I36 (opt: koShowHints; RegistryName: SRegValue_EnableHints; OptionType: kotBool; BoolValue: True; GroupName: 'kogGeneral'), (opt: koBaseLayout; RegistryName: SRegValue_UnderlyingLayout; OptionType: kotLong; IntValue: 0; GroupName: 'kogGeneral'), + (opt: koAutomaticallyReportErrors; RegistryName: SRegValue_AutomaticallyReportErrors; OptionType: kotBool; BoolValue: True; GroupName: 'kogGeneral'), // I4393 + (opt: koAutomaticallyReportUsage; RegistryName: SRegValue_AutomaticallyReportUsage; OptionType: kotBool; BoolValue: True; GroupName: 'kogGeneral'), // I4393 + // OSK options (opt: koReleaseShiftKeysAfterKeyPress; RegistryName: SRegValue_ReleaseShiftKeysAfterKeyPress; OptionType: kotBool; BoolValue: False; GroupName: 'kogOSK'), @@ -147,7 +150,7 @@ const KeymanOptionInfo: array[0..13] of TKeymanOptionInfo = ( // I3331 // I36 (opt: koDeadkeyConversion; RegistryName: SRegValue_DeadkeyConversionMode; OptionType: kotBool; BoolValue: True; GroupName: 'kogAdvanced'), // I4552 (opt: koDebugging; RegistryName: SRegValue_KeymanDebug; OptionType: kotBool; BoolValue: False; GroupName: 'kogAdvanced') // I4393 - ); +); implementation diff --git a/windows/src/engine/tsysinfo/UfrmRemoteExceptionHandler.pas b/windows/src/engine/tsysinfo/UfrmRemoteExceptionHandler.pas index d33e635696..f78c34609c 100644 --- a/windows/src/engine/tsysinfo/UfrmRemoteExceptionHandler.pas +++ b/windows/src/engine/tsysinfo/UfrmRemoteExceptionHandler.pas @@ -92,9 +92,11 @@ function RunCrashReportHandler: Boolean; implementation uses + System.Win.Registry, Vcl.Clipbrd, Keyman.System.KeymanSentryClient, + RegistryKeys, Upload_Settings, utilexecute; @@ -118,10 +120,16 @@ const S_Sentry_ViewEvent_URL = // Do not localize 'https://sentry.keyman.com/organizations/keyman/projects/%0:s/events/%1:s/'; + SENTRY_PROJECT_NAME_DESKTOP = 'keyman-desktop'; + SENTRY_PROJECT_NAME_DEVELOPER = 'keyman-developer'; + function RunCrashReportHandler: Boolean; var frm: TfrmExceptionHandler; crashID, applicationName, applicationID, projectName, eventClassName, eventMessage: string; + reg: TRegistry; + RegKey: string; + reportExceptions: Boolean; begin if ParamStr(1) <> '-c' then Exit(False); @@ -141,6 +149,27 @@ begin frm.ProjectName := projectName; frm.EventClassName := eventClassName; frm.EventMessage := eventMessage; + + // Load the registry settings for privacy settings + + if projectName = SENTRY_PROJECT_NAME_DESKTOP + then RegKey := SRegKey_KeymanEngine_CU + else RegKey := SRegKey_IDEOptions_CU; + + reg := TRegistry.Create; + try + reportExceptions := + not reg.OpenKeyReadOnly(RegKey) or + not reg.ValueExists(SRegValue_AutomaticallyReportErrors) or + reg.ReadBool(SRegValue_AutomaticallyReportErrors); + finally + reg.Free; + end; + + frm.lblText2.Visible := reportExceptions; + frm.lblNoPersonal.Visible := reportExceptions; + //? frm.lblNotReported.Visible := not reportExceptions; + frm.lblTitle.Caption := Format(S_Title_Message, [applicationName]); Application.Run; diff --git a/windows/src/engine/tsysinfox64/Makefile b/windows/src/engine/tsysinfox64/Makefile index 5aab355d7a..a4b496b901 100644 --- a/windows/src/engine/tsysinfox64/Makefile +++ b/windows/src/engine/tsysinfox64/Makefile @@ -6,7 +6,7 @@ build: version.res manifest.res dirs $(DELPHI_MSBUILD) tsysinfox64.dproj /p:Platform=Win64 - $(SENTRYTOOL_DELPHIPREP) $(WIN64_TARGET_PATH)\kmcomapi.x64.dll -dpr kmcomapi.dpr + # Not yet supported: $(SENTRYTOOL_DELPHIPREP) $(WIN64_TARGET_PATH)\tsysinfo.x64.dll -dpr tsysinfo.dpr $(COPY) $(WIN64_TARGET_PATH)\tsysinfox64.exe $(PROGRAM)\engine clean: def-clean diff --git a/windows/src/ext/sentry/Sentry.Client.Console.pas b/windows/src/ext/sentry/Sentry.Client.Console.pas index 8df80d3ca6..3d4817349e 100644 --- a/windows/src/ext/sentry/Sentry.Client.Console.pas +++ b/windows/src/ext/sentry/Sentry.Client.Console.pas @@ -8,7 +8,7 @@ uses type TSentryClientConsole = class(TSentryClient) public - constructor Create(AOptions: TSentryClientOptions; ACaptureExceptions: Boolean = True); override; + constructor Create(AOptions: TSentryClientOptions; AFlags: TSentryClientFlags); override; destructor Destroy; override; end; @@ -17,7 +17,7 @@ implementation { TSentryClientConsole } constructor TSentryClientConsole.Create(AOptions: TSentryClientOptions; - ACaptureExceptions: Boolean); + AFlags: TSentryClientFlags); begin inherited; diff --git a/windows/src/ext/sentry/Sentry.Client.Vcl.pas b/windows/src/ext/sentry/Sentry.Client.Vcl.pas index 7f442c7605..2ca9efd190 100644 --- a/windows/src/ext/sentry/Sentry.Client.Vcl.pas +++ b/windows/src/ext/sentry/Sentry.Client.Vcl.pas @@ -11,7 +11,7 @@ type private procedure HandleApplicationException(Sender: TObject; E: Exception); public - constructor Create(AOptions: TSentryClientOptions; ACaptureExceptions: Boolean = True); override; + constructor Create(AOptions: TSentryClientOptions; AFlags: TSentryClientFlags); override; destructor Destroy; override; end; @@ -23,11 +23,11 @@ uses { TSentryClientVcl } constructor TSentryClientVcl.Create(AOptions: TSentryClientOptions; - ACaptureExceptions: Boolean); + AFlags: TSentryClientFlags); begin - inherited Create(AOptions, ACaptureExceptions); + inherited Create(AOptions, AFlags); - if ACaptureExceptions then + if scfCaptureExceptions in AFlags then begin Application.OnException := HandleApplicationException; end; diff --git a/windows/src/ext/sentry/Sentry.Client.pas b/windows/src/ext/sentry/Sentry.Client.pas index 5d134445d3..d97ce2e840 100644 --- a/windows/src/ext/sentry/Sentry.Client.pas +++ b/windows/src/ext/sentry/Sentry.Client.pas @@ -37,6 +37,9 @@ type TSentryClientEventType = (scetException, scetMessage); TSentryClientEventAction = (sceaContinue, sceaTerminate); + TSentryClientFlag = (scfCaptureExceptions, scfReportExceptions, scfReportMessages); + TSentryClientFlags = set of TSentryClientFlag; + TSentryClientBeforeEvent = procedure(Sender: TObject; EventType: TSentryClientEventType; event: sentry_value_t; const EventClassName, Message: string; @@ -54,6 +57,8 @@ type options: psentry_options_t; FOnBeforeEvent: TSentryClientBeforeEvent; FOnAfterEvent: TSentryClientAfterEvent; + FReportExceptions: Boolean; + FReportMessages: Boolean; procedure DoAfterEvent(const EventID, ExceptionClassName, Message: string; EventType: TSentryClientEventType); procedure DoBeforeEvent(event: sentry_value_t; @@ -62,7 +67,7 @@ type procedure DoTerminate; function EventIDToString(Guid: TGUID): string; public - constructor Create(AOptions: TSentryClientOptions; ACaptureExceptions: Boolean = True); virtual; + constructor Create(AOptions: TSentryClientOptions; AFlags: TSentryClientFlags); virtual; destructor Destroy; override; function MessageEvent(Level: TSentryLevel; const Logger, Message: string; IncludeStack: Boolean = False): TGUID; @@ -70,6 +75,9 @@ type property OnBeforeEvent: TSentryClientBeforeEvent read FOnBeforeEvent write FOnBeforeEvent; property OnAfterEvent: TSentryClientAfterEvent read FOnAfterEvent write FOnAfterEvent; + + property ReportExceptions: Boolean read FReportExceptions; + property ReportMessages: Boolean read FReportMessages; end; TSentryClientClass = class of TSentryClient; @@ -122,10 +130,12 @@ begin end; -constructor TSentryClient.Create(AOptions: TSentryClientOptions; ACaptureExceptions: Boolean = True); +constructor TSentryClient.Create(AOptions: TSentryClientOptions; AFlags: TSentryClientFlags); begin Assert(not Assigned(FInstance)); FInstance := Self; + FReportExceptions := scfReportExceptions in AFlags; + FReportMessages := scfReportMessages in AFlags; inherited Create; options := sentry_options_new; @@ -153,8 +163,7 @@ begin sentry_init(options); - - if ACaptureExceptions then + if scfCaptureExceptions in AFlags then begin ExceptProc := @SentryExceptHandler; end; @@ -283,35 +292,43 @@ const // A pseudo-frame is inserted at the top of the stack which points // to the address of the code that caused the exception begin - event := sentry_value_new_event; + if FReportExceptions then + begin + event := sentry_value_new_event; - DoBeforeEvent(event, ExceptionClassName, Message, scetException); + DoBeforeEvent(event, ExceptionClassName, Message, scetException); -(* - When we set exception information, the report is corrupted. Not sure why. So - for now we won't create as an exception event. We still get all the information - we want from this. + (* + When we set exception information, the report is corrupted. Not sure why. So + for now we won't create as an exception event. We still get all the information + we want from this. - Investigating this further at https://forum.sentry.io/t/corrupted-display-when-exception-data-is-set-using-native-sdk/9167/2 + Investigating this further at https://forum.sentry.io/t/corrupted-display-when-exception-data-is-set-using-native-sdk/9167/2 - exc := sentry_value_new_object; - sentry_value_set_by_key(exc, 'type', sentry_value_new_string(PAnsiChar(UTF8Encode(ExceptionClassName)))); - sentry_value_set_by_key(exc, 'value', sentry_value_new_string(PAnsiChar(UTF8Encode(Message)))); - sentry_value_set_by_key(event, 'exception', exc); -*) + exc := sentry_value_new_object; + sentry_value_set_by_key(exc, 'type', sentry_value_new_string(PAnsiChar(UTF8Encode(ExceptionClassName)))); + sentry_value_set_by_key(exc, 'value', sentry_value_new_string(PAnsiChar(UTF8Encode(Message)))); + sentry_value_set_by_key(event, 'exception', exc); + *) - sentry_value_set_by_key(event, 'message', sentry_value_new_string(PAnsiChar(UTF8Encode(Message)))); + sentry_value_set_by_key(event, 'message', sentry_value_new_string(PAnsiChar(UTF8Encode(Message)))); - if AExceptAddr = nil then - AExceptAddr := System.ExceptAddr; - threads := CaptureStackTrace(AExceptAddr, FRAMES_TO_SKIP); - if threads <> 0 then - sentry_value_set_by_key(event, 'threads', threads); + if AExceptAddr = nil then + AExceptAddr := System.ExceptAddr; + threads := CaptureStackTrace(AExceptAddr, FRAMES_TO_SKIP); + if threads <> 0 then + sentry_value_set_by_key(event, 'threads', threads); - uuid := sentry_capture_event(event); - Result := uuid.native_uuid; + uuid := sentry_capture_event(event); + Result := uuid.native_uuid; - DoAfterEvent(EventIDToString(Result), ExceptionClassName, Message, scetException); + DoAfterEvent(EventIDToString(Result), ExceptionClassName, Message, scetException); + end + else + begin + DoBeforeEvent(0, ExceptionClassName, Message, scetException); + DoAfterEvent('', ExceptionClassName, Message, scetException); + end; end; function TSentryClient.MessageEvent(Level: TSentryLevel; const Logger, @@ -325,24 +342,32 @@ const // Sentry.Client.CaptureStackTrace, // Sentry.Client.TSentryClient.MessageEvent begin - event := sentry_value_new_message_event( - {* level *} sentry_level_t(Level), - {* logger *} PAnsiChar(UTF8Encode(Logger)), - {* message *} PAnsiChar(UTF8Encode(Message)) - ); - - DoBeforeEvent(event, Logger, Message, scetMessage); - - if IncludeStack then + if FReportMessages or (FReportExceptions and (Level in [SENTRY_LEVEL_ERROR, SENTRY_LEVEL_FATAL])) then begin - threads := CaptureStackTrace(nil, FRAMES_TO_SKIP); - if threads <> 0 then - sentry_value_set_by_key(event, 'threads', threads); + event := sentry_value_new_message_event( + {* level *} sentry_level_t(Level), + {* logger *} PAnsiChar(UTF8Encode(Logger)), + {* message *} PAnsiChar(UTF8Encode(Message)) + ); + + DoBeforeEvent(event, Logger, Message, scetMessage); + + if IncludeStack then + begin + threads := CaptureStackTrace(nil, FRAMES_TO_SKIP); + if threads <> 0 then + sentry_value_set_by_key(event, 'threads', threads); + end; + + Result := sentry_capture_event(event).native_uuid; + + DoAfterEvent(EventIDToString(Result), Logger, Message, scetMessage); + end + else + begin + DoBeforeEvent(0, Logger, Message, scetMessage); + DoAfterEvent('', Logger, Message, scetMessage); end; - - Result := sentry_capture_event(event).native_uuid; - - DoAfterEvent(EventIDToString(Result), Logger, Message, scetMessage); end; end. diff --git a/windows/src/global/delphi/general/Keyman.System.KeymanSentryClient.pas b/windows/src/global/delphi/general/Keyman.System.KeymanSentryClient.pas index 21e139e3b8..a0e52cd55f 100644 --- a/windows/src/global/delphi/general/Keyman.System.KeymanSentryClient.pas +++ b/windows/src/global/delphi/general/Keyman.System.KeymanSentryClient.pas @@ -26,6 +26,8 @@ type class procedure Stop; class property Client: TSentryClient read FClient; class property Instance: TKeymanSentryClient read FInstance; + public + const LOGGER_DEVELOPER_IDE = 'KeymanDeveloper.IDE'; end; @@ -36,6 +38,7 @@ uses System.Generics.Collections, System.JSON, System.SysUtils, + System.Win.Registry, {$IF NOT DEFINED(CONSOLE)} System.UITypes, Vcl.Dialogs, @@ -46,6 +49,7 @@ uses KeymanPaths, KeymanVersion, + RegistryKeys, utilexecute; const @@ -95,14 +99,16 @@ begin if EventType = scetException then begin // We need to look for a kmcomapi errlog and report that - ReportRemoteErrors(EventID); + if FClient.ReportExceptions then + ReportRemoteErrors(EventID); if kscfShowUI in FFlags then begin {$IF DEFINED(CONSOLE)} // Write to console writeln(ErrOutput, 'Fatal error '+EventClassName+': '+Message); - writeln(ErrOutput, 'This error has been automatically reported to the Keyman team.'); + if FClient.ReportExceptions then + writeln(ErrOutput, 'This error has been automatically reported to the Keyman team.'); writeln(ErrOutput); {$ELSE} // Launch external gui exception dialog app. @@ -215,7 +221,10 @@ end; constructor TKeymanSentryClient.Create(SentryClientClass: TSentryClientClass; AProject: TKeymanSentryClientProject; AFlags: TKeymanSentryClientFlags); var + reg: TRegistry; o: TSentryClientOptions; + f: TSentryClientFlags; + RegKey: string; begin Assert(not Assigned(FInstance)); @@ -235,7 +244,37 @@ begin o.Release := 'release-'+CKeymanVersionInfo.VersionWithTag; - FClient := SentryClientClass.Create(o, kscfCaptureExceptions in FFlags); + if kscfCaptureExceptions in FFlags + then f := [scfCaptureExceptions] + else f := []; + + // Load the registry settings for privacy settings + + if AProject = kscpDesktop + then RegKey := SRegKey_KeymanEngine_CU + else RegKey := SRegKey_IDEOptions_CU; + + reg := TRegistry.Create; + try + if reg.OpenKeyReadOnly(RegKey) then + begin + if not reg.ValueExists(SRegValue_AutomaticallyReportErrors) or + reg.ReadBool(SRegValue_AutomaticallyReportErrors) then + Include(f, scfReportExceptions); + if not reg.ValueExists(SRegValue_AutomaticallyReportUsage) or + reg.ReadBool(SRegValue_AutomaticallyReportUsage) then + Include(f, scfReportMessages); + end + else + begin + Include(f, scfReportExceptions); + Include(f, scfReportMessages); + end; + finally + reg.Free; + end; + + FClient := SentryClientClass.Create(o, f); FClient.OnAfterEvent := ClientAfterEvent; end; diff --git a/windows/src/global/delphi/general/KeymanOptionNames.pas b/windows/src/global/delphi/general/KeymanOptionNames.pas index 8097a968a5..27aef82ab5 100644 --- a/windows/src/global/delphi/general/KeymanOptionNames.pas +++ b/windows/src/global/delphi/general/KeymanOptionNames.pas @@ -20,7 +20,9 @@ type koAutoOpenOSK, // I1288 koAutoSwitchOSKPages, // I1375 koUseTouchLayout, - koBaseLayout + koBaseLayout, + koAutomaticallyReportErrors, + koAutomaticallyReportUsage ); function KeymanOptionName(Option: TUtilKeymanOption): string; diff --git a/windows/src/global/delphi/general/RegistryKeys.pas b/windows/src/global/delphi/general/RegistryKeys.pas index 6d775b8fe0..3d32a5acc3 100644 --- a/windows/src/global/delphi/general/RegistryKeys.pas +++ b/windows/src/global/delphi/general/RegistryKeys.pas @@ -183,6 +183,11 @@ const SRegValue_AvailableLanguages = 'available languages'; //CU SRegValue_CurrentLanguage = 'current language'; //CU + { Privacy } + + SRegValue_AutomaticallyReportErrors = 'automatically report errors'; // CU, SRegKey_IDEOptions and SRegKey_KeymanEngine_CU + SRegValue_AutomaticallyReportUsage = 'automatically report usage'; // CU, SRegKey_IDEOptions and SRegKey_KeymanEngine_CU + { ActiveKeyboards } SRegKey_ActiveKeyboards_CU = SRegKey_KeymanEngine_CU + '\Active Keyboards'; // CU diff --git a/windows/src/global/inc/registry.h b/windows/src/global/inc/registry.h index 33c6b3441f..ea61282e67 100644 --- a/windows/src/global/inc/registry.h +++ b/windows/src/global/inc/registry.h @@ -126,6 +126,13 @@ #define REGSZ_DeepTSFIntegration "deep tsf integration" +/* Privacy settings - all DWORD 0/1 */ + +#define REGSZ_IDEOptions_CU ( REGSZ_KeymanDeveloperCU "\\IDE\\Options" ) + +#define REGSZ_AutomaticallyReportErrors "automatically report errors" // CU, SRegKey_IDEOptions and SRegKey_KeymanEngine_CU +#define REGSZ_AutomaticallyReportUsage "automatically report usage" // CU, SRegKey_IDEOptions and SRegKey_KeymanEngine_CU + /* Splitting Registry into ReadOnly and FullAccess makes it much easier to ensure that we are using the registry correctly -- readonly wherever possible. */ diff --git a/windows/src/global/vc/keymansentry.cpp b/windows/src/global/vc/keymansentry.cpp index ea22efb05d..28e0cedc2c 100644 --- a/windows/src/global/vc/keymansentry.cpp +++ b/windows/src/global/vc/keymansentry.cpp @@ -3,17 +3,41 @@ #include #include #include +#include #define SENTRY_DSN_DESKTOP "https://92eb58e6005d47daa33c9c9e39458eb7@sentry.keyman.com/5" #define SENTRY_DSN_DEVELOPER "https://39b25a09410349a58fe12aaf721565af@sentry.keyman.com/6" +bool g_report_exceptions, g_report_messages; + int keyman_sentry_init(bool is_keyman_developer) { sentry_options_t *options = sentry_options_new(); + const char *key; if (is_keyman_developer) { sentry_options_set_dsn(options, SENTRY_DSN_DEVELOPER); + key = REGSZ_IDEOptions_CU; } else { sentry_options_set_dsn(options, SENTRY_DSN_DESKTOP); + key = REGSZ_KeymanCU; + } + + HKEY hkey; + if (RegOpenKeyExA(HKEY_CURRENT_USER, key, 0, KEY_READ, &hkey) == ERROR_SUCCESS) { + DWORD dwType, dwValue, dwValueSize = 4; + + g_report_exceptions = + RegQueryValueExA(hkey, REGSZ_AutomaticallyReportErrors, NULL, &dwType, (LPBYTE)&dwValue, &dwValueSize) != ERROR_SUCCESS || dwType != REG_DWORD || dwValue != 0; + + dwValueSize = 4; + g_report_messages = + RegQueryValueExA(hkey, REGSZ_AutomaticallyReportUsage, NULL, &dwType, (LPBYTE)&dwValue, &dwValueSize) != ERROR_SUCCESS || dwType != REG_DWORD || dwValue != 0; + + RegCloseKey(hkey); + } + else { + g_report_exceptions = true; + g_report_messages = true; } sentry_options_set_release(options, KEYMAN_VersionWithTag); @@ -76,56 +100,60 @@ void keyman_sentry_report_exception(DWORD ExceptionCode, PVOID ExceptionAddress) sentry_value_t event; const int FRAMES_TO_SKIP = 0; - event = sentry_value_new_event(); + if (g_report_exceptions) { + event = sentry_value_new_event(); - char message[64]; - wsprintfA(message, "Exception %x at %p", ExceptionCode, ExceptionAddress); + char message[64]; + wsprintfA(message, "Exception %x at %p", ExceptionCode, ExceptionAddress); - /* - When we set exception information, the report is corrupted. Not sure why. So - for now we won't create as an exception event. We still get all the information - we want from this. + /* + When we set exception information, the report is corrupted. Not sure why. So + for now we won't create as an exception event. We still get all the information + we want from this. - Investigating this further at https://forum.sentry.io/t/corrupted-display-when-exception-data-is-set-using-native-sdk/9167/2 + Investigating this further at https://forum.sentry.io/t/corrupted-display-when-exception-data-is-set-using-native-sdk/9167/2 - sentry_value_t exc = sentry_value_new_object(); - sentry_value_set_by_key(exc, "type", sentry_value_new_string("Exception")); - sentry_value_set_by_key(exc, "value", sentry_value_new_string(message)); - sentry_value_set_by_key(event, "exception", exc);*/ - sentry_value_set_by_key(event, "message", sentry_value_new_string(message)); + sentry_value_t exc = sentry_value_new_object(); + sentry_value_set_by_key(exc, "type", sentry_value_new_string("Exception")); + sentry_value_set_by_key(exc, "value", sentry_value_new_string(message)); + sentry_value_set_by_key(event, "exception", exc);*/ + sentry_value_set_by_key(event, "message", sentry_value_new_string(message)); - //sentry_event_value_add_stacktrace(event, &ExceptionAddress, 64); - sentry_value_t threads = CaptureStackTrace(ExceptionAddress, FRAMES_TO_SKIP); - if (threads._bits != 0) { - sentry_value_set_by_key(event, "threads", threads); + //sentry_event_value_add_stacktrace(event, &ExceptionAddress, 64); + sentry_value_t threads = CaptureStackTrace(ExceptionAddress, FRAMES_TO_SKIP); + if (threads._bits != 0) { + sentry_value_set_by_key(event, "threads", threads); + } + + sentry_capture_event(event); + + perror(message); } - - sentry_capture_event(event); - - perror(message); } void keyman_sentry_report_message(keyman_sentry_level_t level, const char *logger, const char *message, bool includeStack) { const int FRAMES_TO_SKIP = 0; - sentry_value_t event; + if ((g_report_exceptions && (level == SENTRY_LEVEL_ERROR || level == SENTRY_LEVEL_DEBUG)) || g_report_messages) { + sentry_value_t event; - event = sentry_value_new_event(); + event = sentry_value_new_event(); - event = sentry_value_new_message_event( - /*level */ sentry_level_t(level), - /*logger */ logger, - /*message*/ message - ); + event = sentry_value_new_message_event( + /*level */ sentry_level_t(level), + /*logger */ logger, + /*message*/ message + ); - if (includeStack) { - sentry_value_t threads = CaptureStackTrace(NULL, FRAMES_TO_SKIP); - if (threads._bits != 0) { - sentry_value_set_by_key(event, "threads", threads); + if (includeStack) { + sentry_value_t threads = CaptureStackTrace(NULL, FRAMES_TO_SKIP); + if (threads._bits != 0) { + sentry_value_set_by_key(event, "threads", threads); + } } - } - sentry_capture_event(event); + sentry_capture_event(event); + } } /* Wrappers for main, wmain */ From b4ea48f70c9650caf006b6ec268a1e3c69873f38 Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Sat, 28 Mar 2020 06:20:52 +1100 Subject: [PATCH 2/3] fix(windows): skip checking sentry.x64.dll signature --- windows/src/test/test_i3633/verify.dpr | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/windows/src/test/test_i3633/verify.dpr b/windows/src/test/test_i3633/verify.dpr index 4446ae2647..4aadabc651 100644 --- a/windows/src/test/test_i3633/verify.dpr +++ b/windows/src/test/test_i3633/verify.dpr @@ -36,8 +36,8 @@ begin Delete(s,1,1); end; - if str[0].ToLower.Contains('sentry.dll') then - // We don't verify sentry.dll because it's not our file + if str[0].ToLower.Contains('sentry.') then + // We don't verify sentry.dll or sentry.x64.dll because it's not our file Exit(''); { Check each element of string } From 591c05080a3aecb09375f63047e70073b61a4344 Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Sat, 28 Mar 2020 06:53:55 +1100 Subject: [PATCH 3/3] fix(developer): copy sentry to bin before building installer --- windows/src/developer/Makefile | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/windows/src/developer/Makefile b/windows/src/developer/Makefile index cd56b60e4b..7eef9c1c09 100644 --- a/windows/src/developer/Makefile +++ b/windows/src/developer/Makefile @@ -35,7 +35,7 @@ kmconvert: cd $(ROOT)\src\developer\kmconvert $(MAKE) $(TARGET) -tike: kmcmpdll +tike: kmcmpdll redist cd $(ROOT)\src\developer\tike $(MAKE) $(TARGET) @@ -47,7 +47,15 @@ setup: cd $(ROOT)\src\developer\setup $(MAKE) $(TARGET) -inst: +# ---------------------------------------------------------------------- + +redist: + copy $(ROOT)\src\ext\sentry\sentry.dll $(ROOT)\bin\developer + copy $(ROOT)\src\ext\sentry\sentry.x64.dll $(ROOT)\bin\developer + +# ---------------------------------------------------------------------- + +inst: redist cd $(ROOT)\src\developer\inst $(MAKE) $(TARGET)