PS4 控制器 - 值为 1 时光标不移动

PS4 Controller - Cursor not moving when value is 1

我试图编写程序来用我的 PS4 控制器控制我的鼠标,一切正常,我得到了数据,我可以相应地移动我的鼠标。但是,当我将操纵杆固定在任何轴上时,鼠标不会移动,不仅在我按住它时发生,而且在操纵杆值不变时也会发生。有什么办法可以解决这个问题吗?

import pygame
import os
import pyautogui

pygame.init()
pygame.joystick.init
j = pygame.joystick.Joystick(0)
j.init()
data = {}

while True:
    for event in pygame.event.get():
        if event.type == pygame.JOYAXISMOTION:
            data[event.axis] = round(event.value, 2)
        if event.type == pygame.JOYBUTTONUP:
            data["test"] = "letsgoooo"
        if event.type == pygame.JOYBUTTONDOWN:
            if "test" in data:
                del data["test"]
        if 0 in data and 1 in data:
            if data[0] > 0.08:
                pyautogui.move(5, 0, 0.1)
            if data[0] < -0.08:
                pyautogui.move(-5, 0, 0.1)
            if data[1] > 0.08:
                pyautogui.move(0, 10, 0.1)
            if data[1] < -0.08:
                pyautogui.move(0, -10, 0.1)
    if 0 in data and 1 in data and 2 in data and 3 in data and 4 in data and 5 in data:
        os.system('cls')
        print(f"Left:\nX = {data[0]}, Y = {data[1]}")
        print(f"Right:\nX = {data[2]}, Y = {data[3]}")
        print(f"Left trigger = {data[5]}, Right trigger = {data[4]}")
        print(f"Mouse: X = {pyautogui.position()[0]}, Y = {pyautogui.position()[1]}") 
        print(data)
    else:
        print("Move your joystick")

操纵杆发送更新事件。我猜有点像鼠标,如果它没有发出事件,你必须假设鼠标没有改变位置。操纵杆事件是相同的,如果操纵杆说它在 0.753 并且此后没有发生任何事件,那么在那个角度它仍然是 still

所以你的移动代码需要记住最近的轴值,并将其用作摇杆的当前位置。当一个新事件到来时,你就更新这个值,否则就不会。这样,摇杆就会定位到“完全锁定”(例如:100% 左),无论操纵杆每帧移动的最大量是多少,您都可以继续重新定位。

PS4控制器上的左方向键盘是一个PyGame“帽子”,所以不会产生事件,你必须独立查询它。无论出于何种原因,上下似乎都会产生与正常人所期望的相反的值(无论如何在撰写本文时)。

我制作了一些示例代码,可以在 window 周围移动 3 个十字准线 (sp?)。每根棍子一个,帽子一个。它还将显示按下了哪些按钮。该代码可能需要重新组织。我不喜欢必须将帽子与粘性事件等分开处理的方式。但它很好地展示了它们如何组合在一起。

哦,左右触发器也是单轴操纵杆,但除了 pass 事件之外,我并没有在代码中对它们做太多处理。

import pygame

# Window size
WINDOW_WIDTH    = 600
WINDOW_HEIGHT   = 600
WINDOW_SURFACE  = pygame.HWSURFACE|pygame.DOUBLEBUF

DARK_BLUE = (   3,   5,  54 )
YELLOWISH = ( 255, 245, 145 )

class PS4Joystick:
    """ Class that knows about PS4 Controller Buttons, etc. """
    BUTTON_CROSS   = 0
    BUTTON_CIRCLE  = 1
    BUTTON_TRIANGLE= 2
    BUTTON_SQUARE  = 3
    BUTTON_L1      = 4
    BUTTON_R1      = 5
    BUTTON_L2      = 6
    BUTTON_R2      = 7
    BUTTON_SHARE   = 8
    BUTTON_OPTIONS = 9
    BUTTON_PS      = 10

    AXIS_LEFT_RIGHT = 1
    AXIS_UP_DOWN    = 2
    AXIS_LTRIGGER   = 3
    AXIS_RTRIGGER   = 4

    STICK_LEFT     = 1
    STICK_RIGHT    = 2
    STICK_LTRIGGER = 3
    STICK_RTRIGGER = 4

    #PS4ButtNames = [ '⨯', '○', '△', '□', 'L1', 'R1', 'L2', 'R2', 'Share', 'Options', 'PS' ]
    PS4ButtNames = [ 'eX', 'Oh', 'Pointy', 'Square', 'L1', 'R1', 'L2', 'R2', 'Share', 'Options', 'PS' ]
    PS4AxisNames = [ 'Left E/W', 'Left N/S', 'Left Trig', 'Right E/W', 'Right N/S', 'Right Trig' ]
    PS4AxisDir   = [ AXIS_LEFT_RIGHT, AXIS_UP_DOWN, AXIS_LTRIGGER, AXIS_LEFT_RIGHT, AXIS_UP_DOWN, AXIS_RTRIGGER ]
    
    @staticmethod
    def buttonName( butt_index ):
        """ Convert the button index to human-readable name """
        if ( butt_index >= 0 and butt_index < len( PS4Joystick.PS4ButtNames ) ):
            return PS4Joystick.PS4ButtNames[ butt_index ]
        else:
            return None  # error

    @staticmethod
    def axisName( axis_index ):
        """ Convert the axis index to human-readable name """
        if ( axis_index >= 0 and axis_index < len( PS4Joystick.PS4AxisNames ) ):
            return PS4Joystick.PS4AxisNames[ axis_index ]
        else:
            return None  # error
    
    @staticmethod
    def axisDirection( axis_index ):
        """ Convert the axis index to x/y indicator """
        if ( axis_index >= 0 and axis_index < len( PS4Joystick.PS4AxisDir ) ):
            return PS4Joystick.PS4AxisDir[ axis_index ]
        else:
            return None  # error

    @staticmethod
    def getStick( axis_index ):
        """ Given an axis, work out if it's from the left or right stick """
        if ( axis_index == 0 or axis_index == 1):
            return PS4Joystick.STICK_LEFT 
        elif ( axis_index == 3 or axis_index == 4 ):
            return PS4Joystick.STICK_RIGHT
        elif ( axis_index == 2 ):
            return PS4Joystick.STICK_LTRIGGER      
        elif ( axis_index == 5 ):
            return PS4Joystick.STICK_RTRIGGER      
        else:
            return None  # error


class CursorSprite( pygame.sprite.Sprite ):
    SIZE   = 48
    SPEED  = 5

    def __init__( self, colour=( 255, 245, 145 ) ):
        pygame.sprite.Sprite.__init__( self )
        self.image = pygame.Surface( ( self.SIZE, self.SIZE ), pygame.SRCALPHA )
        self.rect  = self.image.get_rect( center = ( WINDOW_WIDTH//2, WINDOW_HEIGHT//2 ) )
        # Make a centred '+'
        pygame.draw.line( self.image, colour, ( self.SIZE//2, 0 ), ( self.SIZE//2, self.SIZE ), 3 )
        pygame.draw.line( self.image, colour, ( 0, self.SIZE//2 ), ( self.SIZE, self.SIZE//2 ), 3 )

    def move( self, joy_x, joy_y ):
        # Joystick events are 
        self.rect.x += round( joy_x * self.SPEED )
        self.rect.y += round( joy_y * self.SPEED )


### initialisation
pygame.init()
pygame.font.init()
pygame.mixer.init()
window = pygame.display.set_mode( ( WINDOW_WIDTH, WINDOW_HEIGHT ), WINDOW_SURFACE )
pygame.display.set_caption( "PS4 Joystick Demo" )


### Joystick(s) initialisation
joystick_count = pygame.joystick.get_count()
print( "Initialising %d Joystick(s)" % ( joystick_count ) )
for i in range( joystick_count ):
    joystick = pygame.joystick.Joystick(i)
    joystick.init()
    print( "Joystick %d:" % ( i ) )
    print( "    name ........... [%s]" % ( joystick.get_name() ) )
    print( "    axis count ..... [%d]" % ( joystick.get_numaxes() ) )
    print( "    button count ... [%d]" % ( joystick.get_numbuttons() ) )
    print( "    hat count ...... [%d]" % ( joystick.get_numhats() ) )

# Just deal with Joystick 0 for now
joystick = pygame.joystick.Joystick( 0 )
left_stick_val_horiz = 0
left_stick_val_vert  = 0
right_stick_val_horiz = 0
right_stick_val_vert = 0
hat_val_horiz = 0
hat_val_vert = 0

# cursor to show movement
sprite_group = pygame.sprite.Group()
cursor_sprite_left  = CursorSprite( ( 255, 50, 50 ) )
cursor_sprite_right = CursorSprite( ( 50, 255, 50 ) )
cursor_sprite_hat   = CursorSprite( ( 50, 55, 255 ) )
sprite_group.add( cursor_sprite_left )
sprite_group.add( cursor_sprite_right )
sprite_group.add( cursor_sprite_hat )
button_text = ''

### Main Loop
clock = pygame.time.Clock()
font = pygame.font.Font( 'Arial_Bold.ttf', 24 )
done = False
while not done:

    # Handle user-input
    for event in pygame.event.get():
        if ( event.type == pygame.QUIT ):
            done = True

        # Button pushed
        elif ( event.type == pygame.JOYBUTTONDOWN ):
            button_name = PS4Joystick.buttonName( event.button )
            button_text += ' ' + button_name
            print( "Button %s pressed" % ( button_name ) )

        # Button released
        elif ( event.type == pygame.JOYBUTTONUP ):
            button_name = PS4Joystick.buttonName( event.button )
            button_text = button_text.replace( ' ' + button_name, '' )
            print( "Button %s released" % ( button_name ) )

        # Position update form PS4-stick(s)
        elif ( event.type == pygame.JOYAXISMOTION ):
            stick = PS4Joystick.getStick( event.axis )
            axis  = PS4Joystick.axisDirection( event.axis )
            #name  = PS4Joystick.axisName( event.axis )

            if ( stick == PS4Joystick.STICK_LEFT ):
                if ( axis == PS4Joystick.AXIS_LEFT_RIGHT ):
                    left_stick_val_horiz = event.value   
                else:
                    left_stick_val_vert = event.value   

            elif ( stick == PS4Joystick.STICK_RIGHT ):
                if ( axis == PS4Joystick.AXIS_LEFT_RIGHT ):
                    right_stick_val_horiz = event.value   
                else:
                    right_stick_val_vert = event.value   

            # The left and right triggers are also relative-positioned sticks
            elif ( stick == PS4Joystick.STICK_LTRIGGER ):
                pass
            elif ( stick == PS4Joystick.STICK_RTRIGGER ):
                pass

            #if ( event.value > 0.01 or event.value < -0.01 ):
            #print( "AXIS: %s=%6.8f" % ( name, event.value ) )

    # The Joystick "Hat" is not handled via events
    if ( joystick.get_numhats() > 0 ):
        hat_vals = joystick.get_hat( 0 )
        hat_val_horiz = hat_vals[0]
        hat_val_vert  = -hat_vals[1]  # up/down reversed for some reason

    # Update the on-screen tracker cursors
    cursor_sprite_left.move( left_stick_val_horiz, left_stick_val_vert )
    cursor_sprite_right.move( right_stick_val_horiz, right_stick_val_vert )
    cursor_sprite_hat.move( hat_val_horiz, hat_val_vert )
    
    # Update the window, but not more than 60fps
    window.fill( DARK_BLUE )
    if ( len( button_text ) > 0 ):
        button_display = font.render( button_text+' ',  True, DARK_BLUE, YELLOWISH )
        window.blit( button_display, ( 50, WINDOW_HEIGHT-50-button_display.get_height() ) )
    sprite_group.update()
    sprite_group.draw( window )
    pygame.display.flip()

    # Clamp FPS
    clock.tick_busy_loop(60)


pygame.quit()