# usbhotkey script to handle the Alphagrip AG5 # Copyright (C) 2007 Lars Krueger # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA # We assume a UK keymap here. For a US keymap exchange " and @ print "usbhotkey AG5 script starting\n" # This script places all mappings in ruby tables which are indexed by some # state variable and the USB scan code. The keys are mapped to a # normalised id first. # The basic idea of this script is to provide access to both the red and green # colour levels. This is done by remapping the thumb keys so that they work as # shift keys. This script maps K to green and L to the red shift key. The # right hand side is handled accordingly. Support for more modifiers (Ctrl, # Alt, Windows) may be added later. # # A letter key produces a letter if it is pressed and release alone, thus # K-press, K-release produces a k. K-press, N-press, N-release, K-release # produces Green-N, therefore the question mark. This makes the shift letters # generate events at release and therefore turns off auto-repeat for these # keys. # # All keys can send X11 keycode sequences of arbitrary length. ##################################### Keymap ################################### #================================ USB code to id =============================== KeyId={ USB_g => 0 , USB_r => 1 , USB_f => 2 , USB_t => 3 , USB_d => 4 , USB_e => 5 , USB_w => 6 , USB_s => 7 , USB_q => 8 , USB_a => 9 , USB_m => 10, USB_h => 11, USB_n => 12, USB_u => 13, USB_i => 14, USB_Comma => 15, USB_o => 16, USB_Period => 17, USB_p => 18, USB_b => 19, USB_j => 20, USB_v => 21, USB_x => 22, USB_z => 23, USB_c => 24, USB_y => 25, USB_k => 26, USB_l => 27, USB_Enter => 28, USB_Backspace => 29, USB_Space => 30, USB_Tab => 31, } #================================= colour keys ================================= # Map key id to colour. Regular key codes are handled below ColourKeys={ # Green: k, tab 26 => 1, 31 => 1, # Red: l, space 27 => 2, 30 => 2, # Fn: v, x 21 => 3, 22 => 3, # Ctrl: c, backspace 24 => 4, 29 => 4, # Alt: j, z 20 => 5, 23 => 5, # Win: y, enter 25 => 6, 28 => 6, } #================================ Normal keymap ================================ # Dimension 1 shift state # Dimension 2 by colorshift values # Dimension 3 by backside ID KeyMap=[[], []] # Normal keymap # g|r|f|t|d|e|w|s|q|a|m|h|n|u|i|,|o|.|p|b" KeyMap[0][0] = [ [ WIN_G], [ WIN_R], [ WIN_F], [ WIN_T], [ WIN_D], [ WIN_E], [ WIN_W], [ WIN_S], [ WIN_Q], [ WIN_A], [ WIN_M], [ WIN_H], [ WIN_N], [ WIN_U], [ WIN_I], [ WIN_comma], [ WIN_O], [ WIN_period], [ WIN_P], [ WIN_B], [ WIN_J], [ WIN_V], [ WIN_X], [ WIN_Z], [ WIN_C], [ WIN_Y], [ WIN_K], [ WIN_L], [ WIN_Return], [ WIN_BackSpace], [ WIN_space], [ WIN_Tab], ] # g|r|f|t|d|e|w|s|q|a|m|h|n|u|i|,|o|.|p|b" KeyMap[1][0] = [ [ WIN_Shift_L, WIN_G], [ WIN_Shift_L, WIN_R], [ WIN_Shift_L, WIN_F], [ WIN_Shift_L, WIN_T], [ WIN_Shift_L, WIN_D], [ WIN_Shift_L, WIN_E], [ WIN_Shift_L, WIN_W], [ WIN_Shift_L, WIN_S], [ WIN_Shift_L, WIN_Q], [ WIN_Shift_L, WIN_A], [ WIN_Shift_L, WIN_M], [ WIN_Shift_L, WIN_H], [ WIN_Shift_L, WIN_N], [ WIN_Shift_L, WIN_U], [ WIN_Shift_L, WIN_I], [ WIN_semicolon], [ WIN_Shift_L, WIN_O], [ WIN_Shift_L, WIN_semicolon], [ WIN_Shift_L, WIN_P], [ WIN_Shift_L, WIN_B], [ WIN_Shift_L, WIN_J], [ WIN_Shift_L, WIN_V], [ WIN_Shift_L, WIN_X], [ WIN_Shift_L, WIN_Z], [ WIN_Shift_L, WIN_C], [ WIN_Shift_L, WIN_Y], [ WIN_Shift_L, WIN_K], [ WIN_Shift_L, WIN_L], [ WIN_Shift_L, WIN_Return], [ WIN_Delete], [ WIN_Escape], [ WIN_Shift_L, WIN_Tab], ] # Green keymap, ignore shift # ~,%,"",',(,),{{},{}},[,],{^},_,?,!,&,|,<,>,``,\" KeyMap[0][1] = [ [ WIN_Shift_L, WIN_numbersign ], [ WIN_Shift_L, WIN_5 ], [ WIN_Shift_L, WIN_2 ], [ WIN_apostrophe], [ WIN_Shift_L, WIN_9 ], [ WIN_Shift_L, WIN_0 ], [ WIN_Shift_L, WIN_bracketleft ], [ WIN_Shift_L, WIN_bracketright ], [ WIN_bracketleft ], [ WIN_bracketright ], [ WIN_Shift_L, WIN_6 ], [ WIN_Shift_L, WIN_minus ], [ WIN_Shift_L, WIN_slash ], [ WIN_Shift_L, WIN_1 ], [ WIN_Shift_L, WIN_7 ], [ WIN_Shift_L, WIN_backslash ], [ WIN_Shift_L, WIN_comma ], [ WIN_Shift_L, WIN_period ], [ WIN_quoteleft ], [ WIN_backslash ], [], [], [], [], [], [], [], [], [], [], [], [], ] KeyMap[1][1] = [ [ WIN_Shift_L, WIN_numbersign ], [ WIN_Shift_L, WIN_5 ], [ WIN_Shift_L, WIN_2 ], [ WIN_apostrophe], [ WIN_Shift_L, WIN_9 ], [ WIN_Shift_L, WIN_0 ], [ WIN_Shift_L, WIN_bracketleft ], [ WIN_Shift_L, WIN_bracketright ], [ WIN_bracketleft ], [ WIN_bracketright ], [ WIN_Shift_L, WIN_6 ], [ WIN_Shift_L, WIN_minus ], [ WIN_Shift_L, WIN_slash ], [ WIN_Shift_L, WIN_1 ], [ WIN_Shift_L, WIN_7 ], [ WIN_Shift_L, WIN_backslash ], [ WIN_Shift_L, WIN_comma ], [ WIN_Shift_L, WIN_period ], [ WIN_quoteleft ], [ WIN_backslash ], [], [], [], [], [], [], [], [], [], [], [], [], ] # Red keymap, ignore shift # {#}|.|3|1|{+}|5|-|7|=|9|$|,|2|4|6|Enter|8|*|0|/" KeyMap[0][2] = [ [ WIN_numbersign ], [ WIN_period ], [ WIN_3 ], [ WIN_1 ], [ WIN_Shift_L, WIN_equal ], [ WIN_5 ], [ WIN_minus ], [ WIN_7 ], [ WIN_equal ], [ WIN_9 ], [ WIN_Shift_L, WIN_4 ], [ WIN_comma ], [ WIN_2 ], [ WIN_4 ], [ WIN_6 ], [ WIN_Return ], [ WIN_8 ], [ WIN_Shift_L, WIN_8 ], [ WIN_0 ], [ WIN_slash ], [ WIN_Shift_L, WIN_apostrophe], [], [], [], [ WIN_Up ], [ WIN_Right], [ WIN_Left], [ WIN_Down], [ WIN_Page_Up], [ WIN_End], [ WIN_Home], [ WIN_Page_Down], ] KeyMap[1][2] = [ [ WIN_numbersign ], [ WIN_period ], [ WIN_3 ], [ WIN_1 ], [ WIN_Shift_L, WIN_equal ], [ WIN_5 ], [ WIN_minus ], [ WIN_7 ], [ WIN_equal ], [ WIN_9 ], [ WIN_Shift_L, WIN_4 ], [ WIN_comma ], [ WIN_2 ], [ WIN_4 ], [ WIN_6 ], [ WIN_Return ], [ WIN_8 ], [ WIN_Shift_L, WIN_8 ], [ WIN_0 ], [ WIN_slash ], [], [], [], [], [ WIN_Shift_L, WIN_Up ], [ WIN_Shift_L, WIN_Right], [ WIN_Shift_L, WIN_Left], [ WIN_Shift_L, WIN_Down], [ WIN_Shift_L, WIN_Page_Up], [ WIN_Shift_L, WIN_End], [ WIN_Shift_L, WIN_Home], [ WIN_Shift_L, WIN_Page_Down], ] # Function keymap KeyMap[0][3] = [ [], [], [ WIN_F3 ], [ WIN_F1 ], [], [ WIN_F5 ], [], [ WIN_F7 ], [], [ WIN_F9 ], [], [], [ WIN_F2 ], [ WIN_F4 ], [ WIN_F6 ], [], [ WIN_F8 ], [], [ WIN_F10 ], [], [], [], [], [], [], [], [], [], [], [], ] KeyMap[1][3] = [ [], [], [ WIN_Shift_L, WIN_F3 ], [ WIN_Shift_L, WIN_F1 ], [], [ WIN_Shift_L, WIN_F5 ], [], [ WIN_Shift_L, WIN_F7 ], [], [ WIN_Shift_L, WIN_F9 ], [], [], [ WIN_Shift_L, WIN_F2 ], [ WIN_Shift_L, WIN_F4 ], [ WIN_Shift_L, WIN_F6 ], [], [ WIN_Shift_L, WIN_F8 ], [], [ WIN_Shift_L, WIN_F10 ], [], [], [], [], [], [], [], [], [], [], [], ] # Ctrl keymap KeyMap[0][4] = [ [ WIN_Control_L, WIN_G], [ WIN_Control_L, WIN_R], [ WIN_Control_L, WIN_F], [ WIN_Control_L, WIN_T], [ WIN_Control_L, WIN_D], [ WIN_Control_L, WIN_E], [ WIN_Control_L, WIN_W], [ WIN_Control_L, WIN_S], [ WIN_Control_L, WIN_Q], [ WIN_Control_L, WIN_A], [ WIN_Control_L, WIN_M], [ WIN_Control_L, WIN_H], [ WIN_Control_L, WIN_N], [ WIN_Control_L, WIN_U], [ WIN_Control_L, WIN_I], [ WIN_Control_L, WIN_comma], [ WIN_Control_L, WIN_O], [ WIN_Control_L, WIN_period], [ WIN_Control_L, WIN_P], [ WIN_Control_L, WIN_B], [ WIN_Control_L, WIN_J], [ WIN_Control_L, WIN_V], [ WIN_Control_L, WIN_X], [ WIN_Control_L, WIN_Z], [ WIN_Control_L, WIN_C], [ WIN_Control_L, WIN_Y], [ WIN_Control_L, WIN_K], [ WIN_Control_L, WIN_L], [ WIN_Control_L, WIN_Return], [ WIN_Control_L, WIN_BackSpace], [ WIN_Control_L, WIN_space], [ WIN_Control_L, WIN_Tab], ] KeyMap[1][4] = [ [ WIN_Shift_L, WIN_Control_L, WIN_G], [ WIN_Shift_L, WIN_Control_L, WIN_R], [ WIN_Shift_L, WIN_Control_L, WIN_F], [ WIN_Shift_L, WIN_Control_L, WIN_T], [ WIN_Shift_L, WIN_Control_L, WIN_D], [ WIN_Shift_L, WIN_Control_L, WIN_E], [ WIN_Shift_L, WIN_Control_L, WIN_W], [ WIN_Shift_L, WIN_Control_L, WIN_S], [ WIN_Shift_L, WIN_Control_L, WIN_Q], [ WIN_Shift_L, WIN_Control_L, WIN_A], [ WIN_Shift_L, WIN_Control_L, WIN_M], [ WIN_Shift_L, WIN_Control_L, WIN_H], [ WIN_Shift_L, WIN_Control_L, WIN_N], [ WIN_Shift_L, WIN_Control_L, WIN_U], [ WIN_Shift_L, WIN_Control_L, WIN_I], [ WIN_Shift_L, WIN_Control_L, WIN_comma], [ WIN_Shift_L, WIN_Control_L, WIN_O], [ WIN_Shift_L, WIN_Control_L, WIN_period], [ WIN_Shift_L, WIN_Control_L, WIN_P], [ WIN_Shift_L, WIN_Control_L, WIN_B], [ WIN_Shift_L, WIN_Control_L, WIN_J], [ WIN_Shift_L, WIN_Control_L, WIN_V], [ WIN_Shift_L, WIN_Control_L, WIN_X], [ WIN_Shift_L, WIN_Control_L, WIN_Z], [ WIN_Shift_L, WIN_Control_L, WIN_C], [ WIN_Shift_L, WIN_Control_L, WIN_Y], [ WIN_Shift_L, WIN_Control_L, WIN_K], [ WIN_Shift_L, WIN_Control_L, WIN_L], [ WIN_Shift_L, WIN_Control_L, WIN_Return], [ WIN_Shift_L, WIN_Control_L, WIN_BackSpace], [ WIN_Shift_L, WIN_Control_L, WIN_space], [ WIN_Shift_L, WIN_Control_L, WIN_Tab], ] # Alt keymap KeyMap[0][5] = [ [ WIN_Alt_L, WIN_G], [ WIN_Alt_L, WIN_R], [ WIN_Alt_L, WIN_F], [ WIN_Alt_L, WIN_T], [ WIN_Alt_L, WIN_D], [ WIN_Alt_L, WIN_E], [ WIN_Alt_L, WIN_W], [ WIN_Alt_L, WIN_S], [ WIN_Alt_L, WIN_Q], [ WIN_Alt_L, WIN_A], [ WIN_Alt_L, WIN_M], [ WIN_Alt_L, WIN_H], [ WIN_Alt_L, WIN_N], [ WIN_Alt_L, WIN_U], [ WIN_Alt_L, WIN_I], [ WIN_Alt_L, WIN_comma], [ WIN_Alt_L, WIN_O], [ WIN_Alt_L, WIN_period], [ WIN_Alt_L, WIN_P], [ WIN_Alt_L, WIN_B], [ WIN_Alt_L, WIN_J], [ WIN_Alt_L, WIN_V], [ WIN_Alt_L, WIN_X], [ WIN_Alt_L, WIN_Z], [ WIN_Alt_L, WIN_C], [ WIN_Alt_L, WIN_Y], [ WIN_Alt_L, WIN_K], [ WIN_Alt_L, WIN_L], [ WIN_Alt_L, WIN_Return], [ WIN_Alt_L, WIN_BackSpace], [ WIN_Alt_L, WIN_space], [ WIN_Alt_L, WIN_Tab], ] KeyMap[1][5] = [ [ WIN_Shift_L, WIN_Alt_L, WIN_G], [ WIN_Shift_L, WIN_Alt_L, WIN_R], [ WIN_Shift_L, WIN_Alt_L, WIN_F], [ WIN_Shift_L, WIN_Alt_L, WIN_T], [ WIN_Shift_L, WIN_Alt_L, WIN_D], [ WIN_Shift_L, WIN_Alt_L, WIN_E], [ WIN_Shift_L, WIN_Alt_L, WIN_W], [ WIN_Shift_L, WIN_Alt_L, WIN_S], [ WIN_Shift_L, WIN_Alt_L, WIN_Q], [ WIN_Shift_L, WIN_Alt_L, WIN_A], [ WIN_Shift_L, WIN_Alt_L, WIN_M], [ WIN_Shift_L, WIN_Alt_L, WIN_H], [ WIN_Shift_L, WIN_Alt_L, WIN_N], [ WIN_Shift_L, WIN_Alt_L, WIN_U], [ WIN_Shift_L, WIN_Alt_L, WIN_I], [ WIN_Shift_L, WIN_Alt_L, WIN_comma], [ WIN_Shift_L, WIN_Alt_L, WIN_O], [ WIN_Shift_L, WIN_Alt_L, WIN_period], [ WIN_Shift_L, WIN_Alt_L, WIN_P], [ WIN_Shift_L, WIN_Alt_L, WIN_B], [ WIN_Shift_L, WIN_Alt_L, WIN_J], [ WIN_Shift_L, WIN_Alt_L, WIN_V], [ WIN_Shift_L, WIN_Alt_L, WIN_X], [ WIN_Shift_L, WIN_Alt_L, WIN_Z], [ WIN_Shift_L, WIN_Alt_L, WIN_C], [ WIN_Shift_L, WIN_Alt_L, WIN_Y], [ WIN_Shift_L, WIN_Alt_L, WIN_K], [ WIN_Shift_L, WIN_Alt_L, WIN_L], [ WIN_Shift_L, WIN_Alt_L, WIN_Return], [ WIN_Shift_L, WIN_Alt_L, WIN_BackSpace], [ WIN_Shift_L, WIN_Alt_L, WIN_space], [ WIN_Shift_L, WIN_Alt_L, WIN_Tab], ] # Win keymap KeyMap[0][6] = [ [ WIN_Super_L, WIN_G], [ WIN_Super_L, WIN_R], [ WIN_Super_L, WIN_F], [ WIN_Super_L, WIN_T], [ WIN_Super_L, WIN_D], [ WIN_Super_L, WIN_E], [ WIN_Super_L, WIN_W], [ WIN_Super_L, WIN_S], [ WIN_Super_L, WIN_Q], [ WIN_Super_L, WIN_A], [ WIN_Super_L, WIN_M], [ WIN_Super_L, WIN_H], [ WIN_Super_L, WIN_N], [ WIN_Super_L, WIN_U], [ WIN_Super_L, WIN_I], [ WIN_Super_L, WIN_comma], [ WIN_Super_L, WIN_O], [ WIN_Super_L, WIN_period], [ WIN_Super_L, WIN_P], [ WIN_Super_L, WIN_B], [ WIN_Super_L, WIN_J], [ WIN_Super_L, WIN_V], [ WIN_Super_L, WIN_X], [ WIN_Super_L, WIN_Z], [ WIN_Super_L, WIN_C], [ WIN_Super_L, WIN_Y], [ WIN_Super_L, WIN_K], [ WIN_Super_L, WIN_L], [ WIN_Super_L, WIN_Return], [ WIN_Super_L, WIN_BackSpace], [ WIN_Super_L, WIN_space], [ WIN_Super_L, WIN_Tab], ] KeyMap[1][6] = [ [ WIN_Shift_L, WIN_Super_L, WIN_G], [ WIN_Shift_L, WIN_Super_L, WIN_R], [ WIN_Shift_L, WIN_Super_L, WIN_F], [ WIN_Shift_L, WIN_Super_L, WIN_T], [ WIN_Shift_L, WIN_Super_L, WIN_D], [ WIN_Shift_L, WIN_Super_L, WIN_E], [ WIN_Shift_L, WIN_Super_L, WIN_W], [ WIN_Shift_L, WIN_Super_L, WIN_S], [ WIN_Shift_L, WIN_Super_L, WIN_Q], [ WIN_Shift_L, WIN_Super_L, WIN_A], [ WIN_Shift_L, WIN_Super_L, WIN_M], [ WIN_Shift_L, WIN_Super_L, WIN_H], [ WIN_Shift_L, WIN_Super_L, WIN_N], [ WIN_Shift_L, WIN_Super_L, WIN_U], [ WIN_Shift_L, WIN_Super_L, WIN_I], [ WIN_Shift_L, WIN_Super_L, WIN_comma], [ WIN_Shift_L, WIN_Super_L, WIN_O], [ WIN_Shift_L, WIN_Super_L, WIN_period], [ WIN_Shift_L, WIN_Super_L, WIN_P], [ WIN_Shift_L, WIN_Super_L, WIN_B], [ WIN_Shift_L, WIN_Super_L, WIN_J], [ WIN_Shift_L, WIN_Super_L, WIN_V], [ WIN_Shift_L, WIN_Super_L, WIN_X], [ WIN_Shift_L, WIN_Super_L, WIN_Z], [ WIN_Shift_L, WIN_Super_L, WIN_C], [ WIN_Shift_L, WIN_Super_L, WIN_Y], [ WIN_Shift_L, WIN_Super_L, WIN_K], [ WIN_Shift_L, WIN_Super_L, WIN_L], [ WIN_Shift_L, WIN_Super_L, WIN_Return], [ WIN_Shift_L, WIN_Super_L, WIN_BackSpace], [ WIN_Shift_L, WIN_Super_L, WIN_space], [ WIN_Shift_L, WIN_Super_L, WIN_Tab], ] ##################################### state #################################### # List of keys currently down. Used for error detection. $is_down={} # Current colour shift active. $activeColour=0 # Id of key that caused colour change $activeColourId=0 # True if colour key was used as a modifier $colourIsModifier=0 # An error has occurred. Wait for all keys to come up. Keep the colour state # so all release codes are sent properly. $error=0 ##################################### action ################################### # Send the key presses in the list. def process_keydn_list( list) for i in 0...list.length UHK_keydn( list[i]) end end # Send the key releases in the list in reverse order. def process_keyup_list( list) n=list.length n1=n-1 for i in 0...n UHK_keyup( list[n1-i]) end end # Handle the start and stop marks. def UHK_USB_mark( code, millisecs) # print "Mark: #{code}, #{millisecs}\n" end # Handle key press events. def UHK_USB_keydn( code) # print "keydn: #{code}\n" $is_down[code]=1 # Turn the key code into a key id or quit shiftInd=0 if $is_down.has_key?( USB_SHIFT_L) or $is_down.has_key?( USB_SHIFT_R) shiftInd=1 end # print "Down: #{shiftInd} #{code}\n" # First handle the special case of shift-, send as ;. Turn it into shift-, if (code==USB_Semicolon) if (shiftInd==0) code=USB_Comma shiftInd=1 else code=USB_Period end end if not KeyId.has_key?(code) return end id=KeyId[code] # print "Down: #{shiftInd} #{$activeColour} #{code} #{id}\n" # Handle the fake colour keys if $activeColour == 0 and ColourKeys.has_key?( id) $activeColour=ColourKeys[id] $activeColourId=id $colourIsModifier=0 return end # Regular key, send code according to color and shift state if $activeColour != 0 $colourIsModifier=1 end process_keydn_list( KeyMap[shiftInd][$activeColour][id]) end def UHK_USB_keyup( code) # print "keyup: #{code}\n" $is_down.delete( code) # Turn the key code into a key id or quit shiftInd=0 if $is_down.has_key?( USB_SHIFT_L) or $is_down.has_key?( USB_SHIFT_R) shiftInd=1 end # First handle the special case of shift-, send as ;. Turn it into shift-, if (code==USB_Semicolon) if (shiftInd==0) code=USB_Comma shiftInd=1 else code=USB_Period end end if not KeyId.has_key?(code) return end id=KeyId[code] # Handle the fake colour keys if $activeColour != 0 and id == $activeColourId if $colourIsModifier == 0 process_keydn_list( KeyMap[shiftInd][0][id]) process_keyup_list( KeyMap[shiftInd][0][id]) $activeColour=0 else if $is_down.empty? $activeColour=0 else $error=1 end end return end process_keyup_list( KeyMap[shiftInd][$activeColour][id]) # Error handling if $error != 0 if $is_down.empty? $error=0 $activeColour=0 $colourIsModifier=0 end return end end # Connect to the alphagrip if present. UHK_connect( 0x510, 0x100b, 0x81) # Preload the shift level images print "usbhotkey AG5 script started\n"