(************************************************************************
*    This File is Part of the AHM Triton Tools                          *
*    for Borland Delphi and C++ Builder.                                *
*************************************************************************
* Copyright © 1995-1999 Alexander H. Mehlhorn (AHM) and Tritontools.com *
* All Rights reserved.                                                  *
*                                                                       *
*    For more Information contact us at                                 *
*    E-Mail : support@tritontools.com                                   *
*    URL : http://www.tritontools.com                                   *
*                                                                       *
*    AHM is copyright by Alexander H. Mehlhorn                          *
*    All Parts of this Collection were developed,                       *
*    designed and implemented by AHM                                    *
*                                                                       *
*    Under no Circumstances may you distribute this file                *
*    in this or any other format. This File is supplied                 *
*    as Evaluation of Source only. No Delphi Components may be developed*
*    using extracts or subsets of this code without expressed permission*
*    by AHM.                                                            *
*                                                                       *
*************************************************************************)
unit AHMTHotKeyHolder;
interface
uses
  Windows, Messages, SysUtils,Classes,Menus,AHMSystemClass,Controls;
type
  TAHMHotKeyHolder = class;
  TAHMHotKeys = class;
  TAHMHotKey = class(TCollectionItem)
  private
    FAHMHotKeyHolder : TAHMHotKeyHolder;
    FAtom:TAtom;
    FActive: Boolean;
    FOnKeyDown: TKeyEvent;
    FGlobalKey: TShortcut;
    FWndHandle:HWnd;
    procedure SetActive(const Value: Boolean);
    procedure SetHotKey(const Value: TShortcut);
    procedure NewWndProc(var Message:TMessage);
  protected
    function GetDisplayName: string; override;
  public
    constructor Create(Collection: TCollection); override;
    destructor Destroy; override;
    procedure Assign(Source: TPersistent); override;
    property Owner : TAHMHotKeyHolder read FAHMHotKeyHolder;
    property DisplayName : String read GetDisplayName;
  published
    property Active : Boolean read FActive write SetActive default True;
    property GlobalKey : TShortcut read FGlobalKey write SetHotKey default 0;
    property OnKeyDown: TKeyEvent read FOnKeyDown write FOnKeyDown;
  end;
  TAHMHotKeys = class(TCollection)
  private
    FAHMHotKeyHolder : TAHMHotKeyHolder;
    function GetAHMHotKey(Index: Integer): TAHMHotKey;
    procedure SetAHMHotKey(Index: Integer; Value: TAHMHotKey);
  protected
    function GetOwner : TPersistent; override;
  public
    constructor Create(AOwner: TAHMHotKeyHolder);
    function Add : TAHMHotKey;
   Function Delete(Index :Integer) :Boolean;
    property Owner : TAHMHotKeyHolder read FAHMHotKeyHolder;
    property Items[Index: Integer]: TAHMHotKey read GetAHMHotKey write SetAHMHotKey; default;
  end;
  TAHMHotKeyHolder = class(TAHMSystemsComponent)
  private
    FAHMHotKeys : TAHMHotKeys;
    FOnKeyDown: TKeyEvent;
    procedure SetAHMHotKeys(Value: TAHMHotKeys);
  protected
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
  published
    property OnKeyDown: TKeyEvent read FOnKeyDown write FOnKeyDown;
    property GlobalKeys: TAHMHotKeys read FAHMHotKeys write SetAHMHotKeys;
  end;

implementation
uses Forms;

constructor TAHMHotKey.Create(Collection: TCollection);
begin
  inherited Create(Collection);
  FGlobalkey:=0;
  FAHMHotKeyHolder :=(((Collection as TAHMHotKeys).GetOwner) as TAHMHotKeyHolder);
  FAtom:=GlobalAddAtom(PChar(IntToStr(LongInt(Self))));
  FWndHandle:=AllocateHWnd(NewWndProc);
  FActive:=True;
end;

function TAHMHotKey.GetDisplayName: string;
begin
  if FGlobalKey<>0 then result:=ShortCutToText(FGlobalKey) else 
  Result := inherited GetDisplayName;
end;

function TAHMHotKeys.GetOwner: TPersistent;
begin
  Result := FAHMHotKeyHolder;
end;

procedure TAHMHotKey.Assign(Source: TPersistent);
begin
  if Source is TAHMHotKey then
  begin
    GlobalKey:=TAHMHotkey(Source).GlobalKey;
    Active:=TAHMHotkey(Source).Active;
    OnKeyDown:=TAHMHotkey(Source).OnKeyDown;
    Exit;
  end;
  inherited Assign(Source);
end;

constructor TAHMHotKeys.Create(AOwner: TAHMHotKeyHolder);
begin
  inherited Create(TAHMHotKey);
  FAHMHotKeyHolder := AOwner;
end;

function TAHMHotKeys.Add: TAHMHotKey;
begin
  Result := TAHMHotKey(inherited Add);
end;

function TAHMHotKeys.GetAHMHotKey(Index: Integer): TAHMHotKey;
begin
  Result := TAHMHotKey(inherited GetItem(Index));
end;

procedure TAHMHotKeys.SetAHMHotKey(Index: Integer; Value: TAHMHotKey);
begin
  inherited SetItem(Index, Value);
end;

constructor TAHMHotKeyHolder.Create(AOwner: TComponent);
begin
  inherited create(AOwner);
  FAHMHotKeys:=TAHMHotKeys.Create(self);
end;

destructor TAHMHotKeyHolder.Destroy;
begin
  FAHMHotKeys.Free;
  inherited Destroy;
end;

procedure TAHMHotKeyHolder.SetAHMHotKeys(Value: TAHMHotKeys);
begin
  FAHMHotKeys.Assign(Value);
end;


function TAHMHotKeys.Delete(Index: Integer): Boolean;
begin
  result := true;
  Try
    Items[Index].free;
  Except
    result := false;
    Application.handleexception(self);
  End;
end;

procedure TAHMHotKey.SetActive(const Value: Boolean);
var ShiftState:TShiftState;
    tmpi:Integer;
    Key:Word;
begin
  if FActive<>Value then
  begin
    FActive:=Value;
    if (csDesigning in FAHMHotkeyHolder.ComponentState) then exit;
    if FActive then
    begin
      tmpi:=0;
      ShortCutToKey(FGlobalKey,Key,Shiftstate);
      if ssCtrl in ShiftState then tmpi:=MOD_CONTROL;
      if ssAlt in ShiftState then tmpi:=tmpi or MOD_ALT;
      if ssShift in ShiftState then tmpi:=tmpi or MOD_SHIFT;
      RegisterHotKey(FWndHandle, FAtom, tmpi, Key);
    end else if FGlobalKey<>0 then UnregisterHotKey(FWndHandle, FAtom);
  end;
end;

procedure TAHMHotKey.SetHotKey(const Value: TShortcut);
var ShiftState:TShiftState;
    tmpi:Integer;
    Key :Word;
begin
  if (FGlobalKey<>Value) then
  begin
    FGlobalKey:=Value;
    if (csDesigning in FAHMHotKeyHolder.ComponentState) then exit;
    if FActive then
    if Value<>0 then
    begin
      tmpi:=0;
      ShortCutToKey(Value, Key, ShiftState);
      if ssCtrl in ShiftState then tmpi:=MOD_CONTROL;
      if ssAlt in Shiftstate then tmpi:=tmpi or MOD_ALT;
      if ssShift in ShiftState then tmpi:=tmpi or MOD_SHIFT;
      RegisterHotKey(FWndHandle, FAtom, tmpi, Key);
    end else if FGlobalKey<>0 then UnregisterHotKey(FWndHandle, FAtom);
  end;
end;

procedure TAHMHotKey.NewWndProc(var Message: TMessage);
var Key:Word;
    ShiftState:TShiftState;
begin
  if (Message.Msg=WM_HOTKEY) and Assigned(FOnKeyDown) then
  try
    ShortCutToKey(FGlobalKey, Key, ShiftState);
    if assigned(FOnKeyDown) then FOnKeyDown(self, Key, ShiftState);
    if assigned(FAHMHotkeyHolder.FOnKeyDown) then FAHMHotkeyHolder.FOnKeyDown(self, Key, ShiftState);
  except
    Application.HandleException(Self);
  end;
end;

destructor TAHMHotKey.Destroy;
begin
  if FGlobalKey<>0 then GlobalKey:=0;
  DeleteAtom(FAtom);
  DeallocateHWnd(FWndHandle);
  inherited Destroy;
end;

end.
