Updates: Tyler on PowerHacking CSS to cutestrap your app in this latest episode!

S1E2: DIY Custom Key Deck


Build your own custom key deck through the Linux UAPI in python, then add some custom functionality.

Building your own custom key deck through the Linux kernel UAPI in user space with python, then tying it to custom functionality for live streaming!


Transcript:

Hello everybody welcome back people who
were here last week and people who are
just joining us! This is the
second episode of Coding with Some Guy.
Last week we had a lot of fun - we took
word clouds, words from
public companies and we put them
together in the shape of the company's
logo, and that came out
pretty! That had some very pretty results
and it was really nice because I forgot
to hit the record button so that, for the
10 or so people that saw it, thanks for
watching, you are the only ones!
Sorry you missed it, people who are just
joining. I'll probably get back
to that in a few weeks, if there's some
popular demand, but let's talk about
today! I was a
little surprised when I saw how much a
stream deck cost, and I thought well now
come on I mean custom buttons that's--
I've already got this fantastic custom button
device that's already been debounced, it
has USB capabilities, and it's plugged
straight in to my machine without a lot
of interface problems - no custom software -
and it is called "a keyboard". This is new
technology. But we're going to
repurpose it - we're going to do something
very cool with it, we are going to take
this magical key input device, and we're
going to make it do whatever custom
things that you determine. So later on
in the show we're going to set up some
bindings and get this to do some pretty
cool stuff.
One caveat, this is going to be covering
the Linux Input API, so that's not
really a problem with *this* stream because
you're all using Linux of course and
that's- that's a good thing. So without
further ado, let's get going!
[Music]
"I watched Guy live-code a beer delivery
system on a 52-inch plasma screen from a
beanbag!" -- Thank You, Patrick,
I appreciate you telling everybody about
that... So let's get suited up here for the
drawing. I want to cover a few things
that we are going to be talking about
this time and MyPaint is our friend and
it's going to do some magic drawing for
us so it's very nice to have magic
drawing. So we are in E2 here
and we're doing key magic.
The way we're going to run this is
we've got basically three parts to
getting this to work. The first is we're
gonna have to take that magical key
input device and we're gonna have to
find it. It's going to show up very
differently depending on the type of
keyboard you have, but they're all
basically going to say "wired key input device"
"wireless", whatever, so we're gonna
need to find it in the device list
and we're gonna have to get that
working for us and
we're gonna have to shut off the
keyboard part of it to get our magic
working. And then, after we find it,
we're gonna learn how to take
input codes from that, and we're gonna be
using the UAPI, which is a convenient
tool, and oh hey what's up eftwo,
nightshade, good see you guys, and so
we're going to take that user API, and
we're going to decode those events and
get them rolling. Then as soon as
we've got that all set up, then we're
actually going to get to the fun part
and we're going to do some magical
bindings, so, with that part
we're going to be writing in Python
today so that part I'll sort of
leave that up to you, I'll get a few
samples to get that started, and that's
basically it. So drawing stuff aside,
let's get to the action. All right
since you're all great people,
I'm gonna top up the
mana here. I can only program as long as
I've got mana so we're gonna
keep that going and the target here is gonna
be about a little less than an hour.
So, we've got our our fresh new
directory and we're ready to go.
So the time lapse, by the way, in the
beginning is me making the mana bar so
that's uh, I figured, you know
you gotta top up the mana to do some
some programming. Alright, so we're going
to (and, nice for those even know about
the other things) okay so we've got
nothing in here, and we're going to
get started with our Python 3 app which
we're gonna call, I don't know, what should
we call it, key handling. keyhandler.
And this just takes some of the dirty work out of
having to do all that nonsense.
Once again I'm going to be using
screen and some other magic (mostly
vim, so, sorry for you people that aren't
vim people) but hopefully this text is
gonna be fairly readable on your screen,
I know the stream likes to kind of
crush it a bit. So we've got in here our
little start, we got basically nothing,
we like getting going with our main and,
before we do that, I've taken the liberty
of taking this key input device and
connecting it already, so it's going to
show up on my USB. Now the User API has a
nice feature that it puts the input
devices here - now I've got a bunch of
input devices on this system including
the camera, the headphones,
and all that other fun stuff.
So which of these 30--now keyboards
show up as event interface as they
create key events, the mice they're all
unified in that mice file over there, and
that, we have a lot of events.
I mean, there's like 30 of these,
so I don't really want to go digging around
to find that, but,
you know, Linux, in its infinite wisdom,
gives us this nice little by-id. And
if we look in here we can see,
this happens to be a Dell keyboard I just
picked up, I was using an Amazon Basics
keyboard the other day which I was able
to get for 10 bucks, so this is a
very expensive hack, but I'm putting that
out there for all of you. So this, there's
a few interfaces that show up,
we're interested in this guy over here, so this
is the actual keyboard interface and
that links itself nicely, well, sorry
about all that, but that links itself nicely
to event 15 and then 16 so that's actually
where our keyboard is connected.
Now to fully finish this, you're going to have to
do some udev magic, and the one thing
that I want you to be careful of if you
try this at home (and you *should* try this
at home) is, no, I don't want to cd
into it, I want to show it to you,
you need to make sure that you are in the
right group. So, by default you're
probably not gonna be in the input group,
which sorta makes sense because
X is normally the one that's going
to be handling all that, so, for today, to
keep things simple, I'm keeping the udev
out of it, so we're just gonna go and--
I put myself in this group so I should
be able to cat this thing and you know
actually read the interface. Now it's not
doing anything at the moment and 
that's fine.
So there's another little bit of magic
we need to do there as well because
keyboards normally, if you type on them,
like I'm going to type on this guy, then
it just sends keys and decodes them and
does all the things that it's supposed to
do with a keyboard.
So we don't want it to act as a
normal keyboard, so in order
to get around that, we're gonna need to
find it in this list, which has _slightly_
different names although it does tie to
the same ids in the event system,
so we're just gonna
look at that for wired keyboards and now
we see that we've actually gotten three
because X has done a little bit of magic
and slaved it and now we actually
have three keyboards here--we're gonna
disable all of them because we don't
actually want them to be in use by the
system so that's, this is how we're gonna
find the device and then we're gonna, you know,
actually go and disable it a little
bit later. So what we're working with here
is a bunch of files, which is really
nice and for those of you who used other
versions of Unix, a little bit older,
there's not much in dev other than just
raw devices and in dev and proc and sys
and Linux you actually have a whole
wealth of information about your system,
so it's nice that the interface is so
simple to work with. So I'm just gonna
shorten this today I don't have any
other Dell keyboards, but they all seem
to have this this string, so
we're going to take that as the XInput
keyboard string
and, we're also going to need the device,
the actual device name that this thing
is called in the by-id folder, and that
is, I'm gonna get a full path here
because that's what I want, what was this thing?
Okay, so I'm gonna take this one, and
this is what we're gonna use for our
actual input events. So you can actually
get from one to the other, it involves
looking in the XInput protocol and it's--
it's-- kind of a mess, so we're just gonna
use XInput let it deal with the X-isms
for us today, so, this is the, let's call this
the input, I should really make
these constants, I'm not being very,
pythonic, so
there's our keyboard--I'm just
going over the line limit--and so this is
this-- alright, so we know which
devices we're talking to, getting from
this to that is just a bit of a mess,
X renames a bunch of the inputs, so we're
just going to use the X / XInput list,
if you forget, on your own, alright,
so, what do we want to do? What kind of
format does this keyboard generate?
This is just basically a normal device
input file so there's not, it does have a
few special properties, which we're going
to get from the Linux kernel, which tells
us everything in its Documentation
directory, so where do I--it's just
handy that I happen to have this
downloaded and uncompressed for you, so
this is a recent Linux kernel
and in here
there's just a wealth of stuff
and there's all kinds of information on
the input, so input happens to be here,
but I'm gonna show it to you in the
browser because it's nice to have a few
things open. Alright, so if you open up
this file this input.rst then you end up
with this--down here at the bottom you
get this event interface which is
actually gonna be--this is what we're
interested in, so keys, it's telling us
that we're gonna be able to find these
things in dev input event, like I just
showed you, it's a little tricky to
figure out which keyboards which but
we're gonna use the by-id convenience
directory to do that. You can also do it
by USB device ID, it's really up to
you. That's probably more important if
you're doing the udev
version of it, so we'll we'll leave that
alone for now. Now, when we open this file
it's basically going to
show up as a binary file, and every time
I press a key an event, like this,
in this structure, is going to show up.
Now, for those you not used to
reading C structures, this is basically
an embedded structure - we have
this--this input event structure
contains a time, that's when the key was
pressed, I think it's a
relative offset from the last one,
and it's gonna be called "time". So then
this "time" value is a little messy to
decode, then we're gonna have a type
which is telling us what sort of event
happened, in the case of a keyboard we're
gonna be looking for a key press, which
they tell us down here is going to be
EV_KEY and it's also going to give us a
code, now that's the scan code on the
keyboard, so we're gonna use that to
figure out which key was pressed, and we
have a value which changes depending on
what type we have, and it's telling us
down here that the value is now we're
gonna be dealing with EV_KEYs, we're
not dealing with joysticks and all the
other fun stuff we can input here, but by
the way if you hook a joystick up,
it shows up in this same interface if it
has a proper kernel driver, and the so
EV_KEY is going to give us this value
here of one for a key press and two for
an auto repeat and zero which is for a
release, so key down, it's gonna be one
key up, it's going to be zero, and if I
hold it down it's gonna be two. So we're
just gonna be working with key downs but
we'll get to that a little later.
Now, because nothing in life is simple,
this timeval is defined very--
in a very complicated fashion, and that's
really due to compiler stuff around, if
your machine is 32-bit or 64-bit, and
what sort of time units you're using, I'm
gonna kind of skip over that--
it's-- it's just a normal time value, which
you can see in your--
in your man pages, here, so it's one
of these, which looks nice and simple,
except this type basically
ends up on x86_64, this is a 64-bit
signed number, I don't know why it needs
to be signed, but that's what you'll find if you
go dig around, and this ends up being
a signed integer, except that because
that would be, you know four bytes,
well yeah you have a long here, basically
and, sorry, eight bytes on a 64-bit, and
this would be four bytes, then it pads it
out to add an invisible parameter that
is not being shown here which is going
to be another four bytes, so enough
talking about it, let's actually go
see it. Alright so we're gonna try to
open this guy up, so, this is, we're gonna
open the-- I'm gonna make a note here to
remember that we're going to disable XInput
and we'll get to that a little
later, but for now, we're just going to
open up this--this input device and it is
coming across in a structure that's
binary so make sure that you have that "b"
because otherwise you're gonna be in a
world of pain. Oh, I'll see you later
nightshadedude, thanks for dropping by!
Alright, so, I'm gonna open that up as a
normal file, and I need to know how much
I'm gonna read from it. Now, to calculate
that, we're going to use a little
convenience routine in Python to deal
with C structures, you could use the
cython stuff, I want to try to keep
this simple, so this structure we're
gonna need to know how big this--this
event over here is, so we're
going to calculate it right now
by first specifying the format,
and I just want to make sure I don't
show you the wrong thing, and, yes, okay so
we want to, this is going to be in local
notation, we want to make sure that this
is applicable to this system. Now, we know
that the first part of the time is a long,
we know that the--that's the seconds--the
second part, the microseconds, is an
integer, and then we have some padding, so
that's going to get us through this part.
So then we have the type, we have two
shorts here that are both unsigned
followed by a value, so to get that we're
gonna take our two shorts and then we're
going to just take our normal int, except
it's unsigned over here. Now in case we forget,
and trust me I forget this all the time
what these things are,
Python is handy so we can just go and look at
what all these things mean. Now in here
we see that this is our unsigned short
and this is our unsigned integer and our
long which is signed is gonna be a
lowercase L and our unsigned, well we're
not using it unsigned long, so if I just
split this for everybody then we can
look at this and check that we got this right.
So here we have the long--
So this is our long, and then we have the
integer, and we have another integer for padding
and then we have our-- our
unsigned short, which matches up what
we're seeing here, and we've got two of
them, and then we've got our regular
integer. Okay, so that should be the
description of
the event. So using that, we are going to
calculate how big it is, because we need
to know how many bytes to read.
So we're gonna take that size and we're
gonna call this the INPUT_EVENT_SIZE.
All right, so our constants are out of
the way, we're ready to get reading, so
here I'm going to take this _very_
complicated Python code, I'm going to
just read the size of the structure, that
is my raw event. So that's not really a,
this is basically going to read however
many bytes corresponds to that--
that structure that I just spelled out, and if
I got it right then they should match
this event interface tells us that you
can you can either block or not, and
you'll always get a whole number of
events on read, so I don't have to worry
about, like, getting part of a structure
and waiting for it, the kernel is
going to guarantee that I get the whole thing,
which is handy. So I'm gonna get
this raw_event, and then I'm going to
print it out, because, why not?
Okay, so I can just-- I activated this, I can
just run my key handler, I can press a
key, and I get the binary structure. Now,
you don't really want the binary structure,
what we actually want is
to take that apart, we want to pull out
the fields that are specified. Because
I don't really want to do too much inside this
routine, I'm going to decode the event,
and I'm gonna pass it up here and I'm
gonna make-- I'm gonna make a routine
which takes this raw event, and actually
makes some sense of it. We're gonna use
struct.unpack to read all of those bytes
that are in that structure, and put them
into Python, a Python tuple. So,
let's unpack this using the
INPUT_EVENT_FORMAT and we are going to end up with
a python kind of event. You know,
really the hardest part of all this is
going to be naming things so i'm
just gonna call this an event tuple (et).
It's very original,
Some--Guy--Coding! So I'm gonna take this
thing, and I'm gonna print it out now,
thanks to the magic of Python, I press a
key on that-- oh, I forgot to actually pass
the event! Let's pass the thing we wanted
to code, and I'm gonna hit J and there we go!
The J key shows up and now we have
this decoded, so, here is our number of
seconds, this is our number of microseconds,
this is the padding, so this will always be zero,
and here's the actual fields
that we care about. This is the type,
the code, and the value.
Let's be good people and
let's pull this apart.
Now, we don't really want to read just one,
but before we get to the actual decoder
we do want to make sure that we're going
to end up disabling this thing, so the
inputs that I'm gonna need to disable
all look like this.
I think it's probably better if we just
do them by hand, we can actually parse this,
because what we can do is we can
look at our xinput list, and we can look
for all of the lines that have the
keyboard that we want to find in it.
And, the handy thing about this thing is we
have this nice delimiter, which is gonna--
this down arrow unicode is gonna tell us
exactly where to start, and then there's
a few tabs, and then there, we're gonna go to the end.
Now don't you worry,
I'm gonna do it without a regular expression,
but (maybe we'll use a regular expression--
don't, don't tell me--) Alright, so
let's actually disable this,
so, to do this, we're gonna use-- we're just
gonna read that file that I just told
you about, and I'm not going to use subcommand,
because I don't care about
the command arguments for now,
we basically want to see the results of
"xinput list" and, well, let's just read
all of it.
This, we're gonna end up with a bunch of
lines, and we are going to search for
that particular piece of Unicode is--
pythonic-- this is the Unicode for that--
so, you can also if you are
wondering where that comes from, you can just--
do it the really complicated way,
or you can [beat] and you're gonna discover that
this is really at the Wikipedia,
and if I search for it I will not find my event type,
yeah, it's this downwards arrow with tip right,
this guy, oh hey what's
up Katie--CODY oh sorry my bad dude wasn't
looking here, um, yeah let's run a regex
in a tight loop, yeah, you really came at the
most inopportune moment, but I have
beef with regular expressions as some of
you may know-- so, just because
Cody's here, I'm not even gonna bother to
parse this, I'm gonna do this for him,
so let's get that tight loop
that he's talking about-- let's--
[laughing] thanks dude, we're gonna go and--
we're gonna split this line up, now we
need to give it a pattern, we're
gonna be cool and use a regular
expression on the line and
let's say that we have a whole bunch of stuff,
which is, eh, I don't really need
a regular expression,
let's just be good people and let's make
sure that we have the the actual-- we're
only interested in the Dell keyboard so
let's look at that, we don't want "in",
we just want to see that it "contains",
which, now you don't get "contains",
I want the starting off should we just
say if it's in there, and we could just
find it,
yeah, and then if we give it something it
doesn't know, yeah that's-- yeah, we'll just
use a find. Okay, so this is "find",
this thing is not equal to 1, then we know
that it's in the line, and we can just
make sure that we're hitting the right line,
so let's go and do that, yeah, we're cool.
Okay, so there's our three keyboards
and we need to just pull out after
the Unicode thing, and this'll be, there's my
great naming now, okay, so we just want
to get that and everything up to the,
excuse me, everything up to the-- I'm gonna
write a very perl-like line-- so we're
gonna take, that's gonna match, I mean,
I guess I could check if it matches, but
it's gonna match everything up to the tab,
so let's take this, and split again,
and do everything up to the tab,
and we end up with the right thing, okay, but we
want to drop that first character
because we don't really want that,
so we're gonna slice it, one on, and that
would be-- not the right thing to do.
Oh, because I returned it, right, so
first I need-- there's some perl! You like that?
Okay, so there's my keyboard except
I've got this annoying little space here,
so we're just gonna get rid of that
space.
I know, it's fragile, but hey, I didn't use
a regular expression so, sorry Cody,
I'll save it for next time. Alright, so
spiritresearcher, oh no, "it's trying to put
a SSL on my website but nginx--
up the code-- I start the web server anymore,
I have autism, can help me..."
yeah, that's not really on topic, sorry.
Right now, I can tell you that setting up
SSL and nginx is not the most fun you're
ever gonna have, but there's some great
guides for it on the Internet.
Okay, so, this is gonna be okay, so now we
have the right names, and once we have
those names, all we have to do is--
it's really XInput keyboard names, actually I
only get one at a time, and, because
I don't really want to do another tight loop I'm
just going to build a magic command that
I'm gonna "system" which is gonna be
"xinput disable" the thing that I've
got here.
Alright, and, we're gonna twist in
the keyboard name, and that should look
right, yeah it does, cool, alright well,
do it! There's a million safer ways
to do that, but now when I type on this
keyboard, I get the key input event,
but no keys are coming through,
so it's no longer bound into X.
Yes, Cody, I completely agree, and no no,
no worries Spirit, I just-- I will get to
nginx in a future stream, I'm sure, but
for now it's-- it's really-- it's a lot of
fun. Okay, so, and thanks for dropping that
link Cody, much appreciated. So now I've
got the keyboards disabled and I'm ready
to go do that, so we don't really need to
see these commands anymore, so I'm just
gonna comment them out, alright? Cool.
Now that I've got the actual event I
need to, well, let's do this forever,
because we're just gonna run this, sort of in
the background. So I go and I get keys
and there's a whole lot. Now you might
notice that for one key event (I'm just gonna
press an "H" here) I'm getting a lot of stuff.
Okay and that's-- I'm not really
interested in these times, but, and this
padding is always zero, but what I'm
gonna end up getting here is this is the
type and this happens to be a
mistype, we'll get to that in a sec,
this is going to be some I don't want to
look at that line I really want these
lines with a one because those
correspond to EV_KEY presses so what
this isn't an actual key press
and this is telling us that it was a key
press and not a key release, this is
telling us this is the end of that
packet, sorry, the the actual key release
is over here, which is basically the same
scan code that 35, which corresponds to
the "H", except that now I'm releasing it so
this last field sort of changes
depending on what the record is. So we--
don't really want these, so we're just
going to filter them out and do it
without using an observable. Sorry, I couldn't
resist. So this-- this particular input,
let's unpack it. The actual
event, the parsed event that's coming in,
is really going to be made up of,
this is the tuple, we have the event, this is
the tv_sec field, the first part of
gettimeofday, which, course I closed.
This is the the tv_sec field and
that's our seconds and then we're gonna
have the tv_usec field, try to stay
consistent naming, then we're gonna have
the tv pad which we're not very
interested in and we could really just
drop it on the floor Python style, and
then we've got the three that we're
really interested in. So this is our type,
our code, and our value. So this is our
type,
well I'm gonna refer to these by event,
because that's what it's called over here,
so this is our ev_type, ev_code and our-- so
we're gonna unpack all of those from
there and the ones that we're really
most interested in are the type, the code
and the value. Okay, so, now I press a key
and I get a lot less fields.
Now I only want these ones where the
event type is one. Now to actually know
that, I'd have to go-- it does mention down
here that you can see input codes and if
you dig all that up, you'll find this
file which is also included in your
kernel source, which is available, or you
can even look at it on github like I am
right now, I'm sorry this isn't github,
this is an actual kernel we're looking at.
Now, if we go over to github,
we'll find-- oh look at that! Event types
are just sitting right there waiting for
us! This is all of the types that we
need to deal with! Now this is
really an enum, but you know, kernel-isms.
We're going to do this as defines. So
these are these are all the types that
could show up, the one that we're
interested in is right here.
This corresponds to this one so this is
EV_KEY, we're doing keyboard events, so we
had better not see joystick inputs
coming from the keyboard, at least not
this keyboard, so, because we're good
people,
we're going to use a constant, and
we're going to extract that constant
later, and we can say that if the ev_type
is the key (then I know that I'm getting
a key event) and we're gonna print it out.
So, we do that, and we're only seeing key
presses corresponding to-- oh, and see,
kind of multiplex things there if I
press two at a time, but, so, here we're
just gonna get the key events and we're
gonna get either it was a key down or a
key up, and this is the actual scan code.
And if I hold it down, I'll get a two, and
a release. So this is the-- the actual--
this is a repeat.
So this is generated, I'm not actually
pressing it. I'm only going to be
interested in these ones, here, so now,
they don't actually refer to what
this value is called, so we're gonna
have to make up something, but we're okay
with naming some things. So, we really
want, let's just do-- sorry, looking
at C code, so we really want just the, um,
the case where the value is one, so
that corresponds to a
KEY_VALUE, ah, let's just call it KEYPRESS, so
that's gonna be a 1. So if the value is a
KEYPRESS, then I guess we should be more
specific, this is a KEYDOWN, then, I want
to print the thing out, so looking at
this, yeah, now I'm only getting key down,
so I don't have to worry about if I hold
the key, nothing happens. Alright! So now
we're-- we've kind of tamed that
particular input, so going back to here,
this is-- we've found the device, it was
hidden in the dev system, and we then
figured out how to actually parse the
input, and that's the UAPI that I was
talking about, and now we get to the fun
part. So I'm gonna give you a little
moment for participation if you are
interested, I know Cody is gonna
make me write a regular expression, but
that's just not gonna happen-- I'm not gonna
do that, there are limits, so go ahead and,
what do we want to get one of these keys
to do? Well actually, I mean, it's a little
tricky to know which key is which, which
was also defined in this file because--
there they are! Now this is based on the
USB scan codes, but, this actually tells
us how we're gonna process this code
field, so that corresponds to all of
these keys, so key "whatever". Now, because I
don't want to read this file and parse
it and do all sorts of other nasty
things, just because I love all of you,
I have gone ahead, and--
not, see, there's the season, there's the
episode one you missed, and, we're gonna
see from right in here, as a great
friendly dev, I took this file, and pulled
out all these values. Now, some of them
are actually computations, so if you if
you look, like, a little bit further down,
you'll see some stuff in here-- these are
buttons, sorry, I remember the one that
was "hangeul" (and both spellings), so this could
actually be-- you could see that this is
like "scan code 122" is this key, and here
it is again, but now with the "U" and the "E"
changed, so that's, uh, that's a lot of
fun. But I love that there exists this
key, by the way, I don't know why my
keyboard doesn't have it, but there is
actually a coffee key, and I just-- just in
honor of you, coffee key [salutes and drinks], such a good key,
I need that key, I don't want this key at
all, and that kind of scares me, but
you know, there's all sorts of fun keys in
here, like I need to get this to do
something interesting [KEY_EJECTCD], but we'll worry
about that a little bit later. We are
going to cycle windows plenty of times.
So instead of processing all that,
I'm going to just take this, except, I've got
the reverse problem-- I get a scan code,
and I want to get the key out of it.
So to save a little time, I went and I reversed
that list for you, of course, now they're
quoted, because it's dictionary, and
JSON wonders, but, if I look down here
I've got my, oh! Did I pull the coffee key out?
OH NO!
Well, there's some parsing
fun going on in here,
but the-- oh yeah it would have been 152,
that's a bummer,
it also has screen lock,
oh, I overwrote it, alright, so it's not a
perfect file, but you know, basically it's--
this will get us, for a given
scan code, this will give us a one-to-one
mapping to which particular button it is.
I'm just-- just curious, okay yeah so,
it was when I dumped the thing out, I've
actually got the coffee key in there, but
in the other direction we've only got
one position for a 152, I don't want to
make this a complicated data structure.
You can do that on a whiteboard interview
if you want in Silicon Valley,
it doesn't-- just, just go ahead. That is
absolutely where we're going, eftwo, that--
that's what we're doing! We are
making that-- that thing, I'm not gonna
say what it is, but, we can
actually do anything we want with it!
I shouldn't say that, we can do anything we
want for key-input-magic-key-stuff, so
how do we actually decode this thing,
well, let's read that file. So that
file we have over here, this thing, so
it's that and scan codes, we want the
reverse mapping, so I'm going to take
that as SCANCODE
I really wanna mention that it's a file,
okay "everything", yes so we're going to
read that thing in, and we're gonna
decode it. So it's not that much trouble
because I already packed it up in JSON,
and we already have JSON here, so we're
gonna do a little JSON load of the file, which
is called the SCANCODE_FILE. Now this is
regular ASCII so I don't have to worry
about it
and I'm gonna end up with scan codes--
scancode_decoder, it's my secret decoder
ring! So let's just make sure we get that
file in there right, and, there it is.
Now the only catch we have to watch
out for is that these are strings, they're not
numbers, so we have to remember that, and
trust me, I will forget it, but you're all
gonna tell me when I forget it, "AHHH, Guy,
it's a STRING!" So, let's go and
let's decode something. So
here we have the ev_value that we don't
care about, we have the ev_code which we
do care about, this is the scan code, so
we're gonna use the ev_code, except, just
before I forget, I'm just gonna turn it
into a string, because I know I'm gonna
forget, and I'm going to look just to
make sure it's in my dictionary, actually, let's
just call this the ev_code, I just don't
want to forget, and I know I'm gonna
forget, so let's just make sure that
that's in there, actually, if we
type a key that doesn't show up-- yeah,
alright, we'll be safe if the code
in the scan code decoder, then we're
gonna print that thing out, well, we'll just
leave this printing out normal, but, for
debugging, we're going to look--
because printf debugging-- and we're
going to just see what this corresponds
to by taking the decoder and for this
thing, and we don't want to see every
single key anymore, bad Guy. Hey! That's a
J, that's a K, that's an L, that's an N, and
when you're off by one, these things end
up being kind of crazy. So we can also
check our little magic keys we've got
all sorts of fun stuff here, but we don't
have a coffee key, you'll notice that the
key codes are different on the keypad,
so keypad "1" is different from regular "1",
you all know that, but, you know, we get
our F keys as long as they're not bound
to anything, but I don't have to worry
because this is not going through XInput,
so whatever I type on this
keyboard, it's not going to end up
messing me up, so, some of these keys
they're acting a little bit funny, I'm not
really sure what happened on this
particular keyboard, but we are getting
all of the normal keys. So now
that we have key names, we can actually
go and do something kind of fun with
them. So let's process key!
Alright eftwo, you're the one who
figured it out, so, what do you want the
first action to be for our processed key
key name, okay, I'll be pythonic,
eftwo, I'm just gonna make sure I set the right thing up
here, "obviously you need a key to add some mana",
okay, that's actually a web thing,
so that-- that'd be like a whole other-- you
know, because then you have to build like
a WebSocket, and you know... "Ordering coffee"
we could-- I don't want to pick
something that's already open, but what's--
yeah, let's try ordering coffee, ordering
coffee sounds good.
What do you think, "C"? "C" is a good-- yes
I'm positive we're gonna have a coffee
shop REST API, yeah that-- that's-- I
like where you guys are going. Okay, so
let's-- yeah, let's do it. Let's
turn that into a URL, so we'll do it in a
giant "if" block, actually, let's just make
a command dictionary, so we're gonna--
we're gonna say if we get a key C,
"C" sound good? Yeah...
then we're going to open up a browser, so
let's pop open chrome, and-- chromium,
all right, so let's pop open chromium and
make sure we're in incognito mode,
and let's let's go to duck duck go
and I think just need a query on
them for a coffee API, I'm gonna manually
escape it for now, alright so-- and just
for error-checking, let's make a--
let's make a query to see, "I do nothing fun".
Alright, so, if key name is in our commands
and we can take a look at what we're
gonna get if we do this. Okay, K is
not there, but Q is there, okay and, of
course, we've got our coffee key.
Alright, neat, so let's-- let's do it!
[sarcastically] Nothing could go wrong with this sort of
code! ha ha! Okay, so let's-- well it actually
told us "I do nothing fun." Oh man, there
you go!
Bob's your uncle! There is actually a
coffee API I-- I didn't know! I-- I don't
know what's gonna happen-- oh, oh, you know
what? This is gonna lead to something
very good, because I think we're gonna
have to cover that in another stream, but
this is-- this is the most insane protocol
on the internet that I love. This is an
RFC for the HTCP-CP and if you're not
down with the HTCPCP you're just not
ready for life. I mean, it's just... Now the
one problem we got here is of course I
forgot to put this in the background, so
we're gonna just fix that real quick, and
we like quoting things,
cause even though we're doing it-- alright, so we're just gonna
make these commands go in the background.
All right, great.
Now let's get down with the HTCPCP.
The Hyper Text Coffee Pot Control Protocol.
That's right, RFC 2324 we are ready to
make this thing brew coffee. So I'm gonna
go get a coffee machine--
Okay, no no, we're gonna do the
coffee machine next time but, nope, no, not
next time, there's actually a schedule
but I'll put that on the list, if you're
all interested in it.
So the coffee text-- the hypertext
coffeepot control protocol happens to
have something that some of you may have
run into on the web, which is about the
418 error message, this is actually what
it comes from for those of you who don't
know, but sometimes you might get an 8--
these are HTCPCP return codes, they're
modeled on HTTP, there is the not
acceptable, but, more fun is the 418 I am
a teapot.
You can't send HTCPCP commands to a
teapot, that's just-- that's just not
covered. that's-- that's a completely
different thing. Cody, we're gonna
build it, we're not gonna sit around
waiting for a coffee pot, I don't-- I don't
even know if there is a coffee pot that
is HTCPCP compatible
question mark? I know it's not-- is it
k-cup compatible? See, I don't care-- is it-- no,
see, I don't know where I'd buy
this thing, I don't know where's the
shopping, I mean, can
google do better?
I mean, HTCPCP, oh they are just updating
their terms service all the time! Is
that just a permanent part? Alright, I
don't get compatible coffee-- no, devices!--
someone must have built it, but clearly
no one's selling it, so we're--
we're gonna make one of these. Not now.
Getting away from the coffee pot
control protocol, this is actually--
that's it! That's, you got
your stream deck, I can hook this
up to an event interface, I can hook it
up to OBS
and get it to change scenes, and that's--
what I'm going to be doing, believe you
me, but we might just have to go get a
coffee pot for where we're going next.
Now this actually works with just
about anything,
as you saw, so I can go in here and
add, you know, whatever, I mean let's
add xeyes, for example, which,
unfortunately will not stream for me, so
I'm gonna-- we're gonna close this guy,
and we're gonna go look for our xeyes.
Now xeyes popped up here but you're not--
unfortunately you're not able to see it,
so I'm gonna throw it over here
on the whiteboard for you, and there it
is. There's our eyes. I can go ahead
and add more-- now what's cool about this
is it doesn't matter what application is
active because this is not participating
in the XInput system, so whenever I hit
a key like that X key I just added,
I can go as crazy as I want here. oh, whoa,
that's some serious eyes-- now
we're gonna want to get rid of all
those eyes-- yeah, you guys gotta go,
I'm sorry, it's just-- it's a rough death.
But anyway, very cool that it works
pretty much anywhere I am, so I can
be scrolling around, and wondering what's
going on-- oh, what was the coffeepot
control, like, oh yeah, there it is! That's--
that's where I find that! Alright, so I
think we've gone ahead and shown you
what magical bindings means except I can
remember that this is a touchpad and I
can just go ahead draw all over it. I
think we've gotten our share of key
magic here, in fact I'm so happy with it,
that I'm just gonna change colors for
all of you and when I'm done with my
terrible artwork,
Alright, I don't know, it looks
like that, but when we're done with
all that, we can have some
fun, we basically just built a stream
deck. This can be done XInput and all
of that stuff, there are a bunch of
compatibility libraries for Windows and
I don't want to get into it, though, I
mean it's-- someone who's more
motivated than me on that and can. Feel
free, I'll drop this code off
somewhere, but you can get it from the
stream.
I, yeah, I do think we're gonna
need to turn a cheap coffee pot into a
smart one. One of the things that I've
always loved
I did work briefly in consumer
electronics, and we we had a habit--
robotics stuff-- this was my time over in
Hong Kong, but we used to
joke about "smart" because usually
whenever a product involves, and this
this is something that Scott actually is
huge on, he was over at-- he's exflix
too. When you put "smart" in
front of a device name that usually
means it doesn't work, and it's very
expensive. So like "smart coffee"--
nobody wants "smart coffee". We want
"coffee" and we want it to-- to work-- and,
you know, I mean "smart" has that-- I mean,
I don't want to call it "IOT coffee", I
guess that might be a little more modern.
Oh yeah, thanks eftwo, I appreciate
it, that's-- I do practice this, this stuff
takes some prep but trying to
"be dense" and give you everything within an
hour, so if, if I can stick to that I
think I think I'm gonna be pretty happy
with with how that's going. I don't
have-- this is this is
pretty much where we're going to
stop that. I have a few other, I mean
there's a whole season already laid out--
[laughing] Yes, that's a great idea Cody, I have a--
there's a whole season, there's a lot of
stuff, I'm gonna post the schedule, I
meant to do it before today, I just
didn't finish, there was some issues with
that padding that I showed you earlier,
to get that. "Why is that always zero? Yeah,
this number's not that big, yeah--" anyway
that's the part that I don't
think is really fun for the stream, but,
the next week I'm gonna be covering--
it is gonna be another hardware hack,
we're going to be working with a
rotary encoder, so, for those of you don't
know that's kind of like a pot on
a, if you're from-- it's a potentiometer,
except it has no limits, so a
potentiometer, it's like-- think
like a volume switch you know, so like,
classic volume switches that--
you know, you turned it all the way to 0 and it's
limited, then you turn it all the way up,
to 11, but this-- they have limits on that,
and that's actually working by
resistance, so, a rotary encoder basically
kind of does the same thing but it's
different physics. It's infinite, so
instead it just encodes whenever the
wheel is turning
rather than having limits, so it's better
for infinite kinds of devices. For those
of you who are going to be around, you're
actually going to get a little bit of a
surprise that I'm going to be doing
LuxJam, so I told Lana Lux that I
would participate in her jam and I
didn't really have any time to work out
a game programming toolkit so I'm going
in basically blind. This is gonna be a
live learn session and it's not part of
the normal season so I'll mark it
correctly but the Lux Jam starts today
at
6:00 p.m. so I'm gonna be in some
serious hack mode this weekend. So we'll
see if we can get-- maybe, I don't know,
maybe the game will be just hooking up a
coffeepot, no promises, but, well, I hope
you all enjoyed the show! Thank you
very much!