├── heavymouse ├── __init__.py ├── __main__.py ├── alternate_heavymouse.py └── heavymouse.py ├── setup.cfg ├── requirements.txt ├── setup.py └── README.md /heavymouse/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /setup.cfg: -------------------------------------------------------------------------------- 1 | [metadata] 2 | description-file = README.md 3 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | pkg-resources==0.0.0 2 | python-xlib==0.17 3 | PyUserInput==0.1.11 4 | six==1.10.0 5 | -------------------------------------------------------------------------------- /heavymouse/__main__.py: -------------------------------------------------------------------------------- 1 | from heavymouse import heavymouse 2 | 3 | if __name__ == '__main__': 4 | heavymouse.run_main() 5 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | from distutils.core import setup 2 | setup( 3 | name = 'heavymouse', 4 | packages = ['heavymouse'], # this must be the same as the name above 5 | version = '1.1', 6 | description = 'Give your mouse some mass', 7 | author = 'Alex PB', 8 | author_email = 'chozabu@gmail.com', 9 | url = 'https://github.com/chozabu/HeavyMouse', # use the URL to the github repo 10 | download_url = 'https://github.com/chozabu/HeavyMouse/tarball/1.1', # I'll explain this in a second 11 | keywords = ['joke', 'fun', 'physics'], # arbitrary keywords 12 | install_requires=['python-xlib', 'PyUserInput', 'defopt'], 13 | classifiers = [], 14 | ) 15 | -------------------------------------------------------------------------------- /heavymouse/alternate_heavymouse.py: -------------------------------------------------------------------------------- 1 | import pyautogui, sys, time 2 | mx, my = pyautogui.position() 3 | 4 | vx,vy=0,0 5 | 6 | width,height = pyautogui.size() 7 | 8 | print('Press Ctrl-C to quit.') 9 | try: 10 | while True: 11 | x, y = pyautogui.position() 12 | y+=2 13 | vx,vy=x-mx,y-my 14 | mx=x 15 | my=y 16 | #vy-=0.3 17 | x+=vx*.9 18 | y+=vy*.9 19 | 20 | if x < 0: 21 | x+=width 22 | mx+=width 23 | if y < 0: 24 | y+=height 25 | my+=height 26 | if x > width: 27 | x-=width 28 | mx-=width 29 | if y > height: 30 | #y-=height 31 | #my-=height 32 | y-=vy*2 33 | vy=-vy 34 | 35 | pyautogui.moveTo(int(x), int(y), duration=.1)#, pyautogui.easeOutQuad) 36 | positionStr = 'X: ' + str(x).rjust(4) + ' Y: ' + str(y).rjust(4) 37 | #print(positionStr) 38 | #print('\b' * len(positionStr)) 39 | #sys.stdout.flush() 40 | #time.sleep(.2) 41 | except KeyboardInterrupt: 42 | print('\n') 43 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | #HeavyMouse 2 | 3 | This is a silly program, designed to give your mouse momemtum, gravity and wrap/bounce at the screens edge. 4 | 5 | ###Deps: 6 | 7 | sudo apt-get install python3-xlib 8 | #OR 9 | sudo apt-get install python-xlib 10 | 11 | 12 | pip install pyuserinput 13 | 14 | #optional, for CLI options to control drag and gravity 15 | pip install defopt 16 | 17 | 18 | ##Running: 19 | 20 | python heavymouse.py 21 | 22 | grav and drag are supported as args, so you can try: 23 | 24 | python heavymouse.py --grav 1.5 --drag 0.02 #default settings 25 | python heavymouse.py --grav 0 --drag 0.2 #more usable 26 | 27 | 28 | 29 | ###Alternate version 30 | 31 | using pyautogui instead of pymouse/pyinput: 32 | 33 | sudo apt-get install python3-tk 34 | sudo apt-get install python3-xlib 35 | pip3 install pyautogui 36 | 37 | python3 alternate_heavymouse.py 38 | 39 | Sorry about the low update-rate (jerkyness) on pyautogui version - a PR to fix it would be very welcome ;) 40 | 41 | ##Development 42 | 43 | This is a tiny toy app developed for my own enjoyment - and hopefully yours too. 44 | There are loads of tweaks that could be done if you fancy writing a little code 45 | 46 | - options for effect at screen edges (bounce/wrap/other) 47 | - options to control other features 48 | - auto-detect mouse control backend? 49 | - package for pypi or debian? 50 | - improve momentum implementation (strangeness, due to mouse position being an int) 51 | - visual effects? like a trail following the mouse (this may be hard to do cross platform, but even single platform is fine if it fails gracefully) 52 | -------------------------------------------------------------------------------- /heavymouse/heavymouse.py: -------------------------------------------------------------------------------- 1 | import sys, time, math 2 | from pymouse import PyMouse 3 | 4 | try: 5 | import defopt 6 | except ImportError: 7 | print("could not import defopt, command line options will not work") 8 | print("try 'pip install defopt'") 9 | 10 | ''' 11 | 12 | ___ 13 | _ _ .-' '-. 14 | (.)(.)/ \ jgs (art from http://www.ascii-code.com/ascii-art/animals/rodents/mice.php) 15 | /@@ ; 16 | o_\\-mm-......-mm`~~~~~~~~~~~~~~~~` 17 | ''' 18 | 19 | def main(drag=0.02, grav=1.5, bottom='bounce', left='bounce', right='bounce', top='bounce', allsides=None, maxspeed=40, framerate=50): 20 | """HeavyMouse - a python mouse mover\n 21 | 22 | example, for bouncy walls, no gravity and less speed: \n 23 | python heavymouse.py --drag .04 --grav 0 --allsides bounce --maxspeed 10 24 | 25 | :param float drag: amount of drag. 0.0 to 1.0, default is 0.02 26 | :param float grav: gravity, default is 1.5 27 | :param str bottom: can be 'bounce', 'wrap' or 'stop' - default is bounce 28 | :param str left: can be 'bounce', 'wrap' or 'stop' - default is bounce 29 | :param str right: can be 'bounce', 'wrap' or 'stop' - default is bounce 30 | :param str top: can be 'bounce', 'wrap' or 'stop' - default is bounce 31 | :param str allsides: will override settings for each side - no default 32 | :param int maxspeed: prevent the mouse moving (much) faster than this each frame - default is 40 33 | :param int framerate: frequency the program operates at - default is 50 34 | 35 | """ 36 | friction = 1.0-drag 37 | 38 | sleeptime = 1000.0/framerate/1000.0 39 | 40 | if allsides: 41 | top=right=left=bottom=allsides 42 | print(top, bottom) 43 | 44 | 45 | m = PyMouse() 46 | 47 | mx, my = m.position() 48 | mx,my=float(mx), float(my) 49 | 50 | vx,vy=.0,.0 51 | 52 | width,height = m.screen_size() 53 | 54 | print('Press Ctrl-C to quit.') 55 | try: 56 | while True: 57 | #get current position 58 | x, y = m.position() 59 | x,y=float(x), float(y) 60 | 61 | #alter vel by user input 62 | vx += float(x-mx)-vx+.5 63 | vy += float(y-my)-vy+.5 64 | 65 | #drag 66 | vx*=friction 67 | vy*=friction 68 | 69 | #gravity 70 | vy+=grav 71 | 72 | vel = (math.sqrt(vx**2+vy**2)) 73 | if vel > maxspeed: 74 | vx*=.7 75 | vy*=.7 76 | 77 | #update current and previous position 78 | mx=x 79 | my=y 80 | x+=vx 81 | y+=vy 82 | 83 | #wrap or bounce at screen edges 84 | if x < 0: 85 | if left == 'wrap': 86 | x+=width 87 | mx+=width 88 | elif left == 'bounce': 89 | x-=vx*2 90 | xy=-vx 91 | else: #stop 92 | x=0 93 | 94 | if y < 0: 95 | if top == 'wrap': 96 | y+=height 97 | my+=height 98 | elif top == 'bounce': 99 | y-=vy*2 100 | vy=-vy 101 | else: #stop 102 | y=0 103 | 104 | if x > width: 105 | if right == 'wrap': 106 | x-=width 107 | mx-=width 108 | elif right == 'bounce': 109 | x-=vx*2 110 | xy=-vx 111 | else: #stop 112 | x=width 113 | 114 | if y > height: 115 | if bottom == 'wrap': 116 | y-=height 117 | my-=height 118 | elif bottom == 'bounce': 119 | y-=vy*2 120 | vy=-vy 121 | else: #stop 122 | y=height 123 | 124 | #apply position to mouse 125 | m.move(int(x), int(y)) 126 | 127 | #debug output 128 | #positionStr = 'X: ' + str(x).rjust(4) + ' Y: ' + str(y).rjust(4) 129 | #print(positionStr) 130 | #print(vx, vy) 131 | #print('\b' * len(positionStr)) 132 | #sys.stdout.flush() 133 | 134 | time.sleep(sleeptime) 135 | except KeyboardInterrupt: 136 | print('\n') 137 | 138 | def run_main(): 139 | try: 140 | defopt.run(main) 141 | except NameError: 142 | main() 143 | 144 | 145 | if __name__ == '__main__': 146 | run_main() 147 | --------------------------------------------------------------------------------