#!/usr/bin/wish -f ## ## Tk SCRIPT NAME: tkPointerSettings.tk ## ##+####################################################################### ## PURPOSE: This Tk GUI script provides a GUI wrapper for the ## 'xinput' command --- to use 'xinput' to change (or ## assign) functions of buttons of a mouse or other ## 'pointer' device. ## ## The GUI supplies radiobuttons and other widgets that ## allow the user to change functions of (or assign functions ## to) the various buttons/'features' of a 'pointer device'. ## ## Here 'feature' is meant to represent an action that ## is performed by other than a button press --- such as ## a tilt (right or left) of the scroll-wheel. ## ## And 'pointer device' is meant to convey that this ## wrapper script can apply to devices other than computer ## mice --- devices such as touchpads or game 'pad' controllers. ## ## Some of the typical uses of this GUI are ## 1) To switch the functions of mouse buttons 1 and 3, ## for left-handed users. ## 2) To deactivate the 'paste' function of mouse-button 2, ## for users of a mouse with scroll-wheel, when pressing ## down too hard on the scroll-wheel causes an unwanted ## paste operation. ## 3) To deactivate the 'scroll' functions of the scroll-wheel, ## so that the wheel can be used just for the 'paste' function, ## without accidentally scrolling a window while doing the paste. ## 4) To assign buttons 6 and/or 7 (on a scroll-wheel mouse with ## extra buttons) so that the 'paste' operation can be ## done with one or both of the additional buttons. ## ##+########### ## GUI DESIGN: ## ## The GUI includes ## ## 1) a SCROLLING LISTBOX from which to choose a function to assign ## to a button/'feature' of the 'pointer device' ## ## 2) a set of at least 24 RADIOBUTTONS, to represent the ## buttons/'features' of the pointer device ## ## 3) a TEXT widget in which to show the current parameter settings for ## the 'xinput' command ## ## 4) another SCROLLABLE TEXT widget, in which to show the results ## of an initial 'xinput list' query ## ## 4) BUTTONS, such as 'Exit', 'Help', and 'SetMap'. Clicking on the ## 'SetMap' button causes the 'xinput' command to execute, using ## the current button-assignment settings. ## ##+######################################################################## ## 'CANONICAL' STRUCTURE OF THIS CODE: ## ## 0) Set general window parms (win-name,win-position,win-color-scheme, ## fonts,widget-geom-parameters,win-size-control,text-for-labels-etc). ## 1a) Define ALL frames (and sub-frames). ## 1b) Pack ALL frames and sub-frames. ## 2) Define & pack all widgets in the frames, frame by frame. ## ## 3) Define key and mouse/touchpad/touch-sensitive-screen action ## BINDINGS, if needed. ## 4) Define PROCS, if needed. ## 5) Additional GUI INITIALIZATION (typically with one or two procs ## from section 4), if needed. ## ##+################################# ## Some detail on the code structure of this particular Tk script: ## ## 1a) Define ALL frames: ## ## Top-level : 'fRleft' and 'fRright' ## ## Sub-frames of 'fRleft': none, just one listbox with scrollbar(s) ## ## Sub-frames of 'fRright' (top to bottom): ## ## - 'fRbuttons' for buttons: Exit, Help, SETmap, GETmap, Test, ColorMe ## - 'fRradbutts0' for a label for radiobuttons ## - 'fRradbutts1' for about 8 radiobuttons ## - 'fRradbutts2' for about 8 more radiobuttons ## - 'fRradbutts3' for about 8 more radiobuttons ## - 'fRxinputparms' for a text widget (holding 'xinput' parms) ## - 'fRxinputlist' for a scrollable text widget (holding ## output from 'xinput list') ## ## 1b) Pack ALL frames. ## ## 2) Define & pack all widgets in the frames -- basically going through ## frames & their interiors in left-to-right, top-to-bottom order: ## ## 3) Define bindings: none currently ## ## 4) Define procs: ## ## - 'loadfuncs2listbox' - for loading a set of GUI initialization ## ## - 'show-select_func_in_listbox' - for a binding on the listbox ## ## - 'xinput_setmap' - to 'exec' an 'xinput' command, when the ## 'SetMap' button is clicked ## ## - 'getset_bkgdcolor' - for ColorMe button (gets Rpal255,Gpal255,Bpal255 via ## a separate color-selectorGUI with 3 slider ## bars, then sets the GUI 'palette') ## ## 5) Additional GUI initialization: run 'loadfuncs2listbox' ## ##+####################################################################### ## DEVELOPED WITH: Tcl-Tk 8.5 on Ubuntu 9.10 (2009-october, 'Karmic Koala') ## ## $ wish ## % puts "$tcl_version $tk_version" ## ## showed ## 8.5 8.5 ## but this script should work in most previous 8.x versions, and probably ## even in some 7.x versions (if font handling is made 'old-style'). ##+######################################################################## ## MAINTENANCE HISTORY: ## Started by: Blaise Montandon 2013aug06 Started development, on Ubuntu 9.10, ## for personal use and for donation ## of this script to wiki.tcl.tk. ## Changed by: Blaise Montandon 2013aug25 Add an 'over-ride' to the 1-to-24 setting ## of the 'aRfuncs4butts' array in proc ## 'init_xinput_parms_array' --- example: ## for a Logitech M500 corded mouse, ## to change buttons 8 and 9 to paste ## and to de-activate the paste function ## of button 2. ## Changed by: Blaise Montandon 2013sep08 1) Added initialization-overrides ## for a Logitech G300 mouse to ## proc 'init_xinput_parms_array'. ## 2) Added code to 'xinput_getmap' ## to update array 'aRfuncs4butts' ## in addition to setting the ## 'NUMSstring' var that shows on ## the GUI. ## Changed by: Blaise Montandon 2014apr06 Added 'suggested paste settings' ## for Logitech G300,G500,G510 mice ## to the HELPtext var --- and other ## improvements to the HELPtext var. ##+####################################################################### ##+####################################################################### ## Set WINDOW TITLES and POSITION. ##+####################################################################### wm title . "tkPointerSettings - a 'wrapper' around the 'xinput' command" wm iconname . "tkPointer" wm geometry . +15+30 ##+####################################################################### ## SET COLOR SCHEME (palette) FOR THE WINDOW. ##+####################################################################### ## and ##+####################################################################### ## SET BACKGROUND COLOR vars FOR WIDGETS, like ENTRY & LISTBOX widgets. ##+####################################################################### ## Set a Gray palette for the GUI. ## set Rpal255 210 set Gpal255 210 set Bpal255 210 set COLOR_pal [format "#%02X%02X%02X" $Rpal255 $Gpal255 $Bpal255] tk_setPalette $COLOR_pal set listboxBKGD "#f0f0f0" set entryBKGD "#f0f0f0" set radbuttBKGD "#f0f0f0" set hiliteBKGD "#ff0000" set hilite2BKGD "#00ff00" ##+####################################################################### ## SET FONT VARS for use in the 'font create' statements below. ##+####################################################################### set guiFONTsize 14 set guiFONT_SMALLsize 12 ## For variable width: set FONT_varwidth \ " -family {comic sans ms} -size -$guiFONTsize -weight bold -slant roman " set FONT_SMALL_varwidth \ " -family {comic sans ms} -size -$guiFONT_SMALLsize -weight normal -slant roman " ## For fixed width: set FONT_fixedwidth \ " -family {dejavu sans mono} -size -$guiFONTsize -weight bold -slant roman " set FONT_SMALL_fixedwidth \ " -family {dejavu sans mono} -size -$guiFONT_SMALLsize -weight normal -slant roman " ##+##################################################################### ## DEFINE (temporary) FONT-NAMES using 'font create'. ## The font names are to be used in '-font' widget specs below --- ##+##################################################################### eval font create fontTEMP_button $FONT_varwidth eval font create fontTEMP_label $FONT_varwidth eval font create fontTEMP_varwidth $FONT_varwidth eval font create fontTEMP_entry $FONT_fixedwidth eval font create fontTEMP_listbox $FONT_fixedwidth eval font create fontTEMP_text $FONT_fixedwidth # eval font create fontTEMP_msg $FONT_fixedwidth eval font create fontTEMP_SMALL_button $FONT_SMALL_varwidth eval font create fontTEMP_SMALL_label $FONT_SMALL_varwidth eval font create fontTEMP_SMALL_varwidth $FONT_SMALL_varwidth eval font create fontTEMP_SMALL_entry $FONT_SMALL_fixedwidth eval font create fontTEMP_SMALL_listbox $FONT_SMALL_fixedwidth eval font create fontTEMP_SMALL_text $FONT_SMALL_fixedwidth # eval font create fontTEMP_SMALL_msg $FONT_SMALL_fixedwidth ##+####################################################################### ## SET GEOM VARS FOR THE VARIOUS WIDGET DEFINITIONS. ## (e.g. padx,pady for Buttons) ##+####################################################################### ## For BUTTON widgets: set fePADY_button 0 set fePADX_button 0 set feBDwidth_button 2 ## For LABEL widgets: set fePADY_label 0 set fePADX_label 0 set feBDwidth_label 2 ## For RADIOBUTTON widgets: set fePADY_radbutt 0 set fePADX_radbutt 0 set feBDwidth_radbutt 2 ## For LISTBOX widgets: set feBDwidth_listbox 2 ## For ENTRY widgets: set feBDwidth_entry 2 ## For TEXT and MESSAGE widgets: set feBDwidth_text 2 # set feBDwidth_msg 2 ##+####################################################################### ## SET the top window MIN-SIZE (roughly). ## ## For width: on the LEFT SIDE of the GUI, allow for ## about 20 chars for the button-function names in the listbox. ## and, on the RIGHT SIDE of the GUI, allow for ## the minwidth of the '.fRbuttons' frame: ## at least 4 buttons (Exit,Help,SetMap,...,ColorMe). ## ## For height: allow about 20 chars high --- so that at least 20 function ## names show in the listbox. ##+####################################################################### set minWinWidthPx [font measure fontTEMP_varwidth \ "123456789012345 Exit Help SetMap ColorMe"] ## Add some pixels to account for right-left-side window decoration ## (about 8 pixels), about 6 widgets x 4 pixels/widget for borders/padding ## for 6 widgets --- listbox, 4 or 5 buttons. set minWinWidthPx [expr {32 + $minWinWidthPx}] ## MIN HEIGHT --- allow for about 20 chars high in the listbox: set charHeightPx [font metrics fontTEMP_fixedwidth -linespace] set minWinHeightPx [expr { 20 * $charHeightPx}] ## Add about 28 pixels for top-bottom window decoration, and ## about 6 pixels for the listbox widget's vertical borders/padding. set minWinHeightPx [expr {$minWinHeightPx + 34}] ## FOR TESTING: # puts "minWinWidthPx = $minWinWidthPx" # puts "minWinHeightPx = $minWinHeightPx" wm minsize . $minWinWidthPx $minWinHeightPx ## We allow the window to be resizable and we pack the listbox ## (and a scrollable text widget) with '-fill both' so that the ## listbox (and scrollable text widget) can be enlarged by ## enlarging the window. ## If you want to make the window un-resizable, ## you can use the following statement. # wm resizable . 0 0 ##+#################################################################### ## Set a TEXT-ARRAY to hold text for buttons & labels on the GUI. ## NOTE: This can aid INTERNATIONALIZATION. This array can ## be set according to a nation/region parameter. ##+#################################################################### ## if { "$VARlocale" == "en"} set aRtext(buttonEXIT) "Exit" set aRtext(buttonHELP) "Help" set aRtext(buttonSETMAP) "SETmap" set aRtext(buttonGETMAP) "GETmap" set aRtext(buttonTEST) "Test" set aRtext(buttonCOLOR) "ColorMe" set aRtext(labelDEVICEID) "Device ID:" set aRtext(labelFUNCS) "Functions to map to the numbers" set aRtext(labelRADBUTTS) " Choose a 'button'-number to map next:" set aRtext(labelXINPARMS) "Map-list for 'SETmap':" set aRtext(labelXINLIST) \ "'xinput list' output: (These are devices discovered on this host. Note 'Type is MOUSE', etc.)" ## END OF if { "$VARlocale" == "en"} ##+#################################################################### ##+#################################################################### ## DEFINE *ALL* THE FRAMES: ## ## Top-level : 'fRleft' and 'fRright' ## ## Sub-frames of 'fRleft': none, just one listbox with scrollbar(s) ## ## Sub-frames of 'fRright' (top to bottom): ## ## - 'fRbuttons' ## - 'fRradbutts0' ## - 'fRradbutts1' ## - 'fRradbutts2' ## - 'fRradbutts3' ## - 'fRxinputparms' ## - 'fRxinputlist' ##+#################################################################### ##+#################################################################### ## FOR TESTING of expansion of frames (esp. during window expansion): # set feRELIEF_frame raised # set feBDwidth_frame 2 set feRELIEF_frame flat set feBDwidth_frame 0 frame .fRleft -relief $feRELIEF_frame -borderwidth $feBDwidth_frame frame .fRright -relief $feRELIEF_frame -borderwidth $feBDwidth_frame frame .fRright.fRbuttons \ -relief $feRELIEF_frame -borderwidth $feBDwidth_frame frame .fRright.fRradbutts0 \ -relief $feRELIEF_frame -borderwidth $feBDwidth_frame frame .fRright.fRradbutts1 \ -relief $feRELIEF_frame -borderwidth $feBDwidth_frame frame .fRright.fRradbutts2 \ -relief $feRELIEF_frame -borderwidth $feBDwidth_frame frame .fRright.fRradbutts3 \ -relief $feRELIEF_frame -borderwidth $feBDwidth_frame frame .fRright.fRxinputparms \ -relief $feRELIEF_frame -borderwidth $feBDwidth_frame frame .fRright.fRxinputlist \ -relief $feRELIEF_frame -borderwidth $feBDwidth_frame ##+######################################################## ## PACK *ALL* the FRAMES. ##+######################################################## pack .fRleft \ -side left \ -anchor nw \ -fill both \ -expand 0 pack .fRright \ -side left \ -anchor nw \ -fill both \ -expand 1 ## PACK the subframes of '.fRright'. pack .fRright.fRbuttons \ -side top \ -anchor nw \ -fill none \ -expand 0 pack .fRright.fRradbutts0 \ -side top \ -anchor nw \ -fill none \ -expand 0 pack .fRright.fRradbutts1 \ -side top \ -anchor nw \ -fill none \ -expand 0 pack .fRright.fRradbutts2 \ -side top \ -anchor nw \ -fill none \ -expand 0 pack .fRright.fRradbutts3 \ -side top \ -anchor nw \ -fill none \ -expand 0 pack .fRright.fRxinputparms \ -side top \ -anchor nw \ -fill x \ -expand 0 pack .fRright.fRxinputlist \ -side top \ -anchor nw \ -fill both \ -expand 1 ##+################################################################ ##+################################################################ ## START DEFINING & PACKING WIDGETS WITHIN THEIR FRAMES. ##+################################################################ ##+################################################################ ##+######################################################## ## IN THE 'fRleft' frame -- DEFINE 1 listbox widget, ## with vertical scrollbar. ##+######################################################## label .fRleft.labelFUNCS \ -text "$aRtext(labelFUNCS)" \ -font fontTEMP_label \ -justify left \ -anchor w \ -bg "$hiliteBKGD" \ -relief flat \ -bd 0 listbox .fRleft.listbox \ -width 20 \ -height 25 \ -font fontTEMP_listbox \ -relief raised \ -borderwidth 2 \ -state normal \ -yscrollcommand ".fRleft.scrbary set" \ -xscrollcommand ".fRleft.scrbarx set" \ # -width 0 \ # -height 0 \ scrollbar .fRleft.scrbary \ -orient vertical -command ".fRleft.listbox yview" scrollbar .fRleft.scrbarx \ -orient horizontal -command ".fRleft.listbox xview" ## Pack the widgets in the 'fRleft' frame. pack .fRleft.labelFUNCS \ -side top \ -anchor nw \ -fill none \ -expand 0 pack .fRleft.scrbary \ -side right \ -anchor e \ -fill y \ -expand 0 pack .fRleft.scrbarx \ -side bottom \ -anchor sw \ -fill x \ -expand 0 pack .fRleft.listbox \ -side left \ -anchor nw \ -fill both \ -expand 1 ##+############################################################# ## START DEFINING WIDGETS and PACKING in THE *RIGHT-SIDE* FRAME: ##+############################################################# ##+########################################################## ## IN THE 'fRright.fRbuttons' frame -- ## DEFINE several BUTTONS ## --- Exit, Help, SetMap, ... , ColorMe. ##+########################################################## button .fRright.fRbuttons.buttEXIT \ -text "$aRtext(buttonEXIT)" \ -font fontTEMP_button \ -padx $fePADX_button \ -pady $fePADY_button \ -relief raised \ -bd $feBDwidth_button \ -command {exit} button .fRright.fRbuttons.buttHELP \ -text "$aRtext(buttonHELP)" \ -font fontTEMP_button \ -padx $fePADX_button \ -pady $fePADY_button \ -relief raised \ -bd $feBDwidth_button \ -command {popup_msgVarWithScroll .topHelp "$HELPtext"} button .fRright.fRbuttons.buttSETMAP \ -text "$aRtext(buttonSETMAP)" \ -font fontTEMP_button \ -padx $fePADX_button \ -pady $fePADY_button \ -relief raised \ -bd $feBDwidth_button \ -command {xinput_setmap} button .fRright.fRbuttons.buttGETMAP \ -text "$aRtext(buttonGETMAP)" \ -font fontTEMP_button \ -padx $fePADX_button \ -pady $fePADY_button \ -relief raised \ -bd $feBDwidth_button \ -command {xinput_getmap} button .fRright.fRbuttons.buttTEST \ -text "$aRtext(buttonTEST)" \ -font fontTEMP_button \ -padx $fePADX_button \ -pady $fePADY_button \ -relief raised \ -bd $feBDwidth_button \ -command {xinput_test} button .fRright.fRbuttons.buttCOLOR \ -text "$aRtext(buttonCOLOR)" \ -font fontTEMP_button \ -padx $fePADX_button \ -pady $fePADY_button \ -relief raised \ -bd $feBDwidth_button \ -command {getset_bkgdcolor} label .fRright.fRbuttons.labelDEVICEID \ -text "$aRtext(labelDEVICEID)" \ -font fontTEMP_label \ -justify left \ -anchor w \ -bg "$hiliteBKGD" \ -relief flat \ -bd $feBDwidth_label set deviceID "?" entry .fRright.fRbuttons.entDEVICEID \ -textvariable deviceID \ -bg $entryBKGD \ -font fontTEMP_entry \ -width 2 \ -relief sunken \ -bd $feBDwidth_entry ## Label Widget on which to post some radbutts-info. # label .fRright.fRbuttons.labelINFO \ # -text "$aRtext(labelINFO)" \ # -font fontTEMP_label \ # -justify left \ # -anchor w \ # -relief flat \ # -bd 0 ##+########################################## ## Pack the widgets in the 'fRbuttons' frame. ##+########################################## pack .fRright.fRbuttons.buttEXIT \ .fRright.fRbuttons.buttHELP \ .fRright.fRbuttons.buttSETMAP \ .fRright.fRbuttons.buttGETMAP \ .fRright.fRbuttons.buttTEST \ .fRright.fRbuttons.buttCOLOR \ .fRright.fRbuttons.labelDEVICEID \ .fRright.fRbuttons.entDEVICEID \ -side left \ -anchor w \ -fill none \ -expand 0 ##+######################################################## ## IN THE 'fRright.fRradbutts0' frame -- ## DEFINE a LABEL widget. ##+######################################################## label .fRright.fRradbutts0.labelINFO \ -text "$aRtext(labelRADBUTTS)" \ -font fontTEMP_label \ -justify left \ -anchor w \ -bg "$hiliteBKGD" \ -relief flat \ -bd 0 pack .fRright.fRradbutts0.labelINFO \ -side left \ -anchor w \ -fill none \ -expand 0 ##+######################################################## ## IN THE 'fRright.fRradbutts1' frame -- ## DEFINE about 8 RADIOBUTTON widgets, ## with varname 'positionIDX'. ##+######################################################## set spacerPx 150 frame .fRright.fRradbutts1.spacer \ -width $spacerPx \ -relief flat \ -bd 0 ## We will set 'positionIDX' (the radiobuttons variable) in ## the additional-GUI-init section at the bottom of this script. ## # set positionIDX 2 radiobutton .fRright.fRradbutts1.radbutt01 \ -text "01" \ -font fontTEMP_button \ -anchor w \ -variable positionIDX \ -value "1" \ -selectcolor "$radbuttBKGD" \ -relief flat \ -bd 0 radiobutton .fRright.fRradbutts1.radbutt02 \ -text "02" \ -font fontTEMP_button \ -anchor w \ -variable positionIDX \ -value "2" \ -selectcolor "$radbuttBKGD" \ -relief flat \ -bd 0 radiobutton .fRright.fRradbutts1.radbutt03 \ -text "03" \ -font fontTEMP_button \ -anchor w \ -variable positionIDX \ -value "3" \ -selectcolor "$radbuttBKGD" \ -relief flat \ -bd 0 radiobutton .fRright.fRradbutts1.radbutt04 \ -text "04" \ -font fontTEMP_button \ -anchor w \ -variable positionIDX \ -value "4" \ -selectcolor "$radbuttBKGD" \ -relief flat \ -bd 0 radiobutton .fRright.fRradbutts1.radbutt05 \ -text "05" \ -font fontTEMP_button \ -anchor w \ -variable positionIDX \ -value "5" \ -selectcolor "$radbuttBKGD" \ -relief flat \ -bd 0 radiobutton .fRright.fRradbutts1.radbutt06 \ -text "06" \ -font fontTEMP_button \ -anchor w \ -variable positionIDX \ -value "6" \ -selectcolor "$radbuttBKGD" \ -relief flat \ -bd 0 radiobutton .fRright.fRradbutts1.radbutt07 \ -text "07" \ -font fontTEMP_button \ -anchor w \ -variable positionIDX \ -value "7" \ -selectcolor "$radbuttBKGD" \ -relief flat \ -bd 0 radiobutton .fRright.fRradbutts1.radbutt08 \ -text "08" \ -font fontTEMP_button \ -anchor w \ -variable positionIDX \ -value "8" \ -selectcolor "$radbuttBKGD" \ -relief flat \ -bd 0 ## Pack the widgets in frame 'fRradbutts1'. pack .fRright.fRradbutts1.spacer \ .fRright.fRradbutts1.radbutt01 \ .fRright.fRradbutts1.radbutt02 \ .fRright.fRradbutts1.radbutt03 \ .fRright.fRradbutts1.radbutt04 \ .fRright.fRradbutts1.radbutt05 \ .fRright.fRradbutts1.radbutt06 \ .fRright.fRradbutts1.radbutt07 \ .fRright.fRradbutts1.radbutt08 \ -side left \ -anchor w \ -fill none \ -expand 0 ##+######################################################## ## IN THE 'fRright.fRradbutts2' frame -- ## DEFINE about 8 MORE RADIOBUTTON widgets, ## with varname 'positionIDX'. ##+######################################################## frame .fRright.fRradbutts2.spacer \ -width $spacerPx \ -relief flat \ -bd 0 ## We will set 'positionIDX' (the radiobuttons variable) in ## the additional-GUI-init section at the bottom of this script. ## # set positionIDX 2 radiobutton .fRright.fRradbutts2.radbutt09 \ -text "09" \ -font fontTEMP_button \ -anchor w \ -variable positionIDX \ -value "9" \ -selectcolor "$radbuttBKGD" \ -relief flat \ -bd 0 radiobutton .fRright.fRradbutts2.radbutt10 \ -text "10" \ -font fontTEMP_button \ -anchor w \ -variable positionIDX \ -value "10" \ -selectcolor "$radbuttBKGD" \ -relief flat \ -bd 0 radiobutton .fRright.fRradbutts2.radbutt11 \ -text "11" \ -font fontTEMP_button \ -anchor w \ -variable positionIDX \ -value "11" \ -selectcolor "$radbuttBKGD" \ -relief flat \ -bd 0 radiobutton .fRright.fRradbutts2.radbutt12 \ -text "12" \ -font fontTEMP_button \ -anchor w \ -variable positionIDX \ -value "12" \ -selectcolor "$radbuttBKGD" \ -relief flat \ -bd 0 radiobutton .fRright.fRradbutts2.radbutt13 \ -text "13" \ -font fontTEMP_button \ -anchor w \ -variable positionIDX \ -value "13" \ -selectcolor "$radbuttBKGD" \ -relief flat \ -bd 0 radiobutton .fRright.fRradbutts2.radbutt14 \ -text "14" \ -font fontTEMP_button \ -anchor w \ -variable positionIDX \ -value "14" \ -selectcolor "$radbuttBKGD" \ -relief flat \ -bd 0 radiobutton .fRright.fRradbutts2.radbutt15 \ -text "15" \ -font fontTEMP_button \ -anchor w \ -variable positionIDX \ -value "15" \ -selectcolor "$radbuttBKGD" \ -relief flat \ -bd 0 radiobutton .fRright.fRradbutts2.radbutt16 \ -text "16" \ -font fontTEMP_button \ -anchor w \ -variable positionIDX \ -value "16" \ -selectcolor "$radbuttBKGD" \ -relief flat \ -bd 0 ## Pack the widgets in frame 'fRradbutts2'. pack .fRright.fRradbutts2.spacer \ .fRright.fRradbutts2.radbutt09 \ .fRright.fRradbutts2.radbutt10 \ .fRright.fRradbutts2.radbutt11 \ .fRright.fRradbutts2.radbutt12 \ .fRright.fRradbutts2.radbutt13 \ .fRright.fRradbutts2.radbutt14 \ .fRright.fRradbutts2.radbutt15 \ .fRright.fRradbutts2.radbutt16 \ -side left \ -anchor w \ -fill none \ -expand 0 ##+######################################################## ## IN THE 'fRright.fRradbutts3' frame -- ## DEFINE about 8 MORE RADIOBUTTON widgets, ## with varname 'positionIDX'. ##+######################################################## frame .fRright.fRradbutts3.spacer \ -width $spacerPx \ -relief flat \ -bd 0 ## We will set 'positionIDX' (the radiobuttons variable) in ## the additional-GUI-init section at the bottom of this script. ## # set positionIDX 2 radiobutton .fRright.fRradbutts3.radbutt17 \ -text "17" \ -font fontTEMP_button \ -anchor w \ -variable positionIDX \ -value "17" \ -selectcolor "$radbuttBKGD" \ -relief flat \ -bd 0 radiobutton .fRright.fRradbutts3.radbutt18 \ -text "18" \ -font fontTEMP_button \ -anchor w \ -variable positionIDX \ -value "18" \ -selectcolor "$radbuttBKGD" \ -relief flat \ -bd 0 radiobutton .fRright.fRradbutts3.radbutt19 \ -text "19" \ -font fontTEMP_button \ -anchor w \ -variable positionIDX \ -value "19" \ -selectcolor "$radbuttBKGD" \ -relief flat \ -bd 0 radiobutton .fRright.fRradbutts3.radbutt20 \ -text "20" \ -font fontTEMP_button \ -anchor w \ -variable positionIDX \ -value "20" \ -selectcolor "$radbuttBKGD" \ -relief flat \ -bd 0 radiobutton .fRright.fRradbutts3.radbutt21 \ -text "21" \ -font fontTEMP_button \ -anchor w \ -variable positionIDX \ -value "21" \ -selectcolor "$radbuttBKGD" \ -relief flat \ -bd 0 radiobutton .fRright.fRradbutts3.radbutt22 \ -text "22" \ -font fontTEMP_button \ -anchor w \ -variable positionIDX \ -value "22" \ -selectcolor "$radbuttBKGD" \ -relief flat \ -bd 0 radiobutton .fRright.fRradbutts3.radbutt23 \ -text "23" \ -font fontTEMP_button \ -anchor w \ -variable positionIDX \ -value "23" \ -selectcolor "$radbuttBKGD" \ -relief flat \ -bd 0 radiobutton .fRright.fRradbutts3.radbutt24 \ -text "24" \ -font fontTEMP_button \ -anchor w \ -variable positionIDX \ -value "24" \ -selectcolor "$radbuttBKGD" \ -relief flat \ -bd 0 ## Pack the widgets in frame 'fRradbutts3'. pack .fRright.fRradbutts3.spacer \ .fRright.fRradbutts3.radbutt17 \ .fRright.fRradbutts3.radbutt18 \ .fRright.fRradbutts3.radbutt19 \ .fRright.fRradbutts3.radbutt20 \ .fRright.fRradbutts3.radbutt21 \ .fRright.fRradbutts3.radbutt22 \ .fRright.fRradbutts3.radbutt23 \ .fRright.fRradbutts3.radbutt24 \ -side left \ -anchor w \ -fill none \ -expand 0 ##+######################################################## ## IN THE 'fRright.fRxinputparms' frame -- ## DEFINE a TEXT area --- to hold the current parameter ## settings for use in the 'xinput' command. ##+######################################################## label .fRright.fRxinputparms.labelXINPARMS \ -text "$aRtext(labelXINPARMS)" \ -font fontTEMP_label \ -justify left \ -anchor w \ -bg "$hiliteBKGD" \ -relief flat \ -bd 0 text .fRright.fRxinputparms.txtXINPARMS \ -font fontTEMP_SMALL_text \ -height 1 \ -width 72 \ -wrap none \ -relief raised \ -borderwidth $feBDwidth_text ## Pack the widget in frame '.fRright.fRxinputparms'. pack .fRright.fRxinputparms.labelXINPARMS \ -side left \ -anchor w \ -fill none \ -expand 0 pack .fRright.fRxinputparms.txtXINPARMS \ -side left \ -anchor w \ -fill x \ -expand 0 ##+######################################################## ## IN THE 'fRright.fRxinputlist' frame -- ## DEFINE a SCROLLABLE TEXT area --- to hold the output ## from the 'xinput list' command. ##+######################################################## label .fRright.fRxinputlist.labelXINLIST \ -text "$aRtext(labelXINLIST)" \ -font fontTEMP_label \ -justify left \ -anchor w \ -bg "$hilite2BKGD" \ -relief raised \ -bd 2 text .fRright.fRxinputlist.txtXINLIST \ -font fontTEMP_SMALL_text \ -height 9 \ -width 38 \ -wrap none \ -relief raised \ -borderwidth 4 \ -yscrollcommand ".fRright.fRxinputlist.scrbary set" \ -xscrollcommand ".fRright.fRxinputlist.scrbarx set" scrollbar .fRright.fRxinputlist.scrbary \ -orient vertical \ -command ".fRright.fRxinputlist.txtXINLIST yview" scrollbar .fRright.fRxinputlist.scrbarx \ -orient horizontal \ -command ".fRright.fRxinputlist.txtXINLIST xview" ##+######################################################## ## PACK the widgets in the '.fRright.fRxinputlist' frame. ##+######################################################## pack .fRright.fRxinputlist.labelXINLIST \ -side top \ -anchor nw \ -fill none \ -expand 0 pack .fRright.fRxinputlist.scrbary \ -side right \ -anchor center \ -fill y \ -expand 0 pack .fRright.fRxinputlist.scrbarx \ -side bottom \ -anchor center \ -fill x \ -expand 0 pack .fRright.fRxinputlist.txtXINLIST \ -side top \ -anchor n \ -fill both \ -expand 1 ##+####################################################################### ## GET AN INITIAL 'xinput list' OUTPUT, to show in a scrollable text widget. ##+####################################################################### set xinputLISTtext [exec /usr/bin/xinput list] ##+####################################################### ## Load the 'txtXINLIST' widget using the 'insert' command. ##+####################################################### .fRright.fRxinputlist.txtXINLIST insert end "$xinputLISTtext" ##+###################################################### ## Keep the user from changing the output from the ## 'xinput list' command, in case they type in the widget. ##+###################################################### .fRright.fRxinputlist.txtXINLIST configure -state disabled ##+##################################################################### ## END OF MAIN SECTION TO SETUP THE GUI. ##+##################################################################### ##+##################################################################### ##+##################################################################### ## DEFINE BINDINGS: ## - Run the 'process_listbox_select' proc whenever ## there is a button1-release on the listbox. ##+##################################################################### bind .fRleft.listbox "process_listbox_select 0" ##+##################################################################### ##+##################################################################### ## DEFINE PROCEDURES: ## ## 'loadfuncs2listbox' - called in the 'additional-GUI-initialization' ## section at the bottom of this script. ## ## 'process_listbox_select' - called by a binding on the listbox ## ## 'init_xinput_parms_array' - called once in the ## 'additional-GUI-initialization' section ## at the bottom of this script. ## ## 'rebuild_xinput_parms' - called by the 'process_listbox_select' proc ## ## 'getset_bkgdcolor' - called by the Color button ## (gets Rpal255,Gpal255,Bpal255 via a GUI with 3 slider bars, ## then calls 'set_tkPalette') ## ## 'popup_msgVarWithScroll' - to show Help text when 'Help' button is clicked ## ##+##################################################################### ##+##################################################################### ##+##################################################################### ## proc 'loadfuncs2listbox' ##+##################################################################### ## PURPOSE: Loads names for pointer-device functions to listbox. ## ## ## CALLED BY: Done once, at GUI initialization, at bottom of this script. ##+##################################################################### proc loadfuncs2listbox { } { ## Make sure the listbox is empty. .fRleft.listbox delete 0 end ## Insert each function name into the listbox list. .fRleft.listbox insert end "NoOperation" .fRleft.listbox insert end "functionOfButton1(select)" .fRleft.listbox insert end "functionOfButton2(paste)" .fRleft.listbox insert end "functionOfButton3(menu)" .fRleft.listbox insert end "functionOfButton4(scrollUp)" .fRleft.listbox insert end "functionOfButton5(scrollDown)" .fRleft.listbox insert end "functionOfButton6" .fRleft.listbox insert end "functionOfButton7" .fRleft.listbox insert end "functionOfButton8" .fRleft.listbox insert end "functionOfButton9" .fRleft.listbox insert end "functionOfButton10" .fRleft.listbox insert end "functionOfButton11" .fRleft.listbox insert end "functionOfButton12" .fRleft.listbox insert end "functionOfButton13" .fRleft.listbox insert end "functionOfButton14" .fRleft.listbox insert end "functionOfButton15" .fRleft.listbox insert end "functionOfButton16" .fRleft.listbox insert end "functionOfButton17" .fRleft.listbox insert end "functionOfButton18" .fRleft.listbox insert end "functionOfButton19" .fRleft.listbox insert end "functionOfButton20" .fRleft.listbox insert end "functionOfButton21" .fRleft.listbox insert end "functionOfButton22" .fRleft.listbox insert end "functionOfButton23" .fRleft.listbox insert end "functionOfButton24" } ## END OF PROC 'loadfuncs2listbox' ##+################################################################ ## proc 'process_listbox_select' ##+################################################################ ## PURPOSE: Uses the listbox selection (and the current value ## of the 'positionIDX' radiobuttons variable) to update ## the text in the 'fRxinputparms.txtLIST' text widget. ## ## CALLED BY: bindings (above) on the listbox ##+################################################################ proc process_listbox_select {x} { global positionIDX set sel_index [ .fRleft.listbox curselection ] # if { $sel_index != "" } { # set sel_func [ .fRleft.listbox get $sel_index ] # } ## FOR TESTING: # puts "process_listbox_select: sel_func = $sel_func" ## Rebuild the string for the 'fRxinputparms.txtXINPARMS' text widget ## and load the string into the 'fRxinputparms.txtXINPARMS' text widget ## using the 'insert' command. .fRright.fRxinputparms.txtXINPARMS delete 1.0 end .fRright.fRxinputparms.txtXINPARMS insert end \ [rebuild_xinput_parms $sel_index] ## FOR TESTING: # puts "process_listbox_select: sel_index = $sel_index" } ## END OF PROC 'process_listbox_select' ##+################################################################ ## proc 'init_xinput_parms_array' ##+################################################################ ## PURPOSE: Loads the array 'aRfuncs4butts' that ## holds the current mapping of function-numbers to ## button-numbers --- and ## builds the text string for the 'fRxinputparms.txtLIST' ## text widget, and inserts the string in the widget. ## ## CALLED BY: once in the 'Additional GUI Initialization' section ## at the bottom of this script. ##+################################################################ proc init_xinput_parms_array {} { global aRfuncs4butts NUMSstring # global deviceID ## The following simple loop may be replaced by an ## 'xinput get-button-map $deviceID' query ## to initialize this array according to current ## settings for the user-specified device. for {set k 1} {$k <= 24} {incr k} { set aRfuncs4butts($k) "$k" } ######################################################## ## The following sections allow the user to set defaults ## to appear when the GUI first comes up, showing the ## NUMSstring var which is set below. These defaults can ## be set to suit the user's choice of mouse. ######################################################## ####################################################### ## ** M500 or M510 (side-button paste): ## Override the 1-to-24 setting of array 'aRfuncs4butts', ## to set the 'aRfuncs4butts' array for a *Logitech M500* ## corded mouse or *Logitech M510* wireless mouse or other ## similar mice --- to change buttons 8 and 9 to paste, ## and de-activate the paste function of button 2. ## ## NOTE: This did not work out well. Buttons 8 and 9 are ## on the side of the mouse, and pushing them causes ## the mouse to move when doing a paste --- making it ## hard to paste text where it should go. See the next ## set of settings for the Logitech M500 mouse. ####################################################### if {0} { set aRfuncs4butts(2) "0" set aRfuncs4butts(8) "2" set aRfuncs4butts(9) "2" } ####################################################### ## ** M500 or M510 (top-button paste): ## Override the 1-to-24 setting of array 'aRfuncs4butts', ## to set the 'aRfuncs4butts' array for a *Logitech M500* ## corded mouse or *Logitech M510* wireless mouse or other ## similar mice --- to change buttons 8 and 9 to scroll ## up and down, deactivate 4 and 5 (so that button2 ## does not scroll --- ONLY paste). ## ## NOTE: This is 'pretty good', but since 8 and 9 do not ## 'roll' (i.e. repeat an up or down movement easily), ## one has to keep pushing the side buttons to scroll ## a 'chunk' per press --- i.e. scrolling is slow. ## Another issue is the unpleasant feel of the scroll ## wheel tending to roll when one pushes down on it to ## do a paste. ####################################################### if {0} { set aRfuncs4butts(4) "0" set aRfuncs4butts(5) "0" set aRfuncs4butts(8) "5" set aRfuncs4butts(9) "4" } ####################################################### ## ** G300 (top-button paste): ## Override the 1-to-24 setting of array 'aRfuncs4butts', ## to set the 'aRfuncs4butts' array for a *Logitech G300* ## corded 'gaming' mouse --- to change buttons 8 & 9 (on ## the top left of the mouse) to paste --- and deactivate ## paste on button 2 (the scroll wheel). ## ## NOTE: At least pushing down on button 8 (or 9) to do a ## paste does not move the mouse sideways --- and I still ## have the scrollwheel for fast up and down scrolling. ## This 8,9-paste works in all 3 'profiles' of the G300. ## xinput-test does not show button numbers when I ## press on the 2 buttons on the right of the G300, no ## matter which of the 3 profiles I am in. (???) ## It looks like I cannot de-activate those buttons. ## They act like Ctl-V and Ctl-C when in 'blue' mode. ## I will not use 'blue' mode so I don't accidentally ## do a paste --- or go into copy-mode. ######################################################## if {1} { set aRfuncs4butts(2) "0" set aRfuncs4butts(8) "2" set aRfuncs4butts(9) "2" } #################################################### ## Build a text string from the aRfuncs4butts array. #################################################### set NUMSstring "" for {set k 1} {$k <= 24} {incr k} { set NUMSstring "$NUMSstring $aRfuncs4butts($k)" } #################################################### ## Insert the string in the txtXINPARMS text widget. #################################################### .fRright.fRxinputparms.txtXINPARMS delete 1.0 end .fRright.fRxinputparms.txtXINPARMS insert end "$NUMSstring" } ## END OF PROC 'init_xinput_parms_array' ##+################################################################ ## proc 'rebuild_xinput_parms' ##+################################################################ ## PURPOSE: Uses the listbox selection index (and the current value ## of the 'positionIDX' radiobuttons variable) to update ## an entry in the xinput-parms-array, aRfuncs4butts --- ## and rebuild the text string for the 'fRxinputparms.txtLIST' ## text widget. ## ## CALLED BY: the 'process_listbox_select' proc ##+################################################################ proc rebuild_xinput_parms {func_idx} { global aRfuncs4butts positionIDX NUMSstring set aRfuncs4butts($positionIDX) "$func_idx" ## FOR TESTING: # puts "rebuild_xinput_parms:" # puts " func_idx = $func_idx" # puts " positionIDX = $positionIDX" # puts " aRfuncs4butts(positionIDX) = $aRfuncs4butts($positionIDX)" set NUMSstring "" for {set k 1} {$k <= 24} {incr k} { set NUMSstring "$NUMSstring $aRfuncs4butts($k)" } ## FOR TESTING: # puts "rebuild_xinput_parms: NUMSstring = $NUMSstring" return "$NUMSstring" } ## END OF PROC 'rebuild_xinput_parms' ##+################################################################ ## proc 'xinput_setmap' ##+################################################################ ## PURPOSE: Runs the command ## xinput set-button-map $deviceID $NUMSstring ## to reset the 'button-map' of the user-specified device ## according to the current numbers in $NUMstring. ## ## CALLED BY: the 'SetMap' button ##+################################################################ proc xinput_setmap {} { global deviceID NUMSstring ## We popup a msg-window to the user if device-ID not set. # if {"$deviceID" == "?"} if {![string is integer $deviceID]} { popup_msgVarWithScroll .topMsg "Device ID needed." return } set deviceID [string trim $deviceID] ## NO GOOD: (no error msg, but no effect) # exec /usr/bin/xinput set-button-map $deviceID $NUMSstring ## NO GOOD: (no error msg, but no effect) # exec /usr/bin/xinput set-button-map $deviceID $NUMSstring & ## The '/bin/sh -c' technique WORKS!!! exec /bin/sh -c "/usr/bin/xinput set-button-map $deviceID $NUMSstring" ## FOR TESTING: # puts "xinput_setmap > Ran the command:" # puts "/usr/bin/xinput set-button-map $deviceID $NUMSstring" } ## END OF PROC 'xinput_setmap' ##+################################################################ ## proc 'xinput_getmap' ##+################################################################ ## PURPOSE: Runs the command ## xinput get-button-map $deviceID ## to get the 'button-map' of the user-specified device. ## ## CALLED BY: the 'GetMap' button ##+################################################################ proc xinput_getmap {} { global deviceID NUMSstring aRfuncs4butts ## We popup a msg-window to the user if device-ID not set. if {![string is integer $deviceID]} { popup_msgVarWithScroll .topMsg "Device ID needed." return } set deviceID [string trim $deviceID] ## Some example 'exec' code: # exec /usr/bin/sh -c "$EDITOR_text "$FULFILname" > /dev/null 2>&1" # -command "exec $feREADER_text ./dir2dir_fileman.hlp &" set NUMSstring [exec /usr/bin/xinput get-button-map $deviceID] ## FOR TESTING: # puts "xinput_setmap > Ran the command:" # puts "/usr/bin/xinput get-button-map $deviceID" ## Insert the string in the txtXINPARMS widget. .fRright.fRxinputparms.txtXINPARMS delete 1.0 end .fRright.fRxinputparms.txtXINPARMS insert end "$NUMSstring" ## Say NUMSstring returned from 'get-button-map' is a string of ## N integers. I need to load those N integers into the first ## N entries of the array 'aRfuncs4butts'. (Thing-to-do.) set CNT 1 foreach N $NUMSstring { set aRfuncs4butts($CNT) $N incr CNT } } ## END OF PROC 'xinput_getmap' ##+################################################################ ## proc 'xinput_test' ##+################################################################ ## PURPOSE: Runs the command ## xterm -hold ... -e xinput test $deviceID ## to monitor 'events' from the user-specified device. ## ## CALLED BY: the 'Test' button ##+################################################################ proc xinput_test {} { global deviceID ## We popup a msg-window to the user if device-ID not set. if {![string is integer $deviceID]} { popup_msgVarWithScroll .topMsg "Device ID needed." return } exec xterm -hold -fg white -bg black -e \ /usr/bin/xinput test $deviceID } ## END OF PROC 'xinput_test' ##+##################################################################### ## proc 'getset_bkgdcolor' ##+##################################################################### ## PURPOSE: ## This procedure is invoked to get an RGB triplet (Rpal255 Gpal255 Bpal255) ## via 3 RGB slider bars. ## ## Then uses 'set_palette' proc to set window color scheme. ## ## CALLED BY: .fRright.fRbuttons.buttCOLOR button ##+##################################################################### proc getset_bkgdcolor {} { global Rpal255 Gpal255 Bpal255 # global feDIR_tkguis ## FOR TESTING: # puts "Rpal255: $Rpal255" # puts "Gpal255: $Gpal255" # puts "Bpal255: $Bpal255" set TEMPrgb [ exec \ ./sho_colorvals_via_sliders3rgb.tk \ $Rpal255 $Gpal255 $Bpal255] # $feDIR_tkguis/sho_colorvals_via_sliders3rgb.tk \ ## FOR TESTING: # puts "TEMPrgb: $TEMPrgb" if { "$TEMPrgb" == "" } { return } scan $TEMPrgb "%s %s %s %s" Rpal255 Gpal255 Bpal255 hexRGB ## FOR TESTING: # puts "TEMPrgb: $TEMPrgb" # puts "Rpal255: $Rpal255" # puts "Gpal255: $Gpal255" # puts "Bpal255: $Bpal255" # set hexRGB [format "#%02X%02X%02X" $Rpal255 $Gpal255 $Bpal255] tk_setPalette "#$hexRGB" } ## END OF PROC 'getset_bkgdcolor' ##+######################################################################## ## PROC 'popup_msgVarWithScroll' ##+######################################################################## ## PURPOSE: Report help or error conditions to the user. ## ## We do not use focus,grab,tkwait in this proc, ## because we use it to show help when the GUI is idle, ## and we may want the user to be able to keep the Help ## window open while doing some other things with the GUI ## such as putting a filename in the filename entry field ## or clicking on a radiobutton. ## ## For a similar proc with focus-grab-tkwait added, ## see the proc 'popup_msgVarWithScroll_wait' in a ## 3DterrainGeneratorExaminer Tk script. ## ## REFERENCE: page 602 of 'Practical Programming in Tcl and Tk', ## 4th edition, by Welch, Jones, Hobbs. ## ## ARGUMENTS: A toplevel frame name (such as .fRhelp or .fRerrmsg) ## and a variable holding text (many lines, if needed). ## ## CALLED BY: 'help' button ##+######################################################################## ## To have more control over the formatting of the message (esp. ## words per line), we use this 'toplevel-text' method, ## rather than the 'tk_dialog' method -- like on page 574 of the book ## by Hattie Schroeder & Mike Doyel,'Interactive Web Applications ## with Tcl/Tk', Appendix A "ED, the Tcl Code Editor". ##+######################################################################## proc popup_msgVarWithScroll { toplevName VARtext } { ## global fontTEMP_varwidth #; Not needed. 'wish' makes this global. ## global env # bell # bell ################################################# ## Set VARwidth & VARheight from $VARtext. ################################################# ## To get VARheight, ## split at '\n' (newlines) and count 'lines'. ################################################# set VARlist [ split $VARtext "\n" ] ## For testing: # puts "VARlist: $VARlist" set VARheight [ llength $VARlist ] ## For testing: # puts "VARheight: $VARheight" ################################################# ## To get VARwidth, ## loop through the 'lines' getting length ## of each; save max. ################################################# set VARwidth 0 ############################################# ## LOOK AT EACH LINE IN THE LIST. ############################################# foreach line $VARlist { ############################################# ## Get the length of the line. ############################################# set LINEwidth [ string length $line ] if { $LINEwidth > $VARwidth } { set VARwidth $LINEwidth } } ## END OF foreach line $VARlist ## For testing: # puts "VARwidth: $VARwidth" ############################################################### ## NOTE: VARwidth works for a fixed-width font used for the ## text widget ... BUT the programmer may need to be ## careful that the contents of VARtext are all ## countable characters by the 'string length' command. ############################################################### ##################################### ## SETUP 'TOP LEVEL' HELP WINDOW. ##################################### catch {destroy $toplevName} toplevel $toplevName # wm geometry $toplevName 600x400+100+50 wm geometry $toplevName +100+50 wm title $toplevName "Note" # wm title $toplevName "Note to $env(USER)" wm iconname $toplevName "Note" ##################################### ## In the frame '$toplevName' - ## DEFINE THE TEXT WIDGET and ## its two scrollbars --- and ## DEFINE an OK BUTTON widget. ##################################### if {$VARheight > 10} { text $toplevName.text \ -wrap none \ -font fontTEMP_varwidth \ -width $VARwidth \ -height $VARheight \ -bg "#f0f0f0" \ -relief raised \ -bd 2 \ -yscrollcommand "$toplevName.scrolly set" \ -xscrollcommand "$toplevName.scrollx set" scrollbar $toplevName.scrolly \ -orient vertical \ -command "$toplevName.text yview" scrollbar $toplevName.scrollx \ -orient horizontal \ -command "$toplevName.text xview" } else { text $toplevName.text \ -wrap none \ -font fontTEMP_varwidth \ -width $VARwidth \ -height $VARheight \ -bg "#f0f0f0" \ -relief raised \ -bd 2 } button $toplevName.butt \ -text "OK" \ -font fontTEMP_varwidth \ -command "destroy $toplevName" ############################################### ## PACK *ALL* the widgets in frame '$toplevName'. ############################################### ## Pack the bottom button BEFORE the ## bottom x-scrollbar widget, pack $toplevName.butt \ -side bottom \ -anchor center \ -fill none \ -expand 0 if {$VARheight > 10} { ## Pack the scrollbars BEFORE the text widget, ## so that the text does not monopolize the space. pack $toplevName.scrolly \ -side right \ -anchor center \ -fill y \ -expand 0 ## DO NOT USE '-expand 1' HERE on the Y-scrollbar. ## THAT ALLOWS Y-SCROLLBAR TO EXPAND AND PUTS ## BLANK SPACE BETWEEN Y-SCROLLBAR & THE TEXT AREA. pack $toplevName.scrollx \ -side bottom \ -anchor center \ -fill x \ -expand 0 ## DO NOT USE '-expand 1' HERE on the X-scrollbar. ## THAT KEEPS THE TEXT AREA FROM EXPANDING. pack $toplevName.text \ -side top \ -anchor center \ -fill both \ -expand 1 } else { pack $toplevName.text \ -side top \ -anchor center \ -fill both \ -expand 1 } ##################################### ## LOAD MSG INTO TEXT WIDGET. ##################################### ## $toplevName.text delete 1.0 end $toplevName.text insert end $VARtext $toplevName.text configure -state disabled } ## END OF PROC 'popup_msgVarWithScroll' ##+######################## ## END of PROC definitions. ##+######################## ## Set HELPtext var. ##+######################## set HELPtext "\ \ \ \ \ \ ** HELP for this 'tkPointerSettings' Utility ** This utility provides a GUI wrapper for the 'xinput' command --- so that you can run 'xinput' in an 'assist-mode'. The 'xinput' command can be used to change functions of 'buttons' of a mouse or other 'pointer' device. That is what this utility is intended to do. The GUI supplies radiobuttons, a listbox, and other widgets that help the user to CHANGE FUNCTIONS of (or ASSIGN FUNCTIONS to) the various BUTTONS or 'FEATURES' of a 'POINTER DEVICE'. Here 'FEATURE' refers to a function that is performed by an action OTHER THAN A BUTTON-PRESS --- such as ROLLING a scroll-wheel (forward or backward) --- or TILTING a scroll-wheel (right or left). Rolling a scroll-wheel UP corresponds to one 'button' number, while rolling the scroll-wheel DOWN corresponds to another 'button' number --- even though these actions do not really involve a 'button'. (It might be helpful to think in terms of 'wires' or 'sensors' rather than 'buttons'.) The term 'pointer device' is meant to convey that this Tk GUI 'wrapper' script can apply to devices other than computer mice --- devices such as touchpads or game 'pad' controllers, or even a touchscreen. **************************************** SOME TYPICAL USES OF THIS GUI: **************************************** This GUI can be used to: a) Switch the functions of mouse button 1 (typically used to select items) and button 3 (typically used to expose an auxiliary menu), for left-handed users. b) Deactivate the 'paste' function of mouse-button 2 --- for users of a mouse with scroll-wheel --- when pressing down too hard on the scroll-wheel causes an unwanted paste operation. c) Deactivate the 'scroll' functions of the scroll-wheel --- so that the wheel can be used just for the 'paste' function, without accidentally scrolling the contents of a window while doing the paste. d) Assign extra buttons 6 and/or 7 (on a scroll-wheel mouse with extra buttons) so that the 'paste' operation can be done with one or both of the extra buttons. (For a scroll-wheel mouse whose scroll-wheel can be tilted left or right and thus send signals corresponding to 'buttons' 6 and 7, one might assign extra buttons 8 and/or 9 the 'paste' function.) e) For those who like a quick swipe-and-paste operation with buttons 1 (for swipe) and 2 (for paste), where 2 is a scroll wheel, they may want to: Deactivate the scroll up-and-down functions of 'buttons'/'wires' 4-and-5 (so that button 2, the scroll wheel, is just used for paste, not scroll) --- and re-assign the scroll up and down functions of the scroll wheel to other buttons (side or top), say 7-and-6 or 9-and-8. (This works better than option (d) above, for text pasting, if extra buttons are NOT available on TOP of the mouse --- if extra buttons are ONLY available on the SIDE, via the thumb. We do not want to press on the side of the mouse while we do the paste, because this will generally cause the mouse to move. This will generally scroll the text just pasted far from where the text is wanted --- and it may result in pasting the text where it is not wanted. On the other hand, we do NOT need this precise, 'hold-the-mouse-fixed-while-pressing-the-button' action when doing scrolling. So it is OK to let up on the mouse with the thumb, and use the thumb, with side-pressure, on buttons 8-and-9 or 6-and-7 to scroll down-and-up.) ***************************************** TYPICAL SEQUENCE OF OPERATIONS: (with widgets of the GUI) ***************************************** 1) SET THE DEVICE-ID: (via the 'DeviceID' entry field and the 'Test' button) The **DeviceID ENTRY FIELD** is used to specify a device number for the user's pointer device. The DeviceID for the 'pointer device' of a computer can often be determined simply by looking at the **OUTPUT OF THE 'xinput list' COMMAND**, which is shown in a **SCROLLABLE TEXT** area on the GUI. Sometimes it is not enough to look for a string like 'Type is MOUSE' or 'Type is TOUCHPAD' in the text area to find the DeviceID number after an 'id=' string. And sometimes there is not a distinguishing 'device name', like 'USB Optical Mouse' nor a manufacturer name like 'Logitech' followed by a word like 'Mouse'. In those cases, it is helpful to put a GUESS at a DeviceID number in the DeviceID entry field, and click on the ** 'Test' BUTTON **. Then a window pops up and for any motion of the mouse/pointer-device and for any action, like a button press, text will appear in the 'Test' window to indicate the event. Thus the user can tell whether the guess for the DeviceID was right. The 'Test' button has other uses. If the user plans to assign a function to a button (or other 'protrusion' or 'sensor' or 'wire' of the pointer device), it may not be clear what number that button/sensor/wire has been assigned. Button presses (and other actions) will show a button number. Hence you can determine button numbers for 'protuberances' or 'sensors' or 'wires' of the pointer device. 2) DETERMINE THE CURRENT MAPPING: (via the 'GETmap' button) Once you determine the DeviceID and have it entered in the DeviceID field, you can press the ** 'GETmap' BUTTON ** and the command xinput get-button-map will be run and the output will show up in the text area to the right of the 'Map-list' label on the GUI. The 'Map-list' will be a sequence of integers such as 1 2 3 4 5 6 7 ... or, for a left-hander, it might be 3 2 1 4 5 6 7 ... 3) CHANGE THE MAPPING: (via the radiobuttons and listbox) To change a number in the 'Map-list' string, click on a RADIOBUTTON of the GUI, to choose a position number, from 1 to 24. Then click on a line of the Functions LISTBOX, to assign that function to the chosen position in the Map-list string. The Map-list should immediately update on the GUI. For example, a left-handed user might click on RADIOBUTTON 1 and click on 'functionForButton3(menu)' in the LISTBOX. Then they would click on RADIOBUTTON 3 and click on 'functionForButton1(select)' in the LISTBOX. 4) APPLY THE NEW MAPPING: (via the 'SETmap' button) When the user has set the Map-list string as desired, they click on the ** 'SETmap' BUTTON ** on the GUI, which runs the command xinput set-button-map . The change to the actions of the pointer device should take effect immediately. The user can test this out by doing 'paste' operations or 'select' operations (or whatever) from/to/in various X-windows of the user's desktop. 5) ANOTHER OPERATION: (simply query without a mapping change) The 'GETmap' button can be handy to replace the mapping string with the settings that are currently active for the mouse. For example, you can use GETmap when you first start up the GUI after logging in --- to see what your mouse is currently set to do --- either because of config file settings or log-in scripts, or by default, because none of those things exist. *************************************** SOME SIMPLE MAPPING EXAMPLES: (disable and paste) *************************************** If you want to disable a button, choose 'NoOperation' from the listbox. For example, if you want to disable the 'paste' operation of the scroll-wheel on a scroll-wheel mouse, click on radiobutton number 2 and click on 'NoOperation' in the listbox. And, if you want to give button 8, say, the 'paste' capability, click on radiobutton number 8 and click on 'functionOfButton2(paste)' in the listbox. Of course, there is no point assigning functions to 'wires' if the mouse was not made to have those 'wires'. For example, the simplest scroll-wheel mice usually only have 'wires' 1 through 5. In that case, assigning functions to buttons 6 through 24 will have no effect. For some mappings for 'better pasting', see the examples for specific mice models, near the bottom of this help. ************************************* OTHER WIDGETS OF THE GUI: ************************************* The 'typical sequence of operations' above touches on most of the widgets of the GUI. Of course, the 'Exit' button allows for exiting and closing the 'tkPointerSettings' GUI --- and the 'Help' button shows this help. The 'ColorMe' button is there just in case your friends tell you that the GUI looks 'blah'. You can change the window's 'palette' of colors to a color of their choosing. ******************************************** MAKING A MAPPING CHANGE 'PERMANENT': (for future login sessions) ******************************************** To make the changes permanent (for whenever you login to your computing device), you can copy and paste the 'Map-list' string into a script (or configuration file or whatever) to make the settings 'permanent'. There is plenty of information on the internet on how to make the settings 'permanent' for your particular operating system --- including a lot of information that you would best ignore. How to separate the good info from the bad? That's an art. Typically you might want to make a little two line script that executes the 'xinput set-button-map' command with your 'device NAME' (NOT id number, which might change if devices are added). Also supply the string of numbers from the 'Map-list' that worked for you. Example script: #!/bin/sh ## For a left-handed person: xinput set-button-map 'Logitech Gaming Mouse G300' 3 2 1 4 5 6 7 8 9 You could put these lines in a file named 'my_xinput_mapping.sh' in your home directory or in some sub-directory of the home directory. Then you can call on that script to execute ... from a login or shell 'run control' file --- such as \$HOME/.bashrc or \$HOME/.bash_aliases or \$HOME/.profile or \$HOME/.kshrc or ... where \$HOME represents your home directory. Find information for your operating system on which file is best to modify. --- Another option is to set the 'tkPointerSettings' GUI script to startup with your favorite string of numbers in the 'Map-list'. (See the proc 'init_xinput_parms_array' in the 'tkPointerSettings.tk' script.) Then, after starting up this GUI, you can simply enter the DeviceID for your pointer device and click the 'SETmap' button to activate your favorite settings --- for the current login session. You could setup this Tk script as an icon on your desktop. Then it would be simply a double-click (or right-click and choose Open) on that icon to run this script whenever you want. --- You can return to this GUI to make minor mapping changes during a session --- for example, if the 'scroll' function were bothering you during 'paste' operation and you wanted to disable the scroll function provided by 'wires' 4-and-5 (of the scroll wheel), for a while. OR you could temporarily disable the paste function of button-2 (the scroll wheel), if scrolling was accompanied by unwanted paste operations. ********************************* SETTINGS FOR BETTER PASTE (for various mice) ********************************* A main motivation for developing this 'tkPointerSettings' GUI was to be able to change the default settings of a scroll-wheel mouse so that it is just as suitable for text-paste operations as for scrolling. This typically means finding a suitable scroll-wheel mouse --- with extra buttons that can be used, in place of the scroll-wheel --- and determining a suitable mapping for use with that mouse. Following are some 'paste-friendly' mappings for several mouse models: 1) The Logitech G300 WIRED/CORDED GAMING MOUSE (top-button paste): The Logitech G300 WIRED/CORDED GAMING MOUSE has extra buttons on top of the mouse, on both the left and the right. The buttons on the top-left (8 and 9) can be re-mapped with 'xinput'. Suggested mapping: 1 0 3 4 5 6 7 2 2 10 11 12 ... This mapping changes buttons 8 and 9 (on the top left of the G300 mouse) to paste --- and deactivates paste on button 2 (the scroll wheel). NOTE: Pushing down on button 8 or 9 (labelled 'G4' and 'G5' on the G300) to do a paste does not move the mouse sideways --- and I still have the scrollwheel for fast up and down scrolling. This 8,9-paste works in all 3 'profiles' of the G300. The 'G8' button in the middle of the mouse cycles the mouse through 'red', 'green', and 'blue' profiles. xinput-'Test' does not show button numbers when I press on the 2 buttons on the right of the G300 (labelled 'G6' and 'G7'), no matter which of the 3 profiles I am in. It looks like I cannot de-activate or re-map those buttons. They act like Ctl-V and Ctl-C when in 'blue' mode. If one does not use 'blue' mode, then one won't accidentally do a paste --- or go into copy-mode --- if one accidentally presses the upper-right buttons of this mouse. 2) The Logitech M500 WIRED OR M510 WIRELESS MOUSE (mid-button paste) The Logitech M500 and M510 mice do NOT have EXTRA buttons on the TOP of the mouse, but we can use button 2 for paste and assign the scroll operations elsewhere. These mice have EXTRA BUTTONS (8 and 9) on the LEFT SIDE. We can re-assign the scroll 'buttons' (4 and 5) to the side buttons. That is, we can de-activate 4 and 5 and re-map them to 8 and 9. Suggested mapping: 1 2 3 0 0 6 7 5 4 10 11 12 ... NOTE: This is 'pretty good', but since 8 and 9 do not 'roll' (i.e. do not REPEAT an up or down movement easily), one has to keep pushing the side buttons to scroll a 'chunk' per press --- i.e. scrolling is slow. Another issue is the unpleasant feel of the scroll wheel tending to roll when one pushes down on it to do a paste. 3) The Logitech M500 WIRED OR M510 WIRELESS MOUSE (side-button paste) As mentioned in item 2 above, the Logitech M500 and M510 mice do NOT have EXTRA buttons on the top of the mouse, but there are extra buttons (8 and 9) on the left side. We can keep the scroll 'buttons' (4 and 5) for scrolling and change the paste operation (button 2) to the side buttons. Suggested mapping: 1 0 3 4 5 6 7 2 2 10 11 12 ... NOTE: This did not work out well. Buttons 8 and 9 are on the side of the mouse, and pushing them causes the mouse to move when doing a paste --- making it hard to paste text where it should go --- and remain positioned near the pasted text. See the alternative settings for the Logitech M500 and M510 mice, in item 2 above. --- I may add some 'paste-friendly' mappings for other mice, such as: - the Logitech M570 wireless TRACKBALL mouse, which has a couple of extra buttons on the TOP left of the mouse - the Steelseries 'Legendary Edition' mouse, which has extra buttons on the TOP of the mouse, on both the left and the right. " ##+###################################################### ## Additional GUI INITIALIZATION: ## ## (This is for most of the APPLICATION-SPECIFIC initialization, ## such as widget VARIABLES --- NOT for widget PARAMETERS ## such as button padding or '-relief' settings.) ##+###################################################### ##+################################################## ## Set a default value for the radiobuttons variable. ##+################################################## set positionIDX 2 ##+######################################## ## Load the functions-for-buttons listbox. ##+######################################## loadfuncs2listbox ##+##################################################### ## Initialize the string in the .fRxinputparms.txtINPUT ## text widget --- to the sequence of integers 1-24. ## ## See the internals of this proc for statements that ## tailor the NUMSstring that appears on the GUI to ## a user's favorite mouse. ##+##################################################### init_xinput_parms_array