#include // Declare pointers to variables we access in Novatouch fw unsigned char* const repeat_flags = (unsigned char*)0x2404; unsigned char* const repeat_rate = (unsigned char*)0x252f; unsigned char* const num_for_7x_c1 = (unsigned char*)0x2530; unsigned char* const current_keycode = (unsigned char*)0x2400; // Defines for internal scancodes (corresponding to scancode_table_1). Find out // missing ones by using table at bottom of README.org. //#define KEY_H 0x24 //#define KEY_J 0x25 //#define KEY_K 0x26 //#define KEY_L 0x27 #define KEY_W 0x0 #define KEY_A 0x0 #define KEY_S 0x0 #define KEY_D 0x0 #define KEY_Z 0x0 #define KEY_C 0x0 #define KEY_R 0x0 #define KEY_F 0x0 #define KEY_UP 0x53 #define KEY_DOWN 0x54 #define KEY_LEFT 0x4f #define KEY_RIGHT 0x59 #define KEY_SPACE 0x0 #define KEY_BACKSPACE 0x0 #define KEY_HOME 0x0 #define KEY_END 0x0 #define KEY_PAGEUP 0x0 #define KEY_PAGEDOWN 0x0 #define KEY_TAB 0x0 #define KEY_CAPSLOCK 0x0 // Seems like original FW is compiled with IAR compiler and has different // calling convention than mspgcc. Use macro to call functions and get correct // parameter passing. #define QUEUE_KEY(code) asm("mov.b %0, r12\n" \ "calla #0x91a2" : : "i"(code)) #define UNQUEUE_KEY(code) asm("mov.b %0, r12\n" \ "calla #0x9086" : : "i"(code)) // To be called when key is pressed and fn is also pressed void on_fn_key_down() { // We just replaced this copy to get here, perform it here instead // (although it seems to be redundant because it is never actually // read) *num_for_7x_c1 = *repeat_rate; // Enter BSL if fn + f1 + f4 is pressed if ((*repeat_flags & 0x9) == 0x09) { __dint(); // Maybe need to slow down clock to 8 MHz also, not sure what // is configured by Novatouch fw USBKEYPID = 0x9628; USBCNF &= ~PUR_EN; USBPWRCTL &= ~VBOFFIE; USBKEYPID = 0x9600; ((void (*)())0x1000)(); } // Extra bindings for fn + key switch (*current_keycode) { case KEY_A: QUEUE_KEY(KEY_LEFT); break; case KEY_S: QUEUE_KEY(KEY_DOWN); break; case KEY_W: QUEUE_KEY(KEY_UP); break; case KEY_D: QUEUE_KEY(KEY_RIGHT); break; case KEY_SPACE: QUEUE_KEY(KEY_BACKSPACE); break; case KEY_Z: QUEUE_KEY(KEY_HOME); break; case KEY_C: QUEUE_KEY(KEY_END); break; case KEY_R: QUEUE_KEY(KEY_PAGEUP); break; case KEY_F: QUEUE_KEY(KEY_PAGEDOWN); break; case KEY_TAB: QUEUE_KEY(KEY_CAPSLOCK); break; } } // To be called when key is released and fn is also down void on_fn_key_up() { // Extra bindings for fn + key switch (*current_keycode) { case KEY_A: UNQUEUE_KEY(KEY_LEFT); break; case KEY_S: UNQUEUE_KEY(KEY_DOWN); break; case KEY_W: UNQUEUE_KEY(KEY_UP); break; case KEY_D: UNQUEUE_KEY(KEY_RIGHT); break; case KEY_SPACE: UNQUEUE_KEY(KEY_BACKSPACE); break; case KEY_Z: UNQUEUE_KEY(KEY_HOME); break; case KEY_C: UNQUEUE_KEY(KEY_END); break; case KEY_R: UNQUEUE_KEY(KEY_PAGEUP); break; case KEY_F: UNQUEUE_KEY(KEY_PAGEDOWN); break; case KEY_TAB: UNQUEUE_KEY(KEY_CAPSLOCK); break; default: // Moar ugly hacks! To hook this function we replaced the // original call to unqueue key, setup original argument and // do the call. asm("mov.b &0x2400, r12\n" "calla #0x9086"); break; } }