streamdeck 0.9.4__tar.gz → 0.9.6__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (55) hide show
  1. {streamdeck-0.9.4 → streamdeck-0.9.6}/CHANGELOG +10 -0
  2. streamdeck-0.9.6/PKG-INFO +108 -0
  3. {streamdeck-0.9.4 → streamdeck-0.9.6}/README.md +15 -4
  4. streamdeck-0.9.6/VERSION +1 -0
  5. {streamdeck-0.9.4 → streamdeck-0.9.6}/src/StreamDeck/DeviceManager.py +6 -0
  6. {streamdeck-0.9.4 → streamdeck-0.9.6}/src/StreamDeck/Devices/StreamDeck.py +306 -14
  7. {streamdeck-0.9.4 → streamdeck-0.9.6}/src/StreamDeck/Devices/StreamDeckMini.py +14 -3
  8. streamdeck-0.9.6/src/StreamDeck/Devices/StreamDeckNeo.py +212 -0
  9. {streamdeck-0.9.4 → streamdeck-0.9.6}/src/StreamDeck/Devices/StreamDeckOriginal.py +14 -3
  10. {streamdeck-0.9.4 → streamdeck-0.9.6}/src/StreamDeck/Devices/StreamDeckOriginalV2.py +14 -3
  11. {streamdeck-0.9.4 → streamdeck-0.9.6}/src/StreamDeck/Devices/StreamDeckPedal.py +14 -3
  12. streamdeck-0.9.6/src/StreamDeck/Devices/StreamDeckPlus.py +498 -0
  13. {streamdeck-0.9.4 → streamdeck-0.9.6}/src/StreamDeck/Devices/StreamDeckXL.py +14 -3
  14. streamdeck-0.9.6/src/StreamDeck/ImageHelpers/PILHelper.py +253 -0
  15. {streamdeck-0.9.4 → streamdeck-0.9.6}/src/StreamDeck/ProductIDs.py +4 -2
  16. {streamdeck-0.9.4 → streamdeck-0.9.6}/src/StreamDeck/Transport/LibUSBHIDAPI.py +23 -135
  17. {streamdeck-0.9.4 → streamdeck-0.9.6}/src/StreamDeck/Transport/Transport.py +1 -1
  18. {streamdeck-0.9.4 → streamdeck-0.9.6}/src/example_animated.py +2 -2
  19. {streamdeck-0.9.4 → streamdeck-0.9.6}/src/example_basic.py +6 -2
  20. {streamdeck-0.9.4 → streamdeck-0.9.6}/src/example_deckinfo.py +15 -6
  21. streamdeck-0.9.6/src/example_neo.py +170 -0
  22. streamdeck-0.9.6/src/example_plus.py +135 -0
  23. {streamdeck-0.9.4 → streamdeck-0.9.6}/src/example_tileimage.py +2 -2
  24. streamdeck-0.9.6/src/streamdeck.egg-info/PKG-INFO +108 -0
  25. {streamdeck-0.9.4 → streamdeck-0.9.6}/src/streamdeck.egg-info/SOURCES.txt +6 -1
  26. streamdeck-0.9.6/test/test.py +128 -0
  27. streamdeck-0.9.4/PKG-INFO +0 -97
  28. streamdeck-0.9.4/VERSION +0 -1
  29. streamdeck-0.9.4/src/StreamDeck/ImageHelpers/PILHelper.py +0 -108
  30. streamdeck-0.9.4/src/streamdeck.egg-info/PKG-INFO +0 -97
  31. {streamdeck-0.9.4 → streamdeck-0.9.6}/ExampleDeck.jpg +0 -0
  32. {streamdeck-0.9.4 → streamdeck-0.9.6}/LICENSE +0 -0
  33. {streamdeck-0.9.4 → streamdeck-0.9.6}/MANIFEST.in +0 -0
  34. {streamdeck-0.9.4 → streamdeck-0.9.6}/setup.cfg +0 -0
  35. {streamdeck-0.9.4 → streamdeck-0.9.6}/setup.py +0 -0
  36. {streamdeck-0.9.4 → streamdeck-0.9.6}/src/Assets/Apache License 2.0.txt +0 -0
  37. {streamdeck-0.9.4 → streamdeck-0.9.6}/src/Assets/Attribution.txt +0 -0
  38. {streamdeck-0.9.4 → streamdeck-0.9.6}/src/Assets/CC BY-SA 3.0 License.txt +0 -0
  39. {streamdeck-0.9.4 → streamdeck-0.9.6}/src/Assets/CC0 License.txt +0 -0
  40. {streamdeck-0.9.4 → streamdeck-0.9.6}/src/Assets/Elephant_Walking_animated.gif +0 -0
  41. {streamdeck-0.9.4 → streamdeck-0.9.6}/src/Assets/Exit.png +0 -0
  42. {streamdeck-0.9.4 → streamdeck-0.9.6}/src/Assets/Harold.jpg +0 -0
  43. {streamdeck-0.9.4 → streamdeck-0.9.6}/src/Assets/Pressed.png +0 -0
  44. {streamdeck-0.9.4 → streamdeck-0.9.6}/src/Assets/RGB_color_space_animated_view.gif +0 -0
  45. {streamdeck-0.9.4 → streamdeck-0.9.6}/src/Assets/Released.png +0 -0
  46. {streamdeck-0.9.4 → streamdeck-0.9.6}/src/Assets/Roboto-Regular.ttf +0 -0
  47. {streamdeck-0.9.4 → streamdeck-0.9.6}/src/Assets/Simple_CV_Joint_animated.gif +0 -0
  48. {streamdeck-0.9.4 → streamdeck-0.9.6}/src/StreamDeck/Devices/__init__.py +0 -0
  49. {streamdeck-0.9.4 → streamdeck-0.9.6}/src/StreamDeck/ImageHelpers/__init__.py +0 -0
  50. {streamdeck-0.9.4 → streamdeck-0.9.6}/src/StreamDeck/Transport/Dummy.py +0 -0
  51. {streamdeck-0.9.4 → streamdeck-0.9.6}/src/StreamDeck/Transport/__init__.py +0 -0
  52. {streamdeck-0.9.4 → streamdeck-0.9.6}/src/StreamDeck/__init__.py +0 -0
  53. {streamdeck-0.9.4 → streamdeck-0.9.6}/src/example_pedal.py +0 -0
  54. {streamdeck-0.9.4 → streamdeck-0.9.6}/src/streamdeck.egg-info/dependency_links.txt +0 -0
  55. {streamdeck-0.9.4 → streamdeck-0.9.6}/src/streamdeck.egg-info/top_level.txt +0 -0
@@ -1,3 +1,13 @@
1
+ Version 0.9.6:
2
+ - Fixed StreamDeck+ returning 10 key states instead of the expected 8.
3
+ - Fixed StreamDeck+ dial push event not being detected correctly.
4
+ - Fixed old key states and dial states returned if requested from inside a key or dial callback function.
5
+ - Added support for FreeBSD platforms.
6
+ - Added support for the StreamDeck Neo.
7
+
8
+ Version 0.9.5:
9
+ - Added support for the StreamDeck Plus.
10
+
1
11
  Version 0.9.4:
2
12
  - Updated Windows HIDAPI backend to attempt to load from the local working directory.
3
13
  - Added detection for MacOS Homebrew installations of the libhidapi back-end library.
@@ -0,0 +1,108 @@
1
+ Metadata-Version: 2.1
2
+ Name: streamdeck
3
+ Version: 0.9.6
4
+ Summary: Library to control Elgato StreamDeck devices.
5
+ Home-page: https://github.com/abcminiuser/python-elgato-streamdeck
6
+ Author: Dean Camera
7
+ Author-email: dean@fourwalledcubicle.com
8
+ License: MIT
9
+ Requires-Python: >=3.8
10
+ Description-Content-Type: text/markdown
11
+ License-File: LICENSE
12
+
13
+ # Python Elgato Stream Deck Library
14
+
15
+ ![Example Deck](ExampleDeck.jpg)
16
+
17
+ This is an open source Python 3 library to control an
18
+ [Elgato Stream Deck](https://www.elgato.com/en/gaming/stream-deck) directly,
19
+ without the official software. This can allow you to create your own custom
20
+ front-ends, such as a custom control front-end for home automation software.
21
+
22
+ _________________
23
+
24
+ [PyPi Project Entry](https://pypi.org/project/streamdeck/) - [Online Documentation](https://python-elgato-streamdeck.readthedocs.io) - [Source Code](https://github.com/abcminiuser/python-elgato-streamdeck)
25
+
26
+
27
+ ## Project Status:
28
+
29
+ Working - you can enumerate devices, set the brightness of the panel(s), set
30
+ the images shown on each button, and read the current button states.
31
+
32
+ Currently the following StreamDeck products are supported in multiple hardware
33
+ variants:
34
+
35
+ * StreamDeck Mini
36
+ * StreamDeck Neo
37
+ * StreamDeck Original
38
+ * StreamDeck Pedal
39
+ * StreamDeck Plus
40
+ * StreamDeck XL
41
+
42
+ ## Package Installation:
43
+
44
+ Install the library via pip:
45
+
46
+ ```
47
+ pip install streamdeck
48
+ ```
49
+
50
+ Alternatively, manually clone the project repository:
51
+
52
+ ```
53
+ git clone https://github.com/abcminiuser/python-elgato-streamdeck.git
54
+ ```
55
+
56
+ For detailed installation instructions, refer to the prebuilt
57
+ [online documentation](https://python-elgato-streamdeck.readthedocs.io), or
58
+ build the documentation yourself locally by running `make html` from the `docs`
59
+ directory.
60
+
61
+
62
+ ## Credits:
63
+
64
+ I've used the reverse engineering notes from
65
+ [this GitHub](https://github.com/alvancamp/node-elgato-stream-deck/blob/master/NOTES.md)
66
+ repository to implement this library. Thanks Alex Van Camp!
67
+
68
+ Thank you to the following contributors, large and small, for helping with the
69
+ development and maintenance of this library:
70
+
71
+ - [admiral0](https://github.com/admiral0)
72
+ - [Aetherdyne](https://github.com/Aetherdyne)
73
+ - [benedikt-bartscher](https://github.com/benedikt-bartscher)
74
+ - [brimston3](https://github.com/brimston3)
75
+ - [BS-Tek](https://github.com/BS-Tek)
76
+ - [Core447](https://github.com/Core447)
77
+ - [dirkk0](https://github.com/dirkk0)
78
+ - [dodgyrabbit](https://github.com/dodgyrabbit)
79
+ - [dubstech](https://github.com/dubstech)
80
+ - [Giraut](https://github.com/Giraut)
81
+ - [impala454](https://github.com/impala454)
82
+ - [itsusony](https://github.com/itsusony)
83
+ - [jakobbuis](https://github.com/jakobbuis)
84
+ - [jmudge14](https://github.com/jmudge14)
85
+ - [Kalle-Wirsch](https://github.com/Kalle-Wirsch)
86
+ - [karstlok](https://github.com/karstlok)
87
+ - [Lewiscowles1986](https://github.com/Lewiscowles1986)
88
+ - [m-weigand](https://github.com/m-weigand)
89
+ - [matrixinius](https://github.com/matrixinius)
90
+ - [phillco](https://github.com/phillco)
91
+ - [pointshader](https://github.com/pointshader)
92
+ - [shanna](https://github.com/shanna)
93
+ - [spidererrol](https://github.com/Spidererrol)
94
+ - [spyoungtech](https://github.com/spyoungtech)
95
+ - [Subsentient](https://github.com/Subsentient)
96
+ - [swedishmike](https://github.com/swedishmike)
97
+ - [TheSchmidt](https://github.com/TheSchmidt)
98
+ - [theslimshaney](https://github.com/theslimshaney)
99
+ - [tjemg](https://github.com/tjemg)
100
+ - [VladFlorinIlie](https://github.com/VladFlorinIlie)
101
+
102
+ If you've contributed in some manner, but I've accidentally missed you in the
103
+ list above, please let me know.
104
+
105
+
106
+ ## License:
107
+
108
+ Released under the [MIT license](LICENSE).
@@ -20,11 +20,12 @@ the images shown on each button, and read the current button states.
20
20
  Currently the following StreamDeck products are supported in multiple hardware
21
21
  variants:
22
22
 
23
- * StreamDeck Original
24
23
  * StreamDeck Mini
25
- * StreamDeck XL
24
+ * StreamDeck Neo
25
+ * StreamDeck Original
26
26
  * StreamDeck Pedal
27
-
27
+ * StreamDeck Plus
28
+ * StreamDeck XL
28
29
 
29
30
  ## Package Installation:
30
31
 
@@ -49,21 +50,28 @@ directory.
49
50
  ## Credits:
50
51
 
51
52
  I've used the reverse engineering notes from
52
- [this GitHub](https://github.com/Lange/node-elgato-stream-deck/blob/master/NOTES.md)
53
+ [this GitHub](https://github.com/alvancamp/node-elgato-stream-deck/blob/master/NOTES.md)
53
54
  repository to implement this library. Thanks Alex Van Camp!
54
55
 
55
56
  Thank you to the following contributors, large and small, for helping with the
56
57
  development and maintenance of this library:
57
58
 
59
+ - [admiral0](https://github.com/admiral0)
58
60
  - [Aetherdyne](https://github.com/Aetherdyne)
61
+ - [benedikt-bartscher](https://github.com/benedikt-bartscher)
62
+ - [brimston3](https://github.com/brimston3)
59
63
  - [BS-Tek](https://github.com/BS-Tek)
64
+ - [Core447](https://github.com/Core447)
60
65
  - [dirkk0](https://github.com/dirkk0)
61
66
  - [dodgyrabbit](https://github.com/dodgyrabbit)
62
67
  - [dubstech](https://github.com/dubstech)
68
+ - [Giraut](https://github.com/Giraut)
63
69
  - [impala454](https://github.com/impala454)
70
+ - [itsusony](https://github.com/itsusony)
64
71
  - [jakobbuis](https://github.com/jakobbuis)
65
72
  - [jmudge14](https://github.com/jmudge14)
66
73
  - [Kalle-Wirsch](https://github.com/Kalle-Wirsch)
74
+ - [karstlok](https://github.com/karstlok)
67
75
  - [Lewiscowles1986](https://github.com/Lewiscowles1986)
68
76
  - [m-weigand](https://github.com/m-weigand)
69
77
  - [matrixinius](https://github.com/matrixinius)
@@ -74,7 +82,10 @@ development and maintenance of this library:
74
82
  - [spyoungtech](https://github.com/spyoungtech)
75
83
  - [Subsentient](https://github.com/Subsentient)
76
84
  - [swedishmike](https://github.com/swedishmike)
85
+ - [TheSchmidt](https://github.com/TheSchmidt)
77
86
  - [theslimshaney](https://github.com/theslimshaney)
87
+ - [tjemg](https://github.com/tjemg)
88
+ - [VladFlorinIlie](https://github.com/VladFlorinIlie)
78
89
 
79
90
  If you've contributed in some manner, but I've accidentally missed you in the
80
91
  list above, please let me know.
@@ -0,0 +1 @@
1
+ 0.9.6
@@ -6,10 +6,12 @@
6
6
  #
7
7
 
8
8
  from .Devices.StreamDeckMini import StreamDeckMini
9
+ from .Devices.StreamDeckNeo import StreamDeckNeo
9
10
  from .Devices.StreamDeckOriginal import StreamDeckOriginal
10
11
  from .Devices.StreamDeckOriginalV2 import StreamDeckOriginalV2
11
12
  from .Devices.StreamDeckXL import StreamDeckXL
12
13
  from .Devices.StreamDeckPedal import StreamDeckPedal
14
+ from .Devices.StreamDeckPlus import StreamDeckPlus
13
15
  from .Transport.Dummy import Dummy
14
16
  from .Transport.LibUSBHIDAPI import LibUSBHIDAPI
15
17
  from .ProductIDs import USBVendorIDs, USBProductIDs
@@ -35,9 +37,11 @@ class DeviceManager:
35
37
  USB_PID_STREAMDECK_ORIGINAL = 0x0060
36
38
  USB_PID_STREAMDECK_ORIGINAL_V2 = 0x006d
37
39
  USB_PID_STREAMDECK_MINI = 0x0063
40
+ USB_PID_STREAMDECK_NEO = 0x009a
38
41
  USB_PID_STREAMDECK_XL = 0x006c
39
42
  USB_PID_STREAMDECK_MK2 = 0x0080
40
43
  USB_PID_STREAMDECK_PEDAL = 0x0086
44
+ USB_PID_STREAMDECK_PLUS = 0x0084
41
45
 
42
46
  @staticmethod
43
47
  def _get_transport(transport):
@@ -103,11 +107,13 @@ class DeviceManager:
103
107
  (USBVendorIDs.USB_VID_ELGATO, USBProductIDs.USB_PID_STREAMDECK_ORIGINAL, StreamDeckOriginal),
104
108
  (USBVendorIDs.USB_VID_ELGATO, USBProductIDs.USB_PID_STREAMDECK_ORIGINAL_V2, StreamDeckOriginalV2),
105
109
  (USBVendorIDs.USB_VID_ELGATO, USBProductIDs.USB_PID_STREAMDECK_MINI, StreamDeckMini),
110
+ (USBVendorIDs.USB_VID_ELGATO, USBProductIDs.USB_PID_STREAMDECK_NEO, StreamDeckNeo),
106
111
  (USBVendorIDs.USB_VID_ELGATO, USBProductIDs.USB_PID_STREAMDECK_XL, StreamDeckXL),
107
112
  (USBVendorIDs.USB_VID_ELGATO, USBProductIDs.USB_PID_STREAMDECK_MK2, StreamDeckOriginalV2),
108
113
  (USBVendorIDs.USB_VID_ELGATO, USBProductIDs.USB_PID_STREAMDECK_PEDAL, StreamDeckPedal),
109
114
  (USBVendorIDs.USB_VID_ELGATO, USBProductIDs.USB_PID_STREAMDECK_MINI_MK2, StreamDeckMini),
110
115
  (USBVendorIDs.USB_VID_ELGATO, USBProductIDs.USB_PID_STREAMDECK_XL_V2, StreamDeckXL),
116
+ (USBVendorIDs.USB_VID_ELGATO, USBProductIDs.USB_PID_STREAMDECK_PLUS, StreamDeckPlus),
111
117
  ]
112
118
 
113
119
  streamdecks = list()
@@ -8,10 +8,41 @@
8
8
  import threading
9
9
  import time
10
10
  from abc import ABC, abstractmethod
11
+ from enum import Enum
11
12
 
12
13
  from ..Transport.Transport import TransportError
13
14
 
14
15
 
16
+ class TouchscreenEventType(Enum):
17
+ """
18
+ Type of event that has occurred for a Touchscreen.
19
+ """
20
+
21
+ SHORT = 1
22
+ LONG = 2
23
+ DRAG = 3
24
+
25
+
26
+ class DialEventType(Enum):
27
+ """
28
+ Type of event that has occurred for a Dial.
29
+ """
30
+ TURN = 1
31
+ PUSH = 2
32
+
33
+
34
+ class ControlType(Enum):
35
+ """
36
+ Type of control. This is used when returning internal events from a
37
+ StreamDeck subclass.
38
+
39
+ :meta private:
40
+ """
41
+ KEY = 1
42
+ DIAL = 2
43
+ TOUCHSCREEN = 3
44
+
45
+
15
46
  class StreamDeck(ABC):
16
47
  """
17
48
  Represents a physically attached StreamDeck device.
@@ -21,22 +52,43 @@ class StreamDeck(ABC):
21
52
  KEY_COLS = 0
22
53
  KEY_ROWS = 0
23
54
 
55
+ TOUCH_KEY_COUNT = 0
56
+
24
57
  KEY_PIXEL_WIDTH = 0
25
58
  KEY_PIXEL_HEIGHT = 0
26
59
  KEY_IMAGE_FORMAT = ""
27
60
  KEY_FLIP = (False, False)
28
61
  KEY_ROTATION = 0
29
62
 
63
+ TOUCHSCREEN_PIXEL_WIDTH = 0
64
+ TOUCHSCREEN_PIXEL_HEIGHT = 0
65
+ TOUCHSCREEN_IMAGE_FORMAT = ""
66
+ TOUCHSCREEN_FLIP = (False, False)
67
+ TOUCHSCREEN_ROTATION = 0
68
+
69
+ SCREEN_PIXEL_WIDTH = 0
70
+ SCREEN_PIXEL_HEIGHT = 0
71
+ SCREEN_IMAGE_FORMAT = ""
72
+ SCREEN_FLIP = (False, False)
73
+ SCREEN_ROTATION = 0
74
+
75
+ DIAL_COUNT = 0
76
+
30
77
  DECK_TYPE = ""
31
78
  DECK_VISUAL = False
79
+ DECK_TOUCH = False
32
80
 
33
81
  def __init__(self, device):
34
82
  self.device = device
35
- self.last_key_states = [False] * self.KEY_COUNT
83
+ self.last_key_states = [False] * (self.KEY_COUNT + self.TOUCH_KEY_COUNT)
84
+ self.last_dial_states = [False] * self.DIAL_COUNT
36
85
  self.read_thread = None
37
86
  self.run_read_thread = False
38
87
  self.read_poll_hz = 20
88
+
39
89
  self.key_callback = None
90
+ self.dial_callback = None
91
+ self.touchscreen_callback = None
40
92
 
41
93
  self.update_lock = threading.RLock()
42
94
 
@@ -72,12 +124,11 @@ class StreamDeck(ABC):
72
124
  self.update_lock.release()
73
125
 
74
126
  @abstractmethod
75
- def _read_key_states(self):
127
+ def _read_control_states(self):
76
128
  """
77
129
  Reads the raw key states from an attached StreamDeck.
78
130
 
79
- :rtype: list(bool)
80
- :return: List containing the raw key states.
131
+ :return: dictionary containing states for all controls
81
132
  """
82
133
  pass
83
134
 
@@ -101,24 +152,51 @@ class StreamDeck(ABC):
101
152
 
102
153
  def _read(self):
103
154
  """
104
- Read handler for the underlying transport, listening for button state
155
+ Read handler for the underlying transport, listening for control state
105
156
  changes on the underlying device, caching the new states and firing off
106
157
  any registered callbacks.
107
158
  """
108
159
  while self.run_read_thread:
109
160
  try:
110
- new_key_states = self._read_key_states()
111
- if new_key_states is None:
161
+ control_states = self._read_control_states()
162
+ if control_states is None:
112
163
  time.sleep(1.0 / self.read_poll_hz)
113
164
  continue
114
165
 
115
- if self.key_callback is not None:
116
- for k, (old, new) in enumerate(zip(self.last_key_states, new_key_states)):
117
- if old != new:
166
+ if ControlType.KEY in control_states:
167
+ for k, (old, new) in enumerate(zip(self.last_key_states, control_states[ControlType.KEY])):
168
+ if old == new:
169
+ continue
170
+
171
+ self.last_key_states[k] = new
172
+
173
+ if self.key_callback is not None:
118
174
  self.key_callback(self, k, new)
119
175
 
120
- self.last_key_states = new_key_states
121
- except (TransportError):
176
+ elif ControlType.DIAL in control_states:
177
+ if DialEventType.PUSH in control_states[ControlType.DIAL]:
178
+ for k, (old, new) in enumerate(zip(self.last_dial_states, control_states[ControlType.DIAL][DialEventType.PUSH])):
179
+ if old == new:
180
+ continue
181
+
182
+ self.last_dial_states[k] = new
183
+
184
+ if self.dial_callback is not None:
185
+ self.dial_callback(self, k, DialEventType.PUSH, new)
186
+
187
+ if DialEventType.TURN in control_states[ControlType.DIAL]:
188
+ for k, amount in enumerate(control_states[ControlType.DIAL][DialEventType.TURN]):
189
+ if amount == 0:
190
+ continue
191
+
192
+ if self.dial_callback is not None:
193
+ self.dial_callback(self, k, DialEventType.TURN, amount)
194
+
195
+ elif ControlType.TOUCHSCREEN in control_states:
196
+ if self.touchscreen_callback is not None:
197
+ self.touchscreen_callback(self, *control_states[ControlType.TOUCHSCREEN])
198
+
199
+ except TransportError:
122
200
  self.run_read_thread = False
123
201
  self.close()
124
202
 
@@ -223,12 +301,30 @@ class StreamDeck(ABC):
223
301
  """
224
302
  return self.KEY_COUNT
225
303
 
304
+ def touch_key_count(self):
305
+ """
306
+ Retrieves number of touch buttons on the attached StreamDeck device.
307
+
308
+ :rtype: int
309
+ :return: Number of touch buttons.
310
+ """
311
+ return self.TOUCH_KEY_COUNT
312
+
313
+ def dial_count(self):
314
+ """
315
+ Retrieves number of physical dials on the attached StreamDeck device.
316
+
317
+ :rtype: int
318
+ :return: Number of physical dials
319
+ """
320
+ return self.DIAL_COUNT
321
+
226
322
  def deck_type(self):
227
323
  """
228
324
  Retrieves the model of Stream Deck.
229
325
 
230
326
  :rtype: str
231
- :return: String containing the model name of the StreamDeck device..
327
+ :return: String containing the model name of the StreamDeck device.
232
328
  """
233
329
  return self.DECK_TYPE
234
330
 
@@ -241,6 +337,15 @@ class StreamDeck(ABC):
241
337
  """
242
338
  return self.DECK_VISUAL
243
339
 
340
+ def is_touch(self):
341
+ """
342
+ Returns whether the Stream Deck can receive touch events
343
+
344
+ :rtype: bool
345
+ :return: `True` if the deck can receive touch events, `False` otherwise
346
+ """
347
+ return self.DECK_TOUCH
348
+
244
349
  def key_layout(self):
245
350
  """
246
351
  Retrieves the physical button layout on the attached StreamDeck device.
@@ -269,6 +374,46 @@ class StreamDeck(ABC):
269
374
  'rotation': self.KEY_ROTATION,
270
375
  }
271
376
 
377
+ def touchscreen_image_format(self):
378
+ """
379
+ Retrieves the image format accepted by the touchscreen of the Stream
380
+ Deck. Images should be given in this format when drawing on
381
+ touchscreen.
382
+
383
+ .. seealso:: See :func:`~StreamDeck.set_touchscreen_image` method to
384
+ draw an image on the StreamDeck touchscreen.
385
+
386
+ :rtype: dict()
387
+ :return: Dictionary describing the various image parameters
388
+ (size, image format).
389
+ """
390
+ return {
391
+ 'size': (self.TOUCHSCREEN_PIXEL_WIDTH, self.TOUCHSCREEN_PIXEL_HEIGHT),
392
+ 'format': self.TOUCHSCREEN_IMAGE_FORMAT,
393
+ 'flip': self.TOUCHSCREEN_FLIP,
394
+ 'rotation': self.TOUCHSCREEN_ROTATION,
395
+ }
396
+
397
+ def screen_image_format(self):
398
+ """
399
+ Retrieves the image format accepted by the screen of the Stream
400
+ Deck. Images should be given in this format when drawing on
401
+ screen.
402
+
403
+ .. seealso:: See :func:`~StreamDeck.set_screen_image` method to
404
+ draw an image on the StreamDeck screen.
405
+
406
+ :rtype: dict()
407
+ :return: Dictionary describing the various image parameters
408
+ (size, image format).
409
+ """
410
+ return {
411
+ 'size': (self.SCREEN_PIXEL_WIDTH, self.SCREEN_PIXEL_HEIGHT),
412
+ 'format': self.SCREEN_IMAGE_FORMAT,
413
+ 'flip': self.SCREEN_FLIP,
414
+ 'rotation': self.SCREEN_ROTATION,
415
+ }
416
+
272
417
  def set_poll_frequency(self, hz):
273
418
  """
274
419
  Sets the frequency of the button polling reader thread, determining how
@@ -325,6 +470,94 @@ class StreamDeck(ABC):
325
470
 
326
471
  self.set_key_callback(callback)
327
472
 
473
+ def set_dial_callback(self, callback):
474
+ """
475
+ Sets the callback function called each time there is an interaction
476
+ with a dial on the StreamDeck.
477
+
478
+ .. note:: This callback will be fired from an internal reader thread.
479
+ Ensure that the given callback function is thread-safe.
480
+
481
+ .. note:: Only one callback can be registered at one time.
482
+
483
+ .. seealso:: See :func:`~StreamDeck.set_dial_callback_async` method
484
+ for a version compatible with Python 3 `asyncio`
485
+ asynchronous functions.
486
+
487
+ :param function callback: Callback function to fire each time a button
488
+ state changes.
489
+ """
490
+ self.dial_callback = callback
491
+
492
+ def set_dial_callback_async(self, async_callback, loop=None):
493
+ """
494
+ Sets the asynchronous callback function called each time there is an
495
+ interaction with a dial on the StreamDeck. The given callback should
496
+ be compatible with Python 3's `asyncio` routines.
497
+
498
+ .. note:: The asynchronous callback will be fired in a thread-safe
499
+ manner.
500
+
501
+ .. note:: This will override the callback (if any) set by
502
+ :func:`~StreamDeck.set_dial_callback`.
503
+
504
+ :param function async_callback: Asynchronous callback function to fire
505
+ each time a button state changes.
506
+ :param asyncio.loop loop: Asyncio loop to dispatch the callback into
507
+ """
508
+ import asyncio
509
+
510
+ loop = loop or asyncio.get_event_loop()
511
+
512
+ def callback(*args):
513
+ asyncio.run_coroutine_threadsafe(async_callback(*args), loop)
514
+
515
+ self.set_dial_callback(callback)
516
+
517
+ def set_touchscreen_callback(self, callback):
518
+ """
519
+ Sets the callback function called each time there is an interaction
520
+ with a touchscreen on the StreamDeck.
521
+
522
+ .. note:: This callback will be fired from an internal reader thread.
523
+ Ensure that the given callback function is thread-safe.
524
+
525
+ .. note:: Only one callback can be registered at one time.
526
+
527
+ .. seealso:: See :func:`~StreamDeck.set_touchscreen_callback_async`
528
+ method for a version compatible with Python 3 `asyncio`
529
+ asynchronous functions.
530
+
531
+ :param function callback: Callback function to fire each time a button
532
+ state changes.
533
+ """
534
+ self.touchscreen_callback = callback
535
+
536
+ def set_touchscreen_callback_async(self, async_callback, loop=None):
537
+ """
538
+ Sets the asynchronous callback function called each time there is an
539
+ interaction with the touchscreen on the StreamDeck. The given callback
540
+ should be compatible with Python 3's `asyncio` routines.
541
+
542
+ .. note:: The asynchronous callback will be fired in a thread-safe
543
+ manner.
544
+
545
+ .. note:: This will override the callback (if any) set by
546
+ :func:`~StreamDeck.set_touchscreen_callback`.
547
+
548
+ :param function async_callback: Asynchronous callback function to fire
549
+ each time a button state changes.
550
+ :param asyncio.loop loop: Asyncio loop to dispatch the callback into
551
+ """
552
+ import asyncio
553
+
554
+ loop = loop or asyncio.get_event_loop()
555
+
556
+ def callback(*args):
557
+ asyncio.run_coroutine_threadsafe(async_callback(*args), loop)
558
+
559
+ self.set_touchscreen_callback(callback)
560
+
328
561
  def key_states(self):
329
562
  """
330
563
  Retrieves the current states of the buttons on the StreamDeck.
@@ -336,6 +569,18 @@ class StreamDeck(ABC):
336
569
  """
337
570
  return self.last_key_states
338
571
 
572
+ def dial_states(self):
573
+ """
574
+ Retrieves the current states of the dials (pressed or not) on the
575
+ Stream Deck
576
+
577
+ :rtype: list(bool)
578
+ :return: List describing the current states of each of the dials on
579
+ the device (`True` if the dial is being pressed, `False`
580
+ otherwise).
581
+ """
582
+ return self.last_dial_states
583
+
339
584
  @abstractmethod
340
585
  def reset(self):
341
586
  """
@@ -382,7 +627,7 @@ class StreamDeck(ABC):
382
627
  image being set should be in the correct format for the device, as an
383
628
  enumerable collection of bytes.
384
629
 
385
- .. seealso:: See :func:`~StreamDeck.get_key_image_format` method for
630
+ .. seealso:: See :func:`~StreamDeck.key_image_format` method for
386
631
  information on the image format accepted by the device.
387
632
 
388
633
  :param int key: Index of the button whose image is to be updated.
@@ -391,3 +636,50 @@ class StreamDeck(ABC):
391
636
  color.
392
637
  """
393
638
  pass
639
+
640
+ @abstractmethod
641
+ def set_touchscreen_image(self, image, x_pos=0, y_pos=0, width=0, height=0):
642
+ """
643
+ Draws an image on the touchscreen in a certain position. The image
644
+ should be in the correct format for the devices, as an enumerable
645
+ collection of bytes.
646
+
647
+ .. seealso:: See :func:`~StreamDeck.touchscreen_image_format` method for
648
+ information on the image format accepted by the device.
649
+
650
+ :param enumerable image: Raw data of the image to set on the button.
651
+ If `None`, the touchscreen will be cleared.
652
+ :param int x_pos: Position on x axis of the image to draw
653
+ :param int y_pos: Position on y axis of the image to draw
654
+ :param int width: width of the image
655
+ :param int height: height of the image
656
+
657
+ """
658
+ pass
659
+
660
+ @abstractmethod
661
+ def set_key_color(self, key, r, g, b):
662
+ """
663
+ Sets the color of the touch buttons. These buttons are indexed
664
+ in order after the standard keys.
665
+
666
+ :param int key: Index of the button
667
+ :param int r: Red value
668
+ :param int g: Green value
669
+ :param int b: Blue value
670
+
671
+ """
672
+ pass
673
+
674
+ @abstractmethod
675
+ def set_screen_image(self, image):
676
+ """
677
+ Draws an image on the touchless screen of the StreamDeck.
678
+
679
+ .. seealso:: See :func:`~StreamDeck.screen_image_format` method for
680
+ information on the image format accepted by the device.
681
+
682
+ :param enumerable image: Raw data of the image to set on the button.
683
+ If `None`, the screen will be cleared.
684
+ """
685
+ pass
@@ -5,7 +5,7 @@
5
5
  # www.fourwalledcubicle.com
6
6
  #
7
7
 
8
- from .StreamDeck import StreamDeck
8
+ from .StreamDeck import StreamDeck, ControlType
9
9
  from ..ProductIDs import USBProductIDs
10
10
 
11
11
 
@@ -42,13 +42,15 @@ class StreamDeckMini(StreamDeck):
42
42
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00
43
43
  ] + [0] * (KEY_PIXEL_WIDTH * KEY_PIXEL_HEIGHT * 3)
44
44
 
45
- def _read_key_states(self):
45
+ def _read_control_states(self):
46
46
  states = self.device.read(1 + self.KEY_COUNT)
47
47
  if states is None:
48
48
  return None
49
49
 
50
50
  states = states[1:]
51
- return [bool(s) for s in states]
51
+ return {
52
+ ControlType.KEY: [bool(s) for s in states],
53
+ }
52
54
 
53
55
  def _reset_key_stream(self):
54
56
  payload = bytearray(self.IMAGE_REPORT_LENGTH)
@@ -116,3 +118,12 @@ class StreamDeckMini(StreamDeck):
116
118
 
117
119
  bytes_remaining = bytes_remaining - this_length
118
120
  page_number = page_number + 1
121
+
122
+ def set_touchscreen_image(self, image, x_pos=0, y_pos=0, width=0, height=0):
123
+ pass
124
+
125
+ def set_key_color(self, key, r, g, b):
126
+ pass
127
+
128
+ def set_screen_image(self, image):
129
+ pass