1414from kivy .core .window import Window
1515from kivy .lang import Builder
1616from kivy .uix .boxlayout import BoxLayout
17+ from kivy .base import EventLoop
1718
1819####CEF IMPORT ####
1920import ctypes , os , sys
@@ -59,6 +60,7 @@ def __init__(self, **kwargs):
5960
6061
6162class CefBrowser (Widget ):
63+
6264 '''Represent a browser widget for kivy, which can be used like a normal widget.
6365 '''
6466 def __init__ (self , start_url = 'http://www.google.com' , ** kwargs ):
@@ -105,8 +107,9 @@ def start_cef(self, start_url='http://google.com'):
105107
106108 #configure cef
107109 cefpython .g_debug = True
110+ cefpython .g_debugFile = "debug.log"
108111 settings = {"log_severity" : cefpython .LOGSEVERITY_INFO ,
109- # "log_file": GetApplicationPath( "debug.log") ,
112+ "log_file" : "debug.log" ,
110113 "release_dcheck_enabled" : True , # Enable only when debugging.
111114 # This directories must be set on Linux
112115 "locales_dir_path" : cefpython .GetModuleDirectory ()+ "/locales" ,
@@ -137,43 +140,98 @@ def start_cef(self, start_url='http://google.com'):
137140 # --
138141 # Do not use "about:blank" as navigateUrl - this will cause
139142 # the GoBack() and GoForward() methods to not work.
140- # --
141- # TODO: get rid of the hard-coded path. Use the __file__ variable
142- # to get the current directory. Using a path to a non-existent
143- # local html file seems to not cause any problems, so it can
144- # stay for a moment.
145143 self .browser = cefpython .CreateBrowserSync (windowInfo , browserSettings ,
146- navigateUrl = "file:///home/czarek/cefpython/cefpython/cef3/linux/binaries_64bit/empty2.html" )
144+ navigateUrl = start_url )
147145
148146 #set focus
149147 self .browser .SendFocusEvent (True )
150148
151149 #Create RenderHandler (in ClientHandler)
152150 CH = ClientHandler (self .texture , self )
153151 self .browser .SetClientHandler (CH )
152+
153+ jsBindings = cefpython .JavascriptBindings (
154+ bindToFrames = True , bindToPopups = True )
155+ jsBindings .SetFunction ("__kivy__request_keyboard" ,
156+ self .request_keyboard )
157+ jsBindings .SetFunction ("__kivy__release_keyboard" ,
158+ self .release_keyboard )
159+ self .browser .SetJavascriptBindings (jsBindings )
154160
155161 #Call WasResized() => force cef to call GetViewRect() and OnPaint afterwards
156162 self .browser .WasResized ()
157-
158- # Load desired start URL
159- # TODO: let the local html file "empty.html" to finish loading,
160- # call the LoadUrl() method with a 100ms delay. In the
161- # empty.html you could add a "Loading.." text, this would
162- # event useful, user would see some message instead of the
163- # blank page. Sometimes the lag can cause the website to
164- # load for a few seconds and user would be seeing only a
165- # white screen and wonder of what is happening. The other
166- # solution would be to change the mouse cursor to loading
167- # state - but this won't work in touch screen devices? As
168- # there is no cursor there. In wxpython there is the
169- # wx.CallLater() method, is there anything similar in Kivy?
170- self .browser .GetMainFrame ().LoadUrl (start_url )
171-
172- #Clock.schedule_interval(self.press_key, 5)
173- self ._keyboard = Window .request_keyboard (self ._keyboard_closed , self )
174- self ._keyboard .bind (on_key_down = self .press_key )
175-
163+
164+ # The browserWidget instance is required in OnLoadingStateChange().
165+ self .browser .SetUserData ("browserWidget" , self )
166+
167+
168+ def request_keyboard (self ):
169+ print ("request_keyboard()" )
170+ self ._keyboard = EventLoop .window .request_keyboard (
171+ self .release_keyboard , self )
172+ self ._keyboard .bind (on_key_down = self .on_key_down )
173+ self ._keyboard .bind (on_key_up = self .on_key_up )
174+
175+
176+ def release_keyboard (self ):
177+ if not self ._keyboard :
178+ return
179+ print ("release_keyboard()" )
180+ self ._keyboard .unbind (on_key_down = self .on_key_down )
181+ self ._keyboard .unbind (on_key_up = self .on_key_up )
182+ self ._keyboard .release ()
183+
176184
185+ def on_key_down (self , keyboard , keycode , text , modifiers ):
186+ # Notes:
187+ # - right alt modifier is not sent by Kivy
188+ # (Polish characters don't work)
189+ print ("on_key_down(): keycode = %s modifiers = %s" % (
190+ keycode , modifiers ))
191+ if keycode [0 ] == 27 :
192+ # On escape release the keyboard, see the injected
193+ # javascript in OnLoadStart().
194+ self .browser .GetFocusedFrame ().ExecuteJavascript (
195+ "__kivy__on_escape()" )
196+ return
197+ cefModifiers = cefpython .EVENTFLAG_NONE
198+ if "shift" in modifiers :
199+ cefModifiers |= cefpython .EVENTFLAG_SHIFT_DOWN
200+ if "ctrl" in modifiers :
201+ cefModifiers |= cefpython .EVENTFLAG_CONTROL_DOWN
202+ if "alt" in modifiers :
203+ cefModifiers |= cefpython .EVENTFLAG_ALT_DOWN
204+ if "capslock" in modifiers :
205+ cefModifiers |= cefpython .EVENTFLAG_CAPS_LOCK_ON
206+ # print("on_key_down(): cefModifiers = %s" % cefModifiers)
207+ keyEvent = {
208+ "type" : cefpython .KEYEVENT_RAWKEYDOWN ,
209+ "native_key_code" : keycode [0 ],
210+ "modifiers" : cefModifiers
211+ }
212+ # print("keydown keyEvent: %s" % keyEvent)
213+ self .browser .SendKeyEvent (keyEvent )
214+
215+
216+ def on_key_up (self , keyboard , keycode ):
217+ # print("on_key_up(): keycode = %s" % (keycode,))
218+ cefModifiers = cefpython .EVENTFLAG_NONE
219+ keyEvent = {
220+ "type" : cefpython .KEYEVENT_KEYUP ,
221+ "native_key_code" : keycode [0 ],
222+ "modifiers" : cefModifiers
223+ }
224+ # print("keyup keyEvent: %s" % keyEvent)
225+ self .browser .SendKeyEvent (keyEvent )
226+ keyEvent = {
227+ "type" : cefpython .KEYEVENT_CHAR ,
228+ "native_key_code" : keycode [0 ],
229+ "modifiers" : cefModifiers
230+ }
231+ # print("char keyEvent: %s" % keyEvent)
232+ self .browser .SendKeyEvent (keyEvent )
233+
234+
177235 def go_forward (self ):
178236 '''Going to forward in browser history
179237 '''
@@ -188,15 +246,6 @@ def go_back(self):
188246 self .browser .GoBack ()
189247
190248
191- def _keyboard_closed (self , * kwargs ):
192- pass
193-
194-
195- def press_key (self , wid , key , * kwargs ):
196- #print "key pressed", key[0]
197- self .browser .SendKeyEvent (cefpython .KEYTYPE_CHAR , key [0 ])
198-
199-
200249 def on_touch_down (self , touch , * kwargs ):
201250 if not self .collide_point (* touch .pos ):
202251 return
@@ -225,16 +274,66 @@ def on_touch_up(self, touch, *kwargs):
225274 touch .ungrab (self )
226275
227276
228-
229277class ClientHandler :
230278
231279 def __init__ (self , texture , parent ):
232280 self .texture = texture
233281 self .parent = parent
234-
235282
283+
284+ def OnLoadStart (self , browser , frame ):
285+ print ("OnLoadStart(): injecting focus listeners for text controls" )
286+ # The logic is similar to the one found in kivy-berkelium:
287+ # https://github.com/kivy/kivy-berkelium/blob/master/berkelium/__init__.py
288+ jsCode = """
289+ var __kivy__keyboard_requested = false;
290+ function __kivy__keyboard_interval() {
291+ var element = document.activeElement;
292+ if (!element) {
293+ return;
294+ }
295+ var tag = element.tagName;
296+ var type = element.type;
297+ // <input> with an empty type is a text type by default!
298+ if (tag == "INPUT" && (type == "" || type == "text"
299+ || type == "password") || tag == "TEXTAREA") {
300+ if (!__kivy__keyboard_requested) {
301+ __kivy__request_keyboard();
302+ __kivy__keyboard_requested = true;
303+ }
304+ return;
305+ }
306+ if (__kivy__keyboard_requested) {
307+ __kivy__release_keyboard();
308+ __kivy__keyboard_requested = false;
309+ }
310+ }
311+ function __kivy__on_escape() {
312+ if (document.activeElement) {
313+ document.activeElement.blur();
314+ }
315+ if (__kivy__keyboard_requested) {
316+ __kivy__release_keyboard();
317+ __kivy__keyboard_requested = false;
318+ }
319+ }
320+ setInterval(__kivy__keyboard_interval, 13);
321+ """
322+ frame .ExecuteJavascript (jsCode ,
323+ "kivy_.py > ClientHandler > OnLoadStart" )
324+
325+
326+ def OnLoadingStateChange (self , browser , isLoading , canGoBack ,
327+ canGoForward ):
328+ print ("OnLoadingStateChange(): isLoading = %s" % isLoading )
329+ if isLoading and browser .GetUserData ("browserWidget" ):
330+ # Release keyboard when navigating to a new page.
331+ browser .GetUserData ("browserWidget" ).release_keyboard ()
332+ pass
333+
334+
236335 def OnPaint (self , browser , paintElementType , dirtyRects , buffer , width , height ):
237- print "OnPaint()"
336+ # print "OnPaint()"
238337 if paintElementType != cefpython .PET_VIEW :
239338 print "Popups aren't implemented yet"
240339 return
@@ -250,16 +349,12 @@ def OnPaint(self, browser, paintElementType, dirtyRects, buffer, width, height):
250349
251350
252351 def GetViewRect (self , browser , rect ):
253- print "GetViewRect()"
254352 width , height = self .texture .size
255353 rect .append (0 )
256354 rect .append (0 )
257355 rect .append (width )
258356 rect .append (height )
259- print width
260- print height
261357 return True
262-
263358
264359
265360if __name__ == '__main__' :
0 commit comments