17 |
20 |
Keyboard shortcuts
21 |
22 |
Ctrl-Q or ⌘Q = quit
23 |
F5 = reload
24 |
Ctrl-[ = go back
25 |
Ctrl-] = go forward
26 |
Ctrl-J = run Javascript (debug_keys: true)
27 |
Ctrl-O = go to URL (debug_keys: true)
28 |
29 |
Next steps in IEx
30 |
31 |
iex> WebengineKiosk.go_to_url(browser_pid, "https://elixir-lang.org")
32 |
:ok
33 |
iex> WebengineKiosk.go_home(browser_pid)
34 |
:ok
35 |
iex> WebengineKiosk.run_javascript(browser_pid, "window.alert('Hello, Elixir!')")
36 |
:ok
37 |
iex> WebengineKiosk.back(browser_pid)
38 |
:ok
39 |
iex> WebengineKiosk.blank(browser_pid)
40 |
:ok
41 |
iex> WebengineKiosk.unblank(browser_pid)
42 |
:ok
43 |
iex> WebengineKiosk.set_zoom(browser_pid, 2)
44 |
:ok
45 |
46 |
Useful links
47 |
55 |
56 |
57 |
58 |
--------------------------------------------------------------------------------
/lib/webengine_kiosk/input_event.ex:
--------------------------------------------------------------------------------
1 | if Code.ensure_loaded?(SystemRegistry) do
2 | defmodule WebengineKiosk.InputEvent do
3 | use GenServer
4 |
5 | require Logger
6 |
7 | @dev "/dev"
8 | @group 1000
9 |
10 | def start_link(opts) do
11 | GenServer.start_link(__MODULE__, opts)
12 | end
13 |
14 | def init(opts) do
15 | Application.ensure_all_started(:system_registry)
16 | gid = opts[:gid] || @group
17 | SystemRegistry.register()
18 |
19 | {:ok,
20 | %{
21 | inputs: [],
22 | gid: gid(gid)
23 | }}
24 | end
25 |
26 | def handle_info(
27 | {:system_registry, :global, %{state: %{"subsystems" => %{"input" => inputs}}}},
28 | %{inputs: inputs} = state
29 | ) do
30 | {:noreply, state}
31 | end
32 |
33 | def handle_info(
34 | {:system_registry, :global, %{state: %{"subsystems" => %{"input" => inputs}}} = reg},
35 | state
36 | ) do
37 | inputs = Enum.reject(inputs, &(&1 in state.inputs))
38 |
39 | {events, other_inputs} =
40 | Enum.split_with(inputs, &String.starts_with?(List.last(&1), "event"))
41 |
42 | new_events =
43 | events
44 | |> Enum.map(&{&1, get_in(reg, &1)})
45 | |> Enum.reject(&is_nil(elem(&1, 1)))
46 | |> Enum.map(&{elem(&1, 0), Map.get(elem(&1, 1), "devname")})
47 | |> Enum.filter(&(chgrp(elem(&1, 1), state.gid) == :ok))
48 | |> Enum.map(&elem(&1, 0))
49 |
50 | inputs = new_events ++ other_inputs ++ state.inputs
51 |
52 | {:noreply, %{state | inputs: inputs}}
53 | end
54 |
55 | def handle_info({:system_registry, _, _}, state) do
56 | {:noreply, state}
57 | end
58 |
59 | defp chgrp(devname, gid) do
60 | path = Path.join(@dev, devname)
61 | _ = Logger.info("webengine_kiosk: chgrp #{path}")
62 | File.chgrp(path, gid)
63 | end
64 |
65 | defp gid(gid) when is_integer(gid), do: gid
66 |
67 | defp gid(gid) when is_binary(gid) do
68 | case File.read("/etc/group") do
69 | {:ok, groups} ->
70 | group_rec =
71 | groups
72 | |> String.split()
73 | |> Enum.find(&String.starts_with?(&1, gid))
74 |
75 | case group_rec do
76 | nil ->
77 | @group
78 |
79 | group_rec ->
80 | [_, _, gid | _] = String.split(group_rec, ":")
81 | String.to_integer(gid)
82 | end
83 |
84 | _ ->
85 | @group
86 | end
87 | end
88 | end
89 | end
90 |
--------------------------------------------------------------------------------
/lib/webengine_kiosk/message.ex:
--------------------------------------------------------------------------------
1 | defmodule WebengineKiosk.Message do
2 | # These should match KioskMessage.h
3 | @msg_go_to_url 1
4 | @msg_run_javascript 2
5 | @msg_loading_page 3
6 | @msg_progress 4
7 | @msg_finished_loading_page 5
8 | @msg_url_changed 6
9 | @msg_blank 7
10 | @msg_wakeup 8
11 | @msg_reload 9
12 | @msg_go_back 10
13 | @msg_go_forward 11
14 | @msg_stop_loading 12
15 | @msg_set_zoom 13
16 | @msg_browser_crashed 14
17 | @msg_console_log 15
18 | @msg_channel_msg 16
19 |
20 | @moduledoc false
21 |
22 | @spec go_to_url(String.t()) :: <<_::8, _::_*8>>
23 | def go_to_url(url), do: <<@msg_go_to_url, url::binary>>
24 |
25 | @spec run_javascript(String.t()) :: <<_::8, _::_*8>>
26 | def run_javascript(code), do: <<@msg_run_javascript, code::binary>>
27 |
28 | @spec blank(boolean()) :: <<_::16>>
29 | def blank(true), do: <<@msg_blank, 1>>
30 | def blank(false), do: <<@msg_blank, 0>>
31 |
32 | @spec reload() :: <<_::8>>
33 | def reload(), do: <<@msg_reload>>
34 |
35 | @spec go_back() :: <<_::8>>
36 | def go_back(), do: <<@msg_go_back>>
37 |
38 | @spec go_forward() :: <<_::8>>
39 | def go_forward(), do: <<@msg_go_forward>>
40 |
41 | @spec stop_loading() :: <<_::8>>
42 | def stop_loading(), do: <<@msg_stop_loading>>
43 |
44 | @spec set_zoom(number()) :: <<_::8, _::_*8>>
45 | def set_zoom(factor) when is_number(factor) do
46 | str = to_string(factor)
47 | <<@msg_set_zoom, str::binary>>
48 | end
49 |
50 | @spec decode(binary()) ::
51 | :finished_loading_page
52 | | :started_loading_page
53 | | :wakeup
54 | | {:progress, byte()}
55 | | {:unknown, byte()}
56 | | {:url_changed, String.t()}
57 | | {:browser_crashed, atom(), byte()}
58 | | {:console_log, String.t()}
59 | | {:channel_message, String.t()}
60 | def decode(<<@msg_progress, value>>), do: {:progress, value}
61 | def decode(<<@msg_url_changed, url::binary>>), do: {:url_changed, url}
62 | def decode(<<@msg_loading_page>>), do: :started_loading_page
63 | def decode(<<@msg_finished_loading_page>>), do: :finished_loading_page
64 | def decode(<<@msg_wakeup>>), do: :wakeup
65 |
66 | def decode(<<@msg_browser_crashed, status, exit_code>>) do
67 | {:browser_crashed, termination_status(status), exit_code}
68 | end
69 |
70 | def decode(<<@msg_console_log, message::binary>>) do
71 | {:console_log, message}
72 | end
73 |
74 | def decode(<<@msg_channel_msg, message::binary>>) do
75 | {:channel_message, message}
76 | end
77 |
78 | def decode(<