Mar 9, 2015

Viewport Navigation Without Middle Mouse Button

Blender offers users an option in the Preferences, to change from Middle Mouse Button navigation to Alt-Left Mouse Button navigation. However, the feature is available only if the Right Mouse Button is set as the Select button.

For those of us who prefer to select with the Left Mouse Button, and wish to avoid navigating with the Middle Mouse Button, the addon presented here offers a safe and elegant solution.

Usage instructions for beginners are in a short YouTube tutorial. For advanced users, full details and some additional options are at the top of the script itself.

You can download the tab-indented Python file from Google Drive here:

BVP_NoMMB_Navigation.py

If you prefer, you can copy and paste the space-indented text of the addon manually from here:

# ##### BEGIN GPL LICENSE BLOCK #####
#
#  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.
#
# ##### END GPL LICENSE BLOCK #####

# ##### BEGIN ADVANCED SETTINGS AND INFO #####
#
# This addon provides *additional* mousing keymap items for users who wish to avoid using
# the Middle Mouse Button for navigation in Blender windows. Advantage is taken of the fact
# that the keymap space reserved by Blender for addons will override settings in the main
# keymap. It is thus possible to offer additional keymap items without making any changes to
# the main keymap.
#
# --- MAIN ITEMS ---
# For 2D windows, such as Timeline, Image Editor etc., the offered alternatives are:
#
# Pan View: Alt-ACTIONMOUSE
# Zoom View: Ctrl-Alt-ACTIONMOUSE
#
# Which mouse button is active as ACTIONMOUSE depends on an Input preference setting. By default,
# the Right Mouse Button is set as SELECTMOUSE, and Left is therefore the ACTIONMOUSE. Many users,
# however, perhaps the majority of new users, switch to Select with the Left Mouse Button, to more
# closely match their experience in other applications. Then the Right button is the ACTIONMOUSE.
#
# For 3D View, the offered alternatives to MMB navigation are:
#
# Rotate View: ACTIONMOUSE (no modifiers)
# Move(Pan) View: Alt-ACTIONMOUSE
# Zoom View: Ctrl-Alt-ACTIONMOUSE
# Dolly View: Shift-Ctrl-Alt-ACTIONMOUSE
#
# If you would prefer to press the Alt modifier for rotating rather than for moving/panning the
# 3D View, then set the PressAltForRotation value to 1

PressAltForRotation = 0

# --- STENCIL PAINT MODE ---
# The offered navigation commands do not work in stencil painting mode in 3D View and Image Editor
# because the mousing keymap items are already taken up for stencil transformations. They also don't
# work in Sculpt, Vertex, Weight and Texture Paint modes if Left Mouse Button is the ACTIONMOUSE.
#
# The problem is solved by involving the OSKey, so Alt-ACTIONMOUSE becomes Alt-Oskey-ACTIONMOUSE, etc.
# (The OSKey is the Win key on Windows and Command key on Mac.)
#
# Because the OSKey solution may be problematic for some users, an additional alternative to
# Middle Mouse Button navigation during painting operations is offered: ACTIONMOUSE pressed together
# with key modifiers: COMMA for rotation (3D View only), PERIOD for move/pan, SLASH for zoom.
# For consistency, these items also work outside painting operations (same for the OSKey solution).
#
# These key-modifier items are by default disabled because they change the Pivot Center setting.
# Additionally, pressing the comma in Image Editor during painting will throw up a rather ugly looking
# error. It happens whether or not this addon is enabled.
#
# These key-modifier items are quite comfortable to use though, so feel free to enable them by
# changing the value of EnableKeyModifiers to 1

EnableKeyModifiers = 0

# If you know what you're doing, you can easily change the key modifiers from COMMA, PERIOD, SLASH
# to some other keys. Be careful though, there are not many keys that can safely be used, as most
# are active in the Blender keymap. These values should really only be changed by those who use
# other keymaps. These settings have no effect if key modifiers are turned off with EnableKeyModifiers
# option above being set to 0.
#
# Depending on your keyboard, another good option here might be SLASH, BACK_SLASH and SEMI_COLON, which
# would not interfere with any existing Blender keymap items.

keyModifierRotation = 'COMMA'
keyModifierMovePan = 'PERIOD'
keyModifierZoom = 'SLASH'

# You can see the full list of available key modifiers here:
#
# http://www.blender.org/api/blender_python_api_2_73a_release/bpy.types.KeyMapItem.html#bpy.types.KeyMapItem.key_modifier
#
# --- OVERRIDE CORRECTIONS ---
# Provision is made for correction of the 3 conflicting overrides of the new navigation commands.
#
# 3D View > Cursor positioning: Shift-Ctrl-ACTIONMOUSE
# File Browser > Select with Extend and Fill: Shift-Alt-RIGHTMOUSE
# Node Editor > Backimage Sample: Shift-Ctrl-ACTIONMOUSE
#
# The File Browser correction is needed only if Right Mouse Button is the ACTIONMOUSE
#
# --- EXCEPTIONS ---
# The navigation mousing commands of this addon do not work in Grease Pencil continuous drawing mode,
# and when using the Knife Tool. The usual methods remain available: Middle Mouse Button, and Mouse
# Wheel shortcuts. You don't lose anything by using this addon, but in these two cases you don't gain
# anything either.
#
# ##### END ADVANCED SETTINGS AND INFO #####

bl_info = {
    "name": "BVP No Middle Mouse Button Navigation",
    "author": "BVP, blendervisionpro.blogspot.com",
    "version": (0,1),
    "blender": (2, 73, 0),
    "location": "None",
    "description": "Additional mousing keymap items to enable viewport navigation without middle mouse button",
    "category": "User Interface"}

import bpy

addon_keymaps = []

def register():

    wm = bpy.context.window_manager
    
    # Provide alternative to MMB panning and zooming in all windows with Alt- and Ctrl-Alt-ACTIONMOUSE:
        
    # View 2D
    km = wm.keyconfigs.addon.keymaps.new(name='View2D', space_type='EMPTY', region_type='WINDOW')
    kmi = km.keymap_items.new('view2d.pan', 'ACTIONMOUSE', 'PRESS', alt=True)
    kmi = km.keymap_items.new('view2d.zoom', 'ACTIONMOUSE', 'PRESS', ctrl=True, alt=True)
    
    kmi = km.keymap_items.new('view2d.pan', 'ACTIONMOUSE', 'PRESS', alt=True, oskey=True)
    kmi = km.keymap_items.new('view2d.zoom', 'ACTIONMOUSE', 'PRESS', ctrl=True, alt=True, oskey=True)
    
    if EnableKeyModifiers:
        kmi = km.keymap_items.new('view2d.pan', 'ACTIONMOUSE', 'PRESS', key_modifier=keyModifierMovePan)
        kmi = km.keymap_items.new('view2d.zoom', 'ACTIONMOUSE', 'PRESS', key_modifier=keyModifierZoom)
    
    # View 2D Buttons List
    km = wm.keyconfigs.addon.keymaps.new(name='View2D Buttons List', space_type='EMPTY', region_type='WINDOW')
    kmi = km.keymap_items.new('view2d.pan', 'ACTIONMOUSE', 'PRESS', alt=True)
    kmi = km.keymap_items.new('view2d.zoom', 'ACTIONMOUSE', 'PRESS', ctrl=True, alt=True)
    
    kmi = km.keymap_items.new('view2d.pan', 'ACTIONMOUSE', 'PRESS', alt=True, oskey=True)
    kmi = km.keymap_items.new('view2d.zoom', 'ACTIONMOUSE', 'PRESS', ctrl=True, alt=True, oskey=True)
    
    if EnableKeyModifiers:
        kmi = km.keymap_items.new('view2d.pan', 'ACTIONMOUSE', 'PRESS', key_modifier=keyModifierMovePan)
        kmi = km.keymap_items.new('view2d.zoom', 'ACTIONMOUSE', 'PRESS', key_modifier=keyModifierZoom)
    
    # Clip Editor
    km = wm.keyconfigs.addon.keymaps.new(name='Clip Editor', space_type='CLIP_EDITOR', region_type='WINDOW')
    kmi = km.keymap_items.new('clip.view_pan', 'ACTIONMOUSE', 'PRESS', alt=True)
    kmi = km.keymap_items.new('clip.view_zoom', 'ACTIONMOUSE', 'PRESS', ctrl=True, alt=True)
    
    kmi = km.keymap_items.new('clip.view_pan', 'ACTIONMOUSE', 'PRESS', alt=True, oskey=True)
    kmi = km.keymap_items.new('clip.view_zoom', 'ACTIONMOUSE', 'PRESS', ctrl=True, alt=True, oskey=True)
    
    if EnableKeyModifiers:
        kmi = km.keymap_items.new('clip.view_pan', 'ACTIONMOUSE', 'PRESS', key_modifier=keyModifierMovePan)
        kmi = km.keymap_items.new('clip.view_zoom', 'ACTIONMOUSE', 'PRESS', key_modifier=keyModifierZoom)

    # Image Editor
    km = wm.keyconfigs.addon.keymaps.new(name='Image', space_type='IMAGE_EDITOR', region_type='WINDOW')
    kmi = km.keymap_items.new('image.view_pan', 'ACTIONMOUSE', 'PRESS', alt=True)
    kmi = km.keymap_items.new('image.view_zoom', 'ACTIONMOUSE', 'PRESS', ctrl=True, alt=True)
    
    kmi = km.keymap_items.new('image.view_pan', 'ACTIONMOUSE', 'PRESS', alt=True, oskey=True)
    kmi = km.keymap_items.new('image.view_zoom', 'ACTIONMOUSE', 'PRESS', ctrl=True, alt=True, oskey=True)
    
    if EnableKeyModifiers:
        kmi = km.keymap_items.new('image.view_pan', 'ACTIONMOUSE', 'PRESS', key_modifier=keyModifierMovePan)
        kmi = km.keymap_items.new('image.view_zoom', 'ACTIONMOUSE', 'PRESS', key_modifier=keyModifierZoom)
    
    # Text Editor
    km = wm.keyconfigs.addon.keymaps.new(name='Text', space_type='TEXT_EDITOR', region_type='WINDOW')
    kmi = km.keymap_items.new('text.scroll', 'ACTIONMOUSE', 'PRESS', alt=True)
    kmi = km.keymap_items.new('text.scroll', 'ACTIONMOUSE', 'PRESS', alt=True, oskey=True) # for consistency
    
    # View 3D - special case because of view rotation and cursor
    km = wm.keyconfigs.addon.keymaps.new(name='3D View', space_type='VIEW_3D', region_type='WINDOW')
    kmi = km.keymap_items.new('view3d.cursor3d', 'ACTIONMOUSE', 'PRESS', shift=True, ctrl=True)
    
    if PressAltForRotation:
        kmi = km.keymap_items.new('view3d.rotate', 'ACTIONMOUSE', 'PRESS', alt=True)
        kmi = km.keymap_items.new('view3d.move', 'ACTIONMOUSE', 'PRESS')
    else:
        kmi = km.keymap_items.new('view3d.rotate', 'ACTIONMOUSE', 'PRESS')
        kmi = km.keymap_items.new('view3d.move', 'ACTIONMOUSE', 'PRESS', alt=True)
    kmi = km.keymap_items.new('view3d.zoom', 'ACTIONMOUSE', 'PRESS', ctrl=True, alt=True)
    kmi = km.keymap_items.new('view3d.dolly', 'ACTIONMOUSE', 'PRESS', shift=True, ctrl=True, alt=True)
    
    if PressAltForRotation:
        kmi = km.keymap_items.new('view3d.rotate', 'ACTIONMOUSE', 'PRESS', alt=True, oskey=True)
        kmi = km.keymap_items.new('view3d.move', 'ACTIONMOUSE', 'PRESS', oskey=True)
    else:
        kmi = km.keymap_items.new('view3d.rotate', 'ACTIONMOUSE', 'PRESS', oskey=True)
        kmi = km.keymap_items.new('view3d.move', 'ACTIONMOUSE', 'PRESS', alt=True, oskey=True)
    kmi = km.keymap_items.new('view3d.zoom', 'ACTIONMOUSE', 'PRESS', ctrl=True, alt=True, oskey=True)
    
    if EnableKeyModifiers:
        kmi = km.keymap_items.new('view3d.rotate', 'ACTIONMOUSE', 'PRESS', key_modifier=keyModifierRotation)
        kmi = km.keymap_items.new('view3d.move', 'ACTIONMOUSE', 'PRESS', key_modifier=keyModifierMovePan)
        kmi = km.keymap_items.new('view3d.zoom', 'ACTIONMOUSE', 'PRESS', key_modifier=keyModifierZoom)
    
        # Image Paint in Image Editor
        km = wm.keyconfigs.addon.keymaps.new(name='Image Paint', space_type='EMPTY', region_type='WINDOW')
        kmi = km.keymap_items.new('image.view_pan', 'ACTIONMOUSE', 'PRESS', key_modifier=keyModifierMovePan)
        kmi = km.keymap_items.new('image.view_zoom', 'ACTIONMOUSE', 'PRESS', key_modifier=keyModifierZoom)
    
        # Mask Editing
        km = wm.keyconfigs.addon.keymaps.new(name='Mask Editing', space_type='EMPTY', region_type='WINDOW')
        kmi = km.keymap_items.new('image.view_pan', 'ACTIONMOUSE', 'PRESS', key_modifier=keyModifierMovePan)
        kmi = km.keymap_items.new('image.view_zoom', 'ACTIONMOUSE', 'PRESS', key_modifier=keyModifierZoom)
    
    # UV Editor
    km = wm.keyconfigs.addon.keymaps.new(name='UV Editor', space_type='EMPTY', region_type='WINDOW')
    kmi = km.keymap_items.new('image.view_pan', 'ACTIONMOUSE', 'PRESS', alt=True, oskey=True)
    kmi = km.keymap_items.new('image.view_zoom', 'ACTIONMOUSE', 'PRESS', ctrl=True, alt=True, oskey=True)
    
    if EnableKeyModifiers:
        kmi = km.keymap_items.new('image.view_pan', 'ACTIONMOUSE', 'PRESS', key_modifier=keyModifierMovePan)
        kmi = km.keymap_items.new('image.view_zoom', 'ACTIONMOUSE', 'PRESS', key_modifier=keyModifierZoom)

    # UV Sculpt
    km = wm.keyconfigs.addon.keymaps.new(name='UV Sculpt', space_type='EMPTY', region_type='WINDOW')
    kmi = km.keymap_items.new('image.view_pan', 'ACTIONMOUSE', 'PRESS', alt=True, oskey=True)
    kmi = km.keymap_items.new('image.view_zoom', 'ACTIONMOUSE', 'PRESS', ctrl=True, alt=True, oskey=True)
    
    if EnableKeyModifiers:
        kmi = km.keymap_items.new('image.view_pan', 'ACTIONMOUSE', 'PRESS', key_modifier=keyModifierMovePan)
        kmi = km.keymap_items.new('image.view_zoom', 'ACTIONMOUSE', 'PRESS', key_modifier=keyModifierZoom)
    
        # Image Paint in 3D View
        km = wm.keyconfigs.addon.keymaps.new(name='Image Paint', space_type='EMPTY', region_type='WINDOW')
        kmi = km.keymap_items.new('view3d.rotate', 'ACTIONMOUSE', 'PRESS', key_modifier=keyModifierRotation)
        kmi = km.keymap_items.new('view3d.move', 'ACTIONMOUSE', 'PRESS', key_modifier=keyModifierMovePan)
        kmi = km.keymap_items.new('view3d.zoom', 'ACTIONMOUSE', 'PRESS', key_modifier=keyModifierZoom)
    
        # Vertex Paint
        km = wm.keyconfigs.addon.keymaps.new(name='Vertex Paint', space_type='EMPTY', region_type='WINDOW')
        kmi = km.keymap_items.new('view3d.rotate', 'ACTIONMOUSE', 'PRESS', key_modifier=keyModifierRotation)
        kmi = km.keymap_items.new('view3d.move', 'ACTIONMOUSE', 'PRESS', key_modifier=keyModifierMovePan)
        kmi = km.keymap_items.new('view3d.zoom', 'ACTIONMOUSE', 'PRESS', key_modifier=keyModifierZoom)
    
        # Weight Paint
        km = wm.keyconfigs.addon.keymaps.new(name='Weight Paint', space_type='EMPTY', region_type='WINDOW')
        kmi = km.keymap_items.new('view3d.rotate', 'ACTIONMOUSE', 'PRESS', key_modifier=keyModifierRotation)
        kmi = km.keymap_items.new('view3d.move', 'ACTIONMOUSE', 'PRESS', key_modifier=keyModifierMovePan)
        kmi = km.keymap_items.new('view3d.zoom', 'ACTIONMOUSE', 'PRESS', key_modifier=keyModifierZoom)
    
        # Sculpt
        km = wm.keyconfigs.addon.keymaps.new(name='Sculpt', space_type='EMPTY', region_type='WINDOW')
        kmi = km.keymap_items.new('view3d.rotate', 'ACTIONMOUSE', 'PRESS', key_modifier=keyModifierRotation)
        kmi = km.keymap_items.new('view3d.move', 'ACTIONMOUSE', 'PRESS', key_modifier=keyModifierMovePan)
        kmi = km.keymap_items.new('view3d.zoom', 'ACTIONMOUSE', 'PRESS', key_modifier=keyModifierZoom)
    
    
    # Corrections for the above overrides without existing alternatives, plus some alternatives to MMB:
    
    # Node Editor
    km = wm.keyconfigs.addon.keymaps.new(name='Node Editor', space_type='NODE_EDITOR', region_type='WINDOW')
    # The following two items will themselves override some quite pointlessly repetitive selection
    # commands in Node Editor, which have plenty of alternatives, namely selection with SELECTMOUSE
    kmi = km.keymap_items.new('node.backimage_move', 'ACTIONMOUSE', 'PRESS', shift=True, alt=True)
    kmi = km.keymap_items.new('node.backimage_sample', 'ACTIONMOUSE', 'PRESS', shift=True, ctrl=True) # override correction

    # The following mousing keymap items are alternative to existing MMB keymaps for modal commands,
    # but they do not seem to register, although they register correctly on addon reload.
    # They are small features, but if you don't have MMB, you may like to add them to main keymap manually
    
    # Knife Tool - panning the 3D View while using Knife 
    km = wm.keyconfigs.addon.keymaps.new(name='Knife Tool Modal Map', space_type='EMPTY', region_type='WINDOW', modal=True)
    kmi = km.keymap_items.new_modal('PANNING', 'ACTIONMOUSE', 'PRESS', alt=True)

    # View3D Fly Modal - panning the 3D View in Fly Mode
    km = wm.keyconfigs.addon.keymaps.new(name='View3D Fly Modal', space_type='EMPTY', region_type='WINDOW', modal=True)
    kmi = km.keymap_items.new_modal('PAN_DISABLE', 'ACTIONMOUSE', 'RELEASE', alt=True)
    kmi = km.keymap_items.new_modal('PAN_ENABLE', 'ACTIONMOUSE', 'PRESS', alt=True)

    # Gesture Zoom Border - drawing rectangle border for zooming out in 3D View
    km = wm.keyconfigs.addon.keymaps.new(name='Gesture Zoom Border', space_type='EMPTY', region_type='WINDOW', modal=True)
    kmi = km.keymap_items.new_modal('OUT', 'ACTIONMOUSE', 'RELEASE', alt=True)
    kmi = km.keymap_items.new_modal('BEGIN', 'ACTIONMOUSE', 'PRESS', alt=True)
    
    # File Browser
    km = wm.keyconfigs.addon.keymaps.new(name='File Browser Main', space_type='FILE_BROWSER', region_type='WINDOW')
    kmi = km.keymap_items.new('file.select', 'RIGHTMOUSE', 'CLICK', shift=True, alt=True) # override correction
    kmi.properties['extend'] = 1
    kmi.properties['fill'] = 1

    addon_keymaps.append((km, kmi))
    
def unregister():

    for km, kmi in addon_keymaps:
        km.keymap_items.remove(kmi)
    addon_keymaps.clear()

if __name__ == '__main__':
    register()

2 comments:

  1. Great, this is just what I needed.
    I don"t know what happened, but my MMB stopped working yesterday, so I had no way to rotate view in blender without changing the RMB as my select button, which didn't want to do.
    THANK YOU this will definitely help me. :)

    ReplyDelete
  2. got a laptop - perfect!

    ReplyDelete

Note: Only a member of this blog may post a comment.