fix(wry): swallow WebView2 F6 accelerator to prevent black screen
This commit is contained in:
parent
fa2365153a
commit
e00a6a8b52
|
|
@ -15,7 +15,9 @@ dirs-sys = { path = "vendor/dirs-sys" }
|
||||||
pageant = { path = "vendor/pageant" }
|
pageant = { path = "vendor/pageant" }
|
||||||
# Wry 0.55 probes and creates WebView2 with a null browser folder. Pass the
|
# Wry 0.55 probes and creates WebView2 with a null browser folder. Pass the
|
||||||
# bundled Fixed Runtime path explicitly so Windows 7 does not fall back to an
|
# bundled Fixed Runtime path explicitly so Windows 7 does not fall back to an
|
||||||
# unavailable system Runtime.
|
# unavailable system Runtime. The vendored copy also intercepts the WebView2
|
||||||
|
# F6 "Focus Next Pane" accelerator to prevent a black screen on frameless
|
||||||
|
# Overlay-titlebar windows (see vendor/wry/src/webview2/mod.rs).
|
||||||
wry = { path = "vendor/wry" }
|
wry = { path = "vendor/wry" }
|
||||||
tokio-postgres = { git = "https://github.com/t8y2/tokio-postgres-gaussdb.git", rev = "115f9fef10f0fc3669b5337955e4eb461fc349a6" }
|
tokio-postgres = { git = "https://github.com/t8y2/tokio-postgres-gaussdb.git", rev = "115f9fef10f0fc3669b5337955e4eb461fc349a6" }
|
||||||
postgres-types = { git = "https://github.com/t8y2/tokio-postgres-gaussdb.git", rev = "115f9fef10f0fc3669b5337955e4eb461fc349a6" }
|
postgres-types = { git = "https://github.com/t8y2/tokio-postgres-gaussdb.git", rev = "115f9fef10f0fc3669b5337955e4eb461fc349a6" }
|
||||||
|
|
|
||||||
|
|
@ -2320,7 +2320,7 @@ mod tests {
|
||||||
|
|
||||||
let find = command.get_document("explain").unwrap();
|
let find = command.get_document("explain").unwrap();
|
||||||
assert_eq!(find.get_str("find").unwrap(), "im_msg");
|
assert_eq!(find.get_str("find").unwrap(), "im_msg");
|
||||||
assert_eq!(find.get_document("filter").unwrap().get_bool("active").unwrap(), true);
|
assert!(find.get_document("filter").unwrap().get_bool("active").unwrap());
|
||||||
assert_eq!(find.get_document("projection").unwrap().get_i64("email").unwrap(), 1);
|
assert_eq!(find.get_document("projection").unwrap().get_i64("email").unwrap(), 1);
|
||||||
assert_eq!(find.get_document("sort").unwrap().get_i64("email").unwrap(), 1);
|
assert_eq!(find.get_document("sort").unwrap().get_i64("email").unwrap(), 1);
|
||||||
assert_eq!(find.get_i64("skip").unwrap(), 2);
|
assert_eq!(find.get_i64("skip").unwrap(), 2);
|
||||||
|
|
|
||||||
|
|
@ -1016,7 +1016,7 @@ async fn postgres_query_one_cached(
|
||||||
}
|
}
|
||||||
|
|
||||||
enum PreparedSelectOutcome {
|
enum PreparedSelectOutcome {
|
||||||
Complete(QueryResult),
|
Complete(Box<QueryResult>),
|
||||||
TextFallback { column_types: Vec<String>, unsupported_type: String },
|
TextFallback { column_types: Vec<String>, unsupported_type: String },
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1129,7 +1129,7 @@ async fn execute_select_prepared(
|
||||||
);
|
);
|
||||||
|
|
||||||
let (spatial_columns, spatial_values) = spatial_columns.finish_with_values(spatial_values);
|
let (spatial_columns, spatial_values) = spatial_columns.finish_with_values(spatial_values);
|
||||||
Ok(PreparedSelectOutcome::Complete(QueryResult {
|
Ok(PreparedSelectOutcome::Complete(Box::new(QueryResult {
|
||||||
columns,
|
columns,
|
||||||
column_types,
|
column_types,
|
||||||
column_sortables: Vec::new(),
|
column_sortables: Vec::new(),
|
||||||
|
|
@ -1143,7 +1143,7 @@ async fn execute_select_prepared(
|
||||||
has_more: false,
|
has_more: false,
|
||||||
elasticsearch_raw_body: None,
|
elasticsearch_raw_body: None,
|
||||||
messages: Vec::new(),
|
messages: Vec::new(),
|
||||||
}))
|
})))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn matching_pg_text_column_types(columns: &[String], prepared: Option<Vec<String>>) -> Vec<String> {
|
fn matching_pg_text_column_types(columns: &[String], prepared: Option<Vec<String>>) -> Vec<String> {
|
||||||
|
|
@ -1250,7 +1250,7 @@ async fn finish_prepared_select(
|
||||||
progress_clock: Option<&StreamProgressClock>,
|
progress_clock: Option<&StreamProgressClock>,
|
||||||
) -> Result<QueryResult, String> {
|
) -> Result<QueryResult, String> {
|
||||||
match outcome {
|
match outcome {
|
||||||
PreparedSelectOutcome::Complete(result) => Ok(result),
|
PreparedSelectOutcome::Complete(result) => Ok(*result),
|
||||||
PreparedSelectOutcome::TextFallback { column_types, unsupported_type } => {
|
PreparedSelectOutcome::TextFallback { column_types, unsupported_type } => {
|
||||||
log::info!(
|
log::info!(
|
||||||
"[postgres][select:text_fallback] unsupported_type={} switching_to=simple_query",
|
"[postgres][select:text_fallback] unsupported_type={} switching_to=simple_query",
|
||||||
|
|
@ -1585,8 +1585,10 @@ const POSTGRES_CONNECTION_IDENTITY_SQL: &str = "SELECT pg_backend_pid(), \
|
||||||
/// Notice buffers for live connections, keyed by connection identity. Entries
|
/// Notice buffers for live connections, keyed by connection identity. Entries
|
||||||
/// are weak so they disappear once the pooled connection (and its driver
|
/// are weak so they disappear once the pooled connection (and its driver
|
||||||
/// task) is dropped.
|
/// task) is dropped.
|
||||||
fn postgres_notice_buffers() -> &'static Mutex<HashMap<PostgresConnectionKey, Weak<Mutex<Vec<QueryMessage>>>>> {
|
type PostgresNoticeBuffers = HashMap<PostgresConnectionKey, Weak<Mutex<Vec<QueryMessage>>>>;
|
||||||
static BUFFERS: OnceLock<Mutex<HashMap<PostgresConnectionKey, Weak<Mutex<Vec<QueryMessage>>>>>> = OnceLock::new();
|
|
||||||
|
fn postgres_notice_buffers() -> &'static Mutex<PostgresNoticeBuffers> {
|
||||||
|
static BUFFERS: OnceLock<Mutex<PostgresNoticeBuffers>> = OnceLock::new();
|
||||||
BUFFERS.get_or_init(|| Mutex::new(HashMap::new()))
|
BUFFERS.get_or_init(|| Mutex::new(HashMap::new()))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1599,11 +1601,10 @@ fn postgres_notice_buffers() -> &'static Mutex<HashMap<PostgresConnectionKey, We
|
||||||
/// never be retried from `drain_postgres_notices`, which can run inside the
|
/// never be retried from `drain_postgres_notices`, which can run inside the
|
||||||
/// read-only transaction used for EXPLAIN, where a failing query would abort
|
/// read-only transaction used for EXPLAIN, where a failing query would abort
|
||||||
/// the user's statement.
|
/// the user's statement.
|
||||||
fn postgres_client_keys(
|
type PostgresClientKeys = HashMap<usize, (Weak<deadpool_postgres::StatementCache>, Option<PostgresConnectionKey>)>;
|
||||||
) -> &'static Mutex<HashMap<usize, (Weak<deadpool_postgres::StatementCache>, Option<PostgresConnectionKey>)>> {
|
|
||||||
static KEYS: OnceLock<
|
fn postgres_client_keys() -> &'static Mutex<PostgresClientKeys> {
|
||||||
Mutex<HashMap<usize, (Weak<deadpool_postgres::StatementCache>, Option<PostgresConnectionKey>)>>,
|
static KEYS: OnceLock<Mutex<PostgresClientKeys>> = OnceLock::new();
|
||||||
> = OnceLock::new();
|
|
||||||
KEYS.get_or_init(|| Mutex::new(HashMap::new()))
|
KEYS.get_or_init(|| Mutex::new(HashMap::new()))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3220,12 +3220,12 @@ mod tests {
|
||||||
sqlserver_dml_output_returns_rows, sqlserver_done_trace_event, sqlserver_filter_definition_error,
|
sqlserver_dml_output_returns_rows, sqlserver_done_trace_event, sqlserver_filter_definition_error,
|
||||||
sqlserver_hidden_schema_names, sqlserver_indexes_sql, sqlserver_legacy_indexes_sql, sqlserver_legacy_probe,
|
sqlserver_hidden_schema_names, sqlserver_indexes_sql, sqlserver_legacy_indexes_sql, sqlserver_legacy_probe,
|
||||||
sqlserver_legacy_probe_with_nonce, sqlserver_legacy_wildcard_metadata_query, sqlserver_list_objects_sql,
|
sqlserver_legacy_probe_with_nonce, sqlserver_legacy_wildcard_metadata_query, sqlserver_list_objects_sql,
|
||||||
sqlserver_list_schemas_sql, sqlserver_list_tables_sql, sqlserver_probe_explicit_alias, sqlserver_query_messages,
|
sqlserver_list_schemas_sql, sqlserver_list_tables_sql, sqlserver_probe_explicit_alias,
|
||||||
sqlserver_schema_name_predicate, sqlserver_spatial_marker, sqlserver_supports_session_database_switch,
|
sqlserver_query_messages, sqlserver_schema_name_predicate, sqlserver_spatial_marker,
|
||||||
sqlserver_table_comment_sql, sqlserver_triggers_sql, sqlserver_visible_object_predicate,
|
sqlserver_supports_session_database_switch, sqlserver_table_comment_sql, sqlserver_triggers_sql,
|
||||||
strip_dbx_sqlserver_row_number_column, SqlServerDescribedColumn, SqlServerProbeOutputNameOverride,
|
sqlserver_visible_object_predicate, strip_dbx_sqlserver_row_number_column, SqlServerDescribedColumn,
|
||||||
SqlServerResultSet, SqlServerSpatialColumn, SqlServerTdsEvent, SQLSERVER_COMPLETION_CONTEXT_SQL,
|
SqlServerProbeOutputNameOverride, SqlServerResultSet, SqlServerSpatialColumn, SqlServerTdsEvent,
|
||||||
SQLSERVER_RESULT_TYPE_PROBE_SQL,
|
SQLSERVER_COMPLETION_CONTEXT_SQL, SQLSERVER_RESULT_TYPE_PROBE_SQL,
|
||||||
};
|
};
|
||||||
use crate::types::{
|
use crate::types::{
|
||||||
CompletionAssistantMatchMode, CompletionAssistantObjectKind, CompletionAssistantRequest, QueryResult,
|
CompletionAssistantMatchMode, CompletionAssistantObjectKind, CompletionAssistantRequest, QueryResult,
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,7 @@ use windows::{
|
||||||
Globalization::*,
|
Globalization::*,
|
||||||
Graphics::Gdi::*,
|
Graphics::Gdi::*,
|
||||||
System::{Com::*, LibraryLoader::GetModuleHandleW},
|
System::{Com::*, LibraryLoader::GetModuleHandleW},
|
||||||
UI::{Input::KeyboardAndMouse::SetFocus, Shell::*, WindowsAndMessaging::*},
|
UI::{Input::KeyboardAndMouse::{SetFocus, VK_F6}, Shell::*, WindowsAndMessaging::*},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -471,6 +471,32 @@ impl InnerWebView {
|
||||||
// Webview handlers
|
// Webview handlers
|
||||||
unsafe { Self::attach_handlers(hwnd, &webview, &mut attributes, &mut token, env)? };
|
unsafe { Self::attach_handlers(hwnd, &webview, &mut attributes, &mut token, env)? };
|
||||||
|
|
||||||
|
// Swallow the WebView2 "Focus Next Pane" browser accelerator (F6 / Shift+F6).
|
||||||
|
// DBX has no F6 binding, and Chromium's focus cycling against the frameless
|
||||||
|
// Overlay-titlebar window can drop the compositor into a black screen
|
||||||
|
// (reproduced in both dev and packaged builds). Marking the key as handled
|
||||||
|
// stops the WebView from performing its default focus action.
|
||||||
|
unsafe {
|
||||||
|
let accelerator_key_handler = AcceleratorKeyPressedEventHandler::create(Box::new(
|
||||||
|
move |_, args| {
|
||||||
|
let Some(args) = args else { return Ok(()) };
|
||||||
|
let mut kind = COREWEBVIEW2_KEY_EVENT_KIND::default();
|
||||||
|
args.KeyEventKind(&mut kind)?;
|
||||||
|
if kind == COREWEBVIEW2_KEY_EVENT_KIND_KEY_DOWN
|
||||||
|
|| kind == COREWEBVIEW2_KEY_EVENT_KIND_SYSTEM_KEY_DOWN
|
||||||
|
{
|
||||||
|
let mut virtual_key = 0u32;
|
||||||
|
args.VirtualKey(&mut virtual_key)?;
|
||||||
|
if virtual_key == VK_F6.0 as u32 {
|
||||||
|
args.SetHandled(true)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
},
|
||||||
|
));
|
||||||
|
controller.add_AcceleratorKeyPressed(&accelerator_key_handler, &mut token)?;
|
||||||
|
}
|
||||||
|
|
||||||
// IPC handler
|
// IPC handler
|
||||||
unsafe { Self::attach_ipc_handler(&webview, &mut attributes, &mut token)? };
|
unsafe { Self::attach_ipc_handler(&webview, &mut attributes, &mut token)? };
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue