thoga31 Posted March 18, 2012 at 07:53 PM Report #444502 Posted March 18, 2012 at 07:53 PM Boas, camaradas! Ando a investigar nos tempos livres algo que parece absurdamente simples mas que, em Pascal, não me parece ser assim tão fácil. Decidi aceitar o "desafio" de um livro meu de VB.NET... mas decidi implementá-lo em Pascal, claro! 🙂 A ideia é ter um programa que, de cada vez que um Lock é alterado, é informada a alteração. Exemplo de output: Caps [On] Scroll [Off] Num [Off] Ora, numa Windows Application em VB.NET é astronomicamente simples... Uma RichTextBox onde é feito o output sequencial, um Timer com a propriedade Interval a 100, e um procedimento que verifica o estado dos Locks e indica se houve alteração. Agora em Pascal a cena muda de figura... Encontrei neste um código que exemplifica com o Caps Lock, do qual eu, confesso, percebi pouco. 🙂 A minha questão é: como posso verificar e configurar os Locks? Há outros modos sem ser pela leitura de bytes do Registry? Não há métodos que nos possam auxiliar? E em Delphi, já agora? Espero o vosso contributo nesta questão a fim de poder ter um snippet, ou mesmo um how-to, para colocar na Wiki. 😄 Cumprimentos, thoga31. Knowledge is free!
nunopicado Posted March 18, 2012 at 08:09 PM Report #444505 Posted March 18, 2012 at 08:09 PM Em tURBO Pascal é por registry... Em Delphi ou FreePascal, é tão simples como isto: case GetKeyState(VK_CAPITAL) of 0: // Caps Lock desligado 1: // Caps Lock ligado end; Outros códigos de teclas úteis: VK_NUMLOCK: Num Lock VK_SCROLL: Scroll Lock VK_LSHIFT: Left Shift VK_RSHIFT: Right Shift VK_LCONTROL: Left Control VK_HCONTROL: Right Control VK_LMENU: Left Alt VK_RMENU: Right Alt "A humanidade está a perder os seus génios... Aristóteles morreu, Newton já lá está, Einstein finou-se, e eu hoje não me estou a sentir bem!" > Não esclareço dúvidas por PM: Indica a tua dúvida no quadro correcto do forum.
thoga31 Posted March 18, 2012 at 08:17 PM Author Report #444507 Posted March 18, 2012 at 08:17 PM Really? :o E o Google a debitar-me Registries sem fim! eheheh 🙂 Qual é a unidade necessária para tal? A Dos? Knowledge is free!
nunopicado Posted March 18, 2012 at 08:20 PM Report #444509 Posted March 18, 2012 at 08:20 PM Uses Windows; 🙂 "A humanidade está a perder os seus génios... Aristóteles morreu, Newton já lá está, Einstein finou-se, e eu hoje não me estou a sentir bem!" > Não esclareço dúvidas por PM: Indica a tua dúvida no quadro correcto do forum.
thoga31 Posted March 18, 2012 at 08:21 PM Author Report #444510 Posted March 18, 2012 at 08:21 PM Uses Windows; 😄 Ah, ok... A mesma para as MessageBoxes e afins relacionados 🙂 Já agora, como configurar? SetKeyState? Knowledge is free!
nunopicado Posted March 18, 2012 at 08:37 PM Report #444512 Posted March 18, 2012 at 08:37 PM Actualmente, para encontrares funções do FreePascal, é mais fácil procurares as de Delphi. 🙂 O Delphi evoluiu do Pascal, mas o Pascal evolui também, baseado no Delphi. É o típico caso do mestre que ensina ao pupilo tudo o que sabe. O pupilo entretanto aprende mais, e o mestre vai aprender com ele para poder evoluir também! Para mudar o estado é mais "dificil" do que para os ler. Ainda assim, nada de muito complexo. Precisamos simular o pressionar (e largar) da tecla, para que o processo seja exactamente o mesmo do que sermos nós a carregar. procedure ToogleNumLock; begin if (GetKeyState(VK_NUMLOCK) = 0) // Lê o estado actual then begin Keybd_Event(VK_NUMLOCK, 1, KEYEVENTF_EXTENDEDKEY or 0, 0) ; // "Pressiona" a tecla Keybd_Event(VK_NUMLOCK, 1, KEYEVENTF_EXTENDEDKEY or KEYEVENTF_KEYUP, 0) ; // "Larga" a tecla end else begin Keybd_Event(VK_NUMLOCK, 0, KEYEVENTF_EXTENDEDKEY or 0, 0) ; // "Pressiona" a tecla Keybd_Event(VK_NUMLOCK, 0, KEYEVENTF_EXTENDEDKEY or KEYEVENTF_KEYUP, 0) ; // "Larga" a tecla end; end; "A humanidade está a perder os seus génios... Aristóteles morreu, Newton já lá está, Einstein finou-se, e eu hoje não me estou a sentir bem!" > Não esclareço dúvidas por PM: Indica a tua dúvida no quadro correcto do forum.
thoga31 Posted March 18, 2012 at 09:10 PM Author Report #444515 Posted March 18, 2012 at 09:10 PM Eis a solução do exercício em Pascal! 🙂😄 Que acham? {$MODE DELPHI} PROGRAM LocksTest; USES crt, windows; TYPE // Permite a referência intuitiva ao Lock pretendido, ao invés das constantes reconhecidas pelo Pascal TKeySet = (CapsLock, NumLock, ScrollLock); // Guarda o antigo e o actual estado dos Locks TLockState = RECORD Old : record // Antigos estados Caps, Num, Scroll : boolean; end; Now : record // Novos estados Caps, Num, Scroll : boolean; end; END; CONST // Converte um TKeySet num valor padrão reconhecido pelo Pascal TKey : array [TKeySet] of cardinal = (VK_CAPITAL, VK_NUMLOCK, VK_SCROLL); VAR option : char; // Verifica quando é premido ESC. LocksState : TLockState; // Regista os estados dos Locks PROCEDURE WriteAndRefreshLocksState(const OnLoad : boolean); (* Actualiza os estados dos Locks e, caso algum tenha alterado, escreve o seu novo estado *) // OnLoad: TRUE = início do programa: deve escrever todos os actuais estados. FALSE = no decorrer do programa. function GetLockState(const Lock : TKeySet) : boolean; (* Obtém o estado de um determinado Lock *) begin case GetKeyState(TKey[Lock]) of 0 : result := false; 1 : result := true; end; end; begin // Caps Lock LocksState.Now.Caps := GetLockState(CapsLock); if (LocksState.Now.Caps <> LocksState.Old.Caps) or OnLoad then begin case LocksState.Now.Caps of true : writeln('Caps Lock [On]'); false : writeln('Caps Lock [Off]'); end; LocksState.Old.Caps := LocksState.Now.Caps; end; // Num Lock LocksState.Now.Num := GetLockState(NumLock); if (LocksState.Now.Num <> LocksState.Old.Num) or OnLoad then begin case LocksState.Now.Num of true : writeln('Num Lock [On]'); false : writeln('Num Lock [Off]'); end; LocksState.Old.Num := LocksState.Now.Num; end; // Scroll Lock LocksState.Now.Scroll := GetLockState(ScrollLock); if (LocksState.Now.Scroll <> LocksState.Old.Scroll) or OnLoad then begin case LocksState.Now.Scroll of true : writeln('Scroll Lock [On]'); false : writeln('Scroll Lock [Off]'); end; LocksState.Old.Scroll := LocksState.Now.Scroll; end; end; BEGIN (* BLOCO PRINCIPAL *) writeln('INICIO:'); WriteAndRefreshLocksState(true); // Escreve estados iniciais writeln; writeln('ALTERACOES:'); repeat // Actualiza estados num intervalo de 0,1 segundos. while not KeyPressed do begin WriteAndRefreshLocksState(false); delay(100); // Para não sobrecarregar CPU - equivale à velocidade de reacção do ser humano. end; option := readkey; until (option = #27); // Sai aquando ESC END. EDIT: na Wiki 🙂 Knowledge is free!
nunopicado Posted March 18, 2012 at 09:30 PM Report #444520 Posted March 18, 2012 at 09:30 PM 😄 Deixa-me refazer-te aí uma função, recorrendo a typecasts: function GetLockState(const Lock : TKeySet) : boolean; (* Obtém o estado de um determinado Lock *) begin Result:=Boolean(GetKeyState(TKey[Lock])); end; E já agora, ainda que eu seja fã de arrays de constantes, bastava-te isto: const CapsLock=VK_Capital; NumLock=VK_NumLock; ScrollLock=VK_ScrollLock; Assim funcionam as originais, e as tuas, não enquanto valor do tipo TKeySet, mas como valores constantes. Aliás, com o typecast e as constantes directas, nem vale a pena uma nova função... 🙂 if boolean(GetKeyState(CapsLock)) then // bla bla bla "A humanidade está a perder os seus génios... Aristóteles morreu, Newton já lá está, Einstein finou-se, e eu hoje não me estou a sentir bem!" > Não esclareço dúvidas por PM: Indica a tua dúvida no quadro correcto do forum.
thoga31 Posted March 18, 2012 at 09:37 PM Author Report #444521 Posted March 18, 2012 at 09:37 PM Deixa-me refazer-te aí uma função, recorrendo a typecasts: function GetLockState(const Lock : TKeySet) : boolean; (* Obtém o estado de um determinado Lock *) begin Result:=Boolean(GetKeyState(TKey[Lock])); end; Oi? :o E já agora, ainda que eu seja fã de arrays de constantes, bastava-te isto: const CapsLock=VK_Capital; NumLock=VK_NumLock; ScrollLock=VK_ScrollLock; Fiz daquela forma pois queria utilizar aquela capacidade, capacidade essa que só aprendi muito recentemente 😄 Mas de facto bastava dessa forma, é o meu método mais antigo. 🙂 Mas o snippet no fundo não está nada mal, pois não? :🙂 Knowledge is free!
nunopicado Posted March 18, 2012 at 09:54 PM Report #444526 Posted March 18, 2012 at 09:54 PM Mas o snippet no fundo não está nada mal, pois não? :🙂 Não, não está mal! 🙂 Fiz daquela forma pois queria utilizar aquela capacidade, capacidade essa que só aprendi muito recentemente 😄 hehehehe a sério? Onde? Onde? Oi? :o lol hehehe Ao fazeres Boolean(x), sendo x um valor integer, estás a converter esse valor integer num valor boolean, segundo a fórmula: 0= False Qualquer outro= True Os typecasts são das coisas mai' lindas do pascal/delphi, não são? hehehe "A humanidade está a perder os seus génios... Aristóteles morreu, Newton já lá está, Einstein finou-se, e eu hoje não me estou a sentir bem!" > Não esclareço dúvidas por PM: Indica a tua dúvida no quadro correcto do forum.
thoga31 Posted March 18, 2012 at 09:59 PM Author Report #444529 Posted March 18, 2012 at 09:59 PM hehehehe a sério? Onde? Onde? Num qualquer post teu, relativamente recente 🙂 hehehe Ao fazeres Boolean(x), sendo x um valor integer, estás a converter esse valor integer num valor boolean, segundo a fórmula: 0= False Qualquer outro= True Os typecasts são das coisas mai' lindas do pascal/delphi, não são? hehehe Olha, não sabia! São mes' lindos! 😄 Há mais tipos de dados que fazem typecasts? 🙂 Knowledge is free!
nunopicado Posted March 18, 2012 at 10:06 PM Report #444531 Posted March 18, 2012 at 10:06 PM em Delphi, os typecasts fazem parte da programação... Mal consegues "soltar gazes" sem fazer typecast. (imagem mai' linda e poetica esta, não? 🙂😄🙂 ) Quase todos os tipos dão para fazer typecast, pelo menos a partir de algum outro tipo. Um muito usado, para tornar genérico um dado qualquer, é o TObject. s:='Olá mundo'; obj:=TObject(s); s:=String(Obj); ShowMessage(s); Com isto conseguimos inserir uma informação qualquer dentro das classes de dados, por exemplo: Num combobox, cada linha da caixa pode possuir dois valores: Uma String, e um TObject. Com o typecast com TObjects podemos ter uma string (apresentada na caixa) e outro dado qualquer (escondida, mas associada à string). "A humanidade está a perder os seus génios... Aristóteles morreu, Newton já lá está, Einstein finou-se, e eu hoje não me estou a sentir bem!" > Não esclareço dúvidas por PM: Indica a tua dúvida no quadro correcto do forum.
nunopicado Posted March 19, 2012 at 12:03 AM Report #444554 Posted March 19, 2012 at 12:03 AM Ocorreu-me agora... Ora, numa Windows Application em VB.NET é astronomicamente simples... Uma RichTextBox onde é feito o output sequencial, um Timer com a propriedade Interval a 100, e um procedimento que verifica o estado dos Locks e indica se houve alteração. É assim que se faz em VB.net? My God! 😁 Agora em Pascal a cena muda de figura... Ai pois muda... DELPHI! DELPHI! DELPHI! :smitten: "A humanidade está a perder os seus génios... Aristóteles morreu, Newton já lá está, Einstein finou-se, e eu hoje não me estou a sentir bem!" > Não esclareço dúvidas por PM: Indica a tua dúvida no quadro correcto do forum.
thoga31 Posted March 19, 2012 at 12:14 PM Author Report #444606 Posted March 19, 2012 at 12:14 PM É assim que se faz em VB.net? My God! 😁 Para uma Windows Application, sim. Em consola é super semelhante. A base da verificação, para qualquer uma delas, é esta (e.g. caps lock): If My.Computer.Keyboard.CapsLock Then MsgBox("Caps Lock ON") Else MsgBox("Caps Lock OFF") End If DELPHI! DELPHI! DELPHI! :smitten: O Dia dos Namorados já lá vai... 😁 Knowledge is free!
nunopicado Posted March 19, 2012 at 12:19 PM Report #444607 Posted March 19, 2012 at 12:19 PM Ah, OK. Estava a ficar preocupado com a necessidade de richedits e companhia só para ver o estado da tecla! 😁 "A humanidade está a perder os seus génios... Aristóteles morreu, Newton já lá está, Einstein finou-se, e eu hoje não me estou a sentir bem!" > Não esclareço dúvidas por PM: Indica a tua dúvida no quadro correcto do forum.
thoga31 Posted March 19, 2012 at 01:10 PM Author Report #444613 Posted March 19, 2012 at 01:10 PM Ah, OK. Estava a ficar preocupado com a necessidade de richedits e companhia só para ver o estado da tecla! 😁 Relê bem o que tinha dito (eheheh 😁): - RichTextBox para o output: numa Windows App o output tem de ocorrer de alguma forma, e uma MsgBox não é, com certeza, o melhor 😛 - Timer: há que verificar periodicamente o estado dos Locks, e numa Windows App, o Timer serve para isso mesmo: lança um evento Tick a cada Interval milissegundos - é a cada Tick que faz a verificação; 😉 - Um procedimento que verifica os Locks: aqui sim está a verificação... 3 conjuntos minúsculos como o que escrevi há pouco + umas adaptações para o output, e voilá! Très chique! 😄 Knowledge is free!
nunopicado Posted March 19, 2012 at 01:37 PM Report #444620 Posted March 19, 2012 at 01:37 PM hehehe Então, deixa-me dizer-te que tens maneira melhor de fazer isso em VB.Net, tal como em Delphi (só não te sei é dizer como em VB.Net, mas que dá, eh pá, tem que dar! 😁) O Windows funciona com mensagens, que são comunicadas entre o core e as aplicações e vice-versa. É isto que torna possível usar os eventos do Delphi, C++, VB.Net e linguagens do mesmo estilo: 1. Algo acontece 2. O core disponibiliza uma mensagem informativa 3. A aplicação apanha a mensagem e despoleta o evento. Não existem eventos directos para verificar os Locks, mas também, quem é que precisa da papa toda feita? Se soubermos que vamos ter sempre activo um determinado componente, podemos usar os eventos OnKeyUp e OnKeyDown para detectar que teclas foram pressionadas, e nesse evento verificar o estado das teclas. Caso não se saiba qual componente estará activo, podemos adicionar à aplicação um componente TApplicationEvents, e no seu evento OnMessage, e apanhar as mensagens WM_KEYDOWN ou WM_KEYUP, conforme o desejado... Assim, não é preciso um timer que muito ou pouco, sempre consome recursos, e cá pra nós, não é tão "elegante"! 😁 "A humanidade está a perder os seus génios... Aristóteles morreu, Newton já lá está, Einstein finou-se, e eu hoje não me estou a sentir bem!" > Não esclareço dúvidas por PM: Indica a tua dúvida no quadro correcto do forum.
thoga31 Posted March 19, 2012 at 04:33 PM Author Report #444660 Posted March 19, 2012 at 04:33 PM Em VB.NET tens procedimentos que regem o comportamento a tomar consoante o evento ocorrido num determinado objecto. Imagina o carregamento da Form1: Private Sub Form1_Load(sender As Object, ByVal e As System.EventArgs) Handles MyBase.Load MyBase refere-se ao Form1, a form onde estão contidos os objectos. Existe o evento KeyDown, por exemplo, mas é necessário a form estar focada. Para a aplicação apanhar eventos do sistema já são necessárias outras cenas, as quais desconheço. A forma mais fácil é com recurso a um Timer que obrigará a verificar os Locks de x em x milissegundos. Assim só tens de apanhar o avlor booleano do estado de cada Lock, e não tens de estar atento a nenhum evento. 😁 Private Sub RefreshLocks() ' Actualiza a informação dos Locks End Sub Private Sub Timer1_Tick( etc etc ) Handles Timer1.Tick RefreshLocks() End Sub E pronto, passada a pequena aula de VB.NET e voltando ao Pascal, já sabemos como sacar a informação dos Locks de uma forma cómoda e sem métodos demasiado avançados. 😁 Knowledge is free!
thoga31 Posted March 19, 2012 at 05:40 PM Author Report #444674 Posted March 19, 2012 at 05:40 PM Decidi refazer o meu programa. Está muito mais optimizado e intuitivo para o programador que o ler. 😁 Inovações que utiliza: Cada Lock tem uma função que devolve directamente um Boolean; Estas funções são calculadas por TypeCasting; O programa não informa a alteração, simplesmente tem os 3 indicadores e diz "ON" e "OFF" conforme o estado; Para indicar o estado a partir do Boolean, há uma função que faz a conversão Boolean>OnOff. Espero que apreciem este pequenino snippet renovado. 😁 PROGRAM LocksTest; USES crt, windows; (* TIPOS *) TYPE TRegLocksState = RECORD Old : record Caps, Num, Scroll : boolean; end; Now : record Caps, Num, Scroll : boolean; end; END; (* VARIÁVEIS *) VAR Locks : TRegLocksState; ExitControl : char; FUNCTION CapsLock : boolean; (* Verifica Caps Lock *) begin CapsLock := boolean(GetKeyState(VK_CAPITAL)); end; FUNCTION NumLock : boolean; (* Verifica Num Lock *) begin NumLock := boolean(GetKeyState(VK_NUMLOCK)); end; FUNCTION ScrollLock : boolean; (* Verifica Scroll Lock *) begin ScrollLock := boolean(GetKeyState(VK_SCROLL)); end; PROCEDURE RefreshLocks(const OnLoad : boolean); (* Actualiza indicadores de Locks *) function Bool2OnOff(const b : boolean) : string; (* Converte o booleano do indicador num indicador ON/OFF *) begin case b of true : Bool2Onoff := 'ON '; false : Bool2Onoff := 'OFF'; end; end; begin // Indicador Caps Lock Locks.Now.Caps := CapsLock; if (Locks.Now.Caps <> Locks.Old.Caps) or OnLoad then begin GotoXY(1,1); Write(' Caps Lock ', Bool2OnOff(Locks.Now.Caps)); Locks.Old.Caps := Locks.Now.Caps; end; // Indicador Num Lock Locks.Now.Num := NumLock; if (Locks.Now.Num <> Locks.Old.Num) or OnLoad then begin GotoXY(1,2); Write(' Num Lock ', Bool2OnOff(Locks.Now.Num)); Locks.Old.Num := Locks.Now.Num; end; // Indicador Scroll Lock Locks.Now.Scroll := ScrollLock; if (Locks.Now.Scroll <> Locks.Old.Scroll) or OnLoad then begin GotoXY(1,3); Write('Scroll Lock ', Bool2OnOff(Locks.Now.Scroll)); Locks.Old.Scroll := Locks.Now.Scroll; end; end; BEGIN (* BLOCO PRINCIPAL *) RefreshLocks(true); // Mete indicadores: está a iniciar programa - parâmetro deve ser TRUE repeat while not KeyPressed do begin RefreshLocks(false); // Actualiza Delay(100); end; ExitControl := ReadKey; until (ExitControl = #27); // Sai no ESC END. Knowledge is free!
nunopicado Posted March 19, 2012 at 10:31 PM Report #444704 Posted March 19, 2012 at 10:31 PM Este é o momento certo para um array de constantes. 😁 Substituis isto: function Bool2OnOff(const b : boolean) : string; (* Converte o booleano do indicador num indicador ON/OFF *) begin case b of true : Bool2Onoff := 'ON '; false : Bool2Onoff := 'OFF'; end; end; por isto: Const Bool2OnOff:Array[boolean] of string=('OFF','ON '); E claro, substituir os parentesis curvos onde chamavas a função por parantesis rectos. "A humanidade está a perder os seus génios... Aristóteles morreu, Newton já lá está, Einstein finou-se, e eu hoje não me estou a sentir bem!" > Não esclareço dúvidas por PM: Indica a tua dúvida no quadro correcto do forum.
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now