def _moveHand(self, side, t):############# runs inside play() loop
        if side == 1: 
            c1,c2 = 'tomato', 'orange'
            engagedkeys    = self.engagedkeysR
            engagedfingers = self.engagedfingersR
            H              = self.rightHand
            vpH            = self.vpRH
        else:               
            c1,c2 = 'purple', 'mediumpurple'
            engagedkeys    = self.engagedkeysL
            engagedfingers = self.engagedfingersL
            H              = self.leftHand
            vpH            = self.vpLH

        for i, n in enumerate(H.noteseq):##################### 
            start, stop, f = n.time, n.time+n.duration, n.fingering
            if isinstance(f, str): continue
            if f and stop <= t <= stop+self.dt and engagedkeys[i]: #release key
                engagedkeys[i]    = False
                engagedfingers[f] = False
                name = nameof(n)
                krelease(self.KB[name])
                frelease(vpH[f])
                self.vp.interactor.Render()

        for i, n in enumerate(H.noteseq):##################### 
            start, stop, f = n.time, n.time+n.duration, n.fingering   
            if isinstance(f, str):
                print('Warning: cannot understand lyrics:',f, 'skip note',i)
                continue
            if f and start <= t < stop and not engagedkeys[i] and not engagedfingers[f]: #press key
                if i >= len(H.fingerseq): return                    
                engagedkeys[i]    = True
                engagedfingers[f] = True
                name = nameof(n)
                
                if t> self.t0 + self.vp.clock: 
                    self.t0 = t
                    self.vp.show(zoom=2, interactive=True)

                for g in [1,2,3,4,5]: 
                    vpH[g].x( side * H.fingerseq[i][g] ) 
                vpH[0].x(vpH[3].x()) # index 0 is arm, put it where middle finger is
                
                fpress(vpH[f],  c1)
                kpress(self.KB[name], c2)
                self.vp.show(zoom=2, interactive=False)

                if self.verbose:
                    msg = 'meas.'+str(n.measure)+' t='+str(round(t,2))
                    if side==1: printc((msg,'\t\t\t\tRH.finger', f, 'hit', name), 'b')
                    else:       printc((msg,      '\tLH.finger', f, 'hit', name), 'm')

                if self.playsounds: 
                    playSound(n, self.speedfactor)
                else: 
                    time.sleep(n.duration*self.speedfactor)
                        printc(msg, '\tLH.finger', f, 'hit', name, c='m')

                if self.playsounds:
                    playSound(n, self.speedfactor)
                else:
                    time.sleep(n.duration * self.speedfactor)

    ##########################################
    def runTime(self, key):
        secs = [str(i) for i in range(10)]
        if key not in secs: return
        printc('Will execute score for ' + key + ' seconds')
        self.vp.interactive = False
        self.vp.clock = int(key)
        self.vp.interactor.ExitCallback()


############################ test
if __name__ == "__main__":

    vk = VirtualKeyboard('Chopin Valse in A minor')
    vk.build_LH(None)

    fpress(vk.vpLH[1], 'b')
    kpress(vk.KB['E3'], 'db')
    vk.vp.show(zoom=2, interactive=1)

    frelease(vk.vpLH[1])
    krelease(vk.KB['E3'])
    vk.vp.show(zoom=2, interactive=1)