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()