Cześć.
Moj plugin dla TotalCommandera do odtwarzania modułów muzycznych w sumie przepisany na WinAPI, ale męczę się z jedną rzeczą. Chciałbym aby pasek przewijania do ustalania pozycji odtwarzanego modułu po kliknięciu w pole po lewej lub po prawej od scrolowanego kwadraru ustawiał się od razu na tej pozycji. Taki efekt można osiągnąc z tego co wiem, tylko ze wciśniętym Shiftem. A ja chciałbym to zrobić bez jego wciśkania.
Poniższy kod ma te wadę, ze w obsłudze okna rodzica komunikatu WM_HSCROLL
po ustawieniu pozycji ScrollBara zakodowałem SetFocus na ostatnie aktywne okno, co w większości przypadków powoduje przywrócenie sterowania na listę plików w jednym z okien z plikami i katalogami, w którym nie jest otwarty moj plugin.
Niestety jeżeli myszkę pozostawiliśmy nadal nad scrollbarem to Shift ciągle będzie wciśnęty i zaczniemy zaznaczać pliki lub przy wciskaniu klawiszy efekt będzie taki jakbyśmy to robili nadal ze wciśniętym Shiftem. Prosil bym o przykład jak to lepiej zakodować i ogarnąć. Próbowałem "puszczać" klawisz symulując to w WM_KILLFOCUS
, ale wtedy tylko pierwsze kliknięcie na ScrollBar działa jak należy, później już nie. Natomiast symulowania wciskania Shifta w komunikacie WM_LBUTTONDOWN
następuje za późno, ponieważ efekt jest taki, jakby Shift nie był wciśnięty. Z gory dziękuję za wszelkie kody i porady, bo sam raczej nie przeskoczę tego i albo z tego zrezygnuje albo rozwiązanie będzie jak teraz niedopracowane czego bym nie chciał.
//...
function _TrackMouseEvent; external comctl32 name '_TrackMouseEvent';
procedure KeyDownUp(KeyToSend : Byte; KeyDown : boolean);
const
DownUp_Flags_Arr : array[boolean] of DWORD = (0, KEYEVENTF_KEYUP);
Extended_Flags_Arr : array[boolean] of DWORD = (0, KEYEVENTF_EXTENDEDKEY);
var
Input : TagINPUT;
KeyExtended : boolean;
begin
Input.Itype := INPUT_KEYBOARD;
Input.ki.wVK := KeyToSend;
Input.ki.wScan := MapVirtualKey(KeyToSend, 0);
KeyExtended := KeyToSend in
[VK_CONTROL, VK_LCONTROL, VK_RCONTROL,
VK_UP, VK_DOWN, VK_LEFT, VK_RIGHT,
VK_HOME, VK_END, VK_PRIOR, VK_NEXT,
VK_INSERT, VK_DELETE, VK_MENU];
Input.ki.dwFlags := DownUp_Flags_Arr[not KeyDown] or Extended_Flags_Arr[KeyExtended];
Input.ki.time := 0;
SendInput(1, Input, SizeOf(Input));
end;
procedure DownUpShiftKeyThreadProc(Param : Pointer); stdcall;
begin
KeyDownUp(VK_LSHIFT, Boolean(Param));
end;
function NewScrollBarProc(AHWnd : HWND; Msg : UINT; AWParam : WParam; ALParam : LParam) : LResult; stdcall;
var
ThreadId : Cardinal;
TME : TTrackMouseEvent;
begin
case Msg of
wM_SETCURSOR :
begin
SetCursor(LoadCursor(0, IDC_HAND));
Result := 0;
Exit;
end;
WM_SETFOCUS :
begin
FocusedHandle := GetForegroundWindow;
end;
WM_MOUSEMOVE :
begin
if IsWindowEnabled(AHwnd) then
begin
if not SBTrackingMouse then
begin
TME.cbSize := SizeOf(TME);
TME.dwFlags := TME_LEAVE;
TME.hwndTrack := AHWnd;
_TrackMouseEvent(@TME);
SBTrackingMouse := True;
if DownUpShiftThrHandle = 0 then
begin
DownUpShiftThrHandle := CreateThread(nil, 0, @DownUpShiftKeyThreadProc, Pointer(True), 0, ThreadId);
end;
end;
end;
end;
WM_MOUSELEAVE :
begin
SBTrackingMouse := False;
if DownUpShiftThrHandle > 0 then
begin
CreateThread(nil, 0, @DownUpShiftKeyThreadProc, Pointer(False), 0, ThreadId);
CloseHandle(DownUpShiftThrHandle);
DownUpShiftThrHandle := 0;
end;
end;
end;
Result := CallWindowProc(POldScrollBarProc, AHWnd, Msg, AWParam, ALParam);
end;
procedure CreateModulePositionSB;
var
R : TRect;
begin
Windows.GetClientRect(TimeLabelHandle, R);
TimeLabelHeight := R.Bottom;
ModulePositionSBHandle := CreateWindow('ScrollBar', '', WS_TABSTOP or WS_VISIBLE or WS_CHILD,
(GetControlWidth(ControlsGBHandle) - GetControlWidth(TitleEditHandle)) div 2,
GetControlTop(ShowKindGBHandle) + GetControlHeight(ShowKindGBHandle) + TimeLabelHeight + Controls_Vert_Distance,
GetcontrolWidth(TitleEditHandle), 18,
ControlsGBHandle, IDC_MODULEPOSITIONSB, HInstance, nil);
POldScrollBarProc := Pointer(SetWindowLong(ModulePositionSBHandle, GWL_WNDPROC, Longint(@NewScrollBarProc)));
SetSBMin(ModulePositionSBHandle, 0);
SetSBMax(ModulePositionSBHandle, 100);
SetSBPosition(ModulePositionSBHandle, 0);
end;