Method 1: bl_options
bl_options = {'GRAB_CURSOR', 'BLOCKING'}
Method 2: cursor_warp
You can know the total travel from the cube offset
import bpy
from bpy.props import IntProperty, FloatProperty
class ModalOperator(bpy.types.Operator):
"""Move an object with the mouse, example"""
bl_idname = "object.modal_operator"
bl_label = "Simple Modal Operator"
last_mouse_x: IntProperty()
first_value: FloatProperty()
def modal(self, context, event):
if event.type == 'MOUSEMOVE':
x = event.mouse_x
delta = x - self.last_mouse_x
if abs(delta) > self.w_half:
delta = 0
print(delta)
context.object.location.x += delta * 0.002
# wrap cursor x only
if x < 200:
x = self.w_width - 20
self.cursor_warp(x, event.mouse_y)
elif x > self.w_width:
x = 220
self.cursor_warp(x, event.mouse_y)
self.last_mouse_x = x
elif event.type == 'LEFTMOUSE':
return {'FINISHED'}
elif event.type in {'RIGHTMOUSE', 'ESC'}:
context.object.location.x = self.first_value
return {'CANCELLED'}
return {'RUNNING_MODAL'}
def invoke(self, context, event):
if context.object:
self.last_mouse_x = event.mouse_x
self.first_value = context.object.location.x
# get window height, width
window = context.window
self.w_width = window.width - 200
self.w_half = self.w_width // 2
self.cursor_warp = context.window.cursor_warp
context.window_manager.modal_handler_add(self)
return {'RUNNING_MODAL'}
else:
self.report({'WARNING'}, "No active object, could not finish")
return {'CANCELLED'}
def register():
bpy.utils.register_class(ModalOperator)
def unregister():
bpy.utils.unregister_class(ModalOperator)
if __name__ == "__main__":
register()
# test call
bpy.ops.object.modal_operator('INVOKE_DEFAULT')