mirror of
https://github.com/m1k1o/neko.git
synced 2024-07-24 14:40:50 +12:00
Merge branch 'master' of https://github.com/nurdism/neko into sk_lang
This commit is contained in:
commit
bac0686f20
@ -73,7 +73,8 @@ build() {
|
||||
build_image "xfce4"; \
|
||||
build_image "jwm"; \
|
||||
build_image "firefox"; \
|
||||
build_image "chromium";
|
||||
build_image "chromium"; \
|
||||
build_image "tor-browser";
|
||||
fi
|
||||
|
||||
sudo docker images nurdism/neko
|
||||
@ -90,6 +91,7 @@ push() {
|
||||
sudo docker push nurdism/neko:jwm
|
||||
sudo docker push nurdism/neko:firefox
|
||||
sudo docker push nurdism/neko:chromium
|
||||
sudo docker push nurdism/neko:tor-browser
|
||||
fi
|
||||
}
|
||||
|
||||
|
28
.docker/files/tor-browser/Dockerfile
Normal file
28
.docker/files/tor-browser/Dockerfile
Normal file
@ -0,0 +1,28 @@
|
||||
FROM nurdism/neko:openbox
|
||||
|
||||
#
|
||||
# install dependencies
|
||||
RUN set -eux; apt-get update; \
|
||||
apt-get install -y --no-install-recommends curl xz-utils file libgtk-3-0 libdbus-glib-1-2; \
|
||||
#
|
||||
# clean up
|
||||
apt-get clean -y; \
|
||||
rm -rf /var/lib/apt/lists/* /var/cache/apt/*
|
||||
|
||||
WORKDIR /home/neko
|
||||
USER neko
|
||||
|
||||
#
|
||||
# download TOR browser
|
||||
RUN DOWNLOAD_URI="$(curl -s -N https://www.torproject.org/download/ | grep -Po -m 1 '(?=(dist/torbrowser)).*(?<=.tar.xz)')"; \
|
||||
echo "Downloading $DOWNLOAD_URI"; \
|
||||
curl -sSL -o tor.tar.xz "https://www.torproject.org/$DOWNLOAD_URI"; \
|
||||
tar -xvJf tor.tar.xz; \
|
||||
rm -f tor.tar.xz*;
|
||||
|
||||
USER root
|
||||
|
||||
#
|
||||
# copy configuation file
|
||||
COPY .docker/files/tor-browser/supervisord.conf /etc/neko/supervisord/tor-browser.conf
|
||||
COPY .docker/files/tor-browser/openbox.xml /etc/neko/openbox.xml
|
763
.docker/files/tor-browser/openbox.xml
Normal file
763
.docker/files/tor-browser/openbox.xml
Normal file
@ -0,0 +1,763 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<!-- Default openbox config but all window decorations are moved
|
||||
thereby making it harder to accidentally close the virtual browser -->
|
||||
|
||||
<openbox_config xmlns="http://openbox.org/3.4/rc"
|
||||
xmlns:xi="http://www.w3.org/2001/XInclude">
|
||||
|
||||
<resistance>
|
||||
<strength>10</strength>
|
||||
<screen_edge_strength>20</screen_edge_strength>
|
||||
</resistance>
|
||||
|
||||
<applications>
|
||||
<!-- Match all windows and remove their decorations (obxprop | grep "^_OB_APP") -->
|
||||
<application class="Tor*" name="Navigator">
|
||||
<decor>no</decor>
|
||||
<maximized>true</maximized>
|
||||
<focus>yes</focus>
|
||||
<layer>normal</layer>
|
||||
</application>
|
||||
</applications>
|
||||
|
||||
<focus>
|
||||
<focusNew>yes</focusNew>
|
||||
<!-- always try to focus new windows when they appear. other rules do
|
||||
apply -->
|
||||
<followMouse>no</followMouse>
|
||||
<!-- move focus to a window when you move the mouse into it -->
|
||||
<focusLast>yes</focusLast>
|
||||
<!-- focus the last used window when changing desktops, instead of the one
|
||||
under the mouse pointer. when followMouse is enabled -->
|
||||
<underMouse>no</underMouse>
|
||||
<!-- move focus under the mouse, even when the mouse is not moving -->
|
||||
<focusDelay>200</focusDelay>
|
||||
<!-- when followMouse is enabled, the mouse must be inside the window for
|
||||
this many milliseconds (1000 = 1 sec) before moving focus to it -->
|
||||
<raiseOnFocus>no</raiseOnFocus>
|
||||
<!-- when followMouse is enabled, and a window is given focus by moving the
|
||||
mouse into it, also raise the window -->
|
||||
</focus>
|
||||
|
||||
<placement>
|
||||
<policy>Smart</policy>
|
||||
<!-- 'Smart' or 'UnderMouse' -->
|
||||
<center>yes</center>
|
||||
<!-- whether to place windows in the center of the free area found or
|
||||
the top left corner -->
|
||||
<monitor>Primary</monitor>
|
||||
<!-- with Smart placement on a multi-monitor system, try to place new windows
|
||||
on: 'Any' - any monitor, 'Mouse' - where the mouse is, 'Active' - where
|
||||
the active window is, 'Primary' - only on the primary monitor -->
|
||||
<primaryMonitor>1</primaryMonitor>
|
||||
<!-- The monitor where Openbox should place popup dialogs such as the
|
||||
focus cycling popup, or the desktop switch popup. It can be an index
|
||||
from 1, specifying a particular monitor. Or it can be one of the
|
||||
following: 'Mouse' - where the mouse is, or
|
||||
'Active' - where the active window is -->
|
||||
</placement>
|
||||
|
||||
<theme>
|
||||
<name>Clearlooks</name>
|
||||
<titleLayout>NLIMC</titleLayout>
|
||||
<!--
|
||||
available characters are NDSLIMC, each can occur at most once.
|
||||
N: window icon
|
||||
L: window label (AKA title).
|
||||
I: iconify
|
||||
M: maximize
|
||||
C: close
|
||||
S: shade (roll up/down)
|
||||
D: omnipresent (on all desktops).
|
||||
-->
|
||||
<keepBorder>yes</keepBorder>
|
||||
<animateIconify>yes</animateIconify>
|
||||
<font place="ActiveWindow">
|
||||
<name>sans</name>
|
||||
<size>8</size>
|
||||
<!-- font size in points -->
|
||||
<weight>bold</weight>
|
||||
<!-- 'bold' or 'normal' -->
|
||||
<slant>normal</slant>
|
||||
<!-- 'italic' or 'normal' -->
|
||||
</font>
|
||||
<font place="InactiveWindow">
|
||||
<name>sans</name>
|
||||
<size>8</size>
|
||||
<!-- font size in points -->
|
||||
<weight>bold</weight>
|
||||
<!-- 'bold' or 'normal' -->
|
||||
<slant>normal</slant>
|
||||
<!-- 'italic' or 'normal' -->
|
||||
</font>
|
||||
<font place="MenuHeader">
|
||||
<name>sans</name>
|
||||
<size>9</size>
|
||||
<!-- font size in points -->
|
||||
<weight>normal</weight>
|
||||
<!-- 'bold' or 'normal' -->
|
||||
<slant>normal</slant>
|
||||
<!-- 'italic' or 'normal' -->
|
||||
</font>
|
||||
<font place="MenuItem">
|
||||
<name>sans</name>
|
||||
<size>9</size>
|
||||
<!-- font size in points -->
|
||||
<weight>normal</weight>
|
||||
<!-- 'bold' or 'normal' -->
|
||||
<slant>normal</slant>
|
||||
<!-- 'italic' or 'normal' -->
|
||||
</font>
|
||||
<font place="ActiveOnScreenDisplay">
|
||||
<name>sans</name>
|
||||
<size>9</size>
|
||||
<!-- font size in points -->
|
||||
<weight>bold</weight>
|
||||
<!-- 'bold' or 'normal' -->
|
||||
<slant>normal</slant>
|
||||
<!-- 'italic' or 'normal' -->
|
||||
</font>
|
||||
<font place="InactiveOnScreenDisplay">
|
||||
<name>sans</name>
|
||||
<size>9</size>
|
||||
<!-- font size in points -->
|
||||
<weight>bold</weight>
|
||||
<!-- 'bold' or 'normal' -->
|
||||
<slant>normal</slant>
|
||||
<!-- 'italic' or 'normal' -->
|
||||
</font>
|
||||
</theme>
|
||||
|
||||
<desktops>
|
||||
<!-- this stuff is only used at startup, pagers allow you to change them
|
||||
during a session
|
||||
|
||||
these are default values to use when other ones are not already set
|
||||
by other applications, or saved in your session
|
||||
|
||||
use obconf if you want to change these without having to log out
|
||||
and back in -->
|
||||
<number>1</number>
|
||||
<firstdesk>1</firstdesk>
|
||||
<names>
|
||||
<!-- set names up here if you want to, like this:
|
||||
<name>desktop 1</name>
|
||||
<name>desktop 2</name>
|
||||
-->
|
||||
</names>
|
||||
<popupTime>875</popupTime>
|
||||
<!-- The number of milliseconds to show the popup for when switching
|
||||
desktops. Set this to 0 to disable the popup. -->
|
||||
</desktops>
|
||||
|
||||
<resize>
|
||||
<drawContents>yes</drawContents>
|
||||
<popupShow>Nonpixel</popupShow>
|
||||
<!-- 'Always', 'Never', or 'Nonpixel' (xterms and such) -->
|
||||
<popupPosition>Center</popupPosition>
|
||||
<!-- 'Center', 'Top', or 'Fixed' -->
|
||||
<popupFixedPosition>
|
||||
<!-- these are used if popupPosition is set to 'Fixed' -->
|
||||
|
||||
<x>10</x>
|
||||
<!-- positive number for distance from left edge, negative number for
|
||||
distance from right edge, or 'Center' -->
|
||||
<y>10</y>
|
||||
<!-- positive number for distance from top edge, negative number for
|
||||
distance from bottom edge, or 'Center' -->
|
||||
</popupFixedPosition>
|
||||
</resize>
|
||||
|
||||
<!-- You can reserve a portion of your screen where windows will not cover when
|
||||
they are maximized, or when they are initially placed.
|
||||
Many programs reserve space automatically, but you can use this in other
|
||||
cases. -->
|
||||
<margins>
|
||||
<top>0</top>
|
||||
<bottom>0</bottom>
|
||||
<left>0</left>
|
||||
<right>0</right>
|
||||
</margins>
|
||||
|
||||
<dock>
|
||||
<position>TopLeft</position>
|
||||
<!-- (Top|Bottom)(Left|Right|)|Top|Bottom|Left|Right|Floating -->
|
||||
<floatingX>0</floatingX>
|
||||
<floatingY>0</floatingY>
|
||||
<noStrut>no</noStrut>
|
||||
<stacking>Above</stacking>
|
||||
<!-- 'Above', 'Normal', or 'Below' -->
|
||||
<direction>Vertical</direction>
|
||||
<!-- 'Vertical' or 'Horizontal' -->
|
||||
<autoHide>no</autoHide>
|
||||
<hideDelay>300</hideDelay>
|
||||
<!-- in milliseconds (1000 = 1 second) -->
|
||||
<showDelay>300</showDelay>
|
||||
<!-- in milliseconds (1000 = 1 second) -->
|
||||
<moveButton>Middle</moveButton>
|
||||
<!-- 'Left', 'Middle', 'Right' -->
|
||||
</dock>
|
||||
|
||||
<keyboard>
|
||||
<chainQuitKey>C-g</chainQuitKey>
|
||||
|
||||
<!-- Keybindings for desktop switching -->
|
||||
<keybind key="C-A-Left">
|
||||
<action name="GoToDesktop"><to>left</to><wrap>no</wrap></action>
|
||||
</keybind>
|
||||
<keybind key="C-A-Right">
|
||||
<action name="GoToDesktop"><to>right</to><wrap>no</wrap></action>
|
||||
</keybind>
|
||||
<keybind key="C-A-Up">
|
||||
<action name="GoToDesktop"><to>up</to><wrap>no</wrap></action>
|
||||
</keybind>
|
||||
<keybind key="C-A-Down">
|
||||
<action name="GoToDesktop"><to>down</to><wrap>no</wrap></action>
|
||||
</keybind>
|
||||
<keybind key="S-A-Left">
|
||||
<action name="SendToDesktop"><to>left</to><wrap>no</wrap></action>
|
||||
</keybind>
|
||||
<keybind key="S-A-Right">
|
||||
<action name="SendToDesktop"><to>right</to><wrap>no</wrap></action>
|
||||
</keybind>
|
||||
<keybind key="S-A-Up">
|
||||
<action name="SendToDesktop"><to>up</to><wrap>no</wrap></action>
|
||||
</keybind>
|
||||
<keybind key="S-A-Down">
|
||||
<action name="SendToDesktop"><to>down</to><wrap>no</wrap></action>
|
||||
</keybind>
|
||||
<keybind key="W-F1">
|
||||
<action name="GoToDesktop"><to>1</to></action>
|
||||
</keybind>
|
||||
<keybind key="W-F2">
|
||||
<action name="GoToDesktop"><to>2</to></action>
|
||||
</keybind>
|
||||
<keybind key="W-F3">
|
||||
<action name="GoToDesktop"><to>3</to></action>
|
||||
</keybind>
|
||||
<keybind key="W-F4">
|
||||
<action name="GoToDesktop"><to>4</to></action>
|
||||
</keybind>
|
||||
<keybind key="W-d">
|
||||
<action name="ToggleShowDesktop"/>
|
||||
</keybind>
|
||||
|
||||
<!-- Keybindings for windows -->
|
||||
<keybind key="A-F4">
|
||||
<action name="Close"/>
|
||||
</keybind>
|
||||
<keybind key="A-Escape">
|
||||
<action name="Lower"/>
|
||||
<action name="FocusToBottom"/>
|
||||
<action name="Unfocus"/>
|
||||
</keybind>
|
||||
<keybind key="A-space">
|
||||
<!--action name="ShowMenu"><menu>client-menu</menu></action-->
|
||||
</keybind>
|
||||
<!-- Take a screenshot of the current window with scrot when Alt+Print are pressed -->
|
||||
<keybind key="A-Print">
|
||||
<action name="Execute"><command>scrot -s</command></action>
|
||||
</keybind>
|
||||
|
||||
<!-- Keybindings for window switching -->
|
||||
<keybind key="A-Tab">
|
||||
<action name="NextWindow">
|
||||
<finalactions>
|
||||
<action name="Focus"/>
|
||||
<action name="Raise"/>
|
||||
<action name="Unshade"/>
|
||||
</finalactions>
|
||||
</action>
|
||||
</keybind>
|
||||
<keybind key="A-S-Tab">
|
||||
<action name="PreviousWindow">
|
||||
<finalactions>
|
||||
<action name="Focus"/>
|
||||
<action name="Raise"/>
|
||||
<action name="Unshade"/>
|
||||
</finalactions>
|
||||
</action>
|
||||
</keybind>
|
||||
<keybind key="C-A-Tab">
|
||||
<action name="NextWindow">
|
||||
<panels>yes</panels><desktop>yes</desktop>
|
||||
<finalactions>
|
||||
<action name="Focus"/>
|
||||
<action name="Raise"/>
|
||||
<action name="Unshade"/>
|
||||
</finalactions>
|
||||
</action>
|
||||
</keybind>
|
||||
|
||||
<!-- Keybindings for window switching with the arrow keys -->
|
||||
<keybind key="W-S-Right">
|
||||
<action name="DirectionalCycleWindows">
|
||||
<direction>right</direction>
|
||||
</action>
|
||||
</keybind>
|
||||
<keybind key="W-S-Left">
|
||||
<action name="DirectionalCycleWindows">
|
||||
<direction>left</direction>
|
||||
</action>
|
||||
</keybind>
|
||||
<keybind key="W-S-Up">
|
||||
<action name="DirectionalCycleWindows">
|
||||
<direction>up</direction>
|
||||
</action>
|
||||
</keybind>
|
||||
<keybind key="W-S-Down">
|
||||
<action name="DirectionalCycleWindows">
|
||||
<direction>down</direction>
|
||||
</action>
|
||||
</keybind>
|
||||
|
||||
<!-- Keybindings for running applications -->
|
||||
<keybind key="W-e">
|
||||
<action name="Execute">
|
||||
<startupnotify>
|
||||
<enabled>true</enabled>
|
||||
<name>Konqueror</name>
|
||||
</startupnotify>
|
||||
<command>kfmclient openProfile filemanagement</command>
|
||||
</action>
|
||||
</keybind>
|
||||
<!-- Launch scrot when Print is pressed -->
|
||||
<keybind key="Print">
|
||||
<action name="Execute"><command>scrot</command></action>
|
||||
</keybind>
|
||||
</keyboard>
|
||||
|
||||
<mouse>
|
||||
<dragThreshold>1</dragThreshold>
|
||||
<!-- number of pixels the mouse must move before a drag begins -->
|
||||
<doubleClickTime>500</doubleClickTime>
|
||||
<!-- in milliseconds (1000 = 1 second) -->
|
||||
<screenEdgeWarpTime>400</screenEdgeWarpTime>
|
||||
<!-- Time before changing desktops when the pointer touches the edge of the
|
||||
screen while moving a window, in milliseconds (1000 = 1 second).
|
||||
Set this to 0 to disable warping -->
|
||||
<screenEdgeWarpMouse>false</screenEdgeWarpMouse>
|
||||
<!-- Set this to TRUE to move the mouse pointer across the desktop when
|
||||
switching due to hitting the edge of the screen -->
|
||||
|
||||
<context name="Frame">
|
||||
<mousebind button="A-Left" action="Press">
|
||||
<action name="Focus"/>
|
||||
<action name="Raise"/>
|
||||
</mousebind>
|
||||
<mousebind button="A-Left" action="Click">
|
||||
<action name="Unshade"/>
|
||||
</mousebind>
|
||||
<mousebind button="A-Left" action="Drag">
|
||||
<action name="Move"/>
|
||||
</mousebind>
|
||||
|
||||
<mousebind button="A-Right" action="Press">
|
||||
<action name="Focus"/>
|
||||
<action name="Raise"/>
|
||||
<action name="Unshade"/>
|
||||
</mousebind>
|
||||
<mousebind button="A-Right" action="Drag">
|
||||
<action name="Resize"/>
|
||||
</mousebind>
|
||||
|
||||
<mousebind button="A-Middle" action="Press">
|
||||
<action name="Lower"/>
|
||||
<action name="FocusToBottom"/>
|
||||
<action name="Unfocus"/>
|
||||
</mousebind>
|
||||
|
||||
<mousebind button="A-Up" action="Click">
|
||||
<action name="GoToDesktop"><to>previous</to></action>
|
||||
</mousebind>
|
||||
<mousebind button="A-Down" action="Click">
|
||||
<action name="GoToDesktop"><to>next</to></action>
|
||||
</mousebind>
|
||||
<mousebind button="C-A-Up" action="Click">
|
||||
<action name="GoToDesktop"><to>previous</to></action>
|
||||
</mousebind>
|
||||
<mousebind button="C-A-Down" action="Click">
|
||||
<action name="GoToDesktop"><to>next</to></action>
|
||||
</mousebind>
|
||||
<mousebind button="A-S-Up" action="Click">
|
||||
<action name="SendToDesktop"><to>previous</to></action>
|
||||
</mousebind>
|
||||
<mousebind button="A-S-Down" action="Click">
|
||||
<action name="SendToDesktop"><to>next</to></action>
|
||||
</mousebind>
|
||||
</context>
|
||||
|
||||
<context name="Titlebar">
|
||||
<mousebind button="Left" action="Drag">
|
||||
<action name="Move"/>
|
||||
</mousebind>
|
||||
<mousebind button="Left" action="DoubleClick">
|
||||
<action name="ToggleMaximize"/>
|
||||
</mousebind>
|
||||
|
||||
<mousebind button="Up" action="Click">
|
||||
<action name="if">
|
||||
<shaded>no</shaded>
|
||||
<then>
|
||||
<action name="Shade"/>
|
||||
<action name="FocusToBottom"/>
|
||||
<action name="Unfocus"/>
|
||||
<action name="Lower"/>
|
||||
</then>
|
||||
</action>
|
||||
</mousebind>
|
||||
<mousebind button="Down" action="Click">
|
||||
<action name="if">
|
||||
<shaded>yes</shaded>
|
||||
<then>
|
||||
<action name="Unshade"/>
|
||||
<action name="Raise"/>
|
||||
</then>
|
||||
</action>
|
||||
</mousebind>
|
||||
</context>
|
||||
|
||||
<context name="Titlebar Top Right Bottom Left TLCorner TRCorner BRCorner BLCorner">
|
||||
<mousebind button="Left" action="Press">
|
||||
<action name="Focus"/>
|
||||
<action name="Raise"/>
|
||||
<action name="Unshade"/>
|
||||
</mousebind>
|
||||
|
||||
<mousebind button="Middle" action="Press">
|
||||
<action name="Lower"/>
|
||||
<action name="FocusToBottom"/>
|
||||
<action name="Unfocus"/>
|
||||
</mousebind>
|
||||
|
||||
<!--mousebind button="Right" action="Press">
|
||||
<action name="Focus"/>
|
||||
<action name="Raise"/>
|
||||
<action name="ShowMenu"><menu>client-menu</menu></action>
|
||||
</mousebind-->
|
||||
</context>
|
||||
|
||||
<context name="Top">
|
||||
<mousebind button="Left" action="Drag">
|
||||
<action name="Resize"><edge>top</edge></action>
|
||||
</mousebind>
|
||||
</context>
|
||||
|
||||
<context name="Left">
|
||||
<mousebind button="Left" action="Drag">
|
||||
<action name="Resize"><edge>left</edge></action>
|
||||
</mousebind>
|
||||
</context>
|
||||
|
||||
<context name="Right">
|
||||
<mousebind button="Left" action="Drag">
|
||||
<action name="Resize"><edge>right</edge></action>
|
||||
</mousebind>
|
||||
</context>
|
||||
|
||||
<context name="Bottom">
|
||||
<mousebind button="Left" action="Drag">
|
||||
<action name="Resize"><edge>bottom</edge></action>
|
||||
</mousebind>
|
||||
|
||||
<!--mousebind button="Right" action="Press">
|
||||
<action name="Focus"/>
|
||||
<action name="Raise"/>
|
||||
<action name="ShowMenu"><menu>client-menu</menu></action>
|
||||
</mousebind-->
|
||||
</context>
|
||||
|
||||
<context name="TRCorner BRCorner TLCorner BLCorner">
|
||||
<mousebind button="Left" action="Press">
|
||||
<action name="Focus"/>
|
||||
<action name="Raise"/>
|
||||
<action name="Unshade"/>
|
||||
</mousebind>
|
||||
<mousebind button="Left" action="Drag">
|
||||
<action name="Resize"/>
|
||||
</mousebind>
|
||||
</context>
|
||||
|
||||
<context name="Client">
|
||||
<mousebind button="Left" action="Press">
|
||||
<action name="Focus"/>
|
||||
<action name="Raise"/>
|
||||
</mousebind>
|
||||
<mousebind button="Middle" action="Press">
|
||||
<action name="Focus"/>
|
||||
<action name="Raise"/>
|
||||
</mousebind>
|
||||
<mousebind button="Right" action="Press">
|
||||
<action name="Focus"/>
|
||||
<action name="Raise"/>
|
||||
</mousebind>
|
||||
</context>
|
||||
|
||||
<context name="Icon">
|
||||
<!--mousebind button="Left" action="Press">
|
||||
<action name="Focus"/>
|
||||
<action name="Raise"/>
|
||||
<action name="Unshade"/>
|
||||
<action name="ShowMenu"><menu>client-menu</menu></action>
|
||||
</mousebind>
|
||||
<mousebind button="Right" action="Press">
|
||||
<action name="Focus"/>
|
||||
<action name="Raise"/>
|
||||
<action name="ShowMenu"><menu>client-menu</menu></action>
|
||||
</mousebind-->
|
||||
</context>
|
||||
|
||||
<context name="AllDesktops">
|
||||
<mousebind button="Left" action="Press">
|
||||
<action name="Focus"/>
|
||||
<action name="Raise"/>
|
||||
<action name="Unshade"/>
|
||||
</mousebind>
|
||||
<mousebind button="Left" action="Click">
|
||||
<action name="ToggleOmnipresent"/>
|
||||
</mousebind>
|
||||
</context>
|
||||
|
||||
<context name="Shade">
|
||||
<mousebind button="Left" action="Press">
|
||||
<action name="Focus"/>
|
||||
<action name="Raise"/>
|
||||
</mousebind>
|
||||
<mousebind button="Left" action="Click">
|
||||
<action name="ToggleShade"/>
|
||||
</mousebind>
|
||||
</context>
|
||||
|
||||
<context name="Iconify">
|
||||
<mousebind button="Left" action="Press">
|
||||
<action name="Focus"/>
|
||||
<action name="Raise"/>
|
||||
</mousebind>
|
||||
<mousebind button="Left" action="Click">
|
||||
<action name="Iconify"/>
|
||||
</mousebind>
|
||||
</context>
|
||||
|
||||
<context name="Maximize">
|
||||
<mousebind button="Left" action="Press">
|
||||
<action name="Focus"/>
|
||||
<action name="Raise"/>
|
||||
<action name="Unshade"/>
|
||||
</mousebind>
|
||||
<mousebind button="Middle" action="Press">
|
||||
<action name="Focus"/>
|
||||
<action name="Raise"/>
|
||||
<action name="Unshade"/>
|
||||
</mousebind>
|
||||
<mousebind button="Right" action="Press">
|
||||
<action name="Focus"/>
|
||||
<action name="Raise"/>
|
||||
<action name="Unshade"/>
|
||||
</mousebind>
|
||||
<mousebind button="Left" action="Click">
|
||||
<action name="ToggleMaximize"/>
|
||||
</mousebind>
|
||||
<mousebind button="Middle" action="Click">
|
||||
<action name="ToggleMaximize"><direction>vertical</direction></action>
|
||||
</mousebind>
|
||||
<mousebind button="Right" action="Click">
|
||||
<action name="ToggleMaximize"><direction>horizontal</direction></action>
|
||||
</mousebind>
|
||||
</context>
|
||||
|
||||
<context name="Close">
|
||||
<mousebind button="Left" action="Press">
|
||||
<action name="Focus"/>
|
||||
<action name="Raise"/>
|
||||
<action name="Unshade"/>
|
||||
</mousebind>
|
||||
<mousebind button="Left" action="Click">
|
||||
<action name="Close"/>
|
||||
</mousebind>
|
||||
</context>
|
||||
|
||||
<context name="Desktop">
|
||||
<mousebind button="Up" action="Click">
|
||||
<action name="GoToDesktop"><to>previous</to></action>
|
||||
</mousebind>
|
||||
<mousebind button="Down" action="Click">
|
||||
<action name="GoToDesktop"><to>next</to></action>
|
||||
</mousebind>
|
||||
|
||||
<mousebind button="A-Up" action="Click">
|
||||
<action name="GoToDesktop"><to>previous</to></action>
|
||||
</mousebind>
|
||||
<mousebind button="A-Down" action="Click">
|
||||
<action name="GoToDesktop"><to>next</to></action>
|
||||
</mousebind>
|
||||
<mousebind button="C-A-Up" action="Click">
|
||||
<action name="GoToDesktop"><to>previous</to></action>
|
||||
</mousebind>
|
||||
<mousebind button="C-A-Down" action="Click">
|
||||
<action name="GoToDesktop"><to>next</to></action>
|
||||
</mousebind>
|
||||
|
||||
<mousebind button="Left" action="Press">
|
||||
<action name="Focus"/>
|
||||
<action name="Raise"/>
|
||||
</mousebind>
|
||||
<mousebind button="Right" action="Press">
|
||||
<action name="Focus"/>
|
||||
<action name="Raise"/>
|
||||
</mousebind>
|
||||
</context>
|
||||
|
||||
<context name="Root">
|
||||
<!-- Menus -->
|
||||
<!--mousebind button="Middle" action="Press">
|
||||
<action name="ShowMenu"><menu>client-list-combined-menu</menu></action>
|
||||
</mousebind>
|
||||
<mousebind button="Right" action="Press">
|
||||
<action name="ShowMenu"><menu>root-menu</menu></action>
|
||||
</mousebind-->
|
||||
</context>
|
||||
|
||||
<context name="MoveResize">
|
||||
<mousebind button="Up" action="Click">
|
||||
<action name="GoToDesktop"><to>previous</to></action>
|
||||
</mousebind>
|
||||
<mousebind button="Down" action="Click">
|
||||
<action name="GoToDesktop"><to>next</to></action>
|
||||
</mousebind>
|
||||
<mousebind button="A-Up" action="Click">
|
||||
<action name="GoToDesktop"><to>previous</to></action>
|
||||
</mousebind>
|
||||
<mousebind button="A-Down" action="Click">
|
||||
<action name="GoToDesktop"><to>next</to></action>
|
||||
</mousebind>
|
||||
</context>
|
||||
</mouse>
|
||||
|
||||
<menu>
|
||||
<!-- You can specify more than one menu file in here and they are all loaded,
|
||||
just don't make menu ids clash or, well, it'll be kind of pointless -->
|
||||
|
||||
<!-- default menu file (or custom one in $HOME/.config/openbox/) -->
|
||||
<!-- system menu files on Debian systems -->
|
||||
<!--file>/var/lib/openbox/debian-menu.xml</file-->
|
||||
<file>menu.xml</file>
|
||||
<hideDelay>200</hideDelay>
|
||||
<!-- if a press-release lasts longer than this setting (in milliseconds), the
|
||||
menu is hidden again -->
|
||||
<middle>no</middle>
|
||||
<!-- center submenus vertically about the parent entry -->
|
||||
<submenuShowDelay>100</submenuShowDelay>
|
||||
<!-- time to delay before showing a submenu after hovering over the parent
|
||||
entry.
|
||||
if this is a negative value, then the delay is infinite and the
|
||||
submenu will not be shown until it is clicked on -->
|
||||
<submenuHideDelay>400</submenuHideDelay>
|
||||
<!-- time to delay before hiding a submenu when selecting another
|
||||
entry in parent menu
|
||||
if this is a negative value, then the delay is infinite and the
|
||||
submenu will not be hidden until a different submenu is opened -->
|
||||
<showIcons>yes</showIcons>
|
||||
<!-- controls if icons appear in the client-list-(combined-)menu -->
|
||||
<manageDesktops>yes</manageDesktops>
|
||||
<!-- show the manage desktops section in the client-list-(combined-)menu -->
|
||||
</menu>
|
||||
|
||||
<applications>
|
||||
<!--
|
||||
# this is an example with comments through out. use these to make your
|
||||
# own rules, but without the comments of course.
|
||||
# you may use one or more of the name/class/role/title/type rules to specify
|
||||
# windows to match
|
||||
|
||||
<application name="the window's _OB_APP_NAME property (see obxprop)"
|
||||
class="the window's _OB_APP_CLASS property (see obxprop)"
|
||||
groupname="the window's _OB_APP_GROUP_NAME property (see obxprop)"
|
||||
groupclass="the window's _OB_APP_GROUP_CLASS property (see obxprop)"
|
||||
role="the window's _OB_APP_ROLE property (see obxprop)"
|
||||
title="the window's _OB_APP_TITLE property (see obxprop)"
|
||||
type="the window's _OB_APP_TYPE property (see obxprob)..
|
||||
(if unspecified, then it is 'dialog' for child windows)">
|
||||
# you may set only one of name/class/role/title/type, or you may use more
|
||||
# than one together to restrict your matches.
|
||||
|
||||
# the name, class, role, and title use simple wildcard matching such as those
|
||||
# used by a shell. you can use * to match any characters and ? to match
|
||||
# any single character.
|
||||
|
||||
# the type is one of: normal, dialog, splash, utility, menu, toolbar, dock,
|
||||
# or desktop
|
||||
|
||||
# when multiple rules match a window, they will all be applied, in the
|
||||
# order that they appear in this list
|
||||
|
||||
|
||||
# each rule element can be left out or set to 'default' to specify to not
|
||||
# change that attribute of the window
|
||||
|
||||
<decor>yes</decor>
|
||||
# enable or disable window decorations
|
||||
|
||||
<shade>no</shade>
|
||||
# make the window shaded when it appears, or not
|
||||
|
||||
<position force="no">
|
||||
# the position is only used if both an x and y coordinate are provided
|
||||
# (and not set to 'default')
|
||||
# when force is "yes", then the window will be placed here even if it
|
||||
# says you want it placed elsewhere. this is to override buggy
|
||||
# applications who refuse to behave
|
||||
<x>center</x>
|
||||
# a number like 50, or 'center' to center on screen. use a negative number
|
||||
# to start from the right (or bottom for <y>), ie -50 is 50 pixels from
|
||||
# the right edge (or bottom). use 'default' to specify using value
|
||||
# provided by the application, or chosen by openbox, instead.
|
||||
<y>200</y>
|
||||
<monitor>1</monitor>
|
||||
# specifies the monitor in a xinerama setup.
|
||||
# 1 is the first head, or 'mouse' for wherever the mouse is
|
||||
</position>
|
||||
|
||||
<size>
|
||||
# the size to make the window.
|
||||
<width>20</width>
|
||||
# a number like 20, or 'default' to use the size given by the application.
|
||||
# you can use fractions such as 1/2 or percentages such as 75% in which
|
||||
# case the value is relative to the size of the monitor that the window
|
||||
# appears on.
|
||||
<height>30%</height>
|
||||
</size>
|
||||
|
||||
<focus>yes</focus>
|
||||
# if the window should try be given focus when it appears. if this is set
|
||||
# to yes it doesn't guarantee the window will be given focus. some
|
||||
# restrictions may apply, but Openbox will try to
|
||||
|
||||
<desktop>1</desktop>
|
||||
# 1 is the first desktop, 'all' for all desktops
|
||||
|
||||
<layer>normal</layer>
|
||||
# 'above', 'normal', or 'below'
|
||||
|
||||
<iconic>no</iconic>
|
||||
# make the window iconified when it appears, or not
|
||||
|
||||
<skip_pager>no</skip_pager>
|
||||
# asks to not be shown in pagers
|
||||
|
||||
<skip_taskbar>no</skip_taskbar>
|
||||
# asks to not be shown in taskbars. window cycling actions will also
|
||||
# skip past such windows
|
||||
|
||||
<fullscreen>yes</fullscreen>
|
||||
# make the window in fullscreen mode when it appears
|
||||
|
||||
<maximized>true</maximized>
|
||||
# 'Horizontal', 'Vertical' or boolean (yes/no)
|
||||
</application>
|
||||
|
||||
# end of the example
|
||||
-->
|
||||
</applications>
|
||||
|
||||
</openbox_config>
|
13
.docker/files/tor-browser/supervisord.conf
Normal file
13
.docker/files/tor-browser/supervisord.conf
Normal file
@ -0,0 +1,13 @@
|
||||
[program:tor-browser]
|
||||
environment=HOME="/home/%(ENV_USER)s",USER="%(ENV_USER)s",DISPLAY="%(ENV_DISPLAY)s"
|
||||
command=/home/neko/tor-browser_en-US/Browser/start-tor-browser --display=%(ENV_DISPLAY)s --setDefaultBrowser --window-size 1280,720
|
||||
autorestart=true
|
||||
priority=800
|
||||
user=%(ENV_USER)s
|
||||
stdout_logfile=/var/log/neko/tor-browser.log
|
||||
stdout_logfile_maxbytes=100MB
|
||||
stdout_logfile_backups=10
|
||||
redirect_stderr=true
|
||||
stderr_logfile=/var/log/neko/tor-browser.err.log
|
||||
stderr_logfile_maxbytes=100MB
|
||||
stderr_logfile_backups=10
|
1
client/public/keyboard_layouts.json
Normal file
1
client/public/keyboard_layouts.json
Normal file
@ -0,0 +1 @@
|
||||
{"af":"Afghani","al":"Albanian","et":"Amharic","ma":"Arabic (Morocco)","sy":"Arabic (Syria)","am":"Armenian","az":"Azerbaijani","ml":"Bambara","bd":"Bangla","by":"Belarusian","be":"Belgian","dz":"Berber (Algeria, Latin characters)","ba":"Bosnian","bg":"Bulgarian","mm":"Burmese","hr":"Croatian","cz":"Czech","dk":"Danish","mv":"Dhivehi","nl":"Dutch","bt":"Dzongkha","au":"English (Australian)","cm":"English (Cameroon)","gh":"English (Ghana)","ng":"English (Nigeria)","za":"English (South Africa)","us":"English (US)","gb":"English (UK)","ee":"Estonian","fo":"Faroese","ph":"Filipino","fi":"Finnish","fr":"French","ca":"French (Canada)","cd":"French (Democratic Republic of the Congo)","gn":"French (Guinea)","tg":"French (Togo)","ge":"Georgian","de":"German","at":"German (Austria)","ch":"German (Switzerland)","gr":"Greek","il":"Hebrew","hu":"Hungarian","cn":"Chinese","is":"Icelandic","in":"Indian","id":"Indonesian (Jawi)","iq":"Iraqi","ie":"Irish","it":"Italian","jp":"Japanese","kz":"Kazakh","kh":"Khmer (Cambodia)","kr":"Korean","kg":"Kyrgyz","la":"Lao","lv":"Latvian","lt":"Lithuanian","mk":"Macedonian","my":"Malay (Jawi)","mt":"Maltese","md":"Moldavian","mn":"Mongolian","me":"Montenegrin","np":"Nepali","no":"Norwegian","ir":"Persian","pl":"Polish","pt":"Portuguese","br":"Portuguese (Brazil)","ro":"Romanian","ru":"Russian","rs":"Serbian","lk":"Sinhala (phonetic)","sk":"Slovak","si":"Slovenian","es":"Spanish","ke":"Swahili (Kenya)","tz":"Swahili (Tanzania)","se":"Swedish","tw":"Taiwanese","tj":"Tajik","th":"Thai","bw":"Tswana","tr":"Turkish","tm":"Turkmen","ua":"Ukrainian","pk":"Urdu (Pakistan)","uz":"Uzbek","vn":"Vietnamese","sn":"Wolof"}
|
@ -4,7 +4,7 @@
|
||||
<li>
|
||||
<span>{{ $t('setting.scroll') }}</span>
|
||||
<label class="slider">
|
||||
<input type="range" min="5" max="100" v-model="scroll" />
|
||||
<input type="range" min="1" max="100" v-model="scroll" />
|
||||
</label>
|
||||
</li>
|
||||
<li>
|
||||
@ -35,6 +35,19 @@
|
||||
<span />
|
||||
</label>
|
||||
</li>
|
||||
<li>
|
||||
<span>{{ $t('setting.keyboard_layout') }}</span>
|
||||
<label class="select">
|
||||
<select v-model="keyboard_layout">
|
||||
<option
|
||||
v-for="(name, code) in keyboard_layouts_list"
|
||||
:key="code"
|
||||
:value="code"
|
||||
>{{ name }}</option>
|
||||
</select>
|
||||
<span />
|
||||
</label>
|
||||
</li>
|
||||
<li v-if="connected">
|
||||
<button @click.stop.prevent="logout">{{ $t('logout') }}</button>
|
||||
</li>
|
||||
@ -182,6 +195,31 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.select {
|
||||
max-width: 120px;
|
||||
|
||||
select {
|
||||
display: block;
|
||||
width: 100%;
|
||||
max-width: 100%;
|
||||
padding: 4px;
|
||||
margin: 0;
|
||||
line-height: 30px;
|
||||
font-weight: bold;
|
||||
border: 0;
|
||||
border-radius: 12px;
|
||||
|
||||
color: black;
|
||||
background-color: $style-primary;
|
||||
|
||||
option {
|
||||
font-weight: normal;
|
||||
color: $text-normal;
|
||||
background-color: $background-tertiary;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -236,6 +274,19 @@
|
||||
this.$accessor.settings.setSound(value)
|
||||
}
|
||||
|
||||
get keyboard_layouts_list() {
|
||||
return this.$accessor.settings.keyboard_layouts_list
|
||||
}
|
||||
|
||||
get keyboard_layout() {
|
||||
return this.$accessor.settings.keyboard_layout
|
||||
}
|
||||
|
||||
set keyboard_layout(value: string) {
|
||||
this.$accessor.settings.setKeyboardLayout(value)
|
||||
this.$accessor.remote.changeKeyboard()
|
||||
}
|
||||
|
||||
logout() {
|
||||
this.$accessor.logout()
|
||||
}
|
||||
|
@ -20,8 +20,6 @@
|
||||
@mouseup.stop.prevent="onMouseUp"
|
||||
@mouseenter.stop.prevent="onMouseEnter"
|
||||
@mouseleave.stop.prevent="onMouseLeave"
|
||||
@keydown.stop.prevent="onKeyDown"
|
||||
@keyup.stop.prevent="onKeyUp"
|
||||
/>
|
||||
<div v-if="!playing" class="player-overlay">
|
||||
<i @click.stop.prevent="toggle" v-if="playable" class="fas fa-play-circle" />
|
||||
@ -142,6 +140,8 @@
|
||||
import Emote from './emote.vue'
|
||||
import Resolution from './resolution.vue'
|
||||
|
||||
import GuacamoleKeyboard from '~/utils/guacamole-keyboard.ts'
|
||||
|
||||
@Component({
|
||||
name: 'neko-video',
|
||||
components: {
|
||||
@ -158,10 +158,10 @@
|
||||
@Ref('video') readonly _video!: HTMLVideoElement
|
||||
@Ref('resolution') readonly _resolution!: any
|
||||
|
||||
private keyboard = GuacamoleKeyboard()
|
||||
private observer = new ResizeObserver(this.onResise.bind(this))
|
||||
private focused = false
|
||||
private fullscreen = false
|
||||
private activeKeys: Set<number> = new Set()
|
||||
|
||||
get admin() {
|
||||
return this.$accessor.user.admin
|
||||
@ -335,6 +335,24 @@
|
||||
|
||||
document.addEventListener('focusin', this.onFocus.bind(this))
|
||||
document.addEventListener('focusout', this.onBlur.bind(this))
|
||||
|
||||
/* Initialize Guacamole Keyboard */
|
||||
this.keyboard.onkeydown = (key: number) => {
|
||||
if (!this.focused || !this.hosting || this.locked) {
|
||||
return true
|
||||
}
|
||||
|
||||
this.$client.sendData('keydown', { key })
|
||||
return false
|
||||
}
|
||||
this.keyboard.onkeyup = (key: number) => {
|
||||
if (!this.focused || !this.hosting || this.locked) {
|
||||
return
|
||||
}
|
||||
|
||||
this.$client.sendData('keyup', { key })
|
||||
}
|
||||
this.keyboard.listenTo(this._overlay)
|
||||
}
|
||||
|
||||
beforeDestroy() {
|
||||
@ -342,6 +360,7 @@
|
||||
this.$accessor.video.setPlayable(false)
|
||||
document.removeEventListener('focusin', this.onFocus.bind(this))
|
||||
document.removeEventListener('focusout', this.onBlur.bind(this))
|
||||
/* Guacamole Keyboard does not provide destroy functions */
|
||||
}
|
||||
|
||||
play() {
|
||||
@ -409,10 +428,7 @@
|
||||
return
|
||||
}
|
||||
|
||||
for (let key of this.activeKeys) {
|
||||
this.$client.sendData('keyup', { key })
|
||||
this.activeKeys.delete(key)
|
||||
}
|
||||
this.keyboard.reset()
|
||||
}
|
||||
|
||||
onMousePos(e: MouseEvent) {
|
||||
@ -449,7 +465,7 @@
|
||||
return
|
||||
}
|
||||
this.onMousePos(e)
|
||||
this.$client.sendData('mousedown', { key: e.button })
|
||||
this.$client.sendData('mousedown', { key: e.button + 1 })
|
||||
}
|
||||
|
||||
onMouseUp(e: MouseEvent) {
|
||||
@ -457,7 +473,7 @@
|
||||
return
|
||||
}
|
||||
this.onMousePos(e)
|
||||
this.$client.sendData('mouseup', { key: e.button })
|
||||
this.$client.sendData('mouseup', { key: e.button + 1 })
|
||||
}
|
||||
|
||||
onMouseMove(e: MouseEvent) {
|
||||
@ -477,44 +493,6 @@
|
||||
this.focused = false
|
||||
}
|
||||
|
||||
// frick you firefox
|
||||
getCode(e: KeyboardEvent): number {
|
||||
let key = e.keyCode
|
||||
if (key === 59 && (e.key === ';' || e.key === ':')) {
|
||||
key = 186
|
||||
}
|
||||
|
||||
if (key === 61 && (e.key === '=' || e.key === '+')) {
|
||||
key = 187
|
||||
}
|
||||
|
||||
if (key === 173 && (e.key === '-' || e.key === '_')) {
|
||||
key = 189
|
||||
}
|
||||
|
||||
return key
|
||||
}
|
||||
|
||||
onKeyDown(e: KeyboardEvent) {
|
||||
if (!this.focused || !this.hosting || this.locked) {
|
||||
return
|
||||
}
|
||||
|
||||
let key = this.getCode(e)
|
||||
this.$client.sendData('keydown', { key })
|
||||
this.activeKeys.add(key)
|
||||
}
|
||||
|
||||
onKeyUp(e: KeyboardEvent) {
|
||||
if (!this.focused || !this.hosting || this.locked) {
|
||||
return
|
||||
}
|
||||
|
||||
let key = this.getCode(e)
|
||||
this.$client.sendData('keyup', { key })
|
||||
this.activeKeys.delete(key)
|
||||
}
|
||||
|
||||
onResise() {
|
||||
let height = 0
|
||||
if (!this.fullscreen) {
|
||||
|
@ -60,6 +60,7 @@ export const setting = {
|
||||
autoplay: 'Autoplay Video',
|
||||
ignore_emotes: 'Ignore Emotes',
|
||||
chat_sound: 'Play Chat Sound',
|
||||
keyboard_layout: 'Change Keyboard Layout',
|
||||
}
|
||||
|
||||
export const connection = {
|
||||
|
@ -123,19 +123,19 @@ export abstract class BaseClient extends EventEmitter<BaseEvents> {
|
||||
break
|
||||
case 'keydown':
|
||||
case 'mousedown':
|
||||
buffer = new ArrayBuffer(5)
|
||||
buffer = new ArrayBuffer(11)
|
||||
payload = new DataView(buffer)
|
||||
payload.setUint8(0, OPCODE.KEY_DOWN)
|
||||
payload.setUint16(1, 1, true)
|
||||
payload.setUint16(3, data.key, true)
|
||||
payload.setUint16(1, 8, true)
|
||||
payload.setBigUint64(3, BigInt(data.key), true)
|
||||
break
|
||||
case 'keyup':
|
||||
case 'mouseup':
|
||||
buffer = new ArrayBuffer(5)
|
||||
buffer = new ArrayBuffer(11)
|
||||
payload = new DataView(buffer)
|
||||
payload.setUint8(0, OPCODE.KEY_UP)
|
||||
payload.setUint16(1, 1, true)
|
||||
payload.setUint16(3, data.key, true)
|
||||
payload.setUint16(1, 8, true)
|
||||
payload.setBigUint64(3, BigInt(data.key), true)
|
||||
break
|
||||
default:
|
||||
this.emit('warn', `unknown data event: ${event}`)
|
||||
|
@ -27,6 +27,7 @@ export const EVENT = {
|
||||
REQUESTING: 'control/requesting',
|
||||
CLIPBOARD: 'control/clipboard',
|
||||
GIVE: 'control/give',
|
||||
KEYBOARD: 'control/keyboard'
|
||||
},
|
||||
CHAT: {
|
||||
MESSAGE: 'chat/message',
|
||||
@ -67,6 +68,7 @@ export type ControlEvents =
|
||||
| typeof EVENT.CONTROL.REQUEST
|
||||
| typeof EVENT.CONTROL.GIVE
|
||||
| typeof EVENT.CONTROL.CLIPBOARD
|
||||
| typeof EVENT.CONTROL.KEYBOARD
|
||||
|
||||
export type SystemEvents = typeof EVENT.SYSTEM.DISCONNECT
|
||||
export type MemberEvents = typeof EVENT.MEMBER.LIST | typeof EVENT.MEMBER.CONNECTED | typeof EVENT.MEMBER.DISCONNECTED
|
||||
|
@ -165,6 +165,8 @@ export class NekoClient extends BaseClient implements EventEmitter<NekoEvents> {
|
||||
/////////////////////////////
|
||||
protected [EVENT.CONTROL.LOCKED]({ id }: ControlPayload) {
|
||||
this.$accessor.remote.setHost(id)
|
||||
this.$accessor.remote.changeKeyboard()
|
||||
|
||||
const member = this.member(id)
|
||||
if (!member) {
|
||||
return
|
||||
@ -251,6 +253,8 @@ export class NekoClient extends BaseClient implements EventEmitter<NekoEvents> {
|
||||
}
|
||||
|
||||
this.$accessor.remote.setHost(member)
|
||||
this.$accessor.remote.changeKeyboard()
|
||||
|
||||
this.$accessor.chat.newMessage({
|
||||
id,
|
||||
content: this.$vue.$t('notifications.controls_given', {
|
||||
@ -431,6 +435,7 @@ export class NekoClient extends BaseClient implements EventEmitter<NekoEvents> {
|
||||
|
||||
protected [EVENT.ADMIN.CONTROL]({ id, target }: AdminTargetPayload) {
|
||||
this.$accessor.remote.setHost(id)
|
||||
this.$accessor.remote.changeKeyboard()
|
||||
|
||||
if (!target) {
|
||||
this.$accessor.chat.newMessage({
|
||||
@ -495,6 +500,7 @@ export class NekoClient extends BaseClient implements EventEmitter<NekoEvents> {
|
||||
}
|
||||
|
||||
this.$accessor.remote.setHost(member)
|
||||
this.$accessor.remote.changeKeyboard()
|
||||
|
||||
this.$accessor.chat.newMessage({
|
||||
id,
|
||||
|
@ -30,6 +30,7 @@ export type WebSocketPayloads =
|
||||
| Member
|
||||
| ControlPayload
|
||||
| ControlClipboardPayload
|
||||
| ControlKeyboardPayload
|
||||
| ChatPayload
|
||||
| ChatSendPayload
|
||||
| EmojiSendPayload
|
||||
@ -120,6 +121,10 @@ export interface ControlClipboardPayload {
|
||||
text: string
|
||||
}
|
||||
|
||||
export interface ControlKeyboardPayload {
|
||||
layout: string
|
||||
}
|
||||
|
||||
/*
|
||||
CHAT PAYLOADS
|
||||
*/
|
||||
|
@ -55,6 +55,7 @@ export const actions = actionTree(
|
||||
{
|
||||
initialise(store) {
|
||||
accessor.emoji.initialise()
|
||||
accessor.settings.initialise()
|
||||
},
|
||||
|
||||
lock() {
|
||||
|
@ -133,5 +133,13 @@ export const actions = actionTree(
|
||||
|
||||
$client.sendMessage(EVENT.ADMIN.GIVE, { id: member.id })
|
||||
},
|
||||
|
||||
changeKeyboard({ getters }) {
|
||||
if (!accessor.connected || !getters.hosting) {
|
||||
return
|
||||
}
|
||||
|
||||
$client.sendMessage(EVENT.CONTROL.KEYBOARD, { layout: accessor.settings.keyboard_layout })
|
||||
}
|
||||
},
|
||||
)
|
||||
|
@ -1,8 +1,13 @@
|
||||
import { getterTree, mutationTree } from 'typed-vuex'
|
||||
import { getterTree, mutationTree, actionTree } from 'typed-vuex'
|
||||
import { get, set } from '~/utils/localstorage'
|
||||
import { accessor } from '~/store'
|
||||
|
||||
export const namespaced = true
|
||||
|
||||
interface KeyboardLayouts {
|
||||
[code: string]: string
|
||||
}
|
||||
|
||||
export const state = () => {
|
||||
return {
|
||||
scroll: get<number>('scroll', 10),
|
||||
@ -10,6 +15,9 @@ export const state = () => {
|
||||
autoplay: get<boolean>('autoplay', true),
|
||||
ignore_emotes: get<boolean>('ignore_emotes', false),
|
||||
chat_sound: get<boolean>('chat_sound', true),
|
||||
keyboard_layout: get<string>('keyboard_layout', 'us'),
|
||||
|
||||
keyboard_layouts_list: {} as KeyboardLayouts,
|
||||
}
|
||||
}
|
||||
|
||||
@ -40,4 +48,28 @@ export const mutations = mutationTree(state, {
|
||||
state.chat_sound = value
|
||||
set('chat_sound', value)
|
||||
},
|
||||
|
||||
setKeyboardLayout(state, value: string) {
|
||||
state.keyboard_layout = value
|
||||
set('keyboard_layout', value)
|
||||
},
|
||||
|
||||
setKeyboardLayoutsList(state, value: KeyboardLayouts) {
|
||||
state.keyboard_layouts_list = value
|
||||
},
|
||||
})
|
||||
|
||||
export const actions = actionTree(
|
||||
{ state, getters, mutations },
|
||||
{
|
||||
initialise() {
|
||||
$http
|
||||
.get<KeyboardLayouts>('/keyboard_layouts.json')
|
||||
.then((req) => {
|
||||
accessor.settings.setKeyboardLayoutsList(req.data)
|
||||
console.log(req.data)
|
||||
})
|
||||
.catch(console.error)
|
||||
},
|
||||
},
|
||||
)
|
||||
|
1515
client/src/utils/guacamole-keyboard.js
Normal file
1515
client/src/utils/guacamole-keyboard.js
Normal file
File diff suppressed because it is too large
Load Diff
76
client/src/utils/guacamole-keyboard.ts
Normal file
76
client/src/utils/guacamole-keyboard.ts
Normal file
@ -0,0 +1,76 @@
|
||||
import GuacamoleKeyboard from './guacamole-keyboard.js'
|
||||
|
||||
export interface GuacamoleKeyboardInterface {
|
||||
/**
|
||||
* Fired whenever the user presses a key with the element associated
|
||||
* with this Guacamole.Keyboard in focus.
|
||||
*
|
||||
* @event
|
||||
* @param {Number} keysym The keysym of the key being pressed.
|
||||
* @return {Boolean} true if the key event should be allowed through to the
|
||||
* browser, false otherwise.
|
||||
*/
|
||||
onkeydown?: (keysym: number) => boolean;
|
||||
|
||||
/**
|
||||
* Fired whenever the user releases a key with the element associated
|
||||
* with this Guacamole.Keyboard in focus.
|
||||
*
|
||||
* @event
|
||||
* @param {Number} keysym The keysym of the key being released.
|
||||
*/
|
||||
onkeyup?: (keysym: number) => void;
|
||||
|
||||
/**
|
||||
* Marks a key as pressed, firing the keydown event if registered. Key
|
||||
* repeat for the pressed key will start after a delay if that key is
|
||||
* not a modifier. The return value of this function depends on the
|
||||
* return value of the keydown event handler, if any.
|
||||
*
|
||||
* @param {Number} keysym The keysym of the key to press.
|
||||
* @return {Boolean} true if event should NOT be canceled, false otherwise.
|
||||
*/
|
||||
press: (keysym: number) => boolean;
|
||||
|
||||
/**
|
||||
* Marks a key as released, firing the keyup event if registered.
|
||||
*
|
||||
* @param {Number} keysym The keysym of the key to release.
|
||||
*/
|
||||
release: (keysym: number) => void;
|
||||
|
||||
/**
|
||||
* Presses and releases the keys necessary to type the given string of
|
||||
* text.
|
||||
*
|
||||
* @param {String} str
|
||||
* The string to type.
|
||||
*/
|
||||
type: (str: string) => void;
|
||||
|
||||
/**
|
||||
* Resets the state of this keyboard, releasing all keys, and firing keyup
|
||||
* events for each released key.
|
||||
*/
|
||||
reset: () => void;
|
||||
|
||||
/**
|
||||
* Attaches event listeners to the given Element, automatically translating
|
||||
* received key, input, and composition events into simple keydown/keyup
|
||||
* events signalled through this Guacamole.Keyboard's onkeydown and
|
||||
* onkeyup handlers.
|
||||
*
|
||||
* @param {Element|Document} element
|
||||
* The Element to attach event listeners to for the sake of handling
|
||||
* key or input events.
|
||||
*/
|
||||
listenTo: (element: Element | Document) => void;
|
||||
}
|
||||
|
||||
export default function(element?: Element): GuacamoleKeyboardInterface {
|
||||
var Keyboard = {};
|
||||
|
||||
GuacamoleKeyboard.bind(Keyboard, element)();
|
||||
|
||||
return Keyboard as GuacamoleKeyboardInterface;
|
||||
}
|
@ -102,10 +102,8 @@ func (manager *RemoteManager) StartStream() {
|
||||
|
||||
if !xorg.ValidScreenSize(manager.config.ScreenWidth, manager.config.ScreenHeight, manager.config.ScreenRate) {
|
||||
manager.logger.Warn().Msgf("invalid screen option %dx%d@%d", manager.config.ScreenWidth, manager.config.ScreenHeight, manager.config.ScreenRate)
|
||||
} else {
|
||||
if err := xorg.ChangeScreenSize(manager.config.ScreenWidth, manager.config.ScreenHeight, manager.config.ScreenRate); err != nil {
|
||||
manager.logger.Warn().Err(err).Msg("unable to change screen size")
|
||||
}
|
||||
} else if err := xorg.ChangeScreenSize(manager.config.ScreenWidth, manager.config.ScreenHeight, manager.config.ScreenRate); err != nil {
|
||||
manager.logger.Warn().Err(err).Msg("unable to change screen size")
|
||||
}
|
||||
|
||||
manager.createPipelines()
|
||||
@ -183,19 +181,19 @@ func (manager *RemoteManager) Scroll(x, y int) {
|
||||
xorg.Scroll(x, y)
|
||||
}
|
||||
|
||||
func (manager *RemoteManager) ButtonDown(code int) (*types.Button, error) {
|
||||
func (manager *RemoteManager) ButtonDown(code int) error {
|
||||
return xorg.ButtonDown(code)
|
||||
}
|
||||
|
||||
func (manager *RemoteManager) KeyDown(code int) (*types.Key, error) {
|
||||
func (manager *RemoteManager) KeyDown(code uint64) error {
|
||||
return xorg.KeyDown(code)
|
||||
}
|
||||
|
||||
func (manager *RemoteManager) ButtonUp(code int) (*types.Button, error) {
|
||||
func (manager *RemoteManager) ButtonUp(code int) error {
|
||||
return xorg.ButtonUp(code)
|
||||
}
|
||||
|
||||
func (manager *RemoteManager) KeyUp(code int) (*types.Key, error) {
|
||||
func (manager *RemoteManager) KeyUp(code uint64) error {
|
||||
return xorg.KeyUp(code)
|
||||
}
|
||||
|
||||
@ -218,3 +216,7 @@ func (manager *RemoteManager) ScreenConfigurations() map[int]types.ScreenConfigu
|
||||
func (manager *RemoteManager) GetScreenSize() *types.ScreenSize {
|
||||
return xorg.GetScreenSize()
|
||||
}
|
||||
|
||||
func (manager *RemoteManager) SetKeyboardLayout(layout string) {
|
||||
xorg.SetKeyboardLayout(layout)
|
||||
}
|
@ -22,6 +22,7 @@ const (
|
||||
CONTROL_REQUESTING = "control/requesting"
|
||||
CONTROL_GIVE = "control/give"
|
||||
CONTROL_CLIPBOARD = "control/clipboard"
|
||||
CONTROL_KEYBOARD = "control/keyboard"
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -46,6 +46,11 @@ type Clipboard struct {
|
||||
Text string `json:"text"`
|
||||
}
|
||||
|
||||
type Keyboard struct {
|
||||
Event string `json:"event"`
|
||||
Layout string `json:"layout"`
|
||||
}
|
||||
|
||||
type Control struct {
|
||||
Event string `json:"event"`
|
||||
ID string `json:"id"`
|
||||
|
@ -15,11 +15,12 @@ type RemoteManager interface {
|
||||
ScreenConfigurations() map[int]ScreenConfiguration
|
||||
Move(x, y int)
|
||||
Scroll(x, y int)
|
||||
ButtonDown(code int) (*Button, error)
|
||||
KeyDown(code int) (*Key, error)
|
||||
ButtonUp(code int) (*Button, error)
|
||||
KeyUp(code int) (*Key, error)
|
||||
ButtonDown(code int) error
|
||||
KeyDown(code uint64) error
|
||||
ButtonUp(code int) error
|
||||
KeyUp(code uint64) error
|
||||
ReadClipboard() string
|
||||
WriteClipboard(data string)
|
||||
ResetKeys()
|
||||
SetKeyboardLayout(layout string)
|
||||
}
|
||||
|
@ -33,7 +33,7 @@ type PayloadScroll struct {
|
||||
|
||||
type PayloadKey struct {
|
||||
PayloadHeader
|
||||
Key uint16
|
||||
Key uint64
|
||||
}
|
||||
|
||||
func (manager *WebRTCManager) handle(id string, msg webrtc.DataChannelMessage) error {
|
||||
@ -85,21 +85,21 @@ func (manager *WebRTCManager) handle(id string, msg webrtc.DataChannelMessage) e
|
||||
}
|
||||
|
||||
if payload.Key < 8 {
|
||||
button, err := manager.remote.ButtonDown(int(payload.Key))
|
||||
err := manager.remote.ButtonDown(int(payload.Key))
|
||||
if err != nil {
|
||||
manager.logger.Warn().Err(err).Msg("key down failed")
|
||||
manager.logger.Warn().Err(err).Msg("button down failed")
|
||||
return nil
|
||||
}
|
||||
|
||||
manager.logger.Debug().Msgf("button down %s(%d)", button.Name, payload.Key)
|
||||
manager.logger.Debug().Msgf("button down %d", payload.Key)
|
||||
} else {
|
||||
key, err := manager.remote.KeyDown(int(payload.Key))
|
||||
err := manager.remote.KeyDown(uint64(payload.Key))
|
||||
if err != nil {
|
||||
manager.logger.Warn().Err(err).Msg("key down failed")
|
||||
return nil
|
||||
}
|
||||
|
||||
manager.logger.Debug().Msgf("key down %s(%d)", key.Name, payload.Key)
|
||||
manager.logger.Debug().Msgf("key down %d", payload.Key)
|
||||
}
|
||||
|
||||
break
|
||||
@ -111,21 +111,21 @@ func (manager *WebRTCManager) handle(id string, msg webrtc.DataChannelMessage) e
|
||||
}
|
||||
|
||||
if payload.Key < 8 {
|
||||
button, err := manager.remote.ButtonUp(int(payload.Key))
|
||||
err := manager.remote.ButtonUp(int(payload.Key))
|
||||
if err != nil {
|
||||
manager.logger.Warn().Err(err).Msg("button up failed")
|
||||
return nil
|
||||
}
|
||||
|
||||
manager.logger.Debug().Msgf("button up %s(%d)", button.Name, payload.Key)
|
||||
manager.logger.Debug().Msgf("button up %d", payload.Key)
|
||||
} else {
|
||||
key, err := manager.remote.KeyUp(int(payload.Key))
|
||||
err := manager.remote.KeyUp(uint64(payload.Key))
|
||||
if err != nil {
|
||||
manager.logger.Warn().Err(err).Msg("keyup failed")
|
||||
manager.logger.Warn().Err(err).Msg("key up failed")
|
||||
return nil
|
||||
}
|
||||
|
||||
manager.logger.Debug().Msgf("key up %s(%d)", key.Name, payload.Key)
|
||||
manager.logger.Debug().Msgf("key up %d", payload.Key)
|
||||
}
|
||||
break
|
||||
case OP_KEY_CLK:
|
||||
|
@ -115,3 +115,14 @@ func (h *MessageHandler) controlClipboard(id string, session types.Session, payl
|
||||
h.remote.WriteClipboard(payload.Text)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *MessageHandler) controlKeyboard(id string, session types.Session, payload *message.Keyboard) error {
|
||||
// check if session is host
|
||||
if !h.sessions.IsHost(id) {
|
||||
h.logger.Debug().Str("id", id).Msg("is not the host")
|
||||
return nil
|
||||
}
|
||||
|
||||
h.remote.SetKeyboardLayout(payload.Layout)
|
||||
return nil
|
||||
}
|
||||
|
@ -89,6 +89,13 @@ func (h *MessageHandler) Message(id string, raw []byte) error {
|
||||
utils.Unmarshal(payload, raw, func() error {
|
||||
return h.controlClipboard(id, session, payload)
|
||||
}), "%s failed", header.Event)
|
||||
case event.CONTROL_KEYBOARD:
|
||||
payload := &message.Keyboard{}
|
||||
return errors.Wrapf(
|
||||
utils.Unmarshal(payload, raw, func() error {
|
||||
return h.controlKeyboard(id, session, payload)
|
||||
}), "%s failed", header.Event)
|
||||
|
||||
|
||||
// Chat Events
|
||||
case event.CHAT_MESSAGE:
|
||||
|
@ -12,11 +12,6 @@ func (h *MessageHandler) SessionCreated(id string, session types.Session) error
|
||||
return err
|
||||
}
|
||||
|
||||
// send screen current resolution
|
||||
if err := h.screenResolution(id, session); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if session.Admin() {
|
||||
// send screen configurations if admin
|
||||
if err := h.screenConfigurations(id, session); err != nil {
|
||||
@ -37,6 +32,11 @@ func (h *MessageHandler) SessionConnected(id string, session types.Session) erro
|
||||
return err
|
||||
}
|
||||
|
||||
// send screen current resolution
|
||||
if err := h.screenResolution(id, session); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// tell session there is a host
|
||||
host, ok := h.sessions.GetHost()
|
||||
if ok {
|
||||
|
@ -1,45 +0,0 @@
|
||||
package keycode
|
||||
|
||||
import "n.eko.moe/neko/internal/types"
|
||||
|
||||
var LEFT_BUTTON = types.Button{
|
||||
Name: "LEFT",
|
||||
Code: 0,
|
||||
Keysym: 1,
|
||||
}
|
||||
|
||||
var CENTER_BUTTON = types.Button{
|
||||
Name: "CENTER",
|
||||
Code: 1,
|
||||
Keysym: 2,
|
||||
}
|
||||
|
||||
var RIGHT_BUTTON = types.Button{
|
||||
Name: "RIGHT",
|
||||
Code: 2,
|
||||
Keysym: 3,
|
||||
}
|
||||
|
||||
var SCROLL_UP_BUTTON = types.Button{
|
||||
Name: "SCROLL_UP",
|
||||
Code: 3,
|
||||
Keysym: 4,
|
||||
}
|
||||
|
||||
var SCROLL_DOWN_BUTTON = types.Button{
|
||||
Name: "SCROLL_DOWN",
|
||||
Code: 4,
|
||||
Keysym: 5,
|
||||
}
|
||||
|
||||
var SCROLL_LEFT_BUTTON = types.Button{
|
||||
Name: "SCROLL_LEFT",
|
||||
Code: 5,
|
||||
Keysym: 6,
|
||||
}
|
||||
|
||||
var SCROLL_RIGHT_BUTTON = types.Button{
|
||||
Name: "SCROLL_RIGHT",
|
||||
Code: 6,
|
||||
Keysym: 7,
|
||||
}
|
@ -1,696 +0,0 @@
|
||||
package keycode
|
||||
|
||||
import "n.eko.moe/neko/internal/types"
|
||||
|
||||
var BACKSPACE = types.Key{
|
||||
Name: "BACKSPACE",
|
||||
Value: "BackSpace",
|
||||
Code: 8,
|
||||
Keysym: int(0xff08),
|
||||
}
|
||||
|
||||
var TAB = types.Key{
|
||||
Name: "TAB",
|
||||
Value: "Tab",
|
||||
Code: 9,
|
||||
Keysym: int(0xFF09),
|
||||
}
|
||||
|
||||
var CLEAR = types.Key{
|
||||
Name: "CLEAR",
|
||||
Value: "Clear",
|
||||
Code: 12,
|
||||
Keysym: int(0xFF0B),
|
||||
}
|
||||
|
||||
var ENTER = types.Key{
|
||||
Name: "ENTER",
|
||||
Value: "Enter",
|
||||
Code: 13,
|
||||
Keysym: int(0xFF0D),
|
||||
}
|
||||
|
||||
var SHIFT = types.Key{
|
||||
Name: "SHIFT",
|
||||
Value: "Shift",
|
||||
Code: 16,
|
||||
Keysym: int(0xFFE1),
|
||||
}
|
||||
|
||||
var CTRL = types.Key{
|
||||
Name: "CTRL",
|
||||
Value: "Ctrl",
|
||||
Code: 17,
|
||||
Keysym: int(0xFFE3),
|
||||
}
|
||||
|
||||
var ALT = types.Key{
|
||||
Name: "ALT",
|
||||
Value: "Alt",
|
||||
Code: 18,
|
||||
Keysym: int(0xFFE9),
|
||||
}
|
||||
|
||||
var PAUSE = types.Key{
|
||||
Name: "PAUSE",
|
||||
Value: "Pause",
|
||||
Code: 19,
|
||||
Keysym: int(0xFF13),
|
||||
}
|
||||
|
||||
var CAPS_LOCK = types.Key{
|
||||
Name: "CAPS_LOCK",
|
||||
Value: "Caps Lock",
|
||||
Code: 20,
|
||||
Keysym: int(0xFFE5),
|
||||
}
|
||||
|
||||
var ESCAPE = types.Key{
|
||||
Name: "ESCAPE",
|
||||
Value: "Escape",
|
||||
Code: 27,
|
||||
Keysym: int(0xFF1B),
|
||||
}
|
||||
|
||||
var SPACE = types.Key{
|
||||
Name: "SPACE",
|
||||
Value: " ",
|
||||
Code: 32,
|
||||
Keysym: int(0x0020),
|
||||
}
|
||||
|
||||
var PAGE_UP = types.Key{
|
||||
Name: "PAGE_UP",
|
||||
Value: "Page Up",
|
||||
Code: 33,
|
||||
Keysym: int(0xFF55),
|
||||
}
|
||||
|
||||
var PAGE_DOWN = types.Key{
|
||||
Name: "PAGE_DOWN",
|
||||
Value: "Page Down",
|
||||
Code: 34,
|
||||
Keysym: int(0xFF56),
|
||||
}
|
||||
|
||||
var END = types.Key{
|
||||
Name: "END",
|
||||
Value: "End",
|
||||
Code: 35,
|
||||
Keysym: int(0xFF57),
|
||||
}
|
||||
|
||||
var HOME = types.Key{
|
||||
Name: "HOME",
|
||||
Value: "Home",
|
||||
Code: 36,
|
||||
Keysym: int(0xFF50),
|
||||
}
|
||||
|
||||
var LEFT_ARROW = types.Key{
|
||||
Name: "LEFT_ARROW",
|
||||
Value: "Left Arrow",
|
||||
Code: 37,
|
||||
Keysym: int(0xFF51),
|
||||
}
|
||||
|
||||
var UP_ARROW = types.Key{
|
||||
Name: "UP_ARROW",
|
||||
Value: "Up Arrow",
|
||||
Code: 38,
|
||||
Keysym: int(0xFF52),
|
||||
}
|
||||
|
||||
var RIGHT_ARROW = types.Key{
|
||||
Name: "RIGHT_ARROW",
|
||||
Value: "Right Arrow",
|
||||
Code: 39,
|
||||
Keysym: int(0xFF53),
|
||||
}
|
||||
|
||||
var DOWN_ARROW = types.Key{
|
||||
Name: "DOWN_ARROW",
|
||||
Value: "Down Arrow",
|
||||
Code: 40,
|
||||
Keysym: int(0xFF54),
|
||||
}
|
||||
|
||||
var INSERT = types.Key{
|
||||
Name: "INSERT",
|
||||
Value: "Insert",
|
||||
Code: 45,
|
||||
Keysym: int(0xFF63),
|
||||
}
|
||||
|
||||
var DELETE = types.Key{
|
||||
Name: "DELETE",
|
||||
Value: "Delete",
|
||||
Code: 46,
|
||||
Keysym: int(0xFFFF),
|
||||
}
|
||||
|
||||
var KEY_0 = types.Key{
|
||||
Name: "KEY_0",
|
||||
Value: "0",
|
||||
Code: 48,
|
||||
Keysym: int(0x0030),
|
||||
}
|
||||
|
||||
var KEY_1 = types.Key{
|
||||
Name: "KEY_1",
|
||||
Value: "1",
|
||||
Code: 49,
|
||||
Keysym: int(0x0031),
|
||||
}
|
||||
|
||||
var KEY_2 = types.Key{
|
||||
Name: "KEY_2",
|
||||
Value: "2",
|
||||
Code: 50,
|
||||
Keysym: int(0x0032),
|
||||
}
|
||||
|
||||
var KEY_3 = types.Key{
|
||||
Name: "KEY_3",
|
||||
Value: "3",
|
||||
Code: 51,
|
||||
Keysym: int(0x0033),
|
||||
}
|
||||
|
||||
var KEY_4 = types.Key{
|
||||
Name: "KEY_4",
|
||||
Value: "4",
|
||||
Code: 52,
|
||||
Keysym: int(0x0034),
|
||||
}
|
||||
|
||||
var KEY_5 = types.Key{
|
||||
Name: "KEY_5",
|
||||
Value: "5",
|
||||
Code: 53,
|
||||
Keysym: int(0x0035),
|
||||
}
|
||||
|
||||
var KEY_6 = types.Key{
|
||||
Name: "KEY_6",
|
||||
Value: "6",
|
||||
Code: 54,
|
||||
Keysym: int(0x0036),
|
||||
}
|
||||
|
||||
var KEY_7 = types.Key{
|
||||
Name: "KEY_7",
|
||||
Value: "7",
|
||||
Code: 55,
|
||||
Keysym: int(0x0037),
|
||||
}
|
||||
|
||||
var KEY_8 = types.Key{
|
||||
Name: "KEY_8",
|
||||
Value: "8",
|
||||
Code: 56,
|
||||
Keysym: int(0x0038),
|
||||
}
|
||||
|
||||
var KEY_9 = types.Key{
|
||||
Name: "KEY_9",
|
||||
Value: "9",
|
||||
Code: 57,
|
||||
Keysym: int(0x0039),
|
||||
}
|
||||
|
||||
var KEY_A = types.Key{
|
||||
Name: "KEY_A",
|
||||
Value: "a",
|
||||
Code: 65,
|
||||
Keysym: int(0x0061),
|
||||
}
|
||||
|
||||
var KEY_B = types.Key{
|
||||
Name: "KEY_B",
|
||||
Value: "b",
|
||||
Code: 66,
|
||||
Keysym: int(0x0062),
|
||||
}
|
||||
|
||||
var KEY_C = types.Key{
|
||||
Name: "KEY_C",
|
||||
Value: "c",
|
||||
Code: 67,
|
||||
Keysym: int(0x0063),
|
||||
}
|
||||
|
||||
var KEY_D = types.Key{
|
||||
Name: "KEY_D",
|
||||
Value: "d",
|
||||
Code: 68,
|
||||
Keysym: int(0x0064),
|
||||
}
|
||||
|
||||
var KEY_E = types.Key{
|
||||
Name: "KEY_E",
|
||||
Value: "e",
|
||||
Code: 69,
|
||||
Keysym: int(0x0065),
|
||||
}
|
||||
|
||||
var KEY_F = types.Key{
|
||||
Name: "KEY_F",
|
||||
Value: "f",
|
||||
Code: 70,
|
||||
Keysym: int(0x0066),
|
||||
}
|
||||
|
||||
var KEY_G = types.Key{
|
||||
Name: "KEY_G",
|
||||
Value: "g",
|
||||
Code: 71,
|
||||
Keysym: int(0x0067),
|
||||
}
|
||||
|
||||
var KEY_H = types.Key{
|
||||
Name: "KEY_H",
|
||||
Value: "h",
|
||||
Code: 72,
|
||||
Keysym: int(0x0068),
|
||||
}
|
||||
|
||||
var KEY_I = types.Key{
|
||||
Name: "KEY_I",
|
||||
Value: "i",
|
||||
Code: 73,
|
||||
Keysym: int(0x0069),
|
||||
}
|
||||
|
||||
var KEY_J = types.Key{
|
||||
Name: "KEY_J",
|
||||
Value: "j",
|
||||
Code: 74,
|
||||
Keysym: int(0x006a),
|
||||
}
|
||||
|
||||
var KEY_K = types.Key{
|
||||
Name: "KEY_K",
|
||||
Value: "k",
|
||||
Code: 75,
|
||||
Keysym: int(0x006b),
|
||||
}
|
||||
|
||||
var KEY_L = types.Key{
|
||||
Name: "KEY_L",
|
||||
Value: "l",
|
||||
Code: 76,
|
||||
Keysym: int(0x006c),
|
||||
}
|
||||
|
||||
var KEY_M = types.Key{
|
||||
Name: "KEY_M",
|
||||
Value: "m",
|
||||
Code: 77,
|
||||
Keysym: int(0x006d),
|
||||
}
|
||||
|
||||
var KEY_N = types.Key{
|
||||
Name: "KEY_N",
|
||||
Value: "n",
|
||||
Code: 78,
|
||||
Keysym: int(0x006e),
|
||||
}
|
||||
|
||||
var KEY_O = types.Key{
|
||||
Name: "KEY_O",
|
||||
Value: "o",
|
||||
Code: 79,
|
||||
Keysym: int(0x006f),
|
||||
}
|
||||
|
||||
var KEY_P = types.Key{
|
||||
Name: "KEY_P",
|
||||
Value: "p",
|
||||
Code: 80,
|
||||
Keysym: int(0x0070),
|
||||
}
|
||||
|
||||
var KEY_Q = types.Key{
|
||||
Name: "KEY_Q",
|
||||
Value: "q",
|
||||
Code: 81,
|
||||
Keysym: int(0x0071),
|
||||
}
|
||||
|
||||
var KEY_R = types.Key{
|
||||
Name: "KEY_R",
|
||||
Value: "r",
|
||||
Code: 82,
|
||||
Keysym: int(0x0072),
|
||||
}
|
||||
|
||||
var KEY_S = types.Key{
|
||||
Name: "KEY_S",
|
||||
Value: "s",
|
||||
Code: 83,
|
||||
Keysym: int(0x0073),
|
||||
}
|
||||
|
||||
var KEY_T = types.Key{
|
||||
Name: "KEY_T",
|
||||
Value: "t",
|
||||
Code: 84,
|
||||
Keysym: int(0x0074),
|
||||
}
|
||||
|
||||
var KEY_U = types.Key{
|
||||
Name: "KEY_U",
|
||||
Value: "u",
|
||||
Code: 85,
|
||||
Keysym: int(0x0075),
|
||||
}
|
||||
|
||||
var KEY_V = types.Key{
|
||||
Name: "KEY_V",
|
||||
Value: "v",
|
||||
Code: 86,
|
||||
Keysym: int(0x0076),
|
||||
}
|
||||
|
||||
var KEY_W = types.Key{
|
||||
Name: "KEY_W",
|
||||
Value: "w",
|
||||
Code: 87,
|
||||
Keysym: int(0x0077),
|
||||
}
|
||||
|
||||
var KEY_X = types.Key{
|
||||
Name: "KEY_X",
|
||||
Value: "x",
|
||||
Code: 88,
|
||||
Keysym: int(0x0078),
|
||||
}
|
||||
|
||||
var KEY_Y = types.Key{
|
||||
Name: "KEY_Y",
|
||||
Value: "y",
|
||||
Code: 89,
|
||||
Keysym: int(0x0079),
|
||||
}
|
||||
|
||||
var KEY_Z = types.Key{
|
||||
Name: "KEY_Z",
|
||||
Value: "z",
|
||||
Code: 90,
|
||||
Keysym: int(0x007a),
|
||||
}
|
||||
|
||||
var WIN_LEFT = types.Key{
|
||||
Name: "WIN_LEFT",
|
||||
Value: "Win Left",
|
||||
Code: 91,
|
||||
Keysym: int(0xFFEB),
|
||||
}
|
||||
|
||||
var WIN_RIGHT = types.Key{
|
||||
Name: "WIN_RIGHT",
|
||||
Value: "Win Right",
|
||||
Code: 92,
|
||||
Keysym: int(0xFF67),
|
||||
}
|
||||
|
||||
var PAD_0 = types.Key{
|
||||
Name: "PAD_0",
|
||||
Value: "Num Pad 0",
|
||||
Code: 96,
|
||||
Keysym: int(0xFFB0),
|
||||
}
|
||||
|
||||
var PAD_1 = types.Key{
|
||||
Name: "PAD_1",
|
||||
Value: "Num Pad 1",
|
||||
Code: 97,
|
||||
Keysym: int(0xFFB1),
|
||||
}
|
||||
|
||||
var PAD_2 = types.Key{
|
||||
Name: "PAD_2",
|
||||
Value: "Num Pad 2",
|
||||
Code: 98,
|
||||
Keysym: int(0xFFB2),
|
||||
}
|
||||
|
||||
var PAD_3 = types.Key{
|
||||
Name: "PAD_3",
|
||||
Value: "Num Pad 3",
|
||||
Code: 99,
|
||||
Keysym: int(0xFFB3),
|
||||
}
|
||||
|
||||
var PAD_4 = types.Key{
|
||||
Name: "PAD_4",
|
||||
Value: "Num Pad 4",
|
||||
Code: 100,
|
||||
Keysym: int(0xFFB4),
|
||||
}
|
||||
|
||||
var PAD_5 = types.Key{
|
||||
Name: "PAD_5",
|
||||
Value: "Num Pad 5",
|
||||
Code: 101,
|
||||
Keysym: int(0xFFB5),
|
||||
}
|
||||
|
||||
var PAD_6 = types.Key{
|
||||
Name: "PAD_6",
|
||||
Value: "Num Pad 6",
|
||||
Code: 102,
|
||||
Keysym: int(0xFFB6),
|
||||
}
|
||||
|
||||
var PAD_7 = types.Key{
|
||||
Name: "PAD_7",
|
||||
Value: "Num Pad 7",
|
||||
Code: 103,
|
||||
Keysym: int(0xFFB7),
|
||||
}
|
||||
|
||||
var PAD_8 = types.Key{
|
||||
Name: "PAD_8",
|
||||
Value: "Num Pad 8",
|
||||
Code: 104,
|
||||
Keysym: int(0xFFB8),
|
||||
}
|
||||
|
||||
var PAD_9 = types.Key{
|
||||
Name: "PAD_9",
|
||||
Value: "Num Pad 9",
|
||||
Code: 105,
|
||||
Keysym: int(0xFFB9),
|
||||
}
|
||||
|
||||
var MULTIPLY = types.Key{
|
||||
Name: "MULTIPLY",
|
||||
Value: "*",
|
||||
Code: 106,
|
||||
Keysym: int(0xFFAA),
|
||||
}
|
||||
|
||||
var ADD = types.Key{
|
||||
Name: "ADD",
|
||||
Value: "+",
|
||||
Code: 107,
|
||||
Keysym: int(0xFFAB),
|
||||
}
|
||||
|
||||
var SUBTRACT = types.Key{
|
||||
Name: "SUBTRACT",
|
||||
Value: "-",
|
||||
Code: 109,
|
||||
Keysym: int(0xFFAD),
|
||||
}
|
||||
|
||||
var DECIMAL = types.Key{
|
||||
Name: "DECIMAL",
|
||||
Value: ".",
|
||||
Code: 110,
|
||||
Keysym: int(0xFFAE),
|
||||
}
|
||||
|
||||
var DIVIDE = types.Key{
|
||||
Name: "DIVIDE",
|
||||
Value: "/",
|
||||
Code: 111,
|
||||
Keysym: int(0xFFAF),
|
||||
}
|
||||
|
||||
var KEY_F1 = types.Key{
|
||||
Name: "KEY_F1",
|
||||
Value: "f1",
|
||||
Code: 112,
|
||||
Keysym: int(0xFFBE),
|
||||
}
|
||||
|
||||
var KEY_F2 = types.Key{
|
||||
Name: "KEY_F2",
|
||||
Value: "f2",
|
||||
Code: 113,
|
||||
Keysym: int(0xFFBF),
|
||||
}
|
||||
|
||||
var KEY_F3 = types.Key{
|
||||
Name: "KEY_F3",
|
||||
Value: "f3",
|
||||
Code: 114,
|
||||
Keysym: int(0xFFC0),
|
||||
}
|
||||
|
||||
var KEY_F4 = types.Key{
|
||||
Name: "KEY_F4",
|
||||
Value: "f4",
|
||||
Code: 115,
|
||||
Keysym: int(0xFFC1),
|
||||
}
|
||||
|
||||
var KEY_F5 = types.Key{
|
||||
Name: "KEY_F5",
|
||||
Value: "f5",
|
||||
Code: 116,
|
||||
Keysym: int(0xFFC2),
|
||||
}
|
||||
|
||||
var KEY_F6 = types.Key{
|
||||
Name: "KEY_F6",
|
||||
Value: "f6",
|
||||
Code: 117,
|
||||
Keysym: int(0xFFC3),
|
||||
}
|
||||
|
||||
var KEY_F7 = types.Key{
|
||||
Name: "KEY_F7",
|
||||
Value: "f7",
|
||||
Code: 118,
|
||||
Keysym: int(0xFFC4),
|
||||
}
|
||||
|
||||
var KEY_F8 = types.Key{
|
||||
Name: "KEY_F8",
|
||||
Value: "f8",
|
||||
Code: 119,
|
||||
Keysym: int(0xFFC5),
|
||||
}
|
||||
|
||||
var KEY_F9 = types.Key{
|
||||
Name: "KEY_F9",
|
||||
Value: "f9",
|
||||
Code: 120,
|
||||
Keysym: int(0xFFC6),
|
||||
}
|
||||
|
||||
var KEY_F10 = types.Key{
|
||||
Name: "KEY_F10",
|
||||
Value: "f10",
|
||||
Code: 121,
|
||||
Keysym: int(0xFFC7),
|
||||
}
|
||||
|
||||
var KEY_F11 = types.Key{
|
||||
Name: "KEY_F11",
|
||||
Value: "f11",
|
||||
Code: 122,
|
||||
Keysym: int(0xFFC8),
|
||||
}
|
||||
|
||||
var KEY_F12 = types.Key{
|
||||
Name: "KEY_F12",
|
||||
Value: "f12",
|
||||
Code: 123,
|
||||
Keysym: int(0xFFC9),
|
||||
}
|
||||
|
||||
var NUM_LOCK = types.Key{
|
||||
Name: "NUM_LOCK",
|
||||
Value: "Num Lock",
|
||||
Code: 144,
|
||||
Keysym: int(0xFF7F),
|
||||
}
|
||||
|
||||
var SCROLL_LOCK = types.Key{
|
||||
Name: "SCROLL_LOCK",
|
||||
Value: "Scroll Lock",
|
||||
Code: 145,
|
||||
Keysym: int(0xFF14),
|
||||
}
|
||||
|
||||
var SEMI_COLON = types.Key{
|
||||
Name: "SEMI_COLON",
|
||||
Value: ";",
|
||||
Code: 186,
|
||||
Keysym: int(0x003b),
|
||||
}
|
||||
|
||||
var EQUAL = types.Key{
|
||||
Name: "EQUAL",
|
||||
Value: "=",
|
||||
Code: 187,
|
||||
Keysym: int(0x003d),
|
||||
}
|
||||
|
||||
var COMMA = types.Key{
|
||||
Name: "COMMA",
|
||||
Value: ",",
|
||||
Code: 188,
|
||||
Keysym: int(0x002c),
|
||||
}
|
||||
|
||||
var DASH = types.Key{
|
||||
Name: "DASH",
|
||||
Value: "-",
|
||||
Code: 189,
|
||||
Keysym: int(0x002d),
|
||||
}
|
||||
|
||||
var PERIOD = types.Key{
|
||||
Name: "PERIOD",
|
||||
Value: ".",
|
||||
Code: 190,
|
||||
Keysym: int(0x002e),
|
||||
}
|
||||
|
||||
var FORWARD_SLASH = types.Key{
|
||||
Name: "FORWARD_SLASH",
|
||||
Value: "/",
|
||||
Code: 191,
|
||||
Keysym: int(0x002f),
|
||||
}
|
||||
|
||||
var GRAVE = types.Key{
|
||||
Name: "GRAVE",
|
||||
Value: "`",
|
||||
Code: 192,
|
||||
Keysym: int(0x0060),
|
||||
}
|
||||
|
||||
var OPEN_BRACKET = types.Key{
|
||||
Name: "OPEN_BRACKET",
|
||||
Value: "[",
|
||||
Code: 219,
|
||||
Keysym: int(0x005b),
|
||||
}
|
||||
|
||||
var BACK_SLASH = types.Key{
|
||||
Name: "BACK_SLASH",
|
||||
Value: "\\",
|
||||
Code: 220,
|
||||
Keysym: int(0x005c),
|
||||
}
|
||||
|
||||
var CLOSE_BRAKET = types.Key{
|
||||
Name: "CLOSE_BRAKET",
|
||||
Value: "]",
|
||||
Code: 221,
|
||||
Keysym: int(0x005d),
|
||||
}
|
||||
|
||||
var SINGLE_QUOTE = types.Key{
|
||||
Name: "SINGLE_QUOTE",
|
||||
Value: "'",
|
||||
Code: 222,
|
||||
Keysym: int(0x0022),
|
||||
}
|
@ -89,16 +89,33 @@ void XScroll(int x, int y) {
|
||||
}
|
||||
|
||||
void XButton(unsigned int button, int down) {
|
||||
Display *display = getXDisplay();
|
||||
XTestFakeButtonEvent(display, button, down, CurrentTime);
|
||||
XSync(display, 0);
|
||||
if (button != 0) {
|
||||
Display *display = getXDisplay();
|
||||
XTestFakeButtonEvent(display, button, down, CurrentTime);
|
||||
XSync(display, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void XKey(unsigned long key, int down) {
|
||||
Display *display = getXDisplay();
|
||||
KeyCode code = XKeysymToKeycode(display, key);
|
||||
XTestFakeKeyEvent(display, code, down, CurrentTime);
|
||||
XSync(display, 0);
|
||||
if (key != 0) {
|
||||
Display *display = getXDisplay();
|
||||
KeyCode code = XKeysymToKeycode(display, key);
|
||||
|
||||
// Map non-existing keysyms to new keycodes
|
||||
if(code == 0) {
|
||||
int min, max, numcodes;
|
||||
XDisplayKeycodes(display, &min, &max);
|
||||
XGetKeyboardMapping(display, min, max-min, &numcodes);
|
||||
|
||||
code = (max-min+1)*numcodes;
|
||||
KeySym keysym_list[numcodes];
|
||||
for(int i=0;i<numcodes;i++) keysym_list[i] = key;
|
||||
XChangeKeyboardMapping(display, code, numcodes, keysym_list, 1);
|
||||
}
|
||||
|
||||
XTestFakeKeyEvent(display, code, down, CurrentTime);
|
||||
XSync(display, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void XClipboardSet(char *src) {
|
||||
@ -148,3 +165,10 @@ short XGetScreenRate() {
|
||||
XRRScreenConfiguration *conf = XRRGetScreenInfo(display, RootWindow(display, 0));
|
||||
return XRRConfigCurrentRate(conf);
|
||||
}
|
||||
|
||||
void SetKeyboardLayout(char *layout) {
|
||||
// TOOD: refactor, use native API.
|
||||
char cmd[13] = "setxkbmap ";
|
||||
strncat(cmd, layout, 2);
|
||||
system(cmd);
|
||||
}
|
||||
|
@ -1,9 +1,3 @@
|
||||
// NOTE: I have no fucking clue what I'm doing with this,
|
||||
// it works, but I am positive I'm doing this very wrong...
|
||||
// should I be freeing these strings? does go gc them?
|
||||
// pretty sure this *isn't* thread safe either.... /shrug
|
||||
// if you know a better way to get this done *please* make a pr <3
|
||||
|
||||
package xorg
|
||||
|
||||
/*
|
||||
@ -19,127 +13,18 @@ import (
|
||||
"sync"
|
||||
"time"
|
||||
"unsafe"
|
||||
"regexp"
|
||||
|
||||
"n.eko.moe/neko/internal/types"
|
||||
"n.eko.moe/neko/internal/xorg/keycode"
|
||||
)
|
||||
|
||||
var ScreenConfigurations = make(map[int]types.ScreenConfiguration)
|
||||
|
||||
var debounce = make(map[int]time.Time)
|
||||
var buttons = make(map[int]types.Button)
|
||||
var keys = make(map[int]types.Key)
|
||||
var debounce_button = make(map[int]time.Time)
|
||||
var debounce_key = make(map[uint64]time.Time)
|
||||
var mu = sync.Mutex{}
|
||||
|
||||
func init() {
|
||||
keys[keycode.BACKSPACE.Code] = keycode.BACKSPACE
|
||||
keys[keycode.TAB.Code] = keycode.TAB
|
||||
keys[keycode.CLEAR.Code] = keycode.CLEAR
|
||||
keys[keycode.ENTER.Code] = keycode.ENTER
|
||||
keys[keycode.SHIFT.Code] = keycode.SHIFT
|
||||
keys[keycode.CTRL.Code] = keycode.CTRL
|
||||
keys[keycode.ALT.Code] = keycode.ALT
|
||||
keys[keycode.PAUSE.Code] = keycode.PAUSE
|
||||
keys[keycode.CAPS_LOCK.Code] = keycode.CAPS_LOCK
|
||||
keys[keycode.ESCAPE.Code] = keycode.ESCAPE
|
||||
keys[keycode.SPACE.Code] = keycode.SPACE
|
||||
keys[keycode.PAGE_UP.Code] = keycode.PAGE_UP
|
||||
keys[keycode.PAGE_DOWN.Code] = keycode.PAGE_DOWN
|
||||
keys[keycode.END.Code] = keycode.END
|
||||
keys[keycode.HOME.Code] = keycode.HOME
|
||||
keys[keycode.LEFT_ARROW.Code] = keycode.LEFT_ARROW
|
||||
keys[keycode.UP_ARROW.Code] = keycode.UP_ARROW
|
||||
keys[keycode.RIGHT_ARROW.Code] = keycode.RIGHT_ARROW
|
||||
keys[keycode.DOWN_ARROW.Code] = keycode.DOWN_ARROW
|
||||
keys[keycode.INSERT.Code] = keycode.INSERT
|
||||
keys[keycode.DELETE.Code] = keycode.DELETE
|
||||
keys[keycode.KEY_0.Code] = keycode.KEY_0
|
||||
keys[keycode.KEY_1.Code] = keycode.KEY_1
|
||||
keys[keycode.KEY_2.Code] = keycode.KEY_2
|
||||
keys[keycode.KEY_3.Code] = keycode.KEY_3
|
||||
keys[keycode.KEY_4.Code] = keycode.KEY_4
|
||||
keys[keycode.KEY_5.Code] = keycode.KEY_5
|
||||
keys[keycode.KEY_6.Code] = keycode.KEY_6
|
||||
keys[keycode.KEY_7.Code] = keycode.KEY_7
|
||||
keys[keycode.KEY_8.Code] = keycode.KEY_8
|
||||
keys[keycode.KEY_9.Code] = keycode.KEY_9
|
||||
keys[keycode.KEY_A.Code] = keycode.KEY_A
|
||||
keys[keycode.KEY_B.Code] = keycode.KEY_B
|
||||
keys[keycode.KEY_C.Code] = keycode.KEY_C
|
||||
keys[keycode.KEY_D.Code] = keycode.KEY_D
|
||||
keys[keycode.KEY_E.Code] = keycode.KEY_E
|
||||
keys[keycode.KEY_F.Code] = keycode.KEY_F
|
||||
keys[keycode.KEY_G.Code] = keycode.KEY_G
|
||||
keys[keycode.KEY_H.Code] = keycode.KEY_H
|
||||
keys[keycode.KEY_I.Code] = keycode.KEY_I
|
||||
keys[keycode.KEY_J.Code] = keycode.KEY_J
|
||||
keys[keycode.KEY_K.Code] = keycode.KEY_K
|
||||
keys[keycode.KEY_L.Code] = keycode.KEY_L
|
||||
keys[keycode.KEY_M.Code] = keycode.KEY_M
|
||||
keys[keycode.KEY_N.Code] = keycode.KEY_N
|
||||
keys[keycode.KEY_O.Code] = keycode.KEY_O
|
||||
keys[keycode.KEY_P.Code] = keycode.KEY_P
|
||||
keys[keycode.KEY_Q.Code] = keycode.KEY_Q
|
||||
keys[keycode.KEY_R.Code] = keycode.KEY_R
|
||||
keys[keycode.KEY_S.Code] = keycode.KEY_S
|
||||
keys[keycode.KEY_T.Code] = keycode.KEY_T
|
||||
keys[keycode.KEY_U.Code] = keycode.KEY_U
|
||||
keys[keycode.KEY_V.Code] = keycode.KEY_V
|
||||
keys[keycode.KEY_W.Code] = keycode.KEY_W
|
||||
keys[keycode.KEY_X.Code] = keycode.KEY_X
|
||||
keys[keycode.KEY_Y.Code] = keycode.KEY_Y
|
||||
keys[keycode.KEY_Z.Code] = keycode.KEY_Z
|
||||
keys[keycode.WIN_LEFT.Code] = keycode.WIN_LEFT
|
||||
keys[keycode.WIN_RIGHT.Code] = keycode.WIN_RIGHT
|
||||
keys[keycode.PAD_0.Code] = keycode.PAD_0
|
||||
keys[keycode.PAD_1.Code] = keycode.PAD_1
|
||||
keys[keycode.PAD_2.Code] = keycode.PAD_2
|
||||
keys[keycode.PAD_3.Code] = keycode.PAD_3
|
||||
keys[keycode.PAD_4.Code] = keycode.PAD_4
|
||||
keys[keycode.PAD_5.Code] = keycode.PAD_5
|
||||
keys[keycode.PAD_6.Code] = keycode.PAD_6
|
||||
keys[keycode.PAD_7.Code] = keycode.PAD_7
|
||||
keys[keycode.PAD_8.Code] = keycode.PAD_8
|
||||
keys[keycode.PAD_9.Code] = keycode.PAD_9
|
||||
keys[keycode.MULTIPLY.Code] = keycode.MULTIPLY
|
||||
keys[keycode.ADD.Code] = keycode.ADD
|
||||
keys[keycode.SUBTRACT.Code] = keycode.SUBTRACT
|
||||
keys[keycode.DECIMAL.Code] = keycode.DECIMAL
|
||||
keys[keycode.DIVIDE.Code] = keycode.DIVIDE
|
||||
keys[keycode.KEY_F1.Code] = keycode.KEY_F1
|
||||
keys[keycode.KEY_F2.Code] = keycode.KEY_F2
|
||||
keys[keycode.KEY_F3.Code] = keycode.KEY_F3
|
||||
keys[keycode.KEY_F4.Code] = keycode.KEY_F4
|
||||
keys[keycode.KEY_F5.Code] = keycode.KEY_F5
|
||||
keys[keycode.KEY_F6.Code] = keycode.KEY_F6
|
||||
keys[keycode.KEY_F7.Code] = keycode.KEY_F7
|
||||
keys[keycode.KEY_F8.Code] = keycode.KEY_F8
|
||||
keys[keycode.KEY_F9.Code] = keycode.KEY_F9
|
||||
keys[keycode.KEY_F10.Code] = keycode.KEY_F10
|
||||
keys[keycode.KEY_F11.Code] = keycode.KEY_F11
|
||||
keys[keycode.KEY_F12.Code] = keycode.KEY_F12
|
||||
keys[keycode.NUM_LOCK.Code] = keycode.NUM_LOCK
|
||||
keys[keycode.SCROLL_LOCK.Code] = keycode.SCROLL_LOCK
|
||||
keys[keycode.SEMI_COLON.Code] = keycode.SEMI_COLON
|
||||
keys[keycode.EQUAL.Code] = keycode.EQUAL
|
||||
keys[keycode.COMMA.Code] = keycode.COMMA
|
||||
keys[keycode.DASH.Code] = keycode.DASH
|
||||
keys[keycode.PERIOD.Code] = keycode.PERIOD
|
||||
keys[keycode.FORWARD_SLASH.Code] = keycode.FORWARD_SLASH
|
||||
keys[keycode.GRAVE.Code] = keycode.GRAVE
|
||||
keys[keycode.OPEN_BRACKET.Code] = keycode.OPEN_BRACKET
|
||||
keys[keycode.BACK_SLASH.Code] = keycode.BACK_SLASH
|
||||
keys[keycode.CLOSE_BRAKET.Code] = keycode.CLOSE_BRAKET
|
||||
keys[keycode.SINGLE_QUOTE.Code] = keycode.SINGLE_QUOTE
|
||||
|
||||
buttons[keycode.LEFT_BUTTON.Code] = keycode.LEFT_BUTTON
|
||||
buttons[keycode.CENTER_BUTTON.Code] = keycode.CENTER_BUTTON
|
||||
buttons[keycode.RIGHT_BUTTON.Code] = keycode.RIGHT_BUTTON
|
||||
buttons[keycode.SCROLL_UP_BUTTON.Code] = keycode.SCROLL_UP_BUTTON
|
||||
buttons[keycode.SCROLL_DOWN_BUTTON.Code] = keycode.SCROLL_DOWN_BUTTON
|
||||
buttons[keycode.SCROLL_LEFT_BUTTON.Code] = keycode.SCROLL_LEFT_BUTTON
|
||||
buttons[keycode.SCROLL_RIGHT_BUTTON.Code] = keycode.SCROLL_RIGHT_BUTTON
|
||||
|
||||
C.XGetScreenConfigurations()
|
||||
}
|
||||
|
||||
@ -167,80 +52,60 @@ func Scroll(x, y int) {
|
||||
C.XScroll(C.int(x), C.int(y))
|
||||
}
|
||||
|
||||
func ButtonDown(code int) (*types.Button, error) {
|
||||
func ButtonDown(code int) error {
|
||||
mu.Lock()
|
||||
defer mu.Unlock()
|
||||
|
||||
button, ok := buttons[code]
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("invalid button %v", code)
|
||||
if _, ok := debounce_button[code]; ok {
|
||||
return fmt.Errorf("debounced button %v", code)
|
||||
}
|
||||
|
||||
if _, ok := debounce[code]; ok {
|
||||
return nil, fmt.Errorf("debounced button %v(%v)", button.Name, code)
|
||||
}
|
||||
debounce_button[code] = time.Now()
|
||||
|
||||
debounce[code] = time.Now()
|
||||
|
||||
C.XButton(C.uint(button.Keysym), C.int(1))
|
||||
return &button, nil
|
||||
C.XButton(C.uint(code), C.int(1))
|
||||
return nil
|
||||
}
|
||||
|
||||
func KeyDown(code int) (*types.Key, error) {
|
||||
func KeyDown(code uint64) error {
|
||||
mu.Lock()
|
||||
defer mu.Unlock()
|
||||
|
||||
key, ok := keys[code]
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("invalid key %v", code)
|
||||
if _, ok := debounce_key[code]; ok {
|
||||
return fmt.Errorf("debounced key %v", code)
|
||||
}
|
||||
|
||||
if _, ok := debounce[code]; ok {
|
||||
return nil, fmt.Errorf("debounced key %v(%v)", key.Name, code)
|
||||
}
|
||||
debounce_key[code] = time.Now()
|
||||
|
||||
debounce[code] = time.Now()
|
||||
|
||||
C.XKey(C.ulong(key.Keysym), C.int(1))
|
||||
return &key, nil
|
||||
C.XKey(C.ulong(code), C.int(1))
|
||||
return nil
|
||||
}
|
||||
|
||||
func ButtonUp(code int) (*types.Button, error) {
|
||||
func ButtonUp(code int) error {
|
||||
mu.Lock()
|
||||
defer mu.Unlock()
|
||||
|
||||
button, ok := buttons[code]
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("invalid button %v", code)
|
||||
if _, ok := debounce_button[code]; !ok {
|
||||
return fmt.Errorf("debounced button %v", code)
|
||||
}
|
||||
|
||||
if _, ok := debounce[code]; !ok {
|
||||
return nil, fmt.Errorf("debounced button %v(%v)", button.Name, code)
|
||||
}
|
||||
delete(debounce_button, code)
|
||||
|
||||
delete(debounce, code)
|
||||
|
||||
C.XButton(C.uint(button.Keysym), C.int(0))
|
||||
return &button, nil
|
||||
C.XButton(C.uint(code), C.int(0))
|
||||
return nil
|
||||
}
|
||||
|
||||
func KeyUp(code int) (*types.Key, error) {
|
||||
func KeyUp(code uint64) error {
|
||||
mu.Lock()
|
||||
defer mu.Unlock()
|
||||
|
||||
key, ok := keys[code]
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("invalid key %v", code)
|
||||
if _, ok := debounce_key[code]; !ok {
|
||||
return fmt.Errorf("debounced key %v", code)
|
||||
}
|
||||
|
||||
if _, ok := debounce[code]; !ok {
|
||||
return nil, fmt.Errorf("debounced key %v(%v)", key.Name, code)
|
||||
}
|
||||
delete(debounce_key, code)
|
||||
|
||||
delete(debounce, code)
|
||||
|
||||
C.XKey(C.ulong(key.Keysym), C.int(0))
|
||||
return &key, nil
|
||||
C.XKey(C.ulong(code), C.int(0))
|
||||
return nil
|
||||
}
|
||||
|
||||
func ReadClipboard() string {
|
||||
@ -264,31 +129,35 @@ func WriteClipboard(data string) {
|
||||
}
|
||||
|
||||
func ResetKeys() {
|
||||
for key := range debounce {
|
||||
if key < 8 {
|
||||
ButtonUp(key)
|
||||
} else {
|
||||
KeyUp(key)
|
||||
}
|
||||
for code := range debounce_button {
|
||||
ButtonUp(code)
|
||||
|
||||
delete(debounce, key)
|
||||
delete(debounce_button, code)
|
||||
}
|
||||
for code := range debounce_key {
|
||||
KeyUp(code)
|
||||
|
||||
delete(debounce_key, code)
|
||||
}
|
||||
}
|
||||
|
||||
func CheckKeys(duration time.Duration) {
|
||||
t := time.Now()
|
||||
for key, start := range debounce {
|
||||
for code, start := range debounce_button {
|
||||
if t.Sub(start) < duration {
|
||||
continue
|
||||
}
|
||||
ButtonUp(code)
|
||||
|
||||
if key < 8 {
|
||||
ButtonUp(key)
|
||||
} else {
|
||||
KeyUp(key)
|
||||
delete(debounce_button, code)
|
||||
}
|
||||
for code, start := range debounce_key {
|
||||
if t.Sub(start) < duration {
|
||||
continue
|
||||
}
|
||||
KeyUp(code)
|
||||
|
||||
delete(debounce, key)
|
||||
delete(debounce_key, code)
|
||||
}
|
||||
}
|
||||
|
||||
@ -342,6 +211,20 @@ func GetScreenSize() *types.ScreenSize {
|
||||
return nil
|
||||
}
|
||||
|
||||
func SetKeyboardLayout(layout string) {
|
||||
mu.Lock()
|
||||
defer mu.Unlock()
|
||||
|
||||
if !regexp.MustCompile(`^[a-zA-Z]+$`).MatchString(layout) {
|
||||
return
|
||||
}
|
||||
|
||||
layoutUnsafe := C.CString(layout)
|
||||
defer C.free(unsafe.Pointer(layoutUnsafe))
|
||||
|
||||
C.SetKeyboardLayout(layoutUnsafe)
|
||||
}
|
||||
|
||||
//export goCreateScreenSize
|
||||
func goCreateScreenSize(index C.int, width C.int, height C.int, mwidth C.int, mheight C.int) {
|
||||
ScreenConfigurations[int(index)] = types.ScreenConfiguration{
|
||||
|
@ -38,5 +38,7 @@
|
||||
|
||||
void XDisplayClose(void);
|
||||
void XDisplaySet(char *input);
|
||||
|
||||
void SetKeyboardLayout(char *layout);
|
||||
#endif
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user