Created
July 23, 2017 16:48
-
-
Save ecumene/1ed532b7e2f93f1d3cfe80d43ac72ae4 to your computer and use it in GitHub Desktop.
Ecumene Sidebar
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import urllib, pyxhook, threading, json | |
totalchars = 0 | |
minuteChar = [] | |
def fileArray(): | |
urllib.urlretrieve("https://tmi.twitch.tv/group/user/ecumene/chatters", "data/chatters.json") | |
global totalchars | |
minuteChar.append(totalchars) | |
with open('data/minuteChars.txt', 'w') as outfile: | |
json.dump(minuteChar, outfile) | |
totalchars = 0 | |
threading.Timer(60.0, fileArray).start() | |
#this function is called everytime a key is pressed. | |
def OnKeyPress(event): | |
global totalchars | |
totalchars += 1 | |
fileArray() | |
#instantiate HookManager class | |
new_hook=pyxhook.HookManager() | |
#listen to all keystrokes | |
new_hook.KeyDown=OnKeyPress | |
#hook the keyboard | |
new_hook.HookKeyboard() | |
#start the session | |
new_hook.start() |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import sys | |
import os | |
import re | |
import time | |
import threading | |
from Xlib import X, XK, display, error | |
from Xlib.ext import record | |
from Xlib.protocol import rq | |
####################################################################### | |
########################START CLASS DEF################################ | |
####################################################################### | |
class HookManager(threading.Thread): | |
"""This is the main class. Instantiate it, and you can hand it KeyDown and KeyUp (functions in your own code) which execute to parse the pyxhookkeyevent class that is returned. | |
This simply takes these two values for now: | |
KeyDown = The function to execute when a key is pressed, if it returns anything. It hands the function an argument that is the pyxhookkeyevent class. | |
KeyUp = The function to execute when a key is released, if it returns anything. It hands the function an argument that is the pyxhookkeyevent class. | |
""" | |
def __init__(self): | |
threading.Thread.__init__(self) | |
self.finished = threading.Event() | |
# Give these some initial values | |
self.mouse_position_x = 0 | |
self.mouse_position_y = 0 | |
self.ison = {"shift":False, "caps":False} | |
# Compile our regex statements. | |
self.isshift = re.compile('^Shift') | |
self.iscaps = re.compile('^Caps_Lock') | |
self.shiftablechar = re.compile('^[a-z0-9]$|^minus$|^equal$|^bracketleft$|^bracketright$|^semicolon$|^backslash$|^apostrophe$|^comma$|^period$|^slash$|^grave$') | |
self.logrelease = re.compile('.*') | |
self.isspace = re.compile('^space$') | |
# Assign default function actions (do nothing). | |
self.KeyDown = lambda x: True | |
self.KeyUp = lambda x: True | |
self.MouseAllButtonsDown = lambda x: True | |
self.MouseAllButtonsUp = lambda x: True | |
self.contextEventMask = [X.KeyPress,X.MotionNotify] | |
# Hook to our display. | |
self.local_dpy = display.Display() | |
self.record_dpy = display.Display() | |
def run(self): | |
# Check if the extension is present | |
if not self.record_dpy.has_extension("RECORD"): | |
print "RECORD extension not found" | |
sys.exit(1) | |
r = self.record_dpy.record_get_version(0, 0) | |
print "RECORD extension version %d.%d" % (r.major_version, r.minor_version) | |
# Create a recording context; we only want key and mouse events | |
self.ctx = self.record_dpy.record_create_context( | |
0, | |
[record.AllClients], | |
[{ | |
'core_requests': (0, 0), | |
'core_replies': (0, 0), | |
'ext_requests': (0, 0, 0, 0), | |
'ext_replies': (0, 0, 0, 0), | |
'delivered_events': (0, 0), | |
'device_events': tuple(self.contextEventMask), #(X.KeyPress, X.ButtonPress), | |
'errors': (0, 0), | |
'client_started': False, | |
'client_died': False, | |
}]) | |
# Enable the context; this only returns after a call to record_disable_context, | |
# while calling the callback function in the meantime | |
self.record_dpy.record_enable_context(self.ctx, self.processevents) | |
# Finally free the context | |
self.record_dpy.record_free_context(self.ctx) | |
def cancel(self): | |
self.finished.set() | |
self.local_dpy.record_disable_context(self.ctx) | |
self.local_dpy.flush() | |
def printevent(self, event): | |
print event | |
def HookKeyboard(self): | |
pass | |
# We don't need to do anything here anymore, since the default mask | |
# is now set to contain X.KeyPress | |
#self.contextEventMask[0] = X.KeyPress | |
def HookMouse(self): | |
pass | |
# We don't need to do anything here anymore, since the default mask | |
# is now set to contain X.MotionNotify | |
# need mouse motion to track pointer position, since ButtonPress events | |
# don't carry that info. | |
#self.contextEventMask[1] = X.MotionNotify | |
def processevents(self, reply): | |
if reply.category != record.FromServer: | |
return | |
if reply.client_swapped: | |
print "* received swapped protocol data, cowardly ignored" | |
return | |
if not len(reply.data) or ord(reply.data[0]) < 2: | |
# not an event | |
return | |
data = reply.data | |
while len(data): | |
event, data = rq.EventField(None).parse_binary_value(data, self.record_dpy.display, None, None) | |
if event.type == X.KeyPress: | |
hookevent = self.keypressevent(event) | |
self.KeyDown(hookevent) | |
elif event.type == X.KeyRelease: | |
hookevent = self.keyreleaseevent(event) | |
self.KeyUp(hookevent) | |
elif event.type == X.ButtonPress: | |
hookevent = self.buttonpressevent(event) | |
self.MouseAllButtonsDown(hookevent) | |
elif event.type == X.ButtonRelease: | |
hookevent = self.buttonreleaseevent(event) | |
self.MouseAllButtonsUp(hookevent) | |
elif event.type == X.MotionNotify: | |
# use mouse moves to record mouse position, since press and release events | |
# do not give mouse position info (event.root_x and event.root_y have | |
# bogus info). | |
self.mousemoveevent(event) | |
#print "processing events...", event.type | |
def keypressevent(self, event): | |
matchto = self.lookup_keysym(self.local_dpy.keycode_to_keysym(event.detail, 0)) | |
if self.shiftablechar.match(self.lookup_keysym(self.local_dpy.keycode_to_keysym(event.detail, 0))): ## This is a character that can be typed. | |
if self.ison["shift"] == False: | |
keysym = self.local_dpy.keycode_to_keysym(event.detail, 0) | |
return self.makekeyhookevent(keysym, event) | |
else: | |
keysym = self.local_dpy.keycode_to_keysym(event.detail, 1) | |
return self.makekeyhookevent(keysym, event) | |
else: ## Not a typable character. | |
keysym = self.local_dpy.keycode_to_keysym(event.detail, 0) | |
if self.isshift.match(matchto): | |
self.ison["shift"] = self.ison["shift"] + 1 | |
elif self.iscaps.match(matchto): | |
if self.ison["caps"] == False: | |
self.ison["shift"] = self.ison["shift"] + 1 | |
self.ison["caps"] = True | |
if self.ison["caps"] == True: | |
self.ison["shift"] = self.ison["shift"] - 1 | |
self.ison["caps"] = False | |
return self.makekeyhookevent(keysym, event) | |
def keyreleaseevent(self, event): | |
if self.shiftablechar.match(self.lookup_keysym(self.local_dpy.keycode_to_keysym(event.detail, 0))): | |
if self.ison["shift"] == False: | |
keysym = self.local_dpy.keycode_to_keysym(event.detail, 0) | |
else: | |
keysym = self.local_dpy.keycode_to_keysym(event.detail, 1) | |
else: | |
keysym = self.local_dpy.keycode_to_keysym(event.detail, 0) | |
matchto = self.lookup_keysym(keysym) | |
if self.isshift.match(matchto): | |
self.ison["shift"] = self.ison["shift"] - 1 | |
return self.makekeyhookevent(keysym, event) | |
def buttonpressevent(self, event): | |
#self.clickx = self.rootx | |
#self.clicky = self.rooty | |
return self.makemousehookevent(event) | |
def buttonreleaseevent(self, event): | |
#if (self.clickx == self.rootx) and (self.clicky == self.rooty): | |
##print "ButtonClick " + str(event.detail) + " x=" + str(self.rootx) + " y=" + str(self.rooty) | |
#if (event.detail == 1) or (event.detail == 2) or (event.detail == 3): | |
#self.captureclick() | |
#else: | |
#pass | |
return self.makemousehookevent(event) | |
# sys.stdout.write("ButtonDown " + str(event.detail) + " x=" + str(self.clickx) + " y=" + str(self.clicky) + "\n") | |
# sys.stdout.write("ButtonUp " + str(event.detail) + " x=" + str(self.rootx) + " y=" + str(self.rooty) + "\n") | |
#sys.stdout.flush() | |
def mousemoveevent(self, event): | |
self.mouse_position_x = event.root_x | |
self.mouse_position_y = event.root_y | |
# need the following because XK.keysym_to_string() only does printable chars | |
# rather than being the correct inverse of XK.string_to_keysym() | |
def lookup_keysym(self, keysym): | |
for name in dir(XK): | |
if name.startswith("XK_") and getattr(XK, name) == keysym: | |
return name.lstrip("XK_") | |
return "[%d]" % keysym | |
def asciivalue(self, keysym): | |
asciinum = XK.string_to_keysym(self.lookup_keysym(keysym)) | |
if asciinum < 256: | |
return asciinum | |
else: | |
return 0 | |
def makekeyhookevent(self, keysym, event): | |
storewm = self.xwindowinfo() | |
if event.type == X.KeyPress: | |
MessageName = "key down" | |
elif event.type == X.KeyRelease: | |
MessageName = "key up" | |
return pyxhookkeyevent(storewm["handle"], storewm["name"], storewm["class"], self.lookup_keysym(keysym), self.asciivalue(keysym), False, event.detail, MessageName) | |
def makemousehookevent(self, event): | |
storewm = self.xwindowinfo() | |
if event.detail == 1: | |
MessageName = "mouse left " | |
elif event.detail == 3: | |
MessageName = "mouse right " | |
elif event.detail == 2: | |
MessageName = "mouse middle " | |
elif event.detail == 5: | |
MessageName = "mouse wheel down " | |
elif event.detail == 4: | |
MessageName = "mouse wheel up " | |
else: | |
MessageName = "mouse " + str(event.detail) + " " | |
if event.type == X.ButtonPress: | |
MessageName = MessageName + "down" | |
elif event.type == X.ButtonRelease: | |
MessageName = MessageName + "up" | |
return pyxhookmouseevent(storewm["handle"], storewm["name"], storewm["class"], (self.mouse_position_x, self.mouse_position_y), MessageName) | |
def xwindowinfo(self): | |
try: | |
windowvar = self.local_dpy.get_input_focus().focus | |
wmname = windowvar.get_wm_name() | |
wmclass = windowvar.get_wm_class() | |
wmhandle = str(windowvar)[20:30] | |
except: | |
## This is to keep things running smoothly. It almost never happens, but still... | |
return {"name":None, "class":None, "handle":None} | |
if (wmname == None) and (wmclass == None): | |
try: | |
windowvar = windowvar.query_tree().parent | |
wmname = windowvar.get_wm_name() | |
wmclass = windowvar.get_wm_class() | |
wmhandle = str(windowvar)[20:30] | |
except: | |
## This is to keep things running smoothly. It almost never happens, but still... | |
return {"name":None, "class":None, "handle":None} | |
if wmclass == None: | |
return {"name":wmname, "class":wmclass, "handle":wmhandle} | |
else: | |
return {"name":wmname, "class":wmclass[0], "handle":wmhandle} | |
class pyxhookkeyevent: | |
"""This is the class that is returned with each key event.f | |
It simply creates the variables below in the class. | |
Window = The handle of the window. | |
WindowName = The name of the window. | |
WindowProcName = The backend process for the window. | |
Key = The key pressed, shifted to the correct caps value. | |
Ascii = An ascii representation of the key. It returns 0 if the ascii value is not between 31 and 256. | |
KeyID = This is just False for now. Under windows, it is the Virtual Key Code, but that's a windows-only thing. | |
ScanCode = Please don't use this. It differs for pretty much every type of keyboard. X11 abstracts this information anyway. | |
MessageName = "key down", "key up". | |
""" | |
def __init__(self, Window, WindowName, WindowProcName, Key, Ascii, KeyID, ScanCode, MessageName): | |
self.Window = Window | |
self.WindowName = WindowName | |
self.WindowProcName = WindowProcName | |
self.Key = Key | |
self.Ascii = Ascii | |
self.KeyID = KeyID | |
self.ScanCode = ScanCode | |
self.MessageName = MessageName | |
def __str__(self): | |
return "Window Handle: " + str(self.Window) + "\nWindow Name: " + str(self.WindowName) + "\nWindow's Process Name: " + str(self.WindowProcName) + "\nKey Pressed: " + str(self.Key) + "\nAscii Value: " + str(self.Ascii) + "\nKeyID: " + str(self.KeyID) + "\nScanCode: " + str(self.ScanCode) + "\nMessageName: " + str(self.MessageName) + "\n" | |
class pyxhookmouseevent: | |
"""This is the class that is returned with each key event.f | |
It simply creates the variables below in the class. | |
Window = The handle of the window. | |
WindowName = The name of the window. | |
WindowProcName = The backend process for the window. | |
Position = 2-tuple (x,y) coordinates of the mouse click | |
MessageName = "mouse left|right|middle down", "mouse left|right|middle up". | |
""" | |
def __init__(self, Window, WindowName, WindowProcName, Position, MessageName): | |
self.Window = Window | |
self.WindowName = WindowName | |
self.WindowProcName = WindowProcName | |
self.Position = Position | |
self.MessageName = MessageName | |
def __str__(self): | |
return "Window Handle: " + str(self.Window) + "\nWindow Name: " + str(self.WindowName) + "\nWindow's Process Name: " + str(self.WindowProcName) + "\nPosition: " + str(self.Position) + "\nMessageName: " + str(self.MessageName) + "\n" | |
####################################################################### | |
#########################END CLASS DEF################################# | |
####################################################################### | |
if __name__ == '__main__': | |
hm = HookManager() | |
hm.HookKeyboard() | |
hm.HookMouse() | |
hm.start() | |
time.sleep(10) | |
hm.cancel() |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<html> | |
<head> | |
<link href="//fonts.googleapis.com/css?family=Roboto" rel="stylesheet"> | |
<link href="https://fonts.googleapis.com/css?family=Roboto+Mono" rel="stylesheet"> | |
<link href="//use.fontawesome.com/3b31c92f6b.css" rel="stylesheet"> | |
<style> | |
body { | |
color: #D8CBC7; | |
background: #2D3142; | |
font-family: 'Roboto', sans-serif; | |
} | |
hr { | |
border: none; | |
border-top: 4px solid #FFF; | |
text-align: center; | |
} | |
hr#top { | |
border: none; | |
border-top: 4px dotted #DB440D; | |
text-align: center; | |
} | |
hr#top:after { | |
content: '\f1b3'; | |
display: inline-block; | |
position: relative; | |
top: -25px; | |
padding: 0 10px; | |
background: #2D3142; | |
color: #CC3F0C; | |
font-size: 40px; | |
font-family: FontAwesome; | |
} | |
.marquee { | |
font-weight: bold; | |
} | |
div.streamer { | |
background: rgba(255,79,15,0.9); | |
border: 4px solid rgba(255,79,15,1); | |
padding-left: 10px; | |
padding-right: 10px; | |
padding-bottom: 15px; | |
margin-bottom: 10px; | |
} | |
div.stats { | |
background: #3C6E71; | |
border: 4px solid #3C6E71; | |
color: #BEEE62; | |
padding-left: 10px; | |
padding-right: 10px; | |
padding-bottom: 15px; | |
margin-bottom: 10px; | |
} | |
div.stats p { | |
border-radius: 3px; | |
border: 2px solid #70AE6E; | |
background-color: #70AE6E; | |
color: #EAEFBD; | |
margin-left: 10px; | |
margin-right: 10px; | |
padding: 5px; | |
font-family: 'Roboto Mono', monospace; | |
} | |
img { | |
width: 100%; | |
} | |
.gifotd { | |
font-family: 'Roboto Mono', monospace; | |
font-weight: bold; | |
border: 2px solid #DB440D; | |
background-color: #DB440D; | |
} | |
</style> | |
</head> | |
<body> | |
<center> | |
<br> | |
<h1><u>current task</u></h1> | |
<h3 class="paper">companies window</h3> | |
<br> | |
characters written in the last 5 minutes: | |
<br><br> | |
<canvas id="myChart" width="100" height="50"></canvas> | |
<br> | |
</center> | |
<div class="streamer"> | |
<h3><i class="fa fa-keyboard-o" aria-hidden="true"></i> > mitchell hynes</h3> | |
<hr> | |
<i class="fa fa-twitter" aria-hidden="true"></i> <b>> www.twitter.com/ecumenex</b><br> | |
<i class="fa fa-envelope" aria-hidden="true"></i> <b>> [email protected]</b> | |
</div> | |
<div class='marquee' id="marquee" data-duration='10000' data-gap='10' data-duplicated='true' > | |
SILICON TYCOON DEVELOPMENT IS STREAMED FROM 1:00PM - 8:30PM NDT | FOLLOW ME ON TWITCH FOR MORE GAME DEVELOPMENT! | |
</div><br><br> | |
<!--<div class="stats"> | |
<h3><i class="fa fa-video-camera" aria-hidden="true"></i> currently watching</h3> | |
<hr> | |
<p> admins | <i id="admins"></i></p> | |
<p> mods | <i id="mods"></i></p> | |
<p> viewers | <i id="viewers"></i></p> | |
</div>--> | |
<center><div class="gifotd">GIF OF THE DAY</center> | |
<img src="https://i.makeagif.com/media/11-16-2015/5TC636.gif"></img> | |
<!--<div class="streamer"> | |
<h3>guest: josh</h3> | |
<hr> | |
<i class="fa fa-twitter" aria-hidden="true"></i><b> > xxx</b><br> | |
<i class="fa fa-envelope" aria-hidden="true"></i><b> > xxx</b> | |
</div>--> | |
<iv | |
</body> | |
<script | |
src="//code.jquery.com/jquery-3.2.1.min.js" | |
integrity="sha256-hwg4gsxgFZhOsEEamdOYGBf13FyQuiTwlAQgxVSNgt4=" | |
crossorigin="anonymous"></script> | |
<script src="//cdnjs.cloudflare.com/ajax/libs/Chart.js/2.6.0/Chart.min.js"></script> | |
<script src="//cdn.jsdelivr.net/jquery.marquee/1.4.0/jquery.marquee.min.js" type="text/javascript"></script> | |
<script> | |
setTimeout(function(){ | |
window.location.reload(1); | |
}, 60000); | |
$('.marquee').marquee({ | |
duration: 20000, | |
gap: 50, | |
delayBeforeStart: 0, | |
direction: 'left', | |
duplicated: true | |
}); | |
$.getJSON('http://127.0.0.1:8000/scripts/data/chatters.json') | |
.done(function (data) { | |
var chatters = {}; | |
chatters = data; | |
document.getElementById("viewers").innerHTML = | |
typeof chatters["chatters"]["viewers"] != undefined ? chatters["chatters"]["viewers"].length : 0; | |
document.getElementById("admins").innerHTML = | |
typeof chatters["chatters"]["administrators"] != undefined ? chatters["chatters"]["admins"].length : 0; | |
document.getElementById("mods").innerHTML = | |
typeof chatters["chatters"]["moderators"] != undefined ? chatters["chatters"]["moderators"].length : 0; | |
}); | |
$.getJSON('http://127.0.0.1:8000/scripts/data/minuteChars.txt') | |
.done(function (data) { | |
var longData = data; | |
var last5Mins = [0, 0, 0, 0, 0] | |
for(index = 0; index < 5; ++index) | |
last5Mins[index] = longData[(longData.length - 5) + index] | |
var ctx = document.getElementById("myChart").getContext('2d'); | |
var myChart = new Chart(ctx, { | |
type: 'line', | |
data: { | |
labels: last5Mins, | |
datasets: [{ | |
label: '', | |
data: last5Mins, | |
backgroundColor: ['rgba(204, 63, 12, 0.2)',], | |
borderColor: ['rgba(255,79,15,1)',], | |
borderWidth: 1 | |
}] | |
}, | |
options: { | |
legend: { | |
display: false | |
}, | |
scales: { | |
yAxes: [{ | |
ticks: { | |
beginAtZero:false, | |
} | |
}], | |
xAxes: [{ | |
display: false | |
}] | |
} | |
} | |
}); | |
}); | |
</script> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment