Skip to content

Instantly share code, notes, and snippets.

@TerrorBite
Created March 10, 2026 04:18
Show Gist options
  • Select an option

  • Save TerrorBite/764e9cbeb577484fcf71dd5acad108b9 to your computer and use it in GitHub Desktop.

Select an option

Save TerrorBite/764e9cbeb577484fcf71dd5acad108b9 to your computer and use it in GitHub Desktop.
Keysmash Generator
#include <stdlib.h>
#include <stdio.h>
/* Output string length */
#define OUTMIN 8
#define OUTSPAN 33
/* Define some important constants */
#define MAX_FINGERS 10
#define NUM_ROWS 4
#define HOME_ROW 0
/* Probability-based character selection logic */
#define PROB 100
#define PROB_HANDS 50 // % likelihood to swap hands
#define PROB_HOME 75 // % likelihood to hit home row key
#define PROB_MOVE_ONE 15 // % likelihood to reposition a single finger
#define PROB_SHUFFLE 20 // % likelihood to reposition all fingers of current hand
#define PROB_SYMBOL 5 // % likelihood to include symbols as possible characters when shifting to a new key
#define PROB_OOPS 2 // % likelihood to hit a random symbol key as a one-off
#define PROB_FINGERS 25 // % likelihood to use more/less fingers when repositioning all fingers
/* Shift key logic */
#define PROB_SHIFT 4 // Likelihood to accidentally hit shift for a few keys
#define MAX_SHIFT 14 // Max consecutive keys before unshifting
#define MIN_SHIFT 3 // Min consecutive etc
/* performs touppercase on ASCII. */
static const char* SHIFT_MAP =
" "
" !\"#$%&\"()*+<_>?)!@#$%^&*(::<+>?"
"@ABCDEFGHIJKLMNOPQRSTUVWXYZ{|}^_"
"~ABCDEFGHIJKLMNOPQRSTUVWXYZ{|}~ ";
/* Valid characters. Note duplicates to alter weights */
const char * const chars[] = {
// WITHOUT SYMBOLS
"asdfgasdfgh", // Home row L hand
"ghjklhjkl", // Home row R hand
"qwertyqwert", // Top row L
"yuiopuiop", // Top row R
"zxcvzxcvb", // Bottom row L
"vbnmbnm", // Bottom row R
"12345123456", // Number row L
"678907890", // Number row R
// WITH SYMBOLS
"asdfgh", // Home row L hand
"ghjkl;'", // Home row R hand
"qwerty", // Top row L
"uiop[]\\", // Top row R
"zxcvb", // Bottom row L
"nm,./", // Bottom row R
"`12345", // Number row L
"67890-=", // Number row R
NULL // guard
};
int initRand() {
unsigned int x, c;
FILE *r;
/* Initialize random number generator */
r = fopen("/dev/urandom","r");
if (!r) return 1;
x = 0;
for (c = 0; c < (int)(sizeof(x)/sizeof(char)); c++) x += (fgetc(r) << 8*c);
fclose(r);
srand(x);
return 0;
}
static inline int decide(int prob) {
return prob > rand()%PROB;
}
static inline int randRow() {
/* Probability to use a row other than the home row */
return decide(PROB_HOME) ? HOME_ROW : (1+rand()%(NUM_ROWS-1));
}
char randOne(const char* from) {
/* Select one random char from a null-terminated string.*/
return from[rand()%strlen(from)];
}
char randChar(int hand, int row, char* others) {
char chr, limit;
int symbol;
const char* whichSet;
limit = 0;
do {
symbol = decide(PROB_SYMBOL);
/* Hover over the keys we picked */
whichSet = chars[(symbol<<3)|(row<<1)|(hand&1)];
if(whichSet == NULL) { // just in case
fprintf(stderr,"\n!> chars[] out of bounds\n");
return 255;
}
/* Get the key we're gonna mash */
chr = randOne(whichSet);
limit++;
} while(limit < 32 && strchr(others, chr));
return chr;
}
int getShift() {
int shift;
if(decide(PROB_SHIFT)) {
shift = rand() % (MAX_SHIFT - MIN_SHIFT);
return shift + MIN_SHIFT;
}
return 0;
}
char shift(char c, int shifted) {
if(c<=32) c=255;
return shifted ? SHIFT_MAP[c&127] : c;
}
int keysmash() {
int outlen, hand, c, d, shifted, row, fingers;
int currentFinger, newFinger;
char curchar[MAX_FINGERS+1];
char out[OUTMIN+OUTSPAN];
fingers = 6;
memset(curchar, 0, MAX_FINGERS+1);
outlen = OUTMIN + rand()%OUTSPAN;
/* Initialize the state of the hands */
for (hand = 0; hand < MAX_FINGERS; hand++) {
/* Start on home row always */
curchar[hand] = randChar(hand, HOME_ROW, curchar);
}
shifted = 0;
/* Decide whether to start on the left or right hand */
hand = rand()%fingers;
/* Generate output string */
for (c = 0; c < outlen-1; c++) {
/* Decide whether to move all fingers */
if(decide(PROB_SHUFFLE)) {
/* More or less fingers? */
if(decide(PROB_FINGERS)) {
if(fingers==MAX_FINGERS) hand %= (fingers = 6);
else fingers = MAX_FINGERS;
}
row = randRow();
for(d=hand&1; d<fingers; d+=2) {
curchar[hand] = randChar(hand, row, curchar);
}
}
if(fingers > 2) {
/* Use a different finger */
currentFinger = hand>>1;
newFinger = rand()%((fingers>>1)-1);
if(newFinger>=currentFinger) newFinger++;
hand = (hand&1) | (newFinger<<1);
}
/* Probability to swap hands*/
if(decide(PROB_HANDS)) hand ^= 1;
/* Decide whether to move finger to another key */
if(decide(PROB_MOVE_ONE)) {
curchar[hand] = randChar(hand, randRow(), curchar);
}
/* Mash one (1) key */
/*if(curchar[hand] == ' ') {
fprintf(stderr, "\n!!> hand=%d row=%d\n", hand, row);
}*/
out[c] = shift(
/* Probability for a random symbol key */
decide(PROB_OOPS) ?
randOne(";;'[,") :
curchar[hand],
shifted);
if(shifted) shifted--;
else shifted = getShift();
}
out[outlen-1] = '\0';
/* profit */
puts(out);
return 0;
}
int main(void) {
int i, err;
if(initRand()) return 1;
for(i=0; i<20; i++) {
if((err=keysmash())) return err;
}
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment