feat(ags osk): add spam typing on long press
All checks were successful
Discord / discord commits (push) Has been skipped
All checks were successful
Discord / discord commits (push) Has been skipped
This commit is contained in:
parent
f445db75c1
commit
d85b0847dd
6 changed files with 92 additions and 108 deletions
|
@ -32,8 +32,7 @@
|
||||||
border-radius: 0.7rem;
|
border-radius: 0.7rem;
|
||||||
min-height: 3rem;
|
min-height: 3rem;
|
||||||
|
|
||||||
transition: background-color 0.2s ease-in-out,
|
transition: background-color 0.2s ease-in-out, border-color 0.2s ease-in-out;
|
||||||
border-color 0.2s ease-in-out;
|
|
||||||
|
|
||||||
&.normal,
|
&.normal,
|
||||||
&.Super {
|
&.Super {
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import { execAsync } from 'astal';
|
import { execAsync, idle } from 'astal';
|
||||||
import { Gtk } from 'astal/gtk3';
|
import { Gtk } from 'astal/gtk3';
|
||||||
|
|
||||||
|
import Tablet from '../../services/tablet';
|
||||||
import { hyprMessage } from '../../lib';
|
import { hyprMessage } from '../../lib';
|
||||||
|
|
||||||
import OskWindow from './osk-window';
|
import OskWindow from './osk-window';
|
||||||
|
@ -19,14 +20,18 @@ const releaseAllKeys = () => {
|
||||||
};
|
};
|
||||||
|
|
||||||
export default (window: OskWindow) => {
|
export default (window: OskWindow) => {
|
||||||
const gesture = Gtk.GestureDrag.new(window);
|
const tablet = Tablet.get_default();
|
||||||
|
|
||||||
window.get_child().css = `margin-bottom: -${HIDDEN_MARGIN}px;`;
|
|
||||||
|
|
||||||
let signals = [] as number[];
|
let signals = [] as number[];
|
||||||
|
|
||||||
window.setVisible = (state: boolean) => {
|
const gesture = Gtk.GestureDrag.new(window);
|
||||||
if (state) {
|
|
||||||
|
window.get_child().css = `
|
||||||
|
margin-bottom: -${HIDDEN_MARGIN}px;
|
||||||
|
`;
|
||||||
|
|
||||||
|
window.hook(tablet, 'notify::osk-state', () => {
|
||||||
|
if (tablet.oskState) {
|
||||||
window.setSlideDown();
|
window.setSlideDown();
|
||||||
|
|
||||||
window.get_child().css = `
|
window.get_child().css = `
|
||||||
|
@ -36,6 +41,7 @@ export default (window: OskWindow) => {
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
releaseAllKeys();
|
releaseAllKeys();
|
||||||
|
|
||||||
window.setSlideUp();
|
window.setSlideUp();
|
||||||
|
|
||||||
window.get_child().css = `
|
window.get_child().css = `
|
||||||
|
@ -43,7 +49,11 @@ export default (window: OskWindow) => {
|
||||||
margin-bottom: -${HIDDEN_MARGIN}px;
|
margin-bottom: -${HIDDEN_MARGIN}px;
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
};
|
});
|
||||||
|
|
||||||
|
idle(() => {
|
||||||
|
tablet.oskState = false;
|
||||||
|
});
|
||||||
|
|
||||||
window.killGestureSigs = () => {
|
window.killGestureSigs = () => {
|
||||||
signals.forEach((id) => {
|
signals.forEach((id) => {
|
||||||
|
@ -115,7 +125,7 @@ export default (window: OskWindow) => {
|
||||||
transition: margin-bottom 0.5s ease-in-out;
|
transition: margin-bottom 0.5s ease-in-out;
|
||||||
margin-bottom: 0px;
|
margin-bottom: 0px;
|
||||||
`;
|
`;
|
||||||
window.setVisible(true);
|
tablet.oskState = true;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
window.get_child().css = `
|
window.get_child().css = `
|
||||||
|
@ -184,7 +194,7 @@ export default (window: OskWindow) => {
|
||||||
margin-bottom: -${HIDDEN_MARGIN}px;
|
margin-bottom: -${HIDDEN_MARGIN}px;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
window.setVisible(false);
|
tablet.oskState = false;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
window.get_child().css = `
|
window.get_child().css = `
|
||||||
|
|
|
@ -115,8 +115,8 @@ export default () => (
|
||||||
return (
|
return (
|
||||||
<box vertical>
|
<box vertical>
|
||||||
<box
|
<box
|
||||||
halign={Gtk.Align.END}
|
|
||||||
className="row"
|
className="row"
|
||||||
|
halign={Gtk.Align.END}
|
||||||
>
|
>
|
||||||
{...keys}
|
{...keys}
|
||||||
</box>
|
</box>
|
||||||
|
|
|
@ -1,11 +1,13 @@
|
||||||
import { execAsync, Variable } from 'astal';
|
import { bind, execAsync, interval, Variable } from 'astal';
|
||||||
import { Gdk, Gtk, Widget } from 'astal/gtk3';
|
import { Gtk, Widget } from 'astal/gtk3';
|
||||||
|
|
||||||
import Brightness from '../../services/brightness';
|
import Brightness from '../../services/brightness';
|
||||||
|
|
||||||
import Separator from '../misc/separator';
|
import Separator from '../misc/separator';
|
||||||
|
|
||||||
/* Types */
|
/* Types */
|
||||||
|
import AstalIO from 'gi://AstalIO';
|
||||||
|
|
||||||
interface Key {
|
interface Key {
|
||||||
keytype: string
|
keytype: string
|
||||||
label: string
|
label: string
|
||||||
|
@ -16,7 +18,6 @@ interface Key {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const display = Gdk.Display.get_default();
|
|
||||||
const brightness = Brightness.get_default();
|
const brightness = Brightness.get_default();
|
||||||
|
|
||||||
const SPACING = 4;
|
const SPACING = 4;
|
||||||
|
@ -24,10 +25,6 @@ const LSHIFT_CODE = 42;
|
||||||
const LALT_CODE = 56;
|
const LALT_CODE = 56;
|
||||||
const LCTRL_CODE = 29;
|
const LCTRL_CODE = 29;
|
||||||
|
|
||||||
// Keep track of when a non modifier key
|
|
||||||
// is clicked to release all modifiers
|
|
||||||
const NormalClick = Variable(false);
|
|
||||||
|
|
||||||
// Keep track of modifier statuses
|
// Keep track of modifier statuses
|
||||||
const Super = Variable(false);
|
const Super = Variable(false);
|
||||||
const LAlt = Variable(false);
|
const LAlt = Variable(false);
|
||||||
|
@ -97,42 +94,14 @@ const ModKey = (key: Key) => {
|
||||||
const button = (
|
const button = (
|
||||||
<eventbox
|
<eventbox
|
||||||
className="key"
|
className="key"
|
||||||
|
cursor="pointer"
|
||||||
|
|
||||||
onButtonReleaseEvent={() => {
|
onButtonPressEvent={() => {
|
||||||
console.log('mod toggled');
|
|
||||||
|
|
||||||
execAsync(`ydotool key ${key.keycode}:${Mod.get() ? 0 : 1}`);
|
execAsync(`ydotool key ${key.keycode}:${Mod.get() ? 0 : 1}`);
|
||||||
|
|
||||||
label.toggleClassName('active', !Mod.get());
|
label.toggleClassName('active', !Mod.get());
|
||||||
Mod.set(!Mod.get());
|
Mod.set(!Mod.get());
|
||||||
}}
|
}}
|
||||||
|
|
||||||
setup={(self) => {
|
|
||||||
self.hook(NormalClick, () => {
|
|
||||||
Mod.set(false);
|
|
||||||
|
|
||||||
label.toggleClassName('active', false);
|
|
||||||
execAsync(`ydotool key ${key.keycode}:0`);
|
|
||||||
});
|
|
||||||
|
|
||||||
// OnHover
|
|
||||||
self.connect('enter-notify-event', () => {
|
|
||||||
if (!display) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
self.window.set_cursor(Gdk.Cursor.new_from_name(
|
|
||||||
display,
|
|
||||||
'pointer',
|
|
||||||
));
|
|
||||||
self.toggleClassName('hover', true);
|
|
||||||
});
|
|
||||||
|
|
||||||
// OnHoverLost
|
|
||||||
self.connect('leave-notify-event', () => {
|
|
||||||
self.window.set_cursor(null);
|
|
||||||
self.toggleClassName('hover', false);
|
|
||||||
});
|
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
{label}
|
{label}
|
||||||
</eventbox>
|
</eventbox>
|
||||||
|
@ -147,65 +116,58 @@ const ModKey = (key: Key) => {
|
||||||
};
|
};
|
||||||
|
|
||||||
const RegularKey = (key: Key) => {
|
const RegularKey = (key: Key) => {
|
||||||
|
const IsActive = Variable(false);
|
||||||
|
const IsLongPressing = Variable(false);
|
||||||
|
|
||||||
const widget = (
|
const widget = (
|
||||||
<eventbox
|
<eventbox
|
||||||
className="key"
|
className="key"
|
||||||
|
cursor="pointer"
|
||||||
|
|
||||||
|
onButtonReleaseEvent={() => {
|
||||||
|
IsLongPressing.set(false);
|
||||||
|
IsActive.set(false);
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
<label
|
<label
|
||||||
className={`normal ${key.label}`}
|
className={bind(IsActive).as((v) => [
|
||||||
|
'normal',
|
||||||
|
key.label,
|
||||||
|
(v ? 'active' : ''),
|
||||||
|
].join(' '))}
|
||||||
|
|
||||||
label={key.label}
|
label={key.label}
|
||||||
|
|
||||||
setup={(self) => {
|
setup={(self) => {
|
||||||
self
|
self
|
||||||
.hook(Shift, () => {
|
.hook(Shift, () => {
|
||||||
if (!key.labelShift) {
|
if (key.labelShift) {
|
||||||
return;
|
self.label = Shift.get() ?
|
||||||
|
key.labelShift :
|
||||||
|
key.label;
|
||||||
}
|
}
|
||||||
|
|
||||||
self.label = Shift.get() ? key.labelShift : key.label;
|
|
||||||
})
|
})
|
||||||
.hook(Caps, () => {
|
.hook(Caps, () => {
|
||||||
if (key.label === 'Caps') {
|
if (key.label === 'Caps') {
|
||||||
self.toggleClassName('active', Caps.get());
|
IsActive.set(Caps.get());
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!key.labelShift) {
|
if (key.labelShift && key.label.match(/[A-Za-z]/)) {
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (key.label.match(/[A-Za-z]/)) {
|
|
||||||
self.label = Caps.get() ?
|
self.label = Caps.get() ?
|
||||||
key.labelShift :
|
key.labelShift :
|
||||||
key.label;
|
key.label;
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.hook(AltGr, () => {
|
.hook(AltGr, () => {
|
||||||
if (!key.labelAltGr) {
|
if (key.labelAltGr) {
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
self.toggleClassName('altgr', AltGr.get());
|
self.toggleClassName('altgr', AltGr.get());
|
||||||
self.label = AltGr.get() ? key.labelAltGr : key.label;
|
|
||||||
});
|
|
||||||
|
|
||||||
// OnHover
|
self.label = AltGr.get() ?
|
||||||
self.connect('enter-notify-event', () => {
|
key.labelAltGr :
|
||||||
if (!display) {
|
key.label;
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
self.window.set_cursor(Gdk.Cursor.new_from_name(
|
|
||||||
display,
|
|
||||||
'pointer',
|
|
||||||
));
|
|
||||||
self.toggleClassName('hover', true);
|
|
||||||
});
|
|
||||||
|
|
||||||
// OnHoverLost
|
|
||||||
self.connect('leave-notify-event', () => {
|
|
||||||
self.window.set_cursor(null);
|
|
||||||
self.toggleClassName('hover', false);
|
|
||||||
});
|
});
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
@ -216,8 +178,7 @@ const RegularKey = (key: Key) => {
|
||||||
|
|
||||||
gesture.delay_factor = 1.0;
|
gesture.delay_factor = 1.0;
|
||||||
|
|
||||||
// OnPrimaryClickRelease
|
const onClick = (callback: () => void) => {
|
||||||
widget.hook(gesture, 'cancelled', () => {
|
|
||||||
const pointer = gesture.get_point(null);
|
const pointer = gesture.get_point(null);
|
||||||
const x = pointer[1];
|
const x = pointer[1];
|
||||||
const y = pointer[2];
|
const y = pointer[2];
|
||||||
|
@ -226,11 +187,41 @@ const RegularKey = (key: Key) => {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log('key clicked');
|
callback();
|
||||||
|
};
|
||||||
|
|
||||||
|
widget.hook(gesture, 'begin', () => {
|
||||||
|
IsActive.set(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
widget.hook(gesture, 'cancelled', () => {
|
||||||
|
onClick(() => {
|
||||||
execAsync(`ydotool key ${key.keycode}:1`);
|
execAsync(`ydotool key ${key.keycode}:1`);
|
||||||
execAsync(`ydotool key ${key.keycode}:0`);
|
execAsync(`ydotool key ${key.keycode}:0`);
|
||||||
NormalClick.set(true);
|
|
||||||
|
IsActive.set(false);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// Long Press
|
||||||
|
widget.hook(gesture, 'pressed', () => {
|
||||||
|
onClick(() => {
|
||||||
|
IsLongPressing.set(true);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
let spamClick: AstalIO.Time | undefined;
|
||||||
|
|
||||||
|
IsLongPressing.subscribe((v) => {
|
||||||
|
if (v) {
|
||||||
|
spamClick = interval(100, () => {
|
||||||
|
execAsync(`ydotool key ${key.keycode}:1`);
|
||||||
|
execAsync(`ydotool key ${key.keycode}:0`);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
spamClick?.cancel();
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
|
@ -1,20 +1,15 @@
|
||||||
import { execAsync, idle } from 'astal';
|
import { execAsync } from 'astal';
|
||||||
import { Astal } from 'astal/gtk3';
|
import { Astal } from 'astal/gtk3';
|
||||||
|
|
||||||
import Tablet from '../../services/tablet';
|
|
||||||
|
|
||||||
import OskWindow from './osk-window';
|
import OskWindow from './osk-window';
|
||||||
import Gesture from './gesture';
|
import Gesture from './gesture';
|
||||||
import Keyboard from './keyboard';
|
import Keyboard from './keyboard';
|
||||||
|
|
||||||
|
|
||||||
export default () => {
|
export default () => {
|
||||||
// Start ydotool daemon
|
|
||||||
execAsync('ydotoold').catch(print);
|
execAsync('ydotoold').catch(print);
|
||||||
|
|
||||||
const tablet = Tablet.get_default();
|
return Gesture((
|
||||||
|
|
||||||
const window = (
|
|
||||||
<OskWindow
|
<OskWindow
|
||||||
name="osk"
|
name="osk"
|
||||||
namespace="noanim-osk"
|
namespace="noanim-osk"
|
||||||
|
@ -29,15 +24,5 @@ export default () => {
|
||||||
>
|
>
|
||||||
<Keyboard />
|
<Keyboard />
|
||||||
</OskWindow>
|
</OskWindow>
|
||||||
) as OskWindow;
|
) as OskWindow);
|
||||||
|
|
||||||
window.hook(tablet, 'notify::osk-state', (self, state) => {
|
|
||||||
self.setVisible(state);
|
|
||||||
});
|
|
||||||
|
|
||||||
idle(() => {
|
|
||||||
window.setVisible(false);
|
|
||||||
});
|
|
||||||
|
|
||||||
return Gesture(window);
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -6,7 +6,6 @@ import { register } from 'astal/gobject';
|
||||||
export default class OskWindow extends Widget.Window {
|
export default class OskWindow extends Widget.Window {
|
||||||
public startY: number | null = null;
|
public startY: number | null = null;
|
||||||
|
|
||||||
declare public setVisible: (state: boolean) => void;
|
|
||||||
declare public killGestureSigs: () => void;
|
declare public killGestureSigs: () => void;
|
||||||
declare public setSlideUp: () => void;
|
declare public setSlideUp: () => void;
|
||||||
declare public setSlideDown: () => void;
|
declare public setSlideDown: () => void;
|
||||||
|
|
Loading…
Reference in a new issue