mirror of
https://github.com/keymanapp/keyman.git
synced 2026-09-30 19:47:45 +00:00
* Keyman for Windows 10.0 Open Source * Squashed 'windows/src/ext/jedi/jedi/' content from commit f444ad2 git-subtree-dir: windows/src/ext/jedi/jedi git-subtree-split: f444ad2da4693851e523f1ea6bd541f701904c24 * Squashed 'windows/src/ext/jedi/jcl/' content from commit d63d3c9fd git-subtree-dir: windows/src/ext/jedi/jcl git-subtree-split: d63d3c9fd9ff84efdd8159084ec6a60313644243 * Squashed 'windows/src/ext/jedi/jvcl/' content from commit bee19f3b4 git-subtree-dir: windows/src/ext/jedi/jvcl git-subtree-split: bee19f3b46909fde2fa92c06cd2706f41d99f6c3 * Add required .res files * Add required .res files * Add docbook files (forced) * Add required libxslt * Add required jedi files * Add installation files * Tweak .gitignore for open * CI * Remove KMW from Developer source (#122) * Remove KMW from Developer source (copies during build) * Remove KMW from Developer source (copies during build) * Remove KMW from Developer source (copies during build) * Fixup release build and copy license, readme from kmw during build * Remove obsolete build help documentation * Keyman Engine 10 on Windows regression for shift states (#129) * Improve #128 -- cleaner debug messages * Fixes #127, shift state now resets correctly; and more work for #128 * Fixes #130 (#131)
411 lines
11 KiB
ObjectPascal
411 lines
11 KiB
ObjectPascal
//*************************************************************
|
|
// EwbCoreTools *
|
|
// *
|
|
// Freeware Unit *
|
|
// For Delphi *
|
|
// Developing Team: *
|
|
// Serge Voloshenyuk (SergeV@bsalsa.com) *
|
|
// Eran Bodankin (bsalsa) -(bsalsa@gmail.com) *
|
|
// *
|
|
// Documentation and updated versions: *
|
|
// *
|
|
// http://www.bsalsa.com *
|
|
//*************************************************************
|
|
{LICENSE:
|
|
THIS SOFTWARE IS PROVIDED TO YOU "AS IS" WITHOUT WARRANTY OF ANY KIND,
|
|
EITHER EXPRESSED OR IMPLIED INCLUDING BUT NOT LIMITED TO THE APPLIED
|
|
WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE.
|
|
YOU ASSUME THE ENTIRE RISK AS TO THE ACCURACY AND THE USE OF THE SOFTWARE
|
|
AND ALL OTHER RISK ARISING OUT OF THE USE OR PERFORMANCE OF THIS SOFTWARE
|
|
AND DOCUMENTATION. BSALSA PRODUCTIONS DOES NOT WARRANT THAT THE SOFTWARE IS ERROR-FREE
|
|
OR WILL OPERATE WITHOUT INTERRUPTION. THE SOFTWARE IS NOT DESIGNED, INTENDED
|
|
OR LICENSED FOR USE IN HAZARDOUS ENVIRONMENTS REQUIRING FAIL-SAFE CONTROLS,
|
|
INCLUDING WITHOUT LIMITATION, THE DESIGN, CONSTRUCTION, MAINTENANCE OR
|
|
OPERATION OF NUCLEAR FACILITIES, AIRCRAFT NAVIGATION OR COMMUNICATION SYSTEMS,
|
|
AIR TRAFFIC CONTROL, AND LIFE SUPPORT OR WEAPONS SYSTEMS. BSALSA PRODUCTIONS SPECIFICALLY
|
|
DISCLAIMS ANY EXPRESS OR IMPLIED WARRANTY OF FITNESS FOR SUCH PURPOSE.
|
|
|
|
You may use/ change/ modify the component under 3 conditions:
|
|
1. In your website, add a link to "http://www.bsalsa.com"
|
|
2. In your application, add credits to "Embedded Web Browser"
|
|
3. Mail me (bsalsa@gmail.com) any code change in the unit for the benefit
|
|
of the other users.
|
|
4. Please, consider donation in our web site!
|
|
{*******************************************************************************}
|
|
|
|
|
|
unit EwbCoreTools;
|
|
|
|
{$I EWB.inc}
|
|
|
|
interface
|
|
|
|
uses
|
|
Graphics, ActiveX, Mshtml_Ewb, Windows, SysUtils;
|
|
|
|
function IsWinXPSP2OrLater(): Boolean;
|
|
function ColorToHTML(const Color: TColor): string;
|
|
function WideStringToLPOLESTR(const Source: Widestring): POleStr;
|
|
function XPath4Node(node: IHTMLElement): string;
|
|
function TaskAllocWideString(const S: string): PWChar;
|
|
function AnsiIndexStr(const AText: string; const AValues: array of string): Integer;
|
|
function GetPos(const SubSt, Text: string; StartPos: Integer = -1): Integer;
|
|
function _CharPos(const C: Char; const S: string): Integer;
|
|
function CutString(var Text: string; const Delimiter: string = ' ';
|
|
const Remove: Boolean = True): string;
|
|
procedure FormatPath(Path: string);
|
|
function GetWinText(WinHandle: THandle): string;
|
|
function GetWinClass(Handle: Hwnd): WideString;
|
|
function GetParentWinByClass(ChildHandle: HWND; const ClassName: string): HWND;
|
|
{$IFDEF DELPHI5}
|
|
function DirectoryExists(const Directory: string): Boolean;
|
|
function VarSupports(const V: Variant; const IID: TGUID; out Intf): Boolean;
|
|
{$ENDIF}
|
|
{$IFNDEF DELPHI12_UP}
|
|
function CharInSet(C: Char; const CharSet: TSysCharSet): Boolean;
|
|
{$ENDIF}
|
|
function AddBackSlash(const S: string): string;
|
|
|
|
const
|
|
WM_SETWBFOCUS = $0400 {WM_USER} + $44;
|
|
|
|
implementation
|
|
|
|
uses
|
|
EwbIeConst, EwbAcc;
|
|
|
|
type
|
|
{VerifyVersion}
|
|
fn_VerifyVersionInfo = function(var VersionInformation: OSVERSIONINFOEX;
|
|
dwTypeMask: DWORD; dwlConditionMask: LONGLONG): BOOL; stdcall;
|
|
fn_VerSetConditionMask = function(ConditionMask: LONGLONG; TypeMask: DWORD;
|
|
Condition: Byte): LONGLONG; stdcall;
|
|
|
|
|
|
function IsWinXPSP2OrLater(): Boolean;
|
|
var
|
|
osvi: TOSVersionInfoEx;
|
|
dwlConditionMask: LONGLONG;
|
|
op: Integer;
|
|
hlib: THandle;
|
|
VerifyVersionInfo: fn_VerifyVersionInfo;
|
|
VerSetConditionMask: fn_VerSetConditionMask;
|
|
begin
|
|
Result := False;
|
|
hLib := GetModuleHandle('kernel32.dll');
|
|
if hLib = 0 then
|
|
hLib := LoadLibrary('kernel32.dll');
|
|
if (hLib <> 0) then
|
|
begin
|
|
@VerifyVersionInfo := GetProcAddress(hLib, 'VerifyVersionInfoA');
|
|
@VerSetConditionMask := GetProcAddress(hLib, 'VerSetConditionMask');
|
|
if ((@VerifyVersionInfo = nil) or (@VerSetConditionMask = nil)) then Exit;
|
|
|
|
dwlConditionMask := 0;
|
|
op := VER_GREATER_EQUAL;
|
|
|
|
// Initialize the OSVERSIONINFOEX structure.
|
|
ZeroMemory(@osvi, SizeOf(OSVERSIONINFOEX));
|
|
osvi.dwOSVersionInfoSize := SizeOf(OSVERSIONINFOEX);
|
|
osvi.dwMajorVersion := 5;
|
|
osvi.dwMinorVersion := 1;
|
|
osvi.wServicePackMajor := 2;
|
|
osvi.wServicePackMinor := 0;
|
|
|
|
// Initialize the condition mask.
|
|
dwlConditionMask := VerSetConditionMask(dwlConditionMask, VER_MAJORVERSION, op);
|
|
dwlConditionMask := VerSetConditionMask(dwlConditionMask, VER_MINORVERSION, op);
|
|
dwlConditionMask := VerSetConditionMask(dwlConditionMask, VER_SERVICEPACKMAJOR, op);
|
|
dwlConditionMask := VerSetConditionMask(dwlConditionMask, VER_SERVICEPACKMINOR, op);
|
|
|
|
// Perform the test.
|
|
Result := VerifyVersionInfo(osvi, VER_MAJORVERSION or VER_MINORVERSION or
|
|
VER_SERVICEPACKMAJOR or VER_SERVICEPACKMINOR, dwlConditionMask);
|
|
end;
|
|
end;
|
|
|
|
function GetParentWinByClass(ChildHandle: HWND; const ClassName: string): HWND;
|
|
var
|
|
szClass: array[0..255] of Char;
|
|
begin
|
|
Result := GetParent(ChildHandle);
|
|
while IsWindow(Result) do
|
|
begin
|
|
if (GetClassName(Result, szClass, SizeOf(szClass)) > 0) and
|
|
(AnsiStrComp(PChar(ClassName), szClass) = 0) then Exit;
|
|
Result := GetParent(Result);
|
|
end;
|
|
end;
|
|
|
|
|
|
|
|
{$IFNDEF DELPHI12_UP}
|
|
|
|
function CharInSet(C: Char; const CharSet: TSysCharSet): Boolean;
|
|
begin
|
|
Result := C in CharSet;
|
|
end;
|
|
{$ENDIF}
|
|
|
|
{$IFDEF DELPHI5}
|
|
|
|
function DirectoryExists(const Directory: string): Boolean;
|
|
var
|
|
Code: Integer;
|
|
begin
|
|
{$RANGECHECKS OFF}
|
|
Code := GetFileAttributes(PChar(Directory));
|
|
Result := (Code <> -1) and (FILE_ATTRIBUTE_DIRECTORY and Code <> 0);
|
|
{$RANGECHECKS ON}
|
|
end;
|
|
|
|
function VarSupports(const V: Variant; const IID: TGUID; out Intf): Boolean;
|
|
begin
|
|
Result := Supports(V, IID, Intf);
|
|
end;
|
|
{$ENDIF}
|
|
|
|
function AddBackSlash(const S: string): string;
|
|
begin
|
|
{$IFDEF DELPHI5}
|
|
Result := IncludeTrailingBackslash(S);
|
|
{$ELSE}
|
|
{$IFDEF DELPHI6UP}
|
|
Result := IncludeTrailingPathDelimiter(S);
|
|
{$ELSE}
|
|
if Copy(S, Length(S), 1) = '\' then
|
|
Result := S
|
|
else
|
|
Result := S + '\';
|
|
{$ENDIF}
|
|
{$ENDIF}
|
|
end;
|
|
|
|
function CutString(var Text: string; const Delimiter: string = ' ';
|
|
const Remove: Boolean = True): string;
|
|
var
|
|
IdxPos: Integer;
|
|
begin
|
|
if Delimiter = #0 then
|
|
IdxPos := Pos(Delimiter, Text)
|
|
else
|
|
IdxPos := AnsiPos(Delimiter, Text);
|
|
|
|
if (IdxPos = 0) then
|
|
begin
|
|
Result := Text;
|
|
if Remove then
|
|
Text := '';
|
|
end
|
|
else
|
|
begin
|
|
Result := Copy(Text, 1, IdxPos - 1);
|
|
if Remove then
|
|
Delete(Text, 1, IdxPos + Length(Delimiter) - 1);
|
|
end;
|
|
end;
|
|
|
|
|
|
function GetPos(const SubSt, Text: string; StartPos: Integer = -1): Integer;
|
|
var
|
|
i: Integer;
|
|
LStartPos: Integer;
|
|
LTokenLen: Integer;
|
|
begin
|
|
result := 0;
|
|
LTokenLen := Length(SubSt);
|
|
if StartPos = -1 then
|
|
begin
|
|
StartPos := Length(Text);
|
|
end;
|
|
if StartPos < (Length(Text) - LTokenLen + 1) then
|
|
begin
|
|
LStartPos := StartPos;
|
|
end
|
|
else
|
|
begin
|
|
LStartPos := (Length(Text) - LTokenLen + 1);
|
|
end;
|
|
for i := LStartPos downto 1 do
|
|
begin
|
|
if AnsiSameText(Copy(Text, i, LTokenLen), SubSt) then
|
|
begin
|
|
Result := i;
|
|
Break;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function _CharPos(const C: Char; const S: string): Integer;
|
|
begin
|
|
for Result := 1 to Length(S) do
|
|
if S[Result] = C then Exit;
|
|
Result := 0;
|
|
end;
|
|
|
|
procedure FormatPath(Path: string);
|
|
var
|
|
i: Integer;
|
|
begin
|
|
i := 1;
|
|
while i <= Length(Path) do
|
|
begin
|
|
if CharInSet(Path[i], LeadBytes) then
|
|
Inc(i, 2)
|
|
else
|
|
if Path[i] = '\' then
|
|
begin
|
|
Path[i] := '/';
|
|
Inc(i, 1);
|
|
end
|
|
else
|
|
Inc(i, 1);
|
|
end;
|
|
end;
|
|
|
|
function AnsiIndexStr(const AText: string; const AValues: array of string): Integer;
|
|
var
|
|
I: Integer;
|
|
begin
|
|
Result := -1;
|
|
for I := Low(AValues) to High(AValues) do
|
|
if AnsiSameStr(AText, AValues[I]) then
|
|
begin
|
|
Result := I;
|
|
Break;
|
|
end;
|
|
end;
|
|
|
|
|
|
function TaskAllocWideString(const S: string): PWChar;
|
|
var
|
|
WideLength: integer;
|
|
Wide: PWideChar;
|
|
begin
|
|
WideLength := Length(S) + 1;
|
|
Wide := CoTaskMemAlloc(WideLength * SizeOf(WideChar));
|
|
StringToWideChar(S, Wide, WideLength);
|
|
Result := Wide;
|
|
end;
|
|
|
|
{
|
|
function TaskAllocWideString(const S: string): PWChar;
|
|
var
|
|
Len: Integer;
|
|
begin
|
|
Len := Length(S) + 1;
|
|
Result := CoTaskMemAlloc(2 * Len);
|
|
StringToWideChar(S, Result, Len);
|
|
end;
|
|
}
|
|
|
|
function WideStringToLPOLESTR(const Source: Widestring): POleStr;
|
|
var
|
|
Len: Integer;
|
|
begin
|
|
Len := Length(Source) * SizeOf(WideChar);
|
|
Result := CoTaskMemAlloc(Len + 2);
|
|
FillChar(Result^, Len + 2, 0);
|
|
Move(Result^, PWideString(Source)^, Len);
|
|
end;
|
|
|
|
function ColorToHTML(const Color: TColor): string;
|
|
var
|
|
ColorRGB: LongWord;
|
|
begin
|
|
ColorRGB := ColorToRGB(Color);
|
|
FmtStr(Result, '#%0.2X%0.2X%0.2X',
|
|
[Byte(ColorRGB), Byte(ColorRGB shr 8), Byte(ColorRGB shr 16)]);
|
|
end;
|
|
|
|
function GetWinText(WinHandle: THandle): string;
|
|
var
|
|
DlgName: string;
|
|
TxtLength: Integer;
|
|
begin
|
|
TxtLength := GetWindowTextLength(WinHandle);
|
|
SetLength(DlgName, TxtLength + 1);
|
|
GetWindowText(WinHandle, PChar(DlgName), TxtLength + 1);
|
|
Result := DlgName;
|
|
end;
|
|
|
|
|
|
function GetWinClass(Handle: Hwnd): WideString;
|
|
var
|
|
pwc: PWideChar;
|
|
const
|
|
maxbufsize = 32767 * SizeOf(WideChar);
|
|
begin
|
|
Result := '';
|
|
if IsWindow(Handle) then
|
|
begin
|
|
pwc := GetMemory(maxbufsize);
|
|
if Assigned(pwc) then
|
|
try
|
|
ZeroMemory(pwc, maxbufsize);
|
|
if GetClassnameW(Handle, pwc, maxbufsize) > 0 then
|
|
SetString(Result, pwc, lstrlenW(pwc));
|
|
finally
|
|
FreeMemory(pwc);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
{
|
|
function GetWinClass(WinHandle: THANDLE): string;
|
|
begin
|
|
SetLength(Result, 80);
|
|
SetLength(Result, GetClassName(WinHandle, PChar(Result), Length(Result)));
|
|
end;
|
|
}
|
|
|
|
|
|
function XPath4Node(node: IHTMLElement): string;
|
|
|
|
function NodePosition(elem: IHTMLElement): string;
|
|
var tag: Widestring;
|
|
Idx: Integer;
|
|
n: IHTMLElement;
|
|
cl: IHTMLElementCollection;
|
|
itm: IDispatch;
|
|
I, C, mI: Integer;
|
|
begin
|
|
Result := '';
|
|
if (elem.parentElement = nil) or
|
|
not Supports(elem.parentElement.children, IHTMLElementCollection, cl) then Exit;
|
|
|
|
Tag := elem.tagName;
|
|
Idx := elem.sourceIndex;
|
|
C := 0;
|
|
mI := -1;
|
|
|
|
for I := 0 to cl.length - 1 do
|
|
begin
|
|
itm := cl.item(I, I);
|
|
if Supports(itm, IHTMLElement, n) then
|
|
begin
|
|
if n.tagName = Tag then
|
|
begin
|
|
if n.sourceIndex = Idx then mI := C;
|
|
Inc(C);
|
|
end;
|
|
end;
|
|
end;
|
|
if (mI > 0) or (C > 1) then Result := Format('[%d]', [mI]);
|
|
end;
|
|
|
|
var id: string;
|
|
begin
|
|
if node <> nil then
|
|
begin
|
|
id := node.id;
|
|
if id <> '' then
|
|
Result := Format('%s[@id="%s"]', [node.tagName, id])
|
|
else if node.parentElement = nil then
|
|
Result := '/' + node.tagName
|
|
else Result := Format('%s/%s%s',
|
|
[XPath4Node(node.parentElement), node.tagName, NodePosition(node)]);
|
|
end else Result := '';
|
|
end;
|
|
|
|
end.
|