OberonCore
https://forum.oberoncore.ru/

Прокрутка Крысой
https://forum.oberoncore.ru/viewtopic.php?f=2&t=3391
Страница 1 из 4

Автор:  ilovb [ Пятница, 15 Апрель, 2011 13:44 ]
Заголовок сообщения:  Прокрутка Крысой

Мерцает текст при прокрутке колесом мыши. Раздражает.

Проблема, как я понял, в сообщении WM_MOUSEWHEEL.
Т.е. посылается куча этих сообщений и BlackBox их старательно последовательно пытается обработать.

Думаю, что их нужно толкать в буфер и схлопывать.

Вопрос: Будет ли правильным навесить HOOK? Ну и в нем это обрабатывать, а окну посылать обычный скрол. Или есть другое решение?

Автор:  ilovb [ Понедельник, 18 Апрель, 2011 10:08 ]
Заголовок сообщения:  Re: Прокрутка Крысой

В модуле WinApi неправильно описан хэндлер хука.
Должно быть так:
Код:
HOOKPROC* = PROCEDURE (p1: INTEGER; p2: WPARAM; p3: LPARAM): INTEGER;

Автор:  Евгений Темиргалеев [ Понедельник, 18 Апрель, 2011 10:32 ]
Заголовок сообщения:  Re: Прокрутка Крысой

Сталкивался. Если правильно припоминаю, то это универсальный тип (чтобы не описывать все виды хуков). Для винапи нужен только адрес, сигнатура роли не играет...

Автор:  ilovb [ Понедельник, 18 Апрель, 2011 11:01 ]
Заголовок сообщения:  Re: Прокрутка Крысой

Еще мелкий трабл: не могу поставить локальный хук.

Глобальный нормально ставится.

Автор:  ilovb [ Понедельник, 18 Апрель, 2011 11:08 ]
Заголовок сообщения:  Re: Прокрутка Крысой

Код:
MODULE SmartMWheel;

IMPORT WinApi, StdLog, HostWindows;

VAR
   
   thrd: WinApi.HANDLE;
   mhook: WinApi.HHOOK;
   Handler: PROCEDURE(code: INTEGER; wparam: WinApi.WPARAM; lparam: WinApi.LPARAM): INTEGER;
   hinst: WinApi.HINSTANCE;
   
PROCEDURE Do*();
BEGIN
   mhook := WinApi.SetWindowsHookEx(14, Handler, 0, thrd);
   StdLog.Int(mhook);
END Do;

PROCEDURE Undo*;
BEGIN
   IF WinApi.UnhookWindowsHookEx(mhook) = 0 THEN
      StdLog.String("Hook NOT deleted");
   ELSE
      StdLog.String("Hook deleted");
   END;
END Undo;

PROCEDURE HandlerProc(code: INTEGER; wparam: WinApi.WPARAM; lparam: WinApi.LPARAM): INTEGER;
VAR
   wnd: HostWindows.Window;
   msg: WinApi.MSG;
   res: INTEGER;
BEGIN
   
   wnd := HostWindows.dir.First();
   
   CASE wparam OF
      | WinApi.WM_MOUSEWHEEL:
         StdLog.String("Wheel"); StdLog.Ln;
         
         RETURN -1; (*WinApi.CallNextHookEx(WinApi.WM_NULL, code, wparam, lparam);*)
         
   ELSE
         RETURN WinApi.CallNextHookEx(WinApi.WM_NULL, code, wparam, lparam);
   END;
END HandlerProc;

BEGIN
   Handler := HandlerProc;
   thrd := WinApi.GetCurrentThreadId();
   StdLog.Int(thrd);
END SmartMWheel.

SmartMWheel.Do
SmartMWheel.Undo


Что не так делаю?

Автор:  ilovb [ Понедельник, 18 Апрель, 2011 11:10 ]
Заголовок сообщения:  Re: Прокрутка Крысой

Если

mhook := WinApi.SetWindowsHookEx(14, Handler, 0, thrd);

заменить на:

mhook := WinApi.SetWindowsHookEx(14, Handler, 0, 0);

То будет глобальный, и будет работать. А локальный никак

Автор:  Александр Ильин [ Понедельник, 18 Апрель, 2011 12:04 ]
Заголовок сообщения:  Re: Прокрутка Крысой

ilovb писал(а):
Если

mhook := WinApi.SetWindowsHookEx(14, Handler, 0, thrd);

заменить на:

mhook := WinApi.SetWindowsHookEx(14, Handler, 0, 0);

То будет глобальный, и будет работать. А локальный никак

А справку почитать?
Цитата:
The scope of a hook depends on the hook type. Some hooks can be set only with global scope; others can also be set for only a specific thread, as shown in the following table.
Hook Scope
...
WH_MOUSE Thread or global
WH_MOUSE_LL Global only
У вас вместо именованной константы используется число (буу!!) 14, это соответствует WH_MOUSE_LL.

Автор:  ilovb [ Понедельник, 18 Апрель, 2011 12:09 ]
Заголовок сообщения:  Re: Прокрутка Крысой

ТОЧНО!!! ЗАРАБОТАЛО!

Спасибо большое

Автор:  ilovb [ Четверг, 21 Апрель, 2011 08:52 ]
Заголовок сообщения:  Re: Прокрутка Крысой

Еще в модуле WinApi не хватает структуры появившейся в Win2k:
Код:
MouseHookStructEx = POINTER TO RECORD [untagged]
      pt*: WinApi.POINT;
      hwnd*: WinApi.HWND;
      wHitTestCode*: INTEGER;
      dwExtraInfo*: INTEGER;
      mousedata*: INTEGER;
      END;


Это расширение MouseHookStruct с добавленным полем mousedata (в старшем слове хранится информация о прокрутке колесом)

Автор:  Евгений Темиргалеев [ Четверг, 21 Апрель, 2011 09:25 ]
Заголовок сообщения:  Re: Прокрутка Крысой

Чего не хватает в WinApi можно спокойно организовать в дополнительном инт-м модуле.

WinHdrs - дополнительные интерфейсные модули WinAPI --- тут модуль WinApiEx. Можете добавить

Автор:  ilovb [ Четверг, 21 Апрель, 2011 15:33 ]
Заголовок сообщения:  Re: Прокрутка Крысой

Вот родил уродца: ОСТОРОЖНО ЭКСПЕРИМЕТНАЛЬНЫЙ ГОВНОКОД. ПРОВЕРОК ВЫХОДА ЗА ГРАНИЦЫ НЕТ
Код:
MODULE SmartMWheel;

IMPORT WinApi, StdLog, HostWindows, SYSTEM;

TYPE

   MouseHookStructEx = POINTER TO RECORD [untagged]
      pt*: WinApi.POINT;
      hwnd*: WinApi.HWND;
      wHitTestCode*: INTEGER;
      dwExtraInfo*: INTEGER;
      mousedata*: INTEGER;
   END;
      

VAR
   
   thrd, mythrd: WinApi.HANDLE;
   mhook: WinApi.HHOOK;
   Handler: PROCEDURE(code: INTEGER; wparam: WinApi.WPARAM; lparam: WinApi.LPARAM): INTEGER;
   hinst: WinApi.HINSTANCE;
   ticks: INTEGER;
   lpThreadId: INTEGER;
   Stop: BOOLEAN;
   wnd: HostWindows.Window;
   
   bufdelta: INTEGER;
   
PROCEDURE ThreadRoutine(lpThreadParameter: WinApi.PtrVoid): INTEGER;
VAR   
   a: INTEGER;
   Pos, res: INTEGER;
BEGIN
   
   WHILE ~Stop DO
      
      Pos := WinApi.GetScrollPos(wnd.wnd, WinApi.SB_VERT);
      IF bufdelta # 0 THEN
      (*res := WinApi.SetScrollPos(wnd.wnd, WinApi.SB_VERT, y + bufdelta, 1);*)
      res := WinApi.PostMessageW(wnd.wnd, WinApi.WM_VSCROLL, WinApi.SB_THUMBPOSITION + 10000H * (Pos - bufdelta * 5), 0);
      bufdelta:= 0;
      (*a := WinApi.Beep(100,100);*)
      END;
      
      WinApi.Sleep(0);
   END;
   
   RETURN 0;
END ThreadRoutine;
   
PROCEDURE Do*();
BEGIN
   Stop := FALSE;
   mhook := WinApi.SetWindowsHookEx(WinApi.WH_MOUSE, Handler, 0, thrd);
   mythrd := WinApi.CreateThread(NIL, WinApi.NULL, ThreadRoutine, 0, {}, lpThreadId);
END Do;

PROCEDURE Undo*;
BEGIN
   Stop := TRUE;
   IF WinApi.UnhookWindowsHookEx(mhook) = 0 THEN
      StdLog.String("Hook NOT deleted");
   ELSE
      StdLog.String("Hook deleted");
   END;
   StdLog.Int(bufdelta);
END Undo;

PROCEDURE HandlerProc(code: INTEGER; wparam: WinApi.WPARAM; lparam: WinApi.LPARAM): INTEGER;
VAR
   res, delta: INTEGER;
   msg2: WinApi.PtrMOUSEHOOKSTRUCT;
   msg3: MouseHookStructEx;
BEGIN
   
   wnd := HostWindows.dir.First();
   
   CASE wparam OF
      | WinApi.WM_MOUSEWHEEL:
         
         msg3 := SYSTEM.VAL(MouseHookStructEx, lparam);
         
         delta := msg3.mousedata DIV 10000H;
         bufdelta := bufdelta + delta;
         StdLog.String("Wheel"); StdLog.Ln;
         ticks := WinApi.GetTickCount();
         StdLog.Int(bufdelta); StdLog.Ln;
         RETURN -1; (*WinApi.CallNextHookEx(WinApi.WM_NULL, code, wparam, lparam);*)
         
   ELSE
         RETURN WinApi.CallNextHookEx(WinApi.WM_NULL, code, wparam, lparam);
   END;
END HandlerProc;

BEGIN
   
   ticks := 0;
   Handler := HandlerProc;
   thrd := WinApi.GetCurrentThreadId();
   Stop := FALSE;
   
CLOSE
   IF mhook # WinApi.NULL THEN
      Undo
   END;
END SmartMWheel.

SmartMWheel.Do
SmartMWheel.Undo


Можно проверить на WinApi. Говнокод прокручивает без мерцания :lol:

С удовольствием приму советы по доведению этого г до ума

Автор:  ilovb [ Вторник, 03 Май, 2011 15:03 ]
Заголовок сообщения:  Re: Прокрутка Крысой

Победить не удалось. В BlackBox слишком сильно все привязано на инкремент/декремент одной линии. Даже враппер не поможет.

Вообще победить можно, но нужно много править TextViews.

У меня желания пока нет

Автор:  Иван Кузьмицкий [ Вторник, 03 Май, 2011 18:06 ]
Заголовок сообщения:  Re: Прокрутка Крысой

Объясните, пожалуйста, как выглядит упомянутое мерцание при прокрутке колесом? Что-то не наблюдал у себя. Или не туда смотрю.

Автор:  ilovb [ Среда, 04 Май, 2011 08:17 ]
Заголовок сообщения:  Re: Прокрутка Крысой

Вот скриншот из CamStudio

Вложения:
стоп_кадр.png
стоп_кадр.png [ 128.84 КБ | Просмотров: 21106 ]

Автор:  Иван Кузьмицкий [ Среда, 04 Май, 2011 08:37 ]
Заголовок сообщения:  Re: Прокрутка Крысой

На скриншоте смущают размытые пиксели. ББ не занимается размытием, точно говорю :) Может, видео выложите куда-нибудь?

Автор:  ilovb [ Среда, 04 Май, 2011 08:47 ]
Заголовок сообщения:  Re: Прокрутка Крысой

просматривать лучше в замедленном режиме

Вложения:
blik.7z [2.8 МБ]
Скачиваний: 666

Автор:  Сергей Губанов [ Среда, 04 Май, 2011 14:29 ]
Заголовок сообщения:  Re: Прокрутка Крысой

Иван Кузьмицкий писал(а):
На скриншоте смущают размытые пиксели.
ББ рисует посредством GDI. В Windows-7 GDI реализован как обёртка над новым графическим движком. Древние программы в Windows-7 выглядят как новенькие.

Автор:  ilovb [ Среда, 04 Май, 2011 14:40 ]
Заголовок сообщения:  Re: Прокрутка Крысой

У меня Win7.

[оффтоп]: Хорошая ось. Реально хорошая

Автор:  Евгений Темиргалеев [ Среда, 04 Май, 2011 14:59 ]
Заголовок сообщения:  Re: Прокрутка Крысой

ilovb, Вы случайно не про такое "мерцание"?

Вложения:
scr.png
scr.png [ 27.44 КБ | Просмотров: 21085 ]

Автор:  ilovb [ Среда, 04 Май, 2011 15:30 ]
Заголовок сообщения:  Re: Прокрутка Крысой

Да да. Я удивляюсь как Иван не заметил.

Фишка в том, что сообщения Wheel не буферизуются

Собсна вот виновник:
Код:
PROCEDURE WheelScroll (wnd: WinApi.HANDLE; wParam, lParam: INTEGER);
      VAR w: Window; res, lines, delta, keys: INTEGER; msg: Controllers.WheelMsg;
         p: WinApi.POINT;
   BEGIN
      delta := wParam DIV 10000H; keys := wParam MOD 10000H;
      w := ThisWindow(wnd);
      lines := 3;
      res := WinApi.SystemParametersInfoW(104 (*SPI_GETWHEELSCROLLLINES*), 0, SYSTEM.ADR(lines), 0);
      p.x := lParam MOD 65536; p.y := lParam DIV 65536;
      res := WinApi.ScreenToClient(wnd, p);
      msg.x := p.x * w.port.unit; msg.y := p.y * w.port.unit;
      msg.nofLines := 0; msg.op := -1;
      IF lines > 10 THEN   (* scroll pages *)
         INC(w.wheelPos, delta);
         IF w.wheelPos >= 120 THEN
            msg.op := Controllers.decPage;
            DEC(w.wheelPos, 120)
         ELSIF w.wheelPos <= -120 THEN
            msg.op := Controllers.incPage;
            INC(w.wheelPos, 120)
         END
      ELSIF lines > 0 THEN
         INC(w.wheelPos, delta * lines);
         WHILE w.wheelPos >= 120 DO
            msg.op := Controllers.decLine;
            INC(msg.nofLines);
            DEC(w.wheelPos, 120)
         END;
         WHILE w.wheelPos <= -120 DO
            msg.op := Controllers.incLine;
            INC(msg.nofLines);
            INC(w.wheelPos, 120)
         END
      END;
      msg.done := FALSE;
      IF msg.op >= 0 THEN w.ForwardCtrlMsg(msg) END;
      IF ~msg.done THEN (* scroll document *)
         CASE msg.op OF
         | Controllers.decPage:
            w.Scroll(WinApi.SB_PAGEUP, 0, ODD(keys DIV 8), ~ODD(keys DIV 4))
         | Controllers.incPage:
            w.Scroll(WinApi.SB_PAGEDOWN, 0, ODD(keys DIV 8), ~ODD(keys DIV 4))
         | Controllers.decLine:
            WHILE msg.nofLines > 0 DO
               w.Scroll(WinApi.SB_LINEUP, 0, ODD(keys DIV 8), ~ODD(keys DIV 4));
               DEC(msg.nofLines)
            END
         | Controllers.incLine:
            WHILE msg.nofLines > 0 DO
               w.Scroll(WinApi.SB_LINEDOWN, 0, ODD(keys DIV 8), ~ODD(keys DIV 4));
               DEC(msg.nofLines)
            END
         ELSE
         END
(*
         IF lines > 10 THEN   (* scroll pages *)
            INC(w.wheelPos, delta);
            IF w.wheelPos >= 120 THEN
               w.Scroll(WinApi.SBPageUp, 0, ODD(keys DIV 8), ~ODD(keys DIV 4));
               DEC(w.wheelPos, 120)
            ELSIF w.wheelPos <= -120 THEN
               w.Scroll(WinApi.SBPageDown, 0, ODD(keys DIV 8), ~ODD(keys DIV 4));
               INC(w.wheelPos, 120)
            END
         ELSIF lines > 0 THEN
            INC(w.wheelPos, delta * lines);
            WHILE w.wheelPos >= 120 DO
               w.Scroll(WinApi.SBLineUp, 0, ODD(keys DIV 8), ~ODD(keys DIV 4));
               DEC(w.wheelPos, 120)
            END;
            WHILE w.wheelPos <= -120 DO
               w.Scroll(WinApi.SBLineDown, 0, ODD(keys DIV 8), ~ODD(keys DIV 4));
               INC(w.wheelPos, 120)
            END
         END
*)
      END
   END WheelScroll;


Особенно циклы улыбают :D

Буфер конечно не тут должен быть, а в диспетчере над вьюхой.
С другой стороны можно и тут... вот только другие вьюхи потеряют возможность получать детальный Wheel

Страница 1 из 4 Часовой пояс: UTC + 3 часа
Powered by phpBB® Forum Software © phpBB Group
https://www.phpbb.com/