/
/
Gerenciador de Autenticação com RaspPi Pico como Teclado USB

Gerenciador de Autenticação com RaspPi Pico como Teclado USB

Sumário

Baixe agora a apostila Arduino Iniciante e comece seus projetos

Compartilhe seu conhecimento e receba em dinheiro ou produtos.

blog-eletrogate-autentica-usb-capa

Introdução

Neste tutorial, exploraremos uma aplicação para a placa Raspberry Pi Pico: utilizar a RP Pico para simular um teclado USB para interação com um computador. Para isso, será utilizada a biblioteca Keyboard.h, que permite ao RP Pico enviar pressionamentos de tecla para um computador conectado através da porta USB nativa de seu computador. Também será demonstrado como a placa RP Pico pode detectar e interagir com as funções Num Lock, Caps Lock e Scroll Lock de um computador hospedeiro. Por fim, será demonstrado como criar um Gerenciador de Autenticação com a placa RP Pico. Ao integrar três push buttons à placa Raspberry Pi Pico, será possibilitado a execução de ações específicas no sistema operacional Windows 11 (SO do Computador). Ao pressionar o botão LOGIN, a senha armazenada na memória FLASH da RP Pico será enviada para permitir o acesso à sessão do Windows. Para evitar equívocos causados pelo Caps Lock, será implementada uma função que formata corretamente a senha, independentemente do estado do Caps Lock. Outras funcionalidades incluirão o botão LOGOUT, que enviará um comando para realizar o logout no Windows, e o botão BLOQUEAR, que permitirá bloquear o sistema, exigindo que o usuário faça login novamente para acessar a sessão atual do Windows.

Materiais Necessários para o Projeto Gerenciador de Autenticação com RaspPi Pico como Teclado USB

Neste post será necessário os seguintes materiais: 

Configurando IDE Arduino para a RP Pico

Para utilizar a placa Raspberry Pi Pico deve-se instalar o núcleo Arduino Pico na IDE Arduino. Para isso, siga os passos abaixo:

  1. Abra a IDE Arduino e navegue no menu Arquivo ➜ Preferências;
  2. Clique no botão de adicionar URL na seção URLs Adicionais para Gerenciador de Placas para adicionar o seguinte URL: https://github.com/earlephilhower/arduino-pico/releases/download/global/package_rp2040_index.json e em seguida clique em OK para fechar a janela.
  3. Clique no botão OK da janela Preferências para salvar as alterações.

A biblioteca Keyboard.h

Para que a placa Raspberry Pi Pico possa enviar comandos para o computador, é necessário utilizar a biblioteca Keyboard.h. Esta biblioteca permite enviar pressionamentos de tecla para um computador conectado através da porta USB do RP Pico. Para programar a placa RP Pico, será utilizado o núcleo Arduino Pico desenvolvido por Earle F. Philhower, III (earlephilhower). Este núcleo possui dois stacks USB. As stacks USB são implementações de protocolos e drivers USB que possibilita a comunicação entre dispositivos Arduino e outros dispositivos por meio da interface USB (Universal Serial Bus: Porta Serial Universal). As duas stacks USB existentes no núcleo do Arduino Pico são: Arduino e Adafruit TinyUSB. A stack Arduino (Pico SDK) é a versão mais simples e a stack Adafruit TinyUSB é a mais completa. A escolha entre essas duas pilhas USB pode ser feita através do menu da Arduino IDE. Para isso,na Arduino IDE, navegue no menu Ferramentas ➜ USB Stack. Então, selecione a opção pico-SDK (stack Arduino) ou a opção Adafruit TinyUSB. Neste post, estaremos utilizando a Stack Arduino (Pico SDK), pois a mesma fornece as funcionalidades necessárias. Para a utilização da biblioteca Keyboard.h não é necessário nenhuma instalação de biblioteca, apenas é necessário ter o núcleo Arduino-Pico (de earlephilhower) instalado em sua IDE Arduino. Para instruções de como instalar este núcleo, confira o tópico anterior Configurando IDE Arduino para a RP Pico.

Caracteres ASCII

Nas funções da biblioteca Keyboard.h em que ocorre o pressionamento de tecla, pode-se utilizar caracteres ASCII. Estes caracteres podem ser expressos em um inteiro, em um caractere, em um hexadecimal ou em um binário. Veja na tabela abaixo os caracteres ASCII compatíveis: *Caracteres ASCII azuis são chamados de caracteres de controle, códigos de controle ou caracteres não imprimíveis; Caracteres ASCII vermelhos são caracteres visíveis/imprimíveis que incluem letras maiúsculas, letras minúsculas, números e pontuação básica; Códigos Hexadecimais devem ser precedidos de '0x'; Códigos Binários devem ser precedidos de '0b'.

Modificadores de teclado e teclas especiais

Assim como ocorre com os caracteres ASCII, também se pode utilizar pressionamentos de teclas modificadoras de teclado e teclas especiais. Confira abaixo as teclas modificadoras e teclas especiais:

Principais funções da biblioteca Keyboard.h

Nota: Quando a placa RP Pico usa comandos de pressionamentos de tecla, é assumido o controle do teclado de seu Computador. Para controlar quando o pressionamento ocorre, é utilizado o botão físico BOOTSEL da placa RP Pico. Para detalhes de como efetuar a leitura do botão BOOTSEL da placa Raspberry Pi Pico, consulte o artigo BOOTSEL da Raspberry Pi Pico no Arduino IDE daqui do blog Eletrogate:
  • void begin(const uint8_t *layout = KeyboardLayout_en_US): Inicia a emulação de um teclado conectado a um computador. Esta função inicia o teclado com o layout fornecido. O layout padrão é o teclado em inglês dos Estados Unidos (en_US).
    • Parâmetros da função:
      • layout: representa o layout do teclado. O layout padrão é KeyboardLayout_en_US. a biblioteca oferece suporte aos seguintes layouts de teclado nacionais:
        • KeyboardLayout_da_DK:Dinamarca;
        • KeyboardLayout_de_DE: Alemanha;
        • KeyboardLayout_en_US: EUA;
        • KeyboardLayout_es_ES: Espanha;
        • KeyboardLayout_fr_FR: França;
        • KeyboardLayout_it_IT: Itália;
        • KeyboardLayout_pt_PT: Portugal;
        • KeyboardLayout_sv_SE: Suécia;
    • Exemplo:
      #include <Keyboard.h>  // Inclui a biblioteca para o uso da emulação de teclado
      
      void setup() {
        Keyboard.begin();  // Inicia a comunicação com o teclado
      }
      
      void loop() {
      
        if (BOOTSEL) {  // Verifica se o botão BOOTSEL foi pressionado
          Keyboard.print("ESP32!"); // Envia uma série de pressionamentos de caracteres
      
          while (BOOTSEL) {}  // Aguarda o usuário soltar o botão BOOTSEL
        }
      
        delay(10); // Atraso de 10 milissegundos
      
      }
  • void end(void): Encerra a emulação do teclado, desligando a comunicação com o computador ao qual o teclado está conectado.
    • Exemplo:
      #include <Keyboard.h>  // Inclui a biblioteca para o uso da emulação de teclado
      
      void setup() {}
      
      void loop() {
      
        if (BOOTSEL) {  // Verifica se o botão BOOTSEL foi pressionado
          Keyboard.begin();  // Inicia a comunicação com o teclado
          Keyboard.print("Teste!");  // Envia uma série de pressionamentos de caracteres
          Keyboard.end();  // Finaliza a comunicação com o teclado
      
          while (BOOTSEL) {}  // Aguarda o usuário soltar o botão BOOTSEL
        }
      
        delay(10); // Atraso de 10 milissegundos
      
      }
  • size_t write(uint8_t k): Envia um pressionamento de tecla para um computador conectado. Isso é semelhante a pressionar e soltar uma tecla do teclado. Somente caracteres ASCII presentes no teclado são suportados, além de  modificadores de teclado adicionais e teclas especiais (como CTRL, SHIFT, ALT, entre outras).
    • Parâmetros da função:
    • Retorno: O número de bytes enviados, que será 1 nesta função.
    • Exemplo:
      #include <Keyboard.h>  // Inclui a biblioteca para o uso da emulação de teclado
      
      void setup() {
        Keyboard.begin();  // Inicia a comunicação com o teclado
      }
      
      void loop() {
      
        if (BOOTSEL) {  // Verifica se o botão BOOTSEL foi pressionado
          Keyboard.write(65);         // pressiona e solta a tecla com código ASCII decimal 65 - letra A
          Keyboard.write(0x42);       // pressiona e solta a tecla com código ASCII hexadecimal 42 - letra B
          Keyboard.write(0b1000011);  // pressiona e solta a tecla com código ASCII binário 1000011 - letra C    
          Keyboard.write('D');        // pressiona e solta a tecla de caractere ASCII 'D'
      
          while (BOOTSEL) {}  // Aguarda o usuário soltar o botão BOOTSEL
        }
      
        delay(10); // Atraso de 10 milissegundos
      
      }
  • size_t write(const uint8_t *buffer, size_t size): Envia uma série de pressionamentos de teclas para um computador conectado. Isso é semelhante a pressionar e soltar sequencialmente várias teclas do teclado. Somente caracteres ASCII presentes no teclado são suportados, além de  modificadores de teclado adicionais e teclas especiais (como CTRL, SHIFT, ALT, entre outras).
    • Parâmetros da função:
      •  buffer: Um ponteiro para o array de bytes (buffer) contendo as teclas a serem pressionadas, com cada byte representando a tecla a ser pressionada e solta. Este byte pode ser um inteiro, um caractere, um hexadecimal ou um binário. Confira a tabela de Caracteres ASCII  e a tabela de Modificadores de teclado e teclas especiais;
      • size: O tamanho do buffer, indicando a quantidade de teclas a serem pressionadas.
    • Retorno: O número de bytes escritos, que será igual a size nesta função.
    • Exemplo:
      #include <Keyboard.h>  // Inclui a biblioteca para o uso da emulação de teclado
      
      void setup() {
        Keyboard.begin();  // Inicia a comunicação com o teclado
      }
      
      void loop() {
      
        if (BOOTSEL) {  // Verifica se o botão BOOTSEL foi pressionado
          uint8_t keyBuffer[] = { 'c', 'a', 'l', 'c', 'u', 'l', 'a', 'd', 'o', 'r', 'a' , '\n'}; // Define um buffer com as teclas a serem pressionadas
          size_t tamanhoBuffer = sizeof(keyBuffer)/sizeof(uint8_t); // Calcula o tamanho do buffer em bytes
          Keyboard.write(keyBuffer,tamanhoBuffer);         // pressiona e solta cada tecla do buffer keyBuffer formando a palavra 'calculadora' com uma quebra de linha
      
          while (BOOTSEL) {}  // Aguarda o usuário soltar o botão BOOTSEL
        }
      
        delay(10); // Atraso de 10 milissegundos
      
      }
  • size_t press(uint8_t k): Simula a pressionamento (como se uma tecla fosse pressionada e mantida pressionada no teclado) de uma tecla no Computador conectado. Está função é útil ao usar teclas modificadoras (como SHIFT, CTRL, ALT, F1, F2, WIN, TAB, entre outros).
    • Parâmetros da função:
    • Retorno: O número de bytes escritos, que será 1 nesta função.
    • Exemplo:
      #include <Keyboard.h>  // Inclui a biblioteca para o uso da emulação de teclado
      
      void setup() {
        Keyboard.begin();  // Inicia a comunicação com o teclado
      }
      
      void loop() {
      
        if (BOOTSEL) {  // Verifica se o botão BOOTSEL foi pressionado
      
          //Série de pressionamentos para abrir o Gerenciador de Tarefas do Windows (Ctrl + Shift + Esc)
          Keyboard.press(KEY_LEFT_CTRL);  // pressiona e mantém pressionada a tecla com chave KEY_LEFT_CTRL (tecla Ctrl esquerda)
          Keyboard.press(KEY_LEFT_SHIFT); // pressiona e mantém pressionada a tecla com chave KEY_LEFT_SHIFT (tecla Shift esquerda)
          Keyboard.press(KEY_ESC);        // pressiona e mantém pressionada a tecla com chave KEY_ESC (tecla Esc)
          delay(100); // atraso de 100 milissegundos
          Keyboard.releaseAll(); // solta todas as teclas pressionadas
          
          while (BOOTSEL) {}  // Aguarda o usuário soltar o botão BOOTSEL
        }
      
        delay(10); // Atraso de 10 milissegundos
      
      }
  • size_t release(uint8_t k): Simula a liberação da tecla especificada que estava mantida pressionada no Computador conectado.
    • Parâmetros da função:
    • Retorno: O número de bytes escritos, que será 1 nesta função.
    • Exemplo:
      #include <Keyboard.h>  // Inclui a biblioteca para o uso da emulação de teclado
      
      void setup() {
        Keyboard.begin();  // Inicia a comunicação com o teclado
      }
      
      void loop() {
      
        if (BOOTSEL) {  // Verifica se o botão BOOTSEL foi pressionado
      
          //Série de pressionamentos para colar a última coisa que estiver na área de trânsferência
          Keyboard.press(KEY_LEFT_CTRL);  // pressiona e mantém pressionada a tecla com chave KEY_LEFT_CTRL (tecla Ctrl esquerda)
          Keyboard.press('v'); // pressiona e mantém pressionada a tecla com caractere ASCII 'v' (tecla v minúsculo)
          delay(100); // atraso de 100 milissegundos
          Keyboard.release(KEY_LEFT_CTRL);   // solta a tecla pressionada especificada
          Keyboard.release('v');  // solta a tecla pressionada especificada
          
          while (BOOTSEL) {}  // Aguarda o usuário soltar o botão BOOTSEL
        }
      
        delay(10); // Atraso de 10 milissegundos
      
      }
  • void releaseAll(void): Simula a liberação de todas as teclas que foram previamente pressionadas no teclado do Computador conectado.
    • Exemplo:
      #include <Keyboard.h>  // Inclui a biblioteca para o uso da emulação de teclado
      
      void setup() {
        Keyboard.begin();  // Inicia a comunicação com o teclado
      }
      
      void loop() {
      
        if (BOOTSEL) {  // Verifica se o botão BOOTSEL foi pressionado
      
          //Série de pressionamentos para abrir o histórico da área de transferência
          Keyboard.press(KEY_LEFT_GUI);  // pressiona e mantém pressionada a tecla com chave KEY_LEFT_GUI (tecla Windows esquerda)
          Keyboard.press('v'); // pressiona e mantém pressionada a tecla com caractere ASCII 'v' (tecla v minúsculo)
          delay(100); // atraso de 100 milissegundos
          Keyboard.releaseAll();   // solta todas as teclas pressionadas
          
          while (BOOTSEL) {}  // Aguarda o usuário soltar o botão BOOTSEL
        }
      
        delay(10); // Atraso de 10 milissegundos
      
      }
  • size_t consumerPress(uint16_t k): Simula o pressionamento de uma tecla de controle multimídia, como play, pause, volume up, volume down, entre outras, no Computador conectado.
    • Parâmetros da Função:
    • Retorno: O número de bytes escritos, que será 1 nesta função.
    • Exemplo:
      #include <Keyboard.h>  // Inclui a biblioteca para o uso da emulação de teclado
      
      void setup() {
        Keyboard.begin();  // Inicia a comunicação com o teclado
      }
      
      void loop() {
      
        if (BOOTSEL) {  // Verifica se o botão BOOTSEL foi pressionado
      
          //Série de pressionamentos para deixar o sistema de áudio do Windows Mudo ou 'desmutado'
          Keyboard.consumerPress(KEY_MUTE);  // pressiona e mantém pressionada a tecla com chave KEY_MUTE (tecla mudo)
          delay(100); // atraso de 100 milissegundos
          Keyboard.consumerRelease();   // solta todas as teclas pressionadas de controle de mídia
          
          while (BOOTSEL) {}  // Aguarda o usuário soltar o botão BOOTSEL
        }
      
        delay(10); // Atraso de 10 milissegundos
      
      }
  • size_t consumerRelease(): Simula a liberação das teclas de controle multimídia no Computador conectado.
    • Retorno: O número de bytes escritos, que será 1 nesta função.
    • Exemplo:
      #include <Keyboard.h>  // Inclui a biblioteca para o uso da emulação de teclado
      
      void setup() {
        Keyboard.begin();  // Inicia a comunicação com o teclado
      }
      
      void loop() {
      
        if (BOOTSEL) {  // Verifica se o botão BOOTSEL foi pressionado
      
          //Série de pressionamentos para pausar/dar play na mídia atual que está tocando no Windows
          Keyboard.consumerPress(KEY_PLAY_PAUSE);  // pressiona e mantém pressionada a tecla com chave KEY_PLAY_PAUSE (tecla play / pause)
          delay(100); // atraso de 100 milissegundos
          Keyboard.consumerRelease();   // solta todas as teclas de controle de mídia pressionadas
          
          while (BOOTSEL) {}  // Aguarda o usuário soltar o botão BOOTSEL
        }
      
        delay(10); // Atraso de 10 milissegundos
      
      }
  • size_t Print::print(const char str[]): Envia um ou mais pressionamentos de tecla para um computador conectado.
    • Parâmetros da Função:
      • str: Um char, int ou uma string representando as teclas a serem enviadas.
    • Retorno: o número de pressionamentos de teclas enviados.
    • Exemplo:
      #include <Keyboard.h>  // Inclui a biblioteca para o uso da emulação de teclado
      
      void setup() {
        Keyboard.begin();  // Inicia a comunicação com o teclado
      }
      
      void loop() {
      
        if (BOOTSEL) {  // Verifica se o botão BOOTSEL foi pressionado
      
          Keyboard.print("abc");  // Envia uma série de pressionamentos de caracteres
          while (BOOTSEL) {}  // Aguarda o usuário soltar o botão BOOTSEL
        }
      
        delay(10); // Atraso de 10 milissegundos
      
      }
  • size_t Print::println(const char c[]): Envia um ou mais pressionamentos de tecla para um computador conectado, seguido por um pressionamento na tecla Enter.
    • Parâmetros da Função:
      • c: Um char, int ou uma string representando as teclas a serem enviadas.
    • Retorno: o número de pressionamentos de teclas enviados.
    • Exemplo:
      #include <Keyboard.h>  // Inclui a biblioteca para o uso da emulação de teclado
      
      void setup() {
        Keyboard.begin();  // Inicia a comunicação com o teclado
      }
      
      void loop() {
      
        if (BOOTSEL) {  // Verifica se o botão BOOTSEL foi pressionado
      
          Keyboard.println("xyz");  // Envia uma série de pressionamentos de caracteres
          while (BOOTSEL) {}  // Aguarda o usuário soltar o botão BOOTSEL
        }
      
        delay(10); // Atraso de 10 milissegundos
      
      }

Detectando status de Num Lock, Caps Lock e Scroll Lock do Computador

Para a placa Raspberry Pi Pico detectar quando o computador estiver com as funções Num Lock, Caps Lock e Scroll Lock ativas é utilizada uma função callback na programação da placa. Esta função é a onLed. Veja abaixo a sintaxe dela: void onLED(LedCallbackFcn fcn, void *cbData = nullptr): Ela possui os seguintes parãmetros:

  • fcn: parâmetro do tipo LedCallbackFcn que aceita uma função de callback cuja assinatura é definida como typedef void(*LedCallbackFcn)(bool numlock, bool capslock, bool scrolllock, bool compose, bool kana, void *cbData);. Os parâmetros desta assinatura da callback são:
    • numlock: parâmetro booleano que indica se a função Num Lock está ativa ou não (ao estar ativada trava as funções no teclado numérico do computador).
    • capslock: parâmetro booleano que indica se a função Caps Lock está ativa ou não (ao estar ativada deixa as letras em maiúsculas).
    • scrolllock: parâmetro booleano que indica se a função Scroll Lock está ativa ou não (ao estar ativada bloqueia a rolagem da página).
    • compose: parâmetro booleano que indica o estado da função Compose ou não (ao estar ativada permite a criação de caracteres especiais, veja mais sobre em Compose key - Wikipedia).
    • kana: parâmetro booleano que indica o estado da função Kana ou não (ao estar ativada permite a inserção de caracteres em sistemas de escrita japonesa, veja mais sobre em Japanese input method - Wikipedia).
    • cbData: parãmetro que permite que dados adicionais possam ser passados para a função de callback.
  • cbData : parãmetro OPCIONAL que permite que dados adicionais possam ser passados para a função de callback.

Exemplo de Utilização

Veja o sketch abaixo que exibe no monitor serial o status atual de Num Lock, Caps Lock e Scroll Lock:
#include <Keyboard.h>  // Inclui a biblioteca para o uso da emulação de teclado

bool nl, cl, sl; // variáveis globais que armazenam o status atual de Num Lock, Caps Lock e Scroll Lock

void ledCallBack(bool numlock, bool capslock, bool scrolllock, bool compose, bool kana, void *cbData) {
  nl = numlock;     // Atualiza o status de Num Lock na variável global
  cl = capslock;    // Atualiza o status de Caps Lock na variável global
  sl = scrolllock;  // Atualiza o status de Scroll Lock na variável global
}

void setup() {
  Serial.begin(115200); // configura o monitor serial em 115200 de baudrate
  Keyboard.onLED(ledCallBack); // Associa a função de callback para monitorar os estados das teclas
  Keyboard.begin();  // Inicia a comunicação com o teclado
}

void loop() {
  Serial.println("--------------------------------------------\n");
  Serial.println("Num Lock \t Caps Lock \t Scroll Lock");
  Serial.print("   ");
  Serial.print(nl);   // Exibe o status atual de Num Lock
  Serial.print("\t\t     ");
  Serial.print(cl);   // Exibe o status atual de Caps Lock
  Serial.print("\t\t      ");
  Serial.println(sl); // Exibe o status atual de Scroll Lock
  Serial.println("--------------------------------------------\n");
  delay(100);
}
Ao sketch ser executado na placa RP Pico e ao ser apertada  as teclas Num Lock, Caps Lock ou Scroll Lock do computador, o monitor serial exibe:

Formatando Strings garantindo consistência independente do Caps Lock

Quando uma String é passada como parâmetro para a função print da biblioteca Keyboard.h e o computador de destino estiver com a função Caps Lock ativada, a String pode ser recebida incorretamente. Veja o exemplo:

#include <Keyboard.h>   // Inclui a biblioteca para o uso da emulação de teclado

void setup() {
  Keyboard.begin();  // Inicia a comunicação com o teclado

}

void loop() {
  if (BOOTSEL) {// Verifica se o botão BOOTSEL foi pressionado

    Keyboard.println("ABCdef"); // Envia uma série de pressionamentos de caracteres
    while (BOOTSEL);// Aguarda o usuário soltar o botão BOOTSEL
  }
  delay(10); // atraso de 10 milissegundos no loop principal
}
Neste código anterior, ao pressionar o botão BOOTSEL seria enviado para o computador:
  • Computador com a função Caps Lock desativada: ABCdef
  • Computador com a função Caps Lock ativada: abcDEF
Como visto, quando a função Caps Lock estiver ativada, os caracteres maiúsculos são recebidos como minúsculos e os caracteres minúsculos são recebidos como maiúsculos. Para resolver isso, basta formatar adequadamente a string antes de enviar para o computador de acordo com o status da função Caps Lock no computador. Para formatar a string, foi criada a função formatarString:
// Função para formatar a string, levando em consideração o estado do Caps Lock .
// Lógica de funcionamento:
//  - se a função Caps Lock do computador estiver acionada: 
//      -> os caracteres da string que forem maiúsculos serão transformados em minúsculos,
//         e os caracteres da string que forem minúsculos serão transformados em maiúsculos;
//
//  - se a função Caps Lock do computador NÃO estiver acionada:
//      -> os caracteres da string que forem maiúsculos permanecerão maiúsculos, 
//         e os caracteres da string que forem minúsculos permanecerão minúsculos.
//
String formatarString(String string, bool capsLockAtivo) {
  if (capsLockAtivo) { // Verifica se o Caps Lock está ativado
    
    for (int i = 0; i < string.length(); i++) { // Percorre cada caractere da string
      
      if (isAlpha(string[i])) { // Verifica se o caractere é uma letra
        
        if (isUpperCase(string[i])) { // Verifica se o caractere é maiúsculo
          string[i] = toLowerCase(string[i]); // Converte para minúsculo
        } else { // se não, caso o caractere seja minúsculo, ...
          string[i] = toUpperCase(string[i]); // Converte para maiúsculo
        }
        
      }
      
    }
    
  }
  return string; // Retorna a string formatada
}
Para utilizar esta função no sketch, basta informar nos parâmetros a string a ser formatada e o status da função Caps Lock no computador. Veja o Exemplo:
#include <Keyboard.h>   // Inclui a biblioteca para o uso da emulação de teclado

bool cl; // variável global que armazena o status atual de Caps Lock

void ledCallBack(bool numlock, bool capslock, bool scrolllock, bool compose, bool kana, void *cbData) {
  cl = capslock;    // Atualiza o status de Caps Lock na variável global
}

void setup() {
  Keyboard.onLED(ledCallBack); // Associa a função de callback para monitorar os estados das teclas
  Keyboard.begin();  // Inicia a comunicação com o teclado
}

void loop() {
  if (BOOTSEL) {// Verifica se o botão BOOTSEL foi pressionado

    Keyboard.println(formatarString("ABCdef", cl)); // Envia uma série de pressionamentos de caracteres, com a string sendo formatada adequadamente
    while (BOOTSEL);// Aguarda o usuário soltar o botão BOOTSEL
  }
  delay(10); // atraso de 10 milissegundos no loop principal
}

// Função para formatar a string, levando em consideração o estado do Caps Lock .
// Lógica de funcionamento:
//  - se a função Caps Lock do computador estiver acionada: 
//      -> os caracteres da string que forem maiúsculos serão transformados em minúsculos,
//         e os caracteres da string que forem minúsculos serão transformados em maiúsculos;
//
//  - se a função Caps Lock do computador NÃO estiver acionada:
//      -> os caracteres da string que forem maiúsculos permanecerão maiúsculos, 
//         e os caracteres da string que forem minúsculos permanecerão minúsculos.
//
String formatarString(String string, bool capsLockAtivo) {
  if (capsLockAtivo) { // Verifica se o Caps Lock está ativado
    
    for (int i = 0; i < string.length(); i++) { // Percorre cada caractere da string
      
      if (isAlpha(string[i])) { // Verifica se o caractere é uma letra
        
        if (isUpperCase(string[i])) { // Verifica se o caractere é maiúsculo
          string[i] = toLowerCase(string[i]); // Converte para minúsculo
        } else { // se não, caso o caractere seja minúsculo, ...
          string[i] = toUpperCase(string[i]); // Converte para maiúsculo
        }
        
      }
      
    }
    
  }
  return string; // Retorna a string formatada
}
Agora, neste código, ao pressionar o botão BOOTSEL seria enviado para o computador:
  • Computador com a função Caps Lock desativada: ABCdef
  • Computador com a função Caps Lock ativada: ABCdef
Como visto, não existe mais o problema anterior de "inversão" maiúsculo/minúsculo.

Projeto: Gerenciador de Autenticação com RP Pico

Agora será mostrado como criar um Gerenciador de Autenticação com a placa Raspberry Pi Pico. Ao se clicar em um dos três pushbuttons conectados à placa RP Pico, será enviado ao computador com Sistema Operacional Windows 11 uma determinada ação:

  • Ao clicar no push button LOGIN: será enviado ao PC a senha armazenada na memória FLASH para que se possa fazer login e entrar em uma sessão no Windows. Para evitar erros de senha errada quando o PC estiver com a função Caps Lock ativada, será utilizada uma função que formata corretamente a senha (String) independentemente de a função Caps Lock estiver ativada ou não;
  • Ao clicar no push button LOGOUT: será enviado ao PC um comando para que se possa fazer logout e sair da sessão do Windows;
  • Ao clicar no push button BLOQUEAR: será enviado ao PC um comando para que se possa bloquear o Windows e que o mesmo possa requisitar ao usuário fazer login novamente para entrar na sessão atual do Windows.

Esquemático do Projeto

Monte o circuito do projeto de acordo com o seguinte esquemático:

Sketch do Projeto

Clique aqui para fazer o download do sketch completo. Antes de prosseguir, modifique o valor das seguintes variáveis no sketch:

  • Arquivo credencial.h
    • senhaWindows: substitua SENHA_WINDOWS pela sua senha de autenticação no Windows 11;
Em seguida, faça o upload do sketch para a placa RP Pico. Veja abaixo o sketch (contendo os arquivos gerenciador_autenticacao_rp_pico.ino e credencial.h):
/******************************************************************************
                      Simule um Teclado com Raspberry Pi Pico
                                          +
                      Gerenciador de Autenticação com RP Pico

                        Criado em 05 de Fevereiro de 2024
                     por Michel Galvão (https://micsg.com.br)

                              Sketch Principal

              Eletrogate | Arduino, Robótica, IoT, Apostilas e Kits
                          https://www.eletrogate.com/
******************************************************************************/

#include <Keyboard.h>   // Inclui a biblioteca para o uso da emulação de teclado
#include "credencial.h" // Inclui o arquivo credencial.h que armazena a senha do Computador Windows

#define pinLogin 17 // Define o pino do botão para acionar a função login
#define pinLogout 16// Define o pino do botão para acionar a função logout
#define pinBloquear 15// Define o pino do botão para acionar a função bloqueio

bool cl; // variável global que armazena o status atual de Caps Lock

void ledCallBack(bool numlock, bool capslock, bool scrolllock, bool compose, bool kana, void *cbData) {
  cl = capslock;    // Atualiza o status de Caps Lock na variável global
}

void setup() {
  Serial.begin(115200); // configura o monitor serial em 115200 de baudrate
  Keyboard.onLED(ledCallBack); // Associa a função de callback para monitorar os estados das teclas
  Keyboard.begin();  // Inicia a comunicação com o teclado
  pinMode(pinLogin, INPUT_PULLUP);// Configura o pino do botão login como entrada com resistor de pull-up interno
  pinMode(pinLogout, INPUT_PULLUP);// Configura o pino do botão logout como entrada com resistor de pull-up interno
  pinMode(pinBloquear, INPUT_PULLUP);// Configura o pino do botão bloqueio como entrada com resistor de pull-up interno
}

void loop() {

  if (!digitalRead(pinLogin)) { // se a leitura do botão login for igual à 0 (LOW), ...

    // Estrutura de controle para esperar o usuário soltar o botão Login
    do {  // Início do bloco 'do'
      delay(100); // Aguarda por 100 milissegundos
    }
    while (!digitalRead(pinLogin));// Continua repetindo o loop enquanto o botão de login estiver em nível lógico baixo (pressionado)

    Serial.println("Login acionado"); // Informa pelo Monitor Serial que a Função Login será executada
    Keyboard.write(KEY_RETURN); // pressiona e solta a tecla ENTER
    delay(500); // pausa o programa por 350 milissegundos
    Keyboard.print(formatarString(senhaWindows, cl)); // Envia uma série de pressionamentos dos caracteres da variável contendo a senha de login do Windows 11, com a senha sendo formatada adequadamente
    delay(150); // pausa o programa por 150 milissegundos
    Keyboard.write(KEY_RETURN); // pressiona e solta a tecla ENTER
  }

  if (!digitalRead(pinLogout)) { // se a leitura do botão logout for igual à 0 (LOW), ...

    // Estrutura de controle para esperar o usuário soltar o botão Logout
    do {  // Início do bloco 'do'
      delay(100); // Aguarda por 100 milissegundos
    }
    while (!digitalRead(pinLogout));  // Continua repetindo o loop enquanto o botão de login estiver em nível lógico baixo (pressionado)

    Serial.println("Logout acionado"); // Informa pelo Monitor Serial que a Função Logout será executada
    Keyboard.press(KEY_LEFT_CTRL);  // pressiona e mantém pressionada a tecla com chave KEY_LEFT_CTRL (tecla Ctrl esquerda)
    Keyboard.press(KEY_LEFT_ALT); // pressiona e mantém pressionada a tecla com chave KEY_LEFT_ALT (tecla Alt)
    Keyboard.press(KEY_DELETE); // pressiona e mantém pressionada a tecla com chave KEY_DELETE (tecla Delete)
    Keyboard.releaseAll();  // solta todas as teclas pressionadas
    delay(500); // pausa o programa por 350 milissegundos
    Keyboard.write(KEY_LEFT_ALT); // pressiona e solta a tecla ALT
    delay(150); // pausa o programa por 100 milissegundos
    Keyboard.write('s');  // pressiona e solta a tecla de caractere ASCII 's' (para fazer logout no Windows 11)
  }

  if (!digitalRead(pinBloquear)) { // se a leitura do botão bloquear for igual à 0 (LOW), ...

    // Estrutura de controle para esperar o usuário soltar o botão Bloquear
    do {  // Início do bloco 'do'
      delay(100); // Aguarda por 100 milissegundos
    }
    while (!digitalRead(pinBloquear));  // Continua repetindo o loop enquanto o botão de bloqueio estiver em nível lógico baixo (pressionado)

    Serial.println("Bloqueio acionado"); // Informa pelo Monitor Serial que a Função Bloquear será executada
    Keyboard.press(KEY_LEFT_CTRL);  // pressiona e mantém pressionada a tecla com chave KEY_LEFT_CTRL (tecla Ctrl esquerda)
    Keyboard.press(KEY_LEFT_ALT); // pressiona e mantém pressionada a tecla com chave KEY_LEFT_ALT (tecla Alt)
    Keyboard.press(KEY_DELETE); // pressiona e mantém pressionada a tecla com chave KEY_DELETE (tecla Delete)
    Keyboard.releaseAll();  // solta todas as teclas pressionadas
    delay(500); // pausa o programa por 350 milissegundos
    Keyboard.write(KEY_LEFT_ALT); // pressiona e solta a tecla ALT
    delay(150); // pausa o programa por 100 milissegundos
    Keyboard.write('b');  // pressiona e solta a tecla de caractere ASCII 'b' (para bloquear o Windows 11)
  }

  delay(10); // atraso de 10 milissegundos no loop principal
}

// Função para formatar a string, levando em consideração o estado do Caps Lock .
// Lógica de funcionamento:
//  - se a função Caps Lock do computador estiver acionada: 
//      -> os caracteres da string que forem maiúsculos serão transformados em minúsculos,
//         e os caracteres da string que forem minúsculos serão transformados em maiúsculos;
//
//  - se a função Caps Lock do computador NÃO estiver acionada:
//      -> os caracteres da string que forem maiúsculos permanecerão maiúsculos, 
//         e os caracteres da string que forem minúsculos permanecerão minúsculos.
//
String formatarString(String string, bool capsLockAtivo) {
  if (capsLockAtivo) { // Verifica se o Caps Lock está ativado
    
    for (int i = 0; i < string.length(); i++) { // Percorre cada caractere da string
      
      if (isAlpha(string[i])) { // Verifica se o caractere é uma letra
        
        if (isUpperCase(string[i])) { // Verifica se o caractere é maiúsculo
          string[i] = toLowerCase(string[i]); // Converte para minúsculo
        } else { // se não, caso o caractere seja minúsculo, ...
          string[i] = toUpperCase(string[i]); // Converte para maiúsculo
        }
        
      }
      
    }
    
  }
  return string; // Retorna a string formatada
}
/******************************************************************************
                      Simule um Teclado com Raspberry Pi Pico
                                          +
                      Gerenciador de Autenticação com RP Pico

                        Criado em 05 de Fevereiro de 2024
                     por Michel Galvão (https://micsg.com.br)

                                    Credencial

              Eletrogate | Arduino, Robótica, IoT, Apostilas e Kits
                          https://www.eletrogate.com/
******************************************************************************/

const char *senhaWindows = "SENHA_WINDOWS"; // variável que armazena a senha de autenticação do Windows

Explicação do Funcionamento

Aqui está um resumo explicativo com base no código:
  1. Bibliotecas e Definições:
    • O código utiliza a biblioteca Keyboard.h para emular um teclado.
    • Há uma inclusão do arquivo credencial.h para obter a senha do Windows.
  2. Definição de Pinos:
    • pinLogin, pinLogout, e pinBloquear são definidos como os pinos dos botões para acionar as funções de login, logout e bloqueio, respectivamente.
  3. Configuração Inicial no Setup:
    • Inicialização da comunicação serial.
    • Inicialização da emulação do teclado.
    • Configuração dos pinos dos botões como entradas com resistor de pull-up interno.
  4. Loop Principal:
    • O loop principal contém três blocos condicionais para cada função: login, logout e bloqueio.
    • Cada bloco verifica se o botão correspondente foi pressionado e, em seguida, executa as ações associadas.
  5. Ações de Login, Logout e Bloqueio:
    • A ação de login envolve pressionar Enter, enviar a senha do Windows (devidamente formatada com a função formatarString, por causa do problema de "inversão" de caractere Maiúsculo/minúsculo) e, em seguida, pressionar Enter novamente.
    • A ação de logout envolve pressionar simultaneamente as teclas Ctrl, Alt e Delete, seguido pelo pressionamento da tecla Alt e o envio da tecla 's' para fazer o logout no Windows.
    • A ação de bloqueio é semelhante ao logout, mas envia a tecla 'b' para bloquear o Windows.
  6. Arquivo credencial.h:
    • O arquivo contém a definição da senha do Windows, armazenada na variável senhaWindows.

Demonstração de Funcionamento do Projeto

Veja no vídeo abaixo o funcionamento do projeto:

Conclusão

Em um passo além do projeto original, pode-se utilizar um Módulo Leitor Biométrico (Impressão Digital) - DY50 ou um Kit Módulo RFID Mfrc522 13.56 Mhz para aprimorar ainda mais a autenticação no Windows e permitir ao usuário que, facilmente, possa se autenticar utilizando sua digital, um cartão RFID ou um chaveiro RFID. Curtiu o post? Avalie e deixe um comentário! Siga-nos também no Instagram e nos marque quando fizer algum projeto nosso: @eletrogate. Até a próxima!

Sobre o Autor


Michel Galvão

Graduando em Engenharia de Software pela UniCV de Maringá/PR. Tem experiência em Automação Residencial e Agrícola. É um Eletrogater Expert. Tem como Hobby Sistemas Embarcados e IoT. É desenvolvedor de software de Sistemas MicSG. Site: https://micsg.com.br/

Aprenda a utilizar a placa Raspberry Pi Pico para emular um teclado USB em um Computador, além disso, veja também como criar um Gerenciador de Autenticação de Computador Windows 11 com RP Pico.

Precisa dos componentes para este projeto?

Encontre tudo na Loja Eletrogate com frete grátis para compras acima de R$ 200

Deixe um comentário

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *