Index: src/wp-admin/includes/user.php
===================================================================
--- src/wp-admin/includes/user.php	(revision 37649)
+++ src/wp-admin/includes/user.php	(working copy)
@@ -97,6 +97,7 @@
 	}
 
 	$user->comment_shortcuts = isset( $_POST['comment_shortcuts'] ) && 'true' == $_POST['comment_shortcuts'] ? 'true' : '';
+	$user->editor_shortcuts = isset( $_POST['editor_shortcuts'] ) && 'true' === $_POST['editor_shortcuts'] ? 'true' : 'false';
 
 	$user->use_ssl = 0;
 	if ( !empty($_POST['use_ssl']) )
Index: src/wp-admin/js/editor-expand.js
===================================================================
--- src/wp-admin/js/editor-expand.js	(revision 37649)
+++ src/wp-admin/js/editor-expand.js	(working copy)
@@ -1105,7 +1105,10 @@
 			} );
 
 			editor.addCommand( 'wpToggleDFW', toggle );
-			editor.addShortcut( 'access+w', '', 'wpToggleDFW' );
+
+			if ( ! editor.settings.wp_disable_custom_shortcuts ) {
+				editor.addShortcut( 'access+w', '', 'wpToggleDFW' );
+			}
 		} );
 
 		$document.on( 'tinymce-editor-init.focus', function( event, editor ) {
Index: src/wp-admin/user-edit.php
===================================================================
--- src/wp-admin/user-edit.php	(revision 37649)
+++ src/wp-admin/user-edit.php	(working copy)
@@ -257,7 +257,20 @@
 if ( !( IS_PROFILE_PAGE && !$user_can_edit ) ) : ?>
 <tr class="user-comment-shortcuts-wrap">
 <th scope="row"><?php _e( 'Keyboard Shortcuts' ); ?></th>
-<td><label for="comment_shortcuts"><input type="checkbox" name="comment_shortcuts" id="comment_shortcuts" value="true" <?php if ( ! empty( $profileuser->comment_shortcuts ) ) checked( 'true', $profileuser->comment_shortcuts ); ?> /> <?php _e('Enable keyboard shortcuts for comment moderation.'); ?></label> <?php _e('<a href="https://codex.wordpress.org/Keyboard_Shortcuts" target="_blank">More information</a>'); ?></td>
+<td>
+	<fieldset>
+	<legend class="screen-reader-text"><span><?php _e( 'Keyboard Shortcuts' ); ?></span></legend>
+	<label for="comment_shortcuts">
+		<input type="checkbox" name="comment_shortcuts" id="comment_shortcuts" value="true" <?php if ( ! empty( $profileuser->comment_shortcuts ) ) checked( 'true', $profileuser->comment_shortcuts ); ?> />
+		<?php _e('Enable keyboard shortcuts for comment moderation.'); ?>
+	</label><br />
+	<label for="editor_shortcuts">
+		<input type="checkbox" name="editor_shortcuts" id="editor_shortcuts" value="true" <?php checked( ( ! isset( $profileuser->editor_shortcuts ) || $profileuser->editor_shortcuts !== 'false' ) ); ?> />
+		<?php _e('Enable custom keyboard shortcuts for the Visual editor.'); ?>
+	</label><br />
+	<?php _e('<a href="https://codex.wordpress.org/Keyboard_Shortcuts" target="_blank">More information</a>'); ?>
+	</fieldset>
+</td>
 </tr>
 <?php endif; ?>
 <tr class="show-admin-bar user-admin-bar-front-wrap">
Index: src/wp-includes/class-wp-editor.php
===================================================================
--- src/wp-includes/class-wp-editor.php	(revision 37649)
+++ src/wp-includes/class-wp-editor.php	(working copy)
@@ -554,6 +554,11 @@
 					'wp_lang_attr' => get_bloginfo( 'language' )
 				);
 
+				if ( is_user_logged_in() && 'false' === get_user_option( 'editor_shortcuts' ) ) {
+					self::$first_init['wp_disable_custom_shortcuts'] = true;
+					self::$first_init['wp_profile_url'] = admin_url( 'profile.php' );
+				}
+
 				if ( ! empty( $mce_external_plugins ) ) {
 					self::$first_init['external_plugins'] = wp_json_encode( $mce_external_plugins );
 				}
@@ -1063,6 +1068,8 @@
 			'Ctrl + letter:' => __( 'Ctrl + letter:' ),
 			'Letter' => __( 'Letter' ),
 			'Action' => __( 'Action' ),
+			'Currently disabled. Can be enabled in your %1$sprofile settings%2$s.' => __( 'Currently disabled. Can be enabled in your %1$sprofile settings%2$s.' ),
+			'Can be disabled in your %1$sprofile settings%2$s.' => __( 'Can be disabled in your %1$sprofile settings%2$s.' ),
 			'To move focus to other buttons use Tab or the arrow keys. To return focus to the editor press Escape or use one of the buttons.' =>
 				__( 'To move focus to other buttons use Tab or the arrow keys. To return focus to the editor press Escape or use one of the buttons.' ),
 			'When starting a new paragraph with one of these formatting shortcuts followed by a space, the formatting will be applied automatically. Press Backspace or Escape to undo.' =>
Index: src/wp-includes/css/editor.css
===================================================================
--- src/wp-includes/css/editor.css	(revision 37649)
+++ src/wp-includes/css/editor.css	(working copy)
@@ -127,6 +127,16 @@
 	box-sizing: border-box;
 }
 
+.mce-window .mce-wp-help a {
+	color: #0073aa;
+	text-decoration: underline;
+}
+
+.mce-window .mce-wp-help a:hover,
+.mce-window .mce-wp-help a:active {
+	color: #00a0d2;
+}
+
 .mce-window .mce-wp-help > .mce-container-body {
 	width: auto !important;
 }
Index: src/wp-includes/js/tinymce/plugins/wordpress/plugin.js
===================================================================
--- src/wp-includes/js/tinymce/plugins/wordpress/plugin.js	(revision 37649)
+++ src/wp-includes/js/tinymce/plugins/wordpress/plugin.js	(working copy)
@@ -212,6 +212,7 @@
 			meta = tinymce.Env.mac ? __( 'Cmd + letter:' ) : __( 'Ctrl + letter:' ),
 			table1 = [],
 			table2 = [],
+			disabledStr,
 			header, html, dialog, $wrap;
 
 		each( [
@@ -254,6 +255,14 @@
 			return out + '</tr>';
 		}
 
+		if ( editor.settings.wp_disable_custom_shortcuts ) {
+			disabledStr = __( 'Currently disabled. Can be enabled in your %1$sprofile settings%2$s.' );
+		} else {
+			disabledStr = __( 'Can be disabled in your %1$sprofile settings%2$s.' );
+		}
+
+		disabledStr = disabledStr.replace( '%1$s', '<a href="' + editor.settings.wp_profile_url + '">' ).replace( '%2$s', '</a>' );
+
 		header = [ __( 'Letter' ), __( 'Action' ), __( 'Letter' ), __( 'Action' ) ];
 		header = '<tr><th>' + header.join( '</th><th>' ) + '</th></tr>';
 
@@ -267,6 +276,7 @@
 				table1.join('') +
 			'</table>' +
 			'<h2>' + __( 'Additional shortcuts,' ) + ' ' + access + '</h2>' +
+			'<p>' + disabledStr + '</p>' +
 			'<table class="wp-help-th-center fixed">' +
 				header +
 				table2.join('') +
@@ -421,7 +431,8 @@
 	});
 
 	editor.on( 'init', function() {
-		var env = tinymce.Env,
+		var key,
+			env = tinymce.Env,
 			bodyClass = ['mceContentBody'], // back-compat for themes that use this in editor-style.css...
 			doc = editor.getDoc(),
 			dom = editor.dom;
@@ -502,6 +513,16 @@
 				});
 			});
 		}
+
+		if ( editor.settings.wp_disable_custom_shortcuts ) {
+			// Remove TinyMCE custom shortcuts, but leave the standard OS shortcuts
+			// like Cmd/Ctrl+Z, Cmd/Ctrl+C, Cmd/Ctrl+V, etc.
+			for( key = 1; key < 10; key++ ) {
+				editor.shortcuts.remove( 'access+' + key );
+			}
+			// Remove the shortcut for the fullscreen plugin.
+			editor.shortcuts.remove( 'ctrl+shift+f' );
+		}
 	});
 
 	editor.on( 'SaveContent', function( event ) {
@@ -532,31 +553,33 @@
 			editor.settings.height = 300;
 		}
 
-		each( {
-			c: 'JustifyCenter',
-			r: 'JustifyRight',
-			l: 'JustifyLeft',
-			j: 'JustifyFull',
-			q: 'mceBlockQuote',
-			u: 'InsertUnorderedList',
-			o: 'InsertOrderedList',
-			s: 'unlink',
-			m: 'WP_Medialib',
-			z: 'WP_Adv',
-			t: 'WP_More',
-			d: 'Strikethrough',
-			h: 'WP_Help',
-			p: 'WP_Page',
-			x: 'WP_Code'
-		}, function( command, key ) {
-			editor.shortcuts.add( 'access+' + key, '', command );
-		} );
+		if ( ! editor.settings.wp_disable_custom_shortcuts ) {
+			each( {
+				c: 'JustifyCenter',
+				r: 'JustifyRight',
+				l: 'JustifyLeft',
+				j: 'JustifyFull',
+				q: 'mceBlockQuote',
+				u: 'InsertUnorderedList',
+				o: 'InsertOrderedList',
+				s: 'unlink',
+				m: 'WP_Medialib',
+				z: 'WP_Adv',
+				t: 'WP_More',
+				d: 'Strikethrough',
+				h: 'WP_Help',
+				p: 'WP_Page',
+				x: 'WP_Code'
+			}, function( command, key ) {
+				editor.shortcuts.add( 'access+' + key, '', command );
+			} );
 
-		editor.addShortcut( 'meta+s', '', function() {
-			if ( wp && wp.autosave ) {
-				wp.autosave.server.triggerSave();
-			}
-		} );
+			editor.addShortcut( 'meta+s', '', function() {
+				if ( wp && wp.autosave ) {
+					wp.autosave.server.triggerSave();
+				}
+			} );
+		}
 
 		if ( window.getUserSetting( 'editor_plain_text_paste_warning' ) > 1 ) {
 			editor.settings.paste_plaintext_inform = false;
Index: src/wp-includes/js/tinymce/plugins/wplink/plugin.js
===================================================================
--- src/wp-includes/js/tinymce/plugins/wplink/plugin.js	(revision 37649)
+++ src/wp-includes/js/tinymce/plugins/wplink/plugin.js	(working copy)
@@ -251,10 +251,12 @@
 			}
 		} );
 
-		// WP default shortcut
-		editor.addShortcut( 'access+a', '', 'WP_Link' );
-		// The "de-facto standard" shortcut, see #27305
-		editor.addShortcut( 'meta+k', '', 'WP_Link' );
+		if ( ! editor.settings.wp_disable_custom_shortcuts ) {
+			// WP default shortcut
+			editor.addShortcut( 'access+a', '', 'WP_Link' );
+			// The "de-facto standard" shortcut, see #27305
+			editor.addShortcut( 'meta+k', '', 'WP_Link' );
+		}
 
 		editor.addButton( 'link', {
 			icon: 'link',
Index: src/wp-includes/user.php
===================================================================
--- src/wp-includes/user.php	(revision 37649)
+++ src/wp-includes/user.php	(working copy)
@@ -1336,7 +1336,7 @@
  * Insert a user into the database.
  *
  * Most of the `$userdata` array fields have filters associated with the values. Exceptions are
- * 'ID', 'rich_editing', 'comment_shortcuts', 'admin_color', 'use_ssl',
+ * 'ID', 'rich_editing', 'comment_shortcuts', 'editor_shortcuts', 'admin_color', 'use_ssl',
  * 'user_registered', and 'role'. The filters have the prefix 'pre_user_' followed by the field
  * name. An example using 'description' would have the filter called, 'pre_user_description' that
  * can be hooked into.
@@ -1371,6 +1371,8 @@
  *                                             False if not empty.
  *     @type string|bool $comment_shortcuts    Whether to enable comment moderation keyboard
  *                                             shortcuts for the user. Default false.
+ *     @type string|bool $editor_shortcuts     Whether to enable keyboard shortcuts for the
+ *                                             Visual editor. Default true.
  *     @type string      $admin_color          Admin color scheme for the user. Default 'fresh'.
  *     @type bool        $use_ssl              Whether the user should always access the admin over
  *                                             https. Default false.
@@ -1583,6 +1585,8 @@
 
 	$meta['comment_shortcuts'] = empty( $userdata['comment_shortcuts'] ) || 'false' === $userdata['comment_shortcuts'] ? 'false' : 'true';
 
+	$meta['editor_shortcuts'] = empty( $userdata['editor_shortcuts'] ) || 'false' !== $userdata['editor_shortcuts'] ? 'true' : 'false';
+
 	$admin_color = empty( $userdata['admin_color'] ) ? 'fresh' : $userdata['admin_color'];
 	$meta['admin_color'] = preg_replace( '|[^a-z0-9 _.\-@]|i', '', $admin_color );
 
@@ -1637,7 +1641,8 @@
 	 *     @type string   $last_name            The user's last name.
 	 *     @type string   $description          The user's description.
 	 *     @type bool     $rich_editing         Whether to enable the rich-editor for the user. False if not empty.
-	 *     @type bool     $comment_shortcuts    Whether to enable keyboard shortcuts for the user. Default false.
+	 *     @type bool     $comment_shortcuts    Whether to enable keyboard shortcuts for comment moderation. Default false.
+	 *     @type bool     $editor_shortcuts     Whether to enable keyboard shortcuts for the Visual editor. Default true.
 	 *     @type string   $admin_color          The color scheme for a user's admin screen. Default 'fresh'.
 	 *     @type int|bool $use_ssl              Whether to force SSL on the user's admin area. 0|false if SSL is
 	 *                                          not forced.
@@ -1951,7 +1956,7 @@
  * @return array List of user keys to be populated in wp_update_user().
  */
 function _get_additional_user_keys( $user ) {
-	$keys = array( 'first_name', 'last_name', 'nickname', 'description', 'rich_editing', 'comment_shortcuts', 'admin_color', 'use_ssl', 'show_admin_bar_front' );
+	$keys = array( 'first_name', 'last_name', 'nickname', 'description', 'rich_editing', 'comment_shortcuts', 'editor_shortcuts', 'admin_color', 'use_ssl', 'show_admin_bar_front' );
 	return array_merge( $keys, array_keys( wp_get_user_contact_methods( $user ) ) );
 }
 
