diff --git a/Marlin/src/feature/bedlevel/ubl/ubl_G29.cpp b/Marlin/src/feature/bedlevel/ubl/ubl_G29.cpp
index 573ab10ea8ab9fd7c7afd7d9b38f32cbace52dc3..a4208a1636fff304cdda96ac02d5999e21ffa0bb 100644
--- a/Marlin/src/feature/bedlevel/ubl/ubl_G29.cpp
+++ b/Marlin/src/feature/bedlevel/ubl/ubl_G29.cpp
@@ -24,6 +24,8 @@
 
 #if ENABLED(AUTO_BED_LEVELING_UBL)
 
+  //#define UBL_DEVEL_DEBUGGING
+
   #include "ubl.h"
 
   #include "../../../Marlin.h"
@@ -728,8 +730,31 @@
           z_values[x][y] += g29_constant;
   }
 
-  #if HAS_BED_PROBE
+  #if ENABLED(NEWPANEL)
+
+    typedef void (*clickFunc_t)();
+
+    bool click_and_hold(const clickFunc_t func=NULL) {
+      if (is_lcd_clicked()) {
+        lcd_quick_feedback();
+        const millis_t nxt = millis() + 1500UL;
+        while (is_lcd_clicked()) {                // Loop while the encoder is pressed. Uses hardware flag!
+          idle();                                 // idle, of course
+          if (ELAPSED(millis(), nxt)) {           // After 1.5 seconds
+            lcd_quick_feedback();
+            if (func) (*func)();
+            wait_for_release();
+            safe_delay(50);                       // Debounce the Encoder wheel
+            return true;
+          }
+        }
+      }
+      return false;
+    }
 
+  #endif // NEWPANEL
+
+  #if HAS_BED_PROBE
     /**
      * Probe all invalidated locations of the mesh that can be reached by the probe.
      * This attempts to fill in locations closest to the nozzle's start location first.
@@ -754,10 +779,9 @@
             SERIAL_PROTOCOLLNPGM("\nMesh only partially populated.\n");
             lcd_quick_feedback();
             STOW_PROBE();
-            while (is_lcd_clicked()) idle();
+            wait_for_release();
             lcd_external_control = false;
             restore_ubl_active_state_and_leave();
-            safe_delay(50);  // Debounce the Encoder wheel
             return;
           }
         #endif
@@ -894,19 +918,20 @@
 
   #if ENABLED(NEWPANEL)
 
-    float unified_bed_leveling::measure_point_with_encoder() {
-
-      while (is_lcd_clicked()) delay(50);  // wait for user to release encoder wheel
-      delay(50);  // debounce
-
-      KEEPALIVE_STATE(PAUSED_FOR_USER);
-      while (!is_lcd_clicked()) {     // we need the loop to move the nozzle based on the encoder wheel here!
+    void unified_bed_leveling::move_z_with_encoder(const float &multiplier) {
+      wait_for_release();
+      while (!is_lcd_clicked()) {
         idle();
         if (encoder_diff) {
-          do_blocking_move_to_z(current_position[Z_AXIS] + 0.01 * float(encoder_diff));
+          do_blocking_move_to_z(current_position[Z_AXIS] + float(encoder_diff) * multiplier);
           encoder_diff = 0;
         }
       }
+    }
+
+    float unified_bed_leveling::measure_point_with_encoder() {
+      KEEPALIVE_STATE(PAUSED_FOR_USER);
+      move_z_with_encoder(0.01);
       KEEPALIVE_STATE(IN_HANDLER);
       return current_position[Z_AXIS];
     }
@@ -953,12 +978,19 @@
       return thickness;
     }
 
+    void abort_manual_probe_remaining_mesh() {
+      SERIAL_PROTOCOLLNPGM("\nMesh only partially populated.");
+      do_blocking_move_to_z(Z_CLEARANCE_DEPLOY_PROBE);
+      lcd_external_control = false;
+      KEEPALIVE_STATE(IN_HANDLER);
+      ubl.restore_ubl_active_state_and_leave();
+    }
+
     void unified_bed_leveling::manually_probe_remaining_mesh(const float &rx, const float &ry, const float &z_clearance, const float &thick, const bool do_ubl_mesh_map) {
 
       lcd_external_control = true;
 
       save_ubl_active_state_and_disable();   // we don't do bed level correction because we want the raw data when we probe
-
       do_blocking_move_to(rx, ry, Z_CLEARANCE_BETWEEN_PROBES);
 
       lcd_return_to_status();
@@ -989,34 +1021,15 @@
         const float z_step = 0.01;                                        // existing behavior: 0.01mm per click, occasionally step
         //const float z_step = 1.0 / planner.axis_steps_per_mm[Z_AXIS];   // approx one step each click
 
-        while (is_lcd_clicked()) delay(50);             // wait for user to release encoder wheel
-        delay(50);                                       // debounce
-        while (!is_lcd_clicked()) {                     // we need the loop to move the nozzle based on the encoder wheel here!
-          idle();
-          if (encoder_diff) {
-            do_blocking_move_to_z(current_position[Z_AXIS] + float(encoder_diff) * z_step);
-            encoder_diff = 0;
-          }
-        }
-
-        // this sequence to detect an is_lcd_clicked() debounce it and leave if it is
-        // a Press and Hold is repeated in a lot of places (including G26_Mesh_Validation.cpp).   This
-        // should be redone and compressed.
-        const millis_t nxt = millis() + 1500L;
-        while (is_lcd_clicked()) {     // debounce and watch for abort
-          idle();
-          if (ELAPSED(millis(), nxt)) {
-            SERIAL_PROTOCOLLNPGM("\nMesh only partially populated.");
-            do_blocking_move_to_z(Z_CLEARANCE_DEPLOY_PROBE);
-
-            lcd_quick_feedback();
-            while (is_lcd_clicked()) idle();
-            lcd_external_control = false;
+        move_z_with_encoder(z_step);
 
-            KEEPALIVE_STATE(IN_HANDLER);
-            restore_ubl_active_state_and_leave();
-            return;
-          }
+        if (click_and_hold()) {
+          SERIAL_PROTOCOLLNPGM("\nMesh only partially populated.");
+          do_blocking_move_to_z(Z_CLEARANCE_DEPLOY_PROBE);
+          lcd_external_control = false;
+          KEEPALIVE_STATE(IN_HANDLER);
+          restore_ubl_active_state_and_leave();
+          return;
         }
 
         z_values[location.x_index][location.y_index] = current_position[Z_AXIS] - thick;
@@ -1150,36 +1163,39 @@
     return UBL_OK;
   }
 
-  static int ubl_state_at_invocation = 0,
-             ubl_state_recursion_chk = 0;
-
-  void unified_bed_leveling::save_ubl_active_state_and_disable() {
-    ubl_state_recursion_chk++;
-    if (ubl_state_recursion_chk != 1) {
-      SERIAL_ECHOLNPGM("save_ubl_active_state_and_disabled() called multiple times in a row.");
+  static uint8_t ubl_state_at_invocation = 0;
 
-      #if ENABLED(NEWPANEL)
-        LCD_MESSAGEPGM(MSG_UBL_SAVE_ERROR);
-        lcd_quick_feedback();
-      #endif
+  #ifdef UBL_DEVEL_DEBUGGING
+    static uint8_t ubl_state_recursion_chk = 0;
+  #endif
 
-      return;
-    }
+  void unified_bed_leveling::save_ubl_active_state_and_disable() {
+    #ifdef UBL_DEVEL_DEBUGGING
+      ubl_state_recursion_chk++;
+      if (ubl_state_recursion_chk != 1) {
+        SERIAL_ECHOLNPGM("save_ubl_active_state_and_disabled() called multiple times in a row.");
+        #if ENABLED(NEWPANEL)
+          LCD_MESSAGEPGM(MSG_UBL_SAVE_ERROR);
+          lcd_quick_feedback();
+        #endif
+        return;
+      }
+    #endif
     ubl_state_at_invocation = planner.leveling_active;
     set_bed_leveling_enabled(false);
   }
 
   void unified_bed_leveling::restore_ubl_active_state_and_leave() {
-    if (--ubl_state_recursion_chk) {
-      SERIAL_ECHOLNPGM("restore_ubl_active_state_and_leave() called too many times.");
-
-      #if ENABLED(NEWPANEL)
-        LCD_MESSAGEPGM(MSG_UBL_RESTORE_ERROR);
-        lcd_quick_feedback();
-      #endif
-
-      return;
-    }
+    #ifdef UBL_DEVEL_DEBUGGING
+      if (--ubl_state_recursion_chk) {
+        SERIAL_ECHOLNPGM("restore_ubl_active_state_and_leave() called too many times.");
+        #if ENABLED(NEWPANEL)
+          LCD_MESSAGEPGM(MSG_UBL_RESTORE_ERROR);
+          lcd_quick_feedback();
+        #endif
+        return;
+      }
+    #endif
     set_bed_leveling_enabled(ubl_state_at_invocation);
   }
 
@@ -1249,28 +1265,30 @@
     SERIAL_EOL();
     safe_delay(50);
 
-    SERIAL_PROTOCOLLNPAIR("ubl_state_at_invocation :", ubl_state_at_invocation);
-    SERIAL_EOL();
-    SERIAL_PROTOCOLLNPAIR("ubl_state_recursion_chk :", ubl_state_recursion_chk);
-    SERIAL_EOL();
-    safe_delay(50);
+    #ifdef UBL_DEVEL_DEBUGGING
+      SERIAL_PROTOCOLLNPAIR("ubl_state_at_invocation :", ubl_state_at_invocation);
+      SERIAL_EOL();
+      SERIAL_PROTOCOLLNPAIR("ubl_state_recursion_chk :", ubl_state_recursion_chk);
+      SERIAL_EOL();
+      safe_delay(50);
 
-    SERIAL_PROTOCOLPAIR("Meshes go from ", hex_address((void*)settings.get_start_of_meshes()));
-    SERIAL_PROTOCOLLNPAIR(" to ", hex_address((void*)settings.get_end_of_meshes()));
-    safe_delay(50);
+      SERIAL_PROTOCOLPAIR("Meshes go from ", hex_address((void*)settings.get_start_of_meshes()));
+      SERIAL_PROTOCOLLNPAIR(" to ", hex_address((void*)settings.get_end_of_meshes()));
+      safe_delay(50);
 
-    SERIAL_PROTOCOLLNPAIR("sizeof(ubl) :  ", (int)sizeof(ubl));
-    SERIAL_EOL();
-    SERIAL_PROTOCOLLNPAIR("z_value[][] size: ", (int)sizeof(z_values));
-    SERIAL_EOL();
-    safe_delay(25);
+      SERIAL_PROTOCOLLNPAIR("sizeof(ubl) :  ", (int)sizeof(ubl));
+      SERIAL_EOL();
+      SERIAL_PROTOCOLLNPAIR("z_value[][] size: ", (int)sizeof(z_values));
+      SERIAL_EOL();
+      safe_delay(25);
 
-    SERIAL_PROTOCOLLNPAIR("EEPROM free for UBL: ", hex_address((void*)(settings.get_end_of_meshes() - settings.get_start_of_meshes())));
-    safe_delay(50);
+      SERIAL_PROTOCOLLNPAIR("EEPROM free for UBL: ", hex_address((void*)(settings.get_end_of_meshes() - settings.get_start_of_meshes())));
+      safe_delay(50);
 
-    SERIAL_PROTOCOLPAIR("EEPROM can hold ", settings.calc_num_meshes());
-    SERIAL_PROTOCOLLNPGM(" meshes.\n");
-    safe_delay(25);
+      SERIAL_PROTOCOLPAIR("EEPROM can hold ", settings.calc_num_meshes());
+      SERIAL_PROTOCOLLNPGM(" meshes.\n");
+      safe_delay(25);
+    #endif // UBL_DEVEL_DEBUGGING
 
     if (!sanity_check()) {
       echo_name();
@@ -1456,6 +1474,12 @@
 
   #if ENABLED(NEWPANEL)
 
+    void abort_fine_tune() {
+      lcd_return_to_status();
+      do_blocking_move_to_z(Z_CLEARANCE_BETWEEN_PROBES);
+      LCD_MESSAGEPGM(MSG_EDITING_STOPPED);
+    }
+
     void unified_bed_leveling::fine_tune_mesh(const float &rx, const float &ry, const bool do_ubl_mesh_map) {
       if (!parser.seen('R'))    // fine_tune_mesh() is special. If no repetition count flag is specified
         g29_repetition_cnt = 1;   // do exactly one mesh location. Otherwise use what the parser decided.
@@ -1513,13 +1537,13 @@
 
         lcd_mesh_edit_setup(new_z);
 
-        do {
+        while (!is_lcd_clicked()) {
           new_z = lcd_mesh_edit();
           #if ENABLED(UBL_MESH_EDIT_MOVES_Z)
             do_blocking_move_to_z(h_offset + new_z); // Move the nozzle as the point is edited
           #endif
           idle();
-        } while (!is_lcd_clicked());
+        }
 
         if (!lcd_map_control) lcd_return_to_status();
 
@@ -1531,19 +1555,8 @@
         // this sequence to detect an is_lcd_clicked() debounce it and leave if it is
         // a Press and Hold is repeated in a lot of places (including G26_Mesh_Validation.cpp).   This
         // should be redone and compressed.
-        const millis_t nxt = millis() + 1500UL;
-        while (is_lcd_clicked()) { // debounce and watch for abort
-          idle();
-          if (ELAPSED(millis(), nxt)) {
-            lcd_return_to_status();
-            do_blocking_move_to_z(Z_CLEARANCE_BETWEEN_PROBES);
-            LCD_MESSAGEPGM(MSG_EDITING_STOPPED);
-
-            while (is_lcd_clicked()) idle();
-
-            goto FINE_TUNE_EXIT;
-          }
-        }
+        if (click_and_hold(abort_fine_tune))
+          goto FINE_TUNE_EXIT;
 
         safe_delay(20);                       // We don't want any switch noise.
 
diff --git a/Marlin/src/gcode/bedlevel/G26.cpp b/Marlin/src/gcode/bedlevel/G26.cpp
index d5791b97f7364cbb0676f3b28dafd050f6880d09..0e09f2243fb656f2a1c2a3a1bb9173b43f139d69 100644
--- a/Marlin/src/gcode/bedlevel/G26.cpp
+++ b/Marlin/src/gcode/bedlevel/G26.cpp
@@ -162,28 +162,27 @@ int8_t g26_prime_flag;
    * Detect is_lcd_clicked, debounce it, and return true for cancel
    */
   bool user_canceled() {
-    if (!is_lcd_clicked()) return false;
-    safe_delay(10);                       // Wait for click to settle
+    if (!is_lcd_clicked()) return false; // Return if the button isn't pressed
 
     #if ENABLED(ULTRA_LCD)
       lcd_setstatusPGM(PSTR("Mesh Validation Stopped."), 99);
       lcd_quick_feedback();
     #endif
 
-    while (!is_lcd_clicked()) idle();    // Wait for button release
+    safe_delay(10);                      // Wait for click to settle
+    while (!is_lcd_clicked()) idle();    // Wait for button press again?
 
     // If the button is suddenly pressed again,
     // ask the user to resolve the issue
     lcd_setstatusPGM(PSTR("Release button"), 99); // will never appear...
-    while (is_lcd_clicked()) idle();             // unless this loop happens
+    wait_for_release();
     lcd_reset_status();
-
     return true;
   }
 
   bool exit_from_g26() {
     lcd_setstatusPGM(PSTR("Leaving G26"), -1);
-    while (is_lcd_clicked()) idle();
+    wait_for_release();
     return G26_ERR;
   }
 
@@ -514,7 +513,7 @@ inline bool prime_nozzle() {
         idle();
       }
 
-      while (is_lcd_clicked()) idle();           // Debounce Encoder Wheel
+      wait_for_release();
 
       strcpy_P(lcd_status_message, PSTR("Done Priming")); // We can't do lcd_setstatusPGM() without having it continue;
                                                           // So... We cheat to get a message up.
diff --git a/Marlin/src/lcd/ultralcd.cpp b/Marlin/src/lcd/ultralcd.cpp
index ab784a71f2baa57785085c07ca5154bd74cedfb8..ae58c10b17491189d9a9184a5ad2e79635123e00 100644
--- a/Marlin/src/lcd/ultralcd.cpp
+++ b/Marlin/src/lcd/ultralcd.cpp
@@ -5105,6 +5105,10 @@ void lcd_reset_alert_level() { lcd_status_message_level = 0; }
 
   #if ENABLED(AUTO_BED_LEVELING_UBL) || ENABLED(G26_MESH_VALIDATION)
     bool is_lcd_clicked() { return LCD_CLICKED; }
+    void wait_for_release() {
+      while (is_lcd_clicked()) safe_delay(50);
+      safe_delay(50);
+    }
   #endif
 
 #endif // ULTIPANEL
diff --git a/Marlin/src/lcd/ultralcd.h b/Marlin/src/lcd/ultralcd.h
index 5e1c43934a04f2c514c45bbf2031cc544401c7df..23148ae351230bf63c2484ed66cd4721b2aac1aa 100644
--- a/Marlin/src/lcd/ultralcd.h
+++ b/Marlin/src/lcd/ultralcd.h
@@ -222,6 +222,7 @@
 
   #if ENABLED(AUTO_BED_LEVELING_UBL) || ENABLED(G26_MESH_VALIDATION)
     bool is_lcd_clicked();
+    void wait_for_release();
   #endif
 
 #else // no LCD