unit ModalProtection;
interface
uses
Windows, Messages, SysUtils, Types, UITypes, Classes, Controls, Forms;
type
TAppModalProtection = record
strict private
const
N = 1024;
TimeGap = 2;
CountLimit = 5;
TimeLimit = 20;
type
TModalityEvent = record
Time: TDateTime;
Modal: Boolean;
end;
TModalityHistory = array[0..N - 1] of TModalityEvent;
TModalSpan = record
Duration: Double;
Count: Integer;
end;
class var
FModalityHistory: TModalityHistory;
FIdx: Integer;
FModal: Integer;
FOnWarning: TNotifyEvent;
FSuspend: Boolean;
class procedure AddEvent(AModal: Boolean); static;
class function GetLastModalSpan: TModalSpan; static;
class procedure DoWarning; static;
public
class procedure ModalBegun; static;
class procedure ModalEnded; static;
class property OnWarning: TNotifyEvent read FOnWarning write FOnWarning;
end;
implementation
uses
Math, DateUtils, StrUtils;
class procedure TAppModalProtection.AddEvent(AModal: Boolean);
begin
FIdx := Succ(FIdx) mod N;
FModalityHistory[FIdx].Time := Now;
FModalityHistory[FIdx].Modal := AModal;
end;
class procedure TAppModalProtection.DoWarning;
begin
if Assigned(FOnWarning) then
FOnWarning(nil);
end;
class function TAppModalProtection.GetLastModalSpan: TModalSpan;
begin
Result := Default(TModalSpan);
var LTime := Now;
for var i := 0 to N - 1 do
begin
var LIdx := (FIdx - i + N) mod N;
var LItem := FModalityHistory[LIdx];
if LItem.Time = 0.0 then
Exit;
if LItem.Modal then
begin
Result.Duration := SecondSpan(LItem.Time, Now);
Inc(Result.Count);
LTime := LItem.Time;
end
else if SecondSpan(LItem.Time, LTime) >= TimeGap then
Exit;
end;
Result.Duration := TimeLimit + 1;
end;
class procedure TAppModalProtection.ModalBegun;
begin
if FSuspend then
Exit;
Inc(FModal);
if FModal = 1 then
AddEvent(True);
end;
class procedure TAppModalProtection.ModalEnded;
begin
if FSuspend then
Exit;
Dec(FModal);
if FModal = 0 then
AddEvent(False);
var LMS := GetLastModalSpan;
if (LMS.Count > CountLimit) and (LMS.Duration > TimeLimit) then
begin
FSuspend := True;
try
DoWarning;
finally
FSuspend := False;
end;
end;
end;
end.