source: trunk/src/testing/dim/hwcapture/joystick.py @ 4

Revision 4, 6.7 KB checked in by ajaworski, 13 years ago (diff)

Added modified SAGE sources

Line 
1############################################################################
2#
3# DIM - A Direct Interaction Manager for SAGE
4# Copyright (C) 2007 Electronic Visualization Laboratory,
5# University of Illinois at Chicago
6#
7# All rights reserved.
8#
9# Redistribution and use in source and binary forms, with or without
10# modification, are permitted provided that the following conditions are met:
11#
12#  * Redistributions of source code must retain the above copyright
13#    notice, this list of conditions and the following disclaimer.
14#  * Redistributions in binary form must reproduce the above
15#    copyright notice, this list of conditions and the following disclaimer
16#    in the documentation and/or other materials provided with the distribution.
17#  * Neither the name of the University of Illinois at Chicago nor
18#    the names of its contributors may be used to endorse or promote
19#    products derived from this software without specific prior written permission.
20#
21# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
25# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
26# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
27# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
28# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
29# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
30# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
31# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32#
33# Direct questions, comments etc about SAGE UI to www.evl.uic.edu/cavern/forum
34#
35# Author: Ratko Jagodic
36#       
37############################################################################
38
39
40
41
42
43#### joysticks
44
45from managerConn import ManagerConnection
46import wx, time, sys
47
48
49#DEVICE_TYPE = "joystick"   # a plugin for this type must exist in "devices" called puck.py
50
51# types of messages sent to the manager
52MOVE = "1"
53BUTTON = "2"
54ARROW = "3"
55
56
57class Joystick:
58    def __init__(self, joyId, manager):
59        self.joy = wx.Joystick(joyId)
60
61        self.dontUse = False  # dont report this device
62        if self.joy.GetProductName().startswith('Nintendo'):
63            self.dontUse = True
64           
65        self.isFake = self.joy.GetProductName().startswith('PPJoy')
66        self.isWiimote = False
67       
68        if self.isFake:
69            # determine if it's a wii (PPJoy >= 13 is a wii)
70            self.isWiimote = int(self.joy.GetProductName().lstrip("PPJoy Virtual joystick ")) > 12
71            if self.isWiimote:
72                self.joyId = "joystick"+str(joyId)+"_wiimote"
73            else:
74                self.joyId = "joystick"+str(joyId)+"_fake"
75        else:
76            self.joyId = "joystick"+str(joyId)+"_real"
77
78        self.manager = manager
79        self.xAxis, self.yAxis, self.prevX, self.prevY = 0,0,0,0
80        self.buttons = [False, False, False]
81        self.pov = -1
82
83        # for dealing with drift
84        xmin = self.joy.GetXMin()
85        xmax = self.joy.GetXMax()
86        self.__range = abs(xmax - xmin)
87        self.__center = abs((xmin + xmax)/2.0) #so that 0 <-> max and -max/2 <-> max/2 both work
88        self.drift = 0.1 # maximum of 10% drift accounted for
89        if self.isFake: self.drift = 0.001
90        self.usefulRange = 1 - self.drift
91
92
93    def checkAxis(self):
94        (self.xAxis, self.yAxis) = self.joy.GetPosition()
95        self.__normalize()
96        self.__accountForDrift()
97           
98        # report if there has been change
99        if (not self.isWiimote and (self.xAxis != 0 or self.yAxis != 0)) or \
100               (self.isWiimote and (self.xAxis != self.prevX or self.yAxis != self.prevY)):
101            msg = MOVE +" "+str(self.xAxis)+" "+str(self.yAxis)
102            self.manager.sendMessage(self.joyId, "joystick", msg)
103
104        self.prevX, self.prevY = self.xAxis, self.yAxis   # remember for next time
105
106
107    def checkButtons(self):
108        bits = self.joy.GetButtonState()
109        buttons = [bits & 1 == 1, bits & 2 == 2, bits & 4 == 4]
110        for i in range(0,3):
111            if self.buttons[i] != buttons[i]:
112                self.buttons[i] = buttons[i]
113                msg = BUTTON+" "+str(i+1)+" "+str(int(buttons[i]))
114                self.manager.sendMessage(self.joyId, "joystick", msg)
115
116
117    def checkArrow(self):
118        pov = self.joy.GetPOVPosition()
119        if self.pov != pov:
120            self.pov = pov
121            if pov < 65000:  # ie NOT center
122                msg = ARROW+" "+str(pov)
123                self.manager.sendMessage(self.joyId, "joystick", msg)
124           
125
126
127    def __normalize(self):
128        """ map any type of coords to normalized coords in range -1 to 1 """
129        self.xAxis = ((self.xAxis - self.__center) / (self.__range/2.0))
130        self.yAxis = ((self.yAxis - self.__center) / (self.__range/2.0))
131                       
132       
133    def __accountForDrift(self):
134        x = self.xAxis
135        y = self.yAxis
136       
137        # apply the movement threshold and get the normalized crds
138        if abs(x) <= self.drift:
139            x = 0
140        else:
141            if x > 0:  x = float(x-self.drift)/self.usefulRange
142            else: x = float(x+self.drift)/self.usefulRange
143
144        if abs(y) <= self.drift:
145            y = 0
146        else:
147            if y > 0:  y = float(y-self.drift)/self.usefulRange
148            else: y = float(y+self.drift)/self.usefulRange
149
150        self.xAxis = x
151        self.yAxis = y
152
153           
154
155class CaptureJoysticks:
156   
157    def __init__(self, manager):
158        self.manager = manager
159        self.app = wx.App(redirect=False)
160        self.numJoy = wx.Joystick().GetNumberJoysticks()
161        if self.numJoy > 0:
162            self.createJoysticks()
163            self.capture()
164        else:
165            print "No joysticks connected..."
166            self.manager.quit()
167
168    def createJoysticks(self):
169        self.joysticks = []
170        for j in range(0,self.numJoy):
171            joy = Joystick(j, self.manager)
172            if not joy.dontUse:
173                self.joysticks.append( joy )
174            else:
175                del joy
176       
177    def capture(self):
178        while True:
179            for j in self.joysticks:
180                j.checkButtons()
181                j.checkAxis()
182                j.checkArrow()
183            time.sleep(1.0/40)
184
185
186
187
188# you can optionally pass in a port number of the manager on command line
189port = 20005
190if len(sys.argv) < 2:
191    print "Usage: python "+sys.argv[0]+" sageIP"
192    sys.exit(0)
193elif len(sys.argv) > 2:
194    port = int(sys.argv[2])
195
196# start everything off
197CaptureJoysticks( ManagerConnection(sys.argv[1], port) )
198   
Note: See TracBrowser for help on using the repository browser.