<gh_stars>0
############################################################################
#
# DIM - A Direct Interaction Manager for SAGE
# Copyright (C) 2007 Electronic Visualization Laboratory,
# University of Illinois at Chicago
#
# All rights reserved.
# 
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
# 
#  * Redistributions of source code must retain the above copyright
#    notice, this list of conditions and the following disclaimer.
#  * Redistributions in binary form must reproduce the above
#    copyright notice, this list of conditions and the following disclaimer
#    in the documentation and/or other materials provided with the distribution.
#  * Neither the name of the University of Illinois at Chicago nor
#    the names of its contributors may be used to endorse or promote
#    products derived from this software without specific prior written permission.
# 
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
# Direct questions, comments etc about SAGE UI to www.evl.uic.edu/cavern/forum
#
# Author: <NAME>
#        
############################################################################





#### joysticks

from managerConn import ManagerConnection
import wx, time, sys


#DEVICE_TYPE = "joystick"   # a plugin for this type must exist in "devices" called puck.py

# types of messages sent to the manager
MOVE = "1"
BUTTON = "2"
ARROW = "3"


class Joystick:
    def __init__(self, joyId, manager):
        self.joy = wx.Joystick(joyId)

        self.dontUse = False  # dont report this device
        if self.joy.GetProductName().startswith('Nintendo'):
            self.dontUse = True
            
        self.isFake = self.joy.GetProductName().startswith('PPJoy')
        self.isWiimote = False
        
        if self.isFake:
            # determine if it's a wii (PPJoy >= 13 is a wii)
            self.isWiimote = int(self.joy.GetProductName().lstrip("PPJoy Virtual joystick ")) > 12
            if self.isWiimote:
                self.joyId = "joystick"+str(joyId)+"_wiimote"
            else:
                self.joyId = "joystick"+str(joyId)+"_fake"
        else:
            self.joyId = "joystick"+str(joyId)+"_real"

        self.manager = manager
        self.xAxis, self.yAxis, self.prevX, self.prevY = 0,0,0,0
        self.buttons = [False, False, False]
        self.pov = -1

        # for dealing with drift
        xmin = self.joy.GetXMin()
        xmax = self.joy.GetXMax()
        self.__range = abs(xmax - xmin)
        self.__center = abs((xmin + xmax)/2.0) #so that 0 <-> max and -max/2 <-> max/2 both work
        self.drift = 0.1 # maximum of 10% drift accounted for
        if self.isFake: self.drift = 0.001
        self.usefulRange = 1 - self.drift


    def checkAxis(self):
        (self.xAxis, self.yAxis) = self.joy.GetPosition()
        self.__normalize()
        self.__accountForDrift()
            
        # report if there has been change
        if (not self.isWiimote and (self.xAxis != 0 or self.yAxis != 0)) or \
               (self.isWiimote and (self.xAxis != self.prevX or self.yAxis != self.prevY)):
            msg = MOVE +" "+str(self.xAxis)+" "+str(self.yAxis)
            self.manager.sendMessage(self.joyId, "joystick", msg)

        self.prevX, self.prevY = self.xAxis, self.yAxis   # remember for next time


    def checkButtons(self):
        bits = self.joy.GetButtonState()
        buttons = [bits & 1 == 1, bits & 2 == 2, bits & 4 == 4]
        for i in range(0,3):
            if self.buttons[i] != buttons[i]:
                self.buttons[i] = buttons[i]
                msg = BUTTON+" "+str(i+1)+" "+str(int(buttons[i]))
                self.manager.sendMessage(self.joyId, "joystick", msg)


    def checkArrow(self):
        pov = self.joy.GetPOVPosition()
        if self.pov != pov:
            self.pov = pov
            if pov < 65000:  # ie NOT center
                msg = ARROW+" "+str(pov)
                self.manager.sendMessage(self.joyId, "joystick", msg)
            


    def __normalize(self):
        """ map any type of coords to normalized coords in range -1 to 1 """
        self.xAxis = ((self.xAxis - self.__center) / (self.__range/2.0))
        self.yAxis = ((self.yAxis - self.__center) / (self.__range/2.0))
                        
        
    def __accountForDrift(self):
        x = self.xAxis
        y = self.yAxis
        
        # apply the movement threshold and get the normalized crds
        if abs(x) <= self.drift:
            x = 0
        else:
            if x > 0:  x = float(x-self.drift)/self.usefulRange
            else: x = float(x+self.drift)/self.usefulRange

        if abs(y) <= self.drift:
            y = 0
        else:
            if y > 0:  y = float(y-self.drift)/self.usefulRange
            else: y = float(y+self.drift)/self.usefulRange

        self.xAxis = x
        self.yAxis = y

            

class CaptureJoysticks:
    
    def __init__(self, manager):
        self.manager = manager
        self.app = wx.App(redirect=False)
        self.numJoy = wx.Joystick().GetNumberJoysticks()
        if self.numJoy > 0:
            self.createJoysticks()
            self.capture()
        else:
            print "No joysticks connected..."
            self.manager.quit()

    def createJoysticks(self):
        self.joysticks = []
        for j in range(0,self.numJoy):
            joy = Joystick(j, self.manager)
            if not joy.dontUse:
                self.joysticks.append( joy )
            else:
                del joy
        
    def capture(self):
        while True:
            for j in self.joysticks:
                j.checkButtons()
                j.checkAxis()
                j.checkArrow()
            time.sleep(1.0/40)




# you can optionally pass in a port number of the manager on command line
port = 20005
if len(sys.argv) < 2:
    print "Usage: python "+sys.argv[0]+" sageIP"
    sys.exit(0)
elif len(sys.argv) > 2:
    port = int(sys.argv[2])

# start everything off
CaptureJoysticks( ManagerConnection(sys.argv[1], port) )
    

############################################################################
#
# DIM - A Direct Interaction Manager for SAGE
# Copyright (C) 2007 Electronic Visualization Laboratory,
# University of Illinois at Chicago
#
# All rights reserved.
# 
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
# 
#  * Redistributions of source code must retain the above copyright
#    notice, this list of conditions and the following disclaimer.
#  * Redistributions in binary form must reproduce the above
#    copyright notice, this list of conditions and the following disclaimer
#    in the documentation and/or other materials provided with the distribution.
#  * Neither the name of the University of Illinois at Chicago nor
#    the names of its contributors may be used to endorse or promote
#    products derived from this software without specific prior written permission.
# 
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
# Direct questions, comments etc about SAGE UI to www.evl.uic.edu/cavern/forum
#
# Author: <NAME>
#        
############################################################################





#### joysticks

from managerConn import ManagerConnection
import wx, time, sys


#DEVICE_TYPE = "joystick"   # a plugin for this type must exist in "devices" called puck.py

# types of messages sent to the manager
MOVE = "1"
BUTTON = "2"
ARROW = "3"


class Joystick:
    def __init__(self, joyId, manager):
        self.joy = wx.Joystick(joyId)

        self.dontUse = False  # dont report this device
        if self.joy.GetProductName().startswith('Nintendo'):
            self.dontUse = True
            
        self.isFake = self.joy.GetProductName().startswith('PPJoy')
        self.isWiimote = False
        
        if self.isFake:
            # determine if it's a wii (PPJoy >= 13 is a wii)
            self.isWiimote = int(self.joy.GetProductName().lstrip("PPJoy Virtual joystick ")) > 12
            if self.isWiimote:
                self.joyId = "joystick"+str(joyId)+"_wiimote"
            else:
                self.joyId = "joystick"+str(joyId)+"_fake"
        else:
            self.joyId = "joystick"+str(joyId)+"_real"

        self.manager = manager
        self.xAxis, self.yAxis, self.prevX, self.prevY = 0,0,0,0
        self.buttons = [False, False, False]
        self.pov = -1

        # for dealing with drift
        xmin = self.joy.GetXMin()
        xmax = self.joy.GetXMax()
        self.__range = abs(xmax - xmin)
        self.__center = abs((xmin + xmax)/2.0) #so that 0 <-> max and -max/2 <-> max/2 both work
        self.drift = 0.1 # maximum of 10% drift accounted for
        if self.isFake: self.drift = 0.001
        self.usefulRange = 1 - self.drift


    def checkAxis(self):
        (self.xAxis, self.yAxis) = self.joy.GetPosition()
        self.__normalize()
        self.__accountForDrift()
            
        # report if there has been change
        if (not self.isWiimote and (self.xAxis != 0 or self.yAxis != 0)) or \
               (self.isWiimote and (self.xAxis != self.prevX or self.yAxis != self.prevY)):
            msg = MOVE +" "+str(self.xAxis)+" "+str(self.yAxis)
            self.manager.sendMessage(self.joyId, "joystick", msg)

        self.prevX, self.prevY = self.xAxis, self.yAxis   # remember for next time


    def checkButtons(self):
        bits = self.joy.GetButtonState()
        buttons = [bits & 1 == 1, bits & 2 == 2, bits & 4 == 4]
        for i in range(0,3):
            if self.buttons[i] != buttons[i]:
                self.buttons[i] = buttons[i]
                msg = BUTTON+" "+str(i+1)+" "+str(int(buttons[i]))
                self.manager.sendMessage(self.joyId, "joystick", msg)


    def checkArrow(self):
        pov = self.joy.GetPOVPosition()
        if self.pov != pov:
            self.pov = pov
            if pov < 65000:  # ie NOT center
                msg = ARROW+" "+str(pov)
                self.manager.sendMessage(self.joyId, "joystick", msg)
            


    def __normalize(self):
        """ map any type of coords to normalized coords in range -1 to 1 """
        self.xAxis = ((self.xAxis - self.__center) / (self.__range/2.0))
        self.yAxis = ((self.yAxis - self.__center) / (self.__range/2.0))
                        
        
    def __accountForDrift(self):
        x = self.xAxis
        y = self.yAxis
        
        # apply the movement threshold and get the normalized crds
        if abs(x) <= self.drift:
            x = 0
        else:
            if x > 0:  x = float(x-self.drift)/self.usefulRange
            else: x = float(x+self.drift)/self.usefulRange

        if abs(y) <= self.drift:
            y = 0
        else:
            if y > 0:  y = float(y-self.drift)/self.usefulRange
            else: y = float(y+self.drift)/self.usefulRange

        self.xAxis = x
        self.yAxis = y

            

class CaptureJoysticks:
    
    def __init__(self, manager):
        self.manager = manager
        self.app = wx.App(redirect=False)
        self.numJoy = wx.Joystick().GetNumberJoysticks()
        if self.numJoy > 0:
            self.createJoysticks()
            self.capture()
        else:
            print "No joysticks connected..."
            self.manager.quit()

    def createJoysticks(self):
        self.joysticks = []
        for j in range(0,self.numJoy):
            joy = Joystick(j, self.manager)
            if not joy.dontUse:
                self.joysticks.append( joy )
            else:
                del joy
        
    def capture(self):
        while True:
            for j in self.joysticks:
                j.checkButtons()
                j.checkAxis()
                j.checkArrow()
            time.sleep(1.0/40)




# you can optionally pass in a port number of the manager on command line
port = 20005
if len(sys.argv) < 2:
    print "Usage: python "+sys.argv[0]+" sageIP"
    sys.exit(0)
elif len(sys.argv) > 2:
    port = int(sys.argv[2])

# start everything off
CaptureJoysticks( ManagerConnection(sys.argv[1], port) )
############################################################################ # # DIM - A Direct Interaction Manager for SAGE # Copyright (C) 2007 Electronic Visualization Laboratory, # University of Illinois at Chicago # # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are met: # #  * Redistributions of source code must retain the above copyright #    notice, this list of conditions and the following disclaimer. #  * Redistributions in binary form must reproduce the above #    copyright notice, this list of conditions and the following disclaimer #    in the documentation and/or other materials provided with the distribution. #  * Neither the name of the University of Illinois at Chicago nor #    the names of its contributors may be used to endorse or promote #    products derived from this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR # CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, # EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, # PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR # PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF # LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING # NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # # Direct questions, comments etc about SAGE UI to www.evl.uic.edu/cavern/forum # # Author: <NAME> # ############################################################################ #### joysticks #DEVICE_TYPE = "joystick"   # a plugin for this type must exist in "devices" called puck.py # types of messages sent to the manager # dont report this device # determine if it's a wii (PPJoy >= 13 is a wii) # for dealing with drift #so that 0 <-> max and -max/2 <-> max/2 both work # maximum of 10% drift accounted for # report if there has been change # remember for next time # ie NOT center map any type of coords to normalized coords in range -1 to 1 # apply the movement threshold and get the normalized crds # you can optionally pass in a port number of the manager on command line # start everything off