Secure Keyboard v2.0 Modern C++ Virtual Keyboard for Windows (Glassmorphism UI, Clipboard Auto-Clear)

Joined
Jun 12, 2020
Messages
60
Reaction score
3
This C++ program implements a modern, secure virtual keyboard for Windows called "Secure Keyboard v2.0." It provides a polished graphical interface with colorful keys featuring dynamic gradients, shadow and hover effects, and smooth animations using double buffering. Alphanumeric keys are randomly shuffled at startup to thwart keyloggers, while modifiers such as Shift, Secure (text masking), NumLock, and Clear manage input states in an editable text area with a blinking cursor. Features include automatic copying to the clipboard with auto-clear after 5 seconds, a secure mode that properly wipes sensitive data from memory, audible feedback, an informative status bar, and full mouse/keyboard event handling via the Win32 API. The UI adopts a contemporary glassmorphism aesthetic and uses a fixed, optimized window size of 1200ᅲ900 pixels. The virtual keyboard's memory is not encrypted and the clipboard is not encrypted either; although the clipboard contents are cleared automatically after copying, copying to the clipboard can still lead to data leakage.
C++:
/*


MIT License


Copyright (c) 2025 CoTon_TiGe_MoUaRf



Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:



The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.



THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.


*/
#include <windows.h>

#include <commctrl.h>

#include <stdlib.h>

#include <time.h>

#include <stdio.h>

#include <string.h>

#include <wchar.h>

#include <math.h>


#pragma comment(lib, "comctl32.lib")

#pragma comment(lib, "user32.lib")

#pragma comment(lib, "gdi32.lib")


#define MAX_INPUT 4096

#define NUM_KEYS 44

#define KEY_GAP 8

#define SHADOW_OFFSET 4
static DWORD clipboardSequenceNumber = 0;

// Structure étendue pour les touches

struct Key {

    int x, y, width, height;

    WCHAR character;

    WCHAR shiftedChar;

    COLORREF normalColor;

    COLORREF hoverColor;

    COLORREF pressedColor;

    COLORREF shadowColor;

    bool isSpecial;

    bool isModifier;

    const char* label;

};


// États globaux

static Key keys[NUM_KEYS];

static int numKeys = NUM_KEYS;

static int pressedKeyIndex = -1;

static int hoverKeyIndex = -1;

static WCHAR inputText[MAX_INPUT] = {0};

static WCHAR secureText[MAX_INPUT] = {0};

static int inputLength = 0;

static int cursorPos = 0;

static bool shiftPressed = false;

static bool capsLock = false;

static bool secureMode = false;

static bool numLock = false;

static bool clipboardTimerActive = false;


// Ressources GDI modernes

static HBRUSH hGradientBrush1 = NULL;

static HBRUSH hGradientBrush2 = NULL;

static HBRUSH hPressedBrush = NULL;

static HBRUSH hHoverBrush = NULL;

static HBRUSH hSpecialBrush = NULL;

static HBRUSH hSecureBrush = NULL;

static HBRUSH hTextBgBrush = NULL;

static HPEN hGlowPen = NULL;

static HPEN hBorderPen = NULL;

static HPEN hShadowPen = NULL;

static HFONT hTitleFont = NULL;

static HFONT hKeyFont = NULL;

static HFONT hTextFont = NULL;

static HFONT hStatusFont = NULL;


// Double buffering

static HDC memDC = NULL;

static HBITMAP memBitmap = NULL;


// Prototypes

LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);

void InsertCharAtCursor(WCHAR ch);

void DeleteCharAtCursor();

void MoveCursorLeft();

void MoveCursorRight();

void ClearClipboardDelayed();

void ShuffleKeys(Key* keys, int numKeys);

void MySecureZeroMemory(void* ptr, size_t size);

int GetCursorXPosition(HDC hdc, const WCHAR* text, int cursorPos);

void DrawGradientRect(HDC hdc, RECT* rect, COLORREF topColor, COLORREF bottomColor);

void DrawModernButton(HDC hdc, Key* key, bool isPressed, bool isHovered);

void DrawGlassEffect(HDC hdc, RECT* rect);

void UpdateKeyPositions(int clientWidth, int clientHeight);

void DrawStatusBar(HDC hdc, RECT* rect);


int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE, LPSTR, int nShowCmd) {

    srand((unsigned int)time(NULL));

   

    const char CLASS_NAME[] = "ModernSecureKeyboardClass";


    WNDCLASSEX wc = {};

    wc.cbSize = sizeof(WNDCLASSEX);

    wc.lpfnWndProc = WindowProc;

    wc.hInstance = hInstance;

    wc.lpszClassName = CLASS_NAME;

    wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);

    wc.hCursor = LoadCursor(NULL, IDC_ARROW);

    wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);

    wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION);

    wc.style = CS_HREDRAW | CS_VREDRAW;


    RegisterClassEx(&wc);


  HWND hwnd = CreateWindowEx(

    WS_EX_APPWINDOW | WS_EX_WINDOWEDGE,

    CLASS_NAME, " Clavier Virtuel Securise Moderne v2.0",  // ← Sans L""

    WS_OVERLAPPEDWINDOW & ~WS_MAXIMIZEBOX & ~WS_THICKFRAME,

    CW_USEDEFAULT, CW_USEDEFAULT,

    1200, 900,

    nullptr, nullptr, hInstance, nullptr

);


    if (hwnd == NULL) return 0;


    // Initialiser les touches avec design moderne

    // Rangée 1: Chiffres

    keys[0] = {0,0,70,60, L'1', L'!', RGB(45,130,255), RGB(55,140,265), RGB(35,110,235), RGB(25,110,235), false, false, "1"};

    keys[1] = {0,0,70,60, L'2', L'@', RGB(45,130,255), RGB(55,140,265), RGB(35,110,235), RGB(25,110,235), false, false, "2"};

    keys[2] = {0,0,70,60, L'3', L'#', RGB(45,130,255), RGB(55,140,265), RGB(35,110,235), RGB(25,110,235), false, false, "3"};

    keys[3] = {0,0,70,60, L'4', L'$', RGB(45,130,255), RGB(55,140,265), RGB(35,110,235), RGB(25,110,235), false, false, "4"};

    keys[4] = {0,0,70,60, L'5', L'%', RGB(45,130,255), RGB(55,140,265), RGB(35,110,235), RGB(25,110,235), false, false, "5"};

    keys[5] = {0,0,70,60, L'6', L'^', RGB(45,130,255), RGB(55,140,265), RGB(35,110,235), RGB(25,110,235), false, false, "6"};

    keys[6] = {0,0,70,60, L'7', L'&', RGB(45,130,255), RGB(55,140,265), RGB(35,110,235), RGB(25,110,235), false, false, "7"};

    keys[7] = {0,0,70,60, L'8', L'*', RGB(45,130,255), RGB(55,140,265), RGB(35,110,235), RGB(25,110,235), false, false, "8"};

    keys[8] = {0,0,70,60, L'9', L'(', RGB(45,130,255), RGB(55,140,265), RGB(35,110,235), RGB(25,110,235), false, false, "9"};

    keys[9] = {0,0,70,60, L'0', L')', RGB(45,130,255), RGB(55,140,265), RGB(35,110,235), RGB(25,110,235), false, false, "0"};


    // Rangée QWERTY

    keys[10] = {0,0,65,60, L'q', L'Q', RGB(100,200,100), RGB(110,210,110), RGB(80,180,80), RGB(70,170,70), false, false, "Q"};

    keys[11] = {0,0,65,60, L'w', L'W', RGB(100,200,100), RGB(110,210,110), RGB(80,180,80), RGB(70,170,70), false, false, "W"};

    keys[12] = {0,0,65,60, L'e', L'E', RGB(100,200,100), RGB(110,210,110), RGB(80,180,80), RGB(70,170,70), false, false, "E"};

    keys[13] = {0,0,65,60, L'r', L'R', RGB(100,200,100), RGB(110,210,110), RGB(80,180,80), RGB(70,170,70), false, false, "R"};

    keys[14] = {0,0,65,60, L't', L'T', RGB(100,200,100), RGB(110,210,110), RGB(80,180,80), RGB(70,170,70), false, false, "T"};

    keys[15] = {0,0,65,60, L'y', L'Y', RGB(100,200,100), RGB(110,210,110), RGB(80,180,80), RGB(70,170,70), false, false, "Y"};

    keys[16] = {0,0,65,60, L'u', L'U', RGB(100,200,100), RGB(110,210,110), RGB(80,180,80), RGB(70,170,70), false, false, "U"};

    keys[17] = {0,0,65,60, L'i', L'I', RGB(100,200,100), RGB(110,210,110), RGB(80,180,80), RGB(70,170,70), false, false, "I"};

    keys[18] = {0,0,65,60, L'o', L'O', RGB(100,200,100), RGB(110,210,110), RGB(80,180,80), RGB(70,170,70), false, false, "O"};

    keys[19] = {0,0,65,60, L'p', L'P', RGB(100,200,100), RGB(110,210,110), RGB(80,180,80), RGB(70,170,70), false, false, "P"};


    // Rangée ASDF

    keys[20] = {0,0,65,60, L'a', L'A', RGB(255,180,100), RGB(255,190,110), RGB(235,160,80), RGB(225,150,70), false, false, "A"};

    keys[21] = {0,0,65,60, L's', L'S', RGB(255,180,100), RGB(255,190,110), RGB(235,160,80), RGB(225,150,70), false, false, "S"};

    keys[22] = {0,0,65,60, L'd', L'D', RGB(255,180,100), RGB(255,190,110), RGB(235,160,80), RGB(225,150,70), false, false, "D"};

    keys[23] = {0,0,65,60, L'f', L'F', RGB(255,180,100), RGB(255,190,110), RGB(235,160,80), RGB(225,150,70), false, false, "F"};

    keys[24] = {0,0,65,60, L'g', L'G', RGB(255,180,100), RGB(255,190,110), RGB(235,160,80), RGB(225,150,70), false, false, "G"};

    keys[25] = {0,0,65,60, L'h', L'H', RGB(255,180,100), RGB(255,190,110), RGB(235,160,80), RGB(225,150,70), false, false, "H"};

    keys[26] = {0,0,65,60, L'j', L'J', RGB(255,180,100), RGB(255,190,110), RGB(235,160,80), RGB(225,150,70), false, false, "J"};

    keys[27] = {0,0,65,60, L'k', L'K', RGB(255,180,100), RGB(255,190,110), RGB(235,160,80), RGB(225,150,70), false, false, "K"};

    keys[28] = {0,0,65,60, L'l', L'L', RGB(255,180,100), RGB(255,190,110), RGB(235,160,80), RGB(225,150,70), false, false, "L"};


    // Rangée ZXCV

    keys[29] = {0,0,70,60, L'z', L'Z', RGB(255,100,150), RGB(255,110,160), RGB(235,80,130), RGB(225,70,120), false, false, "Z"};

    keys[30] = {0,0,70,60, L'x', L'X', RGB(255,100,150), RGB(255,110,160), RGB(235,80,130), RGB(225,70,120), false, false, "X"};

    keys[31] = {0,0,70,60, L'c', L'C', RGB(255,100,150), RGB(255,110,160), RGB(235,80,130), RGB(225,70,120), false, false, "C"};

    keys[32] = {0,0,70,60, L'v', L'V', RGB(255,100,150), RGB(255,110,160), RGB(235,80,130), RGB(225,70,120), false, false, "V"};

    keys[33] = {0,0,70,60, L'b', L'B', RGB(255,100,150), RGB(255,110,160), RGB(235,80,130), RGB(225,70,120), false, false, "B"};

    keys[34] = {0,0,70,60, L'n', L'N', RGB(255,100,150), RGB(255,110,160), RGB(235,80,130), RGB(225,70,120), false, false, "N"};

    keys[35] = {0,0,70,60, L'm', L'M', RGB(255,100,150), RGB(255,110,160), RGB(235,80,130), RGB(225,70,120), false, false, "M"};


    // Touches spéciales modernes

    keys[36] = {0,0,160,60, L' ', L' ', RGB(70,70,70), RGB(90,90,90), RGB(50,50,50), RGB(40,40,40), true, false, "ESPACE"};

    keys[37] = {0,0,80,60, L'\b', L'\b', RGB(255,150,80), RGB(255,160,90), RGB(235,130,60), RGB(225,120,50), true, false, "SUPPR"};

    keys[38] = {0,0,80,60, L'\r', L'\r', RGB(80,200,120), RGB(90,210,130), RGB(60,180,100), RGB(50,170,90), true, false, "ENTREE"};

    keys[39] = {0,0,70,60, L'\x1B', L'\x1B', RGB(255,80,80), RGB(255,90,90), RGB(235,60,60), RGB(225,50,50), true, false, "FERMER"};

   

    // Modificateurs

    keys[40] = {0,0,90,60, L'\0', L'\0', RGB(120,120,255), RGB(130,130,255), RGB(100,100,235), RGB(90,90,225), true, true, "SECURE"};

    keys[41] = {0,0,70,60, L'\0', L'\0', RGB(255,200,100), RGB(255,210,110), RGB(235,180,80), RGB(225,170,70), true, true, "SHIFT"};

    keys[42] = {0,0,70,60, L'\0', L'\0', RGB(100,255,200), RGB(110,255,210), RGB(80,235,180), RGB(70,225,170), true, true, "NUM"};

    keys[43] = {0,0,70,60, L'\0', L'\0', RGB(200,100,255), RGB(210,110,255), RGB(180,80,235), RGB(170,70,225), true, true, "EFFACER"};


    UpdateKeyPositions(1200, 900);

    ShuffleKeys(keys, numKeys);


    ShowWindow(hwnd, nShowCmd);

    UpdateWindow(hwnd);


    MSG msg = {};

    while (GetMessage(&msg, nullptr, 0, 0)) {

        TranslateMessage(&msg);

        DispatchMessage(&msg);

    }


    return 0;

}


void UpdateKeyPositions(int clientWidth, int clientHeight) {

    int margin = 30;

    int startY = 220;   // Début après titre et zone texte

   

    // Positions optimisées pour éviter les chevauchements

    int keyY[5] = {startY, startY + 75, startY + 150, startY + 225, startY + 300};

   

    int rowOffsets[4][10] = {

        {0, 80, 160, 240, 320, 400, 480, 560, 640, 720},     // Chiffres (10)

        {20, 95, 170, 245, 320, 395, 470, 545, 620, 695},    // QWERTY (10)

        {10, 85, 160, 235, 310, 385, 460, 535, 610},         // ASDF (9)

        {50, 130, 210, 290, 370, 450, 530}                   // ZXCV (7)

    };

    int rowCounts[4] = {10, 10, 9, 7};

   

    // Positionner les rangées de lettres

    int keyIndex = 0;

    for (int row = 0; row < 4; row++) {

        for (int col = 0; col < rowCounts[row]; col++) {

            keys[keyIndex].x = margin + rowOffsets[row][col];
             keys[keyIndex].y = keyY[row];

            keyIndex++;

        }

    }


    // Positionner touches spéciales - rangée ESPACE

    keys[36].x = margin + 200;      // ESPACE

    keys[36].y = keyY[4];

   

    keys[37].x = margin + 370;      // SUPPR

    keys[37].y = keyY[4];

   

    keys[38].x = margin + 455;      // ENTREE

    keys[38].y = keyY[4];

   

    keys[39].x = margin + 540;      // FERMER

    keys[39].y = keyY[4];


    // Rangée modificateurs

    keys[40].x = margin + 50;       // SECURE

    keys[40].y = keyY[4] + 75;

   

    keys[41].x = margin + 150;      // SHIFT

    keys[41].y = keyY[4] + 75;

   

    keys[42].x = margin + 230;      // NUM

    keys[42].y = keyY[4] + 75;

   

    keys[43].x = margin + 310;      // EFFACER

    keys[43].y = keyY[4] + 75;

}


void ShuffleKeys(Key* keys, int numKeys) {

    for (int i = 0; i < 36; ++i) { // Ne pas mélanger les 8 dernières (spéciales)

        if (!keys[i].isSpecial && !keys[i].isModifier) {

            int j = rand() % 36;

            if (!keys[j].isSpecial && !keys[j].isModifier) {

                Key temp = keys[i];

                keys[i] = keys[j];

                keys[j] = temp;

            }

        }

    }

}


void MySecureZeroMemory(void* ptr, size_t size) {

    volatile char* p = (volatile char*)ptr;

    while (size--) *p++ = 0;

}


void InsertCharAtCursor(WCHAR ch) {

    if (inputLength + 1 >= MAX_INPUT) return;

   

    memmove(&inputText[cursorPos + 1], &inputText[cursorPos],

            (inputLength - cursorPos) * sizeof(WCHAR));

    inputText[cursorPos] = ch;

    inputLength++;

    cursorPos++;

    inputText[inputLength] = 0;

   

    if (secureMode) {

        wcsncpy(secureText, inputText, inputLength);

        for (int i = 0; i < inputLength; i++) {

            secureText[i] = L'*';

        }

        secureText[inputLength] = 0;

    }

}


void DeleteCharAtCursor() {

    if (cursorPos > 0 && inputLength > 0) {

        cursorPos--;

        memmove(&inputText[cursorPos], &inputText[cursorPos + 1],

                (inputLength - cursorPos - 1) * sizeof(WCHAR));

        inputLength--;

        inputText[inputLength] = 0;

       

        if (secureMode) {

            wcsncpy(secureText, inputText, inputLength);

            for (int i = 0; i < inputLength; i++) {

                secureText[i] = L'*';

            }

            secureText[inputLength] = 0;

        }

    }

}


void MoveCursorLeft() {

    if (cursorPos > 0) cursorPos--;

}


void MoveCursorRight() {

    if (cursorPos < inputLength) cursorPos++;

}


int GetCursorXPosition(HDC hdc, const WCHAR* text, int cursorPos) {

    if (cursorPos <= 0) return 0;

   

    WCHAR substr[512];

    wcsncpy(substr, text, cursorPos);

    substr[cursorPos] = 0;

   

    SIZE size;

    GetTextExtentPoint32W(hdc, substr, cursorPos, &size);

    return size.cx;

}


void DrawGradientRect(HDC hdc, RECT* rect, COLORREF topColor, COLORREF bottomColor) {

    HBRUSH topBrush = CreateSolidBrush(topColor);

    HBRUSH bottomBrush = CreateSolidBrush(bottomColor);

   

    int height = rect->bottom - rect->top;

   

    for (int y = 0; y < height; y++) {

        float t = (float)y / (height - 1);

        COLORREF color = RGB(

            (GetRValue(topColor) * (1.0f - t) + GetRValue(bottomColor) * t),

            (GetGValue(topColor) * (1.0f - t) + GetGValue(bottomColor) * t),

            (GetBValue(topColor) * (1.0f - t) + GetBValue(bottomColor) * t)

        );

       

        HBRUSH gradBrush = CreateSolidBrush(color);

        HBRUSH oldBrush = (HBRUSH)SelectObject(hdc, gradBrush);

       

        RECT lineRect = {rect->left, rect->top + y, rect->right, rect->top + y + 1};

        FillRect(hdc, &lineRect, gradBrush);

       

        SelectObject(hdc, oldBrush);

        DeleteObject(gradBrush);

    }

   

    DeleteObject(topBrush);

    DeleteObject(bottomBrush);

}


void DrawGlassEffect(HDC hdc, RECT* rect) {

    HBRUSH glassBrush = CreateSolidBrush(RGB(255, 255, 255));

    HPEN glassPen = CreatePen(PS_SOLID, 1, RGB(200, 200, 200));

   

    HBRUSH oldBrush = (HBRUSH)SelectObject(hdc, glassBrush);

    HPEN oldPen = (HPEN)SelectObject(hdc, glassPen);

   

    Rectangle(hdc, rect->left + 1, rect->top + 1, rect->right - 1, rect->bottom - 1);

   

    SelectObject(hdc, oldBrush);

    SelectObject(hdc, oldPen);

   

    DeleteObject(glassBrush);

    DeleteObject(glassPen);

}


void DrawModernButton(HDC hdc, Key* key, bool isPressed, bool isHovered) {

    RECT rect = {key->x, key->y, key->x + key->width, key->y + key->height};

    RECT shadowRect = {rect.left + SHADOW_OFFSET, rect.top + SHADOW_OFFSET,

                       rect.right + SHADOW_OFFSET, rect.bottom + SHADOW_OFFSET};


    COLORREF mainColor = isPressed ? key->pressedColor :

                        (isHovered ? key->hoverColor : key->normalColor);

    COLORREF glowColor = isPressed ? key->shadowColor :

                        (isHovered ? key->normalColor : key->shadowColor);


    // Sauvegarde complète du contexte

    HBRUSH hOldBrush = (HBRUSH)GetCurrentObject(hdc, OBJ_BRUSH);

    HPEN hOldPen = (HPEN)GetCurrentObject(hdc, OBJ_PEN);

    COLORREF oldTextColor = GetTextColor(hdc);

    int oldBkMode = GetBkMode(hdc);


    // 1. OMBRE

    HBRUSH hShadowBrush = CreateSolidBrush(key->shadowColor);

    HBRUSH hShadowOld = (HBRUSH)SelectObject(hdc, hShadowBrush);

    FillRect(hdc, &shadowRect, hShadowBrush);

    SelectObject(hdc, hShadowOld);

    DeleteObject(hShadowBrush);


    // 2. DÉGRADÉ

    DrawGradientRect(hdc, &rect, glowColor, mainColor);


    // 3. BORDURES

    if (isHovered || isPressed) {

        HPEN hGlow = CreatePen(PS_SOLID, 3, RGB(255,255,255));

        HPEN hGlowOld = (HPEN)SelectObject(hdc, hGlow);

        Rectangle(hdc, rect.left+1, rect.top+1, rect.right-1, rect.bottom-1);

        SelectObject(hdc, hGlowOld);

        DeleteObject(hGlow);

    }


    HPEN hBorder = CreatePen(PS_SOLID, 2, isPressed ? RGB(100,100,100) : RGB(150,150,150));

    HPEN hBorderOld = (HPEN)SelectObject(hdc, hBorder);

    Rectangle(hdc, rect.left, rect.top, rect.right, rect.bottom);

    SelectObject(hdc, hBorderOld);

    DeleteObject(hBorder);


    // 4. TEXTE

    SetBkMode(hdc, TRANSPARENT);

    SetTextColor(hdc, isPressed ? RGB(255,255,255) : RGB(40,40,40));

    RECT textRect = {rect.left + 8, rect.top + 8, rect.right - 8, rect.bottom - 8};

    DrawTextA(hdc, key->label, -1, &textRect, DT_SINGLELINE | DT_CENTER | DT_VCENTER);


    // RESTAURATION COMPLÈTE

    SelectObject(hdc, hOldBrush);

    SelectObject(hdc, hOldPen);

    SetTextColor(hdc, oldTextColor);

    SetBkMode(hdc, oldBkMode);

}


void DrawStatusBar(HDC hdc, RECT* rect) {

    DrawGradientRect(hdc, rect, RGB(50,50,60), RGB(30,30,40));

   

    HPEN glowPen = CreatePen(PS_SOLID, 1, RGB(100,100,120));

    HPEN oldPen = (HPEN)SelectObject(hdc, glowPen);

    Rectangle(hdc, rect->left, rect->top, rect->right, rect->bottom);

    SelectObject(hdc, oldPen);

    DeleteObject(glowPen);

   

    char status[256];

    sprintf(status, "SECURE: %s | SHIFT: %s | CAPS: %s | NUM: %s | %d/%d caracteres | Positions: ALEATOIRES",

           secureMode ? "ON" : "OFF",

           shiftPressed ? "ON" : "OFF",

           capsLock ? "ON" : "OFF",

           numLock ? "ON" : "OFF",

           inputLength, MAX_INPUT - 1);

   

    COLORREF oldTextColor = GetTextColor(hdc);

    int oldBkMode = GetBkMode(hdc);

   

    SetTextColor(hdc, RGB(220,220,240));

    SetBkMode(hdc, TRANSPARENT);

    RECT textRect = {rect->left + 15, rect->top + 5, rect->right - 15, rect->bottom - 5};

    DrawTextA(hdc, status, -1, &textRect, DT_SINGLELINE | DT_VCENTER);

   

    SetTextColor(hdc, oldTextColor);

    SetBkMode(hdc, oldBkMode);

}

void ClearClipboardDelayed() {

    DWORD curSeq = GetClipboardSequenceNumber();

    if (curSeq != clipboardSequenceNumber) return; // Clipboard modifié par utilisateur

   

    if (OpenClipboard(NULL)) {

        EmptyClipboard();

        CloseClipboard();

    }

}


LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {

    static int textLineHeight = 0;

    static int clientWidth = 1200, clientHeight = 850;


    switch (uMsg) {

        case WM_CREATE:

            hTitleFont = CreateFont(28, 0, 0, 0, FW_BOLD, FALSE, FALSE, FALSE,

                                  DEFAULT_CHARSET, OUT_DEFAULT_PRECIS,

                                  CLIP_DEFAULT_PRECIS, CLEARTYPE_QUALITY,

                                  DEFAULT_PITCH, "Segoe UI");

            hKeyFont = CreateFont(16, 0, 0, 0, FW_SEMIBOLD, FALSE, FALSE, FALSE,

                                DEFAULT_CHARSET, OUT_DEFAULT_PRECIS,

                                CLIP_DEFAULT_PRECIS, CLEARTYPE_QUALITY,

                                DEFAULT_PITCH, "Segoe UI");

            hTextFont = CreateFont(18, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE,

                                 DEFAULT_CHARSET, OUT_DEFAULT_PRECIS,

                                 CLIP_DEFAULT_PRECIS, CLEARTYPE_QUALITY,

                                 DEFAULT_PITCH, "Consolas");

            hStatusFont = CreateFont(12, 0, 0, 0, FW_MEDIUM, FALSE, FALSE, FALSE,

                                   DEFAULT_CHARSET, OUT_DEFAULT_PRECIS,

                                   CLIP_DEFAULT_PRECIS, CLEARTYPE_QUALITY,

                                   DEFAULT_PITCH, "Segoe UI");

           

            hSecureBrush = CreateSolidBrush(RGB(255, 248, 240));

            hTextBgBrush = CreateSolidBrush(RGB(248, 250, 255));

            hPressedBrush = CreateSolidBrush(RGB(200, 200, 220));

            hHoverBrush = CreateSolidBrush(RGB(230, 230, 250));

           

            hGlowPen = CreatePen(PS_SOLID, 2, RGB(100, 150, 255));

            hBorderPen = CreatePen(PS_SOLID, 1, RGB(180, 180, 190));

            hShadowPen = CreatePen(PS_SOLID, 1, RGB(120, 120, 140));

            return 0;


        case WM_MOUSEMOVE: {

            POINT p;

            GetCursorPos(&p);

            ScreenToClient(hwnd, &p);

           

            int oldHover = hoverKeyIndex;

            hoverKeyIndex = -1;

           

            for (int i = 0; i < numKeys; i++) {

                if (p.x >= keys[i].x && p.x <= keys[i].x + keys[i].width &&

                    p.y >= keys[i].y && p.y <= keys[i].y + keys[i].height) {

                    hoverKeyIndex = i;

                    break;

                }

            }

           

            if (oldHover != hoverKeyIndex) {

                RECT updateRect = {0, 0, clientWidth, clientHeight};

                InvalidateRect(hwnd, &updateRect, FALSE);

            }

            return 0;

        }


        case WM_LBUTTONDOWN: {

            POINT p;

            GetCursorPos(&p);

            ScreenToClient(hwnd, &p);


            for (int i = 0; i < numKeys; i++) {

                if (p.x >= keys[i].x && p.x <= keys[i].x + keys[i].width &&

                    p.y >= keys[i].y && p.y <= keys[i].y + keys[i].height) {

                   

                    pressedKeyIndex = i;

                    Sleep(rand() % 15 + 5);

                   

                    if (keys[i].isModifier) {

                        if (strcmp(keys[i].label, "SECURE") == 0) {

                            secureMode = !secureMode;

                        } else if (strcmp(keys[i].label, "SHIFT") == 0) {

                            shiftPressed = !shiftPressed;

                        } else if (strcmp(keys[i].label, "NUM") == 0) {

                            numLock = !numLock;

                        } else if (strcmp(keys[i].label, "EFFACER") == 0) {

                            MySecureZeroMemory(inputText, sizeof(inputText));

                            MySecureZeroMemory(secureText, sizeof(secureText));

                            inputLength = 0;

                            cursorPos = 0;

                        }

                    } else if (keys[i].character == L'\x1B') {

                        PostQuitMessage(0);

                    } else if (keys[i].character == L' ') {

                        InsertCharAtCursor(L' ');

                    } else if (keys[i].character == L'\b') {

                        DeleteCharAtCursor();

                    } else if (keys[i].character == L'\r') {

                        InsertCharAtCursor(L'\n');

                    } else if (!keys[i].isSpecial && keys[i].character >= L' ') {

                        WCHAR ch = (shiftPressed || capsLock) ? keys[i].shiftedChar : keys[i].character;

                        InsertCharAtCursor(ch);

                    }

                   

                    Beep(900 + rand() % 200, 60);

                    SetCapture(hwnd);

                    InvalidateRect(hwnd, NULL, TRUE);

                    break;

                }

            }

            return 0;

        }


        case WM_LBUTTONUP: {

            if (pressedKeyIndex != -1) {

                RECT rect = {keys[pressedKeyIndex].x - 10, keys[pressedKeyIndex].y - 10,

                            keys[pressedKeyIndex].x + keys[pressedKeyIndex].width + 10,

                            keys[pressedKeyIndex].y + keys[pressedKeyIndex].height + 10};

                pressedKeyIndex = -1;

                InvalidateRect(hwnd, &rect, FALSE);

            }

            ReleaseCapture();

            return 0;

        }


        case WM_CHAR: {

    WCHAR ch = (WCHAR)wParam;

    if (ch == VK_BACK) {

        DeleteCharAtCursor();

    } else if (ch == '\r' || ch == '\n') {

        if (!secureMode || MessageBoxW(hwnd, L"Copier le texte ? (Clipboard auto-efface 5s)",

                                     L"Confirmation", MB_YESNO | MB_ICONQUESTION) == IDYES) {

            if (OpenClipboard(hwnd)) {

                EmptyClipboard();

                HGLOBAL hMem = GlobalAlloc(GMEM_MOVEABLE, (inputLength + 1) * sizeof(WCHAR));

                if (hMem) {

                    WCHAR* pMem = (WCHAR*)GlobalLock(hMem);

                    wcsncpy(pMem, inputText, inputLength);

                    pMem[inputLength] = 0;

                    GlobalUnlock(hMem);

                    SetClipboardData(CF_UNICODETEXT, hMem);

                    CloseClipboard();

                   

                    // ✅ SAUVEGARDE LE NUMÉRO DE SÉQUENCE

                    clipboardSequenceNumber = GetClipboardSequenceNumber();

                    SetTimer(hwnd, 1, 5000, NULL);

                }

            }

        }

        InsertCharAtCursor(L'\n');

    } else if (ch >= 32 && ch <= 127 && inputLength < MAX_INPUT - 1) {

        InsertCharAtCursor(ch);

    }

    InvalidateRect(hwnd, NULL, TRUE);

    return 0;

}


        case WM_KEYDOWN: {

            switch (wParam) {

                case VK_ESCAPE: PostQuitMessage(0); break;

                case VK_LEFT: MoveCursorLeft(); break;

                case VK_RIGHT: MoveCursorRight(); break;

                case VK_HOME: cursorPos = 0; break;

                case VK_END: cursorPos = inputLength; break;

                case VK_BACK: DeleteCharAtCursor(); break;

                case VK_SHIFT: shiftPressed = true; break;

                case VK_CAPITAL: capsLock = !capsLock; break;

                case 'S':

                    if (GetKeyState(VK_CONTROL) & 0x8000) secureMode = !secureMode;

                    break;

            }

            InvalidateRect(hwnd, NULL, TRUE);

            return 0;

        }


        case WM_KEYUP: {

            if (wParam == VK_SHIFT) shiftPressed = false;

            InvalidateRect(hwnd, NULL, TRUE);

            return 0;

        }


        case WM_TIMER: {

    if (wParam == 1) {

        ClearClipboardDelayed();  // ✅ UTILISE LA FONCTION SÉCURISÉE

        KillTimer(hwnd, 1);

    }

    return 0;

}


        case WM_SIZE: {

            clientWidth = LOWORD(lParam);

            clientHeight = HIWORD(lParam);

            UpdateKeyPositions(clientWidth, clientHeight);

           

            if (memDC) DeleteDC(memDC);

            if (memBitmap) DeleteObject(memBitmap);

           

            RECT rect;

            GetClientRect(hwnd, &rect);

            HDC hdcSize = GetDC(hwnd);

            memDC = CreateCompatibleDC(hdcSize);

            memBitmap = CreateCompatibleBitmap(hdcSize, rect.right, rect.bottom);

            ReleaseDC(hwnd, hdcSize);

            return 0;

        }


        case WM_SETFOCUS: {

            CreateCaret(hwnd, (HBITMAP)NULL, 2, 28);

            ShowCaret(hwnd);

            return 0;

        }


        case WM_KILLFOCUS: {

            HideCaret(hwnd);

            DestroyCaret();

            return 0;

        }


case WM_PAINT: {

    PAINTSTRUCT ps;

    HDC hdcPaint = BeginPaint(hwnd, &ps);

   

    HDC targetDC = hdcPaint;

    HBITMAP oldBitmap = NULL;


    if (memDC) {

        targetDC = memDC;

        oldBitmap = (HBITMAP)SelectObject(memDC, memBitmap);

    }


    RECT clientRect;

    GetClientRect(hwnd, &clientRect);


    int clientWidth = clientRect.right;

    int clientHeight = clientRect.bottom;


    // Fond dégradé moderne

    DrawGradientRect(targetDC, &clientRect, RGB(240, 245, 255), RGB(220, 230, 245));


    // Sauvegarder contexte GDI

    HFONT oldTitleFont = (HFONT)SelectObject(targetDC, hTitleFont);

    HFONT oldKeyFont = (HFONT)SelectObject(targetDC, hKeyFont);

    HFONT oldTextFont = (HFONT)SelectObject(targetDC, hTextFont);

    HFONT oldStatusFont = (HFONT)SelectObject(targetDC, hStatusFont);


    SetBkMode(targetDC, TRANSPARENT);


// Titre principal SANS OMBRE - Ultra lisible
// Titre sans emoji - rentre parfaitement

SetTextColor(targetDC, RGB(25, 45, 80));

SelectObject(targetDC, hTitleFont);


RECT titleRect = {40, 25, clientWidth - 40, 60};

DrawTextA(targetDC, "CLAVIER SECURISE v2.0", -1, &titleRect,

         DT_SINGLELINE | DT_LEFT | DT_VCENTER);


// Sous-titre amélioré

SetTextColor(targetDC, RGB(80, 100, 140));  // ← Gris-bleu clair

SelectObject(targetDC, hStatusFont);

TextOutA(targetDC, 40, 70, "Positions aleatoires anti-keylogger | CTRL+S = Mode securise | Ctrl+Entree = Copier (5s)", 65);


// 🔥 ZONE DE TEXTE - SANS OMBRE/GLASS - Ultra lisible

RECT textLabelRect = {30, 90, clientWidth - 40, 115};

FillRect(targetDC, &textLabelRect, hSecureBrush);  // Fond uni seulement


char labelText[256];

sprintf(labelText, "Zone de saisie %s- Copier: Ctrl+Entree (Clipboard auto-efface 5s) | <- -> Curseur",

       secureMode ? "SECURISE" : "NORMAL");


SetTextColor(targetDC, secureMode ? RGB(90, 50, 20) : RGB(20, 60, 120));

SelectObject(targetDC, hStatusFont);


RECT labelRect = {45, 95, clientWidth - 45, 120};

DrawTextA(targetDC, labelText, -1, &labelRect, DT_SINGLELINE | DT_VCENTER);


    // Zone d'affichage texte - FIXE et LIMITÉE

    RECT textRect = {30, 120, clientWidth - 40, 200};  // ← Hauteur limitée à 80px

    HBRUSH textBg = secureMode ? hSecureBrush : hTextBgBrush;

    FillRect(targetDC, &textRect, textBg);

    DrawGlassEffect(targetDC, &textRect);


    const WCHAR* displayText = secureMode ? secureText : inputText;

    RECT displayRect = {50, 130, clientWidth - 50, 190};  // ← Position corrigée


    SetTextColor(targetDC, secureMode ? RGB(80, 50, 30) : RGB(40, 50, 70));

    SelectObject(targetDC, hTextFont);

    DrawTextW(targetDC, displayText, -1, &displayRect,

             DT_WORDBREAK | DT_LEFT | DT_NOPREFIX | DT_EDITCONTROL);


    // Dessiner toutes les touches APRÈS la zone texte

    SelectObject(targetDC, hKeyFont);

    for (int i = 0; i < numKeys; i++) {

        bool isPressed = (i == pressedKeyIndex);

        bool isHovered = (i == hoverKeyIndex);

        DrawModernButton(targetDC, &keys[i], isPressed, isHovered);

    }


    // Barre de statut

    RECT statusRect = {10, clientHeight - 45, clientWidth - 20, clientHeight - 5};

    DrawStatusBar(targetDC, &statusRect);


    // Curseur - POSITION CORRIGÉE

    if (GetFocus() == hwnd && textLineHeight == 0) {

        TEXTMETRIC tm;

        GetTextMetrics(targetDC, &tm);

        textLineHeight = tm.tmHeight;

    }


    if (GetFocus() == hwnd) {

        int cursorX = GetCursorXPosition(targetDC, displayText, cursorPos);

        int cursorY = 130 + (cursorPos / 60) * textLineHeight;  // ← Y corrigé

        SetCaretPos(50 + cursorX, cursorY);

    }


    // Restaurer contexte GDI

    SelectObject(targetDC, oldTitleFont);

    SelectObject(targetDC, oldKeyFont);

    SelectObject(targetDC, oldTextFont);

    SelectObject(targetDC, oldStatusFont);


    // BitBlt double buffering

    if (memDC && oldBitmap) {

        BitBlt(hdcPaint, 0, 0, clientRect.right, clientRect.bottom,

               memDC, 0, 0, SRCCOPY);

        SelectObject(memDC, oldBitmap);

    }


    EndPaint(hwnd, &ps);

    return 0;

} // ✅ } FERME LE BLOC WM_PAINT


case WM_SYSCOMMAND: {

    if (wParam == SC_CLOSE) {

        MySecureZeroMemory(inputText, sizeof(inputText));

        MySecureZeroMemory(secureText, sizeof(secureText));

    }

    return DefWindowProc(hwnd, uMsg, wParam, lParam);

}


case WM_DESTROY: {

    // Nettoyage complet et sécurisé

    if (hTitleFont) DeleteObject(hTitleFont);

    if (hKeyFont) DeleteObject(hKeyFont);

    if (hTextFont) DeleteObject(hTextFont);

    if (hStatusFont) DeleteObject(hStatusFont);

    if (hSecureBrush) DeleteObject(hSecureBrush);

    if (hTextBgBrush) DeleteObject(hTextBgBrush);

    if (hPressedBrush) DeleteObject(hPressedBrush);

    if (hHoverBrush) DeleteObject(hHoverBrush);

    if (hGlowPen) DeleteObject(hGlowPen);

    if (hBorderPen) DeleteObject(hBorderPen);

    if (hShadowPen) DeleteObject(hShadowPen);

    if (memDC) DeleteDC(memDC);

    if (memBitmap) DeleteObject(memBitmap);

   

    MySecureZeroMemory(inputText, sizeof(inputText));

    MySecureZeroMemory(secureText, sizeof(secureText));

   

    PostQuitMessage(0);

    return 0;

}

}  // ✅ } FERME LE SWITCH


return DefWindowProc(hwnd, uMsg, wParam, lParam);

}
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
474,444
Messages
2,571,709
Members
48,796
Latest member
Greg L.
Top