Jump to content


Photo

ScreenMagnifier - IntelliPoint clone?


  • Please log in to reply
17 replies to this topic

#1 ivanw

ivanw
  • Members
  • 13 posts

Posted 27 December 2006 - 01:03 PM

This is a follow up from a previous ScreenMagnifier subject, in which I made a contribution based on what has been accomplished there.
Some ideas about new features are considered and eveyone is welcome to comment on new one as well as implement them.. :wink: ...and share results here of course.
-ivan

Some issues already:[*:25simobr] majkinetor said: I get empty box! ...details? ...ideas?Some features nice to have:[*:25simobr]Laszlo would like improved resizing and anchored magnified area! ...todoHere is the current starting point (was Fri, 29 Dec):
[edit][*:25simobr]Last is on-line at Autohotkey.net upload space
[*:25simobr]View source: sm.ahk.txt or sm.ahk.html (with gvim syntax highlighting)
[*:25simobr]Download: sm.ahk
(open will execute a temp file, ...hit Escape to terminate)
...updated: 22nd April 2007
[/edit]

; "Screen Magnifier" - IntelliPoint clone? {{{

#SingleInstance ignore          ; ignore script if already-running
#MaxHotkeysPerInterval 200      ; need that with the scrollwheel
Process, Priority, , High       ; tell that to Windows Task Manager
OnExit GuiClose                 ; some clean up before leaving

hotkey, Shift,  toggle_resize   ; Script hotkey: resize by corner
hotkey, Alt,    toggle_aliasing ; Script hotkey: antialiasing
hotkey, Space,  toggle_follow   ; Script hotkey: stick window
hotkey, Ctrl,   toggle_pindown  ; Script hotkey: stick area
hotkey, Escape, GuiClose        ; Script hotkey: terminate script

;=============================================================== }}}
; Initialization: Global Variables {{{

  ; Execution parameters - - - - - - - - - - - - - - - - - - - - - -
  delay     := 10               ; display update intervals (ms)

  follow    := true             ; follow mouse pointer - or not
  pindown   := 0                ; keep current zoom area coordinates
  antialize := 0                ; less starcase

  ; Zoom parameters- - - - - - - - - - - - - - - - - - - - - - - - -
  zoom      := 2                ; initial zoom factor
  ZOOMFX    := 1.189207115      ; zoom factor (square square of 2)
  ZOOMFXMAX := 8                ; zoom factor max
  zooming   := false

  ; Action resources - - - - - - - - - - - - - - - - - - - - - - - -
  resizing  := false            ; zoom window resize in progress
  dragFromX := 0                ; resizing corner reference point
  dragFromY := 0                ; ...
  stickX    := 0                ; stuck window reference point
  stickY    := 0                ; ...
  pinX      := 0                ; stuck zoome area reference point

  ; Window coordinates - - - - - - - - - - - - - - - - - - - - - - -
  wox       := 0                ; zoom window origin x
  wwMax     := A_ScreenWidth    ; max width
  ww        := 480              ; initial
  wwMin     := 32               ; min

  woy       := 0                ; zoom window origin y
  whMax     := A_ScreenHeight   ; max height
  wh        := 200              ; initial ...
  whMin     := 16               ; min     ...

  wwD       := 0                ; window Delta (mouse wheel)
  whD       := 0                ; ...

  ; Mouse pointer coordinates - - - - - - - - - - - - - - - - - - - 
  mx        := 0                ; mouse x current position
  my        := 0                ; ...
  mxp       := mx               ; previous
  myp       := my               ; ...

; }}}
; Initialization: Zoom Window handles {{{

  MouseGetPos, mx, my

  ; Zoom window always on top and starts way off screen
  Gui, +AlwaysOnTop  +Owner -Resize -ToolWindow +E0x00000020
  Gui, Show, NoActivate W%ww% H%wh% X-1000 Y-1000, MagWindow

  WinSet, Transparent, 254, MagWindow
  Gui, -Caption
  Gui, +Border











  WinGet, src_id, id
  src_frame := DllCall("GetDC", UInt, src_id)




  WinGet, dst_id, id, MagWindow
  dst_frame := DllCall("GetDC", UInt, dst_id)

  DllCall( "gdi32.dll\SetStretchBltMode"
	 , "uint", dst_frame
	 , "int", 4*antialize)

; First Zoom Window display
  SetTimer, repaint , %delay%	    ; schedule next repaint ;Gosub, repaint
  Gosub, repaint

return
;=================================================================== }}}

; Event handlers: Mouse Wheel {{{

WheelUp::		; zoom in
    if zoom < %ZOOMFXMAX%
	zoom *= %ZOOMFX%
    zooming := true	; triggers update
return

WheelDown::		; zoom out
    if zoom > %ZOOMFX%
	zoom /= %ZOOMFX%
    zooming := true	; triggers update
return

+WheelDown::		; larger
    wwD =  32
    whD =  32
return

+WheelUp::		; smaller
    wwD = -32
    whD = -32
return

;=================================================================== }}}
; Hotkey handlers: follow, aliasing, GuiClose {{{
toggle_follow:		; follow or stick
    if resizing OR pindown
        return
    if follow {
        if(stickX != 0) OR (stickY != 0)
            MouseMove, stickX, stickY
        stickX := wox + ww/2
        stickY := woy + wh/2
	follow := false
    }
    else {
	follow := true
        MouseGetPos, stickX, stickY
        MouseMove, wox + ww/2, woy + wh/2
    }

return

toggle_aliasing:	; aliasing
    antialize := 1-antialize
    DllCall( "gdi32.dll\SetStretchBltMode"
	   , "uint", dst_frame
	   , "int", 4*antialize)



return

toggle_pindown:		; keep current zoomed area coordinates
    if resizing
        return
    pindown := !pindown
return

toggle_resize:		; enter or leave resize by corner
    if pindown
        return
    if !resizing
    {
        resizing  := true
        if follow {
            ; Move pointer to Zoom Window center
            MouseMove, wox + ww/2, woy + wh/2
            ; Remember Zoom Window center
            MouseGetPos, dragFromX, dragFromY
            ; Move to Zoom Window corner
            MouseMove, dragFromX + ww/2, dragFromY + wh/2
        }
        else {
            ; Remember Zoom Area center
            MouseGetPos, dragFromX, dragFromY
            ; Move pointer to Zoom Area corner
            MouseMove, mx + ww/2/zoom, my + wh/2/zoom
        }

    }
    else {
        resizing := false
        ; Restore pointer position
        MouseMove, dragFromX, dragFromY
    }
return

GuiClose:       ; clean up and terminate
   DllCall("gdi32.dll\DeleteDC", UInt,dst_frame)
   DllCall("gdi32.dll\DeleteDC", UInt,src_frame)

Process, Priority, , Normal
ExitApp
;=================================================================== }}}

; repaint: Zoom, follow, rescale and resize {{{
repaint:
    CoordMode,   Mouse, Screen


    if !pindown {
        MouseGetPos, mx, my
        WinGetPos,   wx, wy, ww, wh, MagWindow

        ; Resize by corner -----------------------------------------
        if resizing
        {
            ww  := 2 * (mx - dragFromX)
            wh  := 2 * (my - dragFromY)
            if !follow {	    ; resizze area instead of window
                ww *= zoom
                wh *= zoom
            }
            ; Make it look like pointer is still centered
            mx  := dragFromX
            my  := dragFromY
            zooming := true	    ; triggers update
        }
        ; Resize with mouse wheel ----------------------------------
        else if (wwD != 0) OR (whD != 0)
        {
            ww  += wwD
            wh  += whD
            wwD := 0
            whD := 0
            zooming := true	    ; triggers update
        }

        clip_on_screen()	    ; keep zoom area on screen
    }
    ; Update -------------------------------------------------------
    if pindown OR zooming OR (mx != mxp) OR (my != myp)
    {
        clip_size()		    ; Keep Window min-max
        clip_pos()		    ; Keep Window on screen

        WinMove, MagWindow, ,wox, woy, %ww%, %wh%

        DllCall( "gdi32.dll\StretchBlt"
               , UInt, dst_frame          ; destination frame
               ,  Int, 2                  ; ...x
               ,  Int, 2                  ; ...y
               ,  Int, ww-6               ; ...width
               ,  Int, wh-6               ; ...height
               , UInt, src_frame          ; source frame
               ,  Int, mx - (ww/2 / zoom) ; ...x
               ,  Int, my - (wh/2 / zoom) ; ...y
               ,  Int,       ww   / zoom  ; ...width
               ,  Int,       wh   / zoom  ; ...height
               , UInt, 0xCC0020)          ; dwRop (raster operation)
    }
    ; Remember and schedule update ---------------------------------
    mxp := mx
    myp := my
return

;=================================================================== }}}





clip_on_screen() ; Keep zoom window area on screen {{{
{
    global

    if(mx   < ww/2/zoom)
        mx := ww/2/zoom
    if(mx   > A_ScreenWidth-(ww/2/zoom))
        mx := A_ScreenWidth-(ww/2/zoom)

    if(my   < wh/2/zoom)
        my := wh/2/zoom
    if(my   > A_ScreenHeight-(wh/2/zoom))
        my := A_ScreenHeight-(wh/2/zoom)
}
; }}}
clip_size() ; Keep Zoom Window size within min-max limits {{{
{
    global


    if( ww < 0 )
       ww *= -1
    if( ww < wwMin )
       ww := wwMin
    if( ww > wwMax )
       ww := wwMax

    if( wh < 0 )
       wh *= -1
    if( wh < whMin )
       wh := whMin
    if( wh > whMax )
       wh := whMax
}
; }}}
clip_pos() ; Keep Zoom Window on screen {{{
{
    global

    if follow {                 ; Window near mouse
        wox := mx-ww/2
        woy := my-wh/2
    }
    else {                      ; Window position fixed
        wox := stickX-ww/2
        woy := stickY-wh/2
    }

    if(wox < 0)                 ; window inside screen
        wox = 0
    if(wox >  (A_ScreenWidth-ww))
        wox := A_ScreenWidth-ww
    if(woy < 0)
        woy = 0
    if(woy >  (A_ScreenHeight-wh))
        woy := A_ScreenHeight-wh
}
; }}}

RemoveToolTip: ; hide tooltips {{{
SetTimer, RemoveToolTip, Off
ToolTip

return
;=================================================================== }}}

; vim: syntax=ahk foldmethod=marker


#2 dash

dash
  • Members
  • 54 posts

Posted 27 December 2006 - 06:15 PM

I like it!

But currently the zoom feels "jerky", if you compare it to holomind's scripts, where the zoom is almost fluid...
And it doesnt make a perfect scale, the image is somewhat distorted (i dont use Antialiasing and without it, its very noticible)
Hope you could improve that in your future fixes ^^

p.s. maybe you should refer to the post bellow, since the gui looks almost "identical":

Hi, i experimented a little bit and solved the flicker problem in a way:

the solution is not beatiful, but works.
now the Desktop (original) is copied to the Magnify image to restore the zoomed areas with the original. to make things faster and not repaint the whole screen all the time it only restores the zoomwindow.
so every second there is a full screen refresh to restore errors. also your desktop could have changed.

i sneaked in some hotkeys. so zoom also works with alt-shift-up down, not only mousewheel, and i can toggle antialize with alt-shilft a.

the bmp buffers are not needed here, they come from another script i copied but here the DCs are copied diretly!

I experimented with "Winset Region" and "Gui Show ..size" and "Winmove" but they all flicker. so this kind of doublebuffer works better.

it would be much better, to only change the size of the Magnifier window, but this flickers

i changed the dimensions to variables so you can change the radius easily.

when you comment "SetTimer, Init" and uncomment "SetTimer, ClipWindow", then you can see how slow the "WinSet Region" is.

i guess the "winset region" forces a full refresh/redraw of the Window!

;original by:    holomind
;modified by: Blablabla
;modified again by: holomind ;)
;see more:       http://www.autohotkey.com/forum/topic11700.html
 
  #NoTrayIcon
  OnExit handle_exit
  SetBatchLines, -1

  CoordMode, Mouse, Screen
  zoom      = 2
  antialize = 0
  refresh_delay = 40
  refresh_full  = 1000
  radius = 400
  m_w  := radius  ; magnifiere_width
  m_h  := radius
  m_wh := m_w / 2 ; half
  m_hh := m_h / 2 

  Gui,  +AlwaysOnTop -Resize -Caption -Border +ToolWindow -SysMenu +E0x00000020
  Gui,Show, x0 y0 w%A_ScreenWidth% h%A_ScreenHeight% , Magnifier 

  WinGet MagnifierID, id  ,Magnifier
  WinSet, Transparent , 254, Magnifier

  ;retrieve the unique ID number (HWND/handle) of that window
  WinGet, SourceWinID, id
 
  hdc_source_frame := DllCall( "GetDC", UInt, SourceWinID )
  hdc_target_frame := DllCall( "GetDC", UInt, MagnifierID )
  
  SetTimer, Init    , %refresh_full% ; force full refresh 1 each second
  SetTimer, Repaint , %refresh_delay%
;  SetTimer, ClipWindow, 500
  Gosub, Init
  Gosub, Repaint
return

Init: 
    DllCall("gdi32.dll\BitBlt", UInt,hdc_target_frame
          , Int     , 0
          , Int     , 0
          , Int     , A_ScreenWidth
          , Int     , A_ScreenHeight
          , UInt    , hdc_source_frame
          , Int     , 0
          , Int     , 0
          , UInt    , 0xCC0020) ; SRCCOPY

Return

Repaint: 

   MouseGetPos, start_x, start_y             ;  position of mouse 
   now_x := start_x - m_wh
   now_y := start_y - m_hh
  
   if  now_x <> old_x       ; only repaint if mouse is moved ?
   {
    ; redraw original desktop
    DllCall("gdi32.dll\BitBlt", UInt,hdc_target_frame
          , UInt     , old_x 
          , UInt     , old_y 
          , Int     , m_w 
          , Int     , m_h 
          , UInt    , hdc_source_frame
          , UInt     , old_x 
          , UInt     , old_y 
          , UInt    , 0xCC0020) ; SRCCOPY
   }

   DllCall("gdi32.dll\StretchBlt", UInt,hdc_target_frame
          , Int     , now_x
          , Int     , now_y
          , Int     , m_w
          , Int     , m_h
          , UInt    , hdc_source_frame
          , Int     , start_x - m_wh / zoom
          , Int     , start_y - m_hh / zoom
          , Int     , m_w / zoom
          , Int     , m_h / zoom 
          , UInt    , 0xCC0020) ; SRCCOPY
   

   old_x := now_x
   old_y := now_y

Return

ClipWindow:
   WinSet, Region, %now_x%-%now_y% W%m_w% H%m_h%  , Magnifier
Return

GuiClose:
handle_exit:
#x::
   DllCall("gdi32.dll\DeleteDC", UInt,hdc_target_frame )
   DllCall("gdi32.dll\DeleteDC", UInt,hdc_source_frame )
ExitApp

!+a::
  antialize := 4 - antialize
  DllCall( "gdi32.dll\SetStretchBltMode", "uint", hdc_target_frame, "int", antialize )  ; Antializing ?
Return

!+WheelUp::         ; Alt+Shift+WheelUp to zoom in
!+Up::
If zoom != 16
      zoom *= 2
Return

!+WheelDown::      ; Alt+Shift+WheelUp to zoom out
!+Down::
  If zoom != 2
      zoom /= 2
Return 



#3 ivanw

ivanw
  • Members
  • 13 posts

Posted 27 December 2006 - 06:17 PM

This version has the new resize feature:

The idea is to move the mouse pointer to the lower right corner of the zoom window so we can resize it as usual.

You have to hit the Shift key once to enter resizing mode. I choose this key because it does not hurt most application receiving current keyboard focus.
Pressing Shift once more terminates resizing.

Current Features (was 27 Dec 2006):[*:if1wqk0q]Min WxH is currently initialized to 32x16
[*:if1wqk0q]Max WxH is the screen size
[*:if1wqk0q]Previous Shift-ScrollWheel-resize still works as a means to keep current aspect ratio.
[*:if1wqk0q]resizing a stuck Zoom Window (with the spacebar) moves the pointer near the window
[*:if1wqk0q]Escape will terminate the script[edit][*:if1wqk0q]Last is on-line at Autohotkey.net upload space
[*:if1wqk0q]View source: sm.ahk.txt
[*:if1wqk0q]Download: sm.ahk
(open will execute a temp file, ...hit Escape to terminate)
[/edit]

; "Screen Magnifier" - IntelliPoint clone? {{{

#SingleInstance ignore          ; attempts to launch an already-running script will be ignored
#MaxHotkeysPerInterval 200	   ; you need that with the scrollwheel
Process, Priority, , High       ; tell that to Windows Task Manager
OnExit handle_exit              ; some clean up before leaving

hotkey, Space,  toggle_follow   ; Script hotkey: stick magnified display in place
hotkey, Shift,  toggle_resize   ; Script hotkey: enter/leave resize by corner
hotkey, Escape, GuiClose        ; Script hotkey: terminate script

;========================================================================= }}}
; INITIALIZATION: Variables and Zoom Window handles {{{

; Global Variables

  delay     := 10               ; Display update intervals (ms)

  resizing  := false            ; magnification window resize in progress
  dragFromX := 0
  dragFromY := 0

  follow    := true             ; magnification window follows mouse pointer - or not


  ZOOMFX    := 1.189207115      ; increase/decrease zoom factor (square of square of 2)
  zoom      := 2                ; initial zoom factor
  antialize := 1                ; less starcases

  wox       := 0		; Zoom Window origin x
  wwMax     := A_ScreenWidth	; max width
  ww        := 480              ; initial
  wwMin     := 32               ; min

  woy       := 0		; Zoom Window origin y
  whMax     := A_ScreenHeight	; max height
  wh        := 200              ; initial ...
  whMin     := 16               ; min     ...



  mx        := 0		; mouse x current position
  my        := 0		; mouse y ...
  mxp       := mx		; ........previous
  myp       := my		; ........previous


  wwD       := 0		; Window width  Delta (changed by mouse wheel)
  whD       := 0		; Window height Delta (handled by next Repaint)

; Zoom Window

  MouseGetPos, mx, my

  Gui, +AlwaysOnTop  +Owner -Resize -ToolWindow +E0x00000020
  Gui, Show, NoActivate W%ww% H%wh% X-1000 Y-1000, MagWindow ; starts way off screen

  WinSet, Transparent, 254, MagWindow
  Gui, -Caption
  Gui, +Border

  WinGet, PrintSourceID, id
  hdd_frame := DllCall("GetDC", UInt, PrintSourceID)

  WinGet, PrintScreenID,  id, MagWindow
  hdc_frame := DllCall("GetDC", UInt, PrintScreenID)
  if(antialize != 0)
      DllCall("gdi32.dll\SetStretchBltMode", "uint", hdc_frame, "int", 4*antialize)

; First Zoom Window display
Gosub, Repaint

return
;============================================================================= }}}
; Event Handlers: Mouse Wheel, Shift key and Exit {{{

WheelUp::       ; zoom in
  if zoom < 4
      zoom *= %ZOOMFX%
return

WheelDown::     ; zoom out
  if zoom > %ZOOMFX%
      zoom /= %ZOOMFX%
return

+WheelDown::	; larger
  wwD =  32
  whD =  32
; Gosub, Repaint
return

+WheelUp::	; smaller
  wwD = -32
  whD = -32
; Gosub, Repaint
return

toggle_follow:
    if resizing
	return
    follow := !follow
return

GuiClose:
handle_exit:
   DllCall("gdi32.dll\DeleteDC"    , UInt,hdc_frame )
   DllCall("gdi32.dll\DeleteDC"    , UInt,hdd_frame )
Process, Priority, , Normal
ExitApp

;============================================================================= }}}
; Function toggle_resize: Enter or leave corner toggle_resize {{{
toggle_resize:
    if !resizing {
	; Center pointer position
	MouseMove, wox + ww/2, woy + wh/2
	; Remember pointer position
	MouseGetPos, dragFromX, dragFromY
	; Move to Zoom window corner
	MouseMove, dragFromX + ww/2, dragFromY + wh/2
	resizing  := true
    }
    else {
	resizing := false
	; Restore pointer position
	MouseMove, dragFromX, dragFromY
    }
return
;============================================================================= }}}
; Function Repaint: Zoom, follow, rescale and resize {{{
Repaint:
    CoordMode,   Mouse, Screen
    MouseGetPos, mx, my
    WinGetPos,   wx, wy, ww, wh, MagWindow

    ; Drag Zoom Window size
    if resizing
    {
	ww  := 2 * (mx - dragFromX)
	wh  := 2 * (my - dragFromY)
	; Make it look like pointer is still at Zoom Window center
	mx  := dragFromX
	my  := dragFromY
    }
    else if (wwD != 0) OR (whD != 0)
    {
	ww  += wwD
	wh  += whD
	wwD := 0
	whD := 0
    }

    if (resizing) OR (mx != mxp) OR (my !- myp)
    {
	; check width limits
	if( ww < 0 )
	   ww *= -1
 	if( ww < wwMin )
 	   ww := wwMin
 	if( ww > wwMax )
 	   ww := wwMax

	; check height limits
 	if( wh < 0 )
 	   wh *= -1
 	if( wh < whMin )
 	   wh := whMin
 	if( wh > whMax )
 	   wh := whMax

        DllCall( "gdi32.dll\StretchBlt"
                , UInt, hdc_frame
                , Int , 2                       ; nXOriginDest
                , Int , 2                       ; nYOriginDest
                , Int , ww-6                    ; nWidthDest
                , Int , wh-6                    ; nHeightDest
                , UInt, hdd_frame               ; hdcSrc
                , Int , mx - (ww / 2 / zoom)    ; nXOriginSrc 
                , Int , my - (wh / 2 / zoom)    ; nYOriginSrc 
                , Int , ww / zoom               ; nWidthSrc 
                , Int , wh / zoom               ; nHeightSrc 
                , UInt, 0xCC0020)               ; dwRop (raster operation)

       if follow OR resizing {
	   wox := mx-ww/2
	   woy := my-wh/2
           WinMove, MagWindow, ,wox, woy, %ww%, %wh%
       }

        mxp = mx
        myp = my
    }
    SetTimer, Repaint , %delay%			; schedule next repaint
return

;============================================================================= }}}



#4 ivanw

ivanw
  • Members
  • 13 posts

Posted 27 December 2006 - 07:30 PM

dash, I could not read your message as we were posting about at the same time :wink:

You are right, holomind's rendering is better. His script was my starting point. I just forgot to to check this aspect after (over)simplifing Dll calls.

I'll try to come with a new bundle unless someone finds a merge before I do.

#5 holomind

holomind
  • Members
  • 341 posts

Posted 28 December 2006 - 06:25 PM

hi, nice to see the magnifier gets modified and optimized ;)

if it flickers you have a problem with repainting whole windows which is forced by windows it self. when windows detects changes to the current window, it sends a "repaint(region)" to this window and this takes time.

if you dont need the target window you should remove it. it slows down things very dramatic. the doublebuffer (or copying the desktop into an image and paint onto this) is quite smooth, but you also have a strong "lag". so its not so good either.

i now own an apple/mac. so i didnt post much new akh-scripts as all these tweaks (like magnifier or expose) are built into osx and implemented perfectly ;) os-x is bad for autohotkey *lol*.

to give you new ideas, in os-x (10.4) you have global zoom which is amazing, its the thing i always wanted to have with my magnifier tool but in osx this is nearly perfect.

a) you have simple usage. simply press "ctrl" and then scroll the mouse to zoom the region around the mouse. (you also can choose antialze or not) .
B) you move your mouse if you need another region

the big difference in osx compared to windows-xp is, that the desktop and all windows are already textures in an opengl-world. and are rendered with opengl already. so zooming only changes the factor for projection and the speed is identical if zoomed or not.
in the gdi version you first paint on the desktop (hdc) and then zoom it later, there is no easy way to redirect the desktop to another source.
copying hdc to another hdc (bitblt) is still much slower than changing distance in opengl.

in windows-vista a zooming similar to os-x will be possible as the win-fx (avalon) is sort of a clone of the opengl enging (window-manager) in os-x. (but it will be based on direct-x i think).

there is still a chance to redirect the whole desktop and all windows to an virtual hdc. if you install an virtual-display-driver which is for example used in the new vnc-server (special video.dll) or in drivers for external usb-vga cards. in this case the desktop is painted invisible to an virtual buffer. (an bmp in memory) and then can be painted to the real deskop (visible) with bitblts. (or better would be opengl). with this technique one could kind of simulate xgl. compiz is some kind of redirecting painting of windows to a texture and then render it with opengl as a 3d-world, where you only use 2d as you always watch your desktop in 90degree angle to get no distortion.

also virtual desktopmanagers work much better in os-x (expose is a special version) as all windows live/exist as real textures and dont need to be redrawn when windows overlap.
windows-xp kind of has no backbuffer for windows but only 1 (in words one) desktop which is painted over and over again.
in vista the windows also will be textures and so you can funny things like expose (called flip 3d ;) and taskbar-preview.

happy new year...

#6 ivanw

ivanw
  • Members
  • 13 posts

Posted 28 December 2006 - 08:57 PM

Thanks holomind for your remarks. I could not find a solution to the flicker issue Yet. Although it would be better to have flicker-free rendering, I think this light version has the advantage of simplicity. Depending on hardware capabilities, it may prove usable - or not! I use it with a mid-range ATI X800 with a Pentium D 820 and, although I prefer IntelliPoint rendering smoothness, this one is an acceptable replacement when you don't want to depend on an MS mouse.

Still looking for an improvement, but I have no Window graphics experience... It would be so easy to BitBlt on the root window of an X server! I found something about StretchBlt usage or picturebox but I have no idea whether I should persist?

In the mean time, I uploaded a version with a new feature that keeps the zoom window inside the screen area:[*:20uuaj3p]sm.ahk on AutoHotkey.netStill looking for a better BitBlt...

#7 holomind

holomind
  • Members
  • 341 posts

Posted 28 December 2006 - 09:08 PM

.. It would be so easy to BitBlt on the root window of an X server! I found something about StretchBlt usage or picturebox but I have no idea whether I should persist?


hmm, gdi and gdiplus have the function bitblt ??? and the root window you are talking seems to be the desktop in windows (hdc with number 0)
get_hdc(0). there should not be a big difference here between linux and windows. (bespite of and x-server works completeley different internally).

bitblt itself is relatively fast (and partly accelerated by hardware as 2d functions are also speed up in hardware and not only 3d games or video).
it gets pretty slow if you copy big regions (big difference between zooming 100x100 px vs. fullscreen 1024x768! ) also strechbit is slower and antializing, as the cpu has do to some calculations to strech things.
if you do streches in opengl its very optimized and very fast.

...

i managed to do some simple opengl experiments with euphoria language, this would be the way to go. i wonder which technique the ms-mouse software uses, (but i guess its direct-x).

#8 ivanw

ivanw
  • Members
  • 13 posts

Posted 29 December 2006 - 05:05 PM

Still no flicker-free solution but some evolutions:
o Screen limits are now considered while dealing with both source and destination windows.
o When follow-mouse is disabled, resizing is based on the source area instead of the zoom window.
o zoom area pin-down (an idea from Laszlo to magnify a chess timer)

TODO:
o Make this usable! It's just way too complicated right now.
o And something is missing to make pin-down usable: The script steals its hotkeys from other applications while it is running. Some input suspend behavior must be implemented :roll:


Current Features (29 Dec 2006):

[*:1h4826jl]ScrollWheel - Zoom in/out
[*:1h4826jl]Shift-ScrollWheel - Resize (preserving aspect ratio)
[*:1h4826jl]Shift - Toggles resize (Zoom Window if follow is on, Zoom Area otherwise)
[*:1h4826jl]Spacebar - Toggles follow mouse (jumps back to both locations)
[*:1h4826jl]Ctrl - Toggles pin-down (fixes Zoom Area where it is)
[*:1h4826jl]Alt - Toggles antialiasing (not always ...?)
[*:1h4826jl]Escape - Terminates script
[*:1h4826jl]Min WxH = 32x16
[*:1h4826jl]Max WxH = screen size
-
[*:1h4826jl]Last version on-line at Autohotkey.net upload space
[*:1h4826jl]View source: sm.ahk.txt
[*:1h4826jl]Download: sm.ahk
(Open will execute a temp file, ...hit Escape to terminate)

#9 holomind

holomind
  • Members
  • 341 posts

Posted 29 December 2006 - 11:21 PM

I experimented a bit with your script and the main reasons for flicker (its not really flicker) is that the WinMove and the StrechBlt are not in sync.

this means, while the strechblt copies the pixels to the mag-window the windows-os is busy moving this window, which results in a jumpy behavior or even looking like shaking and reverse movement.

it would be quite easy to sync them, when one could have a WinMoveWait,, MagWindow. which pauses until the winmove is finished. but window-os is kind of multithreaded and eventbased so the window-repaint is done "on demand" and not predictable.
perhaps somebody has another idea how to sync them.

unfortunately wingetpos does not return the "real" position but the "wanted" position of the window. so its cheating and returns the target-position of the window. because if one could "catch" the real position while moving one could add some offset to bitblt and paint on the "correct" possition.

searching for a way to copy screenregions with open-gl or direct-x i found 2 magnifier apps which do exactly what you try with your ahk script. you might try them:

Magnifying Glass Pro is very smooth and has fast repaint. (but if you choose the "right" options like antialize and transparency and big enough magnifier, you can get an "jumping" effect very similar to our ahk-script. which shows this is a very problem of the os itself and how windows are moved and repainted. but using the right options the lag is very minimal!
it seems it uses gdi(plus) for zooming and not directx, as zooming flashvideo could be more smooth. but the effect of rotating the zoomed area is a nice gimmic (but only a gdiplus function rotate... also not really useful bespite 90degree rotate if you use an external monitor flipped)
the nice thing is having an magnified cursor, and also to be able to use the mouse "normal" in zoomed mode. also mouseshake is a nice gimmic to activate the magnifier.

another one is (perhaps using directx)
virtual magnifier
which is free (gpl) and comes with source-code (its pascal for windows and linux)
hmm, this one seems to be kind of "fake", its like zooming an screenshot. as you exit the program on click. also the image is not updated in zoom mode. but they plan an direct-x mode, also antialize is not enabled.

in the ahk scripts are some syntax errors, which caused the script not to do what you might expect.

  if pindown OR zoomChanged OR (mx != mxp) OR (my != myp)
must be != and not !-

   mxp := mx
   myp := my
needs := and not = , so the value is copied and not the "pointer".

#10 holomind

holomind
  • Members
  • 341 posts

Posted 29 December 2006 - 11:28 PM

[*]Alt - Toggles antialiasing (not always ...?)


this behavior comes from the way strechblt does antializing. there are some funny situaltions where the antialize does not "kick in". if you have a bitmap in your strechblt region then normally you also get antialize. if its text-only you might get direct pixels which are not antialized. i didnt find a way to "force" it antializing. (perhaps you could do it but then i guess it would not be accelerated in a good way.) also you have 2 options for antialize. like "4" is halfmode and "2" is nearest neighbour (2 is much faster, but not as smooth).

#11 ivanw

ivanw
  • Members
  • 13 posts

Posted 30 December 2006 - 12:49 AM

Thanks holomind, I'm just starting to cope with those = and := pointer/value oriented operators ;) This and the !- error forced me to reconsider some state/transitions oddities concerning pointer warp, resize and whether to repaint or not. The refresh timer makes this script multithreaded after all and a wrong placement of state variables like follow or resizing can make the window shaky. Hopefully it looks a little better with these fixes. (on-line file updated)

I did find some efficient tools but I definitely want to stick with AutoHotkey.

The antialiazing is not something important to me, it's just there for who cares...

And surely, I could do better if I was not as ignorant of Windows graphics... Java is my refuge for the time being and I intend to hide there as long as I can ;)

#12 holomind

holomind
  • Members
  • 341 posts

Posted 30 December 2006 - 01:09 AM

you can also try to optimize the usage of winmove and only call it when it really needs to change

; Update -------------------------------------------------------
    if pindown OR zooming OR (mx != mxp) OR (my != myp)
    {
        clip_size()		    ; Keep Window min-max
        clip_pos()		    ; Keep Window on screen

        WinMove, MagWindow, ,wox, woy, %ww%, %wh%
   }
        DllCall( "gdi32.dll\StretchBlt"
               , UInt, dst_frame          ; destination frame
               ,  Int, 2                  ; ...x
               ,  Int, 2                  ; ...y
               ,  Int, ww-6               ; ...width
               ,  Int, wh-6               ; ...height
               , UInt, src_frame          ; source frame
               ,  Int, mx - (ww/2 / zoom) ; ...x
               ,  Int, my - (wh/2 / zoom) ; ...y
               ,  Int,       ww   / zoom  ; ...width
               ,  Int,       wh   / zoom  ; ...height
               , UInt, 0xCC0020)          ; dwRop (raster operation)
    

as you want to update your screen all the time and not only when you move the mouse. and you dont want to move the magnifier until the mouse moves.

maybe winmove to the same position as it is is skipped, but in my experience winmove forces a repaint of the window and slows down things. so i try to use/call it as seldom as possible.

you even could use different timers (threads) for moving the magnifier and repainting the content. (as they are out of sync anyways). this way you could slow down the refreshrate for moving and keep the bitblt fast.

also
SetTimer, repaint , %delay%	    ; schedule next repaint
already triggers a "loop" and only needs to be called once and not inside the loop (but it does not hurt either).

SetTimer calls the specified function "each" x milliseconds and not only once.

but i experienced that you dont have parallel threads and the function is only executed once even if the functions needs longer to complete than then next SetTimer call.
(as i understand chris, the programmer of ahk, threads are "simulated" and are processed in a row and not really parallelized).

if you want to stop the SetTimer function to call your function all the time you can stop the "loop" by calling
SetTimer, repaint, Off

("Off" clears the Timer).

in practice you could change the
; First Zoom Window display
Gosub, repaint

into
; Start Zoom Window display (loop)
  SetTimer, repaint , %delay%	    ; schedule next repaint

and remove the SetTimer inside the "repaint:" -function.

i guess i didnt understand SetTimer well back then when i wrote the magnifier...

#13 holomind

holomind
  • Members
  • 341 posts

Posted 30 December 2006 - 07:25 AM

I created a new version which improves the refresh/lag issue.

see the wiki with the code:
ScreenMagnify_IPClone v1.0

(you can easily create an wiki account and then edit the page, its recommened to use the same nickname in the wiki, look into the real-expose-clone thread to see how versions in wiki work, ... each time you save the wiki-page you create a new version automatically and cant loose old versions).

The trick now is, to have an alternative repaint mechanism, when the mouse moves, (as this causes the jumping). it then restores the old temp image and then paints directly onto gui:2 without the bad winmove. you actually have a gui which is fullscreen and only paints on the region the magnifier sits.
the magnifier is hidden (transparent) so it does not interfere.
when the mouse stops the magnifier is activated again to have the fancy features for mousewheel etc. also the alternate method can create artefacts on the screen. (eg. if you do alt-tab while moving your mouse).

i also did some minor optimizations like the SetTimer.

The changesize is now broken, as it now uses the alternate painting method.
it would be better to simply resize it with the mousewheel.
(normal mousewheel = change zoom)
(shift mousewheel = change size of aim_window (MagWindow)
also shift should not be sticky, but only active while resizing.

#14 tic

tic
  • Members
  • 1902 posts

Posted 22 April 2007 - 08:42 PM

I've had a quick read through your code and was wondering how you allow the cursor to select through the GUI, as in you can click on the desktop and not the GUI despite your GUI being on top

#15 ivanw

ivanw
  • Members
  • 13 posts

Posted 22 April 2007 - 10:15 PM

I've had a quick read through your code and was wondering how you allow the cursor to select through the GUI, as in you can click on the desktop and not the GUI despite your GUI being on top

I'm not sure which version you are talking about as holomind did something completely different concerning the magnifying window.

Mine is a very lightweight version as long as there is only a rendering GUI window involved which lets mouse events pass through. Nothing is done for a smooth rendering (like double buffering) for the sake of simplicity and CPU preservation.

(I've updated my top-most post and its linked files.)