home *** CD-ROM | disk | FTP | other *** search
- unit MouseWheel;
-
- interface
-
- uses
- Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs;
-
- type
- TOnWheelSpin = procedure (Count: Integer) of Object;
-
- TMouseWheel = class(TObject)
- private
- { Private declarations }
- fNative: Boolean;
- fWheelPresent: Boolean;
- fScrollLines: Integer;
- fWheelMessage: UINT;
- fActiveForm: TForm;
- fDelta: SmallInt;
- fOnWheelSpin: TOnWheelSpin;
- fOldWndProc: Integer;
- constructor Create;
- destructor Destroy; override;
- procedure SetActiveForm (Value: TForm);
- function NativeMouseWheelSupport: Boolean;
- procedure SetOnWheelSpin (Value: TOnWheelSpin);
- protected
- { Protected declarations }
- procedure NewWindowProc (var Message: TMessage);
- function ProcessWheelMessage (Wnd: hWnd; var Message: TMessage): LongInt;
- public
- { Public declarations }
- property Native: Boolean read fNative;
- property WheelPresent: Boolean read fWheelPresent;
- property WheelMessage: UINT read fWheelMessage;
- property ScrollLines: Integer read fScrollLines;
- property ActiveForm: TForm read fActiveForm write SetActiveForm;
- property OnWheelSpin: TOnWheelSpin read fOnWheelSpin write SetOnWheelSpin;
- published
- { Published declarations }
- end;
-
- var
- Wheel: TMouseWheel;
-
- implementation
-
- constructor TMouseWheel.Create;
- var
- hWndMouse: hWnd;
- mQueryScrollLines: UINT;
- begin
- Inherited Create;
- if NativeMouseWheelSupport then begin
- fNative := True;
- fWheelPresent := Boolean (GetSystemMetrics (sm_MouseWheelPresent));
- SystemParametersInfo (spi_GetWheelScrollLines, 0, @fScrollLines, 0);
- fWheelMessage := wm_MouseWheel;
- end else begin
- fNative := False;
- { Look for hidden mouse window }
- hWndMouse := FindWindow ('MouseZ', 'Magellan MSWHEEL');
- if hWndMouse <> 0 then begin
- { We're in business - get the scroll line info }
- fWheelPresent := True;
- mQueryScrollLines := RegisterWindowMessage ('MSH_SCROLL_LINES_MSG');
- fScrollLines := SendMessage (hWndMouse, mQueryScrollLines, 0, 0);
- { Finally, get the custom mouse message as well }
- fWheelMessage := RegisterWindowMessage ('MSWHEEL_ROLLMSG');
- end;
- end;
-
- if (fScrollLines < 0) or (fScrollLines > 100) then fScrollLines := 3;
- end;
-
- destructor TMouseWheel.Destroy;
- begin
- SetActiveForm (Nil);
- Inherited Destroy;
- end;
-
- function TMouseWheel.NativeMouseWheelSupport: Boolean;
- var
- ver: TOSVersionInfo;
- begin
- Result := False;
- ver.dwOSVersionInfoSize := sizeof (ver);
- // For Windows 98, assume dwMajorVersion = 5 (It's 4 for W95)
- // For NT, we need 4.0 or better.
- if GetVersionEx (ver) then case ver.dwPlatformID of
- ver_Platform_Win32_Windows: Result := ver.dwMajorVersion >= 5;
- ver_Platform_Win32_NT: Result := ver.dwMajorVersion >= 4;
- end;
-
- { Quick and dirty temporary hack for Windows 98 beta 3 }
- if (Result = False) and (ver.szCSDVersion = ' Beta 3') then Result := True;
- end;
-
- procedure TMouseWheel.SetOnWheelSpin (Value: TOnWheelSpin);
- begin
- if fWheelPresent then fOnWheelSpin := Value;
- end;
-
- procedure TMouseWheel.SetActiveForm (Value: TForm);
- begin
- if fWheelPresent and (Value <> fActiveForm) then begin
- { Unsubclass the current form }
- if (fActiveForm <> Nil) and IsWindow (fActiveForm.Handle) then begin
- SetWindowLong (fActiveForm.Handle, gwl_WndProc, fOldWndProc);
- RemoveProp (fActiveForm.Handle, 'MouseWheelProp');
- end;
-
- { Subclass the current form }
- fActiveForm := Value; fDelta := 0;
- if (fActiveForm <> Nil) and IsWindow (fActiveForm.Handle) then begin
- fOldWndProc := SetWindowLong (fActiveForm.Handle, gwl_WndProc, LongInt (MakeObjectInstance (NewWindowProc)));
- SetProp (fActiveForm.Handle, 'MouseWheelProp', Integer(Self));
- end;
- end;
- end;
-
- procedure TMouseWheel.NewWindowProc (var Message: TMessage);
- var
- Hackomatic: TOnWheelSpin;
- HackomaticAlias: TPoint absolute Hackomatic;
- begin
- if (Message.Msg = fWheelMessage) or (Message.Msg = wm_MouseWheel) then Message.Result := ProcessWheelMessage (fActiveForm.Handle, Message)
- else Message.Result := CallWindowProc (Pointer(fOldWndProc), fActiveForm.Handle, Message.Msg, Message.WParam, Message.lParam);
- { Check if it's time to abandon ship....window handle still valid until after wm_NCDestroy }
- if Message.Msg = wm_Destroy then begin
- { Special check - is fOnWheelSpin a method of form being destroyed ? }
- Hackomatic := fOnWheelSpin;
- if Assigned (fOnWheelSpin) and
- (TObject (HackomaticAlias.y) is TForm) and
- (TForm (HackomaticAlias.y).Handle = fActiveForm.Handle) then fOnWheelSpin := Nil;
- SetActiveForm (Nil);
- end;
- end;
-
- function TMouseWheel.ProcessWheelMessage (Wnd: hWnd; var Message: TMessage): LongInt;
- var
- Idx: Integer;
-
- function GetShiftState: Integer;
- begin
- Result := 0;
- if GetAsyncKeyState (vk_Shift) < 0 then Result := Result or mk_Shift;
- if GetAsyncKeyState (vk_Control) < 0 then Result := Result or mk_Control;
- if GetAsyncKeyState (vk_LButton) < 0 then Result := Result or mk_LButton;
- if GetAsyncKeyState (vk_RButton) < 0 then Result := Result or mk_RButton;
- if GetAsyncKeyState (vk_MButton) < 0 then Result := Result or mk_MButton;
- end;
-
- begin
- Result := 0;
- if not IsWindow (Wnd) then Exit; { Just in case.... }
-
- { Is this a non-native call? If so, convert to native and repost }
- if Message.Msg <> wm_MouseWheel then PostMessage (Wnd, wm_MouseWheel, MakeLong (GetShiftState, Message.wParam), Message.lParam)
- else begin
- fDelta := fDelta + HiWord (Message.wParam);
- while Abs(fDelta) >= 120 do begin
- if fDelta < 0 then begin
- if Assigned (fOnWheelSpin) then fOnWheelSpin (fScrollLines) else
- for Idx := 0 to fScrollLines - 1 do PostMessage (Wnd, wm_VScroll, MakeLong (sb_LineDown, 0), 0);
- fDelta := fDelta + 120;
- end else begin
- if Assigned (fOnWheelSpin) then fOnWheelSpin (-fScrollLines) else
- for Idx := 0 to fScrollLines - 1 do PostMessage (Wnd, wm_VScroll, MakeLong (sb_LineUp, 0), 0);
- fDelta := fDelta - 120;
- end;
- end;
- end;
- end;
-
- initialization
- Wheel := TMouseWheel.Create;
- finalization
- Wheel.Free;
- end.
-