2 Commits
Author SHA1 Message Date
Claude 9c1f22382e Home button between back and forward; Alt+Home
The on-screen buttons are now back / home / forward. Home (and Alt+Home)
loads the site on screen from the address it was set up with under Sites &
Page Timing, hidden sites included. A shared buildTabUrl() builds that
address for both the first load and the home button.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013wi3ZQveYdjfcrEsyazq32
2026-11-06 18:31:38 +00:00
Outis b836fd6771 Merge pull request #132 from outis1one/claude/optimistic-clarke-27gpk1
Back/forward buttons: adjustable opacity; Upgrade refreshes the Web UI copy
2026-11-06 13:23:30 -05:00
5 changed files with 72 additions and 25 deletions
+2 -1
View File
@@ -249,7 +249,7 @@ The kiosk machine still needs a working internet connection (ethernet, or WiFi c
- **1-finger swipe** (dual mode) - Navigate within page (arrow keys) - **1-finger swipe** (dual mode) - Navigate within page (arrow keys)
- **On-screen keyboard** - Auto-shows on text fields or click keyboard icon - **On-screen keyboard** - Auto-shows on text fields or click keyboard icon
- **Navigation menu** - Click key icon (top-left) to access site list and gesture cheat sheet - **Navigation menu** - Click key icon (top-left) to access site list and gesture cheat sheet
- **Back/forward buttons** (optional, off by default) - two half-transparent ◀ ▶ buttons at the top middle of the screen, for kiosks with no keyboard or mouse side buttons. They appear on a tap, click or mouse movement and fade after a few seconds. Turn on in Core Settings → Display & Interaction, or the Web UI, where you can also set how solid they look (opacity 10–100%, default 50). - **Back / home / forward buttons** (optional, off by default) - three half-transparent buttons (◀ 🏠 ▶) at the top middle of the screen; the home button returns the site on screen to the address it was set up with under Sites & Page Timing, for kiosks with no keyboard or mouse side buttons. They appear on a tap, click or mouse movement and fade after a few seconds. Turn on in Core Settings → Display & Interaction, or the Web UI, where you can also set how solid they look (opacity 10–100%, default 50).
### On-Screen Keyboard ### On-Screen Keyboard
- **HTML-based keyboard** with full QWERTY layout - **HTML-based keyboard** with full QWERTY layout
@@ -778,6 +778,7 @@ smb://WORKGROUP/COMPUTER/PrinterName
- `Ctrl+Shift+Tab` or `Ctrl+[` - Previous tab - `Ctrl+Shift+Tab` or `Ctrl+[` - Previous tab
- `Ctrl+PageDown` / `Ctrl+PageUp` - Next/Previous tab (the standard browser keys) - `Ctrl+PageDown` / `Ctrl+PageUp` - Next/Previous tab (the standard browser keys)
- `Alt+Right` / `Alt+Left` - Page forward / back within the current site (the standard browser keys; they used to switch tabs) - `Alt+Right` / `Alt+Left` - Page forward / back within the current site (the standard browser keys; they used to switch tabs)
- `Alt+Home` - Back to the current site's own start address (the one set under Sites & Page Timing)
- Mouse side buttons (back/forward) - the same page forward/back - Mouse side buttons (back/forward) - the same page forward/back
- `F10` or `Ctrl+H` - Toggle hidden tabs - `F10` or `Ctrl+H` - Toggle hidden tabs
- `Escape` - Return to normal tabs (from hidden) - `Escape` - Return to normal tabs (from hidden)
+58 -13
View File
@@ -772,6 +772,23 @@ function rotateToNextSite(){
} }
} }
// The address a site is loaded from: its configured URL, with the site's
// own login filled in (if it has one) and local files/folders turned into
// the kiosk's viewer addresses. Used when a site's view is first created
// and by the home button, so both always agree.
function buildTabUrl(t){
let url=t.url;
if(t.username&&t.password){
try{
const u=new URL(t.url);
u.username=t.username;
u.password=t.password;
url=u.toString();
}catch(e){}
}
return resolveLocalSite(url);
}
function attachView(i){ function attachView(i){
closeHTMLKeyboard(); closeHTMLKeyboard();
@@ -1157,11 +1174,16 @@ function returnToTabs(){
// mouse's side buttons, and the optional on-screen buttons). Not while the // mouse's side buttons, and the optional on-screen buttons). Not while the
// screen is locked or a dialog (PIN, WiFi, power...) is open on top - the // screen is locked or a dialog (PIN, WiFi, power...) is open on top - the
// keys would silently navigate the page hidden behind it. // keys would silently navigate the page hidden behind it.
function historyGo(direction){ function historyBlocked(){
if(isLockedOut)return; if(isLockedOut)return true;
for(const w of [pinWindow,wifiWindow,promptWindow,pauseWindow]){ for(const w of [pinWindow,wifiWindow,promptWindow,pauseWindow]){
if(w&&!w.isDestroyed())return; if(w&&!w.isDestroyed())return true;
} }
return false;
}
function historyGo(direction){
if(historyBlocked())return;
const view=showingHidden?hiddenViews[currentHiddenIndex]:views[currentIndex]; const view=showingHidden?hiddenViews[currentHiddenIndex]:views[currentIndex];
if(!view||!view.webContents||view.webContents.isDestroyed())return; if(!view||!view.webContents||view.webContents.isDestroyed())return;
const wc=view.webContents; const wc=view.webContents;
@@ -1174,6 +1196,36 @@ function historyGo(direction){
markActivity(); markActivity();
} }
// The tab (index into tabs) behind the n-th hidden view: hidden sites are the
// ones with duration -1, in order.
function hiddenViewIndexToTabIndex(h){
let n=0;
for(let i=0;i<tabs.length;i++){
if(parseInt(tabs[i].duration)===-1){
if(n===h)return i;
n++;
}
}
return -1;
}
// Home button / Alt+Home: back to the address this site was set up with
// (Core Settings -> Sites & Page Timing), whatever page the user has
// browsed to since. Acts on the site that's on screen, so with several
// sites each one goes to its own address.
function historyHome(){
if(historyBlocked())return;
const view=showingHidden?hiddenViews[currentHiddenIndex]:views[currentIndex];
if(!view||!view.webContents||view.webContents.isDestroyed())return;
const tabIdx=showingHidden?hiddenViewIndexToTabIndex(currentHiddenIndex):viewIndexToTabIndex(currentIndex);
if(tabIdx<0||!tabs[tabIdx])return;
const target=buildTabUrl(tabs[tabIdx]);
if(view.webContents.getURL()!==target){
view.webContents.loadURL(target).catch(()=>{});
}
markActivity();
}
function showPinEntry(){ function showPinEntry(){
if(pinWindow&&!pinWindow.isDestroyed()){ if(pinWindow&&!pinWindow.isDestroyed()){
pinWindow.focus(); pinWindow.focus();
@@ -1579,16 +1631,7 @@ async function createWindow(){
mainWindow.addBrowserView(view); mainWindow.addBrowserView(view);
let url=t.url; const url=buildTabUrl(t);
if(t.username&&t.password){
try{
const u=new URL(t.url);
u.username=t.username;
u.password=t.password;
url=u.toString();
}catch(e){}
}
url=resolveLocalSite(url);
const initialOrigin=new URL(t.url).origin; const initialOrigin=new URL(t.url).origin;
@@ -1691,6 +1734,7 @@ async function createWindow(){
ipcMain.on('toggle-hidden',toggleHidden); ipcMain.on('toggle-hidden',toggleHidden);
ipcMain.on('history-nav',(event,direction)=>{ ipcMain.on('history-nav',(event,direction)=>{
if(direction==='back'||direction==='forward')historyGo(direction); if(direction==='back'||direction==='forward')historyGo(direction);
else if(direction==='home')historyHome();
}); });
ipcMain.on('return-to-tabs',forceReturnToTabs); ipcMain.on('return-to-tabs',forceReturnToTabs);
ipcMain.on('user-activity',markActivity); ipcMain.on('user-activity',markActivity);
@@ -1890,6 +1934,7 @@ async function createWindow(){
// Standard browser keys for page back/forward. // Standard browser keys for page back/forward.
globalShortcut.register('Alt+Left',()=>{historyGo('back');}); globalShortcut.register('Alt+Left',()=>{historyGo('back');});
globalShortcut.register('Alt+Right',()=>{historyGo('forward');}); globalShortcut.register('Alt+Right',()=>{historyGo('forward');});
globalShortcut.register('Alt+Home',()=>{historyHome();});
globalShortcut.register('F10',toggleHidden); globalShortcut.register('F10',toggleHidden);
globalShortcut.register('Control+H',toggleHidden); globalShortcut.register('Control+H',toggleHidden);
+3 -2
View File
@@ -115,7 +115,7 @@ ipcRenderer.on('keyboard-button-enabled',(event,enabled)=>{
} }
}); });
// On-screen back/forward buttons (top middle, half transparent) - an // On-screen back / home / forward buttons (top middle, half transparent) - an
// option for screens with no keyboard or mouse side buttons. // option for screens with no keyboard or mouse side buttons.
let historyButtonsEnabled=false; let historyButtonsEnabled=false;
let historyBar=null; let historyBar=null;
@@ -280,7 +280,7 @@ window.addEventListener('DOMContentLoaded',()=>{
historyBar.id='electron-history-bar'; historyBar.id='electron-history-bar';
historyBar.style.cssText=` historyBar.style.cssText=`
position:fixed;top:12px;left:50%;transform:translateX(-50%); position:fixed;top:12px;left:50%;transform:translateX(-50%);
display:none;gap:14px;z-index:999999;opacity:${historyOpacity}; display:none;gap:18px;z-index:999999;opacity:${historyOpacity};
transition:opacity 0.15s;user-select:none; transition:opacity 0.15s;user-select:none;
`; `;
const makeButton=(label,direction,path)=>{ const makeButton=(label,direction,path)=>{
@@ -302,6 +302,7 @@ window.addEventListener('DOMContentLoaded',()=>{
}; };
historyBar.append( historyBar.append(
makeButton('Back','back','M15.41 7.41L14 6l-6 6 6 6 1.41-1.41L10.83 12z'), makeButton('Back','back','M15.41 7.41L14 6l-6 6 6 6 1.41-1.41L10.83 12z'),
makeButton('Home (this site\'s start page)','home','M10 20v-6h4v6h5v-8h3L12 3 2 12h3v8z'),
makeButton('Forward','forward','M8.59 16.59L10 18l6-6-6-6-1.41 1.41L13.17 12z') makeButton('Forward','forward','M8.59 16.59L10 18l6-6-6-6-1.41 1.41L13.17 12z')
); );
historyBar.addEventListener('mouseenter',()=>{historyBar.style.opacity=String(historyHoverOpacity());}); historyBar.addEventListener('mouseenter',()=>{historyBar.style.opacity=String(historyHoverOpacity());});
+7 -7
View File
@@ -20,7 +20,7 @@ display_status() {
echo "Pause button: $(onoff "$ENABLE_PAUSE_BUTTON")" echo "Pause button: $(onoff "$ENABLE_PAUSE_BUTTON")"
echo "Keyboard button: $(onoff "$ENABLE_KEYBOARD_BUTTON")" echo "Keyboard button: $(onoff "$ENABLE_KEYBOARD_BUTTON")"
echo "Navigation button: $(onoff "$ENABLE_NAV_BUTTON")" echo "Navigation button: $(onoff "$ENABLE_NAV_BUTTON")"
echo "Back/forward btns: $(onoff "$ENABLE_HISTORY_BUTTONS") (opacity ${HISTORY_BUTTONS_OPACITY}%)" echo "Back/home/fwd btns: $(onoff "$ENABLE_HISTORY_BUTTONS") (opacity ${HISTORY_BUTTONS_OPACITY}%)"
} }
display_menu_builder() { display_menu_builder() {
@@ -30,8 +30,8 @@ display_menu_builder() {
"Toggle pause button (currently: $(onoff "$ENABLE_PAUSE_BUTTON"))" "Toggle pause button (currently: $(onoff "$ENABLE_PAUSE_BUTTON"))"
"Toggle on-screen keyboard button (currently: $(onoff "$ENABLE_KEYBOARD_BUTTON"))" "Toggle on-screen keyboard button (currently: $(onoff "$ENABLE_KEYBOARD_BUTTON"))"
"Toggle navigation/help button (currently: $(onoff "$ENABLE_NAV_BUTTON"))" "Toggle navigation/help button (currently: $(onoff "$ENABLE_NAV_BUTTON"))"
"Toggle on-screen back/forward buttons (currently: $(onoff "$ENABLE_HISTORY_BUTTONS"))" "Toggle on-screen back/home/forward buttons (currently: $(onoff "$ENABLE_HISTORY_BUTTONS"))"
"Back/forward button opacity (currently: ${HISTORY_BUTTONS_OPACITY}%)" "Back/home/forward button opacity (currently: ${HISTORY_BUTTONS_OPACITY}%)"
) )
MENU_HANDLERS=( MENU_HANDLERS=(
action_set_touch_mode action_set_touch_mode
@@ -144,10 +144,10 @@ action_toggle_nav_button() {
action_toggle_history_buttons() { action_toggle_history_buttons() {
if [[ "$ENABLE_HISTORY_BUTTONS" == "true" ]]; then if [[ "$ENABLE_HISTORY_BUTTONS" == "true" ]]; then
ENABLE_HISTORY_BUTTONS="false" ENABLE_HISTORY_BUTTONS="false"
log_warning "On-screen back/forward buttons disabled" log_warning "On-screen back/home/forward buttons disabled"
else else
ENABLE_HISTORY_BUTTONS="true" ENABLE_HISTORY_BUTTONS="true"
log_success "On-screen back/forward buttons enabled" log_success "On-screen back/home/forward buttons enabled"
fi fi
save_config save_config
} }
@@ -156,10 +156,10 @@ action_toggle_history_buttons() {
# They get a little more solid while the mouse is over them. # They get a little more solid while the mouse is over them.
action_set_history_opacity() { action_set_history_opacity() {
echo echo
echo "How solid the on-screen back/forward buttons look (10 = faint, 100 = solid)." echo "How solid the on-screen back/home/forward buttons look (10 = faint, 100 = solid)."
HISTORY_BUTTONS_OPACITY=$(ask_integer "Opacity percent" "$HISTORY_BUTTONS_OPACITY" 10 100) HISTORY_BUTTONS_OPACITY=$(ask_integer "Opacity percent" "$HISTORY_BUTTONS_OPACITY" 10 100)
save_config save_config
log_success "Back/forward button opacity: ${HISTORY_BUTTONS_OPACITY}%" log_success "Back/home/forward button opacity: ${HISTORY_BUTTONS_OPACITY}%"
if [[ "$ENABLE_HISTORY_BUTTONS" != "true" ]]; then if [[ "$ENABLE_HISTORY_BUTTONS" != "true" ]]; then
log_info "The buttons are off - turn them on with the entry above." log_info "The buttons are off - turn them on with the entry above."
fi fi
+2 -2
View File
@@ -95,7 +95,7 @@
<label class="checkbox"><input type="checkbox" name="enablePauseButton"> Pause button</label> <label class="checkbox"><input type="checkbox" name="enablePauseButton"> Pause button</label>
<label class="checkbox"><input type="checkbox" name="enableKeyboardButton"> On-screen keyboard button</label> <label class="checkbox"><input type="checkbox" name="enableKeyboardButton"> On-screen keyboard button</label>
<label class="checkbox"><input type="checkbox" name="enableNavButton"> Navigation/help button</label> <label class="checkbox"><input type="checkbox" name="enableNavButton"> Navigation/help button</label>
<label class="checkbox"><input type="checkbox" name="enableHistoryButtons"> On-screen back/forward buttons (top middle)</label> <label class="checkbox"><input type="checkbox" name="enableHistoryButtons"> On-screen back / home / forward buttons (top middle)</label>
<fieldset> <fieldset>
<legend>Home page</legend> <legend>Home page</legend>
@@ -106,7 +106,7 @@
</select> </select>
</label> </label>
<label> <label>
Back/forward button opacity (10 = faint, 100 = solid) Back/home/forward button opacity (10 = faint, 100 = solid)
<input type="number" name="historyButtonsOpacity" min="10" max="100" step="5"> <input type="number" name="historyButtonsOpacity" min="10" max="100" step="5">
</label> </label>
<label> <label>