unit UnitHotKey;
{
    Purpose:
        Move all the hotkey logic into a contained object
        (In other words, undo the adhoc bad design of the past)

}
{///////////////}
{//}interface{//}
{///////////////}
Type
TACHotKey = class (TObject)
    private
        FormHandle : THandle;
        HotKeyID : integer;
        hkCtrl, hkAlt, hkShift, hkWinkwy : boolean;
        hkKey : word;
        function HotKeyAssign(
            Ctrl: boolean; Alt: boolean; Shift: boolean; Winkey : boolean;
            Keystroke: word ): boolean;
    public
        constructor Create(FormHandle : THandle; UniqueName : string;
            Hotkey_Ctrl, Hotkey_Alt, Hotkey_Shift, Hotkey_Winkey : boolean;
            Hotkey_key : word);
        function SetHotKey(
                Hotkey_Ctrl, Hotkey_Alt, Hotkey_Shift, Hotkey_Winkey : boolean;
                Hotkey_key : word
            ) : boolean;
        procedure UnSet;
        function GetID : word;
        destructor Destroy; override;
end;
{////////////////////}
{//}implementation{//}
{////////////////////}
uses Windows, SysUtils, Forms, UnitFrmMainPopup;

type TACHotKeyException = class(Exception)

end;

constructor TACHotKey.Create(FormHandle : THandle; UniqueName : string;
    Hotkey_Ctrl, Hotkey_Alt, Hotkey_Shift, Hotkey_Winkey : boolean;
    Hotkey_key : word
    );
begin
    Windows.SetLastError(ERROR_SUCCESS);

    self.FormHandle := formhandle;
    HotKeyID := GlobalAddAtom(PChar(UniqueName));
    if not self.HotKeyAssign(Hotkey_Ctrl, Hotkey_Alt, Hotkey_Shift,
        Hotkey_Winkey, Hotkey_Key) then begin

        Raise TACHotKeyException.Create('ERROR: Unable to assign a hotkey. Please change the key.');
    end;
end;

destructor TACHotKey.Destroy;
begin
    self.UnSet;
end;

function TACHotKey.GetID : word;
begin
    result := HotKeyID;
end;

function TACHotKey.SetHotKey(
    Hotkey_Ctrl, Hotkey_Alt, Hotkey_Shift, Hotkey_Winkey : boolean;
    Hotkey_key : word
) : boolean;
begin
    Windows.SetLastError(ERROR_SUCCESS);
    //
    // if the user tries to assign to a hotkey that is already in use,
    // the hotkeyrelease failing is OK
    //
    if HotKeyID <> 0 then begin
        UnRegisterHotKey(FormHandle, HotKeyID);
    end;


    if not (self.HotKeyAssign(Hotkey_Ctrl, Hotkey_Alt, Hotkey_Shift, Hotkey_Winkey,
        Hotkey_key)) then begin
        Raise TACHotKeyException.Create('ERROR: Couldn''t assign hotkey. It may already be assigned by another program.');
    end else begin
        result := true;
    end;
end;

//------------------------
// Private Implementation
//------------------------
function TACHotKey.HotKeyAssign(
    Ctrl: boolean; Alt: boolean; Shift: boolean; Winkey : boolean;
    Keystroke: word ): boolean;
var modifier: word;
begin
    modifier := 0;
    if ctrl then modifier := modifier or MOD_CONTROL;
    if alt then  modifier := modifier or MOD_ALT;
    if shift then modifier := modifier or MOD_SHIFT;
    if winkey then modifier := modifier or MOD_WIN;
    result := false;
    if (HotKeyID = 0) then begin
        exit;
    end;

    hkCtrl := ctrl;
    hkAlt := alt;
    hkShift := shift;
    hkWinkwy := winkey;
    hkKey := Keystroke;

    if not (Windows.RegisterHotKey(FormHandle, HotKeyID, modifier, Keystroke)) then begin
        exit;
    end;

    result := true;
end;


procedure TACHotKey.UnSet;
begin
    if (HotKeyID <> 0) then begin
        UnRegisterHotKey(FormHandle, HotKeyID);
        DeleteAtom(HotKeyID);
        HotKeyID := 0;
    end;
end;

end.
