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);
}