Merge branch 'main' of https://github.com/shenjackyuanjie/Difficult-Rocket into main
ruaaaa
This commit is contained in:
commit
327fe5f324
@ -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)
|
||||
# 设置刷新率
|
||||
|
@ -57,6 +57,7 @@ command_tree = {
|
||||
}
|
||||
}
|
||||
}
|
||||
# TODO 给爷做了他
|
||||
|
||||
|
||||
class CommandTree:
|
||||
|
@ -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)
|
@ -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
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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))
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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():
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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')
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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))
|
||||
|
@ -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',
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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()]
|
||||
|
@ -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])
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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]
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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()),
|
||||
]
|
||||
|
@ -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
|
||||
|
@ -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
Loading…
Reference in New Issue
Block a user