Created
March 10, 2026 04:18
-
-
Save TerrorBite/764e9cbeb577484fcf71dd5acad108b9 to your computer and use it in GitHub Desktop.
Keysmash Generator
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #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