130 lines
4.9 kB
1
defmodule BlogWeb.KeyloggerLive do
2
use BlogWeb, :live_view
3
import BlogWeb.CoreComponents
4
require Logger
5
@meta_attrs [
6
%{name: "title", content: "See what key you are pressing, and have it remembered"},
7
%{name: "description", content: "See what key you are pressing. It also will keep what you type on hand to print if you want"},
8
%{property: "og:title", content: "See what key you are pressing, and have it remembered"},
9
%{property: "og:description", content: "See what key you are pressing. It also will keep what you type on hand to print if you want"},
10
%{property: "og:type", content: "website"}
11
]
12
13
def mount(_params, _session, socket) do
14
{:ok,
15
assign(socket,
16
pressed_key: "",
17
pressed_keys: "",
18
show_modal: true,
19
page_title: "Experiment - sorta typewriter",
20
meta_attrs: @meta_attrs
21
)}
22
end
23
24
def handle_event("keydown", %{"key" => key}, socket) do
25
Logger.info("Key pressed: #{key}")
26
pressed_keys =
27
case key do
28
"Backspace" ->
29
# first we reverse the string, and take the firts character
30
<<_last_character::binary-size(1), rest::binary>> = String.reverse(socket.assigns.pressed_keys)
31
# then since its reversed, and just that one sliced off, we have
32
# effectively "backspaced" and we can now reverse the list again, and
33
# we have the copy that the user desires, successfuly having reached their
34
# backspace escape hatch
35
String.reverse(rest)
36
"Meta" ->
37
# If it is the meta key, they aren't going to be able to
38
# type a character, so we just skip it too
39
socket.assigns.pressed_keys
40
"Shift" ->
41
# if its shift, we skip because the character that shift creates comes next,
42
# e.g, shift + A comes along when shift and a are pressed but we just want the A
43
# so, since we know its coming here, we skip the key itself and
44
# trust that the next event will come
45
socket.assigns.pressed_keys
46
"Enter" ->
47
socket.assigns.pressed_keys <> "\r\n"
48
_ -> socket.assigns.pressed_keys <> key
49
end
50
{:noreply, assign(socket, pressed_key: key, pressed_keys: pressed_keys) |> assign(show_modal: false)}
51
end
52
53
def handle_event("toggle_modal", %{"value" => _}, socket) do
54
{:noreply, assign(socket, show_modal: !socket.assigns.show_modal)}
55
end
56
def handle_event("toggle_modal", _, socket) do
57
{:noreply, assign(socket, show_modal: !socket.assigns.show_modal)}
58
end
59
60
def render(assigns) do
61
~H"""
62
<style>
63
@media print {
64
/* Hide everything by default */
65
body * {
66
visibility: hidden;
67
}
68
69
/* Only show the content we want to print */
70
#content-of-letter,
71
#content-of-letter * {
72
visibility: visible;
73
}
74
75
/* Position the content at the top of the page */
76
#content-of-letter {
77
position: absolute;
78
left: 0;
79
top: 0;
80
width: 100%;
81
text-align: left;
82
white-space: pre-wrap;
83
font-family: "Courier New", Courier, monospace;
84
font-size: 14px;
85
line-height: 1.5;
86
color: #333;
87
padding: 2rem;
88
}
89
}
90
91
.cursor {
92
display: inline-block;
93
width: 2px;
94
height: 1em;
95
background-color: #333;
96
margin-left: 1px;
97
animation: blink 1s step-end infinite;
98
}
99
</style>
100
101
<.head_tags meta_attrs={@meta_attrs} page_title={@page_title} />
102
<h1 class="text-[75px]">Pressing: <%= @pressed_key %></h1>
103
<%= if @show_modal do %>
104
<div class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center" phx-click="toggle_modal">
105
<div class="bg-white p-8 rounded-lg shadow-lg max-w-lg" phx-click-away="toggle_modal">
106
<div class="prose">
107
<p class="font-mono text-gray-800">
108
Simulate a typewriter. We server this up so that when you type out a letter its as if it were on a typewriter, and we package it up to print for whoever you would like if you press the right key shortcut or button
109
</p>
110
</div>
111
<div class="mt-6 flex justify-end">
112
<button
113
phx-click="toggle_modal"
114
class="px-4 py-2 bg-gray-800 text-gray-100 rounded hover:bg-gray-700 font-mono"
115
>
116
Close
117
</button>
118
</div>
119
</div>
120
</div>
121
<% end %>
122
<div id="content-of-letter" class="mt-4 text-gray-500" phx-window-keydown="keydown">
123
THIS COPY IS PROVIDED WITH NO COPY AND PASTE AND IS ALL HAND WRITTEN BY YOUR COMMON HUMAN FRIEND
124
<br>
125
<div class="whitespace-pre-wrap"><%= @pressed_keys %></div>
126
</div>
127
"""
128
end
129
130
end
131