settings/keyboard/
keyboard_fidl_handler.rs1use crate::base::{SettingInfo, SettingType};
6use crate::handler::base::Request;
7use crate::ingress::{request, watch, Scoped};
8use crate::job::source::{Error as JobError, ErrorResponder};
9use crate::job::Job;
10use crate::keyboard::types::{Autorepeat, KeyboardInfo, KeymapId};
11use fidl::prelude::*;
12use fidl_fuchsia_settings::{
13 KeyboardRequest, KeyboardSetResponder, KeyboardSetSetResult, KeyboardSettings,
14 KeyboardWatchResponder,
15};
16
17impl ErrorResponder for KeyboardSetResponder {
18 fn id(&self) -> &'static str {
19 "Keyboard_Set"
20 }
21
22 fn respond(self: Box<Self>, error: fidl_fuchsia_settings::Error) -> Result<(), fidl::Error> {
23 self.send(Err(error))
24 }
25}
26
27impl request::Responder<Scoped<KeyboardSetSetResult>> for KeyboardSetResponder {
28 fn respond(self, Scoped(response): Scoped<KeyboardSetSetResult>) {
29 let _ = self.send(response);
30 }
31}
32
33impl watch::Responder<KeyboardSettings, zx::Status> for KeyboardWatchResponder {
34 fn respond(self, response: Result<KeyboardSettings, zx::Status>) {
35 match response {
36 Ok(settings) => {
37 let _ = self.send(&settings);
38 }
39 Err(error) => {
40 self.control_handle().shutdown_with_epitaph(error);
41 }
42 }
43 }
44}
45
46impl TryFrom<KeyboardRequest> for Job {
47 type Error = JobError;
48
49 fn try_from(item: KeyboardRequest) -> Result<Self, Self::Error> {
50 #[allow(unreachable_patterns)]
51 match item {
52 KeyboardRequest::Set { settings, responder } => match to_request(settings) {
53 Ok(request) => {
54 Ok(request::Work::new(SettingType::Keyboard, request, responder).into())
55 }
56 Err(e) => {
57 log::error!(
58 "Transferring from KeyboardSettings to a Set request has an error: {:?}",
59 e
60 );
61 Err(JobError::InvalidInput(Box::new(responder)))
62 }
63 },
64 KeyboardRequest::Watch { responder } => {
65 Ok(watch::Work::new_job(SettingType::Keyboard, responder))
66 }
67 _ => {
68 log::warn!("Received a call to an unsupported API: {:?}", item);
69 Err(JobError::Unsupported)
70 }
71 }
72 }
73}
74
75impl From<SettingInfo> for KeyboardSettings {
76 fn from(response: SettingInfo) -> Self {
77 if let SettingInfo::Keyboard(info) = response {
78 return KeyboardSettings {
79 keymap: info.keymap.map(KeymapId::into),
80 autorepeat: info.autorepeat.map(Autorepeat::into),
81 ..Default::default()
82 };
83 }
84
85 panic!("incorrect value sent to keyboard");
86 }
87}
88
89fn to_request(settings: KeyboardSettings) -> Result<Request, String> {
90 let autorepeat: Option<Autorepeat> = settings.autorepeat.map(|src| src.into());
91 let keymap = settings.keymap.map(KeymapId::try_from).transpose()?;
92 Ok(Request::SetKeyboardInfo(KeyboardInfo { keymap, autorepeat }))
93}
94
95#[cfg(test)]
96mod tests {
97 use super::*;
98 use crate::job::{execution, work};
99 use assert_matches::assert_matches;
100 use fidl_fuchsia_settings::{KeyboardMarker, KeyboardRequestStream};
101 use futures::StreamExt;
102
103 #[fuchsia::test]
104 fn test_request_from_settings_empty() {
105 let request = to_request(KeyboardSettings::default()).unwrap();
106
107 assert_eq!(
108 request,
109 Request::SetKeyboardInfo(KeyboardInfo { keymap: None, autorepeat: None })
110 );
111 }
112
113 #[fuchsia::test]
114 fn test_request_from_settings_error() {
115 let keyboard_settings = KeyboardSettings {
116 keymap: Some(fidl_fuchsia_input::KeymapId::unknown()),
117 ..Default::default()
118 };
119
120 assert!(format!("{:?}", to_request(keyboard_settings).unwrap_err())
121 .contains("Received an invalid keymap id:"));
122 }
123
124 #[fuchsia::test]
125 fn test_request_from_settings() {
126 use crate::keyboard::types::Autorepeat;
127
128 const KEYMAP_ID: fidl_fuchsia_input::KeymapId = fidl_fuchsia_input::KeymapId::FrAzerty;
129 const DELAY: i64 = 1;
130 const PERIOD: i64 = 2;
131 const AUTOREPEAT: fidl_fuchsia_settings::Autorepeat =
132 fidl_fuchsia_settings::Autorepeat { delay: DELAY, period: PERIOD };
133
134 let keyboard_settings = KeyboardSettings {
135 keymap: Some(KEYMAP_ID),
136 autorepeat: Some(AUTOREPEAT),
137 ..Default::default()
138 };
139
140 let request = to_request(keyboard_settings).unwrap();
141
142 assert_eq!(
143 request,
144 Request::SetKeyboardInfo(KeyboardInfo {
145 keymap: Some(KeymapId::FrAzerty),
146 autorepeat: Some(Autorepeat { delay: DELAY, period: PERIOD }),
147 })
148 );
149 }
150
151 #[fuchsia::test(allow_stalls = false)]
152 async fn try_from_set_converts_supplied_params() {
153 let (proxy, server) = fidl::endpoints::create_proxy::<KeyboardMarker>();
154 let _fut = proxy.set(&KeyboardSettings {
155 keymap: Some(fidl_fuchsia_input::KeymapId::FrAzerty),
156 ..Default::default()
157 });
158 let mut request_stream: KeyboardRequestStream = server.into_stream();
159 let request = request_stream
160 .next()
161 .await
162 .expect("should have on request before stream is closed")
163 .expect("should have gotten a request");
164 let job = Job::try_from(request);
165 let job = job.as_ref();
166 assert_matches!(job.map(|j| j.workload()), Ok(work::Load::Independent(_)));
167 assert_matches!(job.map(|j| j.execution_type()), Ok(execution::Type::Independent));
168 }
169
170 #[fuchsia::test(allow_stalls = false)]
171 async fn try_from_watch_converts_supplied_params() {
172 let (proxy, server) = fidl::endpoints::create_proxy::<KeyboardMarker>();
173 let _fut = proxy.watch();
174 let mut request_stream: KeyboardRequestStream = server.into_stream();
175 let request = request_stream
176 .next()
177 .await
178 .expect("should have on request before stream is closed")
179 .expect("should have gotten a request");
180 let job = Job::try_from(request);
181 let job = job.as_ref();
182 assert_matches!(job.map(|j| j.workload()), Ok(work::Load::Sequential(_, _)));
183 assert_matches!(job.map(|j| j.execution_type()), Ok(execution::Type::Sequential(_)));
184 }
185}