PC SOFT

FORUMS PROFESSIONNELS
WINDEVWEBDEV et WINDEV Mobile

Accueil → WINDEV 2024 → Suite un evênement Windows.
Suite un evênement Windows.
Débuté par yannick, 25 jan. 2022 18:13 - 9 réponses
Posté le 25 janvier 2022 - 18:13
Bonjour tout le monde.

Une demande probablement simple pour vous, mais je veux savoir faire.

Je veux produire une petite application qui fonctionnera en tâche de fond.
Il n'y aura pas de fenêtre utilisateur ouverte en permanence avec le focus dessus.
En tâche de fond donc, parmi tous les autres programmes qui tournent sous Windows.
---------------------------
Le but est d'afficher l'état du bouton MAJ et NUM avec l'affichage d'un logo au milieu de l'écran lorsque l'état change.
J'arrive à le faire tant que le focus est sur l'application qui vérifie ces états. Mais dès que le focus n'est plus dessus, la détection ne fonctionne plus. Et je rappel que ma petite application doit fonctionner en tâche de fond sans avoir le focus.
----------------------------
Voilà.
J'espère que j'ai été clair.
Merci d'avance.
Yannick
Membre enregistré
351 messages
Popularité : +75 (75 votes)
Posté le 26 janvier 2022 - 01:08
Bonjour Yannick,

Il faut faire un hook sur le clavier ... je te laisse chercher sur le forum le code qui t'aidera vu que maintenant tu as le bon mot-clé : "hook" !

--
Bon développement, Patrick [3po.fr]
Posté le 26 janvier 2022 - 08:20
Je regarde tout de suite. Merci.
Posté le 26 janvier 2022 - 18:22
J'ai passé l'après-midi sur ce sujet. Mais rien à faire.
En fait mon code fonctionne très bien mais dès que le programme n'a plus le focus sur lui-même, le code ne fonctionne plus. Et pas de reprise du code même si je clique sur le programme.

Ceci dans la déclaration de COL_xxxx ou se trouve ma procédure en dessous.
CONSTANTE
WH_KEYBOARD_LL = 13
FIN
gnHandleHook est un entier // handle du hook
gnHandleHook = API("User32", "SetWindowsHookExA", WH_KEYBOARD_LL, &Proc_Test_si_MAJ_active, Instance(), 0)

//////////VK_NUMLOCK est un entier = 0x90 + 1
//////////VK_SCROLL est un entier = 0x91 + 1
VK_CAPITAL est un entier = 0x14 + 1
Clavier est un tableau de 256 caractères


Ma procédure :

Procedure Proc_Test_si_MAJ_active()
AppelDLL32("user32", "GetKeyboardState", &Clavier[1])
SI Asc(Clavier[VK_CAPITAL])=128 ALORS // MAJ désactivé.
SysIconeAjoute(SysRep(srProgramFiles)+"\DOSSIER\MAJ-Disable.ico", "" , "MAJ Désactivé")
FIN
SI Asc(Clavier[VK_CAPITAL])=129 ALORS //MAJ Actif.
SysIconeAjoute(SysRep(srProgramFiles)+"\DOSSIER\MAJ-Actif.ico", "" , "MAJ Actif")
FIN


Par contre si je laisse une ligne info("Essai") en dessous de la ligne AppelDLL32("user32", "GetKeyboardState", &Clavier[1])
Mon code fonctionne parfaitement même en arrière plant, mais naturellement la fenêtre info s'affiche et ce n'est pas ce que je veux.
Mais cela montre que le code à besoin d'avoir le focus.
Et cela me pose un problème aussi, car l'utilisateur ne doit pas perdre le focus sur son programme, comme Word par exemple, lorsque qu'il appuis sur MAJ.
Merci
Yannick
Membre enregistré
351 messages
Popularité : +75 (75 votes)
Posté le 26 janvier 2022 - 23:56
Bonjour Yannick,

Il faut que ta procédure de contrôle fonctionne en tâche de fond, tu peux utiliser au choix :
- Un thread ... pour l'affichage dans ton thread, tu utiliseras ExécuteThreadPrincipal
- Un timer ... voir TimerSys
- Une procédure automatique ... équivalent des 2 du dessus mais sans programmation

Documentation : https://doc.pcsoft.fr/fr-FR/?9000072, https://doc.pcsoft.fr/fr-FR/?3077026, https://doc.pcsoft.fr/fr-FR/?3015006

--
Bon développement, Patrick [3po.fr]
Posté le 27 janvier 2022 - 11:57
Bonjour.

Avec la case Thread Principal de coché dans "Automatisme de la procédure", cela ne fonctionne toujours pas.
Je fais sans doute quelque chose pas bien !
Mais quoi ?

Merci
Yannick
Membre enregistré
351 messages
Popularité : +75 (75 votes)
Posté le 28 janvier 2022 - 00:42
Bonjour Yannick,

Aujourd'hui je suis bien luné ... alors je vais te donner un code qui fonctionne pour la base de ton application.

- Créer un projet vide
- Créer une fenêtre avec 2 champs de type "libellé" : Libellé_CapsLock et Libellé_NumLock

Dans la déclaration de la fenêtre, mettre :
Procedure MaFenêtre()

// Déclaration des constantes
CONSTANT
WH_KEYBOARD_LL = 13
VK_CAPITAL = 20
VK_NUMLOCK = 144
FIN

// Structure des paramètres de WH_KEYBOARD_LL
KBDLLHOOKSTRUCT est une Structure
vkCode est un entier sur 4 octets
scanCode est un entier sur 4 octets
flags est un entier sur 4 octets
time est un entier sur 4 octets
dwExtraInfo est un entier système
FIN

// Mise à jour de l'affichage de l'état des touches CapsLock et NumLock
Suivi_CAPSLock_NUMLock()

// Mise en place du Hook
Hook_Handle est un entier système = API("User32","SetWindowsHookExA",WH_KEYBOARD_LL,&_WH_KEYBOARD_LL,SysInstance(),Null)

Dans la fermeture de fenêtre, mettre :
// Suppression du Hook
API("User32","UnhookWindowsHookEx",Hook_Handle)

Créer une procédure locale dans la fenêtre :
Procedure _WH_KEYBOARD_LL(nCode est un entier sur 4 octetsentier systèmen entier systèmeentier systèmen entier système)

// Hook suivant
Hook est un entier système = API("User32","CallNextHookEx",Hook_Handle,nCode,wParam,lParam)

// Si le hook est valide
SI nCode >= 0 ALORS

// On récupère les paramètres du hook
Paramètre_Hook est un KBDLLHOOKSTRUCT
Transfert(&Paramètre_Hook,lParam,Dimension(Paramètre_Hook))

// Si c'est la touche CapsLock ou NumLock alors on affiche le suivi
SI Paramètre_Hook.vkCode DANS (VK_CAPITAL,VK_NUMLOCK) ALORS Suivi_CAPSLock_NUMLock()

FIN

// On retourne la réponse du Hook suivant
RENVOYER Hook

// Et enfin créer une dernière procédure locale avec comme automatisme "Thread Principal" pour que l'affichage soit exécuté par le thread principal :
Procedure Suivi_CAPSLock_NUMLock()

// Récupération de l`état de CapsLock et NumLock
Libellé_CapsLock = "CapsLock : " + (ETBinaire(API("User32","GetKeyState",VK_CAPITAL),1) ? "Actif" SINON "Inactif")
Libellé_NumLock = "NumLock : " + (ETBinaire(API("User32","GetKeyState",VK_NUMLOCK),1) ? "Actif" SINON "Inactif")

Bien sûr ... ce code fonctionne en 32 et 64 bits. Je t'ai mis le projet avec son exécutable à disposition ici : https://3po.fr/_3pO_Démo_xLock.zip

Il ne te restera plus qu'à faire l'affichage dont tu as besoin.

--
Bon développement, Patrick [3po.fr]
Membre enregistré
351 messages
Popularité : +75 (75 votes)
Posté le 28 janvier 2022 - 00:44
Mauvaise interprétation de mon code dans le post précédent, il fallait lire :

PROCÉDURE _WH_KEYBOARD_LL(nCode est un entier sur 4 octets, wParam est un entier système, lParam est un entier système)

--
Bon développement, Patrick [3po.fr]
Posté le 29 janvier 2022 - 09:51
Merci Patrick.

Des petits gestes comme les tiens vers les autres offres toujours une satisfaction et du bien être pour soit.

Ton code fonctionne. Mais il y à deux procédures contrairement à ce qui avait été listé précédemment.
J'adapte le code à mon programme.
Merci encore et à bientôt.
Yannick
Membre enregistré
351 messages
Popularité : +75 (75 votes)
Posté le 01 février 2022 - 19:31
Bonjour Yannick,

Si cela t'a fait plaisir alors le but est atteint ... et en plus le code marche, c'est merveilleux ! [Humour]J'avais pourtant taper des mots au hasard avec mes pieds comme beaucoup de codes que l'on voit sur ce forum ... :)[/Humour]

La gestion des hook oblige de retourner le résultat du hook suivant pour ne pas casser l'enchainement des hook, Tu ne peux donc pas te passer de cette première procédure. C'est d'ailleurs dans ce retour que l'on peut stopper un hook et ainsi arrêter la propagation de l'événement correspondant, tu peux par exemple bloquer Ctrl-Alt-Suppr si tu as envie.

La deuxième procédure "Suivi_CAPSLock_NUMLock()" est là pour 2 raisons : la première est pour l'affichage des états des boutons au lancement de ta fenêtre et la deuxième car elle doit forcément s'exécuter dans le thread principal vu que tu modifies l'UI et que le hook appelle cette routine à partir en dehors du thread principal. C'est cette procédure que tu dois maintenant personnaliser pour avoir l'affichage que tu désires, c'est plus simple ainsi.

Je pense même que dans mon projet j'ai changé
ETBinaire(API("User32","GetKeyState",VK_CAPITAL),1)
par
API("User32","GetKeyState",VK_CAPITAL) & 1
Ces deux lignes sont équivalentes ... je préfère la deuxième syntaxe mais la première est plus lisible pour un néophyte.

--
Bon développement, Patrick [3po.fr]