/********************************************************************* halfqwerty.c: modify the keyboard for one-handed typing. This module reflects the keyboard through the gh line when the space bar is held down, to facilitate one-handed typing. This is also known as half qwerty. So far, this could be done by loadkeys, but we add an additional constraint. Hitting space bar alone enters a space. That can't be done by loadkeys, because you have to monitor the release (key up) codes. But this module can do it. Copyright (C) Karl Dahlke, 2008. This software may be freely distributed under the GPL, general public license, as articulated by the Free Software Foundation. This module uses notifiers, and will not work with kernels prior to 2.6.24. Type `uname -a` to find your kernel version. Compile this as a lkernel module on your system. Then run insmod on the resulting kernel object. *********************************************************************/ #include #include #include #include #include #include #include #include MODULE_LICENSE("GPL"); MODULE_AUTHOR("Karl Dahlke - eklhad@gmail.com"); MODULE_DESCRIPTION("Half qwerty keyboard for the one-handed typist."); /* Pass characters to the tty, when changing the keystrokes. */ static void tty_pushchar(int minor, int ch) { struct vc_data *d = vc_cons[minor - 1].d; struct tty_struct *tty; if(!d) return; tty = d->vc_tty; if(!tty) return; tty_insert_flip_char(tty, ch, 0); con_schedule_flip(tty); } /* tty_pushchar */ /* Reverse the keyboard, with and without shift */ static const char lowercode[] = " -0987654321`\033 [poiuytrewq\t ;lkjhgfdsa /.,mnbvcxz"; static const char uppercode[] = " +)(*&^%$#@!~\033 {POIUYTREWQ\t :LKJHGFDSA ?>value; struct vc_data *vc = param->vc; int minor = vc->vc_num + 1; int downflag = param->down; int shiftstate = param->shift; static char spaceDown = 0; static char spaceUsed = 0; unsigned char is_shift = (shiftstate & 0x01) != 0; unsigned char is_alt = (shiftstate & 0x0a) != 0; unsigned char is_ctrl = (shiftstate & 0x04) != 0; const char *remap; char new_c; /* Sorry, this doesn't work in unicode. */ if(type != KBD_KEYCODE) return NOTIFY_DONE; /* Handle space bar first, that's the strange one. */ if(key == 0x39) { if(downflag == 0) { if(spaceDown && !spaceUsed) tty_pushchar(minor, ' '); spaceDown = 0; } else if(downflag == 1) { spaceDown = 1, spaceUsed = 0; } /* downflag = 2 means autorepeat, but we don't have to do anything here. */ return NOTIFY_STOP; } /* We don't remap control or alt characters, yet. */ if(is_ctrl | is_alt) return NOTIFY_DONE; /* Don't change function keys, and other high keys. */ if(key > 0x35) return NOTIFY_DONE; if(!downflag) return NOTIFY_DONE; spaceUsed = 1; remap = (is_shift ? uppercode : lowercode); new_c = remap[key]; /* We only need worry about the remapped keys. */ if(new_c == ' ') return NOTIFY_DONE; if(!spaceDown) return NOTIFY_DONE; tty_pushchar(minor, new_c); /* Watch here; I am discarding a keyboard event, so I can push my own character. But later, I don't discard the release of that key. So an up event comes along with no down event. Fortunately, the kernel tolerates this, or I'd have to do a lot more bookkeeping. */ return NOTIFY_STOP; } /* keystroke */ static struct notifier_block nb = { .notifier_call = keystroke }; static int __init checkinit(void) { return register_keyboard_notifier(&nb); } /* checkinit */ static void __exit checkexit(void) { unregister_keyboard_notifier(&nb); } /* checkexit */ module_init(checkinit); module_exit(checkexit);