1#![allow(non_camel_case_types, non_snake_case)]
2
3#[macro_use]
10extern crate bitflags;
11
12use std::os::raw::{c_int, c_uint};
13
14pub const MONO_WIDTH: usize = 160;
16
17pub const MONO_HEIGHT: usize = 43;
19
20pub const COLOR_WIDTH: usize = 320;
22
23pub const COLOR_HEIGHT: usize = 240;
25
26bitflags! {
27 pub struct LcdType: u32 {
31 const MONO = 0x00000001;
33 const COLOR = 0b00000010;
35 const EITHER = Self::MONO.bits | Self::COLOR.bits;
37 }
38}
39
40bitflags! {
41 pub struct LcdButton: u32 {
43 const MONO_BUTTON_0 = 0x00000001;
44 const MONO_BUTTON_1 = 0x00000002;
45 const MONO_BUTTON_2 = 0x00000004;
46 const MONO_BUTTON_3 = 0x00000008;
47 const MONO_BUTTON = Self::MONO_BUTTON_0.bits |
48 Self::MONO_BUTTON_1.bits |
49 Self::MONO_BUTTON_2.bits |
50 Self::MONO_BUTTON_3.bits;
51
52 const COLOR_BUTTON_LEFT = 0x00000100;
53 const COLOR_BUTTON_RIGHT = 0x00000200;
54 const COLOR_BUTTON_OK = 0x00000400;
55 const COLOR_BUTTON_CANCEL = 0x00000800;
56 const COLOR_BUTTON_UP = 0x00001000;
57 const COLOR_BUTTON_DOWN = 0x00002000;
58 const COLOR_BUTTON_MENU = 0x00004000;
59 const COLOR_BUTTON = Self::COLOR_BUTTON_LEFT.bits |
60 Self::COLOR_BUTTON_RIGHT.bits |
61 Self::COLOR_BUTTON_OK.bits |
62 Self::COLOR_BUTTON_CANCEL.bits |
63 Self::COLOR_BUTTON_UP.bits |
64 Self::COLOR_BUTTON_DOWN.bits |
65 Self::COLOR_BUTTON_MENU.bits;
66 }
67}
68
69pub struct LogitechLcd {
73 pub LogiLcdInit: unsafe extern "C" fn(friendlyName: *const u16, lcdType: c_uint) -> bool,
75 pub LogiLcdIsConnected: unsafe extern "C" fn(lcdType: c_uint) -> bool,
76 pub LogiLcdIsButtonPressed: unsafe extern "C" fn(button: c_uint) -> bool,
77 pub LogiLcdUpdate: unsafe extern "C" fn(),
78 pub LogiLcdShutdown: unsafe extern "C" fn(),
79
80 pub LogiLcdMonoSetBackground: unsafe extern "C" fn(monoBitmap: *const u8) -> bool,
82 pub LogiLcdMonoSetText: unsafe extern "C" fn(lineNumber: c_int, text: *const u16) -> bool,
83
84 pub LogiLcdColorSetBackground: unsafe extern "C" fn(colorBitmap: *const u8) -> bool,
86 pub LogiLcdColorSetTitle: unsafe extern "C" fn(text: *const u16, red: c_int, green: c_int,
87 blue: c_int) -> bool,
88 pub LogiLcdColorSetText: unsafe extern "C" fn(lineNumber: c_int, text: *const u16, red: c_int,
89 green: c_int, blue: c_int) -> bool,
90
91 pub LogiLcdColorSetBackgroundUDK: unsafe extern "C" fn(partialBitmap: *const u8,
93 arraySize: c_int) -> c_int,
94 pub LogiLcdColorResetBackgroundUDK: unsafe extern "C" fn() -> c_int,
95 pub LogiLcdMonoSetBackgroundUDK: unsafe extern "C" fn(partialBitmap: *const u8,
96 arraySize: c_int) -> c_int,
97 pub LogiLcdMonoResetBackgroundUDK: unsafe extern "C" fn() -> c_int,
98
99 _library: platform::Library,
101}
102
103unsafe impl std::marker::Send for LogitechLcd {}
104
105#[cfg(not(target_os = "windows"))]
106mod platform {
107 use super::LogitechLcd;
108 use std::io::Error;
109
110 pub struct Library;
111
112 impl LogitechLcd {
113 pub fn load() -> Result<LogitechLcd, Error> {
114 unimplemented!();
115 }
116 }
117}
118
119#[cfg(target_os = "windows")]
120mod platform {
121 extern crate winapi;
122 extern crate kernel32;
123 extern crate winreg;
124
125 use super::LogitechLcd;
126
127 use self::winreg::RegKey;
128 use self::winreg::enums::{HKEY_LOCAL_MACHINE, HKEY_CLASSES_ROOT, KEY_READ};
129 use self::winapi::minwindef::{HMODULE, FARPROC};
130
131 use std::os::windows::ffi::OsStrExt;
132 use std::ffi::OsStr;
133 use std::io::Error;
134
135 pub struct Library(HMODULE);
136
137 const ERROR_MOD_NOT_FOUND: i32 = winapi::winerror::ERROR_MOD_NOT_FOUND as i32;
138
139 fn dll_path_clsid() -> Result<Vec<u16>, Error> {
141 let hkcl = RegKey::predef(HKEY_CLASSES_ROOT);
142 let hklm = RegKey::predef(HKEY_LOCAL_MACHINE);
143
144 let mut dll_path = None;
145
146 #[cfg(target_arch = "x86_64")]
147 {
148 match hkcl.open_subkey_with_flags(
149 "CLSID\\{d0e790a5-01a7-49ae-ae0b-e986bdd0c21b}\\ServerBinary", KEY_READ)
150 {
151 Ok(key) => dll_path = key.get_value::<String, &str>("").ok(),
152 Err(_) => {},
153 }
154
155 match hklm.open_subkey_with_flags(
156 "SOFTWARE\\Classes\\CLSID\\{d0e790a5-01a7-49ae-ae0b-e986bdd0c21b}\\ServerBinary",
157 KEY_READ)
158 {
159 Ok(key) => dll_path = key.get_value::<String, &str>("").ok(),
160 Err(_) => {},
161 }
162 }
163
164 #[cfg(target_arch = "x86")]
165 {
166 match hkcl.open_subkey_with_flags(
167 "Wow6432Node\\CLSID\\{d0e790a5-01a7-49ae-ae0b-e986bdd0c21b}\\ServerBinary", KEY_READ)
168 {
169 Ok(key) => dll_path = key.get_value::<String, &str>("").ok(),
170 Err(_) => {},
171 }
172
173 match hklm.open_subkey_with_flags(
174 "SOFTWARE\\Classes\\Wow6432Node\\CLSID\\{d0e790a5-01a7-49ae-ae0b-e986bdd0c21b}\\ServerBinary",
175 KEY_READ)
176 {
177 Ok(key) => dll_path = key.get_value::<String, &str>("").ok(),
178 Err(_) => {},
179 }
180
181 match hklm.open_subkey_with_flags(
182 "SOFTWARE\\Wow6432Node\\Classes\\CLSID\\{d0e790a5-01a7-49ae-ae0b-e986bdd0c21b}\\ServerBinary",
183 KEY_READ)
184 {
185 Ok(key) => dll_path = key.get_value::<String, &str>("").ok(),
186 Err(_) => {},
187 }
188 }
189
190 match dll_path {
191 Some(p) => Ok(OsStr::new(&p[..]).encode_wide().chain(Some(0)).collect::<Vec<u16>>()),
193 None => Err(Error::from_raw_os_error(ERROR_MOD_NOT_FOUND)),
194 }
195 }
196
197 unsafe fn load_lib() -> Result<HMODULE, Error> {
198 match dll_path_clsid() {
199 Ok(wide_path) => {
200 let handle = kernel32::LoadLibraryW(wide_path.as_ptr());
201 if handle.is_null() {
202 let error = Error::last_os_error();
203 let ecode = error.raw_os_error().unwrap();
204 if ecode != ERROR_MOD_NOT_FOUND {
206 return Err(error);
207 }
208 } else {
209 return Ok(handle);
210 }
211 },
212 Err(e) => {
213 match e.raw_os_error() {
214 Some(ERROR_MOD_NOT_FOUND) => {},
215 _ => return Err(e),
216 }
217 },
218 }
219
220 let wide_name = OsStr::new("LogitechLcd.dll").encode_wide().chain(Some(0)).collect::<Vec<u16>>();
222 let handle = kernel32::LoadLibraryW(wide_name.as_ptr());
223 if handle.is_null() {
224 Err(Error::last_os_error())
225 } else {
226 Ok(handle)
227 }
228 }
229
230 impl LogitechLcd {
231 pub fn load() -> Result<LogitechLcd, Error> {
233 use std::mem;
234
235 unsafe {
236 let handle = load_lib()?;
237
238 let mut symbols = [
239 ("LogiLcdInit\0", 0 as FARPROC),
240 ("LogiLcdIsConnected\0", 0 as FARPROC),
241 ("LogiLcdIsButtonPressed\0", 0 as FARPROC),
242 ("LogiLcdUpdate\0", 0 as FARPROC),
243 ("LogiLcdShutdown\0", 0 as FARPROC),
244 ("LogiLcdMonoSetBackground\0", 0 as FARPROC),
245 ("LogiLcdMonoSetText\0", 0 as FARPROC),
246 ("LogiLcdColorSetBackground\0", 0 as FARPROC),
247 ("LogiLcdColorSetTitle\0", 0 as FARPROC),
248 ("LogiLcdColorSetText\0", 0 as FARPROC),
249 ("LogiLcdColorSetBackgroundUDK\0", 0 as FARPROC),
250 ("LogiLcdColorResetBackgroundUDK\0", 0 as FARPROC),
251 ("LogiLcdMonoSetBackgroundUDK\0", 0 as FARPROC),
252 ("LogiLcdMonoResetBackgroundUDK\0", 0 as FARPROC),
253 ];
254
255 for i in symbols.iter_mut() {
256 i.1 = kernel32::GetProcAddress(handle, i.0.as_ptr() as *const i8);
257 if i.1.is_null() {
258 let error = Error::last_os_error();
259 kernel32::FreeLibrary(handle);
260 return Err(error);
261 }
262 }
263
264 Ok(LogitechLcd {
265 LogiLcdInit: mem::transmute(symbols[0].1),
266 LogiLcdIsConnected: mem::transmute(symbols[1].1),
267 LogiLcdIsButtonPressed: mem::transmute(symbols[2].1),
268 LogiLcdUpdate: mem::transmute(symbols[3].1),
269 LogiLcdShutdown: mem::transmute(symbols[4].1),
270 LogiLcdMonoSetBackground: mem::transmute(symbols[5].1),
271 LogiLcdMonoSetText: mem::transmute(symbols[6].1),
272 LogiLcdColorSetBackground: mem::transmute(symbols[7].1),
273 LogiLcdColorSetTitle: mem::transmute(symbols[8].1),
274 LogiLcdColorSetText: mem::transmute(symbols[9].1),
275 LogiLcdColorSetBackgroundUDK: mem::transmute(symbols[10].1),
276 LogiLcdColorResetBackgroundUDK: mem::transmute(symbols[11].1),
277 LogiLcdMonoSetBackgroundUDK: mem::transmute(symbols[12].1),
278 LogiLcdMonoResetBackgroundUDK: mem::transmute(symbols[13].1),
279 _library: Library(handle),
280 })
281 }
282 }
283 }
284
285 impl Drop for Library {
286 fn drop(&mut self) {
287 unsafe {
288 kernel32::FreeLibrary(self.0);
289 }
290 }
291 }
292}