[New PowerToy] OCR PowerToy (#19172)

* Init commit

* Fix unintended GUID change of Microsoft.PowerToys.Run.Plugin.TimeZone.UnitTests

* Region and click word working

* Code style

* Close even when there is no result from the OCR

* Fix spelling concerns, and make overlay black to match snipping tool

* increase opacity of overlay to match snipping tool

* Code Style and cleanup

* Code style

* Create Logos and hook them into the project file

* Make the PowerOCR VCXProj more like Awake VCXProj

* Rename MainWindow to OCROverlay

* Add WindowUtilities and WindowForms

* Remove fsg to fix spelling error

* launch OCR Overlay on every screen

* Add PowerOCR to Runner Main.cpp

* Add PowerOCR Settings and Properties

* Add PowerOcrViewModel

* Fix wrong setting reference in PowerOcrSettingsVM

* Try to clean up the Cpp project for PowerOCR

* Went to ARM64 was x64 thanks @snickler

* Clean up PowerOCR C++ Proj with file refs

* Rewrite C++ dllmain comparing to awake

* Changes for spelling issues. The rest will stay

* Create PowerOcr Settings Page and add to settings shell

* Fix PowerOcr Settings

* Fix multi-monitor scaling issue

* Add close all overlays when escaping

* Update src/runner/main.cpp to call correct Power OCR dll

Co-authored-by: Stefan Markovic <57057282+stefansjfw@users.noreply.github.com>

* Update expect.txt

* Add many files from Color Picker for hotkey activation

* Organize project into helper folder

* Use new hotkey activation and keep process alive

* Fix bug where scalebmp wasn't working

* Add The file headers and dispose app.xaml.cs

* Code style changes

* Fix bug where PowerOCR was toggling Awake

* Unsubscribe from keyboard events making they don't fire twice

* Add SndPowerOcrSetting and add to SettingsVM

* Trying to make the runner close PowerOCR when runner closes

* Fix app_name

* Update spellcheck expect

* use mutex on PowerOCR app to keep to single instance

* Rebuild the module interface using ColorPicker as a template.

Process still stays alive.

* Fix project names of the module interface

* Put app startup args back to 0 like color picker

* Runner now finds and enables/disables PowerOCR

* remove unneeded item groups from settings proj, per stefansjfw

* Add PowerOCR Screenshots

* Revert changed project GUID

* Add OOBE content for PowerOCR

* Keep cursor on one screen since the OCR window does not span screens.

* reload settings when activation key is pressed

* New screenshots and OOBE text

* Add PowerOCR as a case in the settings App.xaml.cs OnLaunched

* Settings and OOBE Text Changes

* Using using on bitmaps and change OCR overlay to stay open if no result

* Keyboard activation is handled is true

* Remove unused start PowerOCR OOBE Method

* [PowerOCR]Add some telemetry

* Add some logging

* Don't recreate the OCR overlay Windows more times

* Add to BugReportTool to get event viewer errors

* Fix wrong comment

* Fix another comment

* Add files to installer

* Add to signing

* Don't take Esc away from other apps

* Default to Win Shift R

* Use low level keyboard hook from runner

* Remove esc from local low level keyboard hook

* Fix some nits

* Default to Win Shift T
This commit is contained in:
Joseph Finney
2022-08-25 05:25:52 -05:00
committed by GitHub
parent 768603eb61
commit eedea3159c
64 changed files with 3040 additions and 16 deletions

View File

@@ -0,0 +1,40 @@
#include <windows.h>
#include "resource.h"
#include "../../../../common/version/version.h"
#define APSTUDIO_READONLY_SYMBOLS
#include "winres.h"
#undef APSTUDIO_READONLY_SYMBOLS
1 VERSIONINFO
FILEVERSION FILE_VERSION
PRODUCTVERSION PRODUCT_VERSION
FILEFLAGSMASK VS_FFI_FILEFLAGSMASK
#ifdef _DEBUG
FILEFLAGS VS_FF_DEBUG
#else
FILEFLAGS 0x0L
#endif
FILEOS VOS_NT_WINDOWS32
FILETYPE VFT_DLL
FILESUBTYPE VFT2_UNKNOWN
BEGIN
BLOCK "StringFileInfo"
BEGIN
BLOCK "040904b0" // US English (0x0409), Unicode (0x04B0) charset
BEGIN
VALUE "CompanyName", COMPANY_NAME
VALUE "FileDescription", FILE_DESCRIPTION
VALUE "FileVersion", FILE_VERSION_STRING
VALUE "InternalName", INTERNAL_NAME
VALUE "LegalCopyright", COPYRIGHT_NOTE
VALUE "OriginalFilename", ORIGINAL_FILENAME
VALUE "ProductName", PRODUCT_NAME
VALUE "ProductVersion", PRODUCT_VERSION_STRING
END
END
BLOCK "VarFileInfo"
BEGIN
VALUE "Translation", 0x409, 1200 // US English (0x0409), Unicode (1200) charset
END
END

View File

@@ -0,0 +1,85 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.220418.1\build\native\Microsoft.Windows.CppWinRT.props" Condition="Exists('..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.220418.1\build\native\Microsoft.Windows.CppWinRT.props')" />
<Target Name="GenerateResourceFiles" BeforeTargets="PrepareForBuild">
<Exec Command="powershell -NonInteractive -executionpolicy Unrestricted $(SolutionDir)tools\build\convert-resx-to-rc.ps1 $(MSBuildThisFileDirectory) resource.base.h resource.h PowerOCR.base.rc PowerOCR.rc" />
</Target>
<PropertyGroup Label="Globals">
<VCProjectVersion>15.0</VCProjectVersion>
<Keyword>Win32Proj</Keyword>
<ProjectGuid>{6AB6A2D6-F859-4A82-9184-0BD29C9F07D1}</ProjectGuid>
<RootNamespace>PowerOCR</RootNamespace>
<ProjectName>PowerOCRModuleInterface</ProjectName>
<TargetName>PowerToys.PowerOCRModuleInterface</TargetName>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<PlatformToolset>v143</PlatformToolset>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="Shared">
</ImportGroup>
<ImportGroup Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup>
<OutDir>$(SolutionDir)$(Platform)\$(Configuration)\modules\PowerOCR\</OutDir>
</PropertyGroup>
<ItemDefinitionGroup>
<ClCompile>
<PreprocessorDefinitions>EXAMPLEPOWERTOY_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>..\..\..\common\inc;..\..\..\common\Telemetry;..\..\;..\..\..\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClInclude Include="PowerOcrConstants.h" />
<ClInclude Include="pch.h" />
<None Include="packages.config" />
<None Include="resource.base.h" />
<ClInclude Include="trace.h" />
<ClInclude Include="Generated Files\resource.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="dllmain.cpp" />
<ClCompile Include="pch.cpp">
<PrecompiledHeader Condition="'$(CIBuild)'!='true'">Create</PrecompiledHeader>
</ClCompile>
<ClCompile Include="trace.cpp" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\common\logger\logger.vcxproj">
<Project>{d9b8fc84-322a-4f9f-bbb9-20915c47ddfd}</Project>
</ProjectReference>
<ProjectReference Include="..\..\..\common\SettingsAPI\SettingsAPI.vcxproj">
<Project>{6955446d-23f7-4023-9bb3-8657f904af99}</Project>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<None Include="PowerOCR.base.rc" />
<ResourceCompile Include="Generated Files\PowerOCR.rc" />
</ItemGroup>
<ItemGroup>
<None Include="Resources.resx">
<SubType>Designer</SubType>
</None>
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<Import Project="..\..\..\..\deps\spdlog.props" />
<ImportGroup Label="ExtensionTargets">
<Import Project="..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.220418.1\build\native\Microsoft.Windows.CppWinRT.targets" Condition="Exists('..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.220418.1\build\native\Microsoft.Windows.CppWinRT.targets')" />
</ImportGroup>
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
</PropertyGroup>
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.220418.1\build\native\Microsoft.Windows.CppWinRT.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.220418.1\build\native\Microsoft.Windows.CppWinRT.props'))" />
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.220418.1\build\native\Microsoft.Windows.CppWinRT.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.220418.1\build\native\Microsoft.Windows.CppWinRT.targets'))" />
</Target>
</Project>

View File

@@ -0,0 +1,62 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Source Files">
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
<Extensions>cpp;c;cc;cxx;c++;def;odl;idl;hpj;bat;asm;asmx</Extensions>
</Filter>
<Filter Include="Header Files">
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
<Extensions>h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd</Extensions>
</Filter>
<Filter Include="Resource Files">
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
</Filter>
<Filter Include="Generated Files">
<UniqueIdentifier>{875a08c6-f610-4667-bd0f-80171ed96072}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<ClInclude Include="pch.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Generated Files\resource.h">
<Filter>Generated Files</Filter>
</ClInclude>
<ClInclude Include="PowerOcrConstants.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="trace.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="dllmain.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="pch.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="trace.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<None Include="resource.base.h">
<Filter>Header Files</Filter>
</None>
<None Include="Resources.resx">
<Filter>Resource Files</Filter>
</None>
<None Include="packages.config" />
<None Include="PowerOCR.base.rc">
<Filter>Resource Files</Filter>
</None>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="Generated Files\PowerOCR.rc">
<Filter>Resource Files</Filter>
</ResourceCompile>
</ItemGroup>
</Project>

View File

@@ -0,0 +1,8 @@
#pragma once
#include <string>
namespace PowerOcrConstants
{
// Name of the powertoy module.
inline const std::wstring ModuleKey = L"PowerOCR";
}

View File

@@ -0,0 +1,126 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="PowerOCR_Name" xml:space="preserve">
<value>PowerOCR</value>
</data>
<data name="PowerOCR_Settings_Desc" xml:space="preserve">
<value>This feature requires Windows 10 version 1903 or higher</value>
</data>
</root>

View File

@@ -0,0 +1,294 @@
// dllmain.cpp : Defines the entry point for the DLL application.
#include "pch.h"
#include <interface/powertoy_module_interface.h>
#include "trace.h"
#include "Generated Files/resource.h"
#include <common/logger/logger.h>
#include <common/SettingsAPI/settings_objects.h>
#include <common/utils/resources.h>
#include <PowerOCR/PowerOCRModuleInterface/PowerOcrConstants.h>
#include <common/interop/shared_constants.h>
#include <common/utils/logger_helper.h>
#include <common/utils/winapi_error.h>
BOOL APIENTRY DllMain(HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
Trace::RegisterProvider();
case DLL_THREAD_ATTACH:
break;
case DLL_THREAD_DETACH:
break;
case DLL_PROCESS_DETACH:
Trace::UnregisterProvider();
break;
}
return TRUE;
}
namespace
{
const wchar_t JSON_KEY_PROPERTIES[] = L"properties";
const wchar_t JSON_KEY_WIN[] = L"win";
const wchar_t JSON_KEY_ALT[] = L"alt";
const wchar_t JSON_KEY_CTRL[] = L"ctrl";
const wchar_t JSON_KEY_SHIFT[] = L"shift";
const wchar_t JSON_KEY_CODE[] = L"code";
const wchar_t JSON_KEY_ACTIVATION_SHORTCUT[] = L"ActivationShortcut";
}
struct ModuleSettings
{
} g_settings;
class PowerOCR : public PowertoyModuleIface
{
private:
bool m_enabled = false;
std::wstring app_name;
//contains the non localized key of the powertoy
std::wstring app_key;
HANDLE m_hProcess;
// Time to wait for process to close after sending WM_CLOSE signal
static const int MAX_WAIT_MILLISEC = 10000;
Hotkey m_hotkey;
// Handle to event used to invoke PowerOCR
HANDLE m_hInvokeEvent;
void parse_hotkey(PowerToysSettings::PowerToyValues& settings)
{
auto settingsObject = settings.get_raw_json();
if (settingsObject.GetView().Size())
{
try
{
auto jsonHotkeyObject = settingsObject.GetNamedObject(JSON_KEY_PROPERTIES).GetNamedObject(JSON_KEY_ACTIVATION_SHORTCUT);
m_hotkey.win = jsonHotkeyObject.GetNamedBoolean(JSON_KEY_WIN);
m_hotkey.alt = jsonHotkeyObject.GetNamedBoolean(JSON_KEY_ALT);
m_hotkey.shift = jsonHotkeyObject.GetNamedBoolean(JSON_KEY_SHIFT);
m_hotkey.ctrl = jsonHotkeyObject.GetNamedBoolean(JSON_KEY_CTRL);
m_hotkey.key = static_cast<unsigned char>(jsonHotkeyObject.GetNamedNumber(JSON_KEY_CODE));
}
catch (...)
{
Logger::error("Failed to initialize PowerOCR start shortcut");
}
}
else
{
Logger::info("PowerOCR settings are empty");
}
if (!m_hotkey.key)
{
Logger::info("PowerOCR is going to use default shortcut");
m_hotkey.win = true;
m_hotkey.alt = false;
m_hotkey.shift = true;
m_hotkey.ctrl = false;
m_hotkey.key = 'T';
}
}
bool is_process_running()
{
return WaitForSingleObject(m_hProcess, 0) == WAIT_TIMEOUT;
}
void launch_process()
{
Logger::trace(L"Starting PowerOCR process");
unsigned long powertoys_pid = GetCurrentProcessId();
std::wstring executable_args = L"";
executable_args.append(std::to_wstring(powertoys_pid));
SHELLEXECUTEINFOW sei{ sizeof(sei) };
sei.fMask = { SEE_MASK_NOCLOSEPROCESS | SEE_MASK_FLAG_NO_UI };
sei.lpFile = L"modules\\PowerOCR\\PowerToys.PowerOCR.exe";
sei.nShow = SW_SHOWNORMAL;
sei.lpParameters = executable_args.data();
if (ShellExecuteExW(&sei))
{
Logger::trace("Successfully started the PowerOCR process");
}
else
{
Logger::error( L"PowerOCR failed to start. {}", get_last_error_or_default(GetLastError()));
}
m_hProcess = sei.hProcess;
}
// Load the settings file.
void init_settings()
{
try
{
// Load and parse the settings file for this PowerToy.
PowerToysSettings::PowerToyValues settings =
PowerToysSettings::PowerToyValues::load_from_settings_file(get_key());
parse_hotkey(settings);
}
catch (std::exception ex)
{
Logger::warn(L"An exception occurred while loading the settings file");
// Error while loading from the settings file. Let default values stay as they are.
}
}
public:
PowerOCR()
{
app_name = GET_RESOURCE_STRING(IDS_POWEROCR_NAME);
app_key = PowerOcrConstants::ModuleKey;
LoggerHelpers::init_logger(app_key, L"ModuleInterface", "PowerOCR");
m_hInvokeEvent = CreateDefaultEvent(CommonSharedConstants::SHOW_POWEROCR_SHARED_EVENT);
init_settings();
}
~PowerOCR()
{
if (m_enabled)
{
}
m_enabled = false;
}
// Destroy the powertoy and free memory
virtual void destroy() override
{
Logger::trace("PowerOCR::destroy()");
delete this;
}
// Return the localized display name of the powertoy
virtual const wchar_t* get_name() override
{
return app_name.c_str();
}
// Return the non localized key of the powertoy, this will be cached by the runner
virtual const wchar_t* get_key() override
{
return app_key.c_str();
}
virtual bool get_config(wchar_t* buffer, int* buffer_size) override
{
HINSTANCE hinstance = reinterpret_cast<HINSTANCE>(&__ImageBase);
// Create a Settings object.
PowerToysSettings::Settings settings(hinstance, get_name());
settings.set_description(GET_RESOURCE_STRING(IDS_POWEROCR_SETTINGS_DESC));
settings.set_overview_link(L"https://aka.ms/PowerToysOverview_PowerOCR");
return settings.serialize_to_buffer(buffer, buffer_size);
}
virtual void call_custom_action(const wchar_t* action) override
{
}
virtual void set_config(const wchar_t* config) override
{
try
{
// Parse the input JSON string.
PowerToysSettings::PowerToyValues values =
PowerToysSettings::PowerToyValues::from_json_string(config, get_key());
parse_hotkey(values);
// If you don't need to do any custom processing of the settings, proceed
// to persists the values calling:
values.save_to_settings_file();
// Otherwise call a custom function to process the settings before saving them to disk:
// save_settings();
}
catch (std::exception ex)
{
// Improper JSON.
}
}
virtual void enable()
{
Logger::trace("PowerOCR::enable()");
ResetEvent(m_hInvokeEvent);
launch_process();
m_enabled = true;
Trace::EnablePowerOCR(true);
};
virtual void disable()
{
Logger::trace("PowerOCR::disable()");
if (m_enabled)
{
ResetEvent(m_hInvokeEvent);
TerminateProcess(m_hProcess, 1);
}
m_enabled = false;
Trace::EnablePowerOCR(false);
}
virtual bool on_hotkey(size_t hotkeyId) override
{
if (m_enabled)
{
Logger::trace(L"PowerOCR hotkey pressed");
if (!is_process_running())
{
launch_process();
}
SetEvent(m_hInvokeEvent);
return true;
}
return false;
}
virtual size_t get_hotkeys(Hotkey* hotkeys, size_t buffer_size) override
{
if (m_hotkey.key)
{
if (hotkeys && buffer_size >= 1)
{
hotkeys[0] = m_hotkey;
}
return 1;
}
else
{
return 0;
}
}
virtual bool is_enabled() override
{
return m_enabled;
}
};
extern "C" __declspec(dllexport) PowertoyModuleIface* __cdecl powertoy_create()
{
return new PowerOCR();
}

View File

@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Microsoft.Windows.CppWinRT" version="2.0.220418.1" targetFramework="native" />
</packages>

View File

@@ -0,0 +1,2 @@
#include "pch.h"

View File

@@ -0,0 +1,7 @@
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <winrt/Windows.Foundation.h>
#include <winrt/Windows.Foundation.Collections.h>
#include <ProjectTelemetry.h>
#include <shellapi.h>
#include <Shlwapi.h>

View File

@@ -0,0 +1,13 @@
//{{NO_DEPENDENCIES}}
// Microsoft Visual C++ generated include file.
// Used by PowerOCR.rc
//////////////////////////////
// Non-localizable
#define FILE_DESCRIPTION "PowerToys PowerOCR"
#define INTERNAL_NAME "PowerToys.PowerOCR"
#define ORIGINAL_FILENAME "PowerToys.PowerOCR.dll"
// Non-localizable
//////////////////////////////

View File

@@ -0,0 +1,30 @@
#include "pch.h"
#include "trace.h"
TRACELOGGING_DEFINE_PROVIDER(
g_hProvider,
"Microsoft.PowerToys",
// {38e8889b-9731-53f5-e901-e8a7c1753074}
(0x38e8889b, 0x9731, 0x53f5, 0xe9, 0x01, 0xe8, 0xa7, 0xc1, 0x75, 0x30, 0x74),
TraceLoggingOptionProjectTelemetry());
void Trace::RegisterProvider()
{
TraceLoggingRegister(g_hProvider);
}
void Trace::UnregisterProvider()
{
TraceLoggingUnregister(g_hProvider);
}
// Log if the user has PowerOCR enabled or disabled
void Trace::EnablePowerOCR(const bool enabled) noexcept
{
TraceLoggingWrite(
g_hProvider,
"PowerOCR_EnablePowerOCR",
ProjectTelemetryPrivacyDataTag(ProjectTelemetryTag_ProductAndServicePerformance),
TraceLoggingKeyword(PROJECT_KEYWORD_MEASURE),
TraceLoggingBoolean(enabled, "Enabled"));
}

View File

@@ -0,0 +1,10 @@
#pragma once
class Trace
{
public:
static void RegisterProvider();
static void UnregisterProvider();
// Log if the user has PowerOCR enabled or disabled
static void EnablePowerOCR(const bool enabled) noexcept;
};