Page 1 sur 2

Mettre un timeout sur une fenêtre

Publié : ven. 22/janv./2016 14:40
par Marc56
Hello,

À la demande des nombreux (3... :mrgreen: ) utilisateurs de mon petit launcher, je suis en train de mettre au point une méthode pour auto escamoter lentement la fenêtre au bout d'un certain temps d'inactivité.

Fonctionnement:
  • La fenêtre peut être déplacée n'importe où à tout moment.
  • Au bout de 3 secondes d'inactivité, elle glisse lentement hors écran vers la droite
  • 1 seconde après elle revient rapidement à la place où elle était dernièrement.
  • Chaque fois qu'on fait quelque chose sur la fenêtre le timeout se remet à 5 secondes
Techniquement, j'ai réalisé ceci:

Code : Tout sélectionner

; AutoHide 001 - TEST
; Auto hide a window when nothing happens above 
; Slowly scrolled off-screen on the right
; (C)Marc56 - 2015-01-22

EnableExplicit

Enumeration 
    #Window_0
    #Check_Second
    #Timeout
EndEnumeration

ExamineDesktops()

OpenWindow      (#Window_0, DesktopWidth(0) - 130, 0 , 100, 600, "", #PB_Window_SystemMenu | #PB_Window_SizeGadget)
AddWindowTimer  (#Window_0, #Check_Second,    1000)
AddWindowTimer  (#Window_0, #Timeout,         3000)



Procedure ShowEvent()
    Debug FormatDate("%ss", Date())    
EndProcedure



Procedure ResetTimer()
    Debug "Reset Timeout 5s"
    RemoveWindowTimer(#Window_0, #Timeout)
    AddWindowTimer(#Window_0, #Timeout, 3000) 
EndProcedure



Procedure AutoHide()
    Debug "Timeout done: Auto hide window" 
    Protected i
    Protected x = WindowX(#Window_0)
    Protected d = DesktopWidth(0) - x

    For i = 1 To d + 130
        ResizeWindow(#Window_0, x + i, #PB_Ignore, #PB_Ignore , #PB_Ignore)
        Delay(10)
    Next i
    
    Delay(1000)
    ResizeWindow(#Window_0, DesktopWidth(0) + 150, #PB_Ignore, #PB_Ignore , #PB_Ignore)
    
    For i = d + 130 To 1 Step -1
        ResizeWindow(#Window_0, x + i, #PB_Ignore, #PB_Ignore , #PB_Ignore)
        Delay(5)
    Next i      
EndProcedure


BindEvent(#PB_Event_Timer,          @ShowEvent(),   #Window_0, #Check_Second)
BindEvent(#PB_Event_Timer,          @AutoHide(),    #Window_0, #Timeout)

BindEvent(#PB_Event_ActivateWindow, @ResetTimer(),  #Window_0)
BindEvent(#PB_Event_RightClick,     @ResetTimer(),  #Window_0)
BindEvent(#PB_Event_LeftClick,      @ResetTimer(),  #Window_0)
BindEvent(#PB_Event_GadgetDrop,     @ResetTimer(),  #Window_0)
BindEvent(#PB_Event_SizeWindow,     @ResetTimer(),  #Window_0)
BindEvent(#PB_Event_MoveWindow,     @ResetTimer(),  #Window_0)

Repeat : Until WaitWindowEvent(50) = #PB_Event_CloseWindow


; -- Version « à l'ancienne »
; Repeat
;     Select WaitWindowEvent(10)
;             
;         Case #PB_Event_Timer
;             Select EventTimer()
;                 Case #Check_Second
;                     ShowEvent()
;                 Case #Timeout
;                     AutoHide()
;             EndSelect
;             
;         Case #PB_Event_ActivateWindow, 
;              #PB_Event_RightClick,
;              #PB_Event_LeftClick,
;              #PB_Event_GadgetDrop,
;              #PB_Event_SizeWindow,
;              #PB_Event_MoveWindow
;             ResetTimer()
;             
;         Case #PB_Event_CloseWindow
;             End
;             
;     EndSelect
; ForEver

End 
(Version avec Bindevent ou standard fonctionnent pareil)
(PS. J'aime bien le code PUR BASIC de préférence, c'est à dire sans appel direct aux API, sans pointeurs etc. Lisible quoi :P )

Techniquement, je remet à zéro le timeout (ici 3 secondes) si la fenêtre a été déplacée, si on a cliqué dessus avec le bouton droit ou gauche ou lâché un objet dessus (j'ai oublié les menus)

Ça fonctionne, mais je je me demande, s'il est possible de simplifier ?
Par exemple une méthode disant: s'il ne se passe rien pendant 3 secondes, alors on déplace la fenêtre.
NB: Je ne peux pas dire "aucun évènement" car il y a toujours plusieurs timers actifs pour gérer l'affichage de l'heure.

Deuxième question: J'aimerais pouvoir arrêter le déplacement en cliquant sur la fenêtre, mais sachant que pour faire un déplacement doux, j'utilise une boucle, cela ne fonctionne pas. Je dois attendre la fin. Je cherche une idée ?

Suggestions, idées bienvenues
:)

Re: Mettre un timeout sur une fenêtre

Publié : ven. 22/janv./2016 15:10
par falsam
[Windows 10 Pro] [PB 5.40 x86]

Hello Marc?

Hum hum .... il y a un comportement étrange. La fenêtre disparaît mais revient à peine sur le bord droit de l'écran. Peut etre que quelqu'un d'autre peut confirmer.

Re: Mettre un timeout sur une fenêtre

Publié : ven. 22/janv./2016 15:14
par Marc56
[W10 standard] [PB 5.40 x64] [Ecran 1920x1080]

Ça fonctionne, mais si je clique sur la fenêtre pendant qu'elle se déplace, elle revient parfois n'importe où. :?

Je pense que je devrais faire un UnbindEvent() sur tous les Events (sauf clic gauche) dès qu'elle bouge, ça peut venir de là?
La fenêtre disparaît mais revient à peine sur le bord droit de l'écran
Je vais tester sur un XP pour voir :o

Edit: Test fait sur un XP Pro en VM (VirtualBox) en 1024x768: ça fonctionne :wink:
Aurais-tu deux écrans ? ou une résolution bizarre ? un facteur de zoom sur la résolution ?
J'utilise la fonction normale DesktopWidth(0) pour récupérer la largeur du bureau.

Re: Mettre un timeout sur une fenêtre

Publié : ven. 22/janv./2016 15:47
par falsam
Marc56 a écrit :Je vais tester sur un XP pour voi
Comme je l'ai indiqué je suis sous environnement Windows 10.
Marc56 a écrit :Aurais-tu deux écrans ? ou une résolution bizarre ? un facteur de zoom sur la résolution ?
Un seul écran pour ce test avec une résolution de 1920 x 1080.

J'ai refait ce test et en fait j'ai cette erreur quand je clique dessus quand la fenêtre réapparaît. C'est ce que j'ai du faire la première fois.

Re: Mettre un timeout sur une fenêtre

Publié : ven. 22/janv./2016 18:32
par Ar-S
Pour un de mes softs j'utilisais la localisation du curseur de la souris. Ainsi lorsqu'il s'approchait de la zone de la fenêtre, le soft apparaissait, si la souris s'éloignait, la fenêtre se cachait.
Ainsi pas besoin de timer, tu bindevent seulement un GetCursorPos_
Tu cherches à faire plus simple, je trouve ça plus simple ;)
Je pense que la barre des taches fonctionne comme ça lorsque les gens cochent "cacher automatiquement".

Re: Mettre un timeout sur une fenêtre

Publié : sam. 23/janv./2016 10:21
par Marc56
Ar-S a écrit :... GetCursorPos_
Intéressant, Merci Ar-S. Je vais voir.

Quelle différence entre GetCursorPos_ (API) et WindowMouseX() (et Y) de PB ?

PS. Il semble que GetCursorPos_ puisse donner une info fausse dans certains cas:

'Use GetPhysicalCursorPos instead if you want your application to get a consistent value when the cursor is moved over all applications on the screen. Otherwise, it will return something different for applications that are scaled by Windows (whose dpiaware setting in their manifest is set to false). '

https://msdn.microsoft.com/fr-fr/librar ... 85%29.aspx

(Je me méfie de l'utilisation systématique des API directement : certaines ont évoluées (mais google continue à référencer celles les plus demandées): je préfère utiliser la fonction native choisie par le programmeur qui a normalement suivi les versions avant d'en encapsuler une)

:wink:

Re: Mettre un timeout sur une fenêtre

Publié : sam. 23/janv./2016 17:21
par nico
Le comportement est étrange, car même si le curseur est sur la fenêtre, celle-ci va disparaître, hyper frustrant. Par contre je ne la vois pas réapparaître.

Pour avoir fait ce genre d'effet, voici les problèmes que j'ai rencontrés:

- Le décalage de la fenêtre sur la droite pose problème si on a deux écrans, elle va donc s'afficher sur le deuxième écran.

- Quand on fait disparaître une fenêtre, ça va, par contre si on l'a fait réapparaître et qu'on utilise une boucle, celle-ci n'est plus rafraîchit donc la fenêtre apparaît mais sans les gadgets, ils apparaissent tout d'un coup une fois sortie de la boucle, en plus je crois que le fond de la fenêtre sera toujours celui par défaut même si tu mets une couleur de fond au moment de la faire réapparaître.

Si je devais le refaire aujourd'hui, j'utiliserais la transparence.

Re: Mettre un timeout sur une fenêtre

Publié : sam. 23/janv./2016 20:29
par nico
Je te propose de réaliser cette fonction si tu veux.

Re: Mettre un timeout sur une fenêtre

Publié : dim. 24/janv./2016 17:24
par nico
Il y aura pas un problème avec cette façon de faire, si je suis en train de taper du texte dans un éditeur, la fenêtre va apparaître toute seule?

Re: Mettre un timeout sur une fenêtre

Publié : lun. 25/janv./2016 7:01
par Marc56
Merci pour les idées et suggestions. :wink:

Ce n'est pas une fonction d'écran de veille que je fais, mais je fais en sorte que le fenêtre disparaisse si on n'y fait rien pendant un certain temps. Type de fonction utilisée par les launchers ou les gestionnaires de presse-papier multiples. On doit pourvoir utiliser les autres applications indépendamment.

Je ne peux pas jouer sur l'inactivité total de la fenêtre car elle a un timer pour afficher l'heure.

D'où la suite d'évènements qui réactivent et qui fonctionne (sauf que cela ne fonctionne plus dès que la fenêtre a commencée à bouger)

Code : Tout sélectionner

         Case #PB_Event_ActivateWindow,
              #PB_Event_RightClick,
              #PB_Event_LeftClick,
              #PB_Event_GadgetDrop,
              #PB_Event_SizeWindow,
              #PB_Event_MoveWindow
             ResetTimer()
Cependant, il est plus simple de tester si la souris est sur la zone de la fenêtre. Donc je vais simplifier. :)

Elle devra réapparaitre si je met la souris sur le bord de l'écran.
(Dans mon exemple, je la fait réapparaitre seule au bout de 3 secondes, mais c'est juste pour essai)

Gérer les éventuels multi écran est assez facile, il suffit de de jouer sur la taille de la fenêtre au lieu de la faire glisser.

PS. Personne n'a pu répondre à ma question ?

Code : Tout sélectionner

Quelle différence entre GetCursorPos_ (API) et WindowMouseX() (et Y) de PB ?
Pourquoi utiliser une API quand la fonction existe déjà dans PB ?

Re: Mettre un timeout sur une fenêtre

Publié : lun. 25/janv./2016 11:18
par Ar-S
WindowMouseX detecte ton curseur au niveau de ta fenêtre.
GetCursorPos se réfère au bureau complet.
J'avais utilisé GetCursorPos pour mon soft afin de faire sortir ma fenêtre au moment ou le curseur entrait dans la ZONE de la fenêtre alors que celle ci était cachée.

En gros :
Fen ouverte X = 980
Fen cachee X = 1030

GetCursorPos permet de commencer le retour de la fenêtre alors que le curseur en X est à 1010 par exemple, ça faisait une petite anticipation que j'aimais bien ;)

Re: Mettre un timeout sur une fenêtre

Publié : lun. 25/janv./2016 14:07
par Marc56
Je me suis trompé, c'est DesktopMouseX() et DesktopMouseY() qui donnent la position absolue du curseur sur le desktop (y compris avec plusieurs écrans)

Renvoie la position absolue en X en pixels de la souris à partir du coin supérieur gauche du moniteur principal.
La coordonnée est négative si la souris est sur un moniteur à gauche de l'écran principal.


Tout est dans la bibliothèque Desktop Pas besoin d'API :wink:

Re: Mettre un timeout sur une fenêtre

Publié : lun. 25/janv./2016 16:22
par Ar-S
là d'accord :)

Re: Mettre un timeout sur une fenêtre

Publié : lun. 25/janv./2016 18:30
par cage
Bonjour,

J'arrive un peu tard dans la discussion, mais voici ce que j'utilise pour tester l'inactivité sur un PC
J'utilise un Timer qui vérifie l'état Idle du PC et active l'écran de veille "scrnsave.scr"
Un déplacement de sourie ou une entrée clavier ré-affiche l'écran normal.
Je ne sais pas si c'est cela qui était souhaité au départ
Dans l'exemple, le temps d'inactivité #Idle est fixé a 3 secondes (modifiable dans l'appel de la proc) et le #Timeout a 2 secondes
Toutes les 2 secondes on teste si l'état Idle du PC est supérieur a 3 secondes

Code : Tout sélectionner

#WinApp  = 11   ; A number to identify the window
#Timer   = 0    ; A number to identify the timer
#Timeout = 2000 ; Timer timeout in milliseconds
#Idle    = 3    ; in seconds, how long the system is in idle state

Procedure getNamePID(ProcessName.s,*ptrPID)
; Retrieve the ProcessID according to exe name.
; Note: If many runing exe share the same name,
; Note: this would retrieve the first exe PID that had found,not all.
; Note: If found it, return 1 else 0, ps: .lbool = .l
  Protected HSnap.l,Prec.processentry32,result.l=#False
  HSnap=CreateToolhelp32Snapshot_(#TH32CS_SNAPPROCESS,0)
  If HSnap=#INVALID_HANDLE_VALUE
    ProcedureReturn result
  EndIf
  Prec\dwSize=SizeOf(prec)
  If Not Process32First_(HSnap,Prec)
    ProcedureReturn result
  EndIf
  Repeat
    If LCase(GetFilePart(PeekS(@Prec\szexefile)))=LCase(ProcessName)
      PokeL(*ptrPID,Prec\th32ProcessID)
      ;ptrPID$ = Str(Prec\th32ProcessID)
      ;Debug "ptrPID=" + ptrPID$
      result=#True
      Break
    EndIf
  Until Not Process32Next_(HSnap,Prec)
  CloseHandle_(HSnap)
  ProcedureReturn result
EndProcedure

Procedure isInputIdle(vIdleTimeout)
  Protected bool, LII.LASTINPUTINFO
  bool = #False
  LII\cbSize = SizeOf(LII)
; Debug "s=" + SizeOf(LII)
; Debug "i=" + GetLastInputInfo_(LII)
; Debug "c=" + Str(GetTickCount_())
; Debug "d=" + Str(LII\dwTime)
; Debug GetTickCount_() - LII\dwTime
; Debug " "
  If GetLastInputInfo_(LII) <> 0
    bool = Bool((GetTickCount_() - LII\dwTime) > (1000 * vIdleTimeout))
  EndIf
  ProcedureReturn bool
EndProcedure

Procedure runScreensave()
  ShellExecute_(#WinApp, "open" , "scrnsave.scr" , #Null$ , #Null$ , #SW_NORMAL)
EndProcedure

Define Flags = #PB_Window_MinimizeGadget|#PB_Window_WindowCentered|#PB_Window_Minimize
If OpenWindow(#WinApp, #PB_Ignore, #PB_Ignore, 270, 210, "check iddle", Flags)
  SetWindowState(#WinApp, #PB_Window_Normal)
  HideWindow(#WinApp, #False, #PB_Window_ScreenCentered)
  AddWindowTimer(#WinApp, #Timer, #Timeout)
  Repeat
    Event = WaitWindowEvent()
    Select Event
      Case #PB_Event_CloseWindow
        Break
      Case #PB_Event_Timer
        Select EventTimer()
          Case #Timer ; every #Timeout seconds
            Define ptrPID = 0
            If isInputIdle(#idle) And Not getNamePID("scrnsave.scr",@ptrPID)
              ;Debug "screen save"
              runScreensave()
            EndIf
        EndSelect
    EndSelect
  ForEver ; Wait For Event = #PB_Event_CloseWindow
EndIf
End

Re: Mettre un timeout sur une fenêtre

Publié : lun. 25/janv./2016 18:55
par Marc56
J'ai sans doute ma exprimé ce que fera mon programme, je m'excuse :oops:

Résumé:
1. Si on ne n'utilise pas cette fenêtre elle se cache lentement sur le côté.
2. Elle reviendra uniquement si on met la souris sur un côté de l'écran.
3. L'utilisateur se sert des autres applications normalement pendant ce temps.

Ce n'est donc pas comme un écran de veille :wink:

PS. Ne vous embêtez-pas: j'ai trouvé ma solution.
:)