Open a 3D space navigator device. Makes this device the current active device, which enables the module-level read() and close()
    calls. For multiple devices, use the read() and close() calls on the returned object instead, and don't use the module-level calls.
    
    Parameters:        
        callback: If callback is provided, it is called on each HID update with a copy of the current state namedtuple  
        button_callback: If button_callback is provided, it is called on each button push, with the arguments (state_tuple, button_state) 
        device: name of device to open. Must be one of the values in supported_devices. If None, chooses the first supported device found.
    Returns:
        Device object if the device was opened successfully
        None if the device could not be opened

def open(callback=None, button_callback=None, device=None):
    """
    Open a 3D space navigator device. Makes this device the current active device, which enables the module-level read() and close()
    calls. For multiple devices, use the read() and close() calls on the returned object instead, and don't use the module-level calls.
    
    Parameters:        
        callback: If callback is provided, it is called on each HID update with a copy of the current state namedtuple  
        button_callback: If button_callback is provided, it is called on each button push, with the arguments (state_tuple, button_state) 
        device: name of device to open. Must be one of the values in supported_devices. If None, chooses the first supported device found.
    Returns:
        Device object if the device was opened successfully
        None if the device could not be opened
    """
    # only used if the module-level functions are used
    global _active_device
    
    # if no device name specified, look for any matching device and choose the first
    if device==None:
        all_devices = list_devices()
        if len(all_devices)>0:
            device = all_devices[0]
        else:
            return None
        
    all_hids = hid.find_all_hid_devices()
    if all_hids:
        for index, dev in enumerate(all_hids):
                spec = device_specs[device]
                if dev.vendor_id == spec.hid_id[0] and dev.product_id == spec.hid_id[1]:
                    print("%s found" % device)
                    # create a copy of the device specification
                    new_device = copy.deepcopy(spec)
                    new_device.device = dev
                    # copy in product details
                    new_device.product_name = dev.product_name
                    new_device.vendor_name = dev.vendor_name
                    new_device.version_number = dev.version_number
                    # doesn't seem to work on 3dconnexion devices...
                    new_device.serial_number = dev.serial_number                                 
                    # set the callbacks
                    new_device.callback = callback
                    new_device.button_callback = button_callback
                    # open the device and set the data handler
                    new_device.open()                    
                    dev.set_raw_data_handler(lambda x:new_device.process(x))   
                    _active_device = new_device
                    return new_device
        print("No supported devices found")
        return None
    else:
        print("No HID devices detected")
        return None