top of page

TwitchPlays.py

for Python 2.7

[ published on 2019-10-31 ]

  1. # Written by DougDoug (DougDoug on Youtube, DougDougW on Twitch)

  2. ​

  3. # Hello!

  4. # This file contains the main logic to process Twitch chat and convert it to game commands.

  5. # All sections that you need to update are labeled with a "TODO" comment.

  6. # The source code primarily comes from:

  7.     # Wituz's "Twitch Plays" tutorial: http://www.wituz.com/make-your-own-twitch-plays-stream.html

  8.     # PythonProgramming's "Python Plays GTA V" tutorial: https://pythonprogramming.net/direct-input-game-python-plays-gta-v/

  9. ​

  10. # There are 2 other files needed to run this code:

  11.     # TwitchPlays_AccountInfo.py is where you put your Twitch username and OAuth token. This is to keep your account details separated from the main source code.

  12.     # TwitchPlays_Connection.py is the code that actually connects to Twitch. You should not modify this file.

  13. ​

  14. # Disclaimer: 

  15.     # This code is NOT optimized or well-organized. I am not a Python programmer.

  16.     # I created a simple version that works quickly, and I'm sharing it for educational purposes.

  17. ​

  18. ###############################################

  19. # Import and define our functions / key codes to send key commands

  20. ​

  21. # General imports

  22. import time

  23. import subprocess

  24. import ctypes

  25. import random

  26. import string

  27. ​

  28. # Twitch imports

  29. import TwitchPlays_Connection

  30. from TwitchPlays_AccountInfo import TWITCH_USERNAME, TWITCH_OAUTH_TOKEN

  31. ​

  32. # Controller imports

  33. import pyautogui

  34. import pynput

  35. from pynput.mouse import Button, Controller

  36. ​

  37. SendInput = ctypes.windll.user32.SendInput

  38. ​

  39. # KEY PRESS NOTES

  40. # The standard "Twitch Plays" tutorial key commands do NOT work in DirectX games (they only work in general windows applications)

  41. # Instead, we use DirectX key codes and input functions below.

  42. # This DirectX code is partially sourced from: https://stackoverflow.com/questions/53643273/how-to-keep-pynput-and-ctypes-from-clashing

  43. ​

  44. # Presses and permanently holds down a keyboard key

  45. def PressKeyPynput(hexKeyCode):

  46.     extra = ctypes.c_ulong(0)

  47.     ii_ = pynput._util.win32.INPUT_union()

  48.     ii_.ki = pynput._util.win32.KEYBDINPUT(0, hexKeyCode, 0x0008, 0, ctypes.cast(ctypes.pointer(extra), ctypes.c_void_p))

  49.     x = pynput._util.win32.INPUT(ctypes.c_ulong(1), ii_)

  50.     SendInput(1, ctypes.pointer(x), ctypes.sizeof(x))

  51. ​

  52. # Releases a keyboard key if it is currently pressed down

  53. def ReleaseKeyPynput(hexKeyCode):

  54.     extra = ctypes.c_ulong(0)

  55.     ii_ = pynput._util.win32.INPUT_union()

  56.     ii_.ki = pynput._util.win32.KEYBDINPUT(0, hexKeyCode, 0x0008 | 0x0002, 0, ctypes.cast(ctypes.pointer(extra), ctypes.c_void_p))

  57.     x = pynput._util.win32.INPUT(ctypes.c_ulong(1), ii_)

  58.     SendInput(1, ctypes.pointer(x), ctypes.sizeof(x))

  59. ​

  60. # Helper function. Holds down a key for the specified number of seconds, then releases it.

  61. def PressAndHoldKey(hexKeyCode, seconds):

  62.     PressKeyPynput(hexKeyCode)

  63.     time.sleep(seconds)

  64.     ReleaseKeyPynput(hexKeyCode)

  65. ​

  66. # Mouse Controller, using pynput

  67.     # pynput.mouse functions are found at: https://pypi.org/project/pynput/

  68.     # NOTE: pyautogui's click() function permanently holds down in DirectX, so I used pynput instead for mouse instead.

  69. mouse = Controller()

  70. ​

  71. ###############################################

  72. # DIRECTX KEY CODES

  73. # These codes identify each key on the keyboard.

  74. # Note that DirectX's key codes (or "scan codes") are NOT the same as Windows virtual hex key codes. 

  75. #   DirectX codes are found at: https://docs.microsoft.com/en-us/previous-versions/visualstudio/visual-studio-6.0/aa299374(v=vs.60)

  76. Q = 0x10

  77. W = 0x11

  78. E = 0x12

  79. R = 0x13

  80. T = 0x14

  81. Y = 0x15

  82. U = 0x16

  83. I = 0x17

  84. O = 0x18

  85. P = 0x19

  86. A = 0x1E

  87. S = 0x1F

  88. D = 0x20

  89. F = 0x21

  90. G = 0x22

  91. H = 0x23

  92. J = 0x24

  93. K = 0x25

  94. L = 0x26

  95. Z = 0x2C

  96. X = 0x2D

  97. C = 0x2E

  98. V = 0x2F

  99. B = 0x30

  100. N = 0x31

  101. M = 0x32

  102. ESC = 0x01

  103. ONE = 0x02

  104. TWO = 0x03

  105. THREE = 0x04

  106. FOUR = 0x05

  107. FIVE = 0x06

  108. SIX = 0x07

  109. SEVEN = 0x08

  110. EIGHT = 0x09

  111. NINE = 0x0A

  112. ZERO = 0x0B

  113. MINUS = 0x0C

  114. EQUALS = 0x0D

  115. BACKSPACE = 0x0E

  116. SEMICOLON = 0x27

  117. TAB = 0x0F

  118. CAPS = 0x3A

  119. ENTER = 0x1C

  120. LEFT_CONTROL = 0x1D

  121. LEFT_ALT = 0x38

  122. LEFT_SHIFT = 0x2A

  123. SPACE = 0x39

  124. DELETE = 0x53

  125. COMMA = 0x33

  126. PERIOD = 0x34

  127. BACKSLASH = 0x35

  128. NUMPAD_0 = 0x52

  129. NUMPAD_1 = 0x4F

  130. NUMPAD_2 = 0x50

  131. NUMPAD_3 = 0x51

  132. NUMPAD_4 = 0x4B

  133. NUMPAD_5 = 0x4C

  134. NUMPAD_6 = 0x4D

  135. NUMPAD_7 = 0x47

  136. NUMPAD_8 = 0x48

  137. NUMPAD_9 = 0x49

  138. NUMPAD_PLUS = 0x4E

  139. NUMPAD_MINUS = 0x4A

  140. LEFT_ARROW = 0xCB

  141. RIGHT_ARROW = 0xCD

  142. UP_ARROW = 0xC8

  143. DOWN_ARROW = 0xD0

  144. LEFT_MOUSE = 0x100

  145. RIGHT_MOUSE = 0x101

  146. MIDDLE_MOUSE = 0x102

  147. MOUSE3 = 0x103

  148. MOUSE4 = 0x104

  149. MOUSE5 = 0x105

  150. MOUSE6 = 0x106

  151. MOUSE7 = 0x107

  152. MOUSE_WHEEL_UP = 0x108

  153. MOUSE_WHEEL_DOWN = 0x109

  154. ########################################################

  155. ​

  156. # An optional countdown before the code actually starts running, so you have time to load up the game before messages are processed.

  157. # TODO: Set the "countdown" variable to whatever countdown length you want.

  158. countdown = 5 #The number of seconds before the code starts running

  159. while countdown > 0:

  160.     print(countdown)

  161.     countdown -= 1

  162.     time.sleep(1)

  163. ​

  164. # Connects to your twitch chat, using your username and OAuth token.

  165. # TODO: make sure that your Twitch username and OAuth token are added to the "TwitchPlays_AccountInfo.py" file

  166. t = TwitchPlays_Connection.Twitch();

  167. t.twitch_connect(TWITCH_USERNAME, TWITCH_OAUTH_TOKEN);

  168. ​

  169. ##########################################################

  170. ​

  171. while True:

  172.     # Check for new chat messages

  173.     new_messages = t.twitch_recieve_messages();

  174.     if not new_messages:

  175.         #No new messages. 

  176.         continue

  177.     else:

  178.         try:  

  179.             for message in new_messages:

  180.                 # We got a new message! Get the message and the username.

  181.                 msg = message['message'].lower()

  182.                 username = message['username'].lower()

  183.                 

  184.                 # TODO:

  185.                 # Now that you have a chat message, this is where you add your game logic.

  186.                 # Use the "PressKeyPynput(KEYCODE)" function to press and hold down a keyboard key.

  187.                 # Use the "ReleaseKeyPynput(KEYCODE)" function to release a specific keyboard key.

  188.                 # Use the "PressAndHoldKey(KEYCODE, SECONDS)" function press down a key for X seconds, then release it.

  189.                 # Use "mouse.press(Button.left)" or "mouse.release(Button.left)" to press/release the mouse. Can use Button.right for right click.

  190. ​

  191.                 # I've added some example videogame logic code below:

  192. ​

  193.                 ###################################

  194.                 # Example GTA V Code 

  195.                 ###################################

  196. ​

  197.                 # If the chat message is "left", then hold down the A key for 2 seconds

  198.                 if msg == "left"

  199.                     PressAndHoldKey(A, 2)

  200. ​

  201.                 # If the chat message is "right", then hold down the D key for 2 seconds

  202.                 if msg == "right"

  203.                     PressAndHoldKey(D, 2)

  204. ​

  205.                 # If message is "drive", then permanently hold down the W key

  206.                 if msg == "drive"

  207.                     ReleaseKeyPynput(S) #release brake key first

  208.                     PressKeyPynput(W) #start permanently driving

  209. ​

  210.                 # If message is "reverse", then permanently hold down the S key

  211.                 if msg == "reverse"

  212.                     ReleaseKeyPynput(W) #release drive key first

  213.                     PressKeyPynput(S) #start permanently reversing

  214. ​

  215.                 # Release both the "drive" and "reverse" keys

  216.                 if msg == "stop"

  217.                     ReleaseKeyPynput(W)

  218.                     ReleaseKeyPynput(S)

  219. ​

  220.                 # Press the spacebar for 0.7 seconds

  221.                 if msg == "brake"

  222.                     PressAndHoldKey(SPACE, 0.7)

  223. ​

  224.                 # Presses the left mouse button down for 1 second, then releases it

  225.                 if msg == "shoot"

  226.                     mouse.press(Button.left)

  227.                     time.sleep(1)

  228.                     mouse.release(Button.left)

  229. ​

  230.                 ###################################

  231.                 # Example Miscellaneous Code 

  232.                 ###################################

  233.                 

  234.                 # Clicks and drags the mouse upwards, using the Pyautogui commands.

  235.                 # NOTE: unfortunately, Pyautogui does not work in DirectX games like GTA V. It will work in all other environments (e.g. on your desktop)

  236.                 # If anyone finds a reliable way to move the mouse in DirectX games, please let me know!

  237.                 if msg == "drag mouse up":

  238.                     pyautogui.drag(0, -50, 0.25, button='left')

  239. ​

  240.                 # Clicks and drags the mouse downwards, using the Pyautogui commands

  241.                 if msg == "drag mouse down":

  242.                     pyautogui.drag(0, 50, 0.25, button='left')

  243. ​

  244.                 # An example of pressing 2 keys at once.

  245.                 # First holds down the LEFT_CONTROL key, then presses the A key for 0.1 seconds, then releases the LEFT_CONTROL key.

  246.                 if msg == "select all":

  247.                     PressKeyPynput(LEFT_CONTROL)

  248.                     PressAndHoldKey(A, 0.1)

  249.                     ReleaseKeyPynput(LEFT_CONTROL)

  250.                 

  251.                 # Can use pyautogui.typewrite() to type messages from chat into the keyboard.

  252.                 # Here, if a chat message says "type ...", it will type out their text.

  253.                 if msg.startswith("type "): 

  254.                     try:

  255.                         typeMsg = msg[5:] # Ignore the "type " portion of the message

  256.                         pyautogui.typewrite(typeMsg)

  257.                     except:

  258.                         # There was some issue typing the msg. Print it out, and move on.

  259.                         print("Typing this particular message didn't work: " + msg)

  260. ​

  261.                 ####################################

  262.                 ####################################

  263. ​

  264.         except:

  265.             # There was some error trying to process this chat message. Simply move on to the next message.

  266.             print('Encountered an exception while reading chat.')

  267. ​

End of Document

bottom of page