spiegel-keyman/windows/src/ext/embeddedwb/Source/EwbCoreTools.pas
Marc Durdin b65b982584 Keyman Desktop and Keyman Developer open source 10.0 alpha seed (#121)
* 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)
2017-07-25 10:53:06 +07:00

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.