ruaaaa
This commit is contained in:
沈瑗杰 2022-05-01 08:39:37 +08:00
commit 327fe5f324
183 changed files with 1080 additions and 434 deletions

View File

@ -128,7 +128,7 @@ class ClientWindow(Window):
self.fps_label = pyglet.text.Label(x=10, y=self.height - 10,
width=self.width - 20, height=20,
anchor_x='left', anchor_y='top',
font_name=tr.微软等宽无线, font_size=20,
font_name=translate.微软等宽无线, font_size=20,
multiline=True,
batch=self.label_batch, group=self.command_group)
# 设置刷新率

View File

@ -57,6 +57,7 @@ command_tree = {
}
}
}
# TODO 给爷做了他
class CommandTree:

View File

@ -10,10 +10,10 @@ using PyCall
include("../../utils/translate.jl")
struct default_style
# font_name::String = fonts.HOS_S()
font_name::String
font_size::UInt8
bold::Bool
italic::Bool
end
a = default_style(1, true, true)
default_style = default_style(fonts.HOS)

View File

@ -8,10 +8,10 @@ translate:
module fonts
export HOS, HOS_C, HOS_S, HOS_T
HOS = "HarmonyOS Sans" :: String
HOS_S = "HarmonyOS Sans SC" :: String
HOS_T = "HarmonyOS Sans TC" :: String
HOS_C = "HarmonyOS Sans Condensed" :: String
const HOS = "HarmonyOS Sans" :: String
const HOS_S = "HarmonyOS Sans SC" :: String
const HOS_T = "HarmonyOS Sans TC" :: String
const HOS_C = "HarmonyOS Sans Condensed" :: String
export 鸿蒙字体, 鸿蒙简体, 鸿蒙繁体, 鸿蒙窄体
鸿蒙字体 = HOS

View File

@ -1,7 +1,7 @@
# ----------------------------------------------------------------------------
# pyglet
# Copyright (c) 2006-2008 Alex Holkner
# Copyright (c) 2008-2021 pyglet contributors
# Copyright (c) 2008-2022 pyglet contributors
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
@ -44,7 +44,7 @@ import sys
from typing import TYPE_CHECKING
#: The release version
version = '2.0.a3'
version = '2.0.dev14'
__version__ = version
if sys.version_info < (3, 6):
@ -159,6 +159,7 @@ options = {
'headless': False,
'headless_device': 0,
'win32_disable_shaping': False,
'xinput_controllers': True,
}
_option_types = {
@ -186,7 +187,8 @@ _option_types = {
'win32_gdi_font': bool,
'headless': bool,
'headless_device': int,
'win32_disable_shaping': bool
'win32_disable_shaping': bool,
'xinput_controllers': bool
}

View File

@ -1,7 +1,7 @@
# ----------------------------------------------------------------------------
# pyglet
# Copyright (c) 2006-2008 Alex Holkner
# Copyright (c) 2008-2021 pyglet contributors
# Copyright (c) 2008-2022 pyglet contributors
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without

View File

@ -1,7 +1,7 @@
# ----------------------------------------------------------------------------
# pyglet
# Copyright (c) 2006-2008 Alex Holkner
# Copyright (c) 2008-2021 pyglet contributors
# Copyright (c) 2008-2022 pyglet contributors
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without

View File

@ -1,7 +1,7 @@
# ----------------------------------------------------------------------------
# pyglet
# Copyright (c) 2006-2008 Alex Holkner
# Copyright (c) 2008-2021 pyglet contributors
# Copyright (c) 2008-2022 pyglet contributors
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without

View File

@ -1,7 +1,7 @@
# ----------------------------------------------------------------------------
# pyglet
# Copyright (c) 2006-2008 Alex Holkner
# Copyright (c) 2008-2021 pyglet contributors
# Copyright (c) 2008-2022 pyglet contributors
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without

View File

@ -1,7 +1,7 @@
# ----------------------------------------------------------------------------
# pyglet
# Copyright (c) 2006-2008 Alex Holkner
# Copyright (c) 2008-2021 pyglet contributors
# Copyright (c) 2008-2022 pyglet contributors
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without

View File

@ -1,7 +1,7 @@
# ----------------------------------------------------------------------------
# pyglet
# Copyright (c) 2006-2008 Alex Holkner
# Copyright (c) 2008-2021 pyglet contributors
# Copyright (c) 2008-2022 pyglet contributors
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without

View File

@ -1,7 +1,7 @@
# ----------------------------------------------------------------------------
# pyglet
# Copyright (c) 2006-2008 Alex Holkner
# Copyright (c) 2008-2021 pyglet contributors
# Copyright (c) 2008-2022 pyglet contributors
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without

View File

@ -1,7 +1,7 @@
# ----------------------------------------------------------------------------
# pyglet
# Copyright (c) 2006-2008 Alex Holkner
# Copyright (c) 2008-2021 pyglet contributors
# Copyright (c) 2008-2022 pyglet contributors
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without

View File

@ -1,7 +1,7 @@
# ----------------------------------------------------------------------------
# pyglet
# Copyright (c) 2006-2008 Alex Holkner
# Copyright (c) 2008-2021 pyglet contributors
# Copyright (c) 2008-2022 pyglet contributors
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without

View File

@ -1,7 +1,7 @@
# ----------------------------------------------------------------------------
# pyglet
# Copyright (c) 2006-2008 Alex Holkner
# Copyright (c) 2008-2021 pyglet contributors
# Copyright (c) 2008-2022 pyglet contributors
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without

View File

@ -1,7 +1,7 @@
# ----------------------------------------------------------------------------
# pyglet
# Copyright (c) 2006-2008 Alex Holkner
# Copyright (c) 2008-2021 pyglet contributors
# Copyright (c) 2008-2022 pyglet contributors
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without

View File

@ -1,7 +1,7 @@
# ----------------------------------------------------------------------------
# pyglet
# Copyright (c) 2006-2008 Alex Holkner
# Copyright (c) 2008-2021 pyglet contributors
# Copyright (c) 2008-2022 pyglet contributors
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without

View File

@ -1,7 +1,7 @@
# ----------------------------------------------------------------------------
# pyglet
# Copyright (c) 2006-2008 Alex Holkner
# Copyright (c) 2008-2021 pyglet contributors
# Copyright (c) 2008-2022 pyglet contributors
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without

View File

@ -1,7 +1,7 @@
# ----------------------------------------------------------------------------
# pyglet
# Copyright (c) 2006-2008 Alex Holkner
# Copyright (c) 2008-2021 pyglet contributors
# Copyright (c) 2008-2022 pyglet contributors
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without

View File

@ -1,7 +1,7 @@
# ----------------------------------------------------------------------------
# pyglet
# Copyright (c) 2006-2008 Alex Holkner
# Copyright (c) 2008-2021 pyglet contributors
# Copyright (c) 2008-2022 pyglet contributors
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without

View File

@ -1,7 +1,7 @@
# ----------------------------------------------------------------------------
# pyglet
# Copyright (c) 2006-2008 Alex Holkner
# Copyright (c) 2008-2021 pyglet contributors
# Copyright (c) 2008-2022 pyglet contributors
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without

View File

@ -1,7 +1,7 @@
# ----------------------------------------------------------------------------
# pyglet
# Copyright (c) 2006-2008 Alex Holkner
# Copyright (c) 2008-2021 pyglet contributors
# Copyright (c) 2008-2022 pyglet contributors
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without

View File

@ -1,7 +1,7 @@
# ----------------------------------------------------------------------------
# pyglet
# Copyright (c) 2006-2008 Alex Holkner
# Copyright (c) 2008-2021 pyglet contributors
# Copyright (c) 2008-2022 pyglet contributors
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without

View File

@ -1,7 +1,7 @@
# ----------------------------------------------------------------------------
# pyglet
# Copyright (c) 2006-2008 Alex Holkner
# Copyright (c) 2008-2021 pyglet contributors
# Copyright (c) 2008-2022 pyglet contributors
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without

View File

@ -1,7 +1,7 @@
# ----------------------------------------------------------------------------
# pyglet
# Copyright (c) 2006-2008 Alex Holkner
# Copyright (c) 2008-2021 pyglet contributors
# Copyright (c) 2008-2022 pyglet contributors
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without

View File

@ -1,7 +1,7 @@
# ----------------------------------------------------------------------------
# pyglet
# Copyright (c) 2006-2008 Alex Holkner
# Copyright (c) 2008-2021 pyglet contributors
# Copyright (c) 2008-2022 pyglet contributors
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without

View File

@ -1,7 +1,7 @@
# ----------------------------------------------------------------------------
# pyglet
# Copyright (c) 2006-2008 Alex Holkner
# Copyright (c) 2008-2021 pyglet contributors
# Copyright (c) 2008-2022 pyglet contributors
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without

View File

@ -1,7 +1,7 @@
# ----------------------------------------------------------------------------
# pyglet
# Copyright (c) 2006-2008 Alex Holkner
# Copyright (c) 2008-2021 pyglet contributors
# Copyright (c) 2008-2022 pyglet contributors
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without

View File

@ -1,7 +1,7 @@
# ----------------------------------------------------------------------------
# pyglet
# Copyright (c) 2006-2008 Alex Holkner
# Copyright (c) 2008-2021 pyglet contributors
# Copyright (c) 2008-2022 pyglet contributors
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without

View File

@ -1,7 +1,7 @@
# ----------------------------------------------------------------------------
# pyglet
# Copyright (c) 2006-2008 Alex Holkner
# Copyright (c) 2008-2021 pyglet contributors
# Copyright (c) 2008-2022 pyglet contributors
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without

View File

@ -1,7 +1,7 @@
# ----------------------------------------------------------------------------
# pyglet
# Copyright (c) 2006-2008 Alex Holkner
# Copyright (c) 2008-2021 pyglet contributors
# Copyright (c) 2008-2022 pyglet contributors
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without

View File

@ -1,7 +1,7 @@
# ----------------------------------------------------------------------------
# pyglet
# Copyright (c) 2006-2008 Alex Holkner
# Copyright (c) 2008-2021 pyglet contributors
# Copyright (c) 2008-2022 pyglet contributors
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without

View File

@ -1,7 +1,7 @@
# ----------------------------------------------------------------------------
# pyglet
# Copyright (c) 2006-2008 Alex Holkner
# Copyright (c) 2008-2021 pyglet contributors
# Copyright (c) 2008-2022 pyglet contributors
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without

View File

@ -1,7 +1,7 @@
# ----------------------------------------------------------------------------
# pyglet
# Copyright (c) 2006-2008 Alex Holkner
# Copyright (c) 2008-2021 pyglet contributors
# Copyright (c) 2008-2022 pyglet contributors
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without

View File

@ -1,7 +1,7 @@
# ----------------------------------------------------------------------------
# pyglet
# Copyright (c) 2006-2008 Alex Holkner
# Copyright (c) 2008-2021 pyglet contributors
# Copyright (c) 2008-2022 pyglet contributors
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without

View File

@ -1,7 +1,7 @@
# ----------------------------------------------------------------------------
# pyglet
# Copyright (c) 2006-2008 Alex Holkner
# Copyright (c) 2008-2021 pyglet contributors
# Copyright (c) 2008-2022 pyglet contributors
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without

View File

@ -1,7 +1,7 @@
# ----------------------------------------------------------------------------
# pyglet
# Copyright (c) 2006-2008 Alex Holkner
# Copyright (c) 2008-2021 pyglet contributors
# Copyright (c) 2008-2022 pyglet contributors
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without

View File

@ -1,7 +1,7 @@
# ----------------------------------------------------------------------------
# pyglet
# Copyright (c) 2006-2008 Alex Holkner
# Copyright (c) 2008-2021 pyglet contributors
# Copyright (c) 2008-2022 pyglet contributors
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without

View File

@ -1,7 +1,7 @@
# ----------------------------------------------------------------------------
# pyglet
# Copyright (c) 2006-2008 Alex Holkner
# Copyright (c) 2008-2021 pyglet contributors
# Copyright (c) 2008-2022 pyglet contributors
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without

View File

@ -1,7 +1,7 @@
# ----------------------------------------------------------------------------
# pyglet
# Copyright (c) 2006-2008 Alex Holkner
# Copyright (c) 2008-2021 pyglet contributors
# Copyright (c) 2008-2022 pyglet contributors
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without

View File

@ -1,7 +1,7 @@
# ----------------------------------------------------------------------------
# pyglet
# Copyright (c) 2006-2008 Alex Holkner
# Copyright (c) 2008-2021 pyglet contributors
# Copyright (c) 2008-2022 pyglet contributors
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without

View File

@ -1,7 +1,7 @@
# ----------------------------------------------------------------------------
# pyglet
# Copyright (c) 2006-2008 Alex Holkner
# Copyright (c) 2008-2021 pyglet contributors
# Copyright (c) 2008-2022 pyglet contributors
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without

View File

@ -1,7 +1,7 @@
# ----------------------------------------------------------------------------
# pyglet
# Copyright (c) 2006-2008 Alex Holkner
# Copyright (c) 2008-2021 pyglet contributors
# Copyright (c) 2008-2022 pyglet contributors
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without

View File

@ -1,7 +1,7 @@
# ----------------------------------------------------------------------------
# pyglet
# Copyright (c) 2006-2008 Alex Holkner
# Copyright (c) 2008-2021 pyglet contributors
# Copyright (c) 2008-2022 pyglet contributors
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without

View File

@ -1,7 +1,7 @@
# ----------------------------------------------------------------------------
# pyglet
# Copyright (c) 2006-2008 Alex Holkner
# Copyright (c) 2008-2021 pyglet contributors
# Copyright (c) 2008-2022 pyglet contributors
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without

View File

@ -1,7 +1,7 @@
# ----------------------------------------------------------------------------
# pyglet
# Copyright (c) 2006-2008 Alex Holkner
# Copyright (c) 2008-2021 pyglet contributors
# Copyright (c) 2008-2022 pyglet contributors
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without

View File

@ -1,7 +1,7 @@
# ----------------------------------------------------------------------------
# pyglet
# Copyright (c) 2006-2008 Alex Holkner
# Copyright (c) 2008-2021 pyglet contributors
# Copyright (c) 2008-2022 pyglet contributors
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without

View File

@ -1,7 +1,7 @@
# ----------------------------------------------------------------------------
# pyglet
# Copyright (c) 2006-2008 Alex Holkner
# Copyright (c) 2008-2021 pyglet contributors
# Copyright (c) 2008-2022 pyglet contributors
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without

View File

@ -1,7 +1,7 @@
# ----------------------------------------------------------------------------
# pyglet
# Copyright (c) 2006-2008 Alex Holkner
# Copyright (c) 2008-2021 pyglet contributors
# Copyright (c) 2008-2022 pyglet contributors
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without

View File

@ -1,7 +1,7 @@
# ----------------------------------------------------------------------------
# pyglet
# Copyright (c) 2006-2008 Alex Holkner
# Copyright (c) 2008-2021 pyglet contributors
# Copyright (c) 2008-2022 pyglet contributors
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without

View File

@ -1,7 +1,7 @@
# ----------------------------------------------------------------------------
# pyglet
# Copyright (c) 2006-2008 Alex Holkner
# Copyright (c) 2008-2021 pyglet contributors
# Copyright (c) 2008-2022 pyglet contributors
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without

View File

@ -1,7 +1,7 @@
# ----------------------------------------------------------------------------
# pyglet
# Copyright (c) 2006-2008 Alex Holkner
# Copyright (c) 2008-2021 pyglet contributors
# Copyright (c) 2008-2022 pyglet contributors
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without

View File

@ -1,7 +1,7 @@
# ----------------------------------------------------------------------------
# pyglet
# Copyright (c) 2006-2008 Alex Holkner
# Copyright (c) 2008-2021 pyglet contributors
# Copyright (c) 2008-2022 pyglet contributors
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without

View File

@ -1,7 +1,7 @@
# ----------------------------------------------------------------------------
# pyglet
# Copyright (c) 2006-2008 Alex Holkner
# Copyright (c) 2008-2021 pyglet contributors
# Copyright (c) 2008-2022 pyglet contributors
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
@ -694,9 +694,6 @@ class TextureGroup(Group):
glActiveTexture(GL_TEXTURE0)
glBindTexture(self.texture.target, self.texture.id)
def unset_state(self):
glBindTexture(self.texture.target, 0)
def __hash__(self):
return hash((self.texture.target, self.texture.id, self.order, self.parent))

View File

@ -1,7 +1,7 @@
# ----------------------------------------------------------------------------
# pyglet
# Copyright (c) 2006-2008 Alex Holkner
# Copyright (c) 2008-2021 pyglet contributors
# Copyright (c) 2008-2022 pyglet contributors
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without

View File

@ -1,7 +1,7 @@
# ----------------------------------------------------------------------------
# pyglet
# Copyright (c) 2006-2008 Alex Holkner
# Copyright (c) 2008-2021 pyglet contributors
# Copyright (c) 2008-2022 pyglet contributors
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without

View File

@ -1,7 +1,7 @@
# ----------------------------------------------------------------------------
# pyglet
# Copyright (c) 2006-2008 Alex Holkner
# Copyright (c) 2008-2021 pyglet contributors
# Copyright (c) 2008-2022 pyglet contributors
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without

View File

@ -1,7 +1,7 @@
# ----------------------------------------------------------------------------
# pyglet
# Copyright (c) 2006-2008 Alex Holkner
# Copyright (c) 2008-2021 pyglet contributors
# Copyright (c) 2008-2022 pyglet contributors
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without

View File

@ -1,7 +1,7 @@
# ----------------------------------------------------------------------------
# pyglet
# Copyright (c) 2006-2008 Alex Holkner
# Copyright (c) 2008-2021 pyglet contributors
# Copyright (c) 2008-2022 pyglet contributors
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without

View File

@ -1,7 +1,7 @@
# ----------------------------------------------------------------------------
# pyglet
# Copyright (c) 2006-2008 Alex Holkner
# Copyright (c) 2008-2021 pyglet contributors
# Copyright (c) 2008-2022 pyglet contributors
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without

View File

@ -1,7 +1,7 @@
# ----------------------------------------------------------------------------
# pyglet
# Copyright (c) 2006-2008 Alex Holkner
# Copyright (c) 2008-2021 pyglet contributors
# Copyright (c) 2008-2022 pyglet contributors
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without

View File

@ -1,7 +1,7 @@
# ----------------------------------------------------------------------------
# pyglet
# Copyright (c) 2006-2008 Alex Holkner
# Copyright (c) 2008-2021 pyglet contributors
# Copyright (c) 2008-2022 pyglet contributors
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without

View File

@ -1,7 +1,7 @@
# ----------------------------------------------------------------------------
# pyglet
# Copyright (c) 2006-2008 Alex Holkner
# Copyright (c) 2008-2021 pyglet contributors
# Copyright (c) 2008-2022 pyglet contributors
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without

View File

@ -1,7 +1,7 @@
# ----------------------------------------------------------------------------
# pyglet
# Copyright (c) 2006-2008 Alex Holkner
# Copyright (c) 2008-2021 pyglet contributors
# Copyright (c) 2008-2022 pyglet contributors
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without

View File

@ -1,7 +1,7 @@
# ----------------------------------------------------------------------------
# pyglet
# Copyright (c) 2006-2008 Alex Holkner
# Copyright (c) 2008-2021 pyglet contributors
# Copyright (c) 2008-2022 pyglet contributors
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without

View File

@ -1,7 +1,7 @@
# ----------------------------------------------------------------------------
# pyglet
# Copyright (c) 2006-2008 Alex Holkner
# Copyright (c) 2008-2021 pyglet contributors
# Copyright (c) 2008-2022 pyglet contributors
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without

View File

@ -1,7 +1,7 @@
# ----------------------------------------------------------------------------
# pyglet
# Copyright (c) 2006-2008 Alex Holkner
# Copyright (c) 2008-2021 pyglet contributors
# Copyright (c) 2008-2022 pyglet contributors
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without

View File

@ -1,7 +1,7 @@
# ----------------------------------------------------------------------------
# pyglet
# Copyright (c) 2006-2008 Alex Holkner
# Copyright (c) 2008-2021 pyglet contributors
# Copyright (c) 2008-2022 pyglet contributors
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without

View File

@ -1,7 +1,7 @@
# ----------------------------------------------------------------------------
# pyglet
# Copyright (c) 2006-2008 Alex Holkner
# Copyright (c) 2008-2021 pyglet contributors
# Copyright (c) 2008-2022 pyglet contributors
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without

View File

@ -1,7 +1,7 @@
# ----------------------------------------------------------------------------
# pyglet
# Copyright (c) 2006-2008 Alex Holkner
# Copyright (c) 2008-2021 pyglet contributors
# Copyright (c) 2008-2022 pyglet contributors
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without

View File

@ -1,7 +1,7 @@
# ----------------------------------------------------------------------------
# pyglet
# Copyright (c) 2006-2008 Alex Holkner
# Copyright (c) 2008-2021 pyglet contributors
# Copyright (c) 2008-2022 pyglet contributors
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without

View File

@ -1,7 +1,7 @@
# ----------------------------------------------------------------------------
# pyglet
# Copyright (c) 2006-2008 Alex Holkner
# Copyright (c) 2008-2021 pyglet contributors
# Copyright (c) 2008-2022 pyglet contributors
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without

View File

@ -1,7 +1,7 @@
# ----------------------------------------------------------------------------
# pyglet
# Copyright (c) 2006-2008 Alex Holkner
# Copyright (c) 2008-2021 pyglet contributors
# Copyright (c) 2008-2022 pyglet contributors
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without

View File

@ -1,7 +1,7 @@
# ----------------------------------------------------------------------------
# pyglet
# Copyright (c) 2006-2008 Alex Holkner
# Copyright (c) 2008-2021 pyglet contributors
# Copyright (c) 2008-2022 pyglet contributors
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without

View File

@ -1,7 +1,7 @@
# ----------------------------------------------------------------------------
# pyglet
# Copyright (c) 2006-2008 Alex Holkner
# Copyright (c) 2008-2021 pyglet contributors
# Copyright (c) 2008-2022 pyglet contributors
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without

View File

@ -1,7 +1,7 @@
# ----------------------------------------------------------------------------
# pyglet
# Copyright (c) 2006-2008 Alex Holkner
# Copyright (c) 2008-2021 pyglet contributors
# Copyright (c) 2008-2022 pyglet contributors
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without

View File

@ -1,7 +1,7 @@
# ----------------------------------------------------------------------------
# pyglet
# Copyright (c) 2006-2008 Alex Holkner
# Copyright (c) 2008-2021 pyglet contributors
# Copyright (c) 2008-2022 pyglet contributors
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without

View File

@ -1,11 +1,11 @@
import warnings
from pyglet.image import *
from pyglet.image.codecs import *
from pyglet import com
from pyglet.libs.win32.constants import *
from pyglet.libs.win32.types import *
from pyglet.libs.win32 import _kernel32 as kernel32
from pyglet.libs.win32 import _ole32 as ole32
from pyglet.libs.win32.constants import *
from pyglet.libs.win32.types import *
CLSID_WICImagingFactory1 = com.GUID(0xcacaf262, 0x9370, 0x4615, 0xa1, 0x3b, 0x9f, 0x55, 0x39, 0xda, 0x4c, 0xa)
CLSID_WICImagingFactory2 = com.GUID(0x317d06e8, 0x5f24, 0x433d, 0xbd, 0xf7, 0x79, 0xce, 0x68, 0xd8, 0xab, 0xc2)
@ -61,7 +61,7 @@ WICBITMAPENCODERCACHEOPTION_FORCE_DWORD = 0x7fffffff
# Different pixel formats.
REFWICPixelFormatGUID = com.GUID
GUID_WICPixelFormatDontCare = com.GUID(0x6fddc324,0x4e03,0x4bfe,0xb1,0x85,0x3d,0x77,0x76,0x8d,0xc9,0x00)
GUID_WICPixelFormatDontCare = com.GUID(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x00)
GUID_WICPixelFormat1bppIndexed = com.GUID(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x01)
GUID_WICPixelFormat2bppIndexed = com.GUID(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x02)
GUID_WICPixelFormat4bppIndexed = com.GUID(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x03)
@ -80,7 +80,8 @@ GUID_WICPixelFormat24bppRGB = com.GUID(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0
GUID_WICPixelFormat32bppBGR = com.GUID(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x0e)
GUID_WICPixelFormat32bppBGRA = com.GUID(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x0f)
GUID_WICPixelFormat32bppPBGRA = com.GUID(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x10)
GUID_WICPixelFormat32bppRGB = com.GUID(0xd98c6b95, 0x3efe, 0x47d6, 0xbb, 0x25, 0xeb, 0x17, 0x48, 0xab, 0x0c, 0xf1) # 7 platform update?
GUID_WICPixelFormat32bppRGB = com.GUID(0xd98c6b95, 0x3efe, 0x47d6, 0xbb, 0x25, 0xeb, 0x17, 0x48, 0xab, 0x0c,
0xf1) # 7 platform update?
GUID_WICPixelFormat32bppRGBA = com.GUID(0xf5c7ad2d, 0x6a8d, 0x43dd, 0xa7, 0xa8, 0xa2, 0x99, 0x35, 0x26, 0x1a, 0xe9)
GUID_WICPixelFormat32bppPRGBA = com.GUID(0x3cc4a650, 0xa527, 0x4d37, 0xa9, 0x16, 0x31, 0x42, 0xc7, 0xeb, 0xed, 0xba)
GUID_WICPixelFormat48bppRGB = com.GUID(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x15)
@ -110,16 +111,6 @@ class IPropertyBag2(com.pIUnknown):
]
# class PROPBAG2(Structure):
# _fields_ = [
# ('dwType', DWORD),
# ('vt', VARTYPE),
# ('cfType', CLIPFORMAT),
# ('dwHint', DWORD),
# ('pstrName', LPOLESTR),
# ('clsid', CLSID)
# ]
class IWICPalette(com.pIUnknown):
_methods_ = [
('InitializePredefined',
@ -143,36 +134,16 @@ class IWICPalette(com.pIUnknown):
('HasAlpha',
com.STDMETHOD()),
]
class IWICStream(com.pIUnknown):
class IWICStream(IStream, com.pIUnknown):
_methods_ = [
('Read',
com.STDMETHOD()),
('Write',
com.STDMETHOD()),
('Seek',
com.STDMETHOD()),
('SetSize',
com.STDMETHOD()),
('CopyTo',
com.STDMETHOD()),
('Commit',
com.STDMETHOD()),
('Revert',
com.STDMETHOD()),
('LockRegion',
com.STDMETHOD()),
('UnlockRegion',
com.STDMETHOD()),
('Stat',
com.STDMETHOD()),
('Clone',
com.STDMETHOD()),
('InitializeFromIStream',
com.STDMETHOD()),
com.STDMETHOD(IStream)),
('InitializeFromFilename',
com.STDMETHOD(LPCWSTR, DWORD)),
('InitializeFromMemory',
com.STDMETHOD(c_void_p, DWORD)),
com.STDMETHOD(POINTER(BYTE), DWORD)),
('InitializeFromIStreamRegion',
com.STDMETHOD()),
]
@ -187,7 +158,7 @@ class IWICBitmapFrameEncode(com.pIUnknown):
('SetResolution',
com.STDMETHOD()),
('SetPixelFormat',
com.STDMETHOD(REFWICPixelFormatGUID)),
com.STDMETHOD(POINTER(REFWICPixelFormatGUID))),
('SetColorContexts',
com.STDMETHOD()),
('SetPalette',
@ -384,7 +355,7 @@ class IWICImagingFactory(com.pIUnknown):
('CreateDecoder',
com.STDMETHOD()),
('CreateEncoder',
com.STDMETHOD(com.GUID, POINTER(com.GUID), POINTER(IWICBitmapEncoder))),
com.STDMETHOD(POINTER(com.GUID), POINTER(com.GUID), POINTER(IWICBitmapEncoder))),
('CreatePalette',
com.STDMETHOD(POINTER(IWICPalette))),
('CreateFormatConverter',
@ -587,7 +558,7 @@ class WICEncoder(ImageEncoder):
def encode(self, image, filename, file):
image = image.get_image_data()
stream = IWICStream()
wicstream = IWICStream()
encoder = IWICBitmapEncoder()
frame = IWICBitmapFrameEncode()
property_bag = IPropertyBag2()
@ -597,7 +568,7 @@ class WICEncoder(ImageEncoder):
# Choose container based on extension. Default to PNG.
container = extension_to_container.get(ext, GUID_ContainerFormatPng)
_factory.CreateStream(byref(stream))
_factory.CreateStream(byref(wicstream))
# https://docs.microsoft.com/en-us/windows/win32/wic/-wic-codec-native-pixel-formats#native-image-formats
if container == GUID_ContainerFormatJpeg:
# Expects BGR, no transparency available. Hard coded.
@ -616,18 +587,18 @@ class WICEncoder(ImageEncoder):
image_data = image.get_data(fmt, -pitch)
size = len(image_data)
size = pitch * image.height
if file:
buf = create_string_buffer(size)
stream.InitializeFromMemory(byref(buf), size)
istream = IStream()
ole32.CreateStreamOnHGlobal(None, True, byref(istream))
wicstream.InitializeFromIStream(istream)
else:
stream.InitializeFromFilename(filename, GENERIC_WRITE)
wicstream.InitializeFromFilename(filename, GENERIC_WRITE)
_factory.CreateEncoder(container, None, byref(encoder))
encoder.Initialize(stream, WICBitmapEncoderNoCache)
encoder.Initialize(wicstream, WICBitmapEncoderNoCache)
encoder.CreateNewFrame(byref(frame), byref(property_bag))
@ -635,7 +606,7 @@ class WICEncoder(ImageEncoder):
frame.SetSize(image.width, image.height)
frame.SetPixelFormat(default_format)
frame.SetPixelFormat(byref(default_format))
data = (c_byte * size).from_buffer(bytearray(image_data))
@ -646,12 +617,26 @@ class WICEncoder(ImageEncoder):
encoder.Commit()
if file:
file.write(buf)
sts = STATSTG()
istream.Stat(byref(sts), 0)
stream_size = sts.cbSize
istream.Seek(0, STREAM_SEEK_SET, None)
buf = (BYTE * stream_size)()
written = ULONG()
istream.Read(byref(buf), stream_size, byref(written))
if written.value == stream_size:
file.write(buf)
else:
print(f"Failed to read all of the data from stream attempting to save {file}")
istream.Release()
encoder.Release()
frame.Release()
property_bag.Release()
stream.Release()
wicstream.Release()
def get_encoders():

View File

@ -1,7 +1,7 @@
# ----------------------------------------------------------------------------
# pyglet
# Copyright (c) 2006-2008 Alex Holkner
# Copyright (c) 2008-2021 pyglet contributors
# Copyright (c) 2008-2022 pyglet contributors
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without

View File

@ -1,7 +1,7 @@
# ----------------------------------------------------------------------------
# pyglet
# Copyright (c) 2006-2008 Alex Holkner
# Copyright (c) 2008-2021 pyglet contributors
# Copyright (c) 2008-2022 pyglet contributors
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
@ -33,7 +33,7 @@
# POSSIBILITY OF SUCH DAMAGE.
# ----------------------------------------------------------------------------
"""Joystick, Game Controller, tablet and USB HID device support.
"""Joystick, Game Controller, Tablet and USB HID device support.
This module provides a unified interface to almost any input device, besides
the regular mouse and keyboard support provided by
@ -52,20 +52,21 @@ not. In these cases the device API may still be useful -- the user will have
to be asked to press each button in turn or move each axis separately to
identify them.
Higher-level interfaces are provided for joysticks, tablets and the Apple
remote control. These devices can usually be identified by pyglet positively,
and a base level of functionality for each one provided through a common
interface.
Higher-level interfaces are provided for joysticks, game controllers, tablets
and the Apple remote control. These devices can usually be identified by pyglet
positively, and a base level of functionality for each one provided through a
common interface.
To use an input device:
1. Call :py:func:`get_devices`, :py:func:`get_apple_remote` or
:py:func:`get_joysticks`
to retrieve and identify the device.
1. Call :py:func:`get_devices`, :py:func:`get_apple_remote`,
:py:func:`get_controllers` or :py:func:`get_joysticks` to retrieve and
identify the device.
2. For low-level devices (retrieved by :py:func:`get_devices`), query the
devices list of controls and determine which ones you are interested in. For
high-level interfaces the set of controls is provided by the interface.
3. Optionally attach event handlers to controls on the device.
3. Optionally attach event handlers to controls on the device. For high-level
interfaces, additional events are available.
4. Call :py:meth:`Device.open` to begin receiving events on the device. You can
begin querying the control values after this time; they will be updated
asynchronously.
@ -77,13 +78,16 @@ note that no control list is available; instead, calling :py:meth:`Tablet.open`
returns a :py:class:`TabletCanvas` onto which you should set your event
handlers.
For game controllers, the :py:class:`ControllerManager` is available. This
provides a convenient way to handle hot-plugging of controllers.
.. versionadded:: 1.2
"""
import sys
from .base import Device, Control, RelativeAxis, AbsoluteAxis
from .base import Device, Control, RelativeAxis, AbsoluteAxis, ControllerManager
from .base import Button, Joystick, AppleRemote, Tablet, Controller
from .base import DeviceException, DeviceOpenException, DeviceExclusiveException
@ -167,29 +171,44 @@ else:
def get_tablets(display=None):
return []
from pyglet import compat_platform
from pyglet import compat_platform, options
if compat_platform.startswith('linux'):
from .x11_xinput_tablet import get_tablets
from .x11_xinput import get_devices as xinput_get_devices
from .x11_xinput import get_devices as x11xinput_get_devices
from .evdev import get_devices as evdev_get_devices
from .evdev import get_joysticks
from .evdev import get_controllers
from .evdev import EvdevControllerManager as ControllerManager
def get_devices(display=None):
return evdev_get_devices(display) + xinput_get_devices(display)
return evdev_get_devices(display) + x11xinput_get_devices(display)
elif compat_platform in ('cygwin', 'win32'):
from .directinput import get_devices
from .directinput import get_devices as dinput_get_devices
from .directinput import get_controllers as dinput_get_controllers
from .directinput import get_joysticks
from .directinput import get_controllers
try:
from .wintab import get_tablets
except:
pass
if options["xinput_controllers"] is False:
get_devices = dinput_get_devices
get_controllers = dinput_get_controllers
else:
from .xinput import get_devices as xinput_get_devices
from .xinput import get_controllers as xinput_get_controllers
from .xinput import XInputControllerManager as ControllerManager
def get_devices(display=None):
return xinput_get_devices() + dinput_get_devices(display)
def get_controllers(display=None):
return xinput_get_controllers() + dinput_get_controllers(display)
elif compat_platform == 'darwin':
from .darwin_hid import get_devices
from .darwin_hid import get_joysticks
from .darwin_hid import get_apple_remote
from .darwin_hid import get_controllers
# TODO: create ControllerManager for OSX

View File

@ -1,7 +1,7 @@
# ----------------------------------------------------------------------------
# pyglet
# Copyright (c) 2006-2008 Alex Holkner
# Copyright (c) 2008-2021 pyglet contributors
# Copyright (c) 2008-2022 pyglet contributors
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
@ -77,6 +77,10 @@ class Device:
self.manufacturer = None
self._is_open = False
@property
def is_open(self):
return self._is_open
def open(self, window=None, exclusive=False):
"""Open the device to begin receiving input from it.
@ -595,13 +599,15 @@ class Controller(EventDispatcher):
`dpdown` : bool
`dpleft` : bool
`dpright` : bool
.. versionadded:: 1.2
"""
self.device = device
self._mapping = mapping
self.name = self._mapping['name']
self.guid = self._mapping['guid']
self.name = mapping.get('name')
self.guid = mapping.get('guid')
self.a = False
self.b = False
@ -614,8 +620,8 @@ class Controller(EventDispatcher):
self.rightshoulder = False
self.leftstick = False # stick press button
self.rightstick = False # stick press button
self.lefttrigger = -1 # default to rest position
self.righttrigger = -1 # default to rest position
self.lefttrigger = 0
self.righttrigger = 0
self.leftx = 0
self.lefty = 0
self.rightx = 0
@ -631,7 +637,12 @@ class Controller(EventDispatcher):
self._hat_x_control = None
self._hat_y_control = None
self._initialize_controls()
def _initialize_controls(self):
def add_axis(control, axis_name):
tscale = 1.0 / (control.max - control.min)
scale = 2.0 / (control.max - control.min)
bias = -1.0 - control.min * scale
if control.inverted:
@ -665,7 +676,7 @@ class Controller(EventDispatcher):
elif axis_name in ("lefttrigger", "righttrigger"):
@control.event
def on_change(value):
normalized_value = value * scale + bias
normalized_value = value * tscale
setattr(self, axis_name, normalized_value)
self.dispatch_event('on_trigger_motion', self, axis_name, normalized_value)
@ -731,10 +742,11 @@ class Controller(EventDispatcher):
self.dispatch_event('on_dpad_motion', self,
self.dpleft, self.dpright, self.dpup, self.dpdown)
for control in device.get_controls():
for control in self.device.get_controls():
"""Categorize the various control types"""
if isinstance(control, Button):
self._button_controls.append(control)
elif isinstance(control, AbsoluteAxis):
if control.name in ('x', 'y', 'z', 'rx', 'ry', 'rz'):
self._axis_controls.append(control)
@ -858,7 +870,7 @@ class Controller(EventDispatcher):
"""A button on the controller was pressed.
:Parameters:
`controller` : `Controller`
`controller` : :py:class:`Controller`
The controller whose button was pressed.
`button` : string
The name of the button that was pressed.
@ -874,6 +886,9 @@ class Controller(EventDispatcher):
The name of the button that was released.
"""
def __repr__(self):
return f"Controller(name={self.name})"
Controller.register_event_type('on_button_press')
Controller.register_event_type('on_button_release')
@ -965,7 +980,7 @@ class AppleRemote(EventDispatcher):
whether or not the user has released the button.
:Parameters:
`button` : unicode
`button` : str
The name of the button that was released. The valid names are
'up', 'down', 'left', 'right', 'left_hold', 'right_hold',
'menu', 'menu_hold', 'select', and 'select_hold'
@ -1112,3 +1127,74 @@ class TabletCursor:
def __repr__(self):
return '%s(%s)' % (self.__class__.__name__, self.name)
class ControllerManager(EventDispatcher):
"""High level interface for managing game Controllers.
This class provides a convenient way to handle the
connection and disconnection of devices. A list of all
connected Controllers can be queried at any time with the
`get_controllers` method. For hot-plugging, events are
dispatched for `on_connect` and `on_disconnect`.
To use the ControllerManager, first make an instance::
controller_man = pyglet.input.ControllerManager()
At the start of your game, query for any Controllers
that are already connected::
controllers = controller_man.get_controllers()
To handle Controllers that are connected or disconnected
after the start of your game, register handlers for the
appropriate events::
@controller_man.event
def on_connect(controller):
# code to handle newly connected
# (or re-connected) controllers
controller.open()
print("Connect:", controller)
@controller_man.event
def on_disconnect(controller):
# code to handle disconnected Controller
print("Disconnect:", controller)
.. versionadded:: 1.2
"""
def get_controllers(self):
"""Get a list of all connected Controllers
:rtype: list of :py:class:`Controller`
"""
raise NotImplementedError
def on_connect(self, controller):
"""A Controller has been connected. If this is
a previously dissconnected Controller that is
being re-connected, the same Controller instance
will be returned.
:Parameters:
`controller` : :py:class:`Controller`
An un-opened Controller instance.
:event:
"""
def on_disconnect(self, controller):
"""A Controller has been disconnected.
:Parameters:
`controller` : :py:class:`Controller`
An un-opened Controller instance.
:event:
"""
ControllerManager.register_event_type('on_connect')
ControllerManager.register_event_type('on_disconnect')

View File

@ -1,7 +1,7 @@
# ----------------------------------------------------------------------------
# pyglet
# Copyright (c) 2006-2008 Alex Holkner
# Copyright (c) 2008-2021 pyglet contributors
# Copyright (c) 2008-2022 pyglet contributors
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without

View File

@ -1,7 +1,7 @@
# ----------------------------------------------------------------------------
# pyglet
# Copyright (c) 2006-2008 Alex Holkner
# Copyright (c) 2008-2021 pyglet contributors
# Copyright (c) 2008-2022 pyglet contributors
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without

View File

@ -1,7 +1,7 @@
# ----------------------------------------------------------------------------
# pyglet
# Copyright (c) 2006-2008 Alex Holkner
# Copyright (c) 2008-2021 pyglet contributors
# Copyright (c) 2008-2022 pyglet contributors
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
@ -226,8 +226,21 @@ def _init_directinput():
def get_devices(display=None):
_init_directinput()
_devices = []
_xinput_devices = []
if pyglet.options["xinput_controllers"]:
try:
from .xinput import get_xinput_guids
_xinput_devices = get_xinput_guids()
except ImportError:
pass
def _device_enum(device_instance, arg):
guid_id = format(device_instance.contents.guidProduct.Data1, "08x")
# Only XInput should handle DirectInput devices if enabled. Filter them out.
if guid_id in _xinput_devices:
# Log somewhere?
return dinput.DIENUM_CONTINUE
device = dinput.IDirectInputDevice8()
_i_dinput.CreateDevice(device_instance.contents.guidInstance, ctypes.byref(device), None)
_devices.append(DirectInputDevice(display, device, device_instance.contents))

View File

@ -1,7 +1,7 @@
# ----------------------------------------------------------------------------
# pyglet
# Copyright (c) 2006-2008 Alex Holkner
# Copyright (c) 2008-2021 pyglet contributors
# Copyright (c) 2008-2022 pyglet contributors
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
@ -34,6 +34,7 @@
# ----------------------------------------------------------------------------
import os
import time
import fcntl
import ctypes
@ -42,12 +43,13 @@ from ctypes import c_int16 as _s16
from ctypes import c_uint32 as _u32
from ctypes import c_int32 as _s32
from ctypes import c_int64 as _s64
from concurrent.futures import ThreadPoolExecutor
import pyglet
from pyglet.app.xlib import XlibSelectDevice
from .base import Device, RelativeAxis, AbsoluteAxis, Button, Joystick, Controller
from .base import DeviceOpenException
from .base import DeviceOpenException, ControllerManager
from .evdev_constants import *
from .controller import get_mapping, Relation
@ -498,14 +500,90 @@ class FFController(Controller):
self.device.ff_upload_effect(self._play_strong_event)
def rumble_stop_weak(self):
"""Stop playing rumble effects on the weak motor."""
self.device.ff_upload_effect(self._stop_weak_event)
def rumble_stop_strong(self):
"""Stop playing rumble effects on the strong motor."""
self.device.ff_upload_effect(self._stop_strong_event)
class EvdevControllerManager(ControllerManager, XlibSelectDevice):
def __init__(self, display=None):
super().__init__()
self._display = display
self._devices_file = open('/proc/bus/input/devices')
self._device_names = self._get_device_names()
self._controllers = {}
self._thread_pool = ThreadPoolExecutor(max_workers=1)
for name in self._device_names:
path = os.path.join('/dev/input', name)
try:
device = EvdevDevice(self._display, path)
except OSError:
continue
controller = _create_controller(device)
if controller:
self._controllers[name] = controller
pyglet.app.platform_event_loop.select_devices.add(self)
def __del__(self):
self._devices_file.close()
def fileno(self):
"""Allow this class to be Selectable"""
return self._devices_file.fileno()
@staticmethod
def _get_device_names():
return {name for name in os.listdir('/dev/input') if name.startswith('event')}
def _make_device_callback(self, future):
name, device = future.result()
if not device:
return
if name in self._controllers:
controller = self._controllers.get(name)
else:
controller = _create_controller(device)
self._controllers[name] = controller
if controller:
self.dispatch_event('on_connect', controller)
def _make_device(self, name, count=1):
path = os.path.join('/dev/input', name)
while count > 0:
try:
return name, EvdevDevice(self._display, path)
except OSError:
if count > 0:
time.sleep(0.1)
count -= 1
return None, None
def select(self):
"""Triggered whenever the devices_file changes."""
new_device_files = self._get_device_names()
appeared = new_device_files - self._device_names
disappeared = self._device_names - new_device_files
self._device_names = new_device_files
for name in appeared:
future = self._thread_pool.submit(self._make_device, name, count=10)
future.add_done_callback(self._make_device_callback)
for name in disappeared:
controller = self._controllers.get(name)
if controller:
self.dispatch_event('on_disconnect', controller)
def get_controllers(self) -> list[Controller]:
return list(self._controllers.values())
def get_devices(display=None):
_devices = {}
base = '/dev/input'
@ -548,8 +626,10 @@ def get_joysticks(display=None):
def _detect_controller_mapping(device):
# detect Controller mapping from the Linux gamepad specification:
# If no explicit mapping is available, we can
# detect it from the Linux gamepad specification:
# https://www.kernel.org/doc/html/v4.13/input/gamepad.html
# Note: legacy device drivers don't always adhere to this.
mapping = dict(guid=device.get_guid(), name=device.name)
_aliases = {BTN_MODE: 'guide', BTN_SELECT: 'back', BTN_START: 'start',

View File

@ -1,7 +1,7 @@
# ----------------------------------------------------------------------------
# pyglet
# Copyright (c) 2006-2008 Alex Holkner
# Copyright (c) 2008-2021 pyglet contributors
# Copyright (c) 2008-2022 pyglet contributors
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without

View File

@ -1,7 +1,7 @@
# ----------------------------------------------------------------------------
# pyglet
# Copyright (c) 2006-2008 Alex Holkner
# Copyright (c) 2008-2021 pyglet contributors
# Copyright (c) 2008-2022 pyglet contributors
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without

View File

@ -1,7 +1,7 @@
# ----------------------------------------------------------------------------
# pyglet
# Copyright (c) 2006-2008 Alex Holkner
# Copyright (c) 2008-2021 pyglet contributors
# Copyright (c) 2008-2022 pyglet contributors
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without

View File

@ -1,7 +1,7 @@
# ----------------------------------------------------------------------------
# pyglet
# Copyright (c) 2006-2008 Alex Holkner
# Copyright (c) 2008-2021 pyglet contributors
# Copyright (c) 2008-2022 pyglet contributors
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without

View File

@ -1,15 +1,21 @@
import time
import ctypes
import weakref
import threading
import pyglet
from pyglet import com
from pyglet.event import EventDispatcher
from pyglet.libs.win32.types import *
from pyglet.input.base import Device, Button, AbsoluteAxis
from pyglet.libs.win32 import _ole32 as ole32, _oleaut32 as oleaut32
from pyglet.libs.win32.constants import CLSCTX_INPROC_SERVER
from pyglet.input.base import Device, Controller, Button, AbsoluteAxis, ControllerManager
lib = pyglet.lib.load_library('xinput1_4')
# TODO Add: xinput1_3 and xinput9_1_0 support
library_name = lib._name
XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE = 7849
@ -39,6 +45,7 @@ XINPUT_GAMEPAD_LEFT_THUMB = 0x0040
XINPUT_GAMEPAD_RIGHT_THUMB = 0x0080
XINPUT_GAMEPAD_LEFT_SHOULDER = 0x0100
XINPUT_GAMEPAD_RIGHT_SHOULDER = 0x0200
XINPUT_GAMEPAD_GUIDE = 0x0400
XINPUT_GAMEPAD_A = 0x1000
XINPUT_GAMEPAD_B = 0x2000
XINPUT_GAMEPAD_X = 0x4000
@ -90,32 +97,20 @@ VK_PAD_RTHUMB_UPRIGHT = 0x5835
VK_PAD_RTHUMB_DOWNRIGHT = 0x5836
VK_PAD_RTHUMB_DOWNLEFT = 0x5837
# /*
# * How many joysticks can be used with this library. Games that
# * use the xinput library will not go over this number.
# */
XUSER_MAX_COUNT = 4
XUSER_MAX_COUNT = 4 # Cannot go over this number.
XUSER_INDEX_ANY = 0x000000FF
# define XUSER_INDEX_ANY 0x000000FF
# define XINPUT_CAPS_FFB_SUPPORTED 0x0001
# define XINPUT_CAPS_WIRELESS 0x0002
# define XINPUT_CAPS_PMD_SUPPORTED 0x0008
# define XINPUT_CAPS_NO_NAVIGATION 0x0010
ERROR_DEVICE_NOT_CONNECTED = 1167
ERROR_EMPTY = 4306
ERROR_SUCCESS = 0
class XINPUT_GAMEPAD(ctypes.Structure):
class XINPUT_GAMEPAD(Structure):
_fields_ = [
('wButtons', WORD),
('bLeftTrigger', BYTE),
('bRightTrigger', BYTE),
('bLeftTrigger', UBYTE),
('bRightTrigger', UBYTE),
('sThumbLX', SHORT),
('sThumbLY', SHORT),
('sThumbRX', SHORT),
@ -123,7 +118,7 @@ class XINPUT_GAMEPAD(ctypes.Structure):
]
class XINPUT_STATE(ctypes.Structure):
class XINPUT_STATE(Structure):
_fields_ = [
('dwPacketNumber', DWORD),
('Gamepad', XINPUT_GAMEPAD)
@ -137,7 +132,7 @@ class XINPUT_VIBRATION(Structure):
]
class XINPUT_CAPABILITIES(ctypes.Structure):
class XINPUT_CAPABILITIES(Structure):
_fields_ = [
('Type', BYTE),
('SubType', BYTE),
@ -154,7 +149,7 @@ class XINPUT_BATTERY_INFORMATION(Structure):
]
class XINPUT_CAPABILITIES_EX(ctypes.Structure):
class XINPUT_CAPABILITIES_EX(Structure):
_fields_ = [
('Capabilities', XINPUT_CAPABILITIES),
('vendorId', WORD),
@ -168,6 +163,10 @@ XInputGetState = lib.XInputGetState
XInputGetState.restype = DWORD
XInputGetState.argtypes = [DWORD, POINTER(XINPUT_STATE)]
XInputGetStateEx = lib[100]
XInputGetStateEx.restype = DWORD
XInputGetStateEx.argtypes = [DWORD, POINTER(XINPUT_STATE)]
XInputSetState = lib.XInputSetState
XInputSetState.argtypes = [DWORD, POINTER(XINPUT_VIBRATION)]
XInputSetState.restype = DWORD
@ -182,9 +181,167 @@ XInputGetCapabilitiesEx.restype = DWORD
XInputGetCapabilitiesEx.argtypes = [DWORD, DWORD, DWORD, POINTER(XINPUT_CAPABILITIES_EX)]
# Only available for 1.4+
XInputGetBatteryInformation = lib.XInputGetBatteryInformation
XInputGetBatteryInformation.argtypes = [DWORD, BYTE, POINTER(XINPUT_BATTERY_INFORMATION)]
XInputGetBatteryInformation.restype = DWORD
if library_name == "xinput1_4":
XInputGetBatteryInformation = lib.XInputGetBatteryInformation
XInputGetBatteryInformation.argtypes = [DWORD, BYTE, POINTER(XINPUT_BATTERY_INFORMATION)]
XInputGetBatteryInformation.restype = DWORD
else:
XInputGetBatteryInformation = None
# wbemcli #################################################
BSTR = LPCWSTR
IWbemContext = c_void_p
RPC_C_AUTHN_WINNT = 10
RPC_C_AUTHZ_NONE = 0
RPC_C_AUTHN_LEVEL_CALL = 0x03
RPC_C_IMP_LEVEL_IMPERSONATE = 3
EOAC_NONE = 0
VT_BSTR = 8
CLSID_WbemLocator = com.GUID(0x4590f811, 0x1d3a, 0x11d0, 0x89, 0x1f, 0x00, 0xaa, 0x00, 0x4b, 0x2e, 0x24)
IID_IWbemLocator = com.GUID(0xdc12a687, 0x737f, 0x11cf, 0x88, 0x4d, 0x00, 0xaa, 0x00, 0x4b, 0x2e, 0x24)
class IWbemClassObject(com.pIUnknown):
_methods_ = [
('GetQualifierSet',
com.STDMETHOD()),
('Get',
com.STDMETHOD(BSTR, LONG, POINTER(VARIANT), c_void_p, c_void_p))
# ... long, unneeded
]
class IEnumWbemClassObject(com.pIUnknown):
_methods_ = [
('Reset',
com.STDMETHOD()),
('Next',
com.STDMETHOD(LONG, ULONG, POINTER(IWbemClassObject), POINTER(ULONG))),
('NextAsync',
com.STDMETHOD()),
('Clone',
com.STDMETHOD()),
('Skip',
com.STDMETHOD())
]
class IWbemServices(com.pIUnknown):
_methods_ = [
('OpenNamespace',
com.STDMETHOD()),
('CancelAsyncCall',
com.STDMETHOD()),
('QueryObjectSink',
com.STDMETHOD()),
('GetObject',
com.STDMETHOD()),
('GetObjectAsync',
com.STDMETHOD()),
('PutClass',
com.STDMETHOD()),
('PutClassAsync',
com.STDMETHOD()),
('DeleteClass',
com.STDMETHOD()),
('DeleteClassAsync',
com.STDMETHOD()),
('CreateClassEnum',
com.STDMETHOD()),
('CreateClassEnumAsync',
com.STDMETHOD()),
('PutInstance',
com.STDMETHOD()),
('PutInstanceAsync',
com.STDMETHOD()),
('DeleteInstance',
com.STDMETHOD()),
('DeleteInstanceAsync',
com.STDMETHOD()),
('CreateInstanceEnum',
com.STDMETHOD(BSTR, LONG, IWbemContext, POINTER(IEnumWbemClassObject))),
('CreateInstanceEnumAsync',
com.STDMETHOD()),
# ... much more.
]
class IWbemLocator(com.pIUnknown):
_methods_ = [
('ConnectServer',
com.STDMETHOD(BSTR, BSTR, BSTR, LONG, LONG, BSTR, IWbemContext, POINTER(IWbemServices))),
]
def get_xinput_guids():
"""We iterate over all devices in the system looking for IG_ in the device ID, which indicates it's an
XInput device. Returns a list of strings containing pid/vid.
Monstrosity found at: https://docs.microsoft.com/en-us/windows/win32/xinput/xinput-and-directinput
"""
ole32.CoInitialize(None)
guids_found = []
locator = IWbemLocator()
services = IWbemServices()
enum_devices = IEnumWbemClassObject()
devices = (IWbemClassObject * 20)()
ole32.CoCreateInstance(CLSID_WbemLocator, None, CLSCTX_INPROC_SERVER, IID_IWbemLocator, byref(locator))
name_space = BSTR("\\\\.\\root\\cimv2")
class_name = BSTR("Win32_PNPEntity")
device_id = BSTR("DeviceID")
# Connect to WMI
hr = locator.ConnectServer(name_space, None, None, 0, 0, None, None, byref(services))
if hr != 0:
return guids_found
# Switch security level to IMPERSONATE.
hr = ole32.CoSetProxyBlanket(services, RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE, None, RPC_C_AUTHN_LEVEL_CALL,
RPC_C_IMP_LEVEL_IMPERSONATE, None, EOAC_NONE)
if hr != 0:
return guids_found
hr = services.CreateInstanceEnum(class_name, 0, None, byref(enum_devices))
if hr != 0:
return guids_found
var = VARIANT()
oleaut32.VariantInit(byref(var))
while True:
returned = ULONG()
_hr = enum_devices.Next(10000, len(devices), devices, byref(returned))
if returned.value == 0:
break
for i in range(returned.value):
result = devices[i].Get(device_id, 0, byref(var), None, None)
if result == 0:
if var.vt == VT_BSTR and var.bstrVal != "":
if 'IG_' in var.bstrVal:
guid = var.bstrVal
pid_start = guid.index("PID_") + 4
dev_pid = guid[pid_start:pid_start + 4]
vid_start = guid.index("VID_") + 4
dev_vid = guid[vid_start:vid_start + 4]
sdl_guid = f"{dev_pid}{dev_vid}".lower()
if sdl_guid not in guids_found:
guids_found.append(sdl_guid)
oleaut32.VariantClear(var)
ole32.CoUninitialize()
return guids_found
# #########################################################
@ -196,6 +353,7 @@ controller_api_to_pyglet = {
XINPUT_GAMEPAD_DPAD_RIGHT: "dpright",
XINPUT_GAMEPAD_START: "start",
XINPUT_GAMEPAD_BACK: "back",
XINPUT_GAMEPAD_GUIDE: "guide",
XINPUT_GAMEPAD_LEFT_THUMB: "leftstick",
XINPUT_GAMEPAD_RIGHT_THUMB: "rightstick",
XINPUT_GAMEPAD_LEFT_SHOULDER: "leftshoulder",
@ -207,91 +365,21 @@ controller_api_to_pyglet = {
}
class XInputManager:
def __init__(self):
self._available_idx = []
self._open_devices = set()
self._devices = [XInputDevice(i, self) for i in range(XUSER_MAX_COUNT)]
self._exit = threading.Event()
self._dev_lock = threading.Lock()
self._thread = threading.Thread(target=self._check_state, daemon=True)
self._thread.start()
def create_device(self):
with self._dev_lock:
try:
index = self._available_idx.pop(0)
return self._devices[index]
except IndexError:
raise IndexError('No available devices')
def open(self, device):
with self._dev_lock:
self._open_devices.add(device)
def close(self, device):
with self._dev_lock:
if device in self._open_devices:
self._open_devices.remove(device)
def _check_state(self):
while not self._exit.is_set():
self._dev_lock.acquire()
for i in range(XUSER_MAX_COUNT):
controller = self._devices[i]
controller.current_state = XINPUT_STATE()
result = XInputGetState(i, byref(controller.current_state))
if result == ERROR_DEVICE_NOT_CONNECTED:
if i in self._available_idx:
self._available_idx.remove(i)
if controller.connected:
print(f"Controller #{controller} was disconnected.")
controller.connected = False
continue
elif result == ERROR_SUCCESS:
if i not in self._available_idx:
self._available_idx.append(i)
if not controller.connected:
controller.connected = True
print(f"Controller #{controller} was connected.")
# Just testing
capabilities = XINPUT_CAPABILITIES_EX()
result = XInputGetCapabilitiesEx(1, i, 0, byref(capabilities))
print(capabilities.vendorId, capabilities.revisionId, capabilities.productId)
# TODO: skip not-open devices
for button, name in controller_api_to_pyglet.items():
controller.controls[name].value = controller.current_state.Gamepad.wButtons & button
controller.controls['lefttrigger'].value = controller.current_state.Gamepad.bLeftTrigger
controller.controls['righttrigger'].value = controller.current_state.Gamepad.bRightTrigger
controller.controls['leftx'].value = controller.current_state.Gamepad.sThumbLX
controller.controls['lefty'].value = controller.current_state.Gamepad.sThumbLY
controller.controls['rightx'].value = controller.current_state.Gamepad.sThumbRX
controller.controls['righty'].value = controller.current_state.Gamepad.sThumbRY
self._dev_lock.release()
time.sleep(0.016)
class XInputDevice(Device):
def __init__(self, index, manager, display=None):
super().__init__(display, f'XInput Controller {index}')
self._manager = weakref.proxy(manager)
def __init__(self, index, manager):
super().__init__(None, f"XInput{index}")
self.index = index
self.current_state = None
self._manager = weakref.proxy(manager)
self.connected = False
self.xinput_state = XINPUT_STATE()
self.packet_number = 0
self.vibration = XINPUT_VIBRATION()
self.weak_duration = None
self.strong_duration = None
self.controls = {
'a': Button('a'),
'b': Button('b'),
@ -299,6 +387,7 @@ class XInputDevice(Device):
'y': Button('y'),
'back': Button('back'),
'start': Button('start'),
'guide': Button('guide'),
'leftshoulder': Button('leftshoulder'),
'rightshoulder': Button('rightshoulder'),
'leftstick': Button('leftstick'),
@ -312,20 +401,235 @@ class XInputDevice(Device):
'lefty': AbsoluteAxis('lefty', -32768, 32768),
'rightx': AbsoluteAxis('rightx', -32768, 32768),
'righty': AbsoluteAxis('righty', -32768, 32768),
'lefttrigger': AbsoluteAxis('lefttrigger', -32768, 32768),
'righttrigger': AbsoluteAxis('righttrigger', -32768, 32768)
'lefttrigger': AbsoluteAxis('lefttrigger', 0, 255),
'righttrigger': AbsoluteAxis('righttrigger', 0, 255)
}
def open(self, window=None, exclusive=False):
super().open(window, exclusive)
self._manager.open(self)
def close(self):
self._manager.close(self)
super().close()
def set_rumble_state(self):
XInputSetState(self.index, byref(self.vibration))
def get_controls(self):
return list(self.controls.values())
def get_guid(self):
return "XINPUTCONTROLLER"
class XInputDeviceManager(EventDispatcher):
def __init__(self):
self.all_devices = [XInputDevice(i, self) for i in range(XUSER_MAX_COUNT)]
self._connected_devices = set()
for i in range(XUSER_MAX_COUNT):
device = self.all_devices[i]
if XInputGetStateEx(i, byref(device.xinput_state)) == ERROR_DEVICE_NOT_CONNECTED:
continue
device.connected = True
self._connected_devices.add(i)
self._polling_rate = 0.016
self._detection_rate = 2.0
self._exit = threading.Event()
self._dev_lock = threading.Lock()
self._thread = threading.Thread(target=self._get_state, daemon=True)
self._thread.start()
def get_devices(self):
with self._dev_lock:
return [dev for dev in self.all_devices if dev.connected]
def _get_state(self):
xuser_max_count = set(range(XUSER_MAX_COUNT)) # {0, 1, 2, 3}
polling_rate = self._polling_rate
detect_rate = self._detection_rate
elapsed = 0.0
while not self._exit.is_set():
self._dev_lock.acquire()
elapsed += polling_rate
# Every few seconds check for new connections:
if elapsed >= detect_rate:
# Only check if not currently connected:
for i in xuser_max_count - self._connected_devices:
device = self.all_devices[i]
if XInputGetStateEx(i, byref(device.xinput_state)) == ERROR_DEVICE_NOT_CONNECTED:
continue
# Found a new connection:
device.connected = True
self._connected_devices.add(i)
self.dispatch_event('on_connect', device)
elapsed = 0.0
# At the set polling rate, update all connected and
# opened devices. Skip unopened devices to save CPU:
for i in self._connected_devices.copy():
device = self.all_devices[i]
result = XInputGetStateEx(i, byref(device.xinput_state))
if result == ERROR_DEVICE_NOT_CONNECTED:
# Newly disconnected device:
if device.connected:
device.connected = False
self._connected_devices.remove(i)
self.dispatch_event('on_disconnect', device)
continue
elif result == ERROR_SUCCESS and device.is_open:
# Stop Rumble effects if a duration is set:
if device.weak_duration:
device.weak_duration -= polling_rate
if device.weak_duration <= 0:
device.weak_duration = None
device.vibration.wRightMotorSpeed = 0
device.set_rumble_state()
if device.strong_duration:
device.strong_duration -= polling_rate
if device.strong_duration <= 0:
device.strong_duration = None
device.vibration.wLeftMotorSpeed = 0
device.set_rumble_state()
# Don't update the Control values if XInput has no new input:
if device.xinput_state.dwPacketNumber == device.packet_number:
continue
for button, name in controller_api_to_pyglet.items():
device.controls[name].value = device.xinput_state.Gamepad.wButtons & button
device.controls['lefttrigger'].value = device.xinput_state.Gamepad.bLeftTrigger
device.controls['righttrigger'].value = device.xinput_state.Gamepad.bRightTrigger
device.controls['leftx'].value = device.xinput_state.Gamepad.sThumbLX
device.controls['lefty'].value = device.xinput_state.Gamepad.sThumbLY
device.controls['rightx'].value = device.xinput_state.Gamepad.sThumbRX
device.controls['righty'].value = device.xinput_state.Gamepad.sThumbRY
device.packet_number = device.xinput_state.dwPacketNumber
self._dev_lock.release()
time.sleep(polling_rate)
def on_connect(self, device):
"""A device was connected."""
def on_disconnect(self, device):
"""A device was disconnected"""
XInputDeviceManager.register_event_type('on_connect')
XInputDeviceManager.register_event_type('on_disconnect')
_device_manager = XInputDeviceManager()
class XInputController(Controller):
def _initialize_controls(self):
for button_name in controller_api_to_pyglet.values():
control = self.device.controls[button_name]
self._button_controls.append(control)
self._add_button(control, button_name)
for axis_name in "leftx", "lefty", "rightx", "righty", "lefttrigger", "righttrigger":
control = self.device.controls[axis_name]
self._axis_controls.append(control)
self._add_axis(control, axis_name)
def _add_axis(self, control, name):
tscale = 1.0 / (control.max - control.min)
scale = 2.0 / (control.max - control.min)
bias = -1.0 - control.min * scale
if name in ("lefttrigger", "righttrigger"):
@control.event
def on_change(value):
normalized_value = value * tscale
setattr(self, name, normalized_value)
self.dispatch_event('on_trigger_motion', self, name, normalized_value)
elif name in ("leftx", "lefty"):
@control.event
def on_change(value):
normalized_value = value * scale + bias
setattr(self, name, normalized_value)
self.dispatch_event('on_stick_motion', self, "leftstick", self.leftx, self.lefty)
elif name in ("rightx", "righty"):
@control.event
def on_change(value):
normalized_value = value * scale + bias
setattr(self, name, normalized_value)
self.dispatch_event('on_stick_motion', self, "rightstick", self.rightx, self.righty)
def _add_button(self, control, name):
if name in ("dpleft", "dpright", "dpup", "dpdown"):
@control.event
def on_change(value):
setattr(self, name, value)
self.dispatch_event('on_dpad_motion', self, self.dpleft, self.dpright, self.dpup, self.dpdown)
else:
@control.event
def on_change(value):
setattr(self, name, value)
@control.event
def on_press():
self.dispatch_event('on_button_press', self, name)
@control.event
def on_release():
self.dispatch_event('on_button_release', self, name)
def rumble_play_weak(self, strength=1.0, duration=0.5):
self.device.vibration.wRightMotorSpeed = int(max(min(1.0, strength), 0) * 0xFFFF)
self.device.weak_duration = duration
self.device.set_rumble_state()
def rumble_play_strong(self, strength=1.0, duration=0.5):
self.device.vibration.wLeftMotorSpeed = int(max(min(1.0, strength), 0) * 0xFFFF)
self.device.strong_duration = duration
self.device.set_rumble_state()
def rumble_stop_weak(self):
self.device.vibration.wRightMotorSpeed = 0
self.device.set_rumble_state()
def rumble_stop_strong(self):
self.device.vibration.wLeftMotorSpeed = 0
self.device.set_rumble_state()
class XInputControllerManager(ControllerManager):
def __init__(self):
self._controllers = {}
for device in _device_manager.all_devices:
meta = {'name': device.name, 'guid': "XINPUTCONTROLLER"}
self._controllers[device] = XInputController(device, meta)
@_device_manager.event
def on_connect(xdevice):
self.dispatch_event('on_connect', self._controllers[xdevice])
@_device_manager.event
def on_disconnect(xdevice):
self.dispatch_event('on_disconnect', self._controllers[xdevice])
def get_controllers(self):
return [ctlr for ctlr in self._controllers.values() if ctlr.device.connected]
def get_devices():
return _device_manager.get_devices()
def get_controllers():
return [XInputController(device, {'name': device.name, 'guid': device.get_guid()}) for device in get_devices()]

View File

@ -1,7 +1,7 @@
# ----------------------------------------------------------------------------
# pyglet
# Copyright (c) 2006-2008 Alex Holkner
# Copyright (c) 2008-2021 pyglet contributors
# Copyright (c) 2008-2022 pyglet contributors
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
@ -162,7 +162,8 @@ class LibraryLoader:
except OSError:
pass
elif self.platform == "win32" and o.winerror != 126:
raise ImportError("Unexpected error loading library %s: %s" % (name, str(o)))
if _debug_lib:
print(f"Unexpected error loading library {name}: {str(o)}")
raise ImportError('Library "%s" not found.' % names[0])

View File

@ -1,7 +1,7 @@
# ----------------------------------------------------------------------------
# pyglet
# Copyright (c) 2006-2008 Alex Holkner
# Copyright (c) 2008-2021 pyglet contributors
# Copyright (c) 2008-2022 pyglet contributors
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without

View File

@ -1,7 +1,7 @@
# ----------------------------------------------------------------------------
# pyglet
# Copyright (c) 2006-2008 Alex Holkner
# Copyright (c) 2008-2021 pyglet contributors
# Copyright (c) 2008-2022 pyglet contributors
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without

View File

@ -1,7 +1,7 @@
# ----------------------------------------------------------------------------
# pyglet
# Copyright (c) 2006-2008 Alex Holkner
# Copyright (c) 2008-2021 pyglet contributors
# Copyright (c) 2008-2022 pyglet contributors
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
@ -91,6 +91,7 @@ _user32 = DebugLibrary(windll.user32)
_dwmapi = DebugLibrary(windll.dwmapi)
_shell32 = DebugLibrary(windll.shell32)
_ole32 = DebugLibrary(windll.ole32)
_oleaut32 = DebugLibrary(windll.oleaut32)
# _gdi32
_gdi32.AddFontMemResourceEx.restype = HANDLE
@ -292,6 +293,8 @@ _shell32.DragQueryPoint.argtypes = [HDROP, LPPOINT]
# ole32
_ole32.CreateStreamOnHGlobal.argtypes = [HGLOBAL, BOOL, LPSTREAM]
_ole32.CoInitialize.restype = HRESULT
_ole32.CoInitialize.argtypes = [LPVOID]
_ole32.CoInitializeEx.restype = HRESULT
_ole32.CoInitializeEx.argtypes = [LPVOID, DWORD]
_ole32.CoUninitialize.restype = HRESULT
@ -300,3 +303,12 @@ _ole32.PropVariantClear.restype = HRESULT
_ole32.PropVariantClear.argtypes = [c_void_p]
_ole32.CoCreateInstance.restype = HRESULT
_ole32.CoCreateInstance.argtypes = [com.REFIID, c_void_p, DWORD, com.REFIID, c_void_p]
_ole32.CoSetProxyBlanket.restype = HRESULT
_ole32.CoSetProxyBlanket.argtypes = (c_void_p, DWORD, DWORD, c_void_p, DWORD, DWORD, c_void_p, DWORD)
# oleaut32
_oleaut32.VariantInit.restype = c_void_p
_oleaut32.VariantInit.argtypes = [c_void_p]
_oleaut32.VariantClear.restype = HRESULT
_oleaut32.VariantClear.argtypes = [c_void_p]

View File

@ -1,7 +1,7 @@
# ----------------------------------------------------------------------------
# pyglet
# Copyright (c) 2006-2008 Alex Holkner
# Copyright (c) 2008-2021 pyglet contributors
# Copyright (c) 2008-2022 pyglet contributors
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
@ -5092,3 +5092,7 @@ CLSCTX_INPROC_SERVER = 0x1
DWM_BB_ENABLE = 0x00000001
DWM_BB_BLURREGION = 0x00000002
DWM_BB_TRANSITIONONMAXIMIZED = 0x00000004
STREAM_SEEK_SET = 0
STREAM_SEEK_CUR = 1
STREAM_SEEK_END = 2

View File

@ -1,7 +1,7 @@
# ----------------------------------------------------------------------------
# pyglet
# Copyright (c) 2006-2008 Alex Holkner
# Copyright (c) 2008-2021 pyglet contributors
# Copyright (c) 2008-2022 pyglet contributors
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without

View File

@ -1,7 +1,7 @@
# ----------------------------------------------------------------------------
# pyglet
# Copyright (c) 2006-2008 Alex Holkner
# Copyright (c) 2008-2021 pyglet contributors
# Copyright (c) 2008-2022 pyglet contributors
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without

View File

@ -1,7 +1,7 @@
# ----------------------------------------------------------------------------
# pyglet
# Copyright (c) 2006-2008 Alex Holkner
# Copyright (c) 2008-2021 pyglet contributors
# Copyright (c) 2008-2022 pyglet contributors
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
@ -35,6 +35,7 @@
import sys
import ctypes
from pyglet import com
from ctypes import *
from ctypes.wintypes import *
@ -82,6 +83,7 @@ def POINTER_(obj):
c_void_p = POINTER_(c_void)
INT = c_int
UBYTE = c_ubyte
LPVOID = c_void_p
HCURSOR = HANDLE
LRESULT = LPARAM
@ -509,6 +511,23 @@ class PROPVARIANT(ctypes.Structure):
('union', _VarTable)
]
class _VarTableVariant(ctypes.Union):
"""Must be in an anonymous union or values will not work across various VT's."""
_fields_ = [
('bstrVal', LPCWSTR)
]
class VARIANT(ctypes.Structure):
_anonymous_ = ['union']
_fields_ = [
('vt', ctypes.c_ushort),
('wReserved1', WORD),
('wReserved2', WORD),
('wReserved3', WORD),
('union', _VarTableVariant)
]
class DWM_BLURBEHIND(ctypes.Structure):
_fields_ = [
@ -517,3 +536,45 @@ class DWM_BLURBEHIND(ctypes.Structure):
("hRgnBlur", HRGN),
("fTransitionOnMaximized", DWORD),
]
class STATSTG(ctypes.Structure):
_fields_ = [
('pwcsName', LPOLESTR),
('type', DWORD),
('cbSize', ULARGE_INTEGER),
('mtime', FILETIME),
('ctime', FILETIME),
('atime', FILETIME),
('grfMode', DWORD),
('grfLocksSupported', DWORD),
('clsid', DWORD),
('grfStateBits', DWORD),
('reserved', DWORD),
]
class IStream(com.pIUnknown):
_methods_ = [
('Read',
com.STDMETHOD(c_void_p, ULONG, POINTER(ULONG))),
('Write',
com.STDMETHOD()),
('Seek',
com.STDMETHOD(LARGE_INTEGER, DWORD, POINTER(ULARGE_INTEGER))),
('SetSize',
com.STDMETHOD()),
('CopyTo',
com.STDMETHOD()),
('Commit',
com.STDMETHOD()),
('Revert',
com.STDMETHOD()),
('LockRegion',
com.STDMETHOD()),
('UnlockRegion',
com.STDMETHOD()),
('Stat',
com.STDMETHOD(POINTER(STATSTG), UINT)),
('Clone',
com.STDMETHOD()),
]

View File

@ -1,7 +1,7 @@
# ----------------------------------------------------------------------------
# pyglet
# Copyright (c) 2006-2008 Alex Holkner
# Copyright (c) 2008-2021 pyglet contributors
# Copyright (c) 2008-2022 pyglet contributors
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without

View File

@ -1,7 +1,7 @@
# ----------------------------------------------------------------------------
# pyglet
# Copyright (c) 2006-2008 Alex Holkner
# Copyright (c) 2008-2021 pyglet contributors
# Copyright (c) 2008-2022 pyglet contributors
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without

Some files were not shown because too many files have changed in this diff Show More