X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/2421eb827857325ff4886131c337391365986d6b..44b8f8e051af41775c9eaeace6a3be139bcbe729:/wxPython/demo/Joystick.py diff --git a/wxPython/demo/Joystick.py b/wxPython/demo/Joystick.py index 03ba8e98c7..394b2ec09f 100644 --- a/wxPython/demo/Joystick.py +++ b/wxPython/demo/Joystick.py @@ -5,7 +5,7 @@ # Author: Jeff Grimmett (grimmtoo@softhome.net), adapted from original # .wdr-derived demo # -# Created: 01/02/04 +# Created: 02-Jan-2004 # RCS-ID: $Id$ # Copyright: # Licence: wxWindows license @@ -15,10 +15,14 @@ import math import wx +haveJoystick = True +if wx.Platform == "__WXMAC__": + haveJoystick = False + #---------------------------------------------------------------------------- -# For convenience -spacer = (10, 10) +# Once all supported versions of Python support 32-bit integers on all +# platforms, this can go up to 32. MAX_BUTTONS = 16 #---------------------------------------------------------------------------- @@ -91,18 +95,18 @@ class JoyGauge(wx.Panel): # Restrict our drawing activities to the square defined # above. - dc.SetClippingRegion((xorigin, yorigin), (edgeSize, edgeSize)) + dc.SetClippingRegion(xorigin, yorigin, edgeSize, edgeSize) # Optimize drawing a bit (for Win) dc.BeginDrawing() dc.SetBrush(wx.Brush(wx.Colour(251, 252, 237))) - dc.DrawRectangle((xorigin, yorigin), (edgeSize, edgeSize)) + dc.DrawRectangle(xorigin, yorigin, edgeSize, edgeSize) dc.SetPen(wx.Pen(wx.BLACK, 1, wx.DOT_DASH)) - dc.DrawLine((xorigin, yorigin + center), (xorigin + edgeSize, yorigin + center)) - dc.DrawLine((xorigin + center, yorigin), (xorigin + center, yorigin + edgeSize)) + dc.DrawLine(xorigin, yorigin + center, xorigin + edgeSize, yorigin + center) + dc.DrawLine(xorigin + center, yorigin, xorigin + center, yorigin + edgeSize) if self.stick: # Get the joystick position as a float @@ -110,8 +114,21 @@ class JoyGauge(wx.Panel): joyy = float(self.stick.GetPosition().y) # Get the joystick range of motion - xrange = self.stick.GetXMax() - self.stick.GetXMin() - yrange = self.stick.GetYMax() - self.stick.GetYMin() + xmin = self.stick.GetXMin() + xmax = self.stick.GetXMax() + if xmin < 0: + xmax += abs(xmin) + joyx += abs(xmin) + xmin = 0 + xrange = max(xmax - xmin, 1) + + ymin = self.stick.GetYMin() + ymax = self.stick.GetYMax() + if ymin < 0: + ymax += abs(ymin) + joyy += abs(ymin) + ymin = 0 + yrange = max(ymax - ymin, 1) # calc a ratio of our range versus the joystick range xratio = float(edgeSize) / xrange @@ -119,7 +136,7 @@ class JoyGauge(wx.Panel): # calc the displayable value based on position times ratio xval = int(joyx * xratio) - yval = int(joyy * xratio) + yval = int(joyy * yratio) # and normalize the value from our brush's origin x = xval + xorigin @@ -127,7 +144,7 @@ class JoyGauge(wx.Panel): # Now to draw it. dc.SetPen(wx.Pen(wx.RED, 2)) - dc.CrossHair((x, y)) + dc.CrossHair(x, y) # Turn off drawing optimization dc.EndDrawing() @@ -235,14 +252,14 @@ class POVGauge(wx.Panel): # our 'raster'. dc.SetBrush(wx.Brush(wx.WHITE)) - dc.DrawCircle((xcenter, ycenter), diameter/2) + dc.DrawCircle(xcenter, ycenter, diameter/2) dc.SetBrush(wx.Brush(wx.BLACK)) - dc.DrawCircle((xcenter, ycenter), 10) + dc.DrawCircle(xcenter, ycenter, 10) # fancy decorations dc.SetPen(wx.Pen(wx.BLACK, 1, wx.DOT_DASH)) - dc.DrawLine((xorigin, ycenter), (xorigin + diameter, ycenter)) - dc.DrawLine((xcenter, yorigin), (xcenter, yorigin + diameter)) + dc.DrawLine(xorigin, ycenter, xorigin + diameter, ycenter) + dc.DrawLine(xcenter, yorigin, xcenter, yorigin + diameter) if self.stick: if self.avail: @@ -280,11 +297,11 @@ class POVGauge(wx.Panel): # Draw the line dc.SetPen(wx.Pen(wx.BLUE, 2)) - dc.DrawLine((xcenter, ycenter), (nx, ny)) + dc.DrawLine(xcenter, ycenter, nx, ny) # And a little thing to show the endpoint dc.SetBrush(wx.Brush(wx.BLUE)) - dc.DrawCircle((nx, ny), 8) + dc.DrawCircle(nx, ny, 8) # Turn off drawing optimization dc.EndDrawing() @@ -458,7 +475,7 @@ class LED(wx.Panel): else: dc.SetBrush(wx.Brush(wx.BLACK)) - dc.DrawCircle((center, center), bw/2) + dc.DrawCircle(center, center, bw/2) txt = str(self.number) @@ -479,7 +496,7 @@ class LED(wx.Panel): # functions. The pseudo-shadow gives the text contrast # regardless of whether the bar is under it or not. dc.SetTextForeground(wx.WHITE) - dc.DrawText(txt, (tx, ty)) + dc.DrawText(txt, tx, ty) # Turn off drawing optimization dc.EndDrawing() @@ -705,10 +722,10 @@ class AxisBar(wx.Gauge): # functions. The pseudo-shadow gives the text contrast # regardless of whether the bar is under it or not. dc.SetTextForeground(wx.BLACK) - dc.DrawText(txt, (tx, ty)) + dc.DrawText(txt, tx, ty) dc.SetTextForeground('white') - dc.DrawText(txt, (tx-1, ty-1)) + dc.DrawText(txt, tx-1, ty-1) #---------------------------------------------------------------------------- @@ -754,10 +771,8 @@ class Axis(wx.Panel): self.GetMax = eval('stick.Get%sMax' % token) # Create our displays and set them up. - self.Min = wx.StaticText(self, -1, str(self.GetMin()), - size=(40,-1), style=wx.ALIGN_RIGHT | wx.ST_NO_AUTORESIZE) - self.Max = wx.StaticText(self, -1, str(self.GetMax()), - size=(40,-1), style=wx.ALIGN_LEFT | wx.ST_NO_AUTORESIZE) + self.Min = wx.StaticText(self, -1, str(self.GetMin()), style=wx.ALIGN_RIGHT) + self.Max = wx.StaticText(self, -1, str(self.GetMax()), style=wx.ALIGN_LEFT) self.bar = AxisBar(self) sizer.Add(self.Min, 0, wx.ALL | wx.ALIGN_RIGHT | wx.ALIGN_CENTER_VERTICAL, 1) @@ -809,20 +824,25 @@ class Axis(wx.Panel): else: val = eval('self.stick.Get%sPosition()' % self.token) + # # While we might be able to rely on a range of 0-FFFFFF on Win, that might # not be true of all drivers on all platforms. Thus, calc the actual full # range first. # + if min < 0: + max += abs(min) + val += abs(min) + min = 0 range = float(max - min) - + # # The relative value is used by the derived wx.Gauge since it is a # positive-only control. # relative = 0 if range: - relative = int(val / range * 1000) + relative = int( val / range * 1000) # # Pass both the raw and relative values to the derived Gauge @@ -937,9 +957,9 @@ class JoystickDemoPanel(wx.Panel): # Capture Joystick events (if they happen) self.Bind(wx.EVT_JOYSTICK_EVENTS, self.OnJoystick) - self.stick.SetMovementThreshold(10) + def Calibrate(self, evt=None): # Do not try this without a stick if not self.stick: @@ -950,6 +970,7 @@ class JoystickDemoPanel(wx.Panel): self.pov.Calibrate() self.buttons.Calibrate() + def OnJoystick(self, evt=None): if not self.stick: return @@ -957,20 +978,127 @@ class JoystickDemoPanel(wx.Panel): self.axes.Update() self.joy.Update() self.pov.Update() - self.buttons.Update() + if evt is not None and evt.IsButton(): + self.buttons.Update() + def ShutdownDemo(self): + if self.stick: + self.stick.ReleaseCapture() + self.stick = None + #---------------------------------------------------------------------------- def runTest(frame, nb, log): - win = JoystickDemoPanel(nb, log) - return win + if haveJoystick: + win = JoystickDemoPanel(nb, log) + return win + else: + dlg = wx.MessageDialog( + frame, 'wx.Joystick is not available on this platform.', + 'Sorry', wx.OK | wx.ICON_INFORMATION + ) + dlg.ShowModal() + dlg.Destroy() + #---------------------------------------------------------------------------- overview = """\ - - + + +

wx.Joystick

+This demo illustrates the use of the wx.Joystick class, which is an interface to +one or more joysticks attached to your system. + +

The data that can be retrieved from the joystick comes in four basic flavors. +All of these are illustrated in the demo. In fact, this demo illustrates everything +you can get from the wx.Joystick control. + +

+ +

Getting data from the joystick can be event-driven thanks to four event types associated +with wx.JoystickEvent, or the joystick can be polled programatically to get data on +a regular basis. + +

Data types

+ +Data from the joystick comes in two flavors: that which defines the boundaries, and that +which defines the current state of the stick. Thus, we have Get*Max() and Get*Min() +methods for all axes, the max number of axes, the max number of buttons, and so on. In +general, this data can be read once and stored to speed computation up. + +

Analog Input

+ +Analog input (the axes) is delivered as a whole, positive number. If you need to know +if the axis is at zero (centered) or not, you will first have to calculate that center +based on the max and min values. The demo shows a bar graph for each axis expressed +in native numerical format, plus a 'centered' X-Y axis compass showing the relationship +of that input to the calculated stick position. + +Analog input may be jumpy and spurious, so the control has a means of 'smoothing' the +analog data by setting a movement threshold. This demo sets the threshold to 10, but +you can set it at any valid value between the min and max. + +

Button Input

+ +Button state is retrieved as one int that contains each button state mapped to a bit. +You get the state of a button by AND-ing its bit against the returned value, in the form + +
+     # assume buttonState is what the stick returned, and buttonBit 
+     # is the bit you want to examine
+     
+     if (buttonState & ( 1 << buttonBit )) :
+         # button pressed, do something with it
+
+ +

The problem here is that some OSs return a 32-bit value for up to 32 buttons +(imagine that stick!). Python V2.3 will generate an exception for bit +values over 30. For that reason, this demo is limited to 16 buttons. + +

Note that more than one button can be pressed at a time, so be sure to check all of them! + + +

POV Input

+ +POV hats come in two flavors: four-way, and continuous. four-way POVs are restricted to +the cardinal points of the compass; continuous, or CTS POV hats can deliver input in +.01 degree increments, theoreticaly. The data is returned as a whole number; the last +two digits are considered to be to the right of the decimal point, so in order to +use this information, you need to divide by 100 right off the bat. + +

Different methods are provided to retrieve the POV data for a CTS hat +versus a four-way hat. + +

Caveats

+ +The wx.Joystick control is in many ways incomplete at the C++ library level, but it is +not insurmountable. In short, while the joystick interface can be event-driven, +the wx.JoystickEvent class lacks event binders for all event types. Thus, you cannot +rely on wx.JoystickEvents to tell you when something has changed, necessarilly. + + + +

Fortunately, there is an easy workaround. In the top level frame, create a wx.Timer +that will poll the stick at a set interval. Of course, if you do this, you might as +well forgo catching wxEVT_JOYSTICK_* events at all and rely on the timer to do the +polling. + +

Ideally, the timer should be a one-shot; after it fires, collect and process data as +needed, then re-start the timer, possibly using wx.CallAfter(). + + + """ #---------------------------------------------------------------------------- @@ -978,4 +1106,4 @@ overview = """\ if __name__ == '__main__': import sys,os import run - run.main(['', os.path.basename(sys.argv[0])]) + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:])