6#include "QskInputContext.h"
7#include "QskInputPanel.h"
8#include "QskInputPanelBox.h"
11#include "QskLinearBox.h"
14#include "QskTextPredictor.h"
16#include "QskPlatform.h"
18#include <qguiapplication.h>
23#include <qpa/qplatforminputcontext.h>
24#include <qpa/qplatformintegration.h>
27#include "QskHunspellTextPredictor.h"
35 Panel( QQuickItem* parent =
nullptr )
43 connect( m_box, &QskInputPanelBox::keySelected,
44 this, &QskInputPanel::keySelected );
46 connect( m_box, &QskInputPanelBox::predictiveTextSelected,
47 this, &QskInputPanel::predictiveTextSelected );
50 void attachItem( QQuickItem* item )
override
52 m_box->attachInputItem( item );
55 QQuickItem* inputProxy()
const override
57 return m_box->inputProxy();
60 void setPrompt(
const QString& prompt )
override
62 m_box->setInputPrompt( prompt );
65 void setPredictionEnabled(
bool on )
override
67 m_box->setPanelHint( QskInputPanelBox::Prediction, on );
70 void setPrediction(
const QStringList& prediction )
override
72 QskInputPanel::setPrediction( prediction );
73 m_box->setPrediction( prediction );
84 QPointer< QQuickItem > item;
87 QPointer< QskInputPanel > panel;
90 QPointer< QskPopup > popup;
91 QPointer< QskWindow > window;
97 inline Channel* currentChannel()
const
99 const auto object = QGuiApplication::focusObject();
100 return channel( qobject_cast< const QQuickItem* >(
object ) );
103 inline Channel* channel(
const QQuickWindow* window )
const
107 auto it = m_map.constFind( window );
108 if ( it != m_map.constEnd() )
109 return const_cast< Channel*
>( &it.value() );
119 QMap< const QQuickWindow*, Channel >::const_iterator it;
121 for( it = m_map.constBegin(); it != m_map.constEnd(); ++it )
123 if( it.value().panel == panel )
124 return const_cast< Channel*
>( &it.value() );
131 inline Channel* channel(
const QQuickItem* item )
const
136 QMap< const QQuickWindow*, Channel >::const_iterator it;
138 for( it = m_map.constBegin(); it != m_map.constEnd(); ++it )
140 if( it.value().item == item )
141 return const_cast< Channel*
>( &it.value() );
148 inline Channel* ancestorChannel(
const QQuickItem* item )
const
150 for (
auto it = m_map.constBegin();
151 it != m_map.constEnd(); ++it )
153 if (
const auto panel = it.value().panel )
155 if ( ( item == panel ) || qskIsAncestorOf( panel, item ) )
157 return const_cast< Channel*
>( &it.value() );
165 inline Channel* insert(
const QQuickWindow* window )
167 return &m_map[ window ];
170 inline void remove(
const QQuickWindow* window )
172 m_map.remove( window );
176 QMap< const QQuickWindow*, Channel > m_map;
180static QPointer< QskInputContext > qskInputContext;
182static void qskSendToPlatformContext( QEvent::Type type )
184 const auto integration = qskPlatformIntegration();
186 if (
const auto inputContext = integration->inputContext() )
188 QEvent event( type );
189 QCoreApplication::sendEvent( inputContext, &event );
193static void qskInputContextHook()
195 qAddPostRoutine( [] {
delete qskInputContext; } );
198Q_COREAPP_STARTUP_FUNCTION( qskInputContextHook )
200#if QT_VERSION >= QT_VERSION_CHECK( 6, 2, 0 )
201 static inline QLocale::Territory qskTerritory(
const QLocale& locale )
202 {
return locale.territory(); }
204 static inline QLocale::Country qskTerritory(
const QLocale& locale )
205 {
return locale.country(); }
210 if ( inputContext != qskInputContext )
212 const auto oldContext = qskInputContext;
213 qskInputContext = inputContext;
215 if ( oldContext && oldContext->parent() ==
nullptr )
220 qskSendToPlatformContext( QEvent::PlatformPanel );
227 return qskInputContext;
230class QskInputContext::PrivateData
238 panel = this->factory->createPanel();
240 if ( panel ==
nullptr )
243 connect( panel, &QskInputPanel::visibleChanged,
244 context, &QskInputContext::activeChanged );
247 context, [] { qskSendToPlatformContext( QEvent::LocaleChange ); } );
249 connect( panel, &QskInputPanel::inputItemDestroyed,
250 context, [ context, panel ] { context->hideChannel( panel ); } );
259 popup->setAutoLayoutChildren(
true );
261 popup->setMargins( 5 );
262 popup->setModal(
true );
264 panel->setParentItem( popup );
265 if ( panel->parent() ==
nullptr )
266 panel->setParent( popup );
275 window->setFlags( window->flags() & Qt::Dialog );
277 window->setAutoLayoutChildren(
true );
279 window->setFlags( Qt::Tool | Qt::WindowDoesNotAcceptFocus );
282 panel->setParentItem( window->contentItem() );
287 void closeChannel( Channel* channel )
289 if ( channel->popup )
290 channel->popup->close();
292 if ( channel->window )
293 channel->window->close();
296 ChannelTable channels;
297 QPointer< QskInputContextFactory > factory;
300QskInputContext::QskInputContext()
301 : m_data( new PrivateData() )
303 setObjectName( QStringLiteral(
"InputContext" ) );
306QskInputContext::~QskInputContext()
312 if ( m_data->factory == factory )
315 if ( m_data->factory && m_data->factory->parent() ==
this )
316 delete m_data->factory;
318 m_data->factory = factory;
320 if ( factory && factory->parent() ==
nullptr )
321 factory->setParent(
this );
326 return m_data->factory;
329std::shared_ptr< QskTextPredictor > QskInputContext::textPredictor(
const QLocale& locale )
331 if ( m_data->factory )
332 return m_data->factory->setupPredictor( locale );
337void QskInputContext::update(
const QQuickItem* item, Qt::InputMethodQueries queries )
339 if ( item ==
nullptr )
342 item = qobject_cast< QQuickItem* >( QGuiApplication::focusObject() );
345 auto channel = m_data->channels.channel( item );
346 if ( channel ==
nullptr )
349 if ( queries & Qt::ImEnabled )
351 QInputMethodQueryEvent event( Qt::ImEnabled );
352 QCoreApplication::sendEvent( channel->item, &event );
354 if ( !event.value( Qt::ImEnabled ).toBool() )
361 channel->panel->updateInputPanel( queries );
364QRectF QskInputContext::panelRect()
const
374void QskInputContext::showPanel(
const QQuickItem* item )
376 if ( item ==
nullptr )
379 if ( m_data->channels.ancestorChannel( item ) )
385 if (
auto channel = m_data->channels.channel( item->window() ) )
387 if ( channel->item == item )
390 hidePanel( channel->item );
393 auto panel = m_data->createPanel(
this );
395 auto channel = m_data->channels.insert( item->window() );
396 channel->item =
const_cast< QQuickItem*
>( item );
397 channel->panel = panel;
399 if ( QskDialog::instance()->policy() == QskDialog::TopLevelWindow )
403 auto window = m_data->createWindow( panel );
405 QSize size = window->sizeConstraint();
406 if ( size.isEmpty() )
409 size = QSize( 800, 240 );
412 window->resize( size );
415 window->setDeleteOnClose(
true );
417 channel->window = window;
423 auto popup = m_data->createPopup( panel );
425 popup->setPopupFlag( QskPopup::DeleteOnClose,
true );
426 popup->setParentItem( item->window()->contentItem() );
427 popup->setParent(
this );
429 channel->popup = popup;
434 panel->attachInputItem(
const_cast< QQuickItem*
>( item ) );
437void QskInputContext::hidePanel(
const QQuickItem* item )
439 if ( item ==
nullptr )
442 if (
auto channel = m_data->channels.channel( item ) )
444 m_data->closeChannel( channel );
445 m_data->channels.remove( item->window() );
449void QskInputContext::hideChannel(
const QskInputPanel* panel )
451 if (
auto channel = m_data->channels.channel( panel ) )
454 m_data->closeChannel( channel );
455 m_data->channels.remove( panel->window() );
459void QskInputContext::setInputPanelVisible(
const QQuickItem* item,
bool on )
463 if ( item ==
nullptr )
464 item = qobject_cast< QQuickItem* >( QGuiApplication::focusObject() );
475bool QskInputContext::isInputPanelVisible()
const
477 return m_data->channels.currentChannel() !=
nullptr;
480QLocale QskInputContext::locale()
const
482 if (
auto channel = m_data->channels.currentChannel() )
484 if ( channel->panel )
485 return channel->panel->locale();
491void QskInputContext::setFocusObject( QObject* )
495void QskInputContext::invokeAction(
496 QInputMethod::Action,
int cursorPosition )
499 Q_UNUSED( cursorPosition )
502void QskInputContext::commitPrediction(
bool )
511class QskInputContextFactory::PrivateData
514 QThread* thread =
nullptr;
515 std::shared_ptr< QskTextPredictor > predictor;
516 QLocale predictorLocale;
519QskInputContextFactory::QskInputContextFactory( QObject* parent )
521 , m_data( new PrivateData() )
525QskInputContextFactory::~QskInputContextFactory()
529 m_data->thread->quit();
530 connect( m_data->thread, &QThread::finished, m_data->thread, &QObject::deleteLater );
534std::shared_ptr< QskTextPredictor > QskInputContextFactory::setupPredictor(
const QLocale& locale )
536 if( !m_data->predictor
537 || m_data->predictorLocale.language() != locale.language()
538 || qskTerritory( m_data->predictorLocale ) != qskTerritory( locale ) )
540 m_data->predictor = std::shared_ptr< QskTextPredictor >( createPredictor( locale ) );
541 m_data->predictorLocale = QLocale( locale.language(), qskTerritory( locale ) );
543 if( m_data->predictor )
545 if( !m_data->thread )
547 m_data->thread =
new QThread();
548 m_data->thread->start();
551 m_data->predictor->moveToThread( m_data->thread );
555 return m_data->predictor;
558QskTextPredictor* QskInputContextFactory::createPredictor(
const QLocale& locale )
574#include "moc_QskInputContext.cpp"
void localeChanged(const QLocale &)
void setAutoLayoutChildren(bool)
void setLayoutAlignmentHint(Qt::Alignment)