void terminate(void) { refresh_timer_.terminate(); clear_remapclasses(); }
void refresh(void) { // We use timer to prevent deadlock of lock_. (refresh may be called in the remap_key, remap_consumer, *). enum { DELAY = 1, }; refresh_timer_.setTimeoutMS(DELAY); }
void terminate(void) { refresh_timer_.terminate(); clear_xml(); IOLockWrapper::free(lock_); }
void initialize(IOWorkLoop& workloop) { statusmessage_[0] = '\0'; lastmessage_[0] = '\0'; remapclasses_ = NULL; enabled_remapclasses_ = NULL; refresh_timer_.initialize(&workloop, NULL, refresh_timer_callback); }
void initialize(IOWorkLoop& workloop) { lock_ = IOLockWrapper::alloc(); statusmessage_[0] = '\0'; lastmessage_[0] = '\0'; remapclasses_ = NULL; enabled_remapclasses_ = NULL; refresh_timer_.initialize(&workloop, NULL, refresh_core); }
void CALLBACK TimerCallbackWrapper(PVOID lpParameter, BOOLEAN TimerOrWaitFired) { TimerWrapper* wrapper = reinterpret_cast<TimerWrapper*>(lpParameter); wrapper->Callback(wrapper->Parameter); }
namespace RemapClassManager { TimerWrapper refresh_timer_; char statusmessage_[BRIDGE_USERCLIENT_STATUS_MESSAGE_MAXLEN]; char lastmessage_[BRIDGE_USERCLIENT_STATUS_MESSAGE_MAXLEN]; bool isEventInputQueueDelayEnabled_ = false; Vector_RemapClassPointer* remapclasses_ = NULL; Vector_RemapClassPointer* enabled_remapclasses_ = NULL; // ====================================================================== static void refresh_timer_callback(OSObject* owner, IOTimerEventSource* sender) { if (! remapclasses_) { IOLOG_ERROR("RemapClassManager::refresh_core remapclasses_ == NULL.\n"); return; } // ---------------------------------------- if (enabled_remapclasses_) { delete enabled_remapclasses_; } enabled_remapclasses_ = new Vector_RemapClassPointer(); if (! enabled_remapclasses_) return; // ---------------------------------------- KeyboardRepeat::cancel(); statusmessage_[0] = '\0'; isEventInputQueueDelayEnabled_ = false; for (size_t i = 0; i < remapclasses_->size(); ++i) { RemapClass* p = (*remapclasses_)[i]; if (! p) continue; if (p->enabled()) { enabled_remapclasses_->push_back(p); const char* msg = p->get_statusmessage(); if (msg) { strlcat(statusmessage_, msg, sizeof(statusmessage_)); strlcat(statusmessage_, " ", sizeof(statusmessage_)); } if (p->is_simultaneouskeypresses()) { isEventInputQueueDelayEnabled_ = true; } } } if (strcmp(statusmessage_, lastmessage_) != 0) { strlcpy(lastmessage_, statusmessage_, sizeof(lastmessage_)); int index = BRIDGE_USERCLIENT_STATUS_MESSAGE_EXTRA; CommonData::clear_statusmessage(index); CommonData::append_statusmessage(index, statusmessage_); CommonData::send_notification_statusmessage(index); } } // ====================================================================== void initialize(IOWorkLoop& workloop) { statusmessage_[0] = '\0'; lastmessage_[0] = '\0'; remapclasses_ = NULL; enabled_remapclasses_ = NULL; refresh_timer_.initialize(&workloop, NULL, refresh_timer_callback); } static void clear_remapclasses(void) { VirtualKey::VK_CONFIG::clear_items(); if (enabled_remapclasses_) { delete enabled_remapclasses_; enabled_remapclasses_ = NULL; } if (remapclasses_) { for (size_t i = 0; i < remapclasses_->size(); ++i) { RemapClass* p = (*remapclasses_)[i]; if (p) { delete p; } } delete remapclasses_; remapclasses_ = NULL; } } void terminate(void) { refresh_timer_.terminate(); clear_remapclasses(); } bool load_remapclasses_initialize_vector(const uint32_t* const remapclasses_initialize_vector, mach_vm_size_t vector_size) { // ------------------------------------------------------------ // clean previous resources and setup new resources. clear_remapclasses(); remapclasses_ = new Vector_RemapClassPointer(); if (! remapclasses_) { IOLOG_ERROR("%s remapclasses_ == NULL.\n", __FUNCTION__); goto error; } // ------------------------------------------------------------ // Validate vector_size // "vector_size" is byte of remapclasses_initialize_vector. (!= count of items.) // Confirming vector_size is a multiple of sizeof(uint32_t). if ((vector_size % sizeof(uint32_t)) != 0) { IOLOG_ERROR("%s (vector_size %% sizeof(uint32_t)) != 0. (%d)\n", __FUNCTION__, static_cast<int>(vector_size)); goto error; } // change vector_size to num of uint32_t. vector_size /= sizeof(uint32_t); // Then, we can treat "remapclasses_initialize_vector + vector_size" as valid. if (vector_size < 2) { IOLOG_ERROR("%s vector_size < 2. (%d)\n", __FUNCTION__, static_cast<int>(vector_size)); goto error; } if (vector_size > RemapClass::MAX_ALLOCATION_COUNT) { IOLOG_ERROR("%s too large vector_size. (%d)\n", __FUNCTION__, static_cast<int>(vector_size)); goto error; } // ------------------------------------------------------------ { const uint32_t* p = remapclasses_initialize_vector; uint32_t version = *p++; uint32_t count = *p++; if (version != BRIDGE_REMAPCLASS_INITIALIZE_VECTOR_FORMAT_VERSION) { IOLOG_ERROR("%s version mismatch.\n", __FUNCTION__); goto error; } if (count > RemapClass::MAX_CONFIG_COUNT) { IOLOG_ERROR("%s too many count. (%d)\n", __FUNCTION__, count); goto error; } // ------------------------------------------------------------ // load remapclasses_->reserve(count); RemapClass::reset_allocation_count(); // (1) Setting NULL to all items. for (uint32_t i = 0; i < count; ++i) { remapclasses_->push_back(NULL); } // (2) Setting RemapClass* to items. for (uint32_t i = 0; i < count; ++i) { if (p >= remapclasses_initialize_vector + vector_size) { IOLOG_ERROR("%s vector_size mismatch.\n", __FUNCTION__); goto error; } uint32_t size = *p++; if (p + size > remapclasses_initialize_vector + vector_size) { IOLOG_ERROR("%s vector_size mismatch. (vector_size:%d, size:%d)\n", __FUNCTION__, static_cast<int>(vector_size), size); goto error; } if (size == 0) { IOLOG_ERROR("%s size == 0.\n", __FUNCTION__); goto error; } uint32_t configindex = *p++; --size; RemapClass* newp = new RemapClass(p, size); if (! newp) { IOLOG_ERROR("%s newp == NULL.\n", __FUNCTION__); goto error; } p += size; if (configindex >= remapclasses_->size()) { IOLOG_ERROR("%s invalid configindex %d (remapclasses_->size() == %d).\n", __FUNCTION__, configindex, static_cast<int>(remapclasses_->size())); goto error; } (*remapclasses_)[configindex] = newp; } // (3) Making sure that is not NULL for all items. for (uint32_t i = 0; i < remapclasses_->size(); ++i) { if (! (*remapclasses_)[i]) { IOLOG_ERROR("%s (*remapclasses_)[i] == NULL.\n", __FUNCTION__); goto error; } } } RemapClass::log_allocation_count(); return true; error: clear_remapclasses(); return false; } bool set_config(const int32_t* const config_vector, mach_vm_size_t config_size) { // ------------------------------------------------------------ // check if (! remapclasses_) { IOLOG_ERROR("%s remapclasses_ == NULL.\n", __FUNCTION__); return false; } if (config_size != (BRIDGE_ESSENTIAL_CONFIG_INDEX__END__ + remapclasses_->size()) * sizeof(int32_t)) { IOLOG_ERROR("%s config_size mismatch.\n", __FUNCTION__); return false; } // ------------------------------------------------------------ // essential config const int32_t* p = config_vector; Config::set_essential_config(p, BRIDGE_ESSENTIAL_CONFIG_INDEX__END__); // remapclasses config p += BRIDGE_ESSENTIAL_CONFIG_INDEX__END__; for (size_t i = 0; i < remapclasses_->size(); ++i) { RemapClass* rc = (*remapclasses_)[i]; if (! rc) { IOLOG_ERROR("%s RemapClass == NULL.\n", __FUNCTION__); } else { rc->setEnabled(p[i]); } } refresh(); return true; } void refresh(void) { // We use timer to prevent deadlock of lock_. (refresh may be called in the remap_key, remap_consumer, *). enum { DELAY = 1, }; refresh_timer_.setTimeoutMS(DELAY); } // ---------------------------------------------------------------------- #define CALL_REMAPCLASS_FUNC(FUNC, PARAMS) { \ if (enabled_remapclasses_) { \ for (size_t i = 0; i < enabled_remapclasses_->size(); ++i) { \ RemapClass* p = (*enabled_remapclasses_)[i]; \ if (p) p->FUNC(PARAMS); \ } \ } \ } void remap_setkeyboardtype(KeyboardType& keyboardType) { CALL_REMAPCLASS_FUNC(remap_setkeyboardtype, keyboardType); } void remap_forcenumlockon(ListHookedKeyboard::Item* item) { CALL_REMAPCLASS_FUNC(remap_forcenumlockon, item); } void remap_key(RemapParams& remapParams) { CALL_REMAPCLASS_FUNC(remap_key, remapParams); } void remap_consumer(RemapConsumerParams& remapParams) { CALL_REMAPCLASS_FUNC(remap_consumer, remapParams); } void remap_pointing(RemapPointingParams_relative& remapParams) { CALL_REMAPCLASS_FUNC(remap_pointing, remapParams); } void remap_pointing_scroll(RemapPointingParams_scroll& remapParams) { CALL_REMAPCLASS_FUNC(remap_pointing_scroll, remapParams); } #undef CALL_REMAPCLASS_FUNC bool remap_simultaneouskeypresses(void) { bool queue_changed = false; if (enabled_remapclasses_) { for (size_t i = 0; i < enabled_remapclasses_->size(); ++i) { RemapClass* p = (*enabled_remapclasses_)[i]; if (p) { if (p->remap_simultaneouskeypresses()) { queue_changed = true; } } } } return queue_changed; } bool remap_dropkeyafterremap(const Params_KeyboardEventCallBack& params) { bool dropped = false; if (enabled_remapclasses_) { for (size_t i = 0; i < enabled_remapclasses_->size(); ++i) { RemapClass* p = (*enabled_remapclasses_)[i]; if (p) { if (p->remap_dropkeyafterremap(params)) dropped = true; } } } return dropped; } bool isEventInputQueueDelayEnabled(void) { return isEventInputQueueDelayEnabled_; } bool isEnabled(size_t configindex) { if (! remapclasses_) return false; if (configindex >= remapclasses_->size()) { IOLOG_ERROR("RemapClass::isEnabled invalid configindex.\n"); return false; } RemapClass* p = (*remapclasses_)[configindex]; if (! p) return false; return p->enabled(); } }
namespace RemapClassManager { IOLock* lock_ = NULL; TimerWrapper refresh_timer_; char statusmessage_[32]; char lastmessage_[32]; bool isEventInputQueueDelayEnabled_ = false; Vector_RemapClassPointer* remapclasses_ = NULL; Vector_RemapClassPointer* enabled_remapclasses_ = NULL; // ====================================================================== static void refresh_core(OSObject* owner, IOTimerEventSource* sender) { IOLockWrapper::ScopedLock lk(lock_); if (! remapclasses_) return; // ---------------------------------------- if (enabled_remapclasses_) { delete enabled_remapclasses_; } enabled_remapclasses_ = new Vector_RemapClassPointer(); if (! enabled_remapclasses_) return; // ---------------------------------------- KeyboardRepeat::cancel(); statusmessage_[0] = '\0'; isEventInputQueueDelayEnabled_ = false; for (size_t i = 0; i < remapclasses_->size(); ++i) { RemapClass* p = (*remapclasses_)[i]; if (! p) continue; if (p->enabled()) { enabled_remapclasses_->push_back(p); const char* msg = p->get_statusmessage(); if (msg) { strlcat(statusmessage_, msg, sizeof(statusmessage_)); strlcat(statusmessage_, " ", sizeof(statusmessage_)); } if (p->is_simultaneouskeypresses()) { isEventInputQueueDelayEnabled_ = true; } } } if (strcmp(statusmessage_, lastmessage_) != 0) { KeyRemap4MacBook_bridge::StatusMessage::Request request(KeyRemap4MacBook_bridge::StatusMessage::MESSAGETYPE_EXTRA, statusmessage_); KeyRemap4MacBook_client::sendmsg(KeyRemap4MacBook_bridge::REQUEST_STATUS_MESSAGE, &request, sizeof(request), NULL, 0); strlcpy(lastmessage_, statusmessage_, sizeof(lastmessage_)); } } // ====================================================================== void initialize(IOWorkLoop& workloop) { lock_ = IOLockWrapper::alloc(); statusmessage_[0] = '\0'; lastmessage_[0] = '\0'; remapclasses_ = NULL; enabled_remapclasses_ = NULL; refresh_timer_.initialize(&workloop, NULL, refresh_core); } void clear_xml(void) { Handle_VK_CONFIG::clear_items(); if (enabled_remapclasses_) { delete enabled_remapclasses_; enabled_remapclasses_ = NULL; } if (remapclasses_) { for (size_t i = 0; i < remapclasses_->size(); ++i) { RemapClass* p = (*remapclasses_)[i]; if (p) { delete p; } } delete remapclasses_; remapclasses_ = NULL; } } void terminate(void) { refresh_timer_.terminate(); clear_xml(); IOLockWrapper::free(lock_); } bool reload_xml(void) { IOLockWrapper::ScopedLock lk(lock_); bool retval = false; uint32_t count = 0; KeyRemap4MacBook_bridge::GetConfigInfo::Reply::Item* configinfo = NULL; // ------------------------------------------------------------ if (Config::do_reload_only_config != 1) { clear_xml(); remapclasses_ = new Vector_RemapClassPointer(); } if (! remapclasses_) { IOLOG_ERROR("do_reload_xml remapclasses_ == NULL.\n"); goto finish; } // ------------------------------------------------------------ // get count { KeyRemap4MacBook_bridge::GetConfigCount::Reply reply; time_t timeout_second = 3; int error = KeyRemap4MacBook_client::sendmsg(KeyRemap4MacBook_bridge::REQUEST_GET_CONFIG_COUNT, NULL, 0, &reply, sizeof(reply), timeout_second, 0); if (error) { IOLOG_ERROR("do_reload_xml GetConfigCount sendmsg failed. (%d)\n", error); goto finish; } count = reply.count; } if (count > RemapClass::MAX_CONFIG_COUNT) { IOLOG_ERROR("do_reload_xml too many config count. (%d)\n", count); goto finish; } // ------------------------------------------------------------ // get configinfo configinfo = new KeyRemap4MacBook_bridge::GetConfigInfo::Reply::Item[count]; if (! configinfo) { IOLOG_ERROR("do_reload_xml allocation failed.\n"); goto finish; } { KeyRemap4MacBook_bridge::GetConfigInfo::Reply* reply = reinterpret_cast<KeyRemap4MacBook_bridge::GetConfigInfo::Reply*>(configinfo); time_t timeout_second = 3; int error = KeyRemap4MacBook_client::sendmsg(KeyRemap4MacBook_bridge::REQUEST_GET_CONFIG_INFO, NULL, 0, reply, static_cast<uint32_t>(sizeof(configinfo[0]) * count), timeout_second, 0); if (error) { IOLOG_ERROR("do_reload_xml GetConfigInfo sendmsg failed. (%d)\n", error); goto finish; } } // ------------------------------------------------------------ if (Config::do_reload_only_config == 1) { if (count != remapclasses_->size()) { IOLOG_ERROR("do_reload_xml count != remapclasses_->size()\n"); goto finish; } for (uint32_t i = 0; i < count; ++i) { (*remapclasses_)[i]->setEnabled(configinfo[i].enabled); } } else { remapclasses_->reserve(count); RemapClass::reset_allocation_count(); // get initialize_vector for (uint32_t i = 0; i < count; ++i) { uint32_t size = configinfo[i].initialize_vector_size; uint32_t* initialize_vector = NULL; if (size > RemapClass::MAX_INITIALIZE_VECTOR_SIZE) { IOLOG_ERROR("do_reload_xml too large initialize_vector. (%d)\n", size); goto finish; } initialize_vector = new uint32_t[size]; { KeyRemap4MacBook_bridge::GetConfigInitializeVector::Request request(i); KeyRemap4MacBook_bridge::GetConfigInitializeVector::Reply* reply = reinterpret_cast<KeyRemap4MacBook_bridge::GetConfigInitializeVector::Reply*>(initialize_vector); time_t timeout_second = 3; int error = KeyRemap4MacBook_client::sendmsg(KeyRemap4MacBook_bridge::REQUEST_GET_CONFIG_INITIALIZE_VECTOR, &request, sizeof(request), reply, static_cast<uint32_t>(sizeof(initialize_vector[0]) * size), timeout_second, 0); RemapClass* newp = NULL; if (! error) { newp = new RemapClass(initialize_vector, configinfo[i].enabled); } remapclasses_->push_back(newp); } delete[] initialize_vector; } RemapClass::log_allocation_count(); } refresh(); retval = true; finish: if (configinfo) { delete[] configinfo; } return retval; } void refresh(void) { // We use timer to prevent deadlock of lock_. (refresh may be called in the remap_key, remap_consumer, *). enum { DELAY = 1, }; refresh_timer_.setTimeoutMS(DELAY); } // ---------------------------------------------------------------------- #define CALL_REMAPCLASS_FUNC(FUNC, PARAMS) { \ IOLockWrapper::ScopedLock lk(lock_); \ if (enabled_remapclasses_) { \ for (size_t i = 0; i < enabled_remapclasses_->size(); ++i) { \ RemapClass* p = (*enabled_remapclasses_)[i]; \ if (p) p->FUNC(PARAMS); \ } \ } \ } void remap_setkeyboardtype(KeyboardType& keyboardType) { CALL_REMAPCLASS_FUNC(remap_setkeyboardtype, keyboardType); } void remap_key(RemapParams& remapParams) { CALL_REMAPCLASS_FUNC(remap_key, remapParams); } void remap_consumer(RemapConsumerParams& remapParams) { CALL_REMAPCLASS_FUNC(remap_consumer, remapParams); } void remap_pointing(RemapPointingParams_relative& remapParams) { CALL_REMAPCLASS_FUNC(remap_pointing, remapParams); } #undef CALL_REMAPCLASS_FUNC bool remap_simultaneouskeypresses(void) { IOLockWrapper::ScopedLock lk(lock_); bool queue_changed = false; if (enabled_remapclasses_) { for (size_t i = 0; i < enabled_remapclasses_->size(); ++i) { RemapClass* p = (*enabled_remapclasses_)[i]; if (p) { if (p->remap_simultaneouskeypresses()) { queue_changed = true; } } } } return queue_changed; } bool remap_dropkeyafterremap(const Params_KeyboardEventCallBack& params) { IOLockWrapper::ScopedLock lk(lock_); bool dropped = false; if (enabled_remapclasses_) { for (size_t i = 0; i < enabled_remapclasses_->size(); ++i) { RemapClass* p = (*enabled_remapclasses_)[i]; if (p) { if (p->remap_dropkeyafterremap(params)) dropped = true; } } } return dropped; } bool isEventInputQueueDelayEnabled(void) { return isEventInputQueueDelayEnabled_; } bool isEnabled(size_t configindex) { // isEnabled called in remap_key, remap_consumer, ... // So, don't make ScopedLock(lock_). if (! remapclasses_) return false; if (configindex >= remapclasses_->size()) { IOLOG_ERROR("RemapClass::isEnabled invalid configindex.\n"); return false; } RemapClass* p = (*remapclasses_)[configindex]; if (! p) return false; return p->enabled(); } }