00001 
00002 '''
00003 Virtual Joystick from Keyboard
00004 Bharat Tak
00005 September 2016
00006 '''
00007 
00008 import uinput, time
00009 import pygame, sys, os
00010 from pygame.locals import *
00011 
00012 pygame.init()
00013 BLACK = (0,0,0)
00014 WIDTH = 335
00015 HEIGHT = 406
00016 windowSurface = pygame.display.set_mode((WIDTH, HEIGHT), 0, 32)
00017 windowSurface.fill(BLACK)
00018 pygame.display.set_caption('Virtual RC Joystick')
00019 
00020 
00021 background = pygame.Surface(windowSurface.get_size())
00022 background = background.convert()
00023 background.fill((250, 250, 250))
00024 
00025 
00026 dir = os.path.dirname(__file__)
00027 filename = os.path.join(dir, '../media/sticks.png')
00028 img = pygame.image.load(filename)
00029 
00030 windowSurface.blit(img,(0,0))
00031 pygame.display.flip()
00032 
00033 class stick_state(object):
00034     def __init__(self, name, stick, key_up, key_down, spring_back=True, incr_val=0.2):
00035         self.name = name                            
00036         self.stick = stick                          
00037         self.key_up = key_up                        
00038         self.key_down = key_down                    
00039         self.spring_back = spring_back              
00040         self.incr_val = incr_val                    
00041         self.min_val = 0.0                          
00042         self.max_val = 255.0                        
00043         self.active_up = False                      
00044         self.active_down = False                    
00045         if self.spring_back:
00046             self.zero = 127.0
00047         else:
00048             self.zero = 0.0
00049         self.val = self.zero                        
00050         self.emit_val = int(self.val)
00051         self.display_ready = False                  
00052         self.display_height = 0                     
00053         self.display_width = 0                      
00054         self.display_hor = True                     
00055         self.display_bar_g = []
00056         self.display_bar_b = []
00057 
00058     def keypress_up(self):
00059         self.active_up = True
00060         if (self.val + self.incr_val) <= self.max_val:
00061             self.val = self.val + self.incr_val
00062         else:
00063             
00064             self.val = self.max_val
00065 
00066     def keypress_down(self):
00067         self.active_down = True
00068         if (self.val - self.incr_val) >= self.min_val:
00069             self.val = self.val - self.incr_val
00070         else:
00071             
00072             self.val = self.min_val
00073 
00074     def release_stick(self):
00075         if not self.spring_back:
00076             pass
00077         else:
00078             if self.val > self.zero:
00079                 self.val = self.val - self.incr_val*0.2
00080             elif self.val < self.zero:
00081                 self.val = self.val + self.incr_val*0.2
00082             else:
00083                 self.val = self.zero
00084 
00085     def emit(self, device):
00086         
00087         if abs(int(round(self.val)) - int(self.emit_val)) > 0.001:
00088             self.emit_val = int(round(self.val))
00089             device.emit(self.stick, int(self.emit_val), syn=False)
00090             if self.display_ready:
00091                 self.display()
00092 
00093     def set_display(self, offset_height, offset_width, horizontal):
00094         self.display_height = offset_height
00095         self.display_width = offset_width
00096         self.display_hor = horizontal
00097         if horizontal:
00098             filename = os.path.join(dir, '../media/hg.png')
00099             self.display_bar_g = pygame.image.load(filename)
00100             filename = os.path.join(dir, '../media/hb.png')
00101             self.display_bar_b = pygame.image.load(filename)
00102         else:
00103             filename = os.path.join(dir, '../media/vg.png')
00104             self.display_bar_g = pygame.image.load(filename)
00105             filename = os.path.join(dir, '../media/vb.png')
00106             self.display_bar_b = pygame.image.load(filename)    
00107         self.display_ready = True
00108 
00109     def display(self):
00110         if not self.display_ready:
00111             pass
00112         else:
00113             
00114             for i in range(256):
00115                 if i <= self.emit_val:
00116                     
00117                     if self.display_hor:
00118                         windowSurface.blit(self.display_bar_g,(self.display_width + i, self.display_height))
00119                     else:
00120                         windowSurface.blit(self.display_bar_g,(self.display_width, self.display_height - i))
00121                 else:
00122                     
00123                     if self.display_hor:
00124                         windowSurface.blit(self.display_bar_b,(self.display_width + i, self.display_height))
00125                     else:
00126                         windowSurface.blit(self.display_bar_b,(self.display_width, self.display_height - i))
00127             
00128             pygame.display.flip()
00129 
00130     def update_event(self, event):
00131         if event.type == KEYUP:
00132             if (event.key == self.key_up):
00133                 self.active_up = False
00134             elif event.key == self.key_down:
00135                 self.active_down = False
00136         elif event.type == KEYDOWN:
00137             if (event.key == self.key_up):
00138                 self.active = True
00139                 self.keypress_up()
00140             elif (event.key == self.key_down):
00141                 self.active = True
00142                 self.keypress_down()
00143 
00144     def update_stick(self, device):
00145         if self.active_up:
00146             self.keypress_up()
00147             self.emit(device)
00148         elif self.active_down:
00149             self.keypress_down()
00150             self.emit(device)
00151         else:
00152             self.release_stick()
00153             self.emit(device)
00154 
00155 def main():
00156     events = (
00157         uinput.BTN_JOYSTICK,
00158         uinput.ABS_X + (0, 255, 0, 0),
00159         uinput.ABS_Y + (0, 255, 0, 0),
00160         uinput.ABS_THROTTLE + (0, 255, 0, 0),
00161         uinput.ABS_RUDDER + (0, 255, 0, 0),
00162         )
00163 
00164     sticks = []
00165 
00166     
00167     roll_stick = stick_state('Roll', uinput.ABS_X, K_RIGHT, K_LEFT)
00168     roll_stick.set_display(21, 39, True)
00169     sticks.append(roll_stick)
00170     pitch_stick = stick_state('Pitch', uinput.ABS_Y, K_UP, K_DOWN)
00171     pitch_stick.set_display(328, 198, False)
00172     sticks.append(pitch_stick)
00173     thr_stick = stick_state('Throttle', uinput.ABS_THROTTLE, K_w, K_s, False)
00174     thr_stick.set_display(328, 95, False)
00175     sticks.append(thr_stick)
00176     rud_stick = stick_state('Yaw', uinput.ABS_RUDDER, K_d, K_a)
00177     rud_stick.set_display(360, 39, True)
00178     sticks.append(rud_stick)
00179 
00180     with uinput.Device(events) as device:
00181         while True:
00182             
00183             for event in pygame.event.get():
00184                 for stick in sticks:
00185                     stick.update_event(event)
00186             for stick in sticks:
00187                     stick.update_stick(device)
00188             time.sleep(0.0005)
00189 
00190 if __name__ == "__main__":
00191     main()