static void Mapping( intf_thread_t *p_intf ) { static const xcb_keysym_t p_x11_modifier_ignored[] = { 0, XK_Num_Lock, XK_Scroll_Lock, XK_Caps_Lock, }; intf_sys_t *p_sys = p_intf->p_sys; p_sys->i_map = 0; p_sys->p_map = NULL; /* Registering of Hotkeys */ for( struct hotkey *p_hotkey = p_intf->p_libvlc->p_hotkeys; p_hotkey->psz_action != NULL; p_hotkey++ ) { char *psz_hotkey; if( asprintf( &psz_hotkey, "global-%s", p_hotkey->psz_action ) < 0 ) break; const int i_vlc_action = p_hotkey->i_action; const int i_vlc_key = config_GetInt( p_intf, psz_hotkey ); free( psz_hotkey ); if( !i_vlc_key ) continue; const xcb_keycode_t key = xcb_key_symbols_get_keycode( p_sys->p_symbols, GetX11Key( i_vlc_key & ~KEY_MODIFIER ) ); const unsigned i_modifier = GetX11Modifier( p_sys->p_connection, p_sys->p_symbols, i_vlc_key & KEY_MODIFIER ); for( int j = 0; j < sizeof(p_x11_modifier_ignored)/sizeof(*p_x11_modifier_ignored); j++ ) { const unsigned i_ignored = GetModifier( p_sys->p_connection, p_sys->p_symbols, p_x11_modifier_ignored[j] ); if( j != 0 && i_ignored == 0x00) continue; hotkey_mapping_t *p_map_old = p_sys->p_map; p_sys->p_map = realloc( p_sys->p_map, sizeof(*p_sys->p_map) * (p_sys->i_map+1) ); if( !p_sys->p_map ) { p_sys->p_map = p_map_old; break; } hotkey_mapping_t *p_map = &p_sys->p_map[p_sys->i_map++]; p_map->i_x11 = key; p_map->i_modifier = i_modifier|i_ignored; p_map->i_action = i_vlc_action; } } }
void MainWindow::setHotKey(const QKeySequence& hotKey_) { // platform-specific code for global key grabbing #ifdef WIN32 UINT i_vk, i_mod = 0; if(!hotKey.isEmpty()) { // disable previous hotkey UnregisterHotKey(NULL, 10); } hotKey = hotKey_; nativeFilter.setHotKey(hotKey); settings.setValue("hotkey", hotKey); if(hotKey.isEmpty()) return; int key = hotKey[0]; if(key & Qt::ALT) i_mod |= MOD_ALT; if(key & Qt::CTRL) i_mod |= MOD_CONTROL; if(key & Qt::SHIFT) i_mod |= MOD_SHIFT; key = key & ~(Qt::ALT | Qt::CTRL | Qt::SHIFT | Qt::META); #ifndef VK_VOLUME_DOWN #define VK_VOLUME_DOWN 0xAE #define VK_VOLUME_UP 0xAF #endif #ifndef VK_MEDIA_NEXT_TRACK #define VK_MEDIA_NEXT_TRACK 0xB0 #define VK_MEDIA_PREV_TRACK 0xB1 #define VK_MEDIA_STOP 0xB2 #define VK_MEDIA_PLAY_PAUSE 0xB3 #endif #ifndef VK_PAGEUP #define VK_PAGEUP 0x21 #define VK_PAGEDOWN 0x22 #endif switch(key) { case Qt::Key_Left: i_vk = VK_LEFT; break; case Qt::Key_Right: i_vk = VK_RIGHT; break; case Qt::Key_Up: i_vk = VK_UP; break; case Qt::Key_Down: i_vk = VK_DOWN; break; case Qt::Key_Space: i_vk = VK_SPACE; break; case Qt::Key_Escape: i_vk = VK_ESCAPE; break; case Qt::Key_Enter: i_vk = VK_RETURN; break; case Qt::Key_Return: i_vk = VK_RETURN; break; case Qt::Key_F1: i_vk = VK_F1; break; case Qt::Key_F2: i_vk = VK_F2; break; case Qt::Key_F3: i_vk = VK_F3; break; case Qt::Key_F4: i_vk = VK_F4; break; case Qt::Key_F5: i_vk = VK_F5; break; case Qt::Key_F6: i_vk = VK_F6; break; case Qt::Key_F7: i_vk = VK_F7; break; case Qt::Key_F8: i_vk = VK_F8; break; case Qt::Key_F9: i_vk = VK_F9; break; case Qt::Key_F10: i_vk = VK_F10; break; case Qt::Key_F11: i_vk = VK_F11; break; case Qt::Key_F12: i_vk = VK_F12; break; case Qt::Key_PageUp: i_vk = VK_PAGEUP; break; case Qt::Key_PageDown: i_vk = VK_PAGEDOWN; break; case Qt::Key_Home: i_vk = VK_HOME; break; case Qt::Key_End: i_vk = VK_END; break; case Qt::Key_Insert: i_vk = VK_INSERT; break; case Qt::Key_Delete: i_vk = VK_DELETE; break; case Qt::Key_VolumeDown: i_vk = VK_VOLUME_DOWN; break; case Qt::Key_VolumeUp: i_vk = VK_VOLUME_UP; break; case Qt::Key_MediaTogglePlayPause: i_vk = VK_MEDIA_PLAY_PAUSE; break; case Qt::Key_MediaStop: i_vk = VK_MEDIA_STOP; break; case Qt::Key_MediaPrevious: i_vk = VK_MEDIA_PREV_TRACK; break; case Qt::Key_MediaNext: i_vk = VK_MEDIA_NEXT_TRACK; break; default: i_vk = toupper( key ); break; } if(!RegisterHotKey(NULL, 10, i_mod, i_vk)) { hotKey = QKeySequence(); nativeFilter.setHotKey(hotKey); settings.setValue("hotkey", hotKey); QMessageBox::warning(this, "Key binding failed", "Binding global hotkey failed."); } #elif LINUX auto platform = qApp->platformNativeInterface(); xcb_connection_t *c = static_cast<xcb_connection_t*>(platform->nativeResourceForWindow("connection", 0)); xcb_key_symbols_t *keysyms = xcb_key_symbols_alloc(c); if(!hotKey.isEmpty()) { // remove previous bindings from all screens xcb_screen_iterator_t iter; iter = xcb_setup_roots_iterator (xcb_get_setup (c)); for (; iter.rem; xcb_screen_next (&iter)) { xcb_ungrab_key(c, XCB_GRAB_ANY, iter.data->root, XCB_MOD_MASK_ANY); } } hotKey = hotKey_; nativeFilter.setHotKey(hotKey); settings.setValue("hotkey", hotKey); if(hotKey.isEmpty()) return; xcb_keysym_t keysym = GetX11Key(hotKey[0]); xcb_keycode_t *keycodes = xcb_key_symbols_get_keycode(keysyms, keysym), keycode; if(!keycodes) { hotKey = QKeySequence(); nativeFilter.setHotKey(hotKey); settings.setValue("hotkey", hotKey); QMessageBox::warning(this, "Key binding failed", "Binding global hotkey failed."); free(keysyms); return; } // add bindings for all screens xcb_screen_iterator_t iter; iter = xcb_setup_roots_iterator (xcb_get_setup (c)); bool any_failed = false; for (; iter.rem; xcb_screen_next (&iter)) { int i = 0; while(keycodes[i] != XCB_NO_SYMBOL) { keycode = keycodes[i]; for(auto modifier : GetX11Modifier(c, keysyms, hotKey[0])) { auto cookie = xcb_grab_key_checked(c, true, iter.data->root, modifier, keycode, XCB_GRAB_MODE_SYNC, XCB_GRAB_MODE_SYNC); if(xcb_request_check(c, cookie)) { any_failed = true; } } i += 1; } } if(any_failed) { QMessageBox::warning(this, "Key binding warning", "Warning: Global hotkey binding problem detected. Some other program might have a conflicting " "key binding. If the hotkey doesn't work, try closing some programs or using a different hotkey."); } free(keysyms); free(keycodes); #endif // WIN32 or LINUX }
static bool Mapping( intf_thread_t *p_intf ) { static const xcb_keysym_t p_x11_modifier_ignored[] = { 0, XK_Num_Lock, XK_Scroll_Lock, XK_Caps_Lock, }; intf_sys_t *p_sys = p_intf->p_sys; bool active = false; p_sys->i_map = 0; p_sys->p_map = NULL; /* Registering of Hotkeys */ for( const struct hotkey *p_hotkey = p_intf->p_libvlc->p_hotkeys; p_hotkey->psz_action != NULL; p_hotkey++ ) { char varname[12 + strlen( p_hotkey->psz_action )]; sprintf( varname, "global-key-%s", p_hotkey->psz_action ); char *key = var_InheritString( p_intf, varname ); if( key == NULL ) continue; uint_fast32_t i_vlc_key = vlc_str2keycode( key ); free( key ); if( i_vlc_key == KEY_UNSET ) continue; xcb_keycode_t *p_keys = xcb_key_symbols_get_keycode( p_sys->p_symbols, GetX11Key( i_vlc_key & ~KEY_MODIFIER ) ); if( !p_keys ) continue; const unsigned i_modifier = GetX11Modifier( p_sys->p_connection, p_sys->p_symbols, i_vlc_key & KEY_MODIFIER ); const size_t max = sizeof(p_x11_modifier_ignored) / sizeof(*p_x11_modifier_ignored); for( unsigned int i = 0; i < max; i++ ) { const unsigned i_ignored = GetModifier( p_sys->p_connection, p_sys->p_symbols, p_x11_modifier_ignored[i] ); if( i != 0 && i_ignored == 0) continue; hotkey_mapping_t *p_map_old = p_sys->p_map; p_sys->p_map = realloc( p_sys->p_map, sizeof(*p_sys->p_map) * (p_sys->i_map+1) ); if( !p_sys->p_map ) { p_sys->p_map = p_map_old; break; } hotkey_mapping_t *p_map = &p_sys->p_map[p_sys->i_map++]; p_map->p_keys = p_keys; p_map->i_modifier = i_modifier|i_ignored; p_map->i_vlc = i_vlc_key; active = true; } } return active; }
bool ZealNativeEventFilter::nativeEventFilter(const QByteArray &eventType, void *message, long *result) { enabled = true; #ifdef WIN32 MSG* msg = static_cast<MSG*>(message); if(WM_HOTKEY == msg->message && msg->wParam == 10) { emit gotHotKey(); return true; } #elsif LINUX // WIN32 or LINUX xcb_generic_event_t* ev = static_cast<xcb_generic_event_t*>(message); if(((ev->response_type&127) == XCB_KEY_PRESS || (ev->response_type&127) == XCB_KEY_RELEASE) && !hotKey.isEmpty()) { // XCB_KEY_RELEASE must be ignored by Qt because otherwise it causes SIGSEGV in QXcbKeyboard::handleKeyReleaseEvent xcb_connection_t *c = static_cast<xcb_connection_t*>( ((QGuiApplication*)QGuiApplication::instance())-> platformNativeInterface()->nativeResourceForWindow("connection", 0)); xcb_key_press_event_t *event = (xcb_key_press_event_t *)ev; xcb_key_symbols_t *keysyms = xcb_key_symbols_alloc(c); xcb_keycode_t *keycodes = xcb_key_symbols_get_keycode(keysyms, GetX11Key(hotKey[0])); bool found = false; // found=true means either (a) complete hotkey was pressed, or (b) any of its separate // keys was released. We return true in both cases, because key releases while window // is not present cause SIGSEGV in QXcbKeyboard::handleKeyReleaseEvent if((ev->response_type&127) == XCB_KEY_RELEASE) { QList<QPair<int, Qt::Modifier> > modifiers; modifiers.append(qMakePair(XK_Alt_L, Qt::ALT)); modifiers.append(qMakePair(XK_Alt_R, Qt::ALT)); modifiers.append(qMakePair(XK_Control_L, Qt::CTRL)); modifiers.append(qMakePair(XK_Control_R, Qt::CTRL)); modifiers.append(qMakePair(XK_Meta_L, Qt::META)); modifiers.append(qMakePair(XK_Meta_R, Qt::META)); for(auto modifier : modifiers) { if(!(hotKey[0] & modifier.second)) { continue; } xcb_keycode_t *mod_keycodes = xcb_key_symbols_get_keycode(keysyms, modifier.first); if(mod_keycodes == nullptr) continue; int i = 0; while(mod_keycodes[i] != XCB_NO_SYMBOL) { if(event->detail == mod_keycodes[i]) { found = true; } i += 1; } free(mod_keycodes); } } int i = 0; while(keycodes[i] != XCB_NO_SYMBOL) { if(event->detail == keycodes[i]) { bool modifiers_present = true; if(hotKey[0] & Qt::ALT) { if(!(event->state & GetModifier(c, keysyms, XK_Alt_L) || event->state & GetModifier(c, keysyms, XK_Alt_R))) { modifiers_present = false; } } if(hotKey[0] & Qt::CTRL) { if(!(event->state & GetModifier(c, keysyms, XK_Control_L) || event->state & GetModifier(c, keysyms, XK_Control_R))) { modifiers_present = false; } } if(hotKey[0] & Qt::META) { if(!(event->state & GetModifier(c, keysyms, XK_Meta_L) || event->state & GetModifier(c, keysyms, XK_Meta_R))) { modifiers_present = false; } } if(hotKey[0] & Qt::SHIFT) { if(!(event->state & GetModifier(c, keysyms, XK_Shift_L) || event->state & GetModifier(c, keysyms, XK_Shift_R))) { modifiers_present = false; } } if(enabled && modifiers_present) { xcb_allow_events(c, XCB_ALLOW_ASYNC_KEYBOARD, event->time); if((ev->response_type&127) == XCB_KEY_PRESS) { emit gotHotKey(); } found = true; } else { if((ev->response_type&127) == XCB_KEY_RELEASE) { found = true; } xcb_allow_events(c, XCB_ALLOW_REPLAY_KEYBOARD, event->time); } break; } i += 1; } free(keysyms); free(keycodes); if(found) return true; } #endif // WIN32 or LINUX return false; }